summaryrefslogtreecommitdiff
path: root/src/components/connection_handler
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/connection_handler')
-rw-r--r--src/components/connection_handler/include/connection_handler/connection.h59
-rw-r--r--src/components/connection_handler/include/connection_handler/connection_handler_impl.h148
-rw-r--r--src/components/connection_handler/include/connection_handler/heartbeat_monitor.h4
-rw-r--r--src/components/connection_handler/src/connection.cc146
-rw-r--r--src/components/connection_handler/src/connection_handler_impl.cc580
-rw-r--r--src/components/connection_handler/src/heartbeat_monitor.cc21
-rw-r--r--src/components/connection_handler/test/connection_handler_impl_test.cc299
-rw-r--r--src/components/connection_handler/test/connection_test.cc178
-rw-r--r--src/components/connection_handler/test/heart_beat_monitor_test.cc226
9 files changed, 1305 insertions, 356 deletions
diff --git a/src/components/connection_handler/include/connection_handler/connection.h b/src/components/connection_handler/include/connection_handler/connection.h
index 9b72d60776..4f900bb65e 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;
@@ -154,9 +159,11 @@ class Connection {
/**
* @brief Adds session to connection
+ * @param connection_handle Connection Handle for the session
* @return new session id or 0 in case of issues
*/
- uint32_t AddNewSession();
+ uint32_t AddNewSession(
+ const transport_manager::ConnectionUID connection_handle);
/**
* @brief Removes session from connection
@@ -171,11 +178,13 @@ class Connection {
* @param session_id session ID
* @param service_type Type of service
* @param is_protected protection state
+ * @param connection_id Connection ID associated with the service
* @return TRUE on success, otherwise FALSE
*/
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 +193,18 @@ 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 +234,11 @@ 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 +305,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.
@@ -304,7 +340,12 @@ class Connection {
*/
SessionMap session_map_;
- mutable sync_primitives::Lock session_map_lock_;
+ mutable sync_primitives::RecursiveLock 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
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 66b2d7cf16..1ab70ce702 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
@@ -54,11 +54,14 @@
#include "utils/stl_utils.h"
#include "utils/rwlock.h"
+const transport_manager::ConnectionUID kDisabledSecondary = 0xFFFFFFFF;
+
/**
* \namespace connection_handler
* \brief SmartDeviceLink connection_handler namespace.
*/
namespace connection_handler {
+
/**
* \class ConnectionHandlerImpl
* \brief SmartDeviceLink connection_handler main class
@@ -193,25 +196,6 @@ class ConnectionHandlerImpl
/**
* \brief Callback function used by ProtocolHandler
* when Mobile Application initiates start of new session.
- * \param connection_handle Connection identifier within which session has to
- * be started.
- * \param session_id Identifier of the session to be started
- * \param service_type Type of service
- * \param is_protected would be service protected
- * \param hash_id pointer for session hash identifier
- * \return uint32_t Id (number) of new session if successful, otherwise 0.
- * \deprecated
- */
- virtual uint32_t 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);
-
- /**
- * \brief Callback function used by ProtocolHandler
- * when Mobile Application initiates start of new session.
* Result must be notified through NotifySessionStartedContext().
* \param connection_handle Connection identifier within which session
* has to be started.
@@ -227,22 +211,7 @@ class ConnectionHandlerImpl
const protocol_handler::ServiceType& service_type,
const bool is_protected,
const BsonObject* params);
- /**
- * \brief Callback function used by ProtocolHandler
- * when Mobile Application initiates session ending.
- * \param connection_handle Connection identifier within which session exists
- * \param sessionId Identifier of the session to be ended
- * \param hashCode Hash used only in second version of SmartDeviceLink
- * protocol.
- * If not equal to hash assigned to session on start then operation fails.
- * \return uint32_t 0 if operation fails, session key otherwise
- * \deprecated
- */
- uint32_t OnSessionEndedCallback(
- const transport_manager::ConnectionUID connection_handle,
- const uint8_t session_id,
- const uint32_t& hashCode,
- const protocol_handler::ServiceType& service_type) OVERRIDE;
+
/**
* \brief Callback function used by ProtocolHandler
* when Mobile Application initiates session ending.
@@ -274,6 +243,24 @@ class ConnectionHandlerImpl
void OnMalformedMessageCallback(const uint32_t& connection_key) OVERRIDE;
/**
+ * @brief Converts connection handle to transport type string used in
+ * smartDeviceLink.ini file, e.g. "TCP_WIFI"
+ * @param connection_handle A connection identifier
+ * @return string representation of the transport of the device
+ */
+ const std::string TransportTypeProfileStringFromConnHandle(
+ transport_manager::ConnectionUID connection_handle) const;
+
+ /**
+ * @brief Converts device handle to transport type string used in
+ * smartDeviceLink.ini file, e.g. "TCP_WIFI"
+ * @param device_handle A device handle
+ * @return string representation of the transport of the device
+ */
+ const std::string TransportTypeProfileStringFromDeviceHandle(
+ DeviceHandle device_handle) const;
+
+ /**
* \brief Creates unique identifier of session (can be used as hash)
* from given connection identifier
* within which session exists and session number.
@@ -503,26 +490,49 @@ class ConnectionHandlerImpl
std::list<int32_t>* sessions_list,
connection_handler::DeviceHandle* device_id) const OVERRIDE;
- /**
- * DEPRECATED
- * \brief information about given Connection Key.
- * \param key Unique key used by other components as session identifier
- * \param app_id Returned: ApplicationID
- * \param sessions_list Returned: List of session keys
- * \param device_id Returned: DeviceID
- * \return int32_t -1 in case of error or 0 in case of success
- */
- int32_t GetDataOnSessionKey(uint32_t key,
- uint32_t* app_id,
- std::list<int32_t>* sessions_list,
- uint32_t* device_id) const OVERRIDE;
-
const ConnectionHandlerSettings& get_settings() const OVERRIDE;
const protocol_handler::SessionObserver& get_session_observer();
DevicesDiscoveryStarter& get_device_discovery_starter();
/**
+ * \brief Add a session. This is meant to be called from Connection class.
+ * \param primary_transport_id the primary connection ID to associate with the
+ * newly created session
+ * \return new session id, or 0 if failed
+ **/
+ uint32_t AddSession(
+ const transport_manager::ConnectionUID primary_transport_id) OVERRIDE;
+
+ /**
+ * \brief Remove a session. This is meant to be called from Connection class.
+ * \param session_id ID of the session to remove
+ * \return true if successful, false otherwise
+ **/
+ bool RemoveSession(uint8_t session_id) OVERRIDE;
+
+ DataAccessor<SessionConnectionMap> session_connection_map() OVERRIDE;
+
+ /**
+ * \brief Associate a secondary transport ID with a session
+ * \param session_id the session ID
+ * \param connection_id the new secondary connection ID to associate with the
+ * session
+ * \return the SessionTransports (newly) associated with the session
+ **/
+ SessionTransports SetSecondaryTransportID(
+ uint8_t session_id,
+ transport_manager::ConnectionUID secondary_transport_id) OVERRIDE;
+
+ /**
+ * \brief Retrieve the session transports associated with a session
+ * \param session_id the session ID
+ * \return the SessionTransports associated with the session
+ **/
+ const SessionTransports GetSessionTransports(
+ uint8_t session_id) const OVERRIDE;
+
+ /**
* \brief Invoked when observer's OnServiceStartedCallback is completed
* \param session_key the key of started session passed to
* OnServiceStartedCallback().
@@ -538,6 +548,28 @@ class ConnectionHandlerImpl
bool result,
std::vector<std::string>& rejected_params);
+ /**
+ * \brief Called when secondary transport with given session ID is established
+ * \param primary_connection_handle Set to identifier of primary connection
+ * \param secondary_connection_handle Identifier of secondary connection
+ * \param sessionid session ID taken from Register Secondary Transport frame
+ **/
+ bool OnSecondaryTransportStarted(
+ transport_manager::ConnectionUID& primary_connection_handle,
+ const transport_manager::ConnectionUID secondary_connection_handle,
+ const uint8_t session_id) OVERRIDE;
+
+ /**
+ * \brief Called when secondary transport shuts down
+ * \param primary_connection_handle Identifier of primary connection
+ * \param secondary_connection_handle Identifier of secondary connection
+ * transport
+ **/
+ void OnSecondaryTransportEnded(
+ const transport_manager::ConnectionUID primary_connection_handle,
+ const transport_manager::ConnectionUID secondary_connection_handle)
+ OVERRIDE;
+
private:
/**
* \brief Disconnect application.
@@ -549,6 +581,9 @@ class ConnectionHandlerImpl
void OnConnectionEnded(const transport_manager::ConnectionUID connection_id);
+ const uint8_t GetSessionIdFromSecondaryTransport(
+ transport_manager::ConnectionUID secondary_transport_id) const;
+
const ConnectionHandlerSettings& settings_;
/**
* \brief Pointer to observer
@@ -568,6 +603,13 @@ class ConnectionHandlerImpl
DeviceMap device_list_;
/**
+ * @brief session/connection map
+ */
+ SessionConnectionMap session_connection_map_;
+ mutable std::shared_ptr<sync_primitives::RecursiveLock>
+ session_connection_map_lock_ptr_;
+
+ /**
* \brief List of connections
*/
ConnectionList connection_list_;
@@ -587,6 +629,11 @@ class ConnectionHandlerImpl
std::map<uint32_t, protocol_handler::SessionContext>
start_service_context_map_;
+ /**
+ * @brief connection object as it's being closed
+ */
+ Connection* ending_connection_;
+
#ifdef BUILD_TESTS
// Methods for test usage
public:
@@ -595,6 +642,9 @@ class ConnectionHandlerImpl
void addDeviceConnection(
const transport_manager::DeviceInfo& device_info,
const transport_manager::ConnectionUID connection_id);
+ SessionConnectionMap& getSessionConnectionMap() {
+ return session_connection_map_;
+ }
#endif
private:
DISALLOW_COPY_AND_ASSIGN(ConnectionHandlerImpl);
diff --git a/src/components/connection_handler/include/connection_handler/heartbeat_monitor.h b/src/components/connection_handler/include/connection_handler/heartbeat_monitor.h
index 4d1d07112c..cf956353dd 100644
--- a/src/components/connection_handler/include/connection_handler/heartbeat_monitor.h
+++ b/src/components/connection_handler/include/connection_handler/heartbeat_monitor.h
@@ -102,7 +102,7 @@ class HeartBeatMonitor : public threads::ThreadDelegate {
void RefreshExpiration();
uint32_t heartbeat_timeout_mseconds_;
- TimevalStruct heartbeat_expiration_;
+ date_time::TimeDuration heartbeat_expiration_;
bool is_heartbeat_sent_;
};
@@ -111,7 +111,7 @@ class HeartBeatMonitor : public threads::ThreadDelegate {
typedef std::map<uint8_t, SessionState> SessionMap;
SessionMap sessions_;
- sync_primitives::Lock sessions_list_lock_; // recurcive
+ sync_primitives::RecursiveLock sessions_list_lock_; // recurcive
sync_primitives::Lock main_thread_lock_;
mutable sync_primitives::Lock heartbeat_timeout_seconds_lock_;
sync_primitives::ConditionalVariable heartbeat_monitor_;
diff --git a/src/components/connection_handler/src/connection.cc b/src/components/connection_handler/src/connection.cc
index 16b88c4164..3f5b0e1901 100644
--- a/src/components/connection_handler/src/connection.cc
+++ b/src/components/connection_handler/src/connection.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Ford Motor Company
+ * Copyright (c) 2018, Ford Motor Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -81,7 +81,7 @@ Connection::Connection(ConnectionHandle connection_handle,
: connection_handler_(connection_handler)
, 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_);
@@ -97,39 +97,62 @@ Connection::~Connection() {
heart_beat_monitor_thread_->join();
delete heartbeat_monitor_;
threads::DeleteThread(heart_beat_monitor_thread_);
- sync_primitives::AutoLock lock(session_map_lock_);
- session_map_.clear();
-}
-// 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;
- }
+ // Before clearing out the session_map_, we must remove all sessions
+ // associated with this Connection from the SessionConnectionMap.
+
+ // NESTED LOCK: make sure to lock session_map_lock_ then ConnectionHandler's
+ // session_connection_map_lock_ptr_ (which will be taken in RemoveSession).
+ sync_primitives::AutoLock lock(session_map_lock_);
+ SessionMap::iterator session_it = session_map_.begin();
+ while (session_it != session_map_.end()) {
+ LOG4CXX_INFO(
+ logger_,
+ "Removed Session ID "
+ << static_cast<int>(session_it->first)
+ << " from Session/Connection Map in Connection Destructor");
+ connection_handler_->RemoveSession(session_it->first);
+ session_it++;
}
- return 0;
+
+ session_map_.clear();
}
-} // namespace
-uint32_t Connection::AddNewSession() {
+uint32_t Connection::AddNewSession(
+ const transport_manager::ConnectionUID connection_handle) {
LOG4CXX_AUTO_TRACE(logger_);
+
+ // NESTED LOCK: make sure to lock session_map_lock_ then ConnectionHandler's
+ // session_connection_map_lock_ptr_ (which will be taken in AddSession)
sync_primitives::AutoLock lock(session_map_lock_);
- const uint32_t session_id = findGap(session_map_);
+
+ // Even though we have our own SessionMap, we use the Connection Handler's
+ // SessionConnectionMap to generate a session ID. We want to make sure that
+ // session IDs are globally unique, and not only unique within a Connection.
+ const uint32_t session_id =
+ connection_handler_->AddSession(connection_handle);
if (session_id > 0) {
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));
}
+
return session_id;
}
uint32_t Connection::RemoveSession(uint8_t session_id) {
+ LOG4CXX_AUTO_TRACE(logger_);
+
+ // Again, a NESTED lock, but it follows the rules.
sync_primitives::AutoLock lock(session_map_lock_);
+
+ if (!connection_handler_->RemoveSession(session_id)) {
+ return 0;
+ }
+
SessionMap::iterator it = session_map_.find(session_id);
if (session_map_.end() == it) {
LOG4CXX_WARN(logger_, "Session not found in this connection!");
@@ -137,12 +160,14 @@ uint32_t Connection::RemoveSession(uint8_t session_id) {
}
heartbeat_monitor_->RemoveSession(session_id);
session_map_.erase(session_id);
+
return 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) {
@@ -152,7 +177,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);
@@ -201,7 +228,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;
}
@@ -246,6 +273,63 @@ 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) {
@@ -346,7 +430,6 @@ const SessionMap Connection::session_map() const {
}
void Connection::CloseSession(uint8_t session_id) {
- size_t size;
{
sync_primitives::AutoLock lock(session_map_lock_);
@@ -354,16 +437,10 @@ void Connection::CloseSession(uint8_t session_id) {
if (session_it == session_map_.end()) {
return;
}
- size = session_map_.size();
}
connection_handler_->CloseSession(
connection_handle_, session_id, connection_handler::kCommon);
-
- // Close connection if it is last session
- if (1 == size) {
- connection_handler_->CloseConnection(connection_handle_);
- }
}
void Connection::UpdateProtocolVersionSession(uint8_t session_id,
@@ -405,6 +482,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 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;
diff --git a/src/components/connection_handler/src/heartbeat_monitor.cc b/src/components/connection_handler/src/heartbeat_monitor.cc
index f3a2322810..4c2d5899af 100644
--- a/src/components/connection_handler/src/heartbeat_monitor.cc
+++ b/src/components/connection_handler/src/heartbeat_monitor.cc
@@ -47,7 +47,6 @@ HeartBeatMonitor::HeartBeatMonitor(uint32_t heartbeat_timeout_mseconds,
Connection* connection)
: default_heartbeat_timeout_(heartbeat_timeout_mseconds)
, connection_(connection)
- , sessions_list_lock_(true)
, run_(true) {}
void HeartBeatMonitor::Process() {
@@ -90,18 +89,20 @@ void HeartBeatMonitor::threadMain() {
}
void HeartBeatMonitor::AddSession(uint8_t session_id) {
- LOG4CXX_DEBUG(logger_,
- "Add session with id " << static_cast<int32_t>(session_id));
+ const uint32_t converted_session_id = static_cast<int32_t>(session_id);
+ UNUSED(converted_session_id);
+ LOG4CXX_DEBUG(logger_, "Add session with id " << converted_session_id);
AutoLock auto_lock(sessions_list_lock_);
if (sessions_.end() != sessions_.find(session_id)) {
LOG4CXX_WARN(logger_,
- "Session with id " << static_cast<int32_t>(session_id)
- << " already exists");
+ "Session with id: " << converted_session_id
+ << " already exists");
return;
}
sessions_.insert(
std::make_pair(session_id, SessionState(default_heartbeat_timeout_)));
- LOG4CXX_INFO(logger_, "Start heartbeat for session " << session_id);
+ LOG4CXX_INFO(logger_,
+ "Start heartbeat for session: " << converted_session_id);
}
void HeartBeatMonitor::RemoveSession(uint8_t session_id) {
@@ -164,8 +165,8 @@ HeartBeatMonitor::SessionState::SessionState(
void HeartBeatMonitor::SessionState::RefreshExpiration() {
LOG4CXX_DEBUG(logger_, "Refresh expiration: " << heartbeat_timeout_mseconds_);
using namespace date_time;
- TimevalStruct time = DateTime::getCurrentTime();
- DateTime::AddMilliseconds(time, heartbeat_timeout_mseconds_);
+ date_time::TimeDuration time = getCurrentTime();
+ AddMilliseconds(time, heartbeat_timeout_mseconds_);
heartbeat_expiration_ = time;
}
@@ -194,8 +195,8 @@ void HeartBeatMonitor::SessionState::KeepAlive() {
}
bool HeartBeatMonitor::SessionState::HasTimeoutElapsed() {
- TimevalStruct now = date_time::DateTime::getCurrentTime();
- return date_time::DateTime::Greater(now, heartbeat_expiration_);
+ date_time::TimeDuration now = date_time::getCurrentTime();
+ return date_time::Greater(now, heartbeat_expiration_);
}
} // namespace connection_handler
diff --git a/src/components/connection_handler/test/connection_handler_impl_test.cc b/src/components/connection_handler/test/connection_handler_impl_test.cc
index d0b9ce4ae4..64de24b103 100644
--- a/src/components/connection_handler/test/connection_handler_impl_test.cc
+++ b/src/components/connection_handler/test/connection_handler_impl_test.cc
@@ -88,7 +88,7 @@ class ConnectionHandlerTest : public ::testing::Test {
mac_address_ = "test_address";
connection_handler_ = new ConnectionHandlerImpl(
- mock_connection_handler_settings, mock_transport_manager_);
+ mock_connection_handler_settings_, mock_transport_manager_);
uid_ = 1u;
connection_key_ = connection_handler_->KeyFromPair(0, 0u);
protected_services_.clear();
@@ -101,23 +101,29 @@ class ConnectionHandlerTest : public ::testing::Test {
void SetSpecificServices() {
#ifdef ENABLE_SECURITY
- ON_CALL(mock_connection_handler_settings, force_protected_service())
+ ON_CALL(mock_connection_handler_settings_, force_protected_service())
.WillByDefault(ReturnRefOfCopy(protected_services_));
- ON_CALL(mock_connection_handler_settings, force_unprotected_service())
+ ON_CALL(mock_connection_handler_settings_, force_unprotected_service())
.WillByDefault(ReturnRefOfCopy(unprotected_services_));
#endif // ENABLE_SECURITY
}
+
// Additional SetUp
void AddTestDeviceConnection() {
const transport_manager::DeviceInfo device_info(
device_handle_, mac_address_, device_name_, connection_type_);
// Add Device and connection
- ON_CALL(mock_connection_handler_settings, heart_beat_timeout())
+ ON_CALL(mock_connection_handler_settings_, heart_beat_timeout())
.WillByDefault(Return(1000u));
connection_handler_->addDeviceConnection(device_info, uid_);
connection_key_ = connection_handler_->KeyFromPair(uid_, 0u);
// Remove all specific services
}
+
+ /**
+ * @brief Adds test session
+ * @return session_id
+ */
void AddTestSession() {
protocol_handler_test::MockProtocolHandler temp_protocol_handler;
connection_handler_->set_protocol_handler(&temp_protocol_handler);
@@ -134,9 +140,11 @@ class ConnectionHandlerTest : public ::testing::Test {
connection_handler_->KeyFromPair(uid_, out_context_.new_session_id_);
CheckSessionExists(uid_, out_context_.new_session_id_);
}
+
uint32_t SessionHash(const uint32_t connection, const uint32_t session) {
return connection_handler_->KeyFromPair(connection, session);
}
+
void AddTestService(ServiceType service_type) {
EXPECT_NE(0u, out_context_.new_session_id_);
EXPECT_EQ(SessionHash(uid_, out_context_.new_session_id_),
@@ -198,10 +206,12 @@ class ConnectionHandlerTest : public ::testing::Test {
}
// Check Service Wrapper
- void CheckServiceExists(const int connectionId,
- const int session_id,
- const ::protocol_handler::ServiceType serviceId,
- const bool exists) {
+ void CheckServiceExists(
+ const int connectionId,
+ const int session_id,
+ const ::protocol_handler::ServiceType serviceId,
+ const ::transport_manager::ConnectionUID serviceConnectionId,
+ const bool exists) {
// Check all trees to find Service and check own protected value
const ConnectionList& connection_list =
connection_handler_->getConnectionList();
@@ -221,6 +231,7 @@ class ConnectionHandlerTest : public ::testing::Test {
std::find(service_list.begin(), service_list.end(), serviceId);
if (exists) {
ASSERT_NE(serv_it, service_list.end());
+ ASSERT_EQ(serv_it->connection_id, serviceConnectionId);
} else {
ASSERT_EQ(serv_it, service_list.end());
}
@@ -306,12 +317,37 @@ class ConnectionHandlerTest : public ::testing::Test {
connection->ProtocolVersion(session_id, check_protocol_version));
EXPECT_EQ(check_protocol_version, protocol_version);
}
+ void AddSecondaryTestService(ServiceType service_type) {
+ EXPECT_NE(0u, out_context_.new_session_id_);
+ EXPECT_EQ(SessionHash(uid_, out_context_.new_session_id_),
+ out_context_.hash_id_);
+ CheckSessionExists(uid_, out_context_.new_session_id_);
+
+ // Set protocol version to 5
+ ChangeProtocol(uid_,
+ out_context_.new_session_id_,
+ protocol_handler::PROTOCOL_VERSION_5);
+
+ connection_handler_test::MockConnectionHandlerObserver
+ temp_connection_handler_observer;
+ connection_handler_->set_connection_handler_observer(
+ &temp_connection_handler_observer);
+ EXPECT_CALL(temp_connection_handler_observer,
+ OnServiceStartedCallback(_, _, service_type, _)).Times(1);
+
+ connection_handler_->OnSessionStartedCallback(2u,
+ out_context_.new_session_id_,
+ service_type,
+ PROTECTION_OFF,
+ static_cast<BsonObject*>(0));
+ connection_handler_->set_connection_handler_observer(NULL);
+ }
ConnectionHandlerImpl* connection_handler_;
testing::NiceMock<transport_manager_test::MockTransportManager>
mock_transport_manager_;
testing::NiceMock<MockConnectionHandlerSettings>
- mock_connection_handler_settings;
+ mock_connection_handler_settings_;
protocol_handler_test::MockProtocolHandler mock_protocol_handler_;
transport_manager::DeviceHandle device_handle_;
transport_manager::ConnectionUID uid_;
@@ -376,23 +412,23 @@ TEST_F(ConnectionHandlerTest, GetAppIdOnSessionKey) {
AddTestSession();
uint32_t app_id = 0;
- const uint32_t testid = SessionHash(uid_, out_context_.new_session_id_);
+ const uint32_t test_id = SessionHash(uid_, out_context_.new_session_id_);
- connection_handler::DeviceHandle null_handle = 0;
+ connection_handler::DeviceHandle* device_id = NULL;
EXPECT_EQ(0,
connection_handler_->GetDataOnSessionKey(
- connection_key_, &app_id, NULL, &null_handle));
- EXPECT_EQ(testid, app_id);
+ connection_key_, &app_id, NULL, device_id));
+ EXPECT_EQ(test_id, app_id);
}
TEST_F(ConnectionHandlerTest, GetAppIdOnSessionKey_SessionNotStarted) {
AddTestDeviceConnection();
uint32_t app_id = 0;
- connection_handler::DeviceHandle null_handle = 0;
+ connection_handler::DeviceHandle* device_id = NULL;
EXPECT_EQ(-1,
connection_handler_->GetDataOnSessionKey(
- connection_key_, &app_id, NULL, &null_handle));
+ connection_key_, &app_id, NULL, device_id));
}
TEST_F(ConnectionHandlerTest, GetDeviceID) {
@@ -500,6 +536,13 @@ TEST_F(ConnectionHandlerTest, GetPairFromKey) {
EXPECT_EQ(out_context_.new_session_id_, session_id);
}
+MATCHER_P(SameDevice, device, "") {
+ return arg.device_handle() == device.device_handle() &&
+ arg.user_friendly_name() == device.user_friendly_name() &&
+ arg.mac_address() == device.mac_address() &&
+ arg.connection_type() == device.connection_type();
+}
+
TEST_F(ConnectionHandlerTest, IsHeartBeatSupported) {
AddTestDeviceConnection();
AddTestSession();
@@ -508,17 +551,10 @@ TEST_F(ConnectionHandlerTest, IsHeartBeatSupported) {
uid_, out_context_.new_session_id_));
}
-MATCHER_P(SameDevice, device, "") {
- return arg.device_handle() == device.device_handle() &&
- arg.user_friendly_name() == device.user_friendly_name() &&
- arg.mac_address() == device.mac_address() &&
- arg.connection_type() == device.connection_type();
-}
-
TEST_F(ConnectionHandlerTest, SendEndServiceWithoutSetProtocolHandler) {
AddTestDeviceConnection();
AddTestSession();
- EXPECT_CALL(mock_protocol_handler_, SendEndService(_, _, kRpc)).Times(0);
+ EXPECT_CALL(mock_protocol_handler_, SendEndService(_, _, _, kRpc)).Times(0);
connection_handler_->SendEndService(connection_key_, kRpc);
}
@@ -526,7 +562,7 @@ TEST_F(ConnectionHandlerTest, SendEndService) {
AddTestDeviceConnection();
AddTestSession();
connection_handler_->set_protocol_handler(&mock_protocol_handler_);
- EXPECT_CALL(mock_protocol_handler_, SendEndService(_, _, kRpc));
+ EXPECT_CALL(mock_protocol_handler_, SendEndService(_, _, _, kRpc));
connection_handler_->SendEndService(connection_key_, kRpc);
}
@@ -1112,7 +1148,7 @@ TEST_F(ConnectionHandlerTest, StartService_withServices) {
PROTECTION_OFF,
static_cast<BsonObject*>(NULL));
EXPECT_NE(0u, audio_context.new_session_id_);
- CheckServiceExists(uid_, audio_context.new_session_id_, kAudio, true);
+ CheckServiceExists(uid_, audio_context.new_session_id_, kAudio, uid_, true);
EXPECT_EQ(protocol_handler::HASH_ID_NOT_SUPPORTED, audio_context.hash_id_);
// Start Audio service
@@ -1122,7 +1158,8 @@ TEST_F(ConnectionHandlerTest, StartService_withServices) {
PROTECTION_OFF,
static_cast<BsonObject*>(NULL));
EXPECT_NE(0u, video_context.new_session_id_);
- CheckServiceExists(uid_, video_context.new_session_id_, kMobileNav, true);
+ CheckServiceExists(
+ uid_, video_context.new_session_id_, kMobileNav, uid_, true);
EXPECT_EQ(protocol_handler::HASH_ID_NOT_SUPPORTED, video_context.hash_id_);
connection_handler_->set_protocol_handler(NULL);
@@ -1150,7 +1187,8 @@ TEST_F(ConnectionHandlerTest, StartService_withServices_withParams) {
PROTECTION_OFF,
dummy_param);
EXPECT_EQ(out_context_.new_session_id_, video_context.new_session_id_);
- CheckServiceExists(uid_, out_context_.new_session_id_, kMobileNav, true);
+ CheckServiceExists(
+ uid_, out_context_.new_session_id_, kMobileNav, uid_, true);
EXPECT_EQ(protocol_handler::HASH_ID_NOT_SUPPORTED, video_context.hash_id_);
connection_handler_->set_protocol_handler(NULL);
@@ -1174,7 +1212,7 @@ TEST_F(ConnectionHandlerTest, ServiceStop_UnExistService) {
connection_handler_->OnSessionEndedCallback(
uid_, out_context_.new_session_id_, &dummy_hash, kAudio);
EXPECT_EQ(0u, end_session_result);
- CheckServiceExists(uid_, out_context_.new_session_id_, kAudio, false);
+ CheckServiceExists(uid_, out_context_.new_session_id_, kAudio, uid_, false);
}
TEST_F(ConnectionHandlerTest, ServiceStop) {
@@ -1204,7 +1242,7 @@ TEST_F(ConnectionHandlerTest, ServiceStop) {
connection_handler_->OnSessionEndedCallback(
uid_, out_context_.new_session_id_, &some_hash_id, kAudio);
EXPECT_EQ(connection_key_, end_session_result);
- CheckServiceExists(uid_, out_context_.new_session_id_, kAudio, false);
+ CheckServiceExists(uid_, out_context_.new_session_id_, kAudio, uid_, false);
}
}
@@ -1235,8 +1273,8 @@ TEST_F(ConnectionHandlerTest, SessionStop_CheckSpecificHash) {
for (uint32_t session = 0; session < 0xFF; ++session) {
AddTestSession();
- uint32_t wrong_hash = protocol_handler::HASH_ID_WRONG;
- uint32_t hash = protocol_handler::HASH_ID_NOT_SUPPORTED;
+ uint32_t hash = connection_key_;
+ uint32_t wrong_hash = hash + 1;
const uint32_t end_audio_wrong_hash =
connection_handler_->OnSessionEndedCallback(
@@ -1273,9 +1311,6 @@ TEST_F(ConnectionHandlerTest, SessionStarted_WithRpc) {
true,
ByRef(empty)));
- EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_))
- .WillOnce(Return(true));
-
connection_handler_->set_protocol_handler(&mock_protocol_handler_);
EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _))
.WillOnce(SaveArg<0>(&out_context_));
@@ -1312,8 +1347,6 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_SUCCESS) {
session_key,
true,
ByRef(empty)));
- EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_))
- .WillOnce(Return(true));
// confirm that NotifySessionStarted() is called
connection_handler_->set_protocol_handler(&mock_protocol_handler_);
@@ -1354,8 +1387,6 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_FAILURE) {
session_key,
false,
ByRef(empty)));
- EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_))
- .WillOnce(Return(true));
// confirm that NotifySessionStarted() is called
connection_handler_->set_protocol_handler(&mock_protocol_handler_);
@@ -1446,9 +1477,6 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_Multiple) {
session_key1,
true,
ByRef(empty))));
- EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_))
- .Times(2)
- .WillRepeatedly(Return(true));
// verify that connection handler will not mix up the two results
SessionContext new_context_first, new_context_second;
@@ -1474,7 +1502,7 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_Multiple) {
TEST_F(ConnectionHandlerTest,
SessionStarted_StartSession_SecureSpecific_Unprotect) {
- EXPECT_CALL(mock_connection_handler_settings, heart_beat_timeout())
+ EXPECT_CALL(mock_connection_handler_settings_, heart_beat_timeout())
.WillOnce(Return(heartbeat_timeout));
// Add virtual device and connection
AddTestDeviceConnection();
@@ -2013,6 +2041,193 @@ TEST_F(ConnectionHandlerTest, OnDeviceConnectionSwitching) {
connection_handler_->OnDeviceSwitchingStart(mac_address_, second_mac_address);
}
+TEST_F(ConnectionHandlerTest, StartStopSecondarySession) {
+ // Add virtual device and connection
+ AddTestDeviceConnection();
+ // Start new session with RPC service
+ AddTestSession();
+
+ connection_handler_test::MockConnectionHandlerObserver
+ mock_connection_handler_observer;
+ connection_handler_->set_connection_handler_observer(
+ &mock_connection_handler_observer);
+
+ // Start a session on a secondary transport
+ const transport_manager::DeviceInfo secondary_device_info(
+ device_handle_, mac_address_, device_name_, std::string("WIFI"));
+ const transport_manager::ConnectionUID secondary_uid = 2u;
+ // Add Device and connection
+ ON_CALL(mock_connection_handler_settings_, heart_beat_timeout())
+ .WillByDefault(Return(1000u));
+ connection_handler_->addDeviceConnection(secondary_device_info,
+ secondary_uid);
+
+ EXPECT_CALL(mock_connection_handler_observer,
+ OnSecondaryTransportStartedCallback(device_handle_, _)).Times(1);
+
+ connection_handler_->OnSecondaryTransportStarted(
+ uid_, secondary_uid, out_context_.new_session_id_);
+
+ SessionTransports st =
+ connection_handler_->GetSessionTransports(out_context_.new_session_id_);
+ EXPECT_EQ(st.primary_transport, uid_);
+ EXPECT_EQ(st.secondary_transport, secondary_uid);
+
+ AddSecondaryTestService(kAudio);
+ AddSecondaryTestService(kMobileNav);
+
+ CheckServiceExists(
+ uid_, out_context_.new_session_id_, kAudio, secondary_uid, true);
+ CheckServiceExists(
+ uid_, out_context_.new_session_id_, kMobileNav, secondary_uid, true);
+
+ connection_handler_->set_connection_handler_observer(
+ &mock_connection_handler_observer);
+ EXPECT_CALL(mock_connection_handler_observer,
+ OnSecondaryTransportEndedCallback(_)).Times(1);
+ EXPECT_CALL(mock_connection_handler_observer,
+ OnServiceEndedCallback(_, kAudio, _)).Times(1);
+ EXPECT_CALL(mock_connection_handler_observer,
+ OnServiceEndedCallback(_, kMobileNav, _)).Times(1);
+
+ connection_handler_->OnSecondaryTransportEnded(uid_, secondary_uid);
+
+ st = connection_handler_->GetSessionTransports(out_context_.new_session_id_);
+ EXPECT_EQ(st.primary_transport, uid_);
+ EXPECT_EQ(st.secondary_transport, 0u);
+
+ CheckServiceExists(
+ uid_, out_context_.new_session_id_, kAudio, secondary_uid, false);
+ CheckServiceExists(
+ uid_, out_context_.new_session_id_, kMobileNav, secondary_uid, false);
+}
+
+TEST_F(ConnectionHandlerTest, StopSecondarySession_NoService) {
+ AddTestDeviceConnection();
+ AddTestSession();
+
+ connection_handler_test::MockConnectionHandlerObserver
+ mock_connection_handler_observer;
+ connection_handler_->set_connection_handler_observer(
+ &mock_connection_handler_observer);
+
+ const transport_manager::DeviceInfo secondary_device_info(
+ device_handle_, mac_address_, device_name_, std::string("WIFI"));
+ const transport_manager::ConnectionUID secondary_uid = 123u;
+ ON_CALL(mock_connection_handler_settings_, heart_beat_timeout())
+ .WillByDefault(Return(1000u));
+ connection_handler_->addDeviceConnection(secondary_device_info,
+ secondary_uid);
+
+ EXPECT_CALL(mock_connection_handler_observer,
+ OnSecondaryTransportStartedCallback(device_handle_, _)).Times(1);
+ connection_handler_->OnSecondaryTransportStarted(
+ uid_, secondary_uid, out_context_.new_session_id_);
+
+ // check if OnSecondaryTransportEndedCallback is triggered with correct
+ // session ID even if we don't have any services
+ EXPECT_CALL(mock_connection_handler_observer,
+ OnSecondaryTransportEndedCallback(_));
+ EXPECT_CALL(mock_connection_handler_observer, OnServiceEndedCallback(_, _, _))
+ .Times(0);
+
+ connection_handler_->OnSecondaryTransportEnded(uid_, secondary_uid);
+
+ SessionTransports st =
+ connection_handler_->GetSessionTransports(out_context_.new_session_id_);
+ EXPECT_EQ(st.primary_transport, uid_);
+ EXPECT_EQ(st.secondary_transport, 0u);
+}
+
+TEST_F(ConnectionHandlerTest, ConnectionType_valid) {
+ AddTestDeviceConnection();
+ AddTestSession();
+
+ std::string ret =
+ connection_handler_->TransportTypeProfileStringFromConnHandle(uid_);
+ EXPECT_EQ(connection_type_, ret);
+}
+
+TEST_F(ConnectionHandlerTest, ConnectionType_invalid) {
+ AddTestDeviceConnection();
+
+ transport_manager::ConnectionUID invalid_uid = 12345;
+ ASSERT_TRUE(invalid_uid != uid_);
+ std::string ret =
+ connection_handler_->TransportTypeProfileStringFromConnHandle(
+ invalid_uid);
+ EXPECT_EQ(std::string(), ret);
+}
+
+TEST_F(ConnectionHandlerTest, SetSecondaryTransportID_UpdateSuccess) {
+ uint8_t session_id = 123;
+ transport_manager::ConnectionUID primary_uid = 100;
+ transport_manager::ConnectionUID secondary_uid = 0;
+
+ SessionConnectionMap& session_connection_map =
+ connection_handler_->getSessionConnectionMap();
+ // secondary transport's ID is 0
+ SessionTransports st = {primary_uid, secondary_uid};
+ session_connection_map[session_id] = st;
+
+ secondary_uid = 200;
+ st = connection_handler_->SetSecondaryTransportID(session_id, secondary_uid);
+ EXPECT_EQ(primary_uid, st.primary_transport);
+ EXPECT_EQ(secondary_uid, st.secondary_transport);
+}
+
+TEST_F(ConnectionHandlerTest, SetSecondaryTransportID_UpdateFailure) {
+ uint8_t session_id = 123;
+ transport_manager::ConnectionUID primary_uid = 100;
+ transport_manager::ConnectionUID secondary_uid = 300;
+
+ SessionConnectionMap& session_connection_map =
+ connection_handler_->getSessionConnectionMap();
+ // secondary transport's ID is already assigned
+ SessionTransports st = {primary_uid, secondary_uid};
+ session_connection_map[session_id] = st;
+
+ st = connection_handler_->SetSecondaryTransportID(session_id, 500);
+ EXPECT_EQ(primary_uid, st.primary_transport);
+ // secondary transport's ID is NOT updated
+ EXPECT_EQ(secondary_uid, st.secondary_transport);
+}
+
+TEST_F(ConnectionHandlerTest, SetSecondaryTransportID_OverwirteSecondaryUID) {
+ uint8_t session_id = 123;
+ transport_manager::ConnectionUID primary_uid = 200;
+ transport_manager::ConnectionUID secondary_uid = 500;
+
+ SessionConnectionMap& session_connection_map =
+ connection_handler_->getSessionConnectionMap();
+ SessionTransports st = {primary_uid, secondary_uid};
+ session_connection_map[session_id] = st;
+
+ secondary_uid = kDisabledSecondary;
+ st = connection_handler_->SetSecondaryTransportID(session_id, secondary_uid);
+ EXPECT_EQ(primary_uid, st.primary_transport);
+ // secondary transport's ID is updated
+ EXPECT_EQ(secondary_uid, st.secondary_transport);
+}
+
+TEST_F(ConnectionHandlerTest, SetSecondaryTransportID_Failure) {
+ uint8_t session_id = 123;
+ transport_manager::ConnectionUID primary_uid = 100;
+ transport_manager::ConnectionUID secondary_uid = 0;
+
+ SessionConnectionMap& session_connection_map =
+ connection_handler_->getSessionConnectionMap();
+ SessionTransports st = {primary_uid, secondary_uid};
+ session_connection_map[session_id] = st;
+
+ uint8_t invalid_session_id = 10;
+ secondary_uid = 300;
+ st = connection_handler_->SetSecondaryTransportID(invalid_session_id,
+ secondary_uid);
+ EXPECT_EQ(0u, st.primary_transport);
+ EXPECT_EQ(0u, st.secondary_transport);
+}
+
} // namespace connection_handler_test
} // namespace components
} // namespace test
diff --git a/src/components/connection_handler/test/connection_test.cc b/src/components/connection_handler/test/connection_test.cc
index de21dd1e97..98b83f5fc4 100644
--- a/src/components/connection_handler/test/connection_test.cc
+++ b/src/components/connection_handler/test/connection_test.cc
@@ -36,6 +36,7 @@
#include "protocol/common.h"
#include "connection_handler/connection.h"
+#include "connection_handler/mock_connection_handler.h"
#include "connection_handler/connection_handler_impl.h"
#include "protocol/service_type.h"
#include "connection_handler/mock_connection_handler_settings.h"
@@ -56,6 +57,8 @@ namespace connection_handler_test {
using namespace ::connection_handler;
using namespace ::protocol_handler;
+using ::testing::Return;
+
class ConnectionTest : public ::testing::Test {
protected:
void SetUp() OVERRIDE {
@@ -78,7 +81,7 @@ class ConnectionTest : public ::testing::Test {
session_id, protocol_handler::PROTOCOL_VERSION_3);
}
void StartDefaultSession() {
- session_id = connection_->AddNewSession();
+ session_id = connection_->AddNewSession(kDefaultConnectionHandle);
EXPECT_NE(session_id, 0u);
const SessionMap sessionMap = connection_->session_map();
EXPECT_FALSE(sessionMap.empty());
@@ -88,13 +91,14 @@ class ConnectionTest : public ::testing::Test {
std::find(serviceList.begin(), serviceList.end(), kRpc);
const bool found_result = (it != serviceList.end());
EXPECT_TRUE(found_result);
+ EXPECT_EQ(connection_->primary_connection_handle(), 0);
}
void AddNewService(const ServiceType service_type,
const bool protection,
const bool expect_add_new_service_call_result,
const bool expect_exist_service) {
- const bool result =
- connection_->AddNewService(session_id, service_type, protection);
+ const bool result = connection_->AddNewService(
+ session_id, service_type, protection, kDefaultConnectionHandle);
EXPECT_EQ(result, expect_add_new_service_call_result);
#ifdef ENABLE_SECURITY
@@ -110,12 +114,35 @@ class ConnectionTest : public ::testing::Test {
std::find(newServiceList.begin(), newServiceList.end(), service_type);
const bool found_result = it != newServiceList.end();
EXPECT_EQ(expect_exist_service, found_result);
-#ifdef ENABLE_SECURITY
if (found_result) {
const Service& service = *it;
+ transport_manager::ConnectionUID expected_connection_handle =
+ kDefaultConnectionHandle;
+ EXPECT_EQ(service.connection_id, expected_connection_handle);
+#ifdef ENABLE_SECURITY
EXPECT_EQ(service.is_protected_, protection);
- }
#endif // ENABLE_SECURITY
+ }
+ }
+ void AddNewSecondaryService(const ServiceType service_type) {
+ const bool result = connection_->AddNewService(
+ session_id, service_type, false, kSecondaryConnectionHandle);
+ EXPECT_EQ(result, true);
+
+ const SessionMap session_map = connection_->session_map();
+ EXPECT_FALSE(session_map.empty());
+ const ServiceList newServiceList = session_map.begin()->second.service_list;
+ EXPECT_FALSE(newServiceList.empty());
+ const ServiceList::const_iterator it =
+ std::find(newServiceList.begin(), newServiceList.end(), service_type);
+ const bool found_result = it != newServiceList.end();
+ EXPECT_TRUE(found_result);
+ if (found_result) {
+ const Service& service = *it;
+ transport_manager::ConnectionUID expected_secondary_connection_handle =
+ kSecondaryConnectionHandle;
+ EXPECT_EQ(service.connection_id, expected_secondary_connection_handle);
+ }
}
void RemoveService(const ServiceType service_type,
@@ -141,6 +168,8 @@ class ConnectionTest : public ::testing::Test {
transport_manager_mock;
ConnectionHandlerImpl* connection_handler_;
uint32_t session_id;
+ static const transport_manager::ConnectionUID kDefaultConnectionHandle = 1;
+ static const transport_manager::ConnectionUID kSecondaryConnectionHandle = 2;
};
TEST_F(ConnectionTest, Session_TryGetProtocolVersionWithoutSession) {
@@ -236,13 +265,17 @@ TEST_F(ConnectionTest, HeartBeat_Protocol5_ZeroHeartBeat_NotSupported) {
// Try to add service without session
TEST_F(ConnectionTest, Session_AddNewServiceWithoutSession) {
- EXPECT_EQ(connection_->AddNewService(session_id, kAudio, true),
+ EXPECT_EQ(connection_->AddNewService(
+ session_id, kAudio, true, kDefaultConnectionHandle),
EXPECT_RETURN_FALSE);
- EXPECT_EQ(connection_->AddNewService(session_id, kAudio, false),
+ EXPECT_EQ(connection_->AddNewService(
+ session_id, kAudio, false, kDefaultConnectionHandle),
EXPECT_RETURN_FALSE);
- EXPECT_EQ(connection_->AddNewService(session_id, kMobileNav, true),
+ EXPECT_EQ(connection_->AddNewService(
+ session_id, kMobileNav, true, kDefaultConnectionHandle),
EXPECT_RETURN_FALSE);
- EXPECT_EQ(connection_->AddNewService(session_id, kMobileNav, false),
+ EXPECT_EQ(connection_->AddNewService(
+ session_id, kMobileNav, false, kDefaultConnectionHandle),
EXPECT_RETURN_FALSE);
}
@@ -409,6 +442,133 @@ TEST_F(ConnectionTest, RemoveSession) {
EXPECT_EQ(0u, connection_->RemoveSession(session_id));
}
+TEST_F(ConnectionTest, AddNewSession_VerifyAddSessionCalled) {
+ MockConnectionHandler mock_connection_handler;
+
+ ConnectionHandle connection_handle = 123;
+ DeviceHandle device_handle = 0u;
+ uint32_t heart_beat = 10000u;
+ Connection* connection = new Connection(
+ connection_handle, device_handle, &mock_connection_handler, heart_beat);
+
+ transport_manager::ConnectionUID connection_handle_uid = 1;
+ uint32_t mock_session_id = 2;
+ EXPECT_CALL(mock_connection_handler, AddSession(connection_handle_uid))
+ .WillOnce(Return(mock_session_id));
+
+ uint32_t sid = connection->AddNewSession(connection_handle_uid);
+ EXPECT_EQ(mock_session_id, sid);
+
+ EXPECT_CALL(mock_connection_handler, RemoveSession(mock_session_id))
+ .WillOnce(Return(true)); // invoked by destructor of connection
+ delete connection;
+}
+
+TEST_F(ConnectionTest, RemoveSession_VerifyRemoveSessionCalled) {
+ MockConnectionHandler mock_connection_handler;
+
+ ConnectionHandle connection_handle = 123;
+ DeviceHandle device_handle = 0u;
+ uint32_t heart_beat = 10000u;
+ Connection* connection = new Connection(
+ connection_handle, device_handle, &mock_connection_handler, heart_beat);
+
+ transport_manager::ConnectionUID connection_handle_uid = 1;
+ uint32_t mock_session_id = 10;
+ EXPECT_CALL(mock_connection_handler, AddSession(connection_handle_uid))
+ .WillOnce(Return(mock_session_id));
+ EXPECT_CALL(mock_connection_handler,
+ RemoveSession(static_cast<uint8_t>(mock_session_id)))
+ .WillOnce(Return(true));
+
+ uint32_t sid = connection->AddNewSession(connection_handle_uid);
+
+ uint32_t ret = connection->RemoveSession(sid);
+ EXPECT_EQ(sid, ret);
+
+ delete connection;
+}
+
+TEST_F(ConnectionTest, SecondarySessionTest) {
+ StartSession();
+ AddNewService(
+ kRpc, PROTECTION_OFF, EXPECT_RETURN_FALSE, EXPECT_SERVICE_EXISTS);
+
+ const ConnectionHandle connectionHandle = 0;
+ const DeviceHandle device_handle = 0u;
+ const uint32_t heart_beat = 0u;
+ Connection* secondary_connection = new Connection(
+ connectionHandle, device_handle, connection_handler_, heart_beat);
+
+ secondary_connection->SetPrimaryConnectionHandle(kDefaultConnectionHandle);
+ connection_handler::ConnectionHandle expected_primary_connection_handle =
+ kDefaultConnectionHandle;
+ EXPECT_EQ(secondary_connection->primary_connection_handle(),
+ expected_primary_connection_handle);
+
+ AddNewSecondaryService(kAudio);
+ AddNewSecondaryService(kMobileNav);
+
+ delete secondary_connection;
+}
+
+TEST_F(ConnectionTest, RemoveSecondaryServices_SUCCESS) {
+ StartSession();
+
+ ServiceType services[2] = {kMobileNav, kAudio};
+ AddNewSecondaryService(services[0]);
+ AddNewSecondaryService(services[1]);
+ size_t services_count = sizeof(services) / sizeof(services[0]);
+
+ std::list<ServiceType> removed_services;
+ uint8_t ret_session_id = connection_->RemoveSecondaryServices(
+ kSecondaryConnectionHandle, removed_services);
+
+ // check return value
+ EXPECT_EQ(session_id, ret_session_id);
+ // check returned list
+ EXPECT_EQ(services_count, removed_services.size());
+ std::list<protocol_handler::ServiceType>::iterator it;
+ it = std::find(removed_services.begin(), removed_services.end(), services[0]);
+ EXPECT_TRUE(it != removed_services.end());
+ it = std::find(removed_services.begin(), removed_services.end(), services[1]);
+ EXPECT_TRUE(it != removed_services.end());
+}
+
+TEST_F(ConnectionTest, RemoveSecondaryServices_NoService) {
+ StartSession();
+ /* do not call AddNewSecondaryService() */
+
+ std::list<ServiceType> removed_services;
+ uint8_t ret_session_id = connection_->RemoveSecondaryServices(
+ kSecondaryConnectionHandle, removed_services);
+
+ // check return value
+ EXPECT_EQ(0, ret_session_id);
+ // check returned list
+ EXPECT_EQ(0u, removed_services.size());
+}
+
+TEST_F(ConnectionTest, RemoveSecondaryServices_InvalidConnectionHandle) {
+ StartSession();
+
+ ServiceType services[2] = {kMobileNav, kAudio};
+ AddNewSecondaryService(services[0]);
+ AddNewSecondaryService(services[1]);
+
+ transport_manager::ConnectionUID invalid_connection_handle = 123;
+ ASSERT_TRUE(kSecondaryConnectionHandle != invalid_connection_handle);
+
+ std::list<ServiceType> removed_services;
+ uint8_t ret_session_id = connection_->RemoveSecondaryServices(
+ invalid_connection_handle, removed_services);
+
+ // check return value
+ EXPECT_EQ(0, ret_session_id);
+ // check returned list
+ EXPECT_EQ(0u, removed_services.size());
+}
+
#ifdef ENABLE_SECURITY
TEST_F(ConnectionTest, SetSSLContextWithoutSession) {
diff --git a/src/components/connection_handler/test/heart_beat_monitor_test.cc b/src/components/connection_handler/test/heart_beat_monitor_test.cc
index 4c67c97191..ccfff34116 100644
--- a/src/components/connection_handler/test/heart_beat_monitor_test.cc
+++ b/src/components/connection_handler/test/heart_beat_monitor_test.cc
@@ -43,6 +43,7 @@ namespace {
const int32_t MILLISECONDS_IN_SECOND = 1000;
const int32_t MICROSECONDS_IN_MILLISECONDS = 1000;
const int32_t MICROSECONDS_IN_SECOND = 1000 * 1000;
+const uint32_t kTime_offset = 20u;
}
namespace test {
@@ -51,27 +52,34 @@ namespace connection_handler_test {
using ::testing::DoAll;
using ::testing::_;
+using ::testing::Return;
class HeartBeatMonitorTest : public testing::Test {
public:
- HeartBeatMonitorTest() : conn(NULL) {
- kTimeout = 5000u;
- }
+ HeartBeatMonitorTest()
+ : connection_(NULL)
+ , timeout_(100u)
+ , time_allowance_multiplier_(1.5)
+ , expiration_timeout_(timeout_ * 2u) {}
protected:
- testing::NiceMock<MockConnectionHandler> connection_handler_mock;
- connection_handler::Connection* conn;
- uint32_t kTimeout;
- static const connection_handler::ConnectionHandle kConnectionHandle =
+ testing::NiceMock<MockConnectionHandler> connection_handler_mock_;
+ connection_handler::Connection* connection_;
+ const uint32_t timeout_;
+ const float_t time_allowance_multiplier_;
+ const uint32_t expiration_timeout_;
+ static const connection_handler::ConnectionHandle connection_handle_ =
0xABCDEF;
+ static const transport_manager::ConnectionUID kDefaultConnectionHandle = 1;
+ static const uint32_t kDefaultSessionId = 1;
- virtual void SetUp() {
- conn = new connection_handler::Connection(
- kConnectionHandle, 0, &connection_handler_mock, kTimeout);
+ void SetUp() OVERRIDE {
+ connection_ = new connection_handler::Connection(
+ connection_handle_, 0, &connection_handler_mock_, timeout_);
}
void TearDown() OVERRIDE {
- delete conn;
+ delete connection_;
}
};
@@ -80,159 +88,191 @@ ACTION_P2(RemoveSession, conn, session_id) {
}
TEST_F(HeartBeatMonitorTest, TimerNotStarted) {
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kDefaultSessionId));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kDefaultSessionId))
+ .WillOnce(Return(true)); // called by destructor of Connection
+
// Whithout StartHeartBeat nothing to be call
- EXPECT_CALL(connection_handler_mock, CloseSession(_, _)).Times(0);
- EXPECT_CALL(connection_handler_mock, CloseConnection(_)).Times(0);
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, _)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, _)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, CloseConnection(_)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, _)).Times(0);
- conn->AddNewSession();
+ connection_->AddNewSession(kDefaultConnectionHandle);
}
TEST_F(HeartBeatMonitorTest, TimerNotElapsed) {
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, _)).Times(0);
- EXPECT_CALL(connection_handler_mock, CloseSession(_, _)).Times(0);
- EXPECT_CALL(connection_handler_mock, CloseConnection(_)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kDefaultSessionId));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kDefaultSessionId))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, _)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, _)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, CloseConnection(_)).Times(0);
- const uint32_t session = conn->AddNewSession();
- conn->StartHeartBeat(session);
+ const uint32_t session = connection_->AddNewSession(kDefaultConnectionHandle);
+ connection_->StartHeartBeat(session);
}
TEST_F(HeartBeatMonitorTest, TimerElapsed) {
- const uint32_t session = conn->AddNewSession();
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kDefaultSessionId));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kDefaultSessionId))
+ .WillOnce(Return(true)); // invoked by RemoveSession action
+
+ const uint32_t session = connection_->AddNewSession(kDefaultConnectionHandle);
TestAsyncWaiter waiter;
uint32_t times = 0;
- EXPECT_CALL(connection_handler_mock, CloseSession(_, session, _))
- .WillOnce(
- DoAll(NotifyTestAsyncWaiter(&waiter), RemoveSession(conn, session)));
- times++;
- EXPECT_CALL(connection_handler_mock, CloseConnection(_))
- .WillOnce(NotifyTestAsyncWaiter(&waiter));
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, session, _))
+ .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter),
+ RemoveSession(connection_, session)));
times++;
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, session))
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, session))
.WillOnce(NotifyTestAsyncWaiter(&waiter));
times++;
- conn->StartHeartBeat(session);
+ connection_->StartHeartBeat(session);
EXPECT_TRUE(waiter.WaitFor(
times,
- 2 * kTimeout * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
+ 2 * timeout_ * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
}
TEST_F(HeartBeatMonitorTest, KeptAlive) {
- EXPECT_CALL(connection_handler_mock, CloseSession(_, _)).Times(0);
- EXPECT_CALL(connection_handler_mock, CloseConnection(_)).Times(0);
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, _)).Times(0);
-
- const uint32_t session = conn->AddNewSession();
- conn->StartHeartBeat(session);
- usleep(kTimeout * MICROSECONDS_IN_MILLISECONDS - MICROSECONDS_IN_SECOND);
- conn->KeepAlive(session);
- usleep(kTimeout * MICROSECONDS_IN_MILLISECONDS - MICROSECONDS_IN_SECOND);
- conn->KeepAlive(session);
- usleep(kTimeout * MICROSECONDS_IN_MILLISECONDS - MICROSECONDS_IN_SECOND);
- conn->KeepAlive(session);
- usleep(kTimeout * MICROSECONDS_IN_MILLISECONDS - MICROSECONDS_IN_SECOND);
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kDefaultSessionId));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kDefaultSessionId))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, _)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, CloseConnection(_)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, _)).Times(0);
+
+ const uint32_t session = connection_->AddNewSession(kDefaultConnectionHandle);
+ connection_->StartHeartBeat(session);
+ usleep(timeout_);
+ connection_->KeepAlive(session);
+ usleep(timeout_);
+ connection_->KeepAlive(session);
}
TEST_F(HeartBeatMonitorTest, NotKeptAlive) {
- const uint32_t session = conn->AddNewSession();
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kDefaultSessionId));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kDefaultSessionId))
+ .WillOnce(Return(true));
+
+ const uint32_t session = connection_->AddNewSession(kDefaultConnectionHandle);
TestAsyncWaiter waiter;
uint32_t times = 0;
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, session))
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, session))
.WillOnce(NotifyTestAsyncWaiter(&waiter));
times++;
- EXPECT_CALL(connection_handler_mock, CloseSession(_, session, _))
- .WillOnce(
- DoAll(NotifyTestAsyncWaiter(&waiter), RemoveSession(conn, session)));
- times++;
- EXPECT_CALL(connection_handler_mock, CloseConnection(_))
- .WillOnce(NotifyTestAsyncWaiter(&waiter));
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, session, _))
+ .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter),
+ RemoveSession(connection_, session)));
times++;
- conn->StartHeartBeat(session);
- usleep(kTimeout * MICROSECONDS_IN_MILLISECONDS - MICROSECONDS_IN_SECOND);
- conn->KeepAlive(session);
- usleep(kTimeout * MICROSECONDS_IN_MILLISECONDS - MICROSECONDS_IN_SECOND);
- conn->KeepAlive(session);
- usleep(kTimeout * MICROSECONDS_IN_MILLISECONDS - MICROSECONDS_IN_SECOND);
- conn->KeepAlive(session);
- usleep(2 * kTimeout * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND);
+ connection_->StartHeartBeat(session);
+ usleep(timeout_);
+ connection_->KeepAlive(session);
EXPECT_TRUE(waiter.WaitFor(
times,
- 2 * kTimeout * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
+ 2 * timeout_ * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
}
TEST_F(HeartBeatMonitorTest, TwoSessionsElapsed) {
- const uint32_t kSession1 = conn->AddNewSession();
- const uint32_t kSession2 = conn->AddNewSession();
+ const uint32_t kMockSessionId1 = 1;
+ const uint32_t kMockSessionId2 = 2;
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kMockSessionId1))
+ .WillOnce(Return(kMockSessionId2));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kMockSessionId1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kMockSessionId2))
+ .WillOnce(Return(true));
+
+ const uint32_t kSession1 =
+ connection_->AddNewSession(kDefaultConnectionHandle);
+
+ const transport_manager::ConnectionUID kAnotherConnectionHandle = 2;
+ const uint32_t kSession2 =
+ connection_->AddNewSession(kAnotherConnectionHandle);
TestAsyncWaiter waiter;
uint32_t times = 0;
- EXPECT_CALL(connection_handler_mock, CloseSession(_, kSession1, _))
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, kSession1, _))
.WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter),
- RemoveSession(conn, kSession1)));
+ RemoveSession(connection_, kSession1)));
times++;
- EXPECT_CALL(connection_handler_mock, CloseSession(_, kSession2, _))
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, kSession2, _))
.WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter),
- RemoveSession(conn, kSession2)));
- times++;
- EXPECT_CALL(connection_handler_mock, CloseConnection(_))
- .WillOnce(NotifyTestAsyncWaiter(&waiter));
+ RemoveSession(connection_, kSession2)));
times++;
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, kSession1))
+
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, kSession1))
.WillOnce(NotifyTestAsyncWaiter(&waiter));
times++;
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, kSession2))
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, kSession2))
.WillOnce(NotifyTestAsyncWaiter(&waiter));
times++;
- conn->StartHeartBeat(kSession1);
- conn->StartHeartBeat(kSession2);
+ connection_->StartHeartBeat(kSession1);
+ connection_->StartHeartBeat(kSession2);
EXPECT_TRUE(waiter.WaitFor(
times,
- 2 * kTimeout * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
+ 2 * timeout_ * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
}
TEST_F(HeartBeatMonitorTest, IncreaseHeartBeatTimeout) {
- const uint32_t kSession = conn->AddNewSession();
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kDefaultSessionId));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kDefaultSessionId))
+ .WillOnce(Return(true));
+
+ const uint32_t kSession =
+ connection_->AddNewSession(kDefaultConnectionHandle);
- EXPECT_CALL(connection_handler_mock, CloseSession(_, _)).Times(0);
- EXPECT_CALL(connection_handler_mock, CloseConnection(_)).Times(0);
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, _)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, _)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, CloseConnection(_)).Times(0);
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, _)).Times(0);
- const uint32_t kNewTimeout = kTimeout + MICROSECONDS_IN_MILLISECONDS;
- conn->StartHeartBeat(kSession);
- conn->SetHeartBeatTimeout(kNewTimeout, kSession);
+ const uint32_t kNewTimeout = timeout_ + MICROSECONDS_IN_MILLISECONDS;
+ connection_->StartHeartBeat(kSession);
+ connection_->SetHeartBeatTimeout(kNewTimeout, kSession);
}
TEST_F(HeartBeatMonitorTest, DecreaseHeartBeatTimeout) {
- const uint32_t kSession = conn->AddNewSession();
+ EXPECT_CALL(connection_handler_mock_, AddSession(_))
+ .WillOnce(Return(kDefaultSessionId));
+ EXPECT_CALL(connection_handler_mock_, RemoveSession(kDefaultSessionId))
+ .WillOnce(Return(true));
+
+ const uint32_t kSession =
+ connection_->AddNewSession(kDefaultConnectionHandle);
TestAsyncWaiter waiter;
uint32_t times = 0;
- EXPECT_CALL(connection_handler_mock, CloseSession(_, kSession, _))
- .WillOnce(
- DoAll(NotifyTestAsyncWaiter(&waiter), RemoveSession(conn, kSession)));
- times++;
- EXPECT_CALL(connection_handler_mock, CloseConnection(_))
- .WillOnce(NotifyTestAsyncWaiter(&waiter));
+ EXPECT_CALL(connection_handler_mock_, CloseSession(_, kSession, _))
+ .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter),
+ RemoveSession(connection_, kSession)));
times++;
- EXPECT_CALL(connection_handler_mock, SendHeartBeat(_, kSession))
+ EXPECT_CALL(connection_handler_mock_, SendHeartBeat(_, kSession))
.WillOnce(NotifyTestAsyncWaiter(&waiter));
times++;
- const uint32_t kNewTimeout = kTimeout - MICROSECONDS_IN_MILLISECONDS;
- conn->StartHeartBeat(kSession);
- conn->SetHeartBeatTimeout(kNewTimeout, kSession);
+ const uint32_t new_timeout = timeout_ - kTime_offset;
+ connection_->StartHeartBeat(kSession);
+ connection_->SetHeartBeatTimeout(new_timeout, kSession);
EXPECT_TRUE(waiter.WaitFor(
times,
- 2 * kTimeout * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
+ 2 * timeout_ * MICROSECONDS_IN_MILLISECONDS + MICROSECONDS_IN_SECOND));
}
} // namespace connection_handler_test