diff options
Diffstat (limited to 'src/components/connection_handler/src/connection_handler_impl.cc')
-rw-r--r-- | src/components/connection_handler/src/connection_handler_impl.cc | 580 |
1 files changed, 468 insertions, 112 deletions
diff --git a/src/components/connection_handler/src/connection_handler_impl.cc b/src/components/connection_handler/src/connection_handler_impl.cc index 5b26304302..478127c42a 100644 --- a/src/components/connection_handler/src/connection_handler_impl.cc +++ b/src/components/connection_handler/src/connection_handler_impl.cc @@ -68,11 +68,14 @@ ConnectionHandlerImpl::ConnectionHandlerImpl( , connection_handler_observer_(NULL) , transport_manager_(tm) , protocol_handler_(NULL) + , session_connection_map_lock_ptr_( + std::make_shared<sync_primitives::RecursiveLock>()) , connection_list_lock_() , connection_handler_observer_lock_() , connection_list_deleter_(&connection_list_) , start_service_context_map_lock_() - , start_service_context_map_() {} + , start_service_context_map_() + , ending_connection_(NULL) {} ConnectionHandlerImpl::~ConnectionHandlerImpl() { LOG4CXX_AUTO_TRACE(logger_); @@ -316,6 +319,7 @@ void ConnectionHandlerImpl::RemoveConnection( bool AllowProtection(const ConnectionHandlerSettings& settings, const protocol_handler::ServiceType& service_type, const bool is_protected) { + LOG4CXX_AUTO_TRACE(logger_); const std::vector<int>& force_unprotected_list = is_protected ? settings.force_unprotected_service() : settings.force_protected_service(); @@ -334,86 +338,42 @@ bool AllowProtection(const ConnectionHandlerSettings& settings, } #endif // ENABLE_SECURITY -uint32_t ConnectionHandlerImpl::OnSessionStartedCallback( +void ConnectionHandlerImpl::OnSessionStartedCallback( const transport_manager::ConnectionUID connection_handle, const uint8_t session_id, const protocol_handler::ServiceType& service_type, const bool is_protected, - uint32_t* hash_id) { + const BsonObject* params) { LOG4CXX_AUTO_TRACE(logger_); - if (hash_id) { - *hash_id = protocol_handler::HASH_ID_WRONG; - } - -#ifdef ENABLE_SECURITY - if (!AllowProtection(get_settings(), service_type, is_protected)) { - return 0; - } -#endif // ENABLE_SECURITY - sync_primitives::AutoReadLock lock(connection_list_lock_); - ConnectionList::iterator it = connection_list_.find(connection_handle); - if (connection_list_.end() == it) { - LOG4CXX_ERROR(logger_, "Unknown connection!"); - return 0; - } - uint32_t new_session_id = 0; + std::vector<std::string> rejected_params; - Connection* connection = it->second; - if ((0 == session_id) && (protocol_handler::kRpc == service_type)) { - new_session_id = connection->AddNewSession(); - if (0 == new_session_id) { - LOG4CXX_ERROR(logger_, "Couldn't start new session!"); - return 0; - } - if (hash_id) { - *hash_id = KeyFromPair(connection_handle, new_session_id); - } - } else { // Could be create new service or protected exists one - if (!connection->AddNewService(session_id, service_type, is_protected)) { - LOG4CXX_ERROR(logger_, - "Couldn't establish " -#ifdef ENABLE_SECURITY - << (is_protected ? "protected" : "non-protected") -#endif // ENABLE_SECURITY - << " service " << static_cast<int>(service_type) - << " for session " << static_cast<int>(session_id)); - return 0; - } - new_session_id = session_id; - if (hash_id) { - *hash_id = protocol_handler::HASH_ID_NOT_SUPPORTED; - } - } - sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); - if (connection_handler_observer_) { - const uint32_t session_key = KeyFromPair(connection_handle, new_session_id); - const bool success = connection_handler_observer_->OnServiceStartedCallback( - connection->connection_device_handle(), session_key, service_type); - if (!success) { + // In case this is a Session running on a Secondary Transport, we need to + // find the Sessions's primary transport. In this case, "connection_handle" + // reflects the secondary transport, which we need for the various callbacks, + // so they can send appropriate Ack or NAK messages on the correct transport. + transport_manager::ConnectionUID primary_connection_handle = + connection_handle; + SessionTransports st = GetSessionTransports(session_id); + if (session_id != 0) { + if (st.primary_transport == 0) { LOG4CXX_WARN(logger_, - "Service starting forbidden by connection_handler_observer"); - if (protocol_handler::kRpc == service_type) { - connection->RemoveSession(new_session_id); - } else { - connection->RemoveService(session_id, service_type); - } - return 0; + "OnSessionStartedCallback could not find Session in the " + "Session/Connection Map!"); + } else { + LOG4CXX_INFO(logger_, + "OnSessionStartedCallback found session " + << static_cast<int>(session_id) + << " with primary connection " + << static_cast<int>(st.primary_transport) + << " and secondary connection " + << static_cast<int>(st.secondary_transport)); + primary_connection_handle = st.primary_transport; } } - return new_session_id; -} -void ConnectionHandlerImpl::OnSessionStartedCallback( - const transport_manager::ConnectionUID connection_handle, - const uint8_t session_id, - const protocol_handler::ServiceType& service_type, - const bool is_protected, - const BsonObject* params) { - LOG4CXX_AUTO_TRACE(logger_); - - std::vector<std::string> rejected_params; - protocol_handler::SessionContext context(connection_handle, + protocol_handler::SessionContext context(primary_connection_handle, + connection_handle, session_id, 0, service_type, @@ -427,7 +387,8 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( } #endif // ENABLE_SECURITY sync_primitives::AutoReadLock lock(connection_list_lock_); - ConnectionList::iterator it = connection_list_.find(connection_handle); + ConnectionList::iterator it = + connection_list_.find(primary_connection_handle); if (connection_list_.end() == it) { LOG4CXX_ERROR(logger_, "Unknown connection!"); protocol_handler_->NotifySessionStarted(context, rejected_params); @@ -439,15 +400,18 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( !connection->SessionServiceExists(session_id, service_type); if ((0 == session_id) && (protocol_handler::kRpc == service_type)) { - context.new_session_id_ = connection->AddNewSession(); + context.new_session_id_ = + connection->AddNewSession(primary_connection_handle); if (0 == context.new_session_id_) { LOG4CXX_ERROR(logger_, "Couldn't start new session!"); protocol_handler_->NotifySessionStarted(context, rejected_params); return; } - context.hash_id_ = KeyFromPair(connection_handle, context.new_session_id_); + context.hash_id_ = + KeyFromPair(primary_connection_handle, context.new_session_id_); } else { // Could be create new service or protected exists one - if (!connection->AddNewService(session_id, service_type, is_protected)) { + if (!connection->AddNewService( + session_id, service_type, is_protected, connection_handle)) { LOG4CXX_ERROR(logger_, "Couldn't establish " #ifdef ENABLE_SECURITY @@ -460,19 +424,16 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( } context.new_session_id_ = session_id; context.hash_id_ = protocol_handler::HASH_ID_NOT_SUPPORTED; + + if (st.secondary_transport == connection_handle) { + sync_primitives::AutoLock auto_lock(session_connection_map_lock_ptr_); + st.secondary_transport_services.push_back(service_type); + } } sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); if (connection_handler_observer_) { const uint32_t session_key = - KeyFromPair(connection_handle, context.new_session_id_); - - uint32_t app_id = 0; - GetDataOnSessionKey( - session_key, &app_id, NULL, static_cast<DeviceHandle*>(NULL)); - if (app_id > 0) { - context.is_ptu_required_ = - !connection_handler_observer_->CheckAppIsNavi(app_id); - } + KeyFromPair(primary_connection_handle, context.new_session_id_); { sync_primitives::AutoLock auto_lock(start_service_context_map_lock_); @@ -509,10 +470,12 @@ void ConnectionHandlerImpl::NotifyServiceStartedResult( start_service_context_map_.erase(it); } + // We need the context's primary connection so we can manage its services list Connection* connection = NULL; { sync_primitives::AutoReadLock lock(connection_list_lock_); - ConnectionList::iterator it = connection_list_.find(context.connection_id_); + ConnectionList::iterator it = + connection_list_.find(context.primary_connection_id_); if (connection_list_.end() == it) { LOG4CXX_ERROR(logger_, "connection not found"); return; @@ -545,6 +508,28 @@ void ConnectionHandlerImpl::OnApplicationFloodCallBack( uint8_t session_id = 0; PairFromKey(connection_key, &connection_handle, &session_id); + // In case this is a Session running on a Secondary Transport, + // "connection_handle" will reflect the active (secondary) transport. + // To close the conneciton and its sessions properly, we need to find + // the Sessions's primary transport/connection. + if (session_id != 0) { + SessionTransports st = GetSessionTransports(session_id); + if (st.primary_transport == 0) { + LOG4CXX_WARN(logger_, + "OnApplicationFloodCallBack could not find Session in the " + "Session/Connection Map!"); + } else { + LOG4CXX_INFO(logger_, + "OnApplicationFloodCallBack found session " + << static_cast<int>(session_id) + << " with primary connection " + << static_cast<int>(st.primary_transport) + << " and secondary connection " + << static_cast<int>(st.secondary_transport)); + connection_handle = st.primary_transport; + } + } + LOG4CXX_INFO(logger_, "Disconnect flooding application"); if (session_id != 0) { CloseSession(connection_handle, session_id, kFlood); @@ -562,6 +547,28 @@ void ConnectionHandlerImpl::OnMalformedMessageCallback( uint8_t session_id = 0; PairFromKey(connection_key, &connection_handle, &session_id); + // In case this is a Session running on a Secondary Transport, + // "connection_handle" will reflect the active (secondary) transport. + // To close the conneciton and its sessions properly, we need to find + // the Sessions's primary transport/connection. + if (session_id != 0) { + SessionTransports st = GetSessionTransports(session_id); + if (st.primary_transport == 0) { + LOG4CXX_WARN(logger_, + "OnMalformedMessageCallback could not find Session in the " + "Session/Connection Map!"); + } else { + LOG4CXX_INFO(logger_, + "OnMalformedMessageCallback found session " + << static_cast<int>(session_id) + << " with primary connection " + << static_cast<int>(st.primary_transport) + << " and secondary connection " + << static_cast<int>(st.secondary_transport)); + connection_handle = st.primary_transport; + } + } + LOG4CXX_INFO(logger_, "Disconnect malformed messaging application"); CloseConnectionSessions(connection_handle, kMalformed); CloseConnection(connection_handle); @@ -570,22 +577,37 @@ void ConnectionHandlerImpl::OnMalformedMessageCallback( uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( const transport_manager::ConnectionUID connection_handle, const uint8_t session_id, - const uint32_t& hashCode, - const protocol_handler::ServiceType& service_type) { - uint32_t hashValue = hashCode; - return OnSessionEndedCallback( - connection_handle, session_id, &hashValue, service_type); -} - -uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( - const transport_manager::ConnectionUID connection_handle, - const uint8_t session_id, uint32_t* hashCode, const protocol_handler::ServiceType& service_type) { LOG4CXX_AUTO_TRACE(logger_); + // In case this is a Session running on a Secondary Transport, we need to + // find the Sessions's primary transport. In this case, "connection_handle" + // reflects the secondary transport, which we need for the various callbacks, + // so they can send appropriate Ack or NAK messages on the correct transport. + transport_manager::ConnectionUID primary_connection_handle = + connection_handle; + if (session_id != 0) { + SessionTransports st = GetSessionTransports(session_id); + if (st.primary_transport == 0) { + LOG4CXX_WARN(logger_, + "OnSessionEndedCallback could not find Session in the " + "Session/Connection Map!"); + } else { + LOG4CXX_INFO(logger_, + "OnSessionEndedCallback found session " + << static_cast<int>(session_id) + << " with primary connection " + << static_cast<int>(st.primary_transport) + << " and secondary connection " + << static_cast<int>(st.secondary_transport)); + primary_connection_handle = st.primary_transport; + } + } + connection_list_lock_.AcquireForReading(); - ConnectionList::iterator it = connection_list_.find(connection_handle); + ConnectionList::iterator it = + connection_list_.find(primary_connection_handle); if (connection_list_.end() == it) { LOG4CXX_WARN(logger_, "Unknown connection!"); connection_list_lock_.Release(); @@ -595,7 +617,8 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( connection_list_lock_.Release(); Connection* connection = connection_item.second; - const uint32_t session_key = KeyFromPair(connection_handle, session_id); + const uint32_t session_key = + KeyFromPair(primary_connection_handle, session_id); if (protocol_handler::kRpc == service_type) { LOG4CXX_INFO(logger_, @@ -638,6 +661,178 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( return session_key; } +bool ConnectionHandlerImpl::OnSecondaryTransportStarted( + transport_manager::ConnectionUID& primary_connection_handle, + const transport_manager::ConnectionUID secondary_connection_handle, + const uint8_t session_id) { + LOG4CXX_AUTO_TRACE(logger_); + + if (session_id == 0) { + LOG4CXX_WARN(logger_, "Session id for secondary transport is invalid"); + return false; + } + + DeviceHandle device_handle; + Connection* connection; + { + sync_primitives::AutoReadLock lock(connection_list_lock_); + ConnectionList::iterator it = + connection_list_.find(secondary_connection_handle); + if (connection_list_.end() == it) { + LOG4CXX_WARN(logger_, + "Unknown connection " << secondary_connection_handle); + return false; + } + + connection = it->second; + device_handle = connection->connection_device_handle(); + } + + // Add the secondary transport connection ID to the SessionConnectionMap + SessionTransports st = + SetSecondaryTransportID(session_id, secondary_connection_handle); + primary_connection_handle = st.primary_transport; + if (st.secondary_transport != secondary_connection_handle) { + LOG4CXX_WARN(logger_, + "Failed setting the session's secondary transport ID"); + return false; + } + + connection->SetPrimaryConnectionHandle(primary_connection_handle); + + const uint32_t session_key = + KeyFromPair(primary_connection_handle, session_id); + + sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); + if (connection_handler_observer_) { + LOG4CXX_TRACE(logger_, + "Calling Connection Handler Observer's " + "OnSecondaryTransportStartedCallback"); + connection_handler_observer_->OnSecondaryTransportStartedCallback( + device_handle, session_key); + } + + return true; +} + +void ConnectionHandlerImpl::OnSecondaryTransportEnded( + const transport_manager::ConnectionUID primary_connection_handle, + const transport_manager::ConnectionUID secondary_connection_handle) { + LOG4CXX_AUTO_TRACE(logger_); + + LOG4CXX_INFO(logger_, + "Secondary Transport: " + << static_cast<int32_t>(secondary_connection_handle) + << " ended. Cleaning up services from primary connection ID " + << static_cast<int32_t>(primary_connection_handle)); + connection_list_lock_.AcquireForReading(); + ConnectionList::iterator itr = + connection_list_.find(primary_connection_handle); + if (connection_list_.end() == itr) { + LOG4CXX_ERROR(logger_, "Primary Connection not found!"); + connection_list_lock_.Release(); + return; + } + Connection* connection = itr->second; + connection_list_lock_.Release(); + + if (connection != NULL) { + std::list<protocol_handler::ServiceType> removed_services_list; + uint8_t session_id = connection->RemoveSecondaryServices( + secondary_connection_handle, removed_services_list); + + if (session_id == 0) { + // The secondary services have already been removed from the primary + // connection, so we find the session associated with this secondary + // transport in the SessionConnectionMap + session_id = + GetSessionIdFromSecondaryTransport(secondary_connection_handle); + } + + if (session_id != 0) { + { + sync_primitives::AutoReadLock read_lock( + connection_handler_observer_lock_); + if (connection_handler_observer_) { + const uint32_t session_key = + KeyFromPair(primary_connection_handle, session_id); + + // Walk the returned list of services and call the ServiceEnded + // callback for each + std::list<protocol_handler::ServiceType>::const_iterator it = + removed_services_list.begin(); + for (; removed_services_list.end() != it; ++it) { + connection_handler_observer_->OnServiceEndedCallback( + session_key, *it, CloseSessionReason::kCommon); + } + + connection_handler_observer_->OnSecondaryTransportEndedCallback( + session_key); + } + } + + // Clear the secondary connection from the Session/Connection map entry + // associated with this session + SetSecondaryTransportID(session_id, 0); + } + } +} + +const std::string +ConnectionHandlerImpl::TransportTypeProfileStringFromConnHandle( + transport_manager::ConnectionUID connection_handle) const { + LOG4CXX_AUTO_TRACE(logger_); + + sync_primitives::AutoReadLock lock(connection_list_lock_); + ConnectionList::const_iterator it = connection_list_.find(connection_handle); + if (connection_list_.end() == it) { + LOG4CXX_WARN(logger_, "Unknown connection " << connection_handle); + return std::string(); + } else { + DeviceHandle device_handle = it->second->connection_device_handle(); + return TransportTypeProfileStringFromDeviceHandle(device_handle); + } +} + +const std::string +ConnectionHandlerImpl::TransportTypeProfileStringFromDeviceHandle( + DeviceHandle device_handle) const { + std::string connection_type; + DeviceMap::const_iterator it = device_list_.find(device_handle); + if (device_list_.end() == it) { + LOG4CXX_ERROR(logger_, "Device not found!"); + } else { + connection_type = it->second.connection_type(); + } + + // Caution: this should be in sync with devicesType map in + // transport_adapter_impl.cc + if (connection_type == "USB_AOA") { + return std::string("AOA_USB"); + } else if (connection_type == "BLUETOOTH") { + return std::string("SPP_BLUETOOTH"); + } else if (connection_type == "USB_IOS") { + return std::string("IAP_USB"); + } else if (connection_type == "BLUETOOTH_IOS") { + return std::string("IAP_BLUETOOTH"); + } else if (connection_type == "WIFI") { + return std::string("TCP_WIFI"); + } else if (connection_type == "USB_IOS_HOST_MODE") { + return std::string("IAP_USB_HOST_MODE"); + } else if (connection_type == "USB_IOS_DEVICE_MODE") { + return std::string("IAP_USB_DEVICE_MODE"); + } else if (connection_type == "CARPLAY_WIRELESS_IOS") { + return std::string("IAP_CARPLAY"); +#ifdef BUILD_TESTS + } else if (connection_type == "BTMAC") { + return std::string("BTMAC"); +#endif + } else { + LOG4CXX_WARN(logger_, "Unknown transport type string: " << connection_type); + return std::string(); + } +} + uint32_t ConnectionHandlerImpl::KeyFromPair( transport_manager::ConnectionUID connection_handle, uint8_t session_id) const { @@ -646,7 +841,7 @@ uint32_t ConnectionHandlerImpl::KeyFromPair( "Key for ConnectionHandle:" << static_cast<uint32_t>(connection_handle) << " Session:" << static_cast<uint32_t>(session_id) - << " is: " << static_cast<uint32_t>(key)); + << " is: 0x" << std::hex << static_cast<uint32_t>(key)); if (protocol_handler::HASH_ID_WRONG == key) { LOG4CXX_ERROR(logger_, "Connection key is WRONG_HASH_ID " @@ -716,18 +911,6 @@ int32_t ConnectionHandlerImpl::GetDataOnSessionKey( return 0; } -int32_t ConnectionHandlerImpl::GetDataOnSessionKey( - uint32_t key, - uint32_t* app_id, - std::list<int32_t>* sessions_list, - uint32_t* device_id) const { - LOG4CXX_AUTO_TRACE(logger_); - DeviceHandle handle; - int32_t result = GetDataOnSessionKey(key, app_id, sessions_list, &handle); - *device_id = static_cast<uint32_t>(handle); - return result; -} - const ConnectionHandlerSettings& ConnectionHandlerImpl::get_settings() const { return settings_; } @@ -741,6 +924,139 @@ DevicesDiscoveryStarter& ConnectionHandlerImpl::get_device_discovery_starter() { return *this; } +// Finds a key not presented in std::map<unsigned char, T> +// Returns 0 if that key not found +namespace { +template <class T> +uint32_t findGap(const std::map<unsigned char, T>& map) { + for (uint32_t i = 1; i <= UCHAR_MAX; ++i) { + if (map.find(i) == map.end()) { + return i; + } + } + return 0; +} +} // namespace + +uint32_t ConnectionHandlerImpl::AddSession( + const transport_manager::ConnectionUID primary_transport_id) { + LOG4CXX_AUTO_TRACE(logger_); + + sync_primitives::AutoLock auto_lock(session_connection_map_lock_ptr_); + const uint32_t session_id = findGap(session_connection_map_); + if (session_id > 0) { + LOG4CXX_INFO(logger_, + "New session ID " << session_id << " and Connection Id " + << static_cast<int>(primary_transport_id) + << " added to Session/Connection Map"); + SessionTransports st; + st.primary_transport = primary_transport_id; + st.secondary_transport = 0; + session_connection_map_[session_id] = st; + } else { + LOG4CXX_WARN(logger_, + "Session/Connection Map could not create a new session ID!!!"); + } + + return session_id; +} + +bool ConnectionHandlerImpl::RemoveSession(uint8_t session_id) { + LOG4CXX_AUTO_TRACE(logger_); + + sync_primitives::AutoLock auto_lock(session_connection_map_lock_ptr_); + SessionConnectionMap::iterator itr = session_connection_map_.find(session_id); + if (session_connection_map_.end() == itr) { + LOG4CXX_WARN(logger_, "Session not found in Session/Connection Map!"); + return false; + } + + LOG4CXX_INFO(logger_, + "Removed Session ID " << static_cast<int>(session_id) + << " from Session/Connection Map"); + session_connection_map_.erase(session_id); + return true; +} + +DataAccessor<SessionConnectionMap> +ConnectionHandlerImpl::session_connection_map() { + return DataAccessor<SessionConnectionMap>(session_connection_map_, + session_connection_map_lock_ptr_); +} + +SessionTransports ConnectionHandlerImpl::SetSecondaryTransportID( + uint8_t session_id, + transport_manager::ConnectionUID secondary_transport_id) { + SessionTransports st; + + sync_primitives::AutoLock auto_lock(session_connection_map_lock_ptr_); + SessionConnectionMap::iterator it = session_connection_map_.find(session_id); + if (session_connection_map_.end() == it) { + LOG4CXX_WARN(logger_, + "SetSecondaryTransportID: session ID " + << static_cast<int>(session_id) + << " not found in Session/Connection map"); + st.primary_transport = 0; + st.secondary_transport = 0; + } else { + st = it->second; + + // The only time we overwrite an existing entry in the map is if the new + // secondary transport ID is kDisabledSecondary, which effectively DISABLES + // the secondary transport feature for the session, or if the new secondary + // transport ID is 0, which means a secondary transport has shut down + if (st.secondary_transport != 0 && + secondary_transport_id != kDisabledSecondary && + secondary_transport_id != 0) { + LOG4CXX_WARN(logger_, + "SetSecondaryTransportID: session ID " + << static_cast<int>(session_id) + << " already has a secondary connection " + << static_cast<int>(st.secondary_transport) + << " in the Session/Connection map"); + } else { + st.secondary_transport = secondary_transport_id; + session_connection_map_[session_id] = st; + } + } + + return st; +} + +const SessionTransports ConnectionHandlerImpl::GetSessionTransports( + uint8_t session_id) const { + SessionTransports st; + sync_primitives::AutoLock auto_lock(session_connection_map_lock_ptr_); + SessionConnectionMap::const_iterator it = + session_connection_map_.find(session_id); + if (session_connection_map_.end() == it) { + st.primary_transport = 0; + st.secondary_transport = 0; + } else { + st = it->second; + } + + return st; +} + +const uint8_t ConnectionHandlerImpl::GetSessionIdFromSecondaryTransport( + transport_manager::ConnectionUID secondary_transport_id) const { + sync_primitives::AutoLock auto_lock(session_connection_map_lock_ptr_); + SessionConnectionMap::const_iterator it = session_connection_map_.begin(); + for (; session_connection_map_.end() != it; it++) { + SessionTransports st = it->second; + if (st.secondary_transport == secondary_transport_id) { + return it->first; + } + } + + LOG4CXX_ERROR(logger_, + "Could not find secondary transport ID " + << static_cast<int>(secondary_transport_id) + << " in the Session/Connection map"); + return 0; +} + struct CompareMAC { explicit CompareMAC(const std::string& mac) : mac_(mac) {} bool operator()(const DeviceMap::value_type& device) { @@ -1117,8 +1433,33 @@ void ConnectionHandlerImpl::SendEndService(uint32_t key, uint8_t service_type) { uint32_t connection_handle = 0; uint8_t session_id = 0; PairFromKey(key, &connection_handle, &session_id); - protocol_handler_->SendEndService( - connection_handle, session_id, service_type); + + // If the service is running on a secondary transport, we need to retrieve + // that transport from the SessionConnection Map + SessionTransports st = GetSessionTransports(session_id); + if (st.primary_transport == 0) { + LOG4CXX_WARN(logger_, + "SendEndService could not find Session in the " + "Session/Connection Map!"); + } else { + LOG4CXX_INFO(logger_, + "SendEndService found session " + << static_cast<int>(session_id) + << " with primary connection " + << static_cast<int>(st.primary_transport) + << " and secondary connection " + << static_cast<int>(st.secondary_transport)); + sync_primitives::AutoLock auto_lock(session_connection_map_lock_ptr_); + auto it = std::find(st.secondary_transport_services.begin(), + st.secondary_transport_services.end(), + service_type); + if (it != st.secondary_transport_services.end()) { + connection_handle = st.secondary_transport; + st.secondary_transport_services.erase(it); + } + protocol_handler_->SendEndService( + st.primary_transport, connection_handle, session_id, service_type); + } } } @@ -1179,12 +1520,16 @@ void ConnectionHandlerImpl::OnConnectionEnded( connection_list_lock_.Release(); return; } - std::auto_ptr<Connection> connection(itr->second); + std::unique_ptr<Connection> connection(itr->second); connection_list_.erase(itr); connection_list_lock_.Release(); sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); if (connection_handler_observer_ && connection.get() != NULL) { + // We have to remember the Connection object we just removed from + // connection_list_, because we will need to retrieve the protocol + // version from it inside of OnServiceEndedCallback + ending_connection_ = connection.get(); const SessionMap session_map = connection->session_map(); for (SessionMap::const_iterator session_it = session_map.begin(); @@ -1201,6 +1546,13 @@ void ConnectionHandlerImpl::OnConnectionEnded( session_key, service_it->service_type, CloseSessionReason::kCommon); } } + ending_connection_ = NULL; + } + + ConnectionHandle primary_connection_handle = + connection->primary_connection_handle(); + if (primary_connection_handle != 0) { + OnSecondaryTransportEnded(primary_connection_handle, connection_id); } } @@ -1241,6 +1593,10 @@ bool ConnectionHandlerImpl::ProtocolVersionUsed( ConnectionList::const_iterator it = connection_list_.find(connection_id); if (connection_list_.end() != it) { return it->second->ProtocolVersion(session_id, protocol_version); + } else if (ending_connection_ && + static_cast<uint32_t>(ending_connection_->connection_handle()) == + connection_id) { + return ending_connection_->ProtocolVersion(session_id, protocol_version); } LOG4CXX_WARN(logger_, "Connection not found !"); return false; |