diff options
author | Conlain Kelly <conlain.k@gmail.com> | 2018-08-10 11:04:43 -0400 |
---|---|---|
committer | Conlain Kelly <conlain.k@gmail.com> | 2018-08-10 11:04:43 -0400 |
commit | 72a64f7419d20bc379d1e050fdaac90b2a6d097f (patch) | |
tree | f5be0f57b4699b2fd30a459c105cfb44c6903508 /src/components/protocol_handler/src/protocol_handler_impl.cc | |
parent | 3b5ddfdacb94f4e3f5752bb7165ca668f62f4a5d (diff) | |
parent | 43e53192045daeff8e9e2887c8b67894725240b5 (diff) | |
download | sdl_core-72a64f7419d20bc379d1e050fdaac90b2a6d097f.tar.gz |
Merge branch 'develop' of https://github.com/smartdevicelink/sdl_core into feature/boost_datetime_implementation
Diffstat (limited to 'src/components/protocol_handler/src/protocol_handler_impl.cc')
-rw-r--r-- | src/components/protocol_handler/src/protocol_handler_impl.cc | 648 |
1 files changed, 633 insertions, 15 deletions
diff --git a/src/components/protocol_handler/src/protocol_handler_impl.cc b/src/components/protocol_handler/src/protocol_handler_impl.cc index ee94f2f39b..b4b66f47be 100644 --- a/src/components/protocol_handler/src/protocol_handler_impl.cc +++ b/src/components/protocol_handler/src/protocol_handler_impl.cc @@ -31,6 +31,7 @@ */ #include "protocol_handler/protocol_handler_impl.h" +#include <arpa/inet.h> // for INET6_ADDRSTRLEN #include <memory.h> #include <algorithm> // std::find #include <bson_object.h> @@ -60,7 +61,8 @@ std::string ConvertPacketDataToString(const uint8_t* data, const size_t kStackSize = 65536; -ProtocolPacket::ProtocolVersion defaultProtocolVersion(5, 0, 0); +ProtocolPacket::ProtocolVersion defaultProtocolVersion(5, 1, 0); +ProtocolPacket::ProtocolVersion minMultipleTransportsVersion(5, 1, 0); ProtocolHandlerImpl::ProtocolHandlerImpl( const ProtocolHandlerSettings& settings, @@ -84,6 +86,7 @@ ProtocolHandlerImpl::ProtocolHandlerImpl( "PH ToMobile", this, threads::ThreadOptions(kStackSize)) , start_session_frame_map_lock_() , start_session_frame_map_() + , tcp_enabled_(false) #ifdef TELEMETRY_MONITOR , metric_observer_(NULL) #endif // TELEMETRY_MONITOR @@ -242,6 +245,8 @@ void ProtocolHandlerImpl::SendStartSessionAck( BsonObject& params) { LOG4CXX_AUTO_TRACE(logger_); + bool send_transport_update_event = false; + uint8_t ack_protocol_version = SupportedSDLProtocolVersion(); const bool proxy_supports_v5_protocol = @@ -317,6 +322,91 @@ void ProtocolHandlerImpl::SendStartSessionAck( "Protocol version parameter was written to bson params: " << protocol_ver_written << "; Value: " << bson_object_get_string(¶ms, strings::protocol_version)); + + LOG4CXX_INFO(logger_, + "Protocol Version String " << protocolVersionString); + + std::vector<std::string> secondaryTransports; + std::vector<int32_t> audioServiceTransports; + std::vector<int32_t> videoServiceTransports; + if (*minVersion >= minMultipleTransportsVersion) { + if (ParseSecondaryTransportConfiguration(connection_id, + secondaryTransports, + audioServiceTransports, + videoServiceTransports)) { + LOG4CXX_DEBUG(logger_, "Multiple transports are enabled."); + BsonArray secondaryTransportsArr; + bson_array_initialize(&secondaryTransportsArr, + secondaryTransports.size()); + for (unsigned int i = 0; i < secondaryTransports.size(); i++) { + char secondaryTransport[255]; + strncpy(secondaryTransport, + secondaryTransports[i].c_str(), + sizeof(secondaryTransport)); + secondaryTransport[sizeof(secondaryTransport) - 1] = '\0'; + LOG4CXX_DEBUG( + logger_, + "Adding " + << secondaryTransport + << " to secondaryTransports parameter of StartSessionAck"); + bson_array_add_string(&secondaryTransportsArr, secondaryTransport); + } + bson_object_put_array( + ¶ms, strings::secondary_transports, &secondaryTransportsArr); + + BsonArray audioServiceTransportsArr; + bson_array_initialize(&audioServiceTransportsArr, + audioServiceTransports.size()); + for (unsigned int i = 0; i < audioServiceTransports.size(); i++) { + LOG4CXX_DEBUG(logger_, + "Adding " << audioServiceTransports[i] + << " to audioServiceTransports parameter " + "of StartSessionAck"); + bson_array_add_int32(&audioServiceTransportsArr, + audioServiceTransports[i]); + } + bson_object_put_array(¶ms, + strings::audio_service_transports, + &audioServiceTransportsArr); + + BsonArray videoServiceTransportsArr; + bson_array_initialize(&videoServiceTransportsArr, + videoServiceTransports.size()); + for (unsigned int i = 0; i < videoServiceTransports.size(); i++) { + LOG4CXX_DEBUG(logger_, + "Adding " << videoServiceTransports[i] + << " to videoServiceTransports parameter " + "of StartSessionAck"); + bson_array_add_int32(&videoServiceTransportsArr, + videoServiceTransports[i]); + } + bson_object_put_array(¶ms, + strings::video_service_transports, + &videoServiceTransportsArr); + + if (settings_.multiple_transports_enabled()) { + send_transport_update_event = true; + } else { + LOG4CXX_DEBUG( + logger_, + "Multiple transports feature is disabled by configuration"); + // In this case, we must remember that this session will never have + // a secondary transport. + connection_handler_.SetSecondaryTransportID(session_id, + kDisabledSecondary); + } + } else { + LOG4CXX_WARN( + logger_, + "Failed to set up secondary transport and service type params"); + connection_handler_.SetSecondaryTransportID(session_id, + kDisabledSecondary); + } + } else { + LOG4CXX_INFO(logger_, "Older protocol version. No multiple transports"); + connection_handler_.SetSecondaryTransportID(session_id, + kDisabledSecondary); + } } uint8_t* payloadBytes = bson_object_to_bytes(¶ms); ptr->set_data(payloadBytes, bson_object_size(¶ms)); @@ -334,6 +424,16 @@ void ProtocolHandlerImpl::SendStartSessionAck( << static_cast<int32_t>(service_type) << " session_id " << static_cast<int32_t>(session_id) << " protection " << (protection ? "ON" : "OFF")); + + if (send_transport_update_event) { + // Wait until the StartService ACK has been processed for sending. + // The TransportUpdateEvent has a higher priority, being that it's + // a SERVICE_TYPE_CONTROL message. (The ACK is SERVICE_TYPE_RPC.) + LOG4CXX_DEBUG(logger_, "Waiting for the MessageToMobile queue to be empty"); + raw_ford_messages_to_mobile_.WaitDumpQueue(); + LOG4CXX_DEBUG(logger_, "Sending the TransportUpdate event"); + SendTransportUpdateEvent(connection_id, session_id); + } } void ProtocolHandlerImpl::SendStartSessionNAck(ConnectionID connection_id, @@ -491,14 +591,18 @@ void ProtocolHandlerImpl::SendEndSessionAck(ConnectionID connection_id, << static_cast<int32_t>(session_id)); } -void ProtocolHandlerImpl::SendEndServicePrivate(int32_t connection_id, +void ProtocolHandlerImpl::SendEndServicePrivate(int32_t primary_connection_id, + int32_t connection_id, uint8_t session_id, uint8_t service_type) { LOG4CXX_AUTO_TRACE(logger_); uint8_t protocol_version; if (session_observer_.ProtocolVersionUsed( - connection_id, session_id, protocol_version)) { + primary_connection_id, session_id, protocol_version)) { + LOG4CXX_TRACE(logger_, + "SendEndServicePrivate using protocol version " + << static_cast<int32_t>(protocol_version)); ProtocolFramePtr ptr( new protocol_handler::ProtocolPacket(connection_id, protocol_version, @@ -513,25 +617,31 @@ void ProtocolHandlerImpl::SendEndServicePrivate(int32_t connection_id, raw_ford_messages_to_mobile_.PostMessage( impl::RawFordMessageToMobile(ptr, false)); LOG4CXX_DEBUG(logger_, - "SendEndSession() for connection " - << connection_id << " for service_type " << service_type + "SendEndServicePrivate() for connection " + << primary_connection_id << " for service_type " + << static_cast<int>(service_type) + << " service connection " << connection_id << " session_id " << static_cast<int32_t>(session_id)); } else { LOG4CXX_WARN( logger_, - "SendEndSession is failed connection or session does not exist"); + "SendEndServicePrivate is failed connection or session does not exist"); } } void ProtocolHandlerImpl::SendEndSession(int32_t connection_id, uint8_t session_id) { - SendEndServicePrivate(connection_id, session_id, SERVICE_TYPE_RPC); + // A session is always associated with a primary connection ID + SendEndServicePrivate( + connection_id, connection_id, session_id, SERVICE_TYPE_RPC); } -void ProtocolHandlerImpl::SendEndService(int32_t connection_id, +void ProtocolHandlerImpl::SendEndService(int32_t primary_connection_id, + int32_t connection_id, uint8_t session_id, uint8_t service_type) { - SendEndServicePrivate(connection_id, session_id, service_type); + SendEndServicePrivate( + primary_connection_id, connection_id, session_id, service_type); } RESULT_CODE ProtocolHandlerImpl::SendHeartBeatAck(ConnectionID connection_id, @@ -563,6 +673,139 @@ RESULT_CODE ProtocolHandlerImpl::SendHeartBeatAck(ConnectionID connection_id, return RESULT_FAIL; } +void ProtocolHandlerImpl::SendTransportUpdateEvent(ConnectionID connection_id, + uint8_t session_id) { + LOG4CXX_AUTO_TRACE(logger_); + + uint8_t protocol_version; + if (session_observer_.ProtocolVersionUsed( + connection_id, session_id, protocol_version)) { + ProtocolFramePtr ptr( + new protocol_handler::ProtocolPacket(connection_id, + protocol_version, + PROTECTION_OFF, + FRAME_TYPE_CONTROL, + SERVICE_TYPE_CONTROL, + FRAME_DATA_TRANSPORT_EVENT_UPDATE, + session_id, + 0, + message_counters_[session_id]++)); + + BsonObject payload_obj; + bson_object_initialize_default(&payload_obj); + + int32_t tcp_port = atoi(tcp_port_.c_str()); + char tcp_ip_address[INET6_ADDRSTRLEN + 1]; + if (tcp_enabled_ && (tcp_port != 0)) { + strncpy(tcp_ip_address, tcp_ip_address_.c_str(), INET6_ADDRSTRLEN); + tcp_ip_address[INET6_ADDRSTRLEN] = '\0'; + bson_object_put_string( + &payload_obj, strings::tcp_ip_address, tcp_ip_address); + bson_object_put_int32(&payload_obj, strings::tcp_port, tcp_port); + } else { + tcp_ip_address[0] = '\0'; + bson_object_put_string( + &payload_obj, strings::tcp_ip_address, tcp_ip_address); + // omit TCP port number + } + LOG4CXX_INFO(logger_, + "SendTransportUpdateEvent IP address: " + << tcp_ip_address << " Port: " << tcp_port); + + uint8_t* payloadBytes = bson_object_to_bytes(&payload_obj); + ptr->set_data(payloadBytes, bson_object_size(&payload_obj)); + free(payloadBytes); + bson_object_deinitialize(&payload_obj); + + raw_ford_messages_to_mobile_.PostMessage( + impl::RawFordMessageToMobile(ptr, false)); + + LOG4CXX_DEBUG(logger_, + "SendTransportUpdateEvent() for connection " + << connection_id << " for session " + << static_cast<int32_t>(session_id)); + } else { + LOG4CXX_WARN(logger_, + "SendTransportUpdateEvent is failed connection or session " + "does not exist"); + } +} + +RESULT_CODE ProtocolHandlerImpl::SendRegisterSecondaryTransportAck( + ConnectionID connection_id, + ConnectionID primary_transport_connection_id, + uint8_t session_id) { + LOG4CXX_AUTO_TRACE(logger_); + + // acquire the protocol version from primary transport + uint8_t protocol_version; + if (session_observer_.ProtocolVersionUsed( + primary_transport_connection_id, session_id, protocol_version)) { + ProtocolFramePtr ptr(new protocol_handler::ProtocolPacket( + connection_id, + protocol_version, + PROTECTION_OFF, + FRAME_TYPE_CONTROL, + SERVICE_TYPE_CONTROL, + FRAME_DATA_REGISTER_SECONDARY_TRANSPORT_ACK, + session_id, + 0u, + 2)); + + raw_ford_messages_to_mobile_.PostMessage( + impl::RawFordMessageToMobile(ptr, false)); + return RESULT_OK; + } + LOG4CXX_WARN(logger_, + "RegisterSecondaryTransportAck is failed connection or session " + "does not exist"); + return RESULT_FAIL; +} + +RESULT_CODE ProtocolHandlerImpl::SendRegisterSecondaryTransportNAck( + ConnectionID connection_id, + ConnectionID primary_transport_connection_id, + uint8_t session_id, + BsonObject* reason) { + LOG4CXX_AUTO_TRACE(logger_); + + // If mobile sends an invalid session ID and we cannot find out the Connection + // ID of primary transport, then we use version 5. (The multiple-transports + // feature is added in 5.1.0.) + uint8_t protocol_version = PROTOCOL_VERSION_5; + if (primary_transport_connection_id > 0) { + // acquire the protocol version from primary transport + if (!session_observer_.ProtocolVersionUsed( + primary_transport_connection_id, session_id, protocol_version)) { + LOG4CXX_WARN(logger_, + "Failed to acquire protocol version for " + "RegisterSecondaryTransportNAck"); + return RESULT_FAIL; + } + } + + ProtocolFramePtr ptr(new protocol_handler::ProtocolPacket( + connection_id, + protocol_version, + PROTECTION_OFF, + FRAME_TYPE_CONTROL, + SERVICE_TYPE_CONTROL, + FRAME_DATA_REGISTER_SECONDARY_TRANSPORT_NACK, + session_id, + 0u, + 2)); + + if (reason) { + uint8_t* payloadBytes = bson_object_to_bytes(reason); + ptr->set_data(payloadBytes, bson_object_size(reason)); + free(payloadBytes); + } + + raw_ford_messages_to_mobile_.PostMessage( + impl::RawFordMessageToMobile(ptr, false)); + return RESULT_OK; +} + void ProtocolHandlerImpl::SendHeartBeat(int32_t connection_id, uint8_t session_id) { LOG4CXX_AUTO_TRACE(logger_); @@ -682,8 +925,7 @@ void ProtocolHandlerImpl::SendMessageToMobileApp(const RawMessagePtr message, } #ifdef TELEMETRY_MONITOR if (metric_observer_) { - PHTelemetryObserver::MessageMetric* metric = - new PHTelemetryObserver::MessageMetric(); + auto metric = std::make_shared<PHTelemetryObserver::MessageMetric>(); metric->message_id = message_id; metric->connection_key = message->connection_key(); metric->raw_msg = message; @@ -857,6 +1099,12 @@ void ProtocolHandlerImpl::OnConnectionClosed( multiframe_builder_.RemoveConnection(connection_id); } +void ProtocolHandlerImpl::OnUnexpectedDisconnect( + const transport_manager::ConnectionUID connection_id, + const transport_manager::CommunicationError& error) { + OnConnectionClosed(connection_id); +} + void ProtocolHandlerImpl::NotifyOnFailedHandshake() { LOG4CXX_AUTO_TRACE(logger_); #ifdef ENABLE_SECURITY @@ -864,6 +1112,72 @@ void ProtocolHandlerImpl::NotifyOnFailedHandshake() { #endif // ENABLE_SECURITY } +void ProtocolHandlerImpl::OnTransportConfigUpdated( + const transport_manager::transport_adapter::TransportConfig& configs) { + LOG4CXX_AUTO_TRACE(logger_); + + transport_manager::transport_adapter::TransportConfig::const_iterator it = + configs.find(transport_manager::transport_adapter::tc_enabled); + if (configs.end() == it) { + LOG4CXX_WARN(logger_, "No enabled field in OnTransportConfigUpdated"); + return; + } + + bool tcp_enabled = (0 == strcmp("true", it->second.c_str())); + std::string tcp_port; + + if (tcp_enabled) { + it = configs.find(transport_manager::transport_adapter::tc_tcp_port); + if (configs.end() == it) { + LOG4CXX_WARN(logger_, "No port field in OnTransportConfigUpdated"); + return; + } + tcp_port = it->second; + + it = configs.find(transport_manager::transport_adapter::tc_tcp_ip_address); + if (configs.end() == it) { + LOG4CXX_WARN(logger_, "No IP address field in OnTransportConfigUpdated"); + return; + } + tcp_enabled_ = true; + tcp_port_ = tcp_port; + tcp_ip_address_ = it->second; + } else { + tcp_enabled_ = false; + tcp_port_.clear(); + tcp_ip_address_.clear(); + } + + LOG4CXX_INFO(logger_, + "OnTransportConfigUpdated: new config enabled is " + << tcp_enabled_ << ". Port is " << tcp_port_ + << ". IP Address is " << tcp_ip_address_); + + // Walk the SessionConnection map and find all sessions that need a + // TransportUpdate Event. Sessions flagged with kDisabledSecondary in their + // secondary transport are ineligible for secondary transport, and + // therefore don't get this event. + DataAccessor<connection_handler::SessionConnectionMap> + session_connection_map_accessor = + connection_handler_.session_connection_map(); + const connection_handler::SessionConnectionMap& session_connection_map = + session_connection_map_accessor.GetData(); + connection_handler::SessionConnectionMap::const_iterator itr = + session_connection_map.begin(); + while (itr != session_connection_map.end()) { + const connection_handler::SessionTransports st = itr->second; + LOG4CXX_INFO(logger_, + "OnTransportConfigUpdated found session " + << itr->first << " with primary connection " + << st.primary_transport << " and secondary connection " + << st.secondary_transport); + if (st.secondary_transport != kDisabledSecondary) { + SendTransportUpdateEvent(st.primary_transport, itr->first); + } + itr++; + } +} + RESULT_CODE ProtocolHandlerImpl::SendFrame(const ProtocolFramePtr packet) { LOG4CXX_AUTO_TRACE(logger_); if (!packet) { @@ -1048,6 +1362,13 @@ RESULT_CODE ProtocolHandlerImpl::HandleSingleFrameMessage( << packet->data_size() << "; message " << ConvertPacketDataToString(packet->data(), packet->data_size())); + // Replace a potential secondary transport ID in the packet with the primary + // transport ID + const connection_handler::SessionTransports st = + connection_handler_.GetSessionTransports(packet->session_id()); + if (st.primary_transport != 0) { + packet->set_connection_id(st.primary_transport); + } const uint32_t connection_key = session_observer_.KeyFromPair( packet->connection_id(), packet->session_id()); @@ -1062,8 +1383,7 @@ RESULT_CODE ProtocolHandlerImpl::HandleSingleFrameMessage( } #ifdef TELEMETRY_MONITOR if (metric_observer_) { - PHTelemetryObserver::MessageMetric* metric = - new PHTelemetryObserver::MessageMetric(); + auto metric = std::make_shared<PHTelemetryObserver::MessageMetric>(); metric->message_id = packet->message_id(); metric->connection_key = connection_key; metric->raw_msg = rawMessage; @@ -1080,6 +1400,14 @@ RESULT_CODE ProtocolHandlerImpl::HandleMultiFrameMessage( const ProtocolFramePtr packet) { LOG4CXX_AUTO_TRACE(logger_); + // Replace a potential secondary transport ID in the packet with the primary + // transport ID + const connection_handler::SessionTransports st = + connection_handler_.GetSessionTransports(packet->session_id()); + if (st.primary_transport != 0) { + packet->set_connection_id(st.primary_transport); + } + if (multiframe_builder_.AddFrame(packet) != RESULT_OK) { LOG4CXX_WARN(logger_, "Frame assembling issue"); } @@ -1117,6 +1445,10 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessage( << packet->connection_id()); return RESULT_OK; } + case FRAME_DATA_REGISTER_SECONDARY_TRANSPORT: { + LOG4CXX_TRACE(logger_, "FrameData: RegisterSecondaryTransport"); + return HandleControlMessageRegisterSecondaryTransport(packet); + } default: LOG4CXX_WARN(logger_, "Control message of type " @@ -1401,6 +1733,11 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession( const ConnectionID connection_id = packet->connection_id(); const uint8_t session_id = packet->session_id(); + LOG4CXX_INFO(logger_, + "StartSession ID " << static_cast<int>(session_id) + << " and Connection ID " + << static_cast<int>(connection_id)); + { sync_primitives::AutoLock auto_lock(start_session_frame_map_lock_); start_session_frame_map_[std::make_pair(connection_id, session_id)] = @@ -1414,6 +1751,50 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession( return RESULT_OK; } +RESULT_CODE ProtocolHandlerImpl::HandleControlMessageRegisterSecondaryTransport( + const ProtocolFramePtr packet) { + LOG4CXX_AUTO_TRACE(logger_); + const uint8_t session_id = packet->session_id(); + const ConnectionID connection_id = packet->connection_id(); + ConnectionID primary_connection_id = 0; + + LOG4CXX_INFO(logger_, + "RegisterSecondaryTransport ID " + << static_cast<int>(session_id) << " and Connection ID " + << static_cast<int>(connection_id)); + + if (connection_handler_.OnSecondaryTransportStarted( + primary_connection_id, connection_id, session_id)) { + SendRegisterSecondaryTransportAck( + connection_id, primary_connection_id, session_id); + } else { + char reason[256]; + BsonObject registerSecondaryTransportNackObj; + bson_object_initialize_default(®isterSecondaryTransportNackObj); + if (0 == session_id) { + strncpy(reason, + "RegisterSecondaryTransport MUST include a non-zero session ID", + 255); + } else if (primary_connection_id == 0) { + strncpy(reason, "RegisterSecondaryTransport session ID not found", 255); + } else { + strncpy( + reason, + "RegisterSecondaryTransport session ID has already been registered", + 255); + } + bson_object_put_string( + ®isterSecondaryTransportNackObj, strings::reason, reason); + SendRegisterSecondaryTransportNAck(connection_id, + primary_connection_id, + session_id, + ®isterSecondaryTransportNackObj); + bson_object_deinitialize(®isterSecondaryTransportNackObj); + } + + return RESULT_OK; +} + void ProtocolHandlerImpl::NotifySessionStartedResult( int32_t connection_id, uint8_t session_id, @@ -1423,6 +1804,7 @@ void ProtocolHandlerImpl::NotifySessionStartedResult( std::vector<std::string>& rejected_params) { LOG4CXX_AUTO_TRACE(logger_); protocol_handler::SessionContext context(connection_id, + connection_id, session_id, generated_session_id, ServiceType::kInvalidServiceType, @@ -1670,8 +2052,7 @@ void ProtocolHandlerImpl::PopValideAndExpirateMultiframes() { #ifdef TELEMETRY_MONITOR if (metric_observer_) { - PHTelemetryObserver::MessageMetric* metric = - new PHTelemetryObserver::MessageMetric(); + auto metric = std::make_shared<PHTelemetryObserver::MessageMetric>(); metric->raw_msg = rawMessage; metric_observer_->EndMessageProcess(metric); } @@ -1989,4 +2370,241 @@ uint8_t ProtocolHandlerImpl::SupportedSDLProtocolVersion() const { LOG4CXX_AUTO_TRACE(logger_); return get_settings().max_supported_protocol_version(); } + +const impl::TransportTypes transportTypes = { + std::make_pair( + std::string("AOA_USB"), + impl::TransportDescription(impl::TransportType::TT_USB, false, true)), + std::make_pair(std::string("SPP_BLUETOOTH"), + impl::TransportDescription( + impl::TransportType::TT_BLUETOOTH, false, true)), + std::make_pair(std::string("IAP_BLUETOOTH"), + impl::TransportDescription( + impl::TransportType::TT_BLUETOOTH, true, false)), + std::make_pair( + std::string("IAP_USB"), + impl::TransportDescription(impl::TransportType::TT_USB, true, false)), + std::make_pair( + std::string("TCP_WIFI"), + impl::TransportDescription(impl::TransportType::TT_WIFI, true, true)), + std::make_pair( + std::string("IAP_USB_HOST_MODE"), + impl::TransportDescription(impl::TransportType::TT_USB, true, false)), + std::make_pair( + std::string("IAP_USB_DEVICE_MODE"), + impl::TransportDescription(impl::TransportType::TT_USB, true, false)), + std::make_pair( + std::string("IAP_CARPLAY"), + impl::TransportDescription(impl::TransportType::TT_WIFI, true, false))}; + +const impl::TransportDescription +ProtocolHandlerImpl::GetTransportTypeFromConnectionType( + const std::string& connection_type) const { + impl::TransportDescription result = + impl::TransportDescription(impl::TransportType::TT_NONE, false, false); + impl::TransportTypes::const_iterator it = + transportTypes.find(connection_type); + if (it != transportTypes.end()) { + result = it->second; + } else { + LOG4CXX_ERROR(logger_, "Unknown connection type " << connection_type); + } + + return result; +} + +const bool ProtocolHandlerImpl::ParseSecondaryTransportConfiguration( + const ConnectionID connection_id, + std::vector<std::string>& secondaryTransports, + std::vector<int32_t>& audioServiceTransports, + std::vector<int32_t>& videoServiceTransports) const { + LOG4CXX_AUTO_TRACE(logger_); + std::vector<std::string> secondary_transport_types; + + // First discover what the connection type of the primary transport is + // and look up the allowed secondary transports for that primary transport + const std::string connection_type = + session_observer_.TransportTypeProfileStringFromConnHandle(connection_id); + const impl::TransportDescription td = + GetTransportTypeFromConnectionType(connection_type); + if (settings_.multiple_transports_enabled()) { + if (td.transport_type_ == impl::TransportType::TT_USB) { + secondary_transport_types = settings_.secondary_transports_for_usb(); + } else if (td.transport_type_ == impl::TransportType::TT_BLUETOOTH) { + secondary_transport_types = + settings_.secondary_transports_for_bluetooth(); + } else if (td.transport_type_ == impl::TransportType::TT_WIFI) { + secondary_transport_types = settings_.secondary_transports_for_wifi(); + } else { + LOG4CXX_ERROR( + logger_, + "Bad or unknown device type in ParseSecondaryTransportConfiguration"); + return false; + } + } + // note: even if settings_.multiple_transports_enabled() is false, we still + // send out an empty "secondaryTransports" parameter, along with + // "videoServiceTransports" and "audioServiceTransports" params which are + // useful without secondary transport. + + // Then, generate the "secondaryTransports" array for the StartSession ACK + GenerateSecondaryTransportsForStartSessionAck(secondary_transport_types, + td.ios_transport_, + td.android_transport_, + secondaryTransports); + + // Next, figure out which connections audio or video services are allowed on + GenerateServiceTransportsForStartSessionAck( + settings_.multiple_transports_enabled(), + settings_.audio_service_transports(), + connection_type, + td.transport_type_, + secondary_transport_types, + audioServiceTransports); + + GenerateServiceTransportsForStartSessionAck( + settings_.multiple_transports_enabled(), + settings_.video_service_transports(), + connection_type, + td.transport_type_, + secondary_transport_types, + videoServiceTransports); + + return true; +} + +void ProtocolHandlerImpl::GenerateSecondaryTransportsForStartSessionAck( + const std::vector<std::string>& secondary_transport_types, + bool device_is_ios, + bool device_is_android, + std::vector<std::string>& secondaryTransports) const { + LOG4CXX_AUTO_TRACE(logger_); + + // Parse the "secondary_transport_types" vector (which comes from + // smartDeviceLink.ini). For each entry in the vector, add an + // appropriate string to the secondaryTransports + std::vector<std::string>::const_iterator it = + secondary_transport_types.begin(); + while (it != secondary_transport_types.end()) { + const utils::custom_string::CustomString transport_type(*it); + if (transport_type.CompareIgnoreCase("USB")) { + if (device_is_ios) { + LOG4CXX_TRACE( + logger_, + "Adding IAP_USB to secondaryTransports for StartSessionAck"); + secondaryTransports.push_back("IAP_USB"); + } + if (device_is_android) { + LOG4CXX_TRACE( + logger_, + "Adding AOA_USB to secondaryTransports for StartSessionAck"); + secondaryTransports.push_back("AOA_USB"); + } + } else if (transport_type.CompareIgnoreCase("Bluetooth")) { + if (device_is_ios) { + LOG4CXX_TRACE( + logger_, + "Adding IAP_BLUETOOTH to secondaryTransports for StartSessionAck"); + secondaryTransports.push_back("IAP_BLUETOOTH"); + } + if (device_is_android) { + LOG4CXX_TRACE( + logger_, + "Adding SPP_BLUETOOTH to secondaryTransports for StartSessionAck"); + secondaryTransports.push_back("SPP_BLUETOOTH"); + } + } + if (transport_type.CompareIgnoreCase("WiFi")) { + LOG4CXX_TRACE( + logger_, + "Adding TCP_WIFI to secondaryTransports for StartSessionAck"); + secondaryTransports.push_back("TCP_WIFI"); + } + + it++; + } +} + +void ProtocolHandlerImpl::GenerateServiceTransportsForStartSessionAck( + bool secondary_enabled, + const std::vector<std::string>& service_transports, + const std::string& primary_connection_type, + const impl::TransportType primary_transport_type, + const std::vector<std::string>& secondary_transport_types, + std::vector<int32_t>& serviceTransports) const { + LOG4CXX_AUTO_TRACE(logger_); + + if (service_transports.size() == 0) { + if (secondary_enabled && !secondary_transport_types.empty()) { + LOG4CXX_TRACE(logger_, + "Empty Service Transports. Allowing service to run on both " + "connections"); + serviceTransports.push_back(1); + serviceTransports.push_back(2); + } else { + serviceTransports.push_back(1); + } + } else { + bool fPrimaryAdded = false; + bool fSecondaryAdded = false; + std::vector<std::string>::const_iterator it = service_transports.begin(); + for (; it != service_transports.end(); it++) { + const utils::custom_string::CustomString transport(*it); + LOG4CXX_TRACE(logger_, + "Service Allowed to run on " << transport.c_str() + << " transport"); + + if (!fPrimaryAdded && + (transport.CompareIgnoreCase(primary_connection_type.c_str()) || + (transport.CompareIgnoreCase("IAP_USB") && + primary_transport_type == impl::TransportType::TT_USB))) { + LOG4CXX_TRACE(logger_, "Service allowed on primary transport"); + serviceTransports.push_back(1); + fPrimaryAdded = true; + } + + if (!fSecondaryAdded) { + const utils::custom_string::CustomString transport_type( + TransportTypeFromTransport(transport)); + std::vector<std::string>::const_iterator found = + std::find_if(secondary_transport_types.begin(), + secondary_transport_types.end(), + [&](const std::string& secondary_transport_type) { + return transport_type.CompareIgnoreCase( + secondary_transport_type.c_str()); + }); + if (found != secondary_transport_types.end()) { + LOG4CXX_TRACE(logger_, "Service allowed on secondary transport"); + serviceTransports.push_back(2); + fSecondaryAdded = true; + } + } + + if (fPrimaryAdded && fSecondaryAdded) { + break; + } + } + } +} + +const std::string ProtocolHandlerImpl::TransportTypeFromTransport( + const utils::custom_string::CustomString& transport) const { + std::string transport_type; + + if (transport.CompareIgnoreCase("IAP_BLUETOOTH") || + transport.CompareIgnoreCase("SPP_BLUETOOTH")) { + transport_type = "Bluetooth"; + } else if (transport.CompareIgnoreCase("IAP_USB") || + transport.CompareIgnoreCase("AOA_USB") || + transport.CompareIgnoreCase("IAP_USB_HOST_MODE") || + transport.CompareIgnoreCase("IAP_USB_DEVICE_MODE")) { + transport_type = "USB"; + } else if (transport.CompareIgnoreCase("TCP_WIFI") || + transport.CompareIgnoreCase("IAP_CARPLAY")) { + transport_type = "WiFi"; + } + + return transport_type; +} + } // namespace protocol_handler |