#include "core/internal/endpoint_channel_manager.h" #include "core/internal/ble_endpoint_channel.h" #include "core/internal/bluetooth_endpoint_channel.h" #include "core/internal/wifi_lan_endpoint_channel.h" #include "platform/synchronized.h" namespace location { namespace nearby { namespace connections { EndpointChannelManager::EndpointChannelManager( Ptr > medium_manager) : lock_(Platform::createLock()), medium_manager_(medium_manager), channel_state_(new ChannelState()) {} EndpointChannelManager::~EndpointChannelManager() { Synchronized s(lock_.get()); // TODO(tracyzhou): logger.atDebug().log("Initiating shutdown of // EndpointChannelManager.") channel_state_.destroy(); // TODO(tracyzhou): logger.atDebug().log("EndpointChannelManager has shut // down."); } Ptr EndpointChannelManager::createOutgoingBluetoothEndpointChannel( const string& channel_name, Ptr bluetooth_socket) { return BluetoothEndpointChannel::createOutgoing(medium_manager_, channel_name, bluetooth_socket); } Ptr EndpointChannelManager::createIncomingBluetoothEndpointChannel( const string& channel_name, Ptr bluetooth_socket) { return BluetoothEndpointChannel::createIncoming(medium_manager_, channel_name, bluetooth_socket); } Ptr EndpointChannelManager::createOutgoingBLEEndpointChannel( const string& channel_name, Ptr ble_socket) { return BLEEndpointChannel::createOutgoing(medium_manager_, channel_name, ble_socket); } Ptr EndpointChannelManager::createIncomingBLEEndpointChannel( const string& channel_name, Ptr ble_socket) { return BLEEndpointChannel::createIncoming(medium_manager_, channel_name, ble_socket); } Ptr EndpointChannelManager::CreateOutgoingWifiLanEndpointChannel( const string& channel_name, Ptr wifi_lan_socket) { return WifiLanEndpointChannel::CreateOutgoing( medium_manager_, channel_name, wifi_lan_socket); } Ptr EndpointChannelManager::CreateIncomingWifiLanEndpointChannel( const string& channel_name, Ptr wifi_lan_socket) { return WifiLanEndpointChannel::CreateIncoming( medium_manager_, channel_name, wifi_lan_socket); } void EndpointChannelManager::registerChannelForEndpoint( Ptr > client_proxy, const string& endpoint_id, Ptr endpoint_channel) { Synchronized s(lock_.get()); // Just in case there was a previous channel, unregister (and, thus, close) it // now. unregisterChannelForEndpoint(endpoint_id); setActiveEndpointChannel(client_proxy, endpoint_id, endpoint_channel); // TODO(tracyzhou): Add logging. } #ifdef BANDWIDTH_UPGRADE_MANAGER_IMPLEMENTED Ptr EndpointChannelManager::replaceChannelForEndpoint( Ptr > client_proxy, const string& endpoint_id, Ptr endpoint_channel) { Synchronized s(lock_.get()); ScopedPtr > scoped_previous_endpoint_channel( channel_state_->getChannelForEndpoint(endpoint_id)); if (scoped_previous_endpoint_channel.isNull()) { // TODO(tracyzhou): Add logging. return Ptr(); } setActiveEndpointChannel(client_proxy, endpoint_id, endpoint_channel); // TODO(tracyzhou): Add logging. return scoped_previous_endpoint_channel.release(); } #endif bool EndpointChannelManager::encryptChannelForEndpoint( const string& endpoint_id, Ptr encryption_context) { Synchronized s(lock_.get()); ScopedPtr > scoped_endpoint_channel( channel_state_->getChannelForEndpoint(endpoint_id)); if (scoped_endpoint_channel.isNull()) { // TODO(tracyzhou): Add logging. return false; } // We found the requested EndpointChannel, so encrypt it. encryptChannel(endpoint_id, scoped_endpoint_channel.get(), encryption_context); // Then update 'endpoint_id' to use this new 'encryption_context' here // onwards. // // Remember to manage the memory of the returned // Ptr responsibly, even though we don't // need what's returned. ScopedPtr >( channel_state_->updateEncryptionContextForEndpoint(endpoint_id, encryption_context)); return true; } Ptr EndpointChannelManager::getChannelForEndpoint( const string& endpoint_id) { Synchronized s(lock_.get()); return channel_state_->getChannelForEndpoint(endpoint_id); } void EndpointChannelManager::setActiveEndpointChannel( Ptr > client_proxy, const string& endpoint_id, Ptr endpoint_channel) { #ifdef BANDWIDTH_UPGRADE_MANAGER_IMPLEMENTED // If the endpoint is currently encrypted, encrypt this new // 'endpoint_channel'. if (channel_state_->isEndpointEncrypted(endpoint_id)) { encryptChannel( endpoint_id, endpoint_channel, channel_state_->getEncryptionContextForEndpoint(endpoint_id)); } #endif // Then update 'endpoint_id' to use this new 'endpoint_channel' here onwards. // // Remember to manage the memory of the returned Ptr // responsibly, even though we don't need what's returned. ScopedPtr >( channel_state_->updateChannelForEndpoint(endpoint_id, endpoint_channel)); } void EndpointChannelManager::encryptChannel( const string& endpoint_id, Ptr endpoint_channel, Ptr encryption_context) { // TODO(tracyzhou): Add logging. endpoint_channel->enableEncryption(encryption_context); } ///////////////////////////////// ChannelState ///////////////////////////////// EndpointChannelManager::ChannelState::~ChannelState() { while (!endpoint_id_to_metadata_.empty()) { typename EndpointIdToMetadataMap::iterator it = endpoint_id_to_metadata_.begin(); // TODO(tracyzhou): Add logging. removeEndpoint(it->first, proto::connections::DisconnectionReason::SHUTDOWN); } } bool EndpointChannelManager::ChannelState::isEndpointEncrypted( const string& endpoint_id) { return !getEncryptionContextForEndpoint(endpoint_id).isNull(); } Ptr EndpointChannelManager::ChannelState::updateChannelForEndpoint( const string& endpoint_id, Ptr endpoint_channel) { Ptr previous_endpoint_channel; Ptr endpoint_metadata; typename EndpointIdToMetadataMap::iterator it = endpoint_id_to_metadata_.find(endpoint_id); if (it == endpoint_id_to_metadata_.end()) { endpoint_metadata = MakePtr(new EndpointMetaData()); } else { endpoint_metadata = it->second; previous_endpoint_channel = endpoint_metadata->endpoint_channel; } // Avoid leaks. ScopedPtr > scoped_previous_endpoint_channel( previous_endpoint_channel); endpoint_metadata->endpoint_channel = endpoint_channel; endpoint_channel.clear(); endpoint_id_to_metadata_[endpoint_id] = endpoint_metadata; return scoped_previous_endpoint_channel.release(); } Ptr EndpointChannelManager::ChannelState::updateEncryptionContextForEndpoint( const string& endpoint_id, Ptr encryption_context) { Ptr previous_encryption_context; Ptr endpoint_metadata; typename EndpointIdToMetadataMap::iterator it = endpoint_id_to_metadata_.find(endpoint_id); if (it == endpoint_id_to_metadata_.end()) { endpoint_metadata = MakePtr(new EndpointMetaData()); } else { endpoint_metadata = it->second; previous_encryption_context = endpoint_metadata->encryption_context; } // Avoid leaks. ScopedPtr > scoped_previous_encryption_context(previous_encryption_context); endpoint_metadata->encryption_context = encryption_context; endpoint_id_to_metadata_[endpoint_id] = endpoint_metadata; return scoped_previous_encryption_context.release(); } bool EndpointChannelManager::ChannelState::removeEndpoint( const string& endpoint_id, proto::connections::DisconnectionReason reason) { typename EndpointIdToMetadataMap::iterator it = endpoint_id_to_metadata_.find(endpoint_id); if (it == endpoint_id_to_metadata_.end()) { return false; } it->second->endpoint_channel->close(reason); it->second.destroy(); endpoint_id_to_metadata_.erase(it); return true; } Ptr EndpointChannelManager::ChannelState::getEncryptionContextForEndpoint( const string& endpoint_id) { typename EndpointIdToMetadataMap::iterator it = endpoint_id_to_metadata_.find(endpoint_id); if (it == endpoint_id_to_metadata_.end()) { return Ptr(); } return it->second->encryption_context; } Ptr EndpointChannelManager::ChannelState::getChannelForEndpoint( const string& endpoint_id) { typename EndpointIdToMetadataMap::iterator it = endpoint_id_to_metadata_.find(endpoint_id); if (it == endpoint_id_to_metadata_.end()) { return Ptr(); } return it->second->endpoint_channel; } bool EndpointChannelManager::unregisterChannelForEndpoint( const string& endpoint_id) { Synchronized s(lock_.get()); if (!channel_state_->removeEndpoint( endpoint_id, proto::connections::DisconnectionReason::LOCAL_DISCONNECTION)) { return false; } // TODO(tracyzhou): Add logging. return true; } } // namespace connections } // namespace nearby } // namespace location