diff options
author | Shobhit Adlakha <ShobhitAd@users.noreply.github.com> | 2020-09-04 12:43:03 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-04 12:43:03 -0400 |
commit | b94d63a0f3e73dc03e7e49d74bf39e2423eb844f (patch) | |
tree | 0aad8837c646a0b1e7eea3d4d6aa2f58a351ed2e /src/components | |
parent | b683e7c3f25ef9dbbff4df4a8749bee2ebbf2450 (diff) | |
download | sdl_core-b94d63a0f3e73dc03e7e49d74bf39e2423eb844f.tar.gz |
Feature/Add reason param to All protocol NAKs (#3462)
* Add reason param to StartService and EndService NAK payloads
* Update the default protocol version
* Fix unit tests
* Implement minor version check for reason param
* Fix unit tests
* Apply suggestions from code review
Co-authored-by: Collin <iCollin@users.noreply.github.com>
* Make semantic versions const and fix handshake NAK reason messages
* Make reason a required param
* Add error check for protocolversionused call
* Use full version for reason param version check
* Get protocol NAK reason from OnSessionEndedCallback
* Fix failing unit tests
* Remove unnecessary condition from protected/unprotected reason check
* Add unit tests for NACK reason param
* Add unit test for EndServiceNAK with reason param
* Fix calltimes in StartSession_NACKReason_SessionObserverReject
* Get reason string for service start failed
* Add more details to the invalid cert nak reason
Co-authored-by: Collin <iCollin@users.noreply.github.com>
Diffstat (limited to 'src/components')
17 files changed, 822 insertions, 173 deletions
diff --git a/src/components/connection_handler/include/connection_handler/connection.h b/src/components/connection_handler/include/connection_handler/connection.h index 7e4ab6a24e..1a93509aca 100644 --- a/src/components/connection_handler/include/connection_handler/connection.h +++ b/src/components/connection_handler/include/connection_handler/connection.h @@ -41,6 +41,7 @@ #include "protocol/service_type.h" #include "protocol_handler/protocol_packet.h" #include "utils/lock.h" +#include "utils/semantic_version.h" #include "utils/threads/thread.h" #ifdef ENABLE_SECURITY @@ -98,12 +99,14 @@ typedef std::vector<Service> ServiceList; struct Session { ServiceList service_list; uint8_t protocol_version; + utils::SemanticVersion full_protocol_version; #ifdef ENABLE_SECURITY security_manager::SSLContext* ssl_context; #endif // ENABLE_SECURITY Session() : service_list() , protocol_version(::protocol_handler::PROTOCOL_VERSION_2) + , full_protocol_version(utils::SemanticVersion(2, 0, 0)) #ifdef ENABLE_SECURITY , ssl_context(NULL) #endif // ENABLE_SECURITY @@ -112,6 +115,7 @@ struct Session { explicit Session(const ServiceList& services, uint8_t protocol_version) : service_list(services) , protocol_version(protocol_version) + , full_protocol_version(utils::SemanticVersion(protocol_version, 0, 0)) #ifdef ENABLE_SECURITY , ssl_context(NULL) #endif // ENABLE_SECURITY @@ -184,7 +188,8 @@ class Connection { bool AddNewService(uint8_t session_id, protocol_handler::ServiceType service_type, const bool is_protected, - transport_manager::ConnectionUID connection_id); + transport_manager::ConnectionUID connection_id, + std::string* err_reason = nullptr); /** * @brief Removes service from session * @param session_id session ID @@ -290,6 +295,15 @@ class Connection { uint8_t protocol_version); /** + * @brief changes protocol version in session + * @param session_id session id + * @param full_protocol_version full protocol version of the registered + * application + */ + void UpdateProtocolVersionSession( + uint8_t session_id, const utils::SemanticVersion& full_protocol_version); + + /** * @brief checks if session supports heartbeat * @param session_id session id * @return TRUE on success, otherwise FALSE @@ -306,6 +320,17 @@ class Connection { bool ProtocolVersion(uint8_t session_id, uint8_t& protocol_version); /** + * @brief find protocol version for session + * @param session_id id of session which is launched on mobile side + * @param full_protocol_version where to write the full protocol version + * output + * @return TRUE if session exists otherwise + * return FALSE + */ + bool ProtocolVersion(uint8_t session_id, + utils::SemanticVersion& full_protocol_version); + + /** * @brief Returns the primary connection handle associated with this * connection * @return ConnectionHandle 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 b2b4c5a970..fb859330b9 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 @@ -247,13 +247,16 @@ class ConnectionHandlerImpl * \param hashCode Hash used only in second version of SmartDeviceLink * protocol. (Set to HASH_ID_WRONG if the hash is incorrect) * If not equal to hash assigned to session on start then operation fails. - * \return uint32_t 0 if operation fails, session key otherwise + * \param err_reason where to write reason for the End Session failure if the + * operation fails \return uint32_t 0 if operation fails, session key + * otherwise */ uint32_t OnSessionEndedCallback( const transport_manager::ConnectionUID connection_handle, const uint8_t session_id, uint32_t* hashCode, - const protocol_handler::ServiceType& service_type) OVERRIDE; + const protocol_handler::ServiceType& service_type, + std::string* err_reason = nullptr) OVERRIDE; /** * \brief Callback function used by ProtocolHandler @@ -490,6 +493,17 @@ class ConnectionHandlerImpl uint8_t protocol_version) OVERRIDE; /** + * @brief binds protocol version with session + * + * @param connection_key pair of connection and session id + * @param full_protocol_version contains full protocol version of registered + * application. + */ + void BindProtocolVersionWithSession( + uint32_t connection_key, + const utils::SemanticVersion& full_protocol_version) OVERRIDE; + + /** * \brief returns TRUE if session supports sending HEART BEAT ACK to mobile * side * \param connection_handle Connection identifier whithin which session @@ -513,6 +527,19 @@ class ConnectionHandlerImpl uint8_t& protocol_version) const OVERRIDE; /** + * @brief find protocol version which application supports + * @param connection_id id of connection + * @param session_id id of session + * @param full_protocol_version where to write the full protocol version + * output + * @return TRUE if session and connection exist otherwise returns FALSE + */ + bool ProtocolVersionUsed( + uint32_t connection_id, + uint8_t session_id, + utils::SemanticVersion& full_protocol_version) const OVERRIDE; + + /** * \brief information about given Connection Key. * \param key Unique key used by other components as session identifier * \param app_id Returned: ApplicationID diff --git a/src/components/connection_handler/src/connection.cc b/src/components/connection_handler/src/connection.cc index c366496056..14e2b83848 100644 --- a/src/components/connection_handler/src/connection.cc +++ b/src/components/connection_handler/src/connection.cc @@ -165,11 +165,15 @@ uint32_t Connection::RemoveSession(uint8_t session_id) { bool Connection::AddNewService(uint8_t session_id, protocol_handler::ServiceType service_type, const bool request_protection, - transport_manager::ConnectionUID connection_id) { + transport_manager::ConnectionUID connection_id, + std::string* err_reason) { // Ignore wrong services if (protocol_handler::kControl == service_type || protocol_handler::kInvalidServiceType == service_type) { SDL_LOG_WARN("Wrong service " << static_cast<int>(service_type)); + if (err_reason) { + *err_reason = "Wrong service type " + std::to_string(service_type); + } return false; } @@ -182,6 +186,11 @@ bool Connection::AddNewService(uint8_t session_id, SessionMap::iterator session_it = session_map_.find(session_id); if (session_it == session_map_.end()) { SDL_LOG_WARN("Session not found in this connection!"); + if (err_reason) { + *err_reason = "Session " + std::to_string(session_id) + + " not found for connection " + + std::to_string(connection_id); + } return false; } Session& session = session_it->second; @@ -206,12 +215,22 @@ bool Connection::AddNewService(uint8_t session_id, SDL_LOG_WARN("Session " << static_cast<int>(session_id) << " already has unprotected service " << static_cast<int>(service_type)); + if (err_reason) { + *err_reason = "Session " + std::to_string(session_id) + + " already has an unprotected service of type " + + std::to_string(service_type); + } return false; } if (service->is_protected_) { SDL_LOG_WARN("Session " << static_cast<int>(session_id) << " already has protected service " << static_cast<int>(service_type)); + if (err_reason) { + *err_reason = "Session " + std::to_string(session_id) + + " already has a protected service of type " + + std::to_string(service_type); + } return false; } // For unproteced service could be start protection @@ -442,6 +461,33 @@ void Connection::UpdateProtocolVersionSession(uint8_t session_id, } Session& session = session_it->second; session.protocol_version = protocol_version; + if (session.full_protocol_version.major_version_ != + session.protocol_version) { + session.full_protocol_version = + utils::SemanticVersion(protocol_version, 0, 0); + } +} + +void Connection::UpdateProtocolVersionSession( + uint8_t session_id, const utils::SemanticVersion& full_protocol_version) { + SDL_LOG_AUTO_TRACE(); + + if (!full_protocol_version.isValid()) { + SDL_LOG_WARN("Invalid version: " << full_protocol_version.toString()); + return; + } + + sync_primitives::AutoLock lock(session_map_lock_); + SessionMap::iterator session_it = session_map_.find(session_id); + if (session_map_.end() == session_it) { + SDL_LOG_WARN("Session not found in this connection!"); + return; + } + + Session& session = session_it->second; + session.protocol_version = + static_cast<uint8_t>(full_protocol_version.major_version_); + session.full_protocol_version = full_protocol_version; } bool Connection::SupportHeartBeat(uint8_t session_id) { @@ -471,6 +517,19 @@ bool Connection::ProtocolVersion(uint8_t session_id, return true; } +bool Connection::ProtocolVersion( + uint8_t session_id, utils::SemanticVersion& full_protocol_version) { + SDL_LOG_AUTO_TRACE(); + sync_primitives::AutoLock lock(session_map_lock_); + SessionMap::iterator session_it = session_map_.find(session_id); + if (session_map_.end() == session_it) { + SDL_LOG_WARN("Session not found in this connection!"); + return false; + } + full_protocol_version = (session_it->second).full_protocol_version; + return true; +} + ConnectionHandle Connection::primary_connection_handle() const { return primary_connection_handle_; } diff --git a/src/components/connection_handler/src/connection_handler_impl.cc b/src/components/connection_handler/src/connection_handler_impl.cc index a57f7c73e0..b9d1de8332 100644 --- a/src/components/connection_handler/src/connection_handler_impl.cc +++ b/src/components/connection_handler/src/connection_handler_impl.cc @@ -457,7 +457,11 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( #ifdef ENABLE_SECURITY if (!AllowProtection(get_settings(), service_type, is_protected)) { - protocol_handler_->NotifySessionStarted(context, rejected_params); + protocol_handler_->NotifySessionStarted( + context, + rejected_params, + "Service of type " + std::to_string(service_type) + " cannot be " + + (is_protected ? "protected" : "unprotected")); return; } #endif // ENABLE_SECURITY @@ -466,7 +470,10 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( connection_list_.find(primary_connection_handle); if (connection_list_.end() == it) { SDL_LOG_ERROR("Unknown connection!"); - protocol_handler_->NotifySessionStarted(context, rejected_params); + protocol_handler_->NotifySessionStarted( + context, + rejected_params, + "Unknown connection " + std::to_string(primary_connection_handle)); return; } @@ -479,21 +486,33 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( connection->AddNewSession(primary_connection_handle); if (0 == context.new_session_id_) { SDL_LOG_ERROR("Couldn't start new session!"); - protocol_handler_->NotifySessionStarted(context, rejected_params); + protocol_handler_->NotifySessionStarted( + context, rejected_params, "Unable to create new session"); return; } 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, connection_handle)) { + std::string err_reason; + if (!connection->AddNewService(session_id, + service_type, + is_protected, + connection_handle, + &err_reason)) { SDL_LOG_ERROR("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)); - protocol_handler_->NotifySessionStarted(context, rejected_params); + + protocol_handler_->NotifySessionStarted( + context, + rejected_params, + "Cannot start " + + std::string(is_protected ? "a protected" : " an unprotected") + + " service of type " + std::to_string(service_type) + ". " + + err_reason); return; } context.new_session_id_ = session_id; @@ -650,7 +669,8 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( const transport_manager::ConnectionUID connection_handle, const uint8_t session_id, uint32_t* hashCode, - const protocol_handler::ServiceType& service_type) { + const protocol_handler::ServiceType& service_type, + std::string* err_reason) { SDL_LOG_AUTO_TRACE(); // In case this is a Session running on a Secondary Transport, we need to @@ -666,6 +686,9 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( SDL_LOG_WARN( "OnSessionEndedCallback could not find Session in the " "Session/Connection Map!"); + if (err_reason) { + *err_reason = "Could not find Session in the Session/Connection Map!"; + } } else { SDL_LOG_INFO("OnSessionEndedCallback found session " << static_cast<int>(session_id) @@ -683,6 +706,9 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( if (connection_list_.end() == it) { SDL_LOG_WARN("Unknown connection!"); connection_list_lock_.Release(); + if (err_reason) { + *err_reason = "Could not find Connection in the Connection Map!"; + } return 0; } std::pair<int32_t, Connection*> connection_item = *it; @@ -704,12 +730,21 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( "Wrong hash_id for session " << static_cast<uint32_t>(session_id)); *hashCode = protocol_handler::HASH_ID_WRONG; + + if (err_reason) { + *err_reason = "Wrong hash_id for session " + + std::to_string(static_cast<uint32_t>(session_id)); + } return 0; } } if (!connection->RemoveSession(session_id)) { SDL_LOG_WARN("Couldn't remove session " << static_cast<uint32_t>(session_id)); + if (err_reason) { + *err_reason = "Couldn't remove session " + + std::to_string(static_cast<uint32_t>(session_id)); + } return 0; } } else { @@ -720,6 +755,10 @@ uint32_t ConnectionHandlerImpl::OnSessionEndedCallback( SDL_LOG_WARN( "Couldn't remove service " << static_cast<uint32_t>(service_type)); + if (err_reason) { + *err_reason = "Couldn't remove service " + + std::to_string(static_cast<uint32_t>(service_type)); + } return 0; } } @@ -1715,6 +1754,21 @@ void ConnectionHandlerImpl::BindProtocolVersionWithSession( } } +void ConnectionHandlerImpl::BindProtocolVersionWithSession( + uint32_t connection_key, + const utils::SemanticVersion& full_protocol_version) { + SDL_LOG_AUTO_TRACE(); + uint32_t connection_handle = 0; + uint8_t session_id = 0; + PairFromKey(connection_key, &connection_handle, &session_id); + + sync_primitives::AutoReadLock lock(connection_list_lock_); + auto connection = GetPrimaryConnection(connection_handle); + if (connection) { + connection->UpdateProtocolVersionSession(session_id, full_protocol_version); + } +} + bool ConnectionHandlerImpl::IsHeartBeatSupported( transport_manager::ConnectionUID connection_handle, uint8_t session_id) const { @@ -1748,6 +1802,25 @@ bool ConnectionHandlerImpl::ProtocolVersionUsed( return false; } +bool ConnectionHandlerImpl::ProtocolVersionUsed( + uint32_t connection_id, + uint8_t session_id, + utils::SemanticVersion& full_protocol_version) const { + SDL_LOG_AUTO_TRACE(); + sync_primitives::AutoReadLock lock(connection_list_lock_); + auto connection = GetPrimaryConnection(connection_id); + + if (connection) { + return connection->ProtocolVersion(session_id, full_protocol_version); + } else if (ending_connection_ && + static_cast<uint32_t>(ending_connection_->connection_handle()) == + connection_id) { + return ending_connection_->ProtocolVersion(session_id, + full_protocol_version); + } + return false; +} + #ifdef BUILD_TESTS ConnectionList& ConnectionHandlerImpl::getConnectionList() { return connection_list_; 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 855225c460..5a8feda2db 100644 --- a/src/components/connection_handler/test/connection_handler_impl_test.cc +++ b/src/components/connection_handler/test/connection_handler_impl_test.cc @@ -127,7 +127,7 @@ class ConnectionHandlerTest : public ::testing::Test { void AddTestSession() { protocol_handler_test::MockProtocolHandler temp_protocol_handler; connection_handler_->set_protocol_handler(&temp_protocol_handler); - EXPECT_CALL(temp_protocol_handler, NotifySessionStarted(_, _)) + EXPECT_CALL(temp_protocol_handler, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&out_context_)); connection_handler_->OnSessionStartedCallback( @@ -164,7 +164,7 @@ class ConnectionHandlerTest : public ::testing::Test { SessionContext context; protocol_handler_test::MockProtocolHandler temp_protocol_handler; connection_handler_->set_protocol_handler(&temp_protocol_handler); - EXPECT_CALL(temp_protocol_handler, NotifySessionStarted(_, _)) + EXPECT_CALL(temp_protocol_handler, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&context)); connection_handler_->OnSessionStartedCallback(uid_, @@ -371,7 +371,7 @@ TEST_F(ConnectionHandlerTest, StartSession_NoConnection) { protocol_handler::SessionContext context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&context)); connection_handler_->OnSessionStartedCallback( @@ -1144,7 +1144,7 @@ TEST_F(ConnectionHandlerTest, StartService_withServices) { SessionContext audio_context, video_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&audio_context)) .WillOnce(SaveArg<0>(&video_context)); @@ -1185,7 +1185,7 @@ TEST_F(ConnectionHandlerTest, StartService_withServices_withParams) { std::vector<std::string> empty; BsonObject* dummy_param = reinterpret_cast<BsonObject*>(&dummy); connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty, _)) .WillOnce(SaveArg<0>(&video_context)); connection_handler_->OnSessionStartedCallback(uid_, @@ -1230,7 +1230,7 @@ TEST_F(ConnectionHandlerTest, ServiceStop) { SessionContext audio_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillRepeatedly(SaveArg<0>(&audio_context)); // Check ignoring hash_id on stop non-rpc service @@ -1319,7 +1319,7 @@ TEST_F(ConnectionHandlerTest, SessionStarted_WithRpc) { ByRef(empty))); connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&out_context_)); // Start new session with RPC service @@ -1357,7 +1357,7 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_SUCCESS) { // confirm that NotifySessionStarted() is called connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty, _)) .WillOnce(SaveArg<0>(&out_context_)); connection_handler_->OnSessionStartedCallback(uid_, @@ -1397,7 +1397,7 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_FAILURE) { // confirm that NotifySessionStarted() is called connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty, _)) .WillOnce(SaveArg<0>(&out_context_)); connection_handler_->OnSessionStartedCallback(uid_, @@ -1421,7 +1421,7 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_Multiple) { protocol_handler_test::MockProtocolHandler temp_protocol_handler; connection_handler_->set_protocol_handler(&temp_protocol_handler); - EXPECT_CALL(temp_protocol_handler, NotifySessionStarted(_, _)) + EXPECT_CALL(temp_protocol_handler, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&context_first)) .WillOnce(SaveArg<0>(&context_second)); @@ -1488,7 +1488,7 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_Multiple) { // verify that connection handler will not mix up the two results SessionContext new_context_first, new_context_second; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, empty, _)) .WillOnce(SaveArg<0>(&new_context_second)) .WillOnce(SaveArg<0>(&new_context_first)); @@ -1520,7 +1520,7 @@ TEST_F(ConnectionHandlerTest, SessionContext fail_context; SessionContext positive_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&fail_context)) .WillOnce(SaveArg<0>(&positive_context)); @@ -1563,7 +1563,7 @@ TEST_F(ConnectionHandlerTest, SessionContext fail_context; SessionContext positive_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&fail_context)) .WillOnce(SaveArg<0>(&positive_context)); @@ -1608,7 +1608,7 @@ TEST_F(ConnectionHandlerTest, SessionContext context_first, context_second; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&context_first)) .WillOnce(SaveArg<0>(&context_second)); @@ -1663,7 +1663,7 @@ TEST_F(ConnectionHandlerTest, SessionContext rejected_context, positive_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&rejected_context)) .WillOnce(SaveArg<0>(&positive_context)); @@ -1706,7 +1706,7 @@ TEST_F(ConnectionHandlerTest, SessionStarted_DealyProtect) { SessionContext context_new, context_second, context_third; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&context_new)) .WillOnce(SaveArg<0>(&context_second)) .WillOnce(SaveArg<0>(&context_third)); @@ -1761,7 +1761,7 @@ TEST_F(ConnectionHandlerTest, SessionStarted_DealyProtectBulk) { SessionContext new_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&new_context)); connection_handler_->OnSessionStartedCallback(uid_, out_context_.new_session_id_, @@ -1867,7 +1867,7 @@ TEST_F(ConnectionHandlerTest, GetSSLContext_ByProtectedService) { SessionContext new_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&new_context)); // Open kAudio service @@ -1904,7 +1904,7 @@ TEST_F(ConnectionHandlerTest, GetSSLContext_ByDealyProtectedRPC) { SessionContext new_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&new_context)); // Protect kRpc (Bulk will be protect also) @@ -1944,7 +1944,7 @@ TEST_F(ConnectionHandlerTest, GetSSLContext_ByDealyProtectedBulk) { SessionContext new_context; connection_handler_->set_protocol_handler(&mock_protocol_handler_); - EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) + EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _, _)) .WillOnce(SaveArg<0>(&new_context)); // Protect Bulk (kRpc will be protected also) diff --git a/src/components/include/connection_handler/connection_handler.h b/src/components/include/connection_handler/connection_handler.h index e98a78f377..de78024e61 100644 --- a/src/components/include/connection_handler/connection_handler.h +++ b/src/components/include/connection_handler/connection_handler.h @@ -205,6 +205,15 @@ class ConnectionHandler { uint8_t protocol_version) = 0; /** + * @brief binds protocol version with session + * @param connection_key pair of connection and session id + * @param full_protocol_version contains full protocol version of registered + * application. + */ + virtual void BindProtocolVersionWithSession( + uint32_t connection_key, + const utils::SemanticVersion& full_protocol_version) = 0; + /** * \brief information about given Connection Key. * \param key Unique key used by other components as session identifier * \param app_id Returned: ApplicationID diff --git a/src/components/include/protocol_handler/protocol_handler.h b/src/components/include/protocol_handler/protocol_handler.h index aacb31c260..bb596631a0 100644 --- a/src/components/include/protocol_handler/protocol_handler.h +++ b/src/components/include/protocol_handler/protocol_handler.h @@ -137,7 +137,8 @@ class ProtocolHandler { */ virtual void NotifySessionStarted( const SessionContext& context, - std::vector<std::string>& rejected_params) = 0; + std::vector<std::string>& rejected_params, + const std::string err_reason = std::string()) = 0; virtual bool IsRPCServiceSecure(const uint32_t connection_key) const = 0; diff --git a/src/components/include/protocol_handler/session_observer.h b/src/components/include/protocol_handler/session_observer.h index e71557fecf..cdf4267188 100644 --- a/src/components/include/protocol_handler/session_observer.h +++ b/src/components/include/protocol_handler/session_observer.h @@ -37,6 +37,8 @@ #include <string> #include "transport_manager/transport_manager.h" #include "utils/macro.h" +#include "utils/semantic_version.h" + #ifdef ENABLE_SECURITY #include "security_manager/ssl_context.h" #endif // ENABLE_SECURITY @@ -150,13 +152,17 @@ class SessionObserver { * protocol. (Set to HASH_ID_WRONG if the hash is incorrect) * If not equal to hash assigned to session on start then operation fails. * \param service_type Type of service - * \return uint32_t 0 if operation fails, session key otherwise + * \param err_reason where to write reason for the End Session failure if the + * operation fails + * \return uint32_t 0 if operation fails, session key + * otherwise */ virtual uint32_t OnSessionEndedCallback( const transport_manager::ConnectionUID connection_handle, const uint8_t sessionId, uint32_t* hashCode, - const protocol_handler::ServiceType& service_type) = 0; + const protocol_handler::ServiceType& service_type, + std::string* err_reason = nullptr) = 0; /** * \brief Callback function used by ProtocolHandler @@ -267,6 +273,18 @@ class SessionObserver { uint8_t& protocol_version) const = 0; /** + * @brief returns protocol version which application supports + * @param connection_id id of connection + * @param session_id id of session + * @param full_protocol_version where to write the full protocol version + * output + * @return TRUE if session and connection exist otherwise returns FALSE + */ + virtual bool ProtocolVersionUsed( + uint32_t connection_id, + uint8_t session_id, + utils::SemanticVersion& full_protocol_version) const = 0; + /** * @brief Check if session contains service with specified service type * @param connection_key unique id of session to check * @param service_type type of service to check diff --git a/src/components/include/test/connection_handler/mock_connection_handler.h b/src/components/include/test/connection_handler/mock_connection_handler.h index 6acffea0ed..d44dd94ddd 100644 --- a/src/components/include/test/connection_handler/mock_connection_handler.h +++ b/src/components/include/test/connection_handler/mock_connection_handler.h @@ -96,6 +96,9 @@ class MockConnectionHandler : public connection_handler::ConnectionHandler { void(uint32_t connection_key, uint8_t session_id)); MOCK_METHOD2(BindProtocolVersionWithSession, void(uint32_t connection_key, uint8_t protocol_version)); + MOCK_METHOD2(BindProtocolVersionWithSession, + void(uint32_t connection_key, + const utils::SemanticVersion& full_protocol_version)); MOCK_CONST_METHOD4(GetDataOnSessionKey, int32_t(uint32_t key, uint32_t* app_id, diff --git a/src/components/include/test/protocol_handler/mock_protocol_handler.h b/src/components/include/test/protocol_handler/mock_protocol_handler.h index 354c797c24..e3a52157ec 100644 --- a/src/components/include/test/protocol_handler/mock_protocol_handler.h +++ b/src/components/include/test/protocol_handler/mock_protocol_handler.h @@ -67,6 +67,10 @@ class MockProtocolHandler : public ::protocol_handler::ProtocolHandler { MOCK_METHOD2(NotifySessionStarted, void(const ::protocol_handler::SessionContext& context, std::vector<std::string>& rejected_params)); + MOCK_METHOD3(NotifySessionStarted, + void(const ::protocol_handler::SessionContext& context, + std::vector<std::string>& rejected_params, + const std::string err_reason)); MOCK_METHOD0(NotifyOnGetSystemTimeFailed, void()); MOCK_CONST_METHOD1(IsRPCServiceSecure, bool(const uint32_t connection_key)); MOCK_METHOD0(ProcessFailedPTU, void()); diff --git a/src/components/include/test/protocol_handler/mock_session_observer.h b/src/components/include/test/protocol_handler/mock_session_observer.h index 01bb41a96e..3414153fc7 100644 --- a/src/components/include/test/protocol_handler/mock_session_observer.h +++ b/src/components/include/test/protocol_handler/mock_session_observer.h @@ -65,6 +65,20 @@ class MockSessionObserver : public ::protocol_handler::SessionObserver { const uint8_t sessionId, uint32_t* hashCode, const protocol_handler::ServiceType& service_type)); + MOCK_METHOD5( + OnSessionEndedCallback, + uint32_t(const transport_manager::ConnectionUID connection_handle, + const uint8_t sessionId, + const uint32_t& hashCode, + const protocol_handler::ServiceType& service_type, + std::string* err_reason)); + MOCK_METHOD5( + OnSessionEndedCallback, + uint32_t(const transport_manager::ConnectionUID connection_handle, + const uint8_t sessionId, + uint32_t* hashCode, + const protocol_handler::ServiceType& service_type, + std::string* err_reason)); MOCK_METHOD1(OnApplicationFloodCallBack, void(const uint32_t& connection_key)); MOCK_METHOD1(OnMalformedMessageCallback, @@ -103,6 +117,10 @@ class MockSessionObserver : public ::protocol_handler::SessionObserver { bool(uint32_t connection_id, uint8_t session_id, uint8_t& protocol_version)); + MOCK_CONST_METHOD3(ProtocolVersionUsed, + bool(uint32_t connection_id, + uint8_t session_id, + utils::SemanticVersion& full_protocol_version)); MOCK_CONST_METHOD2(SessionServiceExists, bool(const uint32_t connection_key, const protocol_handler::ServiceType& service_type)); diff --git a/src/components/protocol_handler/include/protocol_handler/handshake_handler.h b/src/components/protocol_handler/include/protocol_handler/handshake_handler.h index 9552d4c420..a9a5997493 100644 --- a/src/components/protocol_handler/include/protocol_handler/handshake_handler.h +++ b/src/components/protocol_handler/include/protocol_handler/handshake_handler.h @@ -130,8 +130,11 @@ class HandshakeHandler : public security_manager::SecurityManagerListener { * @brief Performs related actions if handshake was failed * @param params set of params used in bson part of message * @param service_status - service status to be sent to HMI + * @param err_reason - Optional error description */ - void ProcessFailedHandshake(BsonObject& params, ServiceStatus service_status); + void ProcessFailedHandshake(BsonObject& params, + ServiceStatus service_status, + std::string err_reason = std::string()); /** * @brief Determines whether service can be protected diff --git a/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h b/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h index 8dbfc4ed4d..ead997da69 100644 --- a/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h +++ b/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h @@ -373,11 +373,13 @@ class ProtocolHandlerImpl * \param session_id ID of session to be sent to mobile application * \param protocol_version Version of protocol used for communication * \param service_type Type of session: RPC or BULK Data. RPC by default + * \param reason String stating the reason for the rejecting the start service */ void SendStartSessionNAck(ConnectionID connection_id, uint8_t session_id, uint8_t protocol_version, - uint8_t service_type); + uint8_t service_type, + const std::string reason); /** * \brief Sends fail of starting session to mobile application @@ -386,12 +388,14 @@ class ProtocolHandlerImpl * \param protocol_version Version of protocol used for communication * \param service_type Type of session: RPC or BULK Data. RPC by default * \param rejected_params List of rejected params to send in payload + * \param reason String stating the reason for the rejecting the start service */ void SendStartSessionNAck(ConnectionID connection_id, uint8_t session_id, uint8_t protocol_version, uint8_t service_type, - std::vector<std::string>& rejectedParams); + std::vector<std::string>& rejectedParams, + const std::string reason); /** * \brief Sends acknowledgement of end session/service to mobile application @@ -416,11 +420,13 @@ class ProtocolHandlerImpl * \param session_id ID of session ment to be ended * \param protocol_version Version of protocol used for communication * \param service_type Type of session: RPC or BULK Data. RPC by default + * \param reason String stating the reason for the rejecting the end service */ void SendEndSessionNAck(ConnectionID connection_id, uint32_t session_id, uint8_t protocol_version, - uint8_t service_type); + uint8_t service_type, + const std::string reason); /** * \brief Sends fail of ending session to mobile application (variant for * Protocol v5) @@ -430,12 +436,14 @@ class ProtocolHandlerImpl * \param protocol_version Version of protocol used for communication * \param service_type Type of session: RPC or BULK Data. RPC by default * \param rejected_params List of rejected params to send in payload + * \param reason String stating the reason for the rejecting the end service */ void SendEndSessionNAck(ConnectionID connection_id, uint32_t session_id, uint8_t protocol_version, uint8_t service_type, - std::vector<std::string>& rejected_params); + std::vector<std::string>& rejected_params, + const std::string reason); SessionObserver& get_session_observer() OVERRIDE; @@ -448,7 +456,8 @@ class ProtocolHandlerImpl * generated_session_id is 0, the list may be empty. */ void NotifySessionStarted(const SessionContext& context, - std::vector<std::string>& rejected_params) OVERRIDE; + std::vector<std::string>& rejected_params, + const std::string err_reason) OVERRIDE; #ifdef BUILD_TESTS const impl::FromMobileQueue& get_from_mobile_queue() const { diff --git a/src/components/protocol_handler/src/handshake_handler.cc b/src/components/protocol_handler/src/handshake_handler.cc index e804fdaa08..4d306fd330 100644 --- a/src/components/protocol_handler/src/handshake_handler.cc +++ b/src/components/protocol_handler/src/handshake_handler.cc @@ -86,7 +86,9 @@ void HandshakeHandler::OnCertificateUpdateRequired() { bool HandshakeHandler::OnCertDecryptFailed() { SDL_LOG_AUTO_TRACE(); if (payload_) { - ProcessFailedHandshake(*payload_, ServiceStatus::CERT_INVALID); + ProcessFailedHandshake(*payload_, + ServiceStatus::CERT_INVALID, + "Failed to decrypt the certificate"); } return true; @@ -136,11 +138,34 @@ bool HandshakeHandler::OnHandshakeDone( const bool success = result == security_manager::SSLContext::Handshake_Result_Success; + auto getInvalidCertReason = + [](const security_manager::SSLContext::HandshakeResult& result) { + switch (result) { + case security_manager::SSLContext::Handshake_Result_CertExpired: + return "Certificate already expired"; + case security_manager::SSLContext::Handshake_Result_NotYetValid: + return "Certificate is not yet valid"; + case security_manager::SSLContext::Handshake_Result_CertNotSigned: + return "Certificate is not signed"; + case security_manager::SSLContext::Handshake_Result_AppIDMismatch: + return "Trying to run handshake with wrong app id"; + case security_manager::SSLContext::Handshake_Result_AppNameMismatch: + return "Trying to run handshake with wrong app name"; + case security_manager::SSLContext::Handshake_Result_AbnormalFail: + return "Error occurred during handshake"; + case security_manager::SSLContext::Handshake_Result_Fail: + return ""; + default: + return ""; + } + }; + if (payload_) { if (success) { ProcessSuccessfulHandshake(connection_key, *payload_); } else { - ProcessFailedHandshake(*payload_, ServiceStatus::CERT_INVALID); + ProcessFailedHandshake( + *payload_, ServiceStatus::CERT_INVALID, getInvalidCertReason(result)); } } else { BsonObject params; @@ -148,7 +173,8 @@ bool HandshakeHandler::OnHandshakeDone( if (success) { ProcessSuccessfulHandshake(connection_key, params); } else { - ProcessFailedHandshake(params, ServiceStatus::CERT_INVALID); + ProcessFailedHandshake( + params, ServiceStatus::CERT_INVALID, getInvalidCertReason(result)); } bson_object_deinitialize(¶ms); } @@ -199,15 +225,20 @@ void HandshakeHandler::ProcessSuccessfulHandshake(const uint32_t connection_key, this->connection_key(), context_.service_type_, ServiceStatus::SERVICE_START_FAILED); + protocol_handler_.SendStartSessionNAck(context_.connection_id_, context_.new_session_id_, protocol_version_, - context_.service_type_); + context_.service_type_, + (is_service_already_protected) + ? "Service is already protected" + : "Service cannot be protected"); } } void HandshakeHandler::ProcessFailedHandshake(BsonObject& params, - ServiceStatus service_status) { + ServiceStatus service_status, + std::string err_reason) { SDL_LOG_AUTO_TRACE(); SDL_LOG_DEBUG("Handshake failed"); const std::vector<int>& force_protected = @@ -238,10 +269,22 @@ void HandshakeHandler::ProcessFailedHandshake(BsonObject& params, } else { service_status_update_handler_.OnServiceUpdate( this->connection_key(), context_.service_type_, service_status); - protocol_handler_.SendStartSessionNAck(context_.connection_id_, - context_.new_session_id_, - protocol_version_, - context_.service_type_); + + std::string reason_msg = + (service_status == ServiceStatus::PTU_FAILED) + ? "Policy Table Update failed" + : (service_status == ServiceStatus::CERT_INVALID) + ? "Invalid certificate" + : (service_status == ServiceStatus::INVALID_TIME) + ? "Failed to get system time" + : "Unknown cause of failure"; + + protocol_handler_.SendStartSessionNAck( + context_.connection_id_, + context_.new_session_id_, + protocol_version_, + context_.service_type_, + reason_msg + (err_reason.empty() ? "" : ": " + err_reason)); } } diff --git a/src/components/protocol_handler/src/protocol_handler_impl.cc b/src/components/protocol_handler/src/protocol_handler_impl.cc index 1f41ab38a3..f1179e7107 100644 --- a/src/components/protocol_handler/src/protocol_handler_impl.cc +++ b/src/components/protocol_handler/src/protocol_handler_impl.cc @@ -61,9 +61,10 @@ std::string ConvertPacketDataToString(const uint8_t* data, const size_t kStackSize = 131072; -utils::SemanticVersion default_protocol_version(5, 2, 0); -utils::SemanticVersion min_multiple_transports_version(5, 1, 0); -utils::SemanticVersion min_cloud_app_version(5, 2, 0); +const utils::SemanticVersion default_protocol_version(5, 3, 0); +const utils::SemanticVersion min_multiple_transports_version(5, 1, 0); +const utils::SemanticVersion min_cloud_app_version(5, 2, 0); +const utils::SemanticVersion min_reason_param_version(5, 3, 0); ProtocolHandlerImpl::ProtocolHandlerImpl( const ProtocolHandlerSettings& settings, @@ -306,13 +307,14 @@ void ProtocolHandlerImpl::SendStartSessionAck( bson_object_get_int32(¶ms, strings::hash_id))); // Minimum protocol version supported by both - utils::SemanticVersion* min_version = + const utils::SemanticVersion& min_version = (full_version.major_version_ < PROTOCOL_VERSION_5) - ? &default_protocol_version - : utils::SemanticVersion::min(full_version, - default_protocol_version); + ? default_protocol_version + : ((full_version < default_protocol_version) + ? full_version + : default_protocol_version); char protocol_version_string[256]; - strncpy(protocol_version_string, (*min_version).toString().c_str(), 255); + strncpy(protocol_version_string, (min_version).toString().c_str(), 255); const bool protocol_ver_written = bson_object_put_string( ¶ms, strings::protocol_version, protocol_version_string); @@ -328,7 +330,7 @@ void ProtocolHandlerImpl::SendStartSessionAck( std::vector<std::string> secondaryTransports; std::vector<int32_t> audioServiceTransports; std::vector<int32_t> videoServiceTransports; - if (*min_version >= min_multiple_transports_version) { + if (min_version >= min_multiple_transports_version) { if (ParseSecondaryTransportConfiguration(connection_id, secondaryTransports, audioServiceTransports, @@ -407,7 +409,7 @@ void ProtocolHandlerImpl::SendStartSessionAck( std::string policy_app_id = connection_handler_.GetCloudAppID(connection_id); - if (*min_version >= min_cloud_app_version && !policy_app_id.empty()) { + if (min_version >= min_cloud_app_version && !policy_app_id.empty()) { sync_primitives::AutoLock lock(auth_token_map_lock_); auto it = auth_token_map_.find(policy_app_id); if (it != auth_token_map_.end()) { @@ -448,13 +450,15 @@ void ProtocolHandlerImpl::SendStartSessionAck( void ProtocolHandlerImpl::SendStartSessionNAck(ConnectionID connection_id, uint8_t session_id, uint8_t protocol_version, - uint8_t service_type) { + uint8_t service_type, + const std::string reason) { std::vector<std::string> rejectedParams; SendStartSessionNAck(connection_id, session_id, protocol_version, service_type, - rejectedParams); + rejectedParams, + reason); } void ProtocolHandlerImpl::SendStartSessionNAck( @@ -462,7 +466,8 @@ void ProtocolHandlerImpl::SendStartSessionNAck( uint8_t session_id, uint8_t protocol_version, uint8_t service_type, - std::vector<std::string>& rejectedParams) { + std::vector<std::string>& rejectedParams, + const std::string reason) { SDL_LOG_AUTO_TRACE(); ProtocolFramePtr ptr( @@ -478,20 +483,34 @@ void ProtocolHandlerImpl::SendStartSessionNAck( uint8_t maxProtocolVersion = SupportedSDLProtocolVersion(); + utils::SemanticVersion full_version; + if (!session_observer_.ProtocolVersionUsed( + connection_id, session_id, full_version)) { + SDL_LOG_WARN("Connection: " << connection_id << " and/or session: " + << session_id << "no longer exist(s)."); + return; + } + if (protocol_version >= PROTOCOL_VERSION_5 && - maxProtocolVersion >= PROTOCOL_VERSION_5 && rejectedParams.size() > 0) { + maxProtocolVersion >= PROTOCOL_VERSION_5) { BsonObject payloadObj; bson_object_initialize_default(&payloadObj); - BsonArray rejectedParamsArr; - bson_array_initialize(&rejectedParamsArr, rejectedParams.size()); - for (std::string param : rejectedParams) { - char paramPtr[256]; - strncpy(paramPtr, param.c_str(), sizeof(paramPtr)); - paramPtr[sizeof(paramPtr) - 1] = '\0'; - bson_array_add_string(&rejectedParamsArr, paramPtr); + if (rejectedParams.size() > 0) { + BsonArray rejectedParamsArr; + bson_array_initialize(&rejectedParamsArr, rejectedParams.size()); + for (std::string param : rejectedParams) { + char paramPtr[256]; + strncpy(paramPtr, param.c_str(), sizeof(paramPtr)); + paramPtr[sizeof(paramPtr) - 1] = '\0'; + bson_array_add_string(&rejectedParamsArr, paramPtr); + } + bson_object_put_array( + &payloadObj, strings::rejected_params, &rejectedParamsArr); + } + if (!reason.empty() && full_version >= min_reason_param_version) { + bson_object_put_string( + &payloadObj, strings::reason, const_cast<char*>(reason.c_str())); } - bson_object_put_array( - &payloadObj, strings::rejected_params, &rejectedParamsArr); uint8_t* payloadBytes = bson_object_to_bytes(&payloadObj); ptr->set_data(payloadBytes, bson_object_size(&payloadObj)); free(payloadBytes); @@ -504,19 +523,22 @@ void ProtocolHandlerImpl::SendStartSessionNAck( SDL_LOG_DEBUG("SendStartSessionNAck() for connection " << connection_id << " for service_type " << static_cast<int32_t>(service_type) << " session_id " - << static_cast<int32_t>(session_id)); + << static_cast<int32_t>(session_id) + << (reason.empty() ? "" : " reason \"" + reason + "\"")); } void ProtocolHandlerImpl::SendEndSessionNAck(ConnectionID connection_id, uint32_t session_id, uint8_t protocol_version, - uint8_t service_type) { + uint8_t service_type, + const std::string reason) { std::vector<std::string> rejectedParams; SendEndSessionNAck(connection_id, session_id, protocol_version, service_type, - rejectedParams); + rejectedParams, + reason); } void ProtocolHandlerImpl::SendEndSessionNAck( @@ -524,7 +546,8 @@ void ProtocolHandlerImpl::SendEndSessionNAck( uint32_t session_id, uint8_t protocol_version, uint8_t service_type, - std::vector<std::string>& rejectedParams) { + std::vector<std::string>& rejectedParams, + const std::string reason) { SDL_LOG_AUTO_TRACE(); ProtocolFramePtr ptr( @@ -540,20 +563,35 @@ void ProtocolHandlerImpl::SendEndSessionNAck( uint8_t maxProtocolVersion = SupportedSDLProtocolVersion(); + utils::SemanticVersion full_version; + if (!session_observer_.ProtocolVersionUsed( + connection_id, session_id, full_version)) { + SDL_LOG_WARN("Connection: " << connection_id << " and/or session: " + << session_id << "no longer exist(s)."); + return; + } + if (protocol_version >= PROTOCOL_VERSION_5 && - maxProtocolVersion >= PROTOCOL_VERSION_5 && rejectedParams.size() > 0) { + maxProtocolVersion >= PROTOCOL_VERSION_5) { BsonObject payloadObj; bson_object_initialize_default(&payloadObj); - BsonArray rejectedParamsArr; - bson_array_initialize(&rejectedParamsArr, rejectedParams.size()); - for (std::string param : rejectedParams) { - char paramPtr[256]; - strncpy(paramPtr, param.c_str(), sizeof(paramPtr)); - paramPtr[sizeof(paramPtr) - 1] = '\0'; - bson_array_add_string(&rejectedParamsArr, paramPtr); + + if (rejectedParams.size() > 0) { + BsonArray rejectedParamsArr; + bson_array_initialize(&rejectedParamsArr, rejectedParams.size()); + for (std::string param : rejectedParams) { + char paramPtr[256]; + strncpy(paramPtr, param.c_str(), sizeof(paramPtr)); + paramPtr[sizeof(paramPtr) - 1] = '\0'; + bson_array_add_string(&rejectedParamsArr, paramPtr); + } + bson_object_put_array( + &payloadObj, strings::rejected_params, &rejectedParamsArr); + } + if (!reason.empty() && full_version >= min_reason_param_version) { + bson_object_put_string( + &payloadObj, strings::reason, const_cast<char*>(reason.c_str())); } - bson_object_put_array( - &payloadObj, strings::rejected_params, &rejectedParamsArr); uint8_t* payloadBytes = bson_object_to_bytes(&payloadObj); ptr->set_data(payloadBytes, bson_object_size(&payloadObj)); free(payloadBytes); @@ -566,7 +604,8 @@ void ProtocolHandlerImpl::SendEndSessionNAck( SDL_LOG_DEBUG("SendEndSessionNAck() for connection " << connection_id << " for service_type " << static_cast<int32_t>(service_type) << " session_id " - << static_cast<int32_t>(session_id)); + << static_cast<int32_t>(session_id) + << (reason.empty() ? "" : " reason \"" + reason + "\"")); } SessionObserver& ProtocolHandlerImpl::get_session_observer() { @@ -1553,8 +1592,9 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageEndSession( const ServiceType service_type = ServiceTypeFromByte(packet.service_type()); const ConnectionID connection_id = packet.connection_id(); + std::string err_reason; const uint32_t session_key = session_observer_.OnSessionEndedCallback( - connection_id, current_session_id, &hash_id, service_type); + connection_id, current_session_id, &hash_id, service_type, &err_reason); // TODO(EZamakhov): add clean up output queue (for removed service) if (session_key != 0) { @@ -1576,12 +1616,14 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageEndSession( current_session_id, packet.protocol_version(), service_type, - rejectedParams); + rejectedParams, + err_reason); } else { SendEndSessionNAck(connection_id, current_session_id, packet.protocol_version(), - service_type); + service_type, + err_reason); } } return RESULT_OK; @@ -1694,8 +1736,12 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession( << service_type << ", disallowed by settings."); service_status_update_handler_->OnServiceUpdate( connection_key, service_type, settings_check); - SendStartSessionNAck( - connection_id, session_id, protocol_version, service_type); + SendStartSessionNAck(connection_id, + session_id, + protocol_version, + service_type, + "Service type: " + std::to_string(service_type) + + " disallowed by settings"); return RESULT_OK; } @@ -1772,7 +1818,9 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageRegisterSecondaryTransport( } void ProtocolHandlerImpl::NotifySessionStarted( - const SessionContext& context, std::vector<std::string>& rejected_params) { + const SessionContext& context, + std::vector<std::string>& rejected_params, + const std::string err_reason) { SDL_LOG_AUTO_TRACE(); ProtocolFramePtr packet; @@ -1805,7 +1853,8 @@ void ProtocolHandlerImpl::NotifySessionStarted( session_id, protocol_version, packet->service_type(), - rejected_params); + rejected_params, + err_reason); return; } @@ -1869,6 +1918,11 @@ void ProtocolHandlerImpl::NotifySessionStarted( bson_object_get_string(&request_params, strings::protocol_version); std::string version_string(version_param == NULL ? "" : version_param); fullVersion = std::make_shared<utils::SemanticVersion>(version_string); + + const auto connection_key = session_observer_.KeyFromPair( + packet->connection_id(), context.new_session_id_); + connection_handler_.BindProtocolVersionWithSession(connection_key, + *fullVersion); // Constructed payloads added in Protocol v5 if (fullVersion->major_version_ < PROTOCOL_VERSION_5) { rejected_params.push_back(std::string(strings::protocol_version)); @@ -1922,7 +1976,8 @@ void ProtocolHandlerImpl::NotifySessionStarted( packet->session_id(), protocol_version, packet->service_type(), - rejected_params); + rejected_params, + "SSL Handshake failed due to rejected parameters"); } else if (ssl_context->IsInitCompleted()) { // mark service as protected session_observer_.SetProtectionFlag(connection_key, service_type); @@ -1955,7 +2010,8 @@ void ProtocolHandlerImpl::NotifySessionStarted( packet->session_id(), protocol_version, packet->service_type(), - rejected_params); + rejected_params, + "System time provider is not ready"); } } } @@ -1983,11 +2039,13 @@ void ProtocolHandlerImpl::NotifySessionStarted( connection_key, context.service_type_, ServiceStatus::SERVICE_START_FAILED); - SendStartSessionNAck(context.connection_id_, - packet->session_id(), - protocol_version, - packet->service_type(), - rejected_params); + SendStartSessionNAck( + context.connection_id_, + packet->session_id(), + protocol_version, + packet->service_type(), + rejected_params, + "Certain parameters in the StartService request were rejected"); } } diff --git a/src/components/protocol_handler/test/protocol_handler_tm_test.cc b/src/components/protocol_handler/test/protocol_handler_tm_test.cc index 312ec88930..d5d68d9b83 100644 --- a/src/components/protocol_handler/test/protocol_handler_tm_test.cc +++ b/src/components/protocol_handler/test/protocol_handler_tm_test.cc @@ -146,8 +146,8 @@ typedef std::shared_ptr< MockServiceStatusUpdateHandlerListenerPtr; // custom action to call a member function with 6 arguments -ACTION_P4(InvokeMemberFuncWithArg2, ptr, memberFunc, a, b) { - (ptr->*memberFunc)(a, b); +ACTION_P5(InvokeMemberFuncWithArg3, ptr, memberFunc, a, b, c) { + (ptr->*memberFunc)(a, b, c); } namespace { @@ -311,10 +311,11 @@ class ProtocolHandlerImplTest : public ::testing::Test { // Return sessions start success WillOnce(DoAll( NotifyTestAsyncWaiter(waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, context, - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; // Expect send Ack with PROTECTION_OFF (on no Security Manager) @@ -520,7 +521,7 @@ TEST_F(ProtocolHandlerImplTest, WillRepeatedly( DoAll(NotifyTestAsyncWaiter(&waiter), SaveArg<2>(&service_type), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -528,10 +529,16 @@ TEST_F(ProtocolHandlerImplTest, service_type, HASH_ID_WRONG, PROTECTION_OFF), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times += call_times; // Expect send NAck + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .Times(call_times) + .WillRepeatedly(Return(true)); + EXPECT_CALL(transport_manager_mock, SendMessageToDevice(ControlMessage(FRAME_DATA_START_SERVICE_NACK, PROTECTION_OFF))) @@ -606,7 +613,7 @@ TEST_F(ProtocolHandlerImplTest, StartSession_Protected_SessionObserverReject) { WillRepeatedly(DoAll( NotifyTestAsyncWaiter(&waiter), SaveArg<2>(&service_type), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -614,10 +621,16 @@ TEST_F(ProtocolHandlerImplTest, StartSession_Protected_SessionObserverReject) { service_type, HASH_ID_WRONG, callback_protection_flag), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times += call_times; // Expect send NAck with encryption OFF + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .Times(call_times) + .WillRepeatedly(Return(true)); + EXPECT_CALL(transport_manager_mock, SendMessageToDevice(ControlMessage(FRAME_DATA_START_SERVICE_NACK, PROTECTION_OFF))) @@ -676,7 +689,7 @@ TEST_F(ProtocolHandlerImplTest, // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -684,7 +697,8 @@ TEST_F(ProtocolHandlerImplTest, start_service, HASH_ID_WRONG, PROTECTION_OFF), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; SetProtocolVersion2(); @@ -837,6 +851,9 @@ TEST_F(ProtocolHandlerImplTest, rejected_param_list.push_back(protocol_handler::strings::video_codec); EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .WillOnce(Return(true)); + EXPECT_CALL(session_observer_mock, OnSessionStartedCallback(connection_id2, session_id2, start_service, @@ -844,7 +861,7 @@ TEST_F(ProtocolHandlerImplTest, An<const BsonObject*>())) .WillOnce(DoAll( NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id2, session_id2, @@ -852,8 +869,9 @@ TEST_F(ProtocolHandlerImplTest, start_service, HASH_ID_WRONG, PROTECTION_OFF), - ByRef(rejected_param_list)), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + ByRef(rejected_param_list), + std::string()), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id1, session_id1, @@ -861,7 +879,8 @@ TEST_F(ProtocolHandlerImplTest, start_service, HASH_ID_WRONG, PROTECTION_OFF), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; BsonObject bson_ack_params; @@ -963,6 +982,9 @@ TEST_F(ProtocolHandlerImplTest, StartSession_Audio_RejectByTransportType) { .WillOnce(ReturnRef(video_service_transports)); // Expect send Ack + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .WillRepeatedly(Return(true)); EXPECT_CALL(transport_manager_mock, SendMessageToDevice(ControlMessage(FRAME_DATA_START_SERVICE_NACK, PROTECTION_OFF))) @@ -1002,6 +1024,10 @@ TEST_F(ProtocolHandlerImplTest, StartSession_Video_RejectByTransportType) { .WillOnce(ReturnRef(video_service_transports)); // Expect send Ack + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .WillRepeatedly(Return(true)); + EXPECT_CALL(transport_manager_mock, SendMessageToDevice(ControlMessage(FRAME_DATA_START_SERVICE_NACK, PROTECTION_OFF))) @@ -1028,8 +1054,11 @@ TEST_F(ProtocolHandlerImplTest, EndSession_SessionObserverReject) { // Expect ConnectionHandler check EXPECT_CALL(session_observer_mock, - OnSessionEndedCallback( - connection_id, session_id, An<uint32_t*>(), service)) + OnSessionEndedCallback(connection_id, + session_id, + An<uint32_t*>(), + service, + An<std::string*>())) . // reject session start WillOnce( @@ -1038,6 +1067,10 @@ TEST_F(ProtocolHandlerImplTest, EndSession_SessionObserverReject) { SetProtocolVersion2(); // Expect send NAck + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .WillRepeatedly(Return(true)); + EXPECT_CALL(transport_manager_mock, SendMessageToDevice( ControlMessage(FRAME_DATA_END_SERVICE_NACK, PROTECTION_OFF))) @@ -1062,8 +1095,11 @@ TEST_F(ProtocolHandlerImplTest, EndSession_Success) { // Expect ConnectionHandler check EXPECT_CALL(session_observer_mock, - OnSessionEndedCallback( - connection_id, session_id, An<uint32_t*>(), service)) + OnSessionEndedCallback(connection_id, + session_id, + An<uint32_t*>(), + service, + An<std::string*>())) . // return sessions start success WillOnce(DoAll(NotifyTestAsyncWaiter(waiter), Return(connection_key))); @@ -1120,7 +1156,7 @@ TEST_F(ProtocolHandlerImplTest, SecurityEnable_StartSessionProtocoloV1) { // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -1128,7 +1164,8 @@ TEST_F(ProtocolHandlerImplTest, SecurityEnable_StartSessionProtocoloV1) { start_service, HASH_ID_WRONG, PROTECTION_OFF), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; SetProtocolVersion2(); @@ -1191,7 +1228,7 @@ TEST_F(ProtocolHandlerImplTest, SecurityEnable_StartSessionUnprotected) { // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -1199,7 +1236,8 @@ TEST_F(ProtocolHandlerImplTest, SecurityEnable_StartSessionUnprotected) { start_service, HASH_ID_WRONG, PROTECTION_OFF), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; SetProtocolVersion2(); @@ -1261,10 +1299,11 @@ TEST_F(ProtocolHandlerImplTest, SecurityEnable_StartSessionProtected_Fail) { // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, context, - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; SetProtocolVersion2(); @@ -1329,7 +1368,7 @@ TEST_F(ProtocolHandlerImplTest, // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -1337,7 +1376,8 @@ TEST_F(ProtocolHandlerImplTest, start_service, HASH_ID_WRONG, PROTECTION_ON), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; SetProtocolVersion2(); @@ -1420,10 +1460,11 @@ TEST_F(ProtocolHandlerImplTest, // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, context, - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; std::vector<int> services; @@ -1516,7 +1557,7 @@ TEST_F(ProtocolHandlerImplTest, // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -1524,7 +1565,8 @@ TEST_F(ProtocolHandlerImplTest, start_service, HASH_ID_WRONG, PROTECTION_ON), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; // call new SSLContext creation @@ -1629,7 +1671,7 @@ TEST_F( // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -1637,7 +1679,8 @@ TEST_F( start_service, HASH_ID_WRONG, PROTECTION_ON), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; // call new SSLContext creation @@ -1740,7 +1783,7 @@ TEST_F(ProtocolHandlerImplTest, // Return sessions start success WillOnce( DoAll(NotifyTestAsyncWaiter(&waiter), - InvokeMemberFuncWithArg2(protocol_handler_impl.get(), + InvokeMemberFuncWithArg3(protocol_handler_impl.get(), &ProtocolHandler::NotifySessionStarted, GetSessionContext(connection_id, NEW_SESSION_ID, @@ -1748,7 +1791,8 @@ TEST_F(ProtocolHandlerImplTest, start_service, HASH_ID_WRONG, PROTECTION_ON), - ByRef(empty_rejected_param_)))); + ByRef(empty_rejected_param_), + std::string()))); times++; // call new SSLContext creation @@ -2121,7 +2165,7 @@ TEST_F(ProtocolHandlerImplTest, // A TransportUpdateEvent is also issued after Start Service ACK. We don't // check it in this test case. - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2173,7 +2217,7 @@ TEST_F(ProtocolHandlerImplTest, std::vector<int32_t> expected_video_service_transports; expected_video_service_transports.push_back(1); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2228,7 +2272,7 @@ TEST_F(ProtocolHandlerImplTest, std::vector<int32_t> expected_video_service_transports; expected_video_service_transports.push_back(2); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2282,7 +2326,7 @@ TEST_F( std::vector<int32_t> expected_video_service_transports; expected_video_service_transports.push_back(2); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2339,7 +2383,7 @@ TEST_F(ProtocolHandlerImplTest, SetSecondaryTransportID(_, kDisabledSecondary)) .WillOnce(Return(dummy_st)); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2383,7 +2427,7 @@ TEST_F(ProtocolHandlerImplTest, expected_video_service_transports.push_back(1); expected_video_service_transports.push_back(2); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2424,7 +2468,7 @@ TEST_F( SetSecondaryTransportID(_, kDisabledSecondary)) .WillOnce(Return(dummy_st)); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2526,7 +2570,7 @@ TEST_F(ProtocolHandlerImplTest, // TransportEventUpdate frame. Enable ProtocolVersionUsed() call and verify // that transport_manager_mock will NOT receive another SendMessageToDevice() // call. - ON_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + ON_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillByDefault(Return(true)); #ifdef ENABLE_SECURITY @@ -2585,7 +2629,7 @@ TEST_F(ProtocolHandlerImplTest, StartSessionAck_PrimaryTransportUSBHostMode) { // A TransportUpdateEvent is also issued after Start Service ACK. We don't // check it in this test case. - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifySecondaryTransportParamsInStartSessionAck( @@ -2607,7 +2651,7 @@ TEST_F(ProtocolHandlerImplTest, StartSessionAck_CloudAppAuthTokenAvailable) { // A TransportUpdateEvent is also issued after Start Service ACK. We don't // check it in this test case. - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly(Return(false)); VerifyCloudAppParamsInStartSessionAck(policy_id, auth_token); @@ -2688,7 +2732,7 @@ TEST_F(ProtocolHandlerImplTest, .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(E_SUCCESS))); times++; - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_5), Return(true))); @@ -2809,7 +2853,7 @@ TEST_F(ProtocolHandlerImplTest, .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(E_SUCCESS))); times++; - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_5), Return(true))); @@ -2890,7 +2934,7 @@ TEST_F(ProtocolHandlerImplTest, .WillOnce(Return(DataAccessor<SessionConnectionMap>( session_connection_map_, session_connection_map_lock_ptr_))); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_5), Return(true))); @@ -2961,7 +3005,7 @@ TEST_F(ProtocolHandlerImplTest, .WillOnce(Return(DataAccessor<SessionConnectionMap>( session_connection_map_, session_connection_map_lock_ptr_))); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, _)) + EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(_, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_5), Return(true))); @@ -3011,7 +3055,7 @@ TEST_F(ProtocolHandlerImplTest, RegisterSecondaryTransport_SUCCESS) { transport_manager::ConnectionUID primary_connection_id = 123; EXPECT_CALL(session_observer_mock, - ProtocolVersionUsed(primary_connection_id, _, _)) + ProtocolVersionUsed(primary_connection_id, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_5), Return(true))); @@ -3046,7 +3090,7 @@ TEST_F(ProtocolHandlerImplTest, RegisterSecondaryTransport_FAILURE) { transport_manager::ConnectionUID primary_connection_id = 123; EXPECT_CALL(session_observer_mock, - ProtocolVersionUsed(primary_connection_id, _, _)) + ProtocolVersionUsed(primary_connection_id, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_5), Return(true))); @@ -3510,7 +3554,7 @@ TEST_F(ProtocolHandlerImplTest, SendEndServicePrivate_NoConnection_MessageNotSent) { // Expect check connection with ProtocolVersionUsed EXPECT_CALL(session_observer_mock, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(false)); // Expect not send End Service EXPECT_CALL(transport_manager_mock, SendMessageToDevice(_)).Times(0); @@ -3529,7 +3573,7 @@ TEST_F(ProtocolHandlerImplTest, // Expect check connection with ProtocolVersionUsed EXPECT_CALL(session_observer_mock, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); // Expect send End Service EXPECT_CALL( @@ -3553,7 +3597,7 @@ TEST_F(ProtocolHandlerImplTest, // Expect check connection with ProtocolVersionUsed EXPECT_CALL(session_observer_mock, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(DoAll(SetArgReferee<2>(PROTOCOL_VERSION_1), Return(true))); // Expect send End Service EXPECT_CALL(transport_manager_mock, @@ -3574,7 +3618,7 @@ TEST_F(ProtocolHandlerImplTest, TEST_F(ProtocolHandlerImplTest, SendHeartBeat_NoConnection_NotSent) { // Expect check connection with ProtocolVersionUsed EXPECT_CALL(session_observer_mock, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(false)); // Expect not send HeartBeat EXPECT_CALL(transport_manager_mock, SendMessageToDevice(_)).Times(0); @@ -3592,7 +3636,7 @@ TEST_F(ProtocolHandlerImplTest, SendHeartBeat_Successful) { // Expect check connection with ProtocolVersionUsed EXPECT_CALL(session_observer_mock, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(DoAll(SetArgReferee<2>(PROTOCOL_VERSION_3), Return(true))); // Expect send HeartBeat EXPECT_CALL( @@ -3617,7 +3661,8 @@ TEST_F(ProtocolHandlerImplTest, SendHeartBeatAck_Successful) { // Expect double check connection and protocol version with // ProtocolVersionUsed - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(connection_id, _, _)) + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(connection_id, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_3), Return(true))); // Expect send HeartBeatAck @@ -3646,7 +3691,8 @@ TEST_F(ProtocolHandlerImplTest, // Expect two checks of connection and protocol version with // ProtocolVersionUsed - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(connection_id, _, _)) + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(connection_id, _, An<uint8_t&>())) .Times(2) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_1), Return(true))); @@ -3823,7 +3869,8 @@ TEST_F(ProtocolHandlerImplTest, SendServiceDataAck_PreVersion5) { EXPECT_CALL(session_observer_mock, PairFromKey(connection_key, _, _)) .WillOnce( DoAll(SetArgPointee<1>(connection_id), SetArgPointee<2>(session_id))); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(connection_id, _, _)) + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(connection_id, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_4), Return(true))); @@ -3849,7 +3896,8 @@ TEST_F(ProtocolHandlerImplTest, SendServiceDataAck_AfterVersion5) { EXPECT_CALL(session_observer_mock, PairFromKey(connection_key, _, _)) .WillOnce( DoAll(SetArgPointee<1>(connection_id), SetArgPointee<2>(session_id))); - EXPECT_CALL(session_observer_mock, ProtocolVersionUsed(connection_id, _, _)) + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(connection_id, _, An<uint8_t&>())) .WillRepeatedly( DoAll(SetArgReferee<2>(PROTOCOL_VERSION_5), Return(true))); @@ -3866,6 +3914,256 @@ TEST_F(ProtocolHandlerImplTest, SendServiceDataAck_AfterVersion5) { EXPECT_TRUE(waiter->WaitFor(times, kAsyncExpectationsTimeout)); } +/* + * ProtocolHandler shall send StartServiceNAK with a reason param when starting + * a video/audio service if the service type is disallowed by the settings + */ +TEST_F(ProtocolHandlerImplTest, StartSession_NACKReason_DisallowedBySettings) { + const ServiceType service_type = kMobileNav; + const utils::SemanticVersion min_reason_param_version(5, 3, 0); + +#ifdef ENABLE_SECURITY + AddSecurityManager(); + + EXPECT_CALL(session_observer_mock, + GetSSLContext(connection_key, service_type)) + .WillOnce(ReturnNull()); +#endif // ENABLE_SECURITY + + AddConnection(); + + // Expect verification of allowed transport + EXPECT_CALL(session_observer_mock, + TransportTypeProfileStringFromConnHandle(connection_id)) + .WillOnce(Return("TCP_WIFI")); + + std::vector<std::string> allowed_transports{"AOA_USB"}; + EXPECT_CALL(protocol_handler_settings_mock, video_service_transports()) + .WillOnce(ReturnRef(allowed_transports)); + EXPECT_CALL(protocol_handler_settings_mock, audio_service_transports()) + .WillOnce(ReturnRef(allowed_transports)); + + // Expect check connection with ProtocolVersionUsed + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed( + connection_id, NEW_SESSION_ID, An<utils::SemanticVersion&>())) + .WillOnce( + DoAll(SetArgReferee<2>(min_reason_param_version), Return(true))); + + BsonObject bson_nack_params; + bson_object_initialize_default(&bson_nack_params); + // NAK reason param + std::string reason = "Service type: " + std::to_string(service_type) + + " disallowed by settings"; + bson_object_put_string(&bson_nack_params, + protocol_handler::strings::reason, + const_cast<char*>(reason.c_str())); + std::vector<uint8_t> nack_params = + CreateVectorFromBsonObject(&bson_nack_params); + bson_object_deinitialize(&bson_nack_params); + + EXPECT_CALL(transport_manager_mock, + SendMessageToDevice(ControlMessage(FRAME_DATA_START_SERVICE_NACK, + PROTECTION_OFF, + connection_id, + Eq(nack_params)))) + .WillOnce(Return(E_SUCCESS)); + + SendControlMessage(PROTECTION_OFF, + service_type, + NEW_SESSION_ID, + FRAME_DATA_START_SERVICE, + PROTOCOL_VERSION_5); + + usleep(kAddSessionWaitTimeMs * kMicrosecondsInMillisecond); +} + +/* + * ProtocolHandler shall send StartServiceNAK with a reason param on + * session_observer rejection Check protection flag OFF for all services from + * kControl to kBulk + */ +TEST_F(ProtocolHandlerImplTest, StartSession_NACKReason_SessionObserverReject) { + const std::vector<ServiceType> service_types{ + kControl, kRpc, kAudio, kMobileNav, kBulk}; + + const int call_times = service_types.size(); + const utils::SemanticVersion min_reason_param_version(5, 3, 0); + const std::string err_reason = "Unable to create new session"; + AddConnection(); + +#ifdef ENABLE_SECURITY + AddSecurityManager(); + + EXPECT_CALL(session_observer_mock, + GetSSLContext(connection_key, + AnyOf(kControl, kRpc, kAudio, kMobileNav, kBulk))) + .WillRepeatedly(ReturnNull()); +#endif // ENABLE_SECURITY + + TestAsyncWaiter waiter; + uint32_t times = 0; + ServiceType service_type; + // Expect verification of allowed transport + EXPECT_CALL(session_observer_mock, + TransportTypeProfileStringFromConnHandle(connection_id)) + .Times(call_times) + .WillRepeatedly(Return("TCP_WIFI")); + + std::vector<std::string> allowed_transports{"TCP_WIFI"}; + EXPECT_CALL(protocol_handler_settings_mock, audio_service_transports()) + .Times(call_times) + .WillRepeatedly(ReturnRef(allowed_transports)); + EXPECT_CALL(protocol_handler_settings_mock, video_service_transports()) + .Times(call_times) + .WillRepeatedly(ReturnRef(allowed_transports)); + + // Expect ConnectionHandler check + EXPECT_CALL( + session_observer_mock, + OnSessionStartedCallback(connection_id, + NEW_SESSION_ID, + AnyOf(kControl, kRpc, kAudio, kMobileNav, kBulk), + PROTECTION_OFF, + An<const BsonObject*>())) + .Times(call_times) + . + // Return sessions start rejection + WillRepeatedly( + DoAll(NotifyTestAsyncWaiter(&waiter), + SaveArg<2>(&service_type), + InvokeMemberFuncWithArg3( + protocol_handler_impl.get(), + &protocol_handler::ProtocolHandler::NotifySessionStarted, + GetSessionContext(connection_id, + NEW_SESSION_ID, + SESSION_START_REJECT, + service_type, + protocol_handler::HASH_ID_WRONG, + PROTECTION_OFF), + ByRef(empty_rejected_param_), + err_reason))); + times += call_times; + + // Expect send NAck + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .Times(call_times) + .WillRepeatedly( + DoAll(SetArgReferee<2>(min_reason_param_version), Return(true))); + + BsonObject bson_nack_params; + bson_object_initialize_default(&bson_nack_params); + // NAK reason param + bson_object_put_string(&bson_nack_params, + protocol_handler::strings::reason, + const_cast<char*>(err_reason.c_str())); + std::vector<uint8_t> nack_params = + CreateVectorFromBsonObject(&bson_nack_params); + bson_object_deinitialize(&bson_nack_params); + + EXPECT_CALL(transport_manager_mock, + SendMessageToDevice(ControlMessage(FRAME_DATA_START_SERVICE_NACK, + PROTECTION_OFF, + connection_id, + Eq(nack_params)))) + .Times(call_times) + + .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(E_SUCCESS))); + times += call_times; + + for (const ServiceType& service_type : service_types) { + SendControlMessage(PROTECTION_OFF, + service_type, + NEW_SESSION_ID, + FRAME_DATA_START_SERVICE, + PROTOCOL_VERSION_5); + } + + EXPECT_TRUE(waiter.WaitFor(times, kAsyncExpectationsTimeout)); +} + +/* + * ProtocolHandler shall send EndServiceNAK with a reason param if + * OnSessionEndedCallback returns an 0 + */ +TEST_F(ProtocolHandlerImplTest, + EndSession_NACKReason_OnSessionEndedCallbackFailed) { + const utils::SemanticVersion min_reason_param_version(5, 3, 0); + std::string err_reason = + "Wrong hash_id for session " + std::to_string(session_id); + std::shared_ptr<TestAsyncWaiter> waiter = std::make_shared<TestAsyncWaiter>(); + uint32_t times = 0; + + AddSession(waiter, times); + const ServiceType service_type = kRpc; + +#ifdef ENABLE_SECURITY + AddSecurityManager(); + + EXPECT_CALL(session_observer_mock, + GetSSLContext(connection_key, service_type)) + .WillOnce(ReturnNull()); +#endif // ENABLE_SECURITY + + // Expect ConnectionHandler check + EXPECT_CALL(session_observer_mock, + OnSessionEndedCallback(connection_id, + session_id, + An<uint32_t*>(), + service_type, + An<std::string*>())) + . + // reject session start + WillOnce(DoAll(NotifyTestAsyncWaiter(waiter), + SetArgPointee<4>(err_reason), + Return(SESSION_START_REJECT))); + times++; + + // Expect send NAck + EXPECT_CALL(session_observer_mock, + ProtocolVersionUsed(_, _, An<utils::SemanticVersion&>())) + .WillOnce( + DoAll(SetArgReferee<2>(min_reason_param_version), Return(true))); + + std::vector<std::string> rejected_param_list; + rejected_param_list.push_back(protocol_handler::strings::hash_id); + + BsonObject bson_nack_params; + bson_object_initialize_default(&bson_nack_params); + // Rejected params + BsonArray bson_arr; + bson_array_initialize(&bson_arr, 1); + bson_array_add_string(&bson_arr, + const_cast<char*>(protocol_handler::strings::hash_id)); + bson_object_put_array( + &bson_nack_params, protocol_handler::strings::rejected_params, &bson_arr); + // NAK reason param + bson_object_put_string(&bson_nack_params, + protocol_handler::strings::reason, + const_cast<char*>(err_reason.c_str())); + + std::vector<uint8_t> nack_params = + CreateVectorFromBsonObject(&bson_nack_params); + bson_object_deinitialize(&bson_nack_params); + + EXPECT_CALL(transport_manager_mock, + SendMessageToDevice(ControlMessage(FRAME_DATA_END_SERVICE_NACK, + PROTECTION_OFF, + connection_id, + Eq(nack_params)))) + .WillOnce(DoAll(NotifyTestAsyncWaiter(waiter), Return(E_SUCCESS))); + times++; + + SendControlMessage(PROTECTION_OFF, + service_type, + session_id, + FRAME_DATA_END_SERVICE, + PROTOCOL_VERSION_5); + + EXPECT_TRUE(waiter->WaitFor(times, kAsyncExpectationsTimeout)); +} + } // namespace protocol_handler_test } // namespace components } // namespace test diff --git a/src/components/security_manager/test/security_manager_test.cc b/src/components/security_manager/test/security_manager_test.cc index 0cbe204f38..4145334115 100644 --- a/src/components/security_manager/test/security_manager_test.cc +++ b/src/components/security_manager/test/security_manager_test.cc @@ -70,6 +70,7 @@ using security_manager::SSLContext; using security_manager_test::InternalErrorWithErrId; using ::testing::_; +using ::testing::An; using ::testing::DoAll; using ::testing::Return; using ::testing::ReturnNull; @@ -286,7 +287,7 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { TestAsyncWaiter waiter; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); EXPECT_CALL(mock_protocol_handler, @@ -332,7 +333,7 @@ TEST_F(SecurityManagerTest, GetEmptyQuery) { // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); EXPECT_CALL( @@ -354,7 +355,7 @@ TEST_F(SecurityManagerTest, GetWrongJSONSize) { // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); // Expect InternalError with ERROR_ID EXPECT_CALL( @@ -382,7 +383,7 @@ TEST_F(SecurityManagerTest, GetInvalidQueryId) { .WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; @@ -429,7 +430,7 @@ TEST_F(SecurityManagerTest, CreateSSLContext_ErrorCreateSSL) { // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp( @@ -459,7 +460,7 @@ TEST_F(SecurityManagerTest, CreateSSLContext_SetSSLContextError) { // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); EXPECT_CALL( @@ -515,7 +516,7 @@ TEST_F(SecurityManagerTest, StartHandshake_ServiceStillUnprotected) { // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); // Expect InternalError with ERROR_INTERNAL EXPECT_CALL(mock_protocol_handler, @@ -548,7 +549,7 @@ TEST_F(SecurityManagerTest, StartHandshake_SSLInternalError) { EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, @@ -579,7 +580,7 @@ TEST_F(SecurityManagerTest, ProcessHandshakeData_WrongDataSize) { TestAsyncWaiter waiter; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(Return(true)); // Expect InternalError with ERROR_ID @@ -612,7 +613,7 @@ TEST_F(SecurityManagerTest, DISABLED_ProcessHandshakeData_ServiceNotProtected) { .WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; EXPECT_CALL( @@ -664,7 +665,7 @@ TEST_F(SecurityManagerTest, ProcessHandshakeData_InvalidData) { .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times += handshake_emulates; @@ -746,7 +747,7 @@ TEST_F(SecurityManagerTest, ProcessHandshakeData_Answer) { .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times += handshake_emulates; @@ -877,7 +878,7 @@ TEST_F(SecurityManagerTest, ProcessHandshakeData_HandshakeFinished) { // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)).Times(2); EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) + ProtocolVersionUsed(connection_id, session_id, An<uint8_t&>())) .Times(2) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times += 2; // matches to the number above |