// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef THIRD_PARTY_NEARBY_SHARING_OUTGOING_SHARE_SESSION_H_ #define THIRD_PARTY_NEARBY_SHARING_OUTGOING_SHARE_SESSION_H_ #include #include #include #include #include #include #include #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "internal/platform/clock.h" #include "internal/platform/task_runner.h" #include "sharing/analytics/analytics_recorder.h" #include "sharing/attachment_container.h" #include "sharing/certificates/nearby_share_decrypted_public_certificate.h" #include "sharing/nearby_connection.h" #include "sharing/nearby_connections_manager.h" #include "sharing/nearby_connections_types.h" #include "sharing/paired_key_verification_runner.h" #include "sharing/proto/enums.pb.h" #include "sharing/share_session.h" #include "sharing/share_target.h" #include "sharing/thread_timer.h" #include "sharing/transfer_metadata.h" namespace nearby::sharing { // Class that represents a single outgoing share session. // This class is thread-compatible. class OutgoingShareSession : public ShareSession { public: OutgoingShareSession( Clock* clock, TaskRunner& service_thread, NearbyConnectionsManager* connections_manager, analytics::AnalyticsRecorder& analytics_recorder, std::string endpoint_id, const ShareTarget& share_target, absl::AnyInvocable transfer_update_callback); OutgoingShareSession(OutgoingShareSession&&); ~OutgoingShareSession() override; bool IsIncoming() const override { return false; } const std::optional& obfuscated_gaia_id() const { return obfuscated_gaia_id_; } void set_obfuscated_gaia_id(std::string obfuscated_gaia_id) { obfuscated_gaia_id_ = std::move(obfuscated_gaia_id); } // Returns true if the attachments are valid and payloads are created // successfully. bool InitiateSendAttachments( std::unique_ptr attachment_container); // Returns true if the introduction frame is written successfully. // `timeout_callback` is called if accept is not received from both sender and // receiver within the timeout. bool SendIntroduction(std::function timeout_callback); // Accept the outgoing transfer and wait for remote accept message in a // ConnectionResponseFrame. bool AcceptTransfer( std::function< void(std::optional< nearby::sharing::service::proto::ConnectionResponseFrame>)> response_callback); // Process the ConnectionResponseFrame. // On success, returns std::nullopt. // On failure, returns the status if the connection should be aborted. std::optional HandleConnectionResponse( std::optional response); // Begin sending payloads. // Listen to the payload status change and send the status to // `payload_transder_update_callback`. // Any other frames received will be passed to `frame_read_callback`. void SendPayloads( std::function< void(bool is_timeout, std::optional frame)> frame_read_callback, std::function payload_transder_update_callback); // Send the next payload to NearbyConnectionManager. // Used only if enable_transfer_cancellation_optimization is true. void SendNextPayload(); // Called when all payloads have been sent. void SendAttachmentsCompleted(const TransferMetadata& metadata); // Wait for receiver to close connection before we notify that the transfer // has succeeded. Here we delay the `complete_metadata` update until receiver // disconnects and forward a modified copy that changes kComplete into // kInProgress. // A 1 min timer is setup so that if we do not receive disconnect from // receiver, we assume the transfer has failed. void DelayComplete(const TransferMetadata& complete_metadata); // Updates the share target in the session to `share_target`. // If the session is not connected, also updates the `certificate` and // `endpoint_id`. // Returns true if the session is not connected and updated successfully. bool UpdateSessionForDedup( const ShareTarget& share_target, std::optional certificate, absl::string_view endpoint_id); // Establish a connection to the remote device identified by `endpoint_info`. // `callback` is called when with the connection establishment status.. void Connect(std::vector endpoint_info, nearby::sharing::proto::DataUsage data_usage, bool disable_wifi_hotspot, std::function callback); // Called to process the result of a connection attempt. // Returns true if the connection was successful. bool OnConnectResult(NearbyConnection* connection, Status status); std::optional ProcessPayloadTransferUpdates(); void SetAdvancedProtectionStatus(bool advanced_protection_enabled, bool advanced_protection_mismatch) { advanced_protection_enabled_ = advanced_protection_enabled; advanced_protection_mismatch_ = advanced_protection_mismatch; } // Returns true if the session is connected or in the process of connecting. bool IsActive() const { return IsConnected() || is_connecting_; } const std::vector& text_payloads() const { return text_payloads_; } const std::vector& wifi_credentials_payloads() const { return wifi_credentials_payloads_; } const std::vector& file_payloads() const { return file_payloads_; } protected: void InvokeTransferUpdateCallback(const TransferMetadata& metadata) override; void OnConnectionDisconnected() override; private: // Calculates transport type based on attachment size. TransportType GetTransportType(bool disable_wifi_hotspot) const; std::optional ExtractNextPayload(); bool FillIntroductionFrame( nearby::sharing::service::proto::IntroductionFrame* introduction) const; void CreateTextPayloads(); void CreateWifiCredentialsPayloads(); // Create file payloads and update the file size of all file attachments. // Returns true if all file payloads are created successfully. bool CreateFilePayloads(); std::optional obfuscated_gaia_id_; // All payloads are in the same order as the attachments in the share target. std::vector text_payloads_; std::vector file_payloads_; std::vector wifi_credentials_payloads_; Status connection_layer_status_ = Status::kUnknown; absl::AnyInvocable transfer_update_callback_; bool ready_for_accept_ = false; // This alarm is used to disconnect the sharing connection if both sides do // not press accept within the timeout. std::unique_ptr mutual_acceptance_timeout_; std::optional pending_complete_metadata_; absl::Time connection_start_time_; // Timeout waiting for remote disconnect in order to complete transfer. std::unique_ptr disconnection_timeout_; bool advanced_protection_enabled_ = false; bool advanced_protection_mismatch_ = false; bool is_connecting_ = false; }; } // namespace nearby::sharing #endif // THIRD_PARTY_NEARBY_SHARING_OUTGOING_SHARE_SESSION_H_