summaryrefslogtreecommitdiff
path: root/src/components/connection_handler/src/connection_handler_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/connection_handler/src/connection_handler_impl.cc')
-rw-r--r--src/components/connection_handler/src/connection_handler_impl.cc499
1 files changed, 463 insertions, 36 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..270b38d724 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::Lock>(true))
, 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();
@@ -361,7 +365,7 @@ uint32_t ConnectionHandlerImpl::OnSessionStartedCallback(
Connection* connection = it->second;
if ((0 == session_id) && (protocol_handler::kRpc == service_type)) {
- new_session_id = connection->AddNewSession();
+ new_session_id = connection->AddNewSession(connection_handle);
if (0 == new_session_id) {
LOG4CXX_ERROR(logger_, "Couldn't start new session!");
return 0;
@@ -370,7 +374,8 @@ 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
@@ -413,7 +418,33 @@ void ConnectionHandlerImpl::OnSessionStartedCallback(
LOG4CXX_AUTO_TRACE(logger_);
std::vector<std::string> rejected_params;
- protocol_handler::SessionContext context(connection_handle,
+
+ // 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_,
+ "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;
+ }
+ }
+
+ protocol_handler::SessionContext context(primary_connection_handle,
+ connection_handle,
session_id,
0,
service_type,
@@ -427,7 +458,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 +471,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
@@ -464,15 +499,7 @@ void ConnectionHandlerImpl::OnSessionStartedCallback(
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 +536,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 +574,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 +613,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);
@@ -584,8 +657,33 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback(
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 +693,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 +737,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 +917,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 +987,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 +1000,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 +1509,28 @@ 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));
+
+ protocol_handler_->SendEndService(st.primary_transport,
+ st.secondary_transport,
+ session_id,
+ service_type);
+ }
}
}
@@ -1179,12 +1591,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 +1617,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 +1664,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;