diff options
Diffstat (limited to 'src/components/connection_handler')
4 files changed, 192 insertions, 29 deletions
diff --git a/src/components/connection_handler/include/connection_handler/connection.h b/src/components/connection_handler/include/connection_handler/connection.h index ca8e550de4..07df9bd943 100644 --- a/src/components/connection_handler/include/connection_handler/connection.h +++ b/src/components/connection_handler/include/connection_handler/connection.h @@ -72,13 +72,18 @@ typedef std::map<int32_t, Connection*> ConnectionList; */ struct Service { protocol_handler::ServiceType service_type; + transport_manager::ConnectionUID connection_id; bool is_protected_; Service() : service_type(protocol_handler::kInvalidServiceType) + , connection_id(0) , is_protected_(false) {} - explicit Service(protocol_handler::ServiceType service_type) - : service_type(service_type), is_protected_(false) {} + explicit Service(protocol_handler::ServiceType service_type, + transport_manager::ConnectionUID connection_id) + : service_type(service_type) + , connection_id(connection_id) + , is_protected_(false) {} bool operator==(const protocol_handler::ServiceType service_type) const { return this->service_type == service_type; @@ -175,7 +180,8 @@ class Connection { */ bool AddNewService(uint8_t session_id, protocol_handler::ServiceType service_type, - const bool is_protected); + const bool is_protected, + transport_manager::ConnectionUID connection_id); /** * @brief Removes service from session * @param session_id session ID @@ -184,6 +190,16 @@ class Connection { */ bool RemoveService(uint8_t session_id, protocol_handler::ServiceType service_type); + + /** + * @brief Removes secondary service from session + * @param secondary_connection_handle connection identifying services to be removed + * \param removed_services_list Returned: List of service types removed + * @return the session ID associated with the services removed + */ + uint8_t RemoveSecondaryServices(transport_manager::ConnectionUID secondary_connection_handle, + std::list<protocol_handler::ServiceType>& removed_services_list); + #ifdef ENABLE_SECURITY /** * @brief Sets crypto context of service @@ -213,10 +229,10 @@ class Connection { const protocol_handler::ServiceType& service_type); #endif // ENABLE_SECURITY - /** - * @brief Returns map of sessions which have been opened in - * current connection. - */ + /** + * @brief Returns map of sessions which have been opened in + * current connection. + */ const SessionMap session_map() const; /** @@ -283,6 +299,20 @@ class Connection { */ bool ProtocolVersion(uint8_t session_id, uint8_t& protocol_version); + /** + * @brief Returns the primary connection handle associated with this connection + * @return ConnectionHandle + */ + ConnectionHandle primary_connection_handle() const; + + /** + * \brief Sets the primary connection handle + * \param primary_connection_handle the primary connection handle to + * associate with this connection + */ + void SetPrimaryConnectionHandle( + ConnectionHandle primary_connection_handle); + private: /** * @brief Current connection handler. @@ -307,6 +337,11 @@ class Connection { mutable sync_primitives::Lock session_map_lock_; /** + * @brief primary connection handle for secondary connections + */ + ConnectionHandle primary_connection_handle_; + + /** * @brief monitor that closes connection if there is no traffic over it */ HeartBeatMonitor* heartbeat_monitor_; diff --git a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h index abd814932b..b6109b59c0 100644 --- a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h +++ b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h @@ -572,13 +572,13 @@ class ConnectionHandlerImpl const uint8_t session_id); /** - * \brief Called when secondary transport with given session ID is removed + * \brief Called when secondary transport shuts down * \param primary_connection_handle Identifier of primary connection - * \param sessionid session ID taken from Register Secondary Transport frame + * \param secondary_connection_handle Identifier of secondary connection transport **/ void OnSecondaryTransportEnded( const transport_manager::ConnectionUID primary_connection_handle, - const uint8_t session_id); + const transport_manager::ConnectionUID secondary_connection_handle); private: /** @@ -591,6 +591,9 @@ class ConnectionHandlerImpl void OnConnectionEnded(const transport_manager::ConnectionUID connection_id); + uint8_t GetSessionIdFromSecondaryTransport( + transport_manager::ConnectionUID secondary_transport_id); + const ConnectionHandlerSettings& settings_; /** * \brief Pointer to observer diff --git a/src/components/connection_handler/src/connection.cc b/src/components/connection_handler/src/connection.cc index cf430aceed..f7a4996e02 100644 --- a/src/components/connection_handler/src/connection.cc +++ b/src/components/connection_handler/src/connection.cc @@ -82,6 +82,7 @@ Connection::Connection(ConnectionHandle connection_handle, , connection_handle_(connection_handle) , connection_device_handle_(connection_device_handle) , session_map_lock_(true) + , primary_connection_handle_(0) , heartbeat_timeout_(heartbeat_timeout) { LOG4CXX_AUTO_TRACE(logger_); DCHECK(connection_handler_); @@ -147,8 +148,8 @@ uint32_t Connection::AddNewSession( sync_primitives::AutoLock lock(session_map_lock_); Session& new_session = session_map_[session_id]; new_session.protocol_version = ::protocol_handler::PROTOCOL_VERSION_2; - new_session.service_list.push_back(Service(protocol_handler::kRpc)); - new_session.service_list.push_back(Service(protocol_handler::kBulk)); + new_session.service_list.push_back(Service(protocol_handler::kRpc, connection_handle)); + new_session.service_list.push_back(Service(protocol_handler::kBulk, connection_handle)); } else { LOG4CXX_WARN(logger_, "Session/Connection Map could not create a new session ID!!!"); } @@ -182,7 +183,8 @@ uint32_t Connection::RemoveSession(uint8_t session_id) { bool Connection::AddNewService(uint8_t session_id, protocol_handler::ServiceType service_type, - const bool request_protection) { + const bool request_protection, + transport_manager::ConnectionUID connection_id) { // Ignore wrong services if (protocol_handler::kControl == service_type || protocol_handler::kInvalidServiceType == service_type) { @@ -192,7 +194,9 @@ bool Connection::AddNewService(uint8_t session_id, LOG4CXX_DEBUG(logger_, "Add service " << service_type << " for session " - << static_cast<uint32_t>(session_id)); + << static_cast<uint32_t>(session_id) + << " using connection ID " + << static_cast<uint32_t>(connection_id)); sync_primitives::AutoLock lock(session_map_lock_); SessionMap::iterator session_it = session_map_.find(session_id); @@ -241,7 +245,7 @@ bool Connection::AddNewService(uint8_t session_id, #endif // ENABLE_SECURITY } // id service is not exists - session.service_list.push_back(Service(service_type)); + session.service_list.push_back(Service(service_type, connection_id)); return true; } @@ -286,6 +290,54 @@ bool Connection::RemoveService(uint8_t session_id, return true; } +uint8_t Connection::RemoveSecondaryServices(transport_manager::ConnectionUID secondary_connection_handle, + std::list<protocol_handler::ServiceType>& removed_services_list) { + LOG4CXX_AUTO_TRACE(logger_); + + uint8_t found_session_id = 0; + sync_primitives::AutoLock lock(session_map_lock_); + + LOG4CXX_INFO(logger_, "RemoveSecondaryServices looking for services on Connection ID " << static_cast<int>(secondary_connection_handle)); + + // Walk the SessionMap in the primary connection, and for each + // Session, we walk its ServiceList, looking for all the services + // that were running on the now-closed Secondary Connection. + for (SessionMap::iterator session_it = session_map_.begin(); + session_map_.end() != session_it; + ++session_it) { + + LOG4CXX_INFO(logger_, "RemoveSecondaryServices found session ID " << static_cast<int>(session_it->first)); + + // Now, for each session, walk the its ServiceList, looking for services + // that were using secondary)_connection_handle. If we find such a service, + // set session_found and break out of the outer loop. + ServiceList& service_list = session_it->second.service_list; + ServiceList::iterator service_it = service_list.begin(); + for ( ; service_it != service_list.end() ; ) { + LOG4CXX_INFO(logger_, "RemoveSecondaryServices found service ID " << static_cast<int>(service_it->service_type)); + if (service_it->connection_id == secondary_connection_handle) { + found_session_id = session_it->first; + + LOG4CXX_INFO(logger_, "RemoveSecondaryServices removing Service " << + static_cast<int>(service_it->service_type) << + " in session " << static_cast<int>(found_session_id)); + + removed_services_list.push_back(service_it->service_type); + service_it = service_list.erase(service_it); + } else { + service_it++; + } + } + + // If we found a session that had services running on the secondary connection, we're done. + if (found_session_id != 0) { + break; + } + } + + return found_session_id; +} + #ifdef ENABLE_SECURITY int Connection::SetSSLContext(uint8_t session_id, security_manager::SSLContext* context) { @@ -445,6 +497,15 @@ bool Connection::ProtocolVersion(uint8_t session_id, return true; } +ConnectionHandle Connection::primary_connection_handle() const { + return primary_connection_handle_; +} + +void Connection::SetPrimaryConnectionHandle( + ConnectionHandle primary_connection_handle) { + primary_connection_handle_ = primary_connection_handle; +} + void Connection::StartHeartBeat(uint8_t session_id) { heartbeat_monitor_->AddSession(session_id); } diff --git a/src/components/connection_handler/src/connection_handler_impl.cc b/src/components/connection_handler/src/connection_handler_impl.cc index c4865ccd53..f69ee0bd00 100644 --- a/src/components/connection_handler/src/connection_handler_impl.cc +++ b/src/components/connection_handler/src/connection_handler_impl.cc @@ -372,7 +372,7 @@ uint32_t ConnectionHandlerImpl::OnSessionStartedCallback( *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)) { + if (!connection->AddNewService(session_id, service_type, is_protected, connection_handle)) { LOG4CXX_ERROR(logger_, "Couldn't establish " #ifdef ENABLE_SECURITY @@ -471,7 +471,7 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( } 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 @@ -724,6 +724,7 @@ bool ConnectionHandlerImpl::OnSecondaryTransportStarted( } DeviceHandle device_handle; + Connection* connection; { sync_primitives::AutoReadLock lock(connection_list_lock_); ConnectionList::iterator it = @@ -734,7 +735,7 @@ bool ConnectionHandlerImpl::OnSecondaryTransportStarted( return false; } - Connection* connection = it->second; + connection = it->second; device_handle = connection->connection_device_handle(); } @@ -742,14 +743,18 @@ bool ConnectionHandlerImpl::OnSecondaryTransportStarted( 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_valid_ && connection_handler_observer_) { + LOG4CXX_TRACE(logger_, "Calling Connection Handler Observer's OnSecondaryTransportStartedCallback"); connection_handler_observer_->OnSecondaryTransportStartedCallback( device_handle, session_key); } @@ -759,21 +764,55 @@ bool ConnectionHandlerImpl::OnSecondaryTransportStarted( void ConnectionHandlerImpl::OnSecondaryTransportEnded( const transport_manager::ConnectionUID primary_connection_handle, - const uint8_t session_id) { + const transport_manager::ConnectionUID secondary_connection_handle) { LOG4CXX_AUTO_TRACE(logger_); - if (session_id == 0) { - LOG4CXX_WARN(logger_, "Session id for secondary transport is invalid"); + 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(); - const uint32_t session_key = - KeyFromPair(primary_connection_handle, session_id); + if (connection != NULL) { + std::list<protocol_handler::ServiceType> removed_services_list; + uint8_t session_id = connection->RemoveSecondaryServices(secondary_connection_handle, removed_services_list); - sync_primitives::AutoReadLock read_lock(connection_handler_observer_lock_); - if (connection_handler_observer_valid_ && connection_handler_observer_) { - connection_handler_observer_->OnSecondaryTransportEndedCallback( - session_key); + 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_valid_ && 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); + } } } @@ -902,8 +941,9 @@ SessionTransports ConnectionHandlerImpl::SetSecondaryTransportID( st = it->second; // The only time we overwrite an existing entry in the map is if the new secondary transport ID - // is 0xFFFFFFFF, which effectively DISABLES the secondary transport feature for the session - if (st.secondary_transport != 0 && secondary_transport_id != 0xFFFFFFFF) { + // is 0xFFFFFFFF, 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 != 0xFFFFFFFF && 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"); @@ -931,6 +971,25 @@ SessionTransports ConnectionHandlerImpl::GetSessionTransports(uint8_t session_id return st; } +uint8_t ConnectionHandlerImpl::GetSessionIdFromSecondaryTransport( + transport_manager::ConnectionUID secondary_transport_id) { + NonConstDataAccessor<SessionConnectionMap> session_connection_map_accessor = session_connection_map(); + SessionConnectionMap& session_connection_map = session_connection_map_accessor.GetData(); + SessionConnectionMap::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) { @@ -1406,6 +1465,11 @@ void ConnectionHandlerImpl::OnConnectionEnded( } ending_connection_ = NULL; } + + ConnectionHandle primary_connection_handle = connection->primary_connection_handle(); + if (primary_connection_handle != 0) { + OnSecondaryTransportEnded(primary_connection_handle, connection_id); + } } void ConnectionHandlerImpl::BindProtocolVersionWithSession( |