#ifndef CORE_INTERNAL_ENDPOINT_MANAGER_H_ #define CORE_INTERNAL_ENDPOINT_MANAGER_H_ #include #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel.h" #include "core/internal/endpoint_channel_manager.h" #include "proto/connections/offline_wire_formats.pb.h" #include "platform/api/count_down_latch.h" #include "platform/api/submittable_executor.h" #include "platform/api/system_clock.h" #include "platform/api/thread_utils.h" #include "platform/byte_array.h" #include "platform/port/string.h" #include "platform/ptr.h" #include "platform/runnable.h" #include "proto/connections_enums.pb.h" namespace location { namespace nearby { namespace connections { namespace endpoint_manager { template class ReaderRunnable; template class KeepAliveManagerRunnable; template class EndpointChannelLoopRunnable; template class RegisterIncomingOfflineFrameProcessorRunnable; template class UnregisterIncomingOfflineFrameProcessorRunnable; template class RegisterEndpointRunnable; template class UnregisterEndpointRunnable; template class DiscardEndpointRunnable; template class GetOfflineFrameProcessorCallable; } // namespace endpoint_manager // Manages all operations related to the remote endpoints with which we are // interacting. // //

All processing of incoming and outgoing payloads is spread across this and // the PayloadManager as described below. // //

The sending of outgoing payloads originates in // PayloadManager.sendPayload() before control is transferred over to // EndpointManager.sendPayloadChunk(). This work happens on one of three // dedicated writer threads belonging to the PayloadManager. The writer thread // that is used depends on the PayloadType. // //

The EndpointManager has one dedicated reader thread for each registered // endpoint, and the receiving of every incoming payload (and its subsequent // chunks) originates on one of those threads before control is transferred over // to PayloadManager.processIncomingOfflineFrame() (still running on that // same dedicated reader thread). template class EndpointManager { public: class IncomingOfflineFrameProcessor { public: virtual ~IncomingOfflineFrameProcessor() {} // This function takes full ownership of offline_frame. // @EndpointManagerReaderThread virtual void processIncomingOfflineFrame( ConstPtr offline_frame, const string& from_endpoint_id, Ptr > to_client_proxy, proto::connections::Medium current_medium) = 0; // Implementations must call process_disconnection_barrier.countDown() once // they're done. This parallelizes the disconnection event across all frame // processors. // // @EndpointManagerThread virtual void processEndpointDisconnection( Ptr > client_proxy, const string& endpoint_id, Ptr process_disconnection_barrier) = 0; // Operator overloads when comparing Ptr. bool operator==( const typename EndpointManager::IncomingOfflineFrameProcessor& rhs); bool operator<( const typename EndpointManager::IncomingOfflineFrameProcessor& rhs); }; explicit EndpointManager( Ptr > endpoint_channel_manager); ~EndpointManager(); // Invoked from the constructors of the various *Manager components that make // up the OfflineServiceController implementation. void registerIncomingOfflineFrameProcessor( V1Frame::FrameType frame_type, Ptr processor); void unregisterIncomingOfflineFrameProcessor( V1Frame::FrameType frame_type, Ptr processor); // Invoked from the different PCPHandler implementations (of which there can // be only one at a time). void registerEndpoint( Ptr > client_proxy, const string& endpoint_id, const string& endpoint_name, const string& authentication_token, ConstPtr raw_authentication_token, bool is_incoming, Ptr endpoint_channel, Ptr connection_lifecycle_listener); // Called when a client explicitly asks to disconnect from this endpoint. In // this case, we do not notify the client of onDisconnected(). void unregisterEndpoint(Ptr > client_proxy, const string& endpoint_id); // Called when we internally want to get rid of the endpoint, without the // client directly telling us to. For example... // a) We failed to read from the endpoint in its dedicated reader thread. // b) We failed to write to the endpoint in PayloadManager. // c) The connection was rejected in PCPHandler. // d) The dedicated KeepAlive thread exceeded its period of inactivity. // Or in the numerous other cases where a failure occurred and we no longer // believe the endpoint is in a healthy state. // // Note: This must not block. Otherwise we can get into a deadlock where we // ask everyone who's registered an IncomingOfflineFrameProcessor to // processEndpointDisconnection() while the caller of discardEndpoint() is // blocked here. void discardEndpoint(Ptr > client_proxy, const string& endpoint_id); Ptr getOfflineFrameProcessor( V1Frame::FrameType frame_type); // Returns the list of endpoints to which sending this chunk failed. // // Invoked from the PayloadManager's sendPayload() method. std::vector sendPayloadChunk( const PayloadTransferFrame::PayloadHeader& payload_header, const PayloadTransferFrame::PayloadChunk& payload_chunk, const std::vector& endpoint_ids); void sendControlMessage( const PayloadTransferFrame::PayloadHeader& payload_header, const PayloadTransferFrame::ControlMessage& control_message, const std::vector& endpoint_ids); private: template friend class endpoint_manager::ReaderRunnable; template friend class endpoint_manager::KeepAliveManagerRunnable; template friend class endpoint_manager::EndpointChannelLoopRunnable; template friend class endpoint_manager::RegisterIncomingOfflineFrameProcessorRunnable; template friend class endpoint_manager:: UnregisterIncomingOfflineFrameProcessorRunnable; template friend class endpoint_manager::RegisterEndpointRunnable; template friend class endpoint_manager::UnregisterEndpointRunnable; template friend class endpoint_manager::DiscardEndpointRunnable; template friend class endpoint_manager::GetOfflineFrameProcessorCallable; static void waitForLatch(const string& method_name, Ptr latch); static void waitForLatch(const string& method_name, Ptr latch, std::int32_t timeout_millis); template static T waitForResult(const string& method_name, Ptr > result_future); static const std::int32_t kKeepAliveWriteIntervalMillis; static const std::int32_t kKeepAliveReadTimeoutMillis; static const std::int32_t kProcessEndpointDisconnectionTimeoutMillis; static const std::int32_t kMaxConcurrentEndpoints; static const std::int32_t kEndpointIdLength; // It should be noted that this method may be called multiple times (because // invoking this method closes the endpoint channel, which causes the // dedicated reader and KeepAlive threads to terminate, which in turn leads to // this method being called), but that's alright because the implementation of // this method is idempotent. void removeEndpoint(Ptr > client_proxy, const string& endpoint_id, bool send_disconnection_notification); void waitForEndpointDisconnectionProcessing( Ptr > client_proxy, const string& endpoint_id); std::vector sendTransferFrameBytes( const std::vector& endpoint_ids, ConstPtr payload_transfer_frame_bytes, std::int64_t payload_id, std::int64_t offset, const string& packet_type); void startEndpointReader(Ptr runnable); void startEndpointKeepAliveManager(Ptr runnable); void runOnEndpointManagerThread(Ptr runnable); template Ptr > runOnEndpointManagerThread(Ptr > callable); ScopedPtr > thread_utils_; ScopedPtr > system_clock_; Ptr > endpoint_channel_manager_; typedef std::map > IncomingOfflineFrameProcessorsMap; IncomingOfflineFrameProcessorsMap incoming_offline_frame_processors_; ScopedPtr > endpoint_keep_alive_manager_thread_pool_; ScopedPtr > endpoint_readers_thread_pool_; ScopedPtr > serial_executor_; }; } // namespace connections } // namespace nearby } // namespace location #include "core/internal/endpoint_manager.cc" #endif // CORE_INTERNAL_ENDPOINT_MANAGER_H_