diff options
Diffstat (limited to 'src/components/transport_manager')
48 files changed, 3193 insertions, 254 deletions
diff --git a/src/components/transport_manager/CMakeLists.txt b/src/components/transport_manager/CMakeLists.txt index 4fa224393d..2f734b3a05 100644 --- a/src/components/transport_manager/CMakeLists.txt +++ b/src/components/transport_manager/CMakeLists.txt @@ -43,6 +43,12 @@ include_directories ( ${LOG4CXX_INCLUDE_DIRECTORY} ) +if (CMAKE_SYSTEM_NAME STREQUAL "QNX") + include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/include/transport_manager/tcp/platform_specific/qnx") +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") + include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/include/transport_manager/tcp/platform_specific/linux") +endif () + set(PATHS ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src @@ -96,8 +102,23 @@ if(NOT BUILD_TESTS) ) endif() +# exclude platform-dependent files before running collect_sources +list(APPEND EXCLUDE_PATHS + ${COMPONENTS_DIR}/transport_manager/include/transport_manager/tcp/platform_specific + ${COMPONENTS_DIR}/transport_manager/src/tcp/platform_specific +) + collect_sources(SOURCES "${PATHS}" "${EXCLUDE_PATHS}") +# then add platform-dependent files later +set(PLATFORM_DEPENDENT_SOURCES) +if (CMAKE_SYSTEM_NAME STREQUAL "QNX") + collect_sources(PLATFORM_DEPENDENT_SOURCES "${COMPONENTS_DIR}/transport_manager/src/tcp/platform_specific/qnx") +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") + collect_sources(PLATFORM_DEPENDENT_SOURCES "${COMPONENTS_DIR}/transport_manager/src/tcp/platform_specific/linux") +endif () +list(APPEND SOURCES ${PLATFORM_DEPENDENT_SOURCES}) + add_library("TransportManager" ${SOURCES}) target_link_libraries("TransportManager" ${LIBRARIES}) diff --git a/src/components/transport_manager/include/transport_manager/iap2_emulation/iap2_transport_adapter.h b/src/components/transport_manager/include/transport_manager/iap2_emulation/iap2_transport_adapter.h index 36a2b374dd..e53a472bcb 100644 --- a/src/components/transport_manager/include/transport_manager/iap2_emulation/iap2_transport_adapter.h +++ b/src/components/transport_manager/include/transport_manager/iap2_emulation/iap2_transport_adapter.h @@ -74,6 +74,15 @@ class IAP2BluetoothEmulationTransportAdapter : public TcpTransportAdapter { */ void DeviceSwitched(const DeviceUID& device_handle) OVERRIDE; + /** + * @brief Notification that transport's configuration is updated. This + * override is needed so that a OnTransportConfigUpdated is not sent to the + * mobile device for the emulated transport. + * + * @param new_config The new configuration of the transport + */ + void TransportConfigUpdated(const TransportConfig& new_config) OVERRIDE; + protected: /** * @brief GetDeviceType Provides SDL device type for transport adapter @@ -110,6 +119,15 @@ class IAP2USBEmulationTransportAdapter : public TcpTransportAdapter { */ void DeviceSwitched(const DeviceUID& device_handle) OVERRIDE; + /** + * @brief Notification that transport's configuration is updated. This + * override is needed so that a OnTransportConfigUpdated is not sent to the + * mobile device for the emulated transport. + * + * @param new_config The new configuration of the transport + */ + void TransportConfigUpdated(const TransportConfig& new_config) OVERRIDE; + protected: /** * @brief GetDeviceType Provides SDL device type for transport adapter diff --git a/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h new file mode 100644 index 0000000000..8154503077 --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener.h @@ -0,0 +1,41 @@ +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_H_ + +namespace transport_manager { +namespace transport_adapter { + +/** + * @brief Listener to detect various events on network interfaces + */ +class NetworkInterfaceListener { + public: + /** + * @brief Destructor + */ + virtual ~NetworkInterfaceListener() {} + + /** + * @brief Initialize this listener + */ + virtual bool Init() = 0; + + /** + * @brief Deinitialize this listener + */ + virtual void Deinit() = 0; + + /** + * @brief Start this listener + */ + virtual bool Start() = 0; + + /** + * @brief Stop this listener + */ + virtual bool Stop() = 0; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_H_ diff --git a/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener_impl.h b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener_impl.h new file mode 100644 index 0000000000..159b5ff21d --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/tcp/network_interface_listener_impl.h @@ -0,0 +1,63 @@ +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_IMPL_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_IMPL_H_ + +#include <string> +#include <memory> + +#include "utils/macro.h" +#include "transport_manager/tcp/network_interface_listener.h" + +namespace transport_manager { +namespace transport_adapter { + +class TcpClientListener; + +/** + * @brief Listener to detect various events on network interfaces + */ +class NetworkInterfaceListenerImpl : public NetworkInterfaceListener { + public: + /** + * @brief Constructor + * + * @param tcp_client_listener an instance of TcpClientListener which receives + * status updates + * @param designated_interface if we want to listen only on a specific + * network interface, specify its name + */ + NetworkInterfaceListenerImpl(TcpClientListener* tcp_client_listener, + const std::string designated_interface); + + /** + * @brief Destructor + */ + virtual ~NetworkInterfaceListenerImpl(); + + /** + * @brief Initialize this listener + */ + bool Init() OVERRIDE; + + /** + * @brief Deinitialize this listener + */ + void Deinit() OVERRIDE; + + /** + * @brief Start this listener + */ + bool Start() OVERRIDE; + + /** + * @brief Stop this listener + */ + bool Stop() OVERRIDE; + + private: + std::unique_ptr<NetworkInterfaceListener> platform_specific_impl_; +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_NETWORK_INTERFACE_LISTENER_IMPL_H_ diff --git a/src/components/transport_manager/include/transport_manager/tcp/platform_specific/linux/platform_specific_network_interface_listener_impl.h b/src/components/transport_manager/include/transport_manager/tcp/platform_specific/linux/platform_specific_network_interface_listener_impl.h new file mode 100644 index 0000000000..bb60b09a9d --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/tcp/platform_specific/linux/platform_specific_network_interface_listener_impl.h @@ -0,0 +1,201 @@ +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_LINUX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_LINUX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_ + +#include <map> +#include <string> +#include <vector> + +#include <netinet/in.h> +#include "transport_manager/tcp/network_interface_listener.h" +#include "utils/macro.h" +#include "utils/threads/thread_delegate.h" + +struct ifaddrmsg; + +namespace transport_manager { +namespace transport_adapter { + +class TcpClientListener; + +/** + * @brief Struct to keep network interface's status flags and IP addresses + */ +class InterfaceStatus { + public: + InterfaceStatus() + : flags_(0) + , has_ipv4_(false) + , has_ipv6_(false) + , ipv4_address_() + , ipv6_address_() {} + ~InterfaceStatus() {} + + bool IsAvailable() const; + bool IsLoopback() const; + // only for debugging output + unsigned int GetFlags() const { + return flags_; + } + + bool HasIPAddress() const; + std::string GetIPv4Address() const; + std::string GetIPv6Address() const; + + void SetFlags(unsigned int flags) { + flags_ = flags; + } + + // specify NULL to remove existing address + void SetIPv4Address(struct in_addr* addr); + void SetIPv6Address(struct in6_addr* addr); + + private: + unsigned int flags_; + bool has_ipv4_; + bool has_ipv6_; + struct in_addr ipv4_address_; + struct in6_addr ipv6_address_; +}; + +typedef std::map<std::string, InterfaceStatus> InterfaceStatusTable; + +/** + * @brief Listener to detect various events on network interfaces + */ +class PlatformSpecificNetworkInterfaceListener + : public NetworkInterfaceListener { + public: + /** + * @brief Constructor + * + * @param tcp_client_listener an instance of TcpClientListener which receives + * status updates + * @param designated_interface if we want to listen only on a specific + * network interface, specify its name + */ + PlatformSpecificNetworkInterfaceListener( + TcpClientListener* tcp_client_listener, + const std::string designated_interface = ""); + + /** + * @brief Destructor + */ + virtual ~PlatformSpecificNetworkInterfaceListener(); + + /** + * @brief Initialize this listener + */ + bool Init() OVERRIDE; + + /** + * @brief Deinitialize this listener + */ + void Deinit() OVERRIDE; + + /** + * @brief Start this listener + */ + bool Start() OVERRIDE; + + /** + * @brief Stop this listener + */ + bool Stop() OVERRIDE; + +#ifdef BUILD_TESTS + void SetTesting(bool enabled) { + testing_ = enabled; + } + + int GetSocket() const { + return socket_; + } + + threads::Thread* GetThread() const { + return thread_; + } + + void OverwriteStatusTable(const InterfaceStatusTable dummy_table) { + status_table_ = dummy_table; + } + + void testCallNotifyIPAddresses() { + NotifyIPAddresses(); + } + + const std::string& GetSelectedInterfaceName() const { + return selected_interface_; + } +#endif // BUILD_TESTS + + private: + // Struct to hold an event on a network interface. + // The event can be either an update on flags or an update on IP address. + struct EventParam { + unsigned int if_index; + unsigned int flags; + struct sockaddr_storage address; + + EventParam(int interface_index, unsigned int interface_flags = 0) + : if_index(interface_index), flags(interface_flags), address() {} + }; + + // parent class which we will notify the events to + TcpClientListener* tcp_client_listener_; + // if configured, NetworkInterfaceListener will always look into the IP + // addresses of this interface + const std::string designated_interface_; + + // a map to store status of each interface + InterfaceStatusTable status_table_; + // this is the name of the interface we are currently focusing on + std::string selected_interface_; + // previous IP addresses that we have notified + std::string notified_ipv4_addr_; + std::string notified_ipv6_addr_; + + int socket_; + int pipe_fds_[2]; + threads::Thread* thread_; + +#ifdef BUILD_TESTS + bool testing_; +#endif + + void Loop(); + bool StopLoop(); + + // reset status_table_ by fetching current status of each interface + bool InitializeStatus(); + // update status_table_ by applying the events + bool UpdateStatus(uint16_t type, std::vector<EventParam>& params); + // update notified_ipv4_addr_ and notified_ipv6_addr_ then notify the parent + // class of the change if necessary + void NotifyIPAddresses(); + // Select an appropriate network interface that we will get IP addresses. Also + // update selected_interface_. + const std::string SelectInterface(); + // convert ifaddrmsg to a list of EventParam structs + std::vector<EventParam> ParseIFAddrMessage(struct ifaddrmsg* message, + unsigned int size); + // for debugging + void DumpTable() const; + + class ListenerThreadDelegate : public threads::ThreadDelegate { + public: + explicit ListenerThreadDelegate( + PlatformSpecificNetworkInterfaceListener* parent); + virtual void threadMain(); + void exitThreadMain(); + + private: + PlatformSpecificNetworkInterfaceListener* parent_; + }; + + DISALLOW_COPY_AND_ASSIGN(PlatformSpecificNetworkInterfaceListener); +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_LINUX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_ diff --git a/src/components/transport_manager/include/transport_manager/tcp/platform_specific/qnx/platform_specific_network_interface_listener_impl.h b/src/components/transport_manager/include/transport_manager/tcp/platform_specific/qnx/platform_specific_network_interface_listener_impl.h new file mode 100644 index 0000000000..2cb5eb47a7 --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/tcp/platform_specific/qnx/platform_specific_network_interface_listener_impl.h @@ -0,0 +1,70 @@ +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_QNX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_QNX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_ + +#include <map> +#include <string> +#include <vector> + +#include <netinet/in.h> +#include "transport_manager/tcp/network_interface_listener.h" +#include "utils/macro.h" +#include "utils/threads/thread_delegate.h" + +class Thread; +struct ifaddrmsg; + +namespace transport_manager { +namespace transport_adapter { + +class TcpClientListener; + +/** + * @brief Listener to detect various events on network interfaces + */ +class PlatformSpecificNetworkInterfaceListener + : public NetworkInterfaceListener { + public: + /** + * @brief Constructor + * + * @param tcp_client_listener an instance of TcpClientListener which receives + * status updates + * @param designated_interface if we want to listen only on a specific + * network interface, specify its name + */ + PlatformSpecificNetworkInterfaceListener( + TcpClientListener* tcp_client_listener, + const std::string designated_interface = ""); + + /** + * @brief Destructor + */ + virtual ~PlatformSpecificNetworkInterfaceListener(); + + /** + * @brief Initialize this listener + */ + bool Init() OVERRIDE; + + /** + * @brief Deinitialize this listener + */ + void Deinit() OVERRIDE; + + /** + * @brief Start this listener + */ + bool Start() OVERRIDE; + + /** + * @brief Stop this listener + */ + bool Stop() OVERRIDE; + + private: +}; + +} // namespace transport_adapter +} // namespace transport_manager + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_PLATFORM_SPECIFIC_QNX_PLATFORM_SPECIFIC_NETWORK_INTERFACE_LISTENER_H_ diff --git a/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h b/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h index 2640049ecc..0f9529d8d8 100644 --- a/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h +++ b/src/components/transport_manager/include/transport_manager/tcp/tcp_client_listener.h @@ -36,15 +36,18 @@ #ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_TCP_CLIENT_LISTENER_H_ #define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TCP_TCP_CLIENT_LISTENER_H_ +#include "utils/lock.h" #include "utils/threads/thread_delegate.h" #include "transport_manager/transport_adapter/client_connection_listener.h" class Thread; +struct in_addr; namespace transport_manager { namespace transport_adapter { class TransportAdapterController; +class NetworkInterfaceListener; /** * @brief Listener of device adapter that use TCP transport. @@ -57,11 +60,15 @@ class TcpClientListener : public ClientConnectionListener { * @param controller Pointer to the device adapter controller. * @param port Port No. * @param enable_keepalive If true enables TCP keepalive on accepted + * @param designated_interface Specify the name of the network interface to + *listen on. If empty, then this process will listen on all network + *interfaces. *connections */ TcpClientListener(TransportAdapterController* controller, uint16_t port, - bool enable_keepalive); + bool enable_keepalive, + const std::string designated_interface = ""); /** * @brief Destructor. @@ -101,7 +108,18 @@ class TcpClientListener : public ClientConnectionListener { */ virtual TransportAdapter::Error StopListening(); + /** + * @brief Called from NetworkInterfaceListener when IP address of the network + * interface is changed. + */ + virtual void OnIPAddressUpdated(const std::string ipv4_addr, + const std::string ipv6_addr); + #ifdef BUILD_TESTS + void set_network_interface_listener(NetworkInterfaceListener* listener) { + interface_listener_ = listener; + } + uint16_t port() const { return port_; } @@ -113,19 +131,47 @@ class TcpClientListener : public ClientConnectionListener { threads::Thread* thread() const { return thread_; } + + static void set_testing(bool enabled) { + testing_ = enabled; + } #endif // BUILD_TESTS private: const uint16_t port_; const bool enable_keepalive_; TransportAdapterController* controller_; + bool initialized_; + bool started_; threads::Thread* thread_; int socket_; bool thread_stop_requested_; + int pipe_fds_[2]; + NetworkInterfaceListener* interface_listener_; + const std::string designated_interface_; + std::string current_ip_address_; + sync_primitives::Lock start_stop_lock_; + +#ifdef BUILD_TESTS + static bool testing_; +#endif // BUILD_TESTS void Loop(); void StopLoop(); + TransportAdapter::Error StartListeningThread(); + TransportAdapter::Error StopListeningThread(); + + bool StartOnNetworkInterface(); + bool StopOnNetworkInterface(); + bool IsListeningOnSpecificInterface() const; + + static int CreateIPv4ServerSocket(uint16_t port, + const std::string interface_name = ""); + static void DestroyServerSocket(int sock); + static bool GetIPv4Address(const std::string interface_name, + struct in_addr* ip_address); + class ListeningThreadDelegate : public threads::ThreadDelegate { public: explicit ListeningThreadDelegate(TcpClientListener* parent); diff --git a/src/components/transport_manager/include/transport_manager/tcp/tcp_transport_adapter.h b/src/components/transport_manager/include/transport_manager/tcp/tcp_transport_adapter.h index 5431b4455d..37f5a7fe49 100644 --- a/src/components/transport_manager/include/transport_manager/tcp/tcp_transport_adapter.h +++ b/src/components/transport_manager/include/transport_manager/tcp/tcp_transport_adapter.h @@ -58,6 +58,18 @@ class TcpTransportAdapter : public TransportAdapterImpl { */ virtual ~TcpTransportAdapter(); + /** + * @brief Notification that transport's configuration is updated + * + * @param new_config The new configuration of the transport + */ + void TransportConfigUpdated(const TransportConfig& new_config) OVERRIDE; + + /** + * @brief Returns the transport's configuration information + */ + virtual TransportConfig GetTransportConfiguration() const OVERRIDE; + protected: /** * @brief Return type of device. @@ -77,6 +89,19 @@ class TcpTransportAdapter : public TransportAdapterImpl { * @return True on success false otherwise */ virtual bool Restore(); + + private: + /** + * @brief Keeps transport specific configuration + * + * TCP transport uses following information: + * - "enabled": whether the transport is currently enabled or not. Value can + * be "true" or "false". + * - "tcp_ip_address": string representation of IP address (either IPv4 or + * IPv6) + * - "tcp_port": string representation of TCP port number (e.g. "12345") + */ + TransportConfig transport_config_; }; } // namespace transport_adapter diff --git a/src/components/transport_manager/include/transport_manager/telemetry_observer.h b/src/components/transport_manager/include/transport_manager/telemetry_observer.h index 5e42289a03..a38255966b 100644 --- a/src/components/transport_manager/include/transport_manager/telemetry_observer.h +++ b/src/components/transport_manager/include/transport_manager/telemetry_observer.h @@ -42,8 +42,8 @@ namespace transport_manager { class TMTelemetryObserver { public: struct MessageMetric { - TimevalStruct begin; - TimevalStruct end; + date_time::TimeDuration begin; + date_time::TimeDuration end; size_t data_size; }; virtual void StartRawMsg(const protocol_handler::RawMessage* ptr) = 0; diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/connection.h b/src/components/transport_manager/include/transport_manager/transport_adapter/connection.h index 537e94b055..2374d8a126 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/connection.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/connection.h @@ -35,7 +35,6 @@ #ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TRANSPORT_ADAPTER_CONNECTION_H_ #define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TRANSPORT_ADAPTER_CONNECTION_H_ -#include "utils/shared_ptr.h" #include "transport_manager/transport_adapter/transport_adapter.h" namespace transport_manager { @@ -67,7 +66,7 @@ class Connection { virtual TransportAdapter::Error Disconnect() = 0; }; -typedef utils::SharedPtr<Connection> ConnectionSPtr; +typedef std::shared_ptr<Connection> ConnectionSPtr; } // namespace transport_adapter } // namespace transport_manager diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/threaded_socket_connection.h b/src/components/transport_manager/include/transport_manager/transport_adapter/threaded_socket_connection.h index 3792b94d7c..f1c679c123 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/threaded_socket_connection.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/threaded_socket_connection.h @@ -40,7 +40,7 @@ #include "transport_manager/transport_adapter/connection.h" #include "protocol/common.h" -#include "utils/atomic_object.h" +#include <atomic> #include "utils/threads/thread_delegate.h" #include "utils/lock.h" @@ -201,7 +201,7 @@ class ThreadedSocketConnection : public Connection { FrameQueue frames_to_send_; mutable sync_primitives::Lock frames_to_send_mutex_; - sync_primitives::atomic_int socket_; + std::atomic_int socket_; bool terminate_flag_; bool unexpected_disconnect_; const DeviceUID device_uid_; diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h index 0b38f82637..69d76b4b2b 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_controller.h @@ -204,6 +204,13 @@ class TransportAdapterController { const ApplicationHandle& app_handle, ::protocol_handler::RawMessagePtr message, const DataSendError&) = 0; + + /** + * @brief Notification that transport's configuration is updated + * + * @param new_config The new configuration of the transport + */ + virtual void TransportConfigUpdated(const TransportConfig& new_config) = 0; }; } // namespace transport_adapter diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h index 2b1ada79ad..078f93b32f 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_impl.h @@ -400,6 +400,13 @@ class TransportAdapterImpl : public TransportAdapter, const DataSendError& error) OVERRIDE; /** + * @brief Notification that transport's configuration is updated + * + * @param new_config The new configuration of the transport + */ + void TransportConfigUpdated(const TransportConfig& new_config) OVERRIDE; + + /** * @brief DoTransportSwitch notifies listeners of transport adapter events * that transport switching is requested by system */ @@ -420,6 +427,14 @@ class TransportAdapterImpl : public TransportAdapter, SwitchableDevices GetSwitchableDevices() const OVERRIDE; /** + * @brief Returns the transport's configuration information + */ + virtual TransportConfig GetTransportConfiguration() const OVERRIDE { + // default is empty + return TransportConfig(); + } + + /** * @brief Return name of device. * * @param device_id Device unique identifier. diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h index 424fa53dea..4606bac2d4 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener.h @@ -277,6 +277,15 @@ class TransportAdapterListener { */ virtual void OnTransportSwitchRequested( const TransportAdapter* transport_adapter) = 0; + + /** + * @brief Notification that the transport's specific configuration has been + * updated. + * + * @param transport_adapter pointer to the transport adapter + */ + virtual void OnTransportConfigUpdated( + const TransportAdapter* transport_adapter) = 0; }; } // transport_adapter namespace diff --git a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h index 8a8031c3cf..a744400279 100644 --- a/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_adapter/transport_adapter_listener_impl.h @@ -272,6 +272,15 @@ class TransportAdapterListenerImpl */ void OnTransportSwitchRequested(const TransportAdapter* adapter) OVERRIDE; + /** + * @brief Notification that the transport's specific configuration has been + * updated. + * + * @param transport_adapter pointer to the transport adapter + */ + void OnTransportConfigUpdated( + const transport_adapter::TransportAdapter* adapter) OVERRIDE; + private: TransportManager* transport_manager_; TransportAdapter* transport_adapter_; diff --git a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h index eaa71ce3bb..c1df49f91b 100644 --- a/src/components/transport_manager/include/transport_manager/transport_manager_impl.h +++ b/src/components/transport_manager/include/transport_manager/transport_manager_impl.h @@ -64,7 +64,7 @@ typedef threads::MessageLoopThread<std::queue<protocol_handler::RawMessagePtr> > RawMessageLoopThread; typedef threads::MessageLoopThread<std::queue<TransportAdapterEvent> > TransportAdapterEventLoopThread; -typedef utils::SharedPtr<timer::Timer> TimerSPtr; +typedef std::shared_ptr<timer::Timer> TimerSPtr; typedef std::map<DeviceUID, TransportAdapter*> DeviceToAdapterMap; /** @@ -245,14 +245,6 @@ class TransportManagerImpl int Visibility(const bool& on_off) const OVERRIDE; /** - * DEPRECATED - * Must be moved under 'private' section - * @brief Updates total device list with info from specific transport adapter. - * @param ta Transport adapter - */ - void UpdateDeviceList(TransportAdapter* ta); - - /** * @brief OnDeviceListUpdated updates device list and sends appropriate * notifications to listeners in case of something is changed * @param ta Transport adapter to check for updated devices state @@ -501,6 +493,12 @@ class TransportManagerImpl * @return True if mapping has been updated, otherwise - false */ bool UpdateDeviceMapping(TransportAdapter* ta); + + /** + * @brief Updates total device list with info from specific transport adapter. + * @param ta Transport adapter + */ + void UpdateDeviceList(TransportAdapter* ta); }; // class TransportManagerImpl } // namespace transport_manager #endif // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TRANSPORT_MANAGER_IMPL_H_ diff --git a/src/components/transport_manager/include/transport_manager/usb/common.h b/src/components/transport_manager/include/transport_manager/usb/common.h index 1c6011dbb2..1db1a83a3a 100644 --- a/src/components/transport_manager/include/transport_manager/usb/common.h +++ b/src/components/transport_manager/include/transport_manager/usb/common.h @@ -35,8 +35,6 @@ #include <stdint.h> -#include "utils/shared_ptr.h" - #if defined(__QNXNTO__) #include "transport_manager/usb/qnx/usb_handler.h" #else @@ -64,7 +62,7 @@ static const uint16_t kApplePid8 = 0x12a8; // iPhone 5 static const int kUsbConfiguration = 1; -typedef utils::SharedPtr<UsbHandler> UsbHandlerSptr; +typedef std::shared_ptr<UsbHandler> UsbHandlerSptr; class UsbDeviceListener { public: diff --git a/src/components/transport_manager/include/transport_manager/usb/usb_device.h b/src/components/transport_manager/include/transport_manager/usb/usb_device.h index 8ca1a32a28..ea31bb0376 100644 --- a/src/components/transport_manager/include/transport_manager/usb/usb_device.h +++ b/src/components/transport_manager/include/transport_manager/usb/usb_device.h @@ -54,9 +54,9 @@ class UsbDevice : public Device { return usb_device_; } - protected: virtual ~UsbDevice() {} + protected: virtual bool IsSameAs(const Device* other_device) const { return unique_device_id() == other_device->unique_device_id(); } diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc b/src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc index 0d8a77c88f..62615cb30f 100644 --- a/src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc +++ b/src/components/transport_manager/src/bluetooth/bluetooth_connection_factory.cc @@ -37,7 +37,6 @@ #include "transport_manager/bluetooth/bluetooth_connection_factory.h" #include "transport_manager/bluetooth/bluetooth_socket_connection.h" #include "utils/logger.h" -#include "utils/make_shared.h" namespace transport_manager { namespace transport_adapter { @@ -55,8 +54,8 @@ TransportAdapter::Error BluetoothConnectionFactory::Init() { TransportAdapter::Error BluetoothConnectionFactory::CreateConnection( const DeviceUID& device_uid, const ApplicationHandle& app_handle) { LOG4CXX_AUTO_TRACE(logger_); - utils::SharedPtr<BluetoothSocketConnection> connection = - utils::MakeShared<BluetoothSocketConnection>( + std::shared_ptr<BluetoothSocketConnection> connection = + std::make_shared<BluetoothSocketConnection>( device_uid, app_handle, controller_); controller_->ConnectionCreated(connection, device_uid, app_handle); TransportAdapter::Error error = connection->Start(); diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_device.cc b/src/components/transport_manager/src/bluetooth/bluetooth_device.cc index 038515170d..e7cc3d4f34 100644 --- a/src/components/transport_manager/src/bluetooth/bluetooth_device.cc +++ b/src/components/transport_manager/src/bluetooth/bluetooth_device.cc @@ -45,6 +45,7 @@ #include <sys/socket.h> #include <algorithm> +#include <iostream> #include <limits> #include "utils/logger.h" @@ -56,7 +57,8 @@ bool BluetoothDevice::GetRfcommChannel(const ApplicationHandle app_handle, uint8_t* channel_out) { LOG4CXX_TRACE(logger_, "enter. app_handle: " << app_handle - << ", channel_out: " << channel_out); + << ", channel_out: " << std::hex + << reinterpret_cast<void*>(channel_out)); if (app_handle < 0 || app_handle > std::numeric_limits<uint8_t>::max()) { LOG4CXX_TRACE(logger_, "exit with FALSE. Condition: app_handle < 0 || app_handle > " diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc b/src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc index 743c95f2e6..75ea799ce8 100644 --- a/src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc +++ b/src/components/transport_manager/src/bluetooth/bluetooth_device_scanner.cc @@ -262,8 +262,8 @@ void BluetoothDeviceScanner::CheckSDLServiceOnDevices( deviceName[name_len - 1] = '\0'; } - Device* bluetooth_device = - new BluetoothDevice(bd_address, deviceName, sdl_rfcomm_channels[i]); + auto bluetooth_device = std::make_shared<BluetoothDevice>( + bd_address, deviceName, sdl_rfcomm_channels[i]); if (bluetooth_device) { LOG4CXX_INFO(logger_, "Bluetooth device created successfully"); discovered_devices->push_back(bluetooth_device); diff --git a/src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc b/src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc index 0f83f32c60..b373744f79 100644 --- a/src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc +++ b/src/components/transport_manager/src/bluetooth/bluetooth_transport_adapter.cc @@ -80,8 +80,8 @@ void BluetoothTransportAdapter::Store() const { if (!device) { // device could have been disconnected continue; } - utils::SharedPtr<BluetoothDevice> bluetooth_device = - DeviceSptr::static_pointer_cast<BluetoothDevice>(device); + std::shared_ptr<BluetoothDevice> bluetooth_device = + std::static_pointer_cast<BluetoothDevice>(device); Json::Value device_dictionary; device_dictionary["name"] = bluetooth_device->name(); char address[18]; diff --git a/src/components/transport_manager/src/iap2_emulation/iap2_transport_adapter.cc b/src/components/transport_manager/src/iap2_emulation/iap2_transport_adapter.cc index 6b7d44ea8d..31e997f3ba 100644 --- a/src/components/transport_manager/src/iap2_emulation/iap2_transport_adapter.cc +++ b/src/components/transport_manager/src/iap2_emulation/iap2_transport_adapter.cc @@ -69,6 +69,11 @@ DeviceType IAP2BluetoothEmulationTransportAdapter::GetDeviceType() const { return IOS_BT; } +void IAP2BluetoothEmulationTransportAdapter::TransportConfigUpdated( + const TransportConfig& new_config) { + return; +} + IAP2USBEmulationTransportAdapter::IAP2USBEmulationTransportAdapter( const uint16_t port, resumption::LastState& last_state, @@ -78,6 +83,7 @@ IAP2USBEmulationTransportAdapter::IAP2USBEmulationTransportAdapter( signal_handler_ = threads::CreateThread("iAP signal handler", delegate); signal_handler_->start(); const auto result = mkfifo(out_signals_channel, mode); + UNUSED(result); LOG4CXX_DEBUG(logger_, "Out signals channel creation result: " << result); } @@ -119,10 +125,16 @@ DeviceType IAP2USBEmulationTransportAdapter::GetDeviceType() const { return IOS_USB; } +void IAP2USBEmulationTransportAdapter::TransportConfigUpdated( + const TransportConfig& new_config) { + return; +} + IAP2USBEmulationTransportAdapter::IAPSignalHandlerDelegate:: IAPSignalHandlerDelegate(IAP2USBEmulationTransportAdapter& adapter) : adapter_(adapter), run_flag_(true), in_(0) { const auto result = mkfifo(in_signals_channel, mode); + UNUSED(result); LOG4CXX_DEBUG(logger_, "In signals channel creation result: " << result); } diff --git a/src/components/transport_manager/src/tcp/network_interface_listener_impl.cc b/src/components/transport_manager/src/tcp/network_interface_listener_impl.cc new file mode 100644 index 0000000000..85c479134d --- /dev/null +++ b/src/components/transport_manager/src/tcp/network_interface_listener_impl.cc @@ -0,0 +1,42 @@ +#include "transport_manager/tcp/network_interface_listener_impl.h" +#include "platform_specific_network_interface_listener_impl.h" + +namespace transport_manager { +namespace transport_adapter { + +CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager") + +NetworkInterfaceListenerImpl::NetworkInterfaceListenerImpl( + TcpClientListener* tcp_client_listener, + const std::string designated_interface) + : platform_specific_impl_(new PlatformSpecificNetworkInterfaceListener( + tcp_client_listener, designated_interface)) { + LOG4CXX_AUTO_TRACE(logger_); +} + +NetworkInterfaceListenerImpl::~NetworkInterfaceListenerImpl() { + LOG4CXX_AUTO_TRACE(logger_); +} + +bool NetworkInterfaceListenerImpl::Init() { + LOG4CXX_AUTO_TRACE(logger_); + return platform_specific_impl_->Init(); +} + +void NetworkInterfaceListenerImpl::Deinit() { + LOG4CXX_AUTO_TRACE(logger_); + platform_specific_impl_->Deinit(); +} + +bool NetworkInterfaceListenerImpl::Start() { + LOG4CXX_AUTO_TRACE(logger_); + return platform_specific_impl_->Start(); +} + +bool NetworkInterfaceListenerImpl::Stop() { + LOG4CXX_AUTO_TRACE(logger_); + return platform_specific_impl_->Stop(); +} + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/tcp/platform_specific/linux/platform_specific_network_interface_listener.cc b/src/components/transport_manager/src/tcp/platform_specific/linux/platform_specific_network_interface_listener.cc new file mode 100644 index 0000000000..047d43b7bf --- /dev/null +++ b/src/components/transport_manager/src/tcp/platform_specific/linux/platform_specific_network_interface_listener.cc @@ -0,0 +1,673 @@ +#include "transport_manager/tcp/platform_specific/linux/platform_specific_network_interface_listener_impl.h" + +#include <arpa/inet.h> +#include <asm/types.h> +#include <errno.h> +#include <fcntl.h> +#include <ifaddrs.h> +#include <unistd.h> +#include <net/if.h> +#include <sys/types.h> +#include <sys/select.h> +#include <sys/socket.h> + +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#include "transport_manager/tcp/tcp_client_listener.h" +#include "utils/logger.h" +#include "utils/threads/thread.h" + +namespace transport_manager { +namespace transport_adapter { + +CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager") + +static std::string GetInterfaceName(unsigned int if_index); +static bool SetNonblocking(int s); + +bool InterfaceStatus::IsAvailable() const { + // check if the interface is UP and RUNNING + return ((flags_ & IFF_UP) > 0) && ((flags_ & IFF_RUNNING) > 0); +} + +bool InterfaceStatus::IsLoopback() const { + return flags_ & IFF_LOOPBACK; +} + +bool InterfaceStatus::HasIPAddress() const { + return has_ipv4_ || has_ipv6_; +} + +std::string InterfaceStatus::GetIPv4Address() const { + char buf[INET_ADDRSTRLEN] = ""; + if (has_ipv4_ && IsAvailable()) { + inet_ntop(AF_INET, &ipv4_address_, buf, sizeof(buf)); + } + return std::string(buf); +} + +std::string InterfaceStatus::GetIPv6Address() const { + char buf[INET6_ADDRSTRLEN] = ""; + if (has_ipv6_ && IsAvailable()) { + inet_ntop(AF_INET6, &ipv6_address_, buf, sizeof(buf)); + } + return std::string(buf); +} + +void InterfaceStatus::SetIPv4Address(struct in_addr* addr) { + if (addr == NULL) { + has_ipv4_ = false; + } else { + ipv4_address_ = *addr; + has_ipv4_ = true; + } +} + +void InterfaceStatus::SetIPv6Address(struct in6_addr* addr) { + if (addr == NULL) { + has_ipv6_ = false; + } else { + ipv6_address_ = *addr; + has_ipv6_ = true; + } +} + +PlatformSpecificNetworkInterfaceListener:: + PlatformSpecificNetworkInterfaceListener( + TcpClientListener* tcp_client_listener, + const std::string designated_interface) + : tcp_client_listener_(tcp_client_listener) + , designated_interface_(designated_interface) + , selected_interface_("") + , notified_ipv4_addr_("") + , notified_ipv6_addr_("") + , socket_(-1) +#ifdef BUILD_TESTS + , testing_(false) +#endif // BUILD_TESTS +{ + pipe_fds_[0] = pipe_fds_[1] = -1; + thread_ = threads::CreateThread("PlatformSpecificNetworkInterfaceListener", + new ListenerThreadDelegate(this)); +} + +PlatformSpecificNetworkInterfaceListener:: + ~PlatformSpecificNetworkInterfaceListener() { + LOG4CXX_AUTO_TRACE(logger_); + + Stop(); + Deinit(); + + delete thread_->delegate(); + threads::DeleteThread(thread_); +} + +bool PlatformSpecificNetworkInterfaceListener::Init() { + LOG4CXX_AUTO_TRACE(logger_); + + if (socket_ >= 0) { + LOG4CXX_WARN(logger_, "Network interface listener is already initialized"); + return false; + } + + socket_ = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (socket_ == -1) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to create netlink socket"); + return false; + } + + if (!SetNonblocking(socket_)) { + LOG4CXX_WARN(logger_, "Failed to configure netlink socket to non-blocking"); + } + + struct sockaddr_nl addr; + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pad = 0; + addr.nl_pid = 0; + addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; + + if (bind(socket_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to bind netlink socket"); + close(socket_); + socket_ = -1; + return false; + } + + if (pipe(pipe_fds_) != 0) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to create internal pipe"); + close(socket_); + socket_ = -1; + return false; + } + + if (!SetNonblocking(pipe_fds_[0])) { + LOG4CXX_WARN(logger_, "Failed to configure pipe to non-blocking"); + } + + return true; +} + +void PlatformSpecificNetworkInterfaceListener::Deinit() { + LOG4CXX_AUTO_TRACE(logger_); + + if (socket_ >= 0) { + close(socket_); + socket_ = -1; + } + if (pipe_fds_[1] >= 0) { + close(pipe_fds_[1]); + pipe_fds_[1] = -1; + } + if (pipe_fds_[0] >= 0) { + close(pipe_fds_[0]); + pipe_fds_[0] = -1; + } +} + +bool PlatformSpecificNetworkInterfaceListener::Start() { + LOG4CXX_AUTO_TRACE(logger_); + + if (socket_ < 0) { + LOG4CXX_WARN(logger_, "Interface listener is not initialized"); + return false; + } + + if (thread_->is_running()) { + LOG4CXX_WARN(logger_, "Interface listener is already started"); + return false; + } + + if (!thread_->start()) { + LOG4CXX_ERROR(logger_, "Failed to start interface listener"); + return false; + } + + LOG4CXX_INFO(logger_, "Network interface listener started"); + return true; +} + +bool PlatformSpecificNetworkInterfaceListener::Stop() { + LOG4CXX_AUTO_TRACE(logger_); + + if (!thread_->is_running()) { + LOG4CXX_DEBUG(logger_, "interface listener is not running"); + return false; + } + + thread_->join(); + + LOG4CXX_INFO(logger_, "Network interface listener stopped"); + return true; +} + +void PlatformSpecificNetworkInterfaceListener::Loop() { + LOG4CXX_AUTO_TRACE(logger_); + + // Initialize status_table_ by acquiring a list of interfaces and their + // current statuses. Also we will notify an event to the listener if IP + // address is already available. + InitializeStatus(); + NotifyIPAddresses(); + + // I am not sure required buffer size for netlink data structures. Most of + // implementation I found online uses 4096 so I followed them. + char buf[4096]; + fd_set rfds; + + while (1) { + FD_ZERO(&rfds); + FD_SET(socket_, &rfds); + FD_SET(pipe_fds_[0], &rfds); + int nfds = socket_ > pipe_fds_[0] ? socket_ : pipe_fds_[0]; + + // wait for some data from netlink socket (socket_) and our internal pipe + int ret = select(nfds + 1, &rfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EINTR) { + continue; + } else { + LOG4CXX_WARN(logger_, + "select failed for netlink. Aborting interface listener."); + break; + } + } + + // Received data from internal pipe, indicating StopLoop() is called. + // We'll break the while() loop and eventually exit this thread. + if (FD_ISSET(pipe_fds_[0], &rfds)) { + ret = read(pipe_fds_[0], buf, sizeof(buf)); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + LOG4CXX_WARN( + logger_, + "Failed to read from pipe. Aborting interface listener."); + break; + } + } else if (ret == 0) { + LOG4CXX_WARN(logger_, + "Pipe disconnected. Aborting interface listener."); + break; + } else { + LOG4CXX_DEBUG(logger_, "received terminating event through pipe"); + break; + } + } + +#ifdef BUILD_TESTS + if (testing_) { // don't enable events from network interface while testing + continue; + } +#endif // BUILD_TESTS + + // received data from netlink socket + if (FD_ISSET(socket_, &rfds)) { + ret = recv(socket_, buf, sizeof(buf), 0); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + LOG4CXX_WARN(logger_, + "Failed to read from netlink socket. Aborting interface " + "listener."); + break; + } + } else if (ret == 0) { + LOG4CXX_WARN( + logger_, + "Netlink socket disconnected. Aborting interface listener."); + break; + } else { + struct nlmsghdr* header = reinterpret_cast<struct nlmsghdr*>(buf); + int len = ret; + + // Parse the stream. We may receive multiple (header + data) pairs at a + // time so we use for-loop to go through. + for (; NLMSG_OK(header, len); header = NLMSG_NEXT(header, len)) { + if (header->nlmsg_type == NLMSG_ERROR) { + LOG4CXX_WARN(logger_, "received error event from netlink"); + break; + } + + std::vector<EventParam> params; + + if (header->nlmsg_type == RTM_NEWLINK || + header->nlmsg_type == RTM_DELLINK) { + // For these events, data part contains an ifinfomsg struct and a + // series of rtattr structures. See rtnetlink(7). + // We are only interested in interface index and flags. + struct ifinfomsg* ifinfo_msg = + reinterpret_cast<struct ifinfomsg*>(NLMSG_DATA(header)); + EventParam param(ifinfo_msg->ifi_index, ifinfo_msg->ifi_flags); + params.push_back(param); + + } else if (header->nlmsg_type == RTM_NEWADDR || + header->nlmsg_type == RTM_DELADDR) { + // For these events, data part contains an ifaddrmsg struct and + // optionally some rtattr structures. We'll extract IP address(es) + // from them. + struct ifaddrmsg* ifaddr_msg = + reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(header)); + unsigned int size = IFA_PAYLOAD(header); + params = ParseIFAddrMessage(ifaddr_msg, size); + + } else { + continue; + } + + // update status_table_ based on received data + UpdateStatus(header->nlmsg_type, params); + } + } + + // notify the listener if necessary + NotifyIPAddresses(); + } + } +} + +bool PlatformSpecificNetworkInterfaceListener::StopLoop() { + LOG4CXX_AUTO_TRACE(logger_); + + LOG4CXX_INFO(logger_, "Stopping network interface listener"); + + if (pipe_fds_[1] < 0) { + LOG4CXX_WARN(logger_, "StopLoop called in invalid state"); + return false; + } + + char dummy[1] = {0}; + int ret = write(pipe_fds_[1], dummy, sizeof(dummy)); + if (ret <= 0) { + LOG4CXX_WARN_WITH_ERRNO( + logger_, "Failed to send stop message to interface listener"); + return false; + } + + return true; +} + +bool PlatformSpecificNetworkInterfaceListener::InitializeStatus() { + LOG4CXX_AUTO_TRACE(logger_); + +#ifdef BUILD_TESTS + if (testing_) { + // don't actually call getifaddrs() + return true; + } +#endif // BUILD_TESTS + + struct ifaddrs* if_list, *interface; + if (getifaddrs(&if_list) != 0) { + LOG4CXX_WARN(logger_, + "getifaddr failed, interface status won't be available until " + "a change occurs"); + return false; + } + + // clear existing table + status_table_.clear(); + + for (interface = if_list; interface != NULL; + interface = interface->ifa_next) { + if (interface->ifa_name == NULL || interface->ifa_name[0] == '\0') { + continue; + } + if (interface->ifa_addr == NULL) { + continue; + } + + std::string ifname(interface->ifa_name); + InterfaceStatus& status = status_table_[ifname]; + + switch (interface->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in* addr = + reinterpret_cast<struct sockaddr_in*>(interface->ifa_addr); + status.SetIPv4Address(&addr->sin_addr); + break; + } + case AF_INET6: { + struct sockaddr_in6* addr = + reinterpret_cast<struct sockaddr_in6*>(interface->ifa_addr); + status.SetIPv6Address(&addr->sin6_addr); + break; + } + default: + continue; + } + status.SetFlags(interface->ifa_flags); + } + + freeifaddrs(if_list); + + LOG4CXX_DEBUG(logger_, "Successfully acquired network interface status"); + DumpTable(); + return true; +} + +bool PlatformSpecificNetworkInterfaceListener::UpdateStatus( + uint16_t type, std::vector<EventParam>& params) { + LOG4CXX_AUTO_TRACE(logger_); + + for (std::vector<EventParam>::iterator it = params.begin(); + it != params.end(); + ++it) { + std::string ifname = GetInterfaceName(it->if_index); + if (ifname.empty()) { + continue; + } + + InterfaceStatus& status = status_table_[ifname]; + + switch (type) { + case RTM_NEWLINK: { + LOG4CXX_DEBUG(logger_, + "netlink event: interface " << ifname + << " created or updated"); + status.SetFlags(it->flags); + break; + } + case RTM_DELLINK: + LOG4CXX_DEBUG(logger_, + "netlink event: interface " << ifname << " removed"); + status_table_.erase(ifname); + break; + case RTM_NEWADDR: { + sockaddr* addr = reinterpret_cast<sockaddr*>(&it->address); + if (addr->sa_family == AF_INET) { + sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(addr); + status.SetIPv4Address(&addr_in->sin_addr); + LOG4CXX_DEBUG(logger_, + "netlink event: IPv4 address of interface " + << ifname << " updated to " + << status.GetIPv4Address()); + } else if (addr->sa_family == AF_INET6) { + sockaddr_in6* addr_in6 = reinterpret_cast<sockaddr_in6*>(addr); + status.SetIPv6Address(&addr_in6->sin6_addr); + LOG4CXX_DEBUG(logger_, + "netlink event: IPv6 address of interface " + << ifname << " updated to " + << status.GetIPv6Address()); + } + break; + } + case RTM_DELADDR: { + sockaddr* addr = reinterpret_cast<sockaddr*>(&it->address); + if (addr->sa_family == AF_INET) { + LOG4CXX_DEBUG(logger_, + "netlink event: IPv4 address of interface " + << ifname << " removed"); + status.SetIPv4Address(NULL); + } else if (addr->sa_family == AF_INET6) { + LOG4CXX_DEBUG(logger_, + "netlink event: IPv6 address of interface " + << ifname << " removed"); + status.SetIPv6Address(NULL); + } + break; + } + default: + LOG4CXX_WARN(logger_, "Unsupported netlink event (" << type << ")"); + break; + } + } + return true; +} + +void PlatformSpecificNetworkInterfaceListener::NotifyIPAddresses() { + LOG4CXX_AUTO_TRACE(logger_); + + std::string ipv4_addr; + std::string ipv6_addr; + const std::string interface_name = SelectInterface(); + + // note that if interface_name is empty (i.e. no interface is selected), + // the IP addresses will be empty + if (!interface_name.empty()) { + InterfaceStatusTable::iterator it = status_table_.find(interface_name); + if (status_table_.end() != it) { + InterfaceStatus& status = it->second; + ipv4_addr = status.GetIPv4Address(); + ipv6_addr = status.GetIPv6Address(); + } + } + + if (notified_ipv4_addr_ != ipv4_addr || notified_ipv6_addr_ != ipv6_addr) { + LOG4CXX_INFO(logger_, + "IP address updated: \"" << notified_ipv4_addr_ << "\" -> \"" + << ipv4_addr << "\", \"" + << notified_ipv6_addr_ << "\" -> \"" + << ipv6_addr << "\""); + + notified_ipv4_addr_ = ipv4_addr; + notified_ipv6_addr_ = ipv6_addr; + + tcp_client_listener_->OnIPAddressUpdated(notified_ipv4_addr_, + notified_ipv6_addr_); + } +} + +const std::string PlatformSpecificNetworkInterfaceListener::SelectInterface() { + LOG4CXX_AUTO_TRACE(logger_); + + if (!designated_interface_.empty()) { + return designated_interface_; + } + + InterfaceStatusTable::iterator it; + + if (!selected_interface_.empty()) { + // if current network interface is still available and has IP address, then + // we use it + it = status_table_.find(selected_interface_); + if (it != status_table_.end()) { + InterfaceStatus& status = it->second; + if (status.IsAvailable() && status.HasIPAddress()) { + return selected_interface_; + } + } + } + + // pick a network interface that has IP address + for (it = status_table_.begin(); it != status_table_.end(); ++it) { + InterfaceStatus& status = it->second; + // ignore loopback interfaces + if (status.IsLoopback()) { + continue; + } + // if the interface has to be UP and RUNNING, and must have an IP address + if (!(status.IsAvailable() && status.HasIPAddress())) { + continue; + } + + selected_interface_ = it->first; + LOG4CXX_DEBUG(logger_, + "selecting network interface: " << selected_interface_); + return selected_interface_; + } + + selected_interface_ = ""; + return selected_interface_; +} + +std::vector<PlatformSpecificNetworkInterfaceListener::EventParam> +PlatformSpecificNetworkInterfaceListener::ParseIFAddrMessage( + struct ifaddrmsg* message, unsigned int size) { + LOG4CXX_AUTO_TRACE(logger_); + + std::vector<EventParam> params; + + // Iterate through rtattr structs. (The first one can be acquired through + // IFA_RTA() macro) + for (struct rtattr* attr = IFA_RTA(message); RTA_OK(attr, size); + attr = RTA_NEXT(attr, size)) { + if (!(attr->rta_type == IFA_LOCAL || attr->rta_type == IFA_ADDRESS)) { + continue; + } + + EventParam param(message->ifa_index); + + if (message->ifa_family == AF_INET) { + // make sure the size of data is >= 4 bytes + if (RTA_PAYLOAD(attr) < sizeof(struct in_addr)) { + LOG4CXX_DEBUG(logger_, + "Invalid netlink event: insufficient IPv4 address data"); + continue; + } + + // Data part of rtattr contains IPv4 address. Copy it to param.address + struct in_addr* ipv4_addr = + reinterpret_cast<struct in_addr*>(RTA_DATA(attr)); + + struct sockaddr_in* sockaddr = + reinterpret_cast<struct sockaddr_in*>(¶m.address); + sockaddr->sin_family = AF_INET; + sockaddr->sin_addr = *ipv4_addr; + + } else if (message->ifa_family == AF_INET6) { + // make sure the size of data is >= 16 bytes + if (RTA_PAYLOAD(attr) < sizeof(struct in6_addr)) { + LOG4CXX_DEBUG(logger_, + "Invalid netlink event: insufficient IPv6 address data"); + continue; + } + + // Data part of rtattr contains IPv6 address. Copy it to param.address + struct in6_addr* ipv6_addr = + reinterpret_cast<struct in6_addr*>(RTA_DATA(attr)); + + struct sockaddr_in6* sockaddr = + reinterpret_cast<struct sockaddr_in6*>(¶m.address); + sockaddr->sin6_family = AF_INET6; + sockaddr->sin6_addr = *ipv6_addr; + + } else { + LOG4CXX_WARN(logger_, + "Unsupported family (" << message->ifa_family << ")"); + continue; + } + + params.push_back(param); + } + + return params; +} + +void PlatformSpecificNetworkInterfaceListener::DumpTable() const { + LOG4CXX_DEBUG(logger_, + "Number of network interfaces: " << status_table_.size()); + + for (auto it = status_table_.begin(); it != status_table_.end(); ++it) { + const std::string ifname = it->first; + const InterfaceStatus& status = it->second; + UNUSED(status); + + LOG4CXX_DEBUG( + logger_, + " " << ifname << " : flags=" << status.GetFlags() + << " : available: " << (status.IsAvailable() ? "yes" : "no") + << " IPv4: " << status.GetIPv4Address() + << " IPv6: " << status.GetIPv6Address() + << (status.IsLoopback() ? " (loopback)" : "")); + } +} + +PlatformSpecificNetworkInterfaceListener::ListenerThreadDelegate:: + ListenerThreadDelegate(PlatformSpecificNetworkInterfaceListener* parent) + : parent_(parent) {} + +void PlatformSpecificNetworkInterfaceListener::ListenerThreadDelegate:: + threadMain() { + parent_->Loop(); +} + +void PlatformSpecificNetworkInterfaceListener::ListenerThreadDelegate:: + exitThreadMain() { + parent_->StopLoop(); +} + +static std::string GetInterfaceName(unsigned int if_index) { + char buf[IFNAMSIZ + 1] = ""; + if_indextoname(if_index, buf); + return std::string(buf); +} + +static bool SetNonblocking(int s) { + int prev_flag = fcntl(s, F_GETFL, 0); + if (prev_flag == -1) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to acquire socket flag"); + return false; + } + + int ret = fcntl(s, F_SETFL, prev_flag | O_NONBLOCK); + if (ret == -1) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, + "Failed to configure socket to non-blocking"); + return false; + } + + return true; +} + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/tcp/platform_specific/qnx/platform_specific_network_interface_listener.cc b/src/components/transport_manager/src/tcp/platform_specific/qnx/platform_specific_network_interface_listener.cc new file mode 100644 index 0000000000..15b3814999 --- /dev/null +++ b/src/components/transport_manager/src/tcp/platform_specific/qnx/platform_specific_network_interface_listener.cc @@ -0,0 +1,38 @@ +#include "transport_manager/tcp/platform_specific/qnx/platform_specific_network_interface_listener_impl.h" + +namespace transport_manager { +namespace transport_adapter { + +CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager") + +PlatformSpecificNetworkInterfaceListener:: + PlatformSpecificNetworkInterfaceListener( + TcpClientListener* tcp_client_listener, + const std::string designated_interface) {} + +PlatformSpecificNetworkInterfaceListener:: + ~PlatformSpecificNetworkInterfaceListener() { + LOG4CXX_AUTO_TRACE(logger_); +} + +bool PlatformSpecificNetworkInterfaceListener::Init() { + LOG4CXX_AUTO_TRACE(logger_); + return true; +} + +void PlatformSpecificNetworkInterfaceListener::Deinit() { + LOG4CXX_AUTO_TRACE(logger_); +} + +bool PlatformSpecificNetworkInterfaceListener::Start() { + LOG4CXX_AUTO_TRACE(logger_); + return true; +} + +bool PlatformSpecificNetworkInterfaceListener::Stop() { + LOG4CXX_AUTO_TRACE(logger_); + return true; +} + +} // namespace transport_adapter +} // namespace transport_manager diff --git a/src/components/transport_manager/src/tcp/tcp_client_listener.cc b/src/components/transport_manager/src/tcp/tcp_client_listener.cc index 207149eb8c..9f2597f0a7 100644 --- a/src/components/transport_manager/src/tcp/tcp_client_listener.cc +++ b/src/components/transport_manager/src/tcp/tcp_client_listener.cc @@ -36,11 +36,14 @@ #include <memory.h> #include <signal.h> #include <errno.h> +#include <fcntl.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/types.h> +#include <sys/select.h> #include <sys/sysctl.h> #include <sys/socket.h> +#include <ifaddrs.h> #ifdef __linux__ #include <linux/tcp.h> #else // __linux__ @@ -53,9 +56,10 @@ #include <sstream> #include "utils/logger.h" -#include "utils/make_shared.h" + #include "utils/threads/thread.h" #include "transport_manager/transport_adapter/transport_adapter_controller.h" +#include "transport_manager/tcp/network_interface_listener_impl.h" #include "transport_manager/tcp/tcp_device.h" #include "transport_manager/tcp/tcp_socket_connection.h" @@ -64,72 +68,88 @@ namespace transport_adapter { CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager") +static bool SetNonblocking(int s); + +#ifdef BUILD_TESTS +bool TcpClientListener::testing_ = false; +#endif // BUILD_TESTS + TcpClientListener::TcpClientListener(TransportAdapterController* controller, const uint16_t port, - const bool enable_keepalive) + const bool enable_keepalive, + const std::string designated_interface) : port_(port) , enable_keepalive_(enable_keepalive) , controller_(controller) + , initialized_(false) + , started_(false) , thread_(0) , socket_(-1) - , thread_stop_requested_(false) { + , thread_stop_requested_(false) + , designated_interface_(designated_interface) { + pipe_fds_[0] = pipe_fds_[1] = -1; thread_ = threads::CreateThread("TcpClientListener", new ListeningThreadDelegate(this)); + interface_listener_ = + new NetworkInterfaceListenerImpl(this, designated_interface); } TransportAdapter::Error TcpClientListener::Init() { LOG4CXX_AUTO_TRACE(logger_); thread_stop_requested_ = false; - socket_ = socket(AF_INET, SOCK_STREAM, 0); - if (-1 == socket_) { - LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to create socket"); - return TransportAdapter::FAIL; - } - - sockaddr_in server_address = {0}; - server_address.sin_family = AF_INET; - server_address.sin_port = htons(port_); - server_address.sin_addr.s_addr = INADDR_ANY; - - int optval = 1; - if (0 != - setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "setsockopt SO_REUSEADDR failed"); + if (!IsListeningOnSpecificInterface()) { + // Network interface is not specified. We will listen on all interfaces + // using INADDR_ANY. If socket creation fails, we will treat it an error. + socket_ = CreateIPv4ServerSocket(port_); + if (-1 == socket_) { + LOG4CXX_ERROR(logger_, "Failed to create TCP socket"); + return TransportAdapter::FAIL; + } + } else { + // Network interface is specified and we wiill listen only on the interface. + // In this case, the server socket will be created once + // NetworkInterfaceListener notifies the interface's IP address. + LOG4CXX_INFO(logger_, + "TCP server socket will listen on " + << designated_interface_ + << " once it has an IPv4 address."); } - if (bind(socket_, - reinterpret_cast<sockaddr*>(&server_address), - sizeof(server_address)) != 0) { - LOG4CXX_ERROR_WITH_ERRNO(logger_, "bind() failed"); + if (!interface_listener_->Init()) { + if (socket_ >= 0) { + close(socket_); + socket_ = -1; + } return TransportAdapter::FAIL; } - const int kBacklog = 128; - if (0 != listen(socket_, kBacklog)) { - LOG4CXX_ERROR_WITH_ERRNO(logger_, "listen() failed"); - return TransportAdapter::FAIL; - } + initialized_ = true; return TransportAdapter::OK; } void TcpClientListener::Terminate() { LOG4CXX_AUTO_TRACE(logger_); - if (socket_ == -1) { - LOG4CXX_WARN(logger_, "Socket has been closed"); + + if (!initialized_) { return; } - if (shutdown(socket_, SHUT_RDWR) != 0) { - LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to shutdown socket"); - } - if (close(socket_) != 0) { - LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to close socket"); + + if (!IsListeningOnSpecificInterface()) { + DestroyServerSocket(socket_); + socket_ = -1; + } else { + sync_primitives::AutoLock auto_lock(start_stop_lock_); + DestroyServerSocket(socket_); + socket_ = -1; } - socket_ = -1; + + interface_listener_->Deinit(); + initialized_ = false; } bool TcpClientListener::IsInitialised() const { - return thread_; + return initialized_; } TcpClientListener::~TcpClientListener() { @@ -138,6 +158,7 @@ TcpClientListener::~TcpClientListener() { delete thread_->delegate(); threads::DeleteThread(thread_); Terminate(); + delete interface_listener_; } void SetKeepaliveOptions(const int fd) { @@ -203,104 +224,152 @@ void SetKeepaliveOptions(const int fd) { void TcpClientListener::Loop() { LOG4CXX_AUTO_TRACE(logger_); - while (!thread_stop_requested_) { - sockaddr_in client_address; - socklen_t client_address_size = sizeof(client_address); - const int connection_fd = accept( - socket_, (struct sockaddr*)&client_address, &client_address_size); - if (thread_stop_requested_) { - LOG4CXX_DEBUG(logger_, "thread_stop_requested_"); - close(connection_fd); - break; - } + fd_set rfds; + char dummy[16]; - if (connection_fd < 0) { - LOG4CXX_ERROR_WITH_ERRNO(logger_, "accept() failed"); - continue; - } - - if (AF_INET != client_address.sin_family) { - LOG4CXX_DEBUG(logger_, "Address of connected client is invalid"); - close(connection_fd); - continue; + while (!thread_stop_requested_) { + FD_ZERO(&rfds); + FD_SET(socket_, &rfds); + FD_SET(pipe_fds_[0], &rfds); + int nfds = socket_ > pipe_fds_[0] ? socket_ : pipe_fds_[0]; + + int ret = select(nfds + 1, &rfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno == EINTR) { + continue; + } else { + LOG4CXX_WARN(logger_, "select failed for TCP server socket"); + break; + } } - char device_name[32]; - strncpy(device_name, - inet_ntoa(client_address.sin_addr), - sizeof(device_name) / sizeof(device_name[0])); - LOG4CXX_INFO(logger_, "Connected client " << device_name); - LOG4CXX_INFO(logger_, "Port is: " << port_); - - if (enable_keepalive_) { - SetKeepaliveOptions(connection_fd); + if (FD_ISSET(pipe_fds_[0], &rfds)) { + ret = read(pipe_fds_[0], dummy, sizeof(dummy)); + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + LOG4CXX_WARN( + logger_, + "Failed to read from pipe, aborting TCP server socket loop."); + break; + } + } else if (ret == 0) { + LOG4CXX_WARN(logger_, + "Pipe disconnected, aborting TCP server socket loop."); + break; + } else { + LOG4CXX_DEBUG(logger_, + "received stop command of TCP server socket loop"); + break; + } } - const auto device_uid = - device_name + std::string(":") + std::to_string(port_); + if (FD_ISSET(socket_, &rfds)) { + sockaddr_in client_address; + socklen_t client_address_size = sizeof(client_address); + const int connection_fd = accept( + socket_, (struct sockaddr*)&client_address, &client_address_size); + if (thread_stop_requested_) { + LOG4CXX_DEBUG(logger_, "thread_stop_requested_"); + close(connection_fd); + break; + } + + if (connection_fd < 0) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "accept() failed"); + continue; + } + + if (AF_INET != client_address.sin_family) { + LOG4CXX_DEBUG(logger_, "Address of connected client is invalid"); + close(connection_fd); + continue; + } + + char device_name[32]; + size_t size = sizeof(device_name) / sizeof(device_name[0]); + strncpy(device_name, inet_ntoa(client_address.sin_addr), size); + + device_name[size - 1] = '\0'; + LOG4CXX_INFO(logger_, "Connected client " << device_name); + LOG4CXX_INFO(logger_, "Port is: " << port_); + + if (enable_keepalive_) { + SetKeepaliveOptions(connection_fd); + } + + const auto device_uid = + device_name + std::string(":") + std::to_string(port_); #if defined(BUILD_TESTS) - TcpDevice* tcp_device = - new TcpDevice(client_address.sin_addr.s_addr, device_uid, device_name); + auto tcp_device = std::make_shared<TcpDevice>( + client_address.sin_addr.s_addr, device_uid, device_name); #else - TcpDevice* tcp_device = - new TcpDevice(client_address.sin_addr.s_addr, device_uid); + auto tcp_device = std::make_shared<TcpDevice>( + client_address.sin_addr.s_addr, device_uid); #endif // BUILD_TESTS - DeviceSptr device = controller_->AddDevice(tcp_device); - tcp_device = static_cast<TcpDevice*>(device.get()); - const ApplicationHandle app_handle = - tcp_device->AddIncomingApplication(connection_fd); - - utils::SharedPtr<TcpSocketConnection> connection = - utils::MakeShared<TcpSocketConnection>( - device->unique_device_id(), app_handle, controller_); - controller_->ConnectionCreated( - connection, device->unique_device_id(), app_handle); - connection->set_socket(connection_fd); - const TransportAdapter::Error error = connection->Start(); - if (TransportAdapter::OK != error) { - LOG4CXX_ERROR(logger_, - "TCP connection::Start() failed with error: " << error); + DeviceSptr device = controller_->AddDevice(tcp_device); + auto tcp_device_raw = static_cast<TcpDevice*>(device.get()); + const ApplicationHandle app_handle = + tcp_device_raw->AddIncomingApplication(connection_fd); + + std::shared_ptr<TcpSocketConnection> connection = + std::make_shared<TcpSocketConnection>( + device->unique_device_id(), app_handle, controller_); + controller_->ConnectionCreated( + connection, device->unique_device_id(), app_handle); + connection->set_socket(connection_fd); + const TransportAdapter::Error error = connection->Start(); + if (TransportAdapter::OK != error) { + LOG4CXX_ERROR(logger_, + "TCP connection::Start() failed with error: " << error); + } } } + + LOG4CXX_INFO(logger_, "TCP server socket loop is terminated."); } void TcpClientListener::StopLoop() { LOG4CXX_AUTO_TRACE(logger_); + if (pipe_fds_[1] < 0) { + LOG4CXX_WARN(logger_, "StopLoop called in invalid state"); + return; + } + thread_stop_requested_ = true; - // We need to connect to the listening socket to unblock accept() call - int byesocket = socket(AF_INET, SOCK_STREAM, 0); - sockaddr_in server_address = {0}; - server_address.sin_family = AF_INET; - server_address.sin_port = htons(port_); - server_address.sin_addr.s_addr = INADDR_ANY; - if (0 != connect(byesocket, - reinterpret_cast<sockaddr*>(&server_address), - sizeof(server_address))) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Failed to connect byesocket"); - } else { - // Can only shutdown socket if connected - if (0 != shutdown(byesocket, SHUT_RDWR)) { - LOG4CXX_WARN_WITH_ERRNO(logger_, "Failed to shutdown byesocket"); - } + + char dummy[1] = {0}; + int ret = write(pipe_fds_[1], dummy, sizeof(dummy)); + if (ret <= 0) { + LOG4CXX_WARN_WITH_ERRNO( + logger_, "Failed to send stop message to TCP server socket loop"); } - close(byesocket); } TransportAdapter::Error TcpClientListener::StartListening() { LOG4CXX_AUTO_TRACE(logger_); - if (thread_->is_running()) { + if (started_) { LOG4CXX_WARN( logger_, "TransportAdapter::BAD_STATE. Listener has already been started"); return TransportAdapter::BAD_STATE; } - if (!thread_->start()) { - LOG4CXX_ERROR(logger_, "Tcp client listener thread start failed"); + if (!interface_listener_->Start()) { return TransportAdapter::FAIL; } + + if (!IsListeningOnSpecificInterface()) { + TransportAdapter::Error ret = StartListeningThread(); + if (TransportAdapter::OK != ret) { + LOG4CXX_ERROR(logger_, "Tcp client listener thread start failed"); + interface_listener_->Stop(); + return ret; + } + } + + started_ = true; LOG4CXX_INFO(logger_, "Tcp client listener has started successfully"); return TransportAdapter::OK; } @@ -319,16 +388,286 @@ TcpClientListener::ListeningThreadDelegate::ListeningThreadDelegate( TransportAdapter::Error TcpClientListener::StopListening() { LOG4CXX_AUTO_TRACE(logger_); - if (!thread_->is_running()) { + if (!started_) { LOG4CXX_DEBUG(logger_, "TcpClientListener is not running now"); return TransportAdapter::BAD_STATE; } - thread_->join(); + interface_listener_->Stop(); + + StopListeningThread(); + started_ = false; LOG4CXX_INFO(logger_, "Tcp client listener has stopped successfully"); return TransportAdapter::OK; } +TransportAdapter::Error TcpClientListener::StartListeningThread() { + LOG4CXX_AUTO_TRACE(logger_); + + // StartListening() can be called from multiple threads + sync_primitives::AutoLock auto_lock(start_stop_lock_); + + if (pipe_fds_[0] < 0 || pipe_fds_[1] < 0) { + // recreate the pipe every time, so that the thread loop will not get + // leftover + // data inside pipe after it is started + if (pipe(pipe_fds_) != 0) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to create internal pipe"); + return TransportAdapter::FAIL; + } + if (!SetNonblocking(pipe_fds_[0])) { + LOG4CXX_WARN(logger_, "Failed to configure pipe to non-blocking"); + } + } + + thread_stop_requested_ = false; + + if (!thread_->start()) { + return TransportAdapter::FAIL; + } + return TransportAdapter::OK; +} + +TransportAdapter::Error TcpClientListener::StopListeningThread() { + LOG4CXX_AUTO_TRACE(logger_); + + // StopListening() can be called from multiple threads + sync_primitives::AutoLock auto_lock(start_stop_lock_); + + thread_->join(); + + close(pipe_fds_[1]); + pipe_fds_[1] = -1; + close(pipe_fds_[0]); + pipe_fds_[0] = -1; + + return TransportAdapter::OK; +} + +void TcpClientListener::OnIPAddressUpdated(const std::string ipv4_addr, + const std::string ipv6_addr) { + LOG4CXX_AUTO_TRACE(logger_); + + // Since we only create a TCP socket with IPv4 option (AF_INET), currently we + // do not use IPv6 address. + if (ipv4_addr != current_ip_address_) { + if (IsListeningOnSpecificInterface()) { + if (!current_ip_address_.empty()) { + // the server socket is running, terminate it + LOG4CXX_DEBUG(logger_, + "Stopping current TCP server socket on " + << designated_interface_); + StopOnNetworkInterface(); + } + if (!ipv4_addr.empty()) { + // start (or restart) server socket with the new IP address + LOG4CXX_DEBUG( + logger_, "Starting TCP server socket on " << designated_interface_); + StartOnNetworkInterface(); + } + } + + current_ip_address_ = ipv4_addr; + + std::string enabled = !current_ip_address_.empty() ? "true" : "false"; + std::ostringstream oss; + oss << port_; + + TransportConfig config; + config.insert(std::make_pair(tc_enabled, enabled)); + config.insert(std::make_pair(tc_tcp_ip_address, current_ip_address_)); + config.insert(std::make_pair(tc_tcp_port, oss.str())); + + controller_->TransportConfigUpdated(config); + } +} + +bool TcpClientListener::StartOnNetworkInterface() { + LOG4CXX_AUTO_TRACE(logger_); + + // this method is only for the case that network interface is specified + if (IsListeningOnSpecificInterface()) { + { + // make sure that two threads will not update socket_ at the same time + sync_primitives::AutoLock auto_lock(start_stop_lock_); + if (socket_ < 0) { + socket_ = CreateIPv4ServerSocket(port_, designated_interface_); + if (-1 == socket_) { + LOG4CXX_WARN(logger_, "Failed to create TCP socket"); + return false; + } + } + } + + if (TransportAdapter::OK != StartListeningThread()) { + LOG4CXX_WARN(logger_, "Failed to start TCP client listener"); + return false; + } + LOG4CXX_INFO(logger_, + "TCP server socket started on " << designated_interface_); + } + return true; +} + +bool TcpClientListener::StopOnNetworkInterface() { + LOG4CXX_AUTO_TRACE(logger_); + + if (IsListeningOnSpecificInterface()) { + if (TransportAdapter::OK != StopListeningThread()) { + LOG4CXX_WARN(logger_, "Failed to stop TCP client listener"); + return false; + } + + { + sync_primitives::AutoLock auto_lock(start_stop_lock_); + DestroyServerSocket(socket_); + socket_ = -1; + } + + LOG4CXX_INFO(logger_, + "TCP server socket on " << designated_interface_ + << " stopped"); + } + return true; +} + +bool TcpClientListener::IsListeningOnSpecificInterface() const { + return !designated_interface_.empty(); +} + +int TcpClientListener::CreateIPv4ServerSocket( + uint16_t port, const std::string interface_name) { + LOG4CXX_AUTO_TRACE(logger_); + + struct in_addr ipv4_address; + memset(&ipv4_address, 0, sizeof(ipv4_address)); + if (interface_name.empty()) { + ipv4_address.s_addr = htonl(INADDR_ANY); + } else if (!GetIPv4Address(interface_name, &ipv4_address)) { + return -1; + } + + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (-1 == sock) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to create socket"); + return -1; + } + + sockaddr_in server_address = {0}; + server_address.sin_family = AF_INET; + server_address.sin_port = htons(port); + server_address.sin_addr = ipv4_address; + + int optval = 1; + if (0 != + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) { + LOG4CXX_WARN_WITH_ERRNO(logger_, "setsockopt SO_REUSEADDR failed"); + } + + if (bind(sock, + reinterpret_cast<sockaddr*>(&server_address), + sizeof(server_address)) != 0) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "bind() failed"); + close(sock); + return -1; + } + + const int kBacklog = 128; + if (0 != listen(sock, kBacklog)) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "listen() failed"); + close(sock); + return -1; + } + + return sock; +} + +void TcpClientListener::DestroyServerSocket(int sock) { + LOG4CXX_AUTO_TRACE(logger_); + if (sock >= 0) { + if (shutdown(sock, SHUT_RDWR) != 0) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to shutdown socket"); + } + if (close(sock) != 0) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to close socket"); + } + } +} + +bool TcpClientListener::GetIPv4Address(const std::string interface_name, + struct in_addr* ip_address) { + LOG4CXX_AUTO_TRACE(logger_); + +#ifdef BUILD_TESTS + if (testing_) { + // don't actually call getifaddrs(), instead return a dummy address of + // INADDR_LOOPBACK + struct in_addr dummy_addr; + dummy_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (ip_address != NULL) { + *ip_address = dummy_addr; + } + return true; + } +#endif // BUILD_TESTS + + struct ifaddrs* if_list; + if (getifaddrs(&if_list) != 0) { + LOG4CXX_WARN(logger_, "getifaddrs failed"); + return false; + } + + struct ifaddrs* interface; + bool found = false; + + for (interface = if_list; interface != NULL; + interface = interface->ifa_next) { + if (interface->ifa_name == NULL) { + continue; + } + if (interface_name == interface->ifa_name) { + if (interface->ifa_addr == NULL) { + continue; + } + switch (interface->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in* addr = + reinterpret_cast<struct sockaddr_in*>(interface->ifa_addr); + if (ip_address != NULL) { + *ip_address = addr->sin_addr; + } + found = true; + break; + } + default: + break; + } + } + } + + freeifaddrs(if_list); + + return found; +} + +static bool SetNonblocking(int s) { + int prev_flag = fcntl(s, F_GETFL, 0); + if (prev_flag == -1) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to acquire socket flag"); + return false; + } + + int ret = fcntl(s, F_SETFL, prev_flag | O_NONBLOCK); + if (ret == -1) { + LOG4CXX_ERROR_WITH_ERRNO(logger_, + "Failed to configure socket to non-blocking"); + return false; + } + + return true; +} + } // namespace transport_adapter } // namespace transport_manager diff --git a/src/components/transport_manager/src/tcp/tcp_connection_factory.cc b/src/components/transport_manager/src/tcp/tcp_connection_factory.cc index 114425076a..e202554f8f 100644 --- a/src/components/transport_manager/src/tcp/tcp_connection_factory.cc +++ b/src/components/transport_manager/src/tcp/tcp_connection_factory.cc @@ -35,7 +35,6 @@ #include "transport_manager/tcp/tcp_server_originated_socket_connection.h" #include "utils/logger.h" -#include "utils/make_shared.h" namespace transport_manager { namespace transport_adapter { @@ -56,8 +55,8 @@ TransportAdapter::Error TcpConnectionFactory::CreateConnection( LOG4CXX_DEBUG(logger_, "DeviceUID: " << &device_uid << ", ApplicationHandle: " << &app_handle); - utils::SharedPtr<TcpServerOriginatedSocketConnection> connection = - utils::MakeShared<TcpServerOriginatedSocketConnection>( + std::shared_ptr<TcpServerOriginatedSocketConnection> connection = + std::make_shared<TcpServerOriginatedSocketConnection>( device_uid, app_handle, controller_); controller_->ConnectionCreated(connection, device_uid, app_handle); const TransportAdapter::Error error = connection->Start(); diff --git a/src/components/transport_manager/src/tcp/tcp_server_originated_socket_connection.cc b/src/components/transport_manager/src/tcp/tcp_server_originated_socket_connection.cc index 516f2d3ec4..2f10bd9454 100644 --- a/src/components/transport_manager/src/tcp/tcp_server_originated_socket_connection.cc +++ b/src/components/transport_manager/src/tcp/tcp_server_originated_socket_connection.cc @@ -56,7 +56,7 @@ bool TcpServerOriginatedSocketConnection::Establish(ConnectError** error) { DCHECK(error); LOG4CXX_DEBUG(logger_, "error " << error); DeviceSptr device = controller()->FindDevice(device_handle()); - if (!device.valid()) { + if (device.use_count() == 0) { LOG4CXX_ERROR(logger_, "Device " << device_handle() << " not found"); *error = new ConnectError(); return false; diff --git a/src/components/transport_manager/src/tcp/tcp_transport_adapter.cc b/src/components/transport_manager/src/tcp/tcp_transport_adapter.cc index 0e9e63263b..b3dbf49628 100644 --- a/src/components/transport_manager/src/tcp/tcp_transport_adapter.cc +++ b/src/components/transport_manager/src/tcp/tcp_transport_adapter.cc @@ -55,14 +55,35 @@ TcpTransportAdapter::TcpTransportAdapter( const uint16_t port, resumption::LastState& last_state, const TransportManagerSettings& settings) - : TransportAdapterImpl(NULL, - new TcpConnectionFactory(this), - new TcpClientListener(this, port, true), - last_state, - settings) {} + : TransportAdapterImpl( + NULL, + new TcpConnectionFactory(this), + new TcpClientListener( + this, + port, + true, + settings.transport_manager_tcp_adapter_network_interface()), + last_state, + settings) {} TcpTransportAdapter::~TcpTransportAdapter() {} +void TcpTransportAdapter::TransportConfigUpdated( + const TransportConfig& new_config) { + LOG4CXX_AUTO_TRACE(logger_); + + transport_config_ = new_config; + + // call the method of parent class to trigger OnTransportConfigUpdated() for + // the listeners + TransportAdapterImpl::TransportConfigUpdated(new_config); +} + +TransportConfig TcpTransportAdapter::GetTransportConfiguration() const { + LOG4CXX_AUTO_TRACE(logger_); + return transport_config_; +} + DeviceType TcpTransportAdapter::GetDeviceType() const { return TCP; } @@ -79,8 +100,8 @@ void TcpTransportAdapter::Store() const { if (!device) { // device could have been disconnected continue; } - utils::SharedPtr<TcpDevice> tcp_device = - DeviceSptr::static_pointer_cast<TcpDevice>(device); + std::shared_ptr<TcpDevice> tcp_device = + std::static_pointer_cast<TcpDevice>(device); Json::Value device_dictionary; device_dictionary["name"] = tcp_device->name(); struct in_addr address; diff --git a/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc index bdacd68006..346139cbd2 100644 --- a/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc +++ b/src/components/transport_manager/src/transport_adapter/transport_adapter_impl.cc @@ -43,18 +43,24 @@ namespace transport_manager { namespace transport_adapter { +const char* tc_enabled = "enabled"; +const char* tc_tcp_port = "tcp_port"; +const char* tc_tcp_ip_address = "tcp_ip_address"; + CREATE_LOGGERPTR_GLOBAL(logger_, "TransportManager") namespace { -// @deprecated DeviceTypes: PASA_AOA, PASA_BLUETOOTH, MME DeviceTypes devicesType = { std::make_pair(DeviceType::AOA, std::string("USB_AOA")), - std::make_pair(DeviceType::PASA_AOA, std::string("USB_AOA")), std::make_pair(DeviceType::BLUETOOTH, std::string("BLUETOOTH")), - std::make_pair(DeviceType::PASA_BLUETOOTH, std::string("BLUETOOTH")), - std::make_pair(DeviceType::MME, std::string("USB_IOS")), std::make_pair(DeviceType::IOS_BT, std::string("BLUETOOTH_IOS")), std::make_pair(DeviceType::IOS_USB, std::string("USB_IOS")), - std::make_pair(DeviceType::TCP, std::string("WIFI"))}; + std::make_pair(DeviceType::TCP, std::string("WIFI")), + std::make_pair(DeviceType::IOS_USB_HOST_MODE, + std::string("USB_IOS_HOST_MODE")), + std::make_pair(DeviceType::IOS_USB_DEVICE_MODE, + std::string("USB_IOS_DEVICE_MODE")), + std::make_pair(DeviceType::IOS_CARPLAY_WIRELESS, + std::string("CARPLAY_WIRELESS_IOS"))}; } TransportAdapterImpl::TransportAdapterImpl( @@ -695,6 +701,16 @@ void TransportAdapterImpl::DataSendFailed( LOG4CXX_TRACE(logger_, "exit"); } +void TransportAdapterImpl::TransportConfigUpdated( + const TransportConfig& new_config) { + LOG4CXX_AUTO_TRACE(logger_); + for (TransportAdapterListenerList::iterator it = listeners_.begin(); + it != listeners_.end(); + ++it) { + (*it)->OnTransportConfigUpdated(this); + } +} + void TransportAdapterImpl::DoTransportSwitch() const { LOG4CXX_AUTO_TRACE(logger_); std::for_each( @@ -803,16 +819,16 @@ ApplicationList TransportAdapterImpl::GetApplicationList( const DeviceUID& device_id) const { LOG4CXX_TRACE(logger_, "enter. device_id: " << &device_id); DeviceSptr device = FindDevice(device_id); - if (device.valid()) { + if (device.use_count() != 0) { ApplicationList lst = device->GetApplicationList(); LOG4CXX_TRACE(logger_, "exit with ApplicationList. It's size = " - << lst.size() << " Condition: device.valid()"); + << lst.size() << " Condition: device.use_count() != 0"); return lst; } - LOG4CXX_TRACE( - logger_, - "exit with empty ApplicationList. Condition: NOT device.valid()"); + LOG4CXX_TRACE(logger_, + "exit with empty ApplicationList. Condition: NOT " + "device.use_count() != 0"); return ApplicationList(); } @@ -875,7 +891,7 @@ bool TransportAdapterImpl::IsInitialised() const { std::string TransportAdapterImpl::DeviceName(const DeviceUID& device_id) const { DeviceSptr device = FindDevice(device_id); - if (device.valid()) { + if (device.use_count() != 0) { return device->name(); } else { return ""; diff --git a/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc b/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc index f1181ce921..544cdde999 100644 --- a/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc +++ b/src/components/transport_manager/src/transport_adapter/transport_adapter_listener_impl.cc @@ -275,7 +275,7 @@ void TransportAdapterListenerImpl::OnDataSendDone( device, app_id, data_container, - new BaseError()); + std::make_shared<BaseError>()); if (transport_manager_ != NULL && transport_manager::E_SUCCESS != transport_manager_->ReceiveEventFromDevice(event)) { @@ -376,4 +376,23 @@ void TransportAdapterListenerImpl::OnTransportSwitchRequested( LOG4CXX_WARN(logger_, "Failed to receive event from device"); } } + +void TransportAdapterListenerImpl::OnTransportConfigUpdated( + const transport_adapter::TransportAdapter* adapter) { + LOG4CXX_AUTO_TRACE(logger_); + + const TransportAdapterEvent event(EventTypeEnum::ON_TRANSPORT_CONFIG_UPDATED, + transport_adapter_, + "", + 0, + ::protocol_handler::RawMessagePtr(), + BaseErrorPtr()); + + if (transport_manager_ != NULL && + transport_manager::E_SUCCESS != + transport_manager_->ReceiveEventFromDevice(event)) { + LOG4CXX_WARN(logger_, "Failed to receive event from device"); + } +} + } // namespace transport_manager diff --git a/src/components/transport_manager/src/transport_manager_impl.cc b/src/components/transport_manager/src/transport_manager_impl.cc index a364220a64..2b0296debb 100644 --- a/src/components/transport_manager/src/transport_manager_impl.cc +++ b/src/components/transport_manager/src/transport_manager_impl.cc @@ -44,7 +44,7 @@ #include "utils/macro.h" #include "utils/logger.h" -#include "utils/make_shared.h" + #include "utils/timer_task_impl.h" #include "transport_manager/common.h" #include "transport_manager/transport_manager_listener.h" @@ -529,6 +529,8 @@ int TransportManagerImpl::Reinit() { LOG4CXX_AUTO_TRACE(logger_); DisconnectAllDevices(); TerminateAllAdapters(); + device_to_adapter_map_.clear(); + connection_id_counter_ = 0; int ret = InitAllAdapters(); return ret; } @@ -1066,7 +1068,7 @@ void TransportManagerImpl::Handle(TransportAdapterEvent event) { LOG4CXX_ERROR(logger_, "Transport adapter failed to send data"); // TODO(YK): potential error case -> thread unsafe // update of message content - if (event.event_data.valid()) { + if (event.event_data.use_count() != 0) { event.event_data->set_waiting(true); } else { LOG4CXX_DEBUG(logger_, "Data is invalid"); @@ -1144,6 +1146,13 @@ void TransportManagerImpl::Handle(TransportAdapterEvent event) { LOG4CXX_DEBUG(logger_, "eevent_type = ON_UNEXPECTED_DISCONNECT"); break; } + case EventTypeEnum::ON_TRANSPORT_CONFIG_UPDATED: { + LOG4CXX_DEBUG(logger_, "event_type = ON_TRANSPORT_CONFIG_UPDATED"); + transport_adapter::TransportConfig config = + event.transport_adapter->GetTransportConfiguration(); + RaiseEvent(&TransportManagerListener::OnTransportConfigUpdated, config); + break; + } } // switch LOG4CXX_TRACE(logger_, "exit"); } @@ -1203,9 +1212,9 @@ TransportManagerImpl::ConnectionInternal::ConnectionInternal( const DeviceHandle device_handle) : transport_manager(transport_manager) , transport_adapter(transport_adapter) - , timer(utils::MakeShared<timer::Timer, - const char*, - ::timer::TimerTaskImpl<ConnectionInternal>*>( + , timer(std::make_shared<timer::Timer, + const char*, + ::timer::TimerTaskImpl<ConnectionInternal>*>( "TM DiscRoutine", new ::timer::TimerTaskImpl<ConnectionInternal>( this, &ConnectionInternal::DisconnectFailedRoutine))) diff --git a/src/components/transport_manager/src/usb/libusb/usb_connection.cc b/src/components/transport_manager/src/usb/libusb/usb_connection.cc index e9ab2bae8e..212e6e0ec3 100644 --- a/src/components/transport_manager/src/usb/libusb/usb_connection.cc +++ b/src/components/transport_manager/src/usb/libusb/usb_connection.cc @@ -224,7 +224,7 @@ void UsbConnection::OnOutTransfer(libusb_transfer* transfer) { device_uid_, app_handle_, current_out_message_, DataSendError()); PopOutMessage(); } - if (!current_out_message_.valid()) { + if (current_out_message_.use_count() == 0) { libusb_free_transfer(transfer); out_transfer_ = NULL; waiting_out_transfer_cancel_ = false; @@ -242,7 +242,7 @@ TransportAdapter::Error UsbConnection::SendData( return TransportAdapter::BAD_STATE; } sync_primitives::AutoLock locker(out_messages_mutex_); - if (current_out_message_.valid()) { + if (current_out_message_.use_count() != 0) { out_messages_.push_back(message); } else { current_out_message_ = message; diff --git a/src/components/transport_manager/src/usb/qnx/usb_connection.cc b/src/components/transport_manager/src/usb/qnx/usb_connection.cc index 516a367ebc..b9386c5d9f 100644 --- a/src/components/transport_manager/src/usb/qnx/usb_connection.cc +++ b/src/components/transport_manager/src/usb/qnx/usb_connection.cc @@ -230,7 +230,7 @@ void UsbConnection::OnOutTransfer(usbd_urb* urb) { } } - if ((!disconnecting_) && current_out_message_.valid()) { + if ((!disconnecting_) && (current_out_message_.use_count() != 0)) { PostOutTransfer(); } else { pending_out_transfer_ = false; @@ -243,7 +243,7 @@ TransportAdapter::Error UsbConnection::SendData( return TransportAdapter::BAD_STATE; } sync_primitives::AutoLock locker(out_messages_mutex_); - if (current_out_message_.valid()) { + if (current_out_message_.use_count() != 0) { out_messages_.push_back(message); } else { current_out_message_ = message; diff --git a/src/components/transport_manager/src/usb/usb_connection_factory.cc b/src/components/transport_manager/src/usb/usb_connection_factory.cc index 1136dfad21..528855cd50 100644 --- a/src/components/transport_manager/src/usb/usb_connection_factory.cc +++ b/src/components/transport_manager/src/usb/usb_connection_factory.cc @@ -34,7 +34,6 @@ #include "transport_manager/usb/usb_device.h" #include "transport_manager/transport_adapter/transport_adapter_impl.h" #include "utils/logger.h" -#include "utils/make_shared.h" #if defined(__QNXNTO__) #include "transport_manager/usb/qnx/usb_connection.h" @@ -65,21 +64,21 @@ TransportAdapter::Error UsbConnectionFactory::CreateConnection( "enter DeviceUID: " << &device_uid << ", ApplicationHandle: " << &app_handle); DeviceSptr device = controller_->FindDevice(device_uid); - if (!device.valid()) { + if (device.use_count() == 0) { LOG4CXX_ERROR(logger_, "device " << device_uid << " not found"); - LOG4CXX_TRACE( - logger_, - "exit with TransportAdapter::BAD_PARAM. Condition: !device.valid()"); + LOG4CXX_TRACE(logger_, + "exit with TransportAdapter::BAD_PARAM. Condition: " + "device.use_count() == 0"); return TransportAdapter::BAD_PARAM; } UsbDevice* usb_device = static_cast<UsbDevice*>(device.get()); - utils::SharedPtr<UsbConnection> connection = - utils::MakeShared<UsbConnection>(device_uid, - app_handle, - controller_, - usb_handler_, - usb_device->usb_device()); + std::shared_ptr<UsbConnection> connection = + std::make_shared<UsbConnection>(device_uid, + app_handle, + controller_, + usb_handler_, + usb_device->usb_device()); controller_->ConnectionCreated(connection, device_uid, app_handle); if (connection->Init()) { LOG4CXX_INFO(logger_, "USB connection initialised"); diff --git a/src/components/transport_manager/test/CMakeLists.txt b/src/components/transport_manager/test/CMakeLists.txt index 41aae296ac..240784436b 100644 --- a/src/components/transport_manager/test/CMakeLists.txt +++ b/src/components/transport_manager/test/CMakeLists.txt @@ -42,11 +42,18 @@ include_directories( ) set(EXCLUDE_PATHS + platform_specific raw_message_matcher.cc ) collect_sources(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}" "${EXCLUDE_PATHS}") +set(PLATFORM_DEPENDENT_SOURCES) +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + collect_sources(PLATFORM_DEPENDENT_SOURCES platform_specific/linux) +endif() +list(APPEND SOURCES ${PLATFORM_DEPENDENT_SOURCES}) + set(LIBRARIES gmock ConfigProfile diff --git a/src/components/transport_manager/test/include/transport_manager/raw_message_matcher.h b/src/components/transport_manager/test/include/transport_manager/raw_message_matcher.h index bb15c19d3b..9c7327e6fb 100644 --- a/src/components/transport_manager/test/include/transport_manager/raw_message_matcher.h +++ b/src/components/transport_manager/test/include/transport_manager/raw_message_matcher.h @@ -57,8 +57,8 @@ class RawMessageMatcher : public MatcherInterface<RawMessagePtr> { virtual bool MatchAndExplain(const RawMessagePtr ptr, MatchResultListener* listener) const; - virtual void DescribeTo(::std::ostream* os) const; - virtual void DescribeNegationTo(::std::ostream* os) const; + virtual void DescribeTo(std::ostream* os) const; + virtual void DescribeNegationTo(std::ostream* os) const; private: const RawMessagePtr ptr_; diff --git a/src/components/transport_manager/test/include/transport_manager/tcp/mock_tcp_client_listener.h b/src/components/transport_manager/test/include/transport_manager/tcp/mock_tcp_client_listener.h new file mode 100644 index 0000000000..d18500b02d --- /dev/null +++ b/src/components/transport_manager/test/include/transport_manager/tcp/mock_tcp_client_listener.h @@ -0,0 +1,34 @@ +#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_TCP_MOCK_TCP_CLIENT_LISTENER_H_ +#define SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_TCP_MOCK_TCP_CLIENT_LISTENER_H_ + +#include "gmock/gmock.h" +#include "transport_manager/tcp/tcp_client_listener.h" + +namespace test { +namespace components { +namespace transport_manager_test { + +using namespace ::transport_manager::transport_adapter; + +class MockTcpClientListener : public TcpClientListener { + public: + MockTcpClientListener(TransportAdapterController* controller, + uint16_t port, + bool enable_keepalive, + const std::string designated_interface = "") + : TcpClientListener( + controller, port, enable_keepalive, designated_interface) {} + MOCK_METHOD0(Init, TransportAdapter::Error()); + MOCK_METHOD0(Terminate, void()); + MOCK_CONST_METHOD0(IsInitialised, bool()); + MOCK_METHOD0(StartListening, TransportAdapter::Error()); + MOCK_METHOD0(StopListening, TransportAdapter::Error()); + MOCK_METHOD2(OnIPAddressUpdated, + void(const std::string ipv4_addr, const std::string ipv6_addr)); +}; + +} // namespace transport_manager_test +} // namespace components +} // namespace test + +#endif // SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_TCP_MOCK_TCP_CLIENT_LISTENER_H_ diff --git a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h index 03e7630e8b..dce23189c8 100644 --- a/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h +++ b/src/components/transport_manager/test/include/transport_manager/transport_adapter/mock_transport_adapter_listener.h @@ -122,6 +122,8 @@ class MockTransportAdapterListener : public TransportAdapterListener { const ApplicationHandle&)); MOCK_METHOD1(OnTransportSwitchRequested, void(const TransportAdapter* transport_adapter)); + MOCK_METHOD1(OnTransportConfigUpdated, + void(const TransportAdapter* transport_adapter)); }; } // namespace transport_manager_test diff --git a/src/components/transport_manager/test/network_interface_listener_test.cc b/src/components/transport_manager/test/network_interface_listener_test.cc new file mode 100644 index 0000000000..55a35fb4ea --- /dev/null +++ b/src/components/transport_manager/test/network_interface_listener_test.cc @@ -0,0 +1,57 @@ +#include <arpa/inet.h> +#include <net/if.h> +#include <time.h> + +#include "gtest/gtest.h" +#include "transport_manager/tcp/network_interface_listener_impl.h" +#include "transport_manager/tcp/mock_tcp_client_listener.h" +#include "utils/test_async_waiter.h" +#include "utils/threads/thread.h" + +namespace test { +namespace components { +namespace transport_manager_test { + +namespace { +const long kThreadStartWaitMsec = 10; +const uint32_t kStartNotificationTimeoutMsec = 500; +} + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::SaveArg; + +class NetworkInterfaceListenerTest : public ::testing::Test { + public: + NetworkInterfaceListenerTest() + : interface_listener_impl_(NULL) + , mock_tcp_client_listener_(NULL, 0, false, "") {} + + virtual ~NetworkInterfaceListenerTest() {} + + protected: + struct InterfaceEntry { + const char* name; + const char* ipv4_address; + const char* ipv6_address; + unsigned int flags; + }; + + void Deinit() { + delete interface_listener_impl_; + } + + void SleepFor(long msec) const { + if (msec > 0) { + struct timespec ts = {0, msec * 1000 * 1000}; + nanosleep(&ts, NULL); + } + } + + NetworkInterfaceListenerImpl* interface_listener_impl_; + MockTcpClientListener mock_tcp_client_listener_; +}; + +} // namespace transport_manager_test +} // namespace components +} // namespace test diff --git a/src/components/transport_manager/test/platform_specific/linux/linux_network_interface_listener_test.cc b/src/components/transport_manager/test/platform_specific/linux/linux_network_interface_listener_test.cc new file mode 100644 index 0000000000..da58466c29 --- /dev/null +++ b/src/components/transport_manager/test/platform_specific/linux/linux_network_interface_listener_test.cc @@ -0,0 +1,567 @@ +#include <arpa/inet.h> +#include <net/if.h> +#include <time.h> + +#include "gtest/gtest.h" +#include "platform_specific_network_interface_listener_impl.h" +#include "transport_manager/tcp/mock_tcp_client_listener.h" +#include "utils/test_async_waiter.h" +#include "utils/threads/thread.h" + +namespace test { +namespace components { +namespace transport_manager_test { + +namespace { +const long kThreadStartWaitMsec = 10; +const uint32_t kStartNotificationTimeoutMsec = 500; +} + +using ::testing::_; +using ::testing::AtLeast; +using ::testing::SaveArg; + +class NetworkInterfaceListenerTest : public ::testing::Test { + public: + NetworkInterfaceListenerTest() + : interface_listener_impl_(NULL) + , mock_tcp_client_listener_(NULL, 0, false, "") {} + + virtual ~NetworkInterfaceListenerTest() {} + + protected: + struct InterfaceEntry { + const char* name; + const char* ipv4_address; + const char* ipv6_address; + unsigned int flags; + }; + + void Init(const std::string interface_name) { + interface_listener_impl_ = new PlatformSpecificNetworkInterfaceListener( + &mock_tcp_client_listener_, interface_name); + // disable events from actual network interfaces + interface_listener_impl_->SetTesting(true); + } + + void Deinit() { + delete interface_listener_impl_; + } + + void SetDummyInterfaceTable(struct InterfaceEntry* entries) { + InterfaceStatusTable dummy_table; + + while (entries->name != NULL) { + InterfaceStatus status; + if (entries->ipv4_address != NULL) { + struct in_addr addr; + ASSERT_EQ(1, inet_pton(AF_INET, entries->ipv4_address, &addr)); + status.SetIPv4Address(&addr); + } + if (entries->ipv6_address != NULL) { + struct in6_addr addr6; + ASSERT_EQ(1, inet_pton(AF_INET6, entries->ipv6_address, &addr6)); + status.SetIPv6Address(&addr6); + } + status.SetFlags(entries->flags); + + dummy_table.insert(std::make_pair(entries->name, status)); + entries++; + } + + interface_listener_impl_->OverwriteStatusTable(dummy_table); + } + + void SleepFor(long msec) const { + if (msec > 0) { + struct timespec ts = {0, msec * 1000 * 1000}; + nanosleep(&ts, NULL); + } + } + + PlatformSpecificNetworkInterfaceListener* interface_listener_impl_; + MockTcpClientListener mock_tcp_client_listener_; +}; + +TEST_F(NetworkInterfaceListenerTest, Init) { + Init(""); + + EXPECT_TRUE(interface_listener_impl_->Init()); + EXPECT_TRUE(0 <= interface_listener_impl_->GetSocket()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Deinit) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + interface_listener_impl_->Deinit(); + + EXPECT_EQ(-1, interface_listener_impl_->GetSocket()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Start_success) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + SetDummyInterfaceTable(entries); + + // after stated, it is expected that the listener notifies current IP address + // (if it's available) + TestAsyncWaiter waiter; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries[0].ipv4_address, "")) + .WillOnce(NotifyTestAsyncWaiter(&waiter)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + + // the "isThreadRunning_" flag of the thread will be update slightly later + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(interface_listener_impl_->GetThread()->is_running()); + + EXPECT_TRUE(waiter.WaitFor(1, kStartNotificationTimeoutMsec)); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Start_twice) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + // ignore OnIPAddressUpdated call + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .Times(AtLeast(0)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(interface_listener_impl_->Start()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Stop_success) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + // ignore OnIPAddressUpdated call + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .Times(AtLeast(0)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(interface_listener_impl_->Stop()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(interface_listener_impl_->GetThread()->is_running()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Stop_twice) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + // ignore OnIPAddressUpdated call + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .Times(AtLeast(0)); + + EXPECT_TRUE(interface_listener_impl_->Start()); + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(interface_listener_impl_->Stop()); + + EXPECT_FALSE(interface_listener_impl_->Stop()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, Stop_without_Start) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + EXPECT_FALSE(interface_listener_impl_->Stop()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_IPAddressChanged) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int0", "5.6.7.8", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, "")).Times(1); + + // this test case doesn't call Start() - we only check the behavior of + // NotifyIPAddresses() + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries2[0].ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_IPAddressNotChanged) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {"dummy_int1", "172.16.23.30", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + // OnIPAddressUpdated() shouldn't be notified + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(0); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_GoesUnavailable) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", "fdc2:12af:327a::1", IFF_UP | IFF_RUNNING}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int0", "1.2.3.4", "fdc2:12af:327a::1", IFF_UP}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, + entries1[0].ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated("", "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_Removed) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int0", "1.2.3.4", "fdc2:12af:327a::1", IFF_UP | IFF_RUNNING}, + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries1[0].ipv4_address, + entries1[0].ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated("", "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, DesignatedInterface_Added) { + Init("dummy_int0"); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries1[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + struct InterfaceEntry entries2[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {"dummy_int0", "1.2.3.4", NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + SetDummyInterfaceTable(entries2); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries2[1].ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_SelectInterface) { + // automatically select network interface + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries); + + std::string output_ipv4_address; + std::string output_ipv6_address; + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)) + .WillOnce(DoAll(SaveArg<0>(&output_ipv4_address), + SaveArg<1>(&output_ipv6_address))); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + std::string selected_interface = + interface_listener_impl_->GetSelectedInterfaceName(); + + // the interface listener should pick one of the interfaces + EXPECT_TRUE((selected_interface == entries[0].name && + output_ipv4_address == entries[0].ipv4_address && + output_ipv6_address == "") || + (selected_interface == entries[1].name && + output_ipv4_address == entries[1].ipv4_address && + output_ipv6_address == entries[1].ipv6_address)); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, + AutoSelectInterface_SkipUnavailableInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries); + + // dummy_int1 should not be selected + struct InterfaceEntry* expected = &entries[1]; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(expected->ipv4_address, + expected->ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(expected->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_SkipEmptyInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING}, + {"net_dummy2", NULL, NULL, IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + SetDummyInterfaceTable(entries); + + // net_dummy2 should not be selected + struct InterfaceEntry* expected = &entries[0]; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(expected->ipv4_address, "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(expected->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, + AutoSelectInterface_SkipLoopbackInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", "10.10.10.12", NULL, IFF_UP | IFF_RUNNING | IFF_LOOPBACK}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + // dummy_int1 should not be selected + struct InterfaceEntry* expected = &entries[1]; + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(expected->ipv4_address, + expected->ipv6_address)).Times(1); + + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(expected->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_DisableInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"net_dummy0", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + // make the interface "not running" + entries[0].flags &= ~IFF_RUNNING; + SetDummyInterfaceTable(entries); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated("", "")).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ("", interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_EnableInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"net_dummy0", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + // make the interface "not running" + entries[0].flags &= ~IFF_RUNNING; + SetDummyInterfaceTable(entries); + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + // make it running again + entries[0].flags |= IFF_RUNNING; + SetDummyInterfaceTable(entries); + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(entries[0].ipv4_address, + entries[0].ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(entries[0].name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +TEST_F(NetworkInterfaceListenerTest, AutoSelectInterface_SwitchInterface) { + Init(""); + EXPECT_TRUE(interface_listener_impl_->Init()); + + struct InterfaceEntry entries[] = { + {"dummy_int1", + "10.10.10.12", + "fd53:ba79:241d:30c1::78", + IFF_UP | IFF_RUNNING}, + {"net_dummy2", "192.168.2.3", "fdc2:12af:327a::22", IFF_UP | IFF_RUNNING}, + {NULL, NULL, NULL, 0}}; + + EXPECT_CALL(mock_tcp_client_listener_, OnIPAddressUpdated(_, _)).Times(1); + SetDummyInterfaceTable(entries); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + const std::string selected_interface = + interface_listener_impl_->GetSelectedInterfaceName(); + struct InterfaceEntry* selected = &entries[0]; + while (selected->name != NULL) { + if (selected->name == selected_interface) { + break; + } + selected++; + } + ASSERT_TRUE(selected->name != NULL); + + // make the interface "not running" + selected->flags &= ~IFF_RUNNING; + SetDummyInterfaceTable(entries); + + struct InterfaceEntry* switched; + if (selected == &entries[0]) { + switched = &entries[1]; + } else { + switched = &entries[0]; + } + + EXPECT_CALL(mock_tcp_client_listener_, + OnIPAddressUpdated(switched->ipv4_address, + switched->ipv6_address)).Times(1); + + interface_listener_impl_->testCallNotifyIPAddresses(); + + EXPECT_EQ(switched->name, + interface_listener_impl_->GetSelectedInterfaceName()); + + Deinit(); +} + +} // namespace transport_manager_test +} // namespace components +} // namespace test diff --git a/src/components/transport_manager/test/tcp_client_listener_test.cc b/src/components/transport_manager/test/tcp_client_listener_test.cc index b179f63ece..5205d6ae3c 100644 --- a/src/components/transport_manager/test/tcp_client_listener_test.cc +++ b/src/components/transport_manager/test/tcp_client_listener_test.cc @@ -30,21 +30,38 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#include <time.h> + #include "gtest/gtest.h" #include "transport_manager/transport_adapter/mock_transport_adapter.h" #include "transport_manager/tcp/tcp_client_listener.h" +#include "transport_manager/tcp/network_interface_listener.h" #include "transport_manager/mock_transport_manager.h" #include "transport_manager/transport_adapter/transport_adapter_controller.h" -#include "transport_manager/transport_adapter/device.h" +#include "transport_manager/transport_adapter/mock_device.h" + +#include "utils/test_async_waiter.h" +#include "utils/threads/thread.h" namespace test { namespace components { namespace transport_manager_test { +using ::testing::_; +using ::testing::AtLeast; using ::testing::Return; using namespace ::transport_manager; using namespace ::transport_manager::transport_adapter; +namespace { +const long kThreadStartWaitMsec = 10; +const uint32_t kConnectionCreatedTimeoutMsec = 200; +} + class MockTransportAdapterController : public TransportAdapterController { public: MOCK_METHOD1(AddDevice, DeviceSptr(DeviceSptr device)); @@ -95,37 +112,491 @@ class MockTransportAdapterController : public TransportAdapterController { MOCK_METHOD2(DeviceDisconnected, void(const DeviceUID& device_handle, const DisconnectDeviceError& error)); + MOCK_METHOD1(TransportConfigUpdated, + void(const transport_manager::transport_adapter::TransportConfig& + new_config)); }; -class TcpClientListenerTest : public ::testing::Test { +class MockNetworkInterfaceListener : public NetworkInterfaceListener { + public: + MOCK_METHOD0(Init, bool()); + MOCK_METHOD0(Deinit, void()); + MOCK_METHOD0(Start, bool()); + MOCK_METHOD0(Stop, bool()); +}; + +class TcpClientListenerTest : public ::testing::TestWithParam<std::string> { public: TcpClientListenerTest() - : port_(0) + : port_(0) /* On Linux, binding to port 0 lets the system choose an + available port */ , enable_keep_alive_(false) - , tcp_client_listener_( - &adapter_controller_mock_, port_, enable_keep_alive_) {} + , interface_listener_mock_(NULL) + , tcp_client_listener_(NULL) {} + virtual ~TcpClientListenerTest() { + delete tcp_client_listener_; + } protected: + void SetUp() OVERRIDE { + tcp_client_listener_ = new TcpClientListener( + &adapter_controller_mock_, port_, enable_keep_alive_, GetParam()); + interface_listener_mock_ = new MockNetworkInterfaceListener(); + tcp_client_listener_->set_testing(true); + tcp_client_listener_->set_network_interface_listener( + interface_listener_mock_); + } + + bool InterfaceNameSpecified() const { + return "" != GetParam(); + } + + void SleepFor(long msec) const { + if (msec > 0) { + struct timespec ts = {0, msec * 1000 * 1000}; + nanosleep(&ts, NULL); + } + } + uint16_t port_; bool enable_keep_alive_; MockTransportAdapterController adapter_controller_mock_; - TcpClientListener tcp_client_listener_; + MockNetworkInterfaceListener* interface_listener_mock_; + TcpClientListener* tcp_client_listener_; }; -TEST_F(TcpClientListenerTest, Ctor_test) { - EXPECT_EQ(0, tcp_client_listener_.port()); - EXPECT_TRUE(NULL != tcp_client_listener_.thread()); - EXPECT_EQ(-1, tcp_client_listener_.get_socket()); +TEST_P(TcpClientListenerTest, Ctor_test) { + EXPECT_EQ(0, tcp_client_listener_->port()); + EXPECT_TRUE(NULL != tcp_client_listener_->thread()); + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); +} + +TEST_P(TcpClientListenerTest, IsInitialised) { + // should return false until Init() is called + EXPECT_FALSE(tcp_client_listener_->IsInitialised()); +} + +TEST_P(TcpClientListenerTest, Init) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + + if (InterfaceNameSpecified()) { + // TcpClientListener will create socket once IP address of the network is + // notified. + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); + } else { + // Interface name is not designated. In this case, TcpClientListener will + // create socket with Init(). + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + } + + EXPECT_TRUE(tcp_client_listener_->IsInitialised()); + + // Deinit() will be called during destructor + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, Terminate) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); + + tcp_client_listener_->Terminate(); + + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); +} + +TEST_P(TcpClientListenerTest, StartListening) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + // the "isThreadRunning_" flag of the thread will be update slightly later + SleepFor(kThreadStartWaitMsec); + + if (InterfaceNameSpecified()) { + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + } else { + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + // Stop() and Deinit() will be called during destructor + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, StartListening_twice) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + // call again + EXPECT_EQ(TransportAdapter::BAD_STATE, + tcp_client_listener_->StartListening()); + + // Stop() and Deinit() will be called during destructor + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, StopListening) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StopListening()); + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, StopListening_twice) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StopListening()); + + // call again + EXPECT_EQ(TransportAdapter::BAD_STATE, tcp_client_listener_->StopListening()); + + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); } -TEST_F(TcpClientListenerTest, IsInitialised) { - EXPECT_TRUE(tcp_client_listener_.IsInitialised()); +TEST_P(TcpClientListenerTest, ClientConnection) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + if (InterfaceNameSpecified()) { + // set up a server socket by notifying a dummy IP address + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(_)).Times(1); + tcp_client_listener_->OnIPAddressUpdated(std::string("192.168.1.1"), + std::string("")); + } + + // get the port number (assigned by system) that the socket is listening on + struct sockaddr_in server_addr; + socklen_t server_addr_len = sizeof(server_addr); + EXPECT_EQ(0, + getsockname(tcp_client_listener_->get_socket(), + reinterpret_cast<struct sockaddr*>(&server_addr), + &server_addr_len)); + + // try connecting to the socket + struct sockaddr_in client_addr; + client_addr.sin_family = AF_INET; + client_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + client_addr.sin_port = server_addr.sin_port; + socklen_t client_addr_len = sizeof(client_addr); + + int s = socket(AF_INET, SOCK_STREAM, 0); + EXPECT_TRUE(0 <= s); + + TestAsyncWaiter waiter; + + // controller should be notified of AddDevice event + DeviceSptr mock_device = std::make_shared<MockTCPDevice>( + htonl(INADDR_LOOPBACK), "dummy_tcp_device"); + EXPECT_CALL(adapter_controller_mock_, AddDevice(_)) + .WillOnce(Return(mock_device)); + EXPECT_CALL(adapter_controller_mock_, ConnectionCreated(_, _, _)) + .WillOnce(NotifyTestAsyncWaiter(&waiter)); + + // adapter_controller_mock_ may also receive ConnectDone() and + // ConnectionFinished() from ThreadedSocketConnection. Ignore them as hey are + // not part ly client listener's tests. + EXPECT_CALL(adapter_controller_mock_, ConnectDone(_, _)).Times(AtLeast(0)); + EXPECT_CALL(adapter_controller_mock_, ConnectionFinished(_, _)) + .Times(AtLeast(0)); + + EXPECT_EQ(0, + connect(s, + reinterpret_cast<struct sockaddr*>(&client_addr), + client_addr_len)); + + // since the connection is handled on another thread, wait for some time + EXPECT_TRUE(waiter.WaitFor(1, kConnectionCreatedTimeoutMsec)); + + close(s); + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); } -TEST_F(TcpClientListenerTest, Init) { - EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_.Init()); +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_ValidIPv4Address) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config; + expected_config.insert(std::make_pair(tc_enabled, "true")); + expected_config.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr)); + expected_config.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(expected_config)) + .Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + // when the client listener runs with designated interface name, it should + // start the thread here + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); } +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_changed) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(tc_enabled, "true")); + expected_config_1.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = "172.16.2.3"; + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(tc_enabled, "true")); + expected_config_2.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_2)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_same) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(tc_enabled, "true")); + expected_config_1.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = "192.168.1.1"; // same as before + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(tc_enabled, "true")); + expected_config_2.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(tc_tcp_port, test_port)); + + // client listener should not generate TransportConfigUpdated event + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(_)).Times(0); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_disabled) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(tc_enabled, "true")); + expected_config_1.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = ""; + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(tc_enabled, "false")); + expected_config_2.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_2)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_IPv4Address_reenabled) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr_1 = "192.168.1.1"; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + TransportConfig expected_config_1; + expected_config_1.insert(std::make_pair(tc_enabled, "true")); + expected_config_1.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_1)); + expected_config_1.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_1)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_1, test_ipv6_addr); + + const std::string test_ipv4_addr_2 = ""; + TransportConfig expected_config_2; + expected_config_2.insert(std::make_pair(tc_enabled, "false")); + expected_config_2.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_2)); + expected_config_2.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_2)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_2, test_ipv6_addr); + + const std::string test_ipv4_addr_3 = "192.168.1.1"; + TransportConfig expected_config_3; + expected_config_3.insert(std::make_pair(tc_enabled, "true")); + expected_config_3.insert(std::make_pair(tc_tcp_ip_address, test_ipv4_addr_3)); + expected_config_3.insert(std::make_pair(tc_tcp_port, test_port)); + + EXPECT_CALL(adapter_controller_mock_, + TransportConfigUpdated(expected_config_3)).Times(1); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr_3, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_TRUE(0 <= tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_TRUE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +TEST_P(TcpClientListenerTest, OnIPAddressUpdated_EmptyIPv4Address) { + EXPECT_CALL(*interface_listener_mock_, Init()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->Init()); + EXPECT_CALL(*interface_listener_mock_, Start()).WillOnce(Return(true)); + EXPECT_EQ(TransportAdapter::OK, tcp_client_listener_->StartListening()); + + const std::string test_ipv4_addr = ""; + const std::string test_ipv6_addr = ""; + char buf[16]; + snprintf(buf, sizeof(buf), "%u", port_); + const std::string test_port(buf); + + // if the client listener receives an empty IP address after started, it + // should ignore it + EXPECT_CALL(adapter_controller_mock_, TransportConfigUpdated(_)).Times(0); + + tcp_client_listener_->OnIPAddressUpdated(test_ipv4_addr, test_ipv6_addr); + + if (InterfaceNameSpecified()) { + EXPECT_EQ(-1, tcp_client_listener_->get_socket()); + + SleepFor(kThreadStartWaitMsec); + + EXPECT_FALSE(tcp_client_listener_->thread()->is_running()); + } + + EXPECT_CALL(*interface_listener_mock_, Stop()).WillOnce(Return(true)); + EXPECT_CALL(*interface_listener_mock_, Deinit()).Times(1); +} + +INSTANTIATE_TEST_CASE_P(NetworkInterfaceName, + TcpClientListenerTest, + ::testing::Values(std::string(""), + std::string("dummy_interface0"))); + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/tcp_transport_adapter_test.cc b/src/components/transport_manager/test/tcp_transport_adapter_test.cc index dd587569d3..959180948a 100644 --- a/src/components/transport_manager/test/tcp_transport_adapter_test.cc +++ b/src/components/transport_manager/test/tcp_transport_adapter_test.cc @@ -41,13 +41,12 @@ #include "transport_manager/tcp/mock_tcp_transport_adapter.h" #include "transport_manager/mock_transport_manager_settings.h" -#include "utils/make_shared.h" - namespace test { namespace components { namespace transport_manager_test { using ::testing::Return; +using ::testing::ReturnRef; using ::testing::_; using namespace ::protocol_handler; @@ -61,6 +60,13 @@ class TcpAdapterTest : public ::testing::Test { resumption::LastStateImpl last_state_; const uint32_t port = 12345; const std::string string_port = "12345"; + std::string network_interface = ""; + + void SetUp() OVERRIDE { + EXPECT_CALL(transport_manager_settings, + transport_manager_tcp_adapter_network_interface()) + .WillRepeatedly(ReturnRef(network_interface)); + } }; TEST_F(TcpAdapterTest, StoreDataWithOneDeviceAndOneApplication) { @@ -68,7 +74,8 @@ TEST_F(TcpAdapterTest, StoreDataWithOneDeviceAndOneApplication) { MockTCPTransportAdapter transport_adapter( port, last_state_, transport_manager_settings); std::string uniq_id = "unique_device_name"; - utils::SharedPtr<MockTCPDevice> mockdev = new MockTCPDevice(port, uniq_id); + std::shared_ptr<MockTCPDevice> mockdev = + std::make_shared<MockTCPDevice>(port, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -79,7 +86,7 @@ TEST_F(TcpAdapterTest, StoreDataWithOneDeviceAndOneApplication) { std::vector<int> intList = {app_handle}; EXPECT_CALL(*mockdev, GetApplicationList()).WillOnce(Return(intList)); - ConnectionSPtr mock_connection = new MockConnection(); + ConnectionSPtr mock_connection = std::make_shared<MockConnection>(); EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); EXPECT_CALL(transport_adapter, FindEstablishedConnection(uniq_id, app_handle)) .WillOnce(Return(mock_connection)); @@ -107,13 +114,13 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevicesAndOneApplication) { MockTCPTransportAdapter transport_adapter( port, last_state_, transport_manager_settings); const uint32_t count_dev = 10; - utils::SharedPtr<MockTCPDevice> mockdev[count_dev]; + std::shared_ptr<MockTCPDevice> mockdev[count_dev]; std::string uniq_id[count_dev]; for (uint32_t i = 0; i < count_dev; i++) { char numb[12]; std::snprintf(numb, 12, "%d", i); uniq_id[i] = "unique_device_name" + std::string(numb); - mockdev[i] = new MockTCPDevice(port, uniq_id[i]); + mockdev[i] = std::make_shared<MockTCPDevice>(port, uniq_id[i]); EXPECT_CALL(*(mockdev[i]), IsSameAs(_)).WillRepeatedly(Return(false)); transport_adapter.AddDevice(mockdev[i]); } @@ -125,7 +132,7 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevicesAndOneApplication) { const int app_handle = 1; std::vector<int> intList = {app_handle}; - ConnectionSPtr mock_connection = new MockConnection(); + ConnectionSPtr mock_connection = std::make_shared<MockConnection>(); for (uint32_t i = 0; i < count_dev; i++) { EXPECT_CALL(transport_adapter, FindDevice(uniq_id[i])) .WillOnce(Return(mockdev[i])); @@ -162,13 +169,13 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevicesAndSeveralApplications) { port, last_state_, transport_manager_settings); const uint32_t count_dev = 10; - utils::SharedPtr<MockTCPDevice> mockdev[count_dev]; + std::shared_ptr<MockTCPDevice> mockdev[count_dev]; std::string uniq_id[count_dev]; for (uint32_t i = 0; i < count_dev; i++) { char numb[12]; std::snprintf(numb, 12, "%d", i); uniq_id[i] = "unique_device_name" + std::string(numb); - mockdev[i] = new MockTCPDevice(port, uniq_id[i]); + mockdev[i] = std::make_shared<MockTCPDevice>(port, uniq_id[i]); EXPECT_CALL(*(mockdev[i]), IsSameAs(_)).WillRepeatedly(Return(false)); transport_adapter.AddDevice(mockdev[i]); } @@ -182,7 +189,7 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevicesAndSeveralApplications) { std::vector<int> intList = {app_handle[0], app_handle[1], app_handle[2]}; const std::string ports[connection_count] = {"11111", "67890", "98765"}; const int int_port[connection_count] = {11111, 67890, 98765}; - ConnectionSPtr mock_connection = new MockConnection(); + ConnectionSPtr mock_connection = std::make_shared<MockConnection>(); for (uint32_t i = 0; i < count_dev; i++) { EXPECT_CALL(transport_adapter, FindDevice(uniq_id[i])) .WillOnce(Return(mockdev[i])); @@ -220,7 +227,7 @@ TEST_F(TcpAdapterTest, StoreData_ConnectionNotExist_DataNotStored) { MockTCPTransportAdapter transport_adapter( port, last_state_, transport_manager_settings); std::string uniq_id = "unique_device_name"; - utils::SharedPtr<MockTCPDevice> mockdev = new MockTCPDevice(port, uniq_id); + auto mockdev = std::make_shared<MockTCPDevice>(port, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -257,7 +264,8 @@ TEST_F(TcpAdapterTest, StoreDataWithOneDevice_RestoreData) { MockTCPTransportAdapter transport_adapter( port, last_state_, transport_manager_settings); std::string uniq_id = "unique_device_name"; - utils::SharedPtr<MockTCPDevice> mockdev = new MockTCPDevice(port, uniq_id); + std::shared_ptr<MockTCPDevice> mockdev = + std::make_shared<MockTCPDevice>(port, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -268,7 +276,7 @@ TEST_F(TcpAdapterTest, StoreDataWithOneDevice_RestoreData) { std::vector<int> intList = {app_handle}; EXPECT_CALL(*mockdev, GetApplicationList()).WillOnce(Return(intList)); - ConnectionSPtr mock_connection = new MockConnection(); + ConnectionSPtr mock_connection = std::make_shared<MockConnection>(); EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); EXPECT_CALL(transport_adapter, FindEstablishedConnection(uniq_id, app_handle)) .WillOnce(Return(mock_connection)); @@ -292,13 +300,13 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevices_RestoreData) { port, last_state_, transport_manager_settings); const uint32_t count_dev = 10; - utils::SharedPtr<MockTCPDevice> mockdev[count_dev]; + std::shared_ptr<MockTCPDevice> mockdev[count_dev]; std::string uniq_id[count_dev]; for (uint32_t i = 0; i < count_dev; i++) { char numb[12]; std::snprintf(numb, 12, "%d", i); uniq_id[i] = "unique_device_name" + std::string(numb); - mockdev[i] = new MockTCPDevice(port, uniq_id[i]); + mockdev[i] = std::make_shared<MockTCPDevice>(port, uniq_id[i]); EXPECT_CALL(*(mockdev[i]), IsSameAs(_)).WillRepeatedly(Return(false)); transport_adapter.AddDevice(mockdev[i]); } @@ -310,7 +318,7 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevices_RestoreData) { const int app_handle = 1; std::vector<int> intList = {app_handle}; - ConnectionSPtr mock_connection = new MockConnection(); + ConnectionSPtr mock_connection = std::make_shared<MockConnection>(); for (uint32_t i = 0; i < count_dev; i++) { EXPECT_CALL(transport_adapter, FindDevice(uniq_id[i])) .WillOnce(Return(mockdev[i])); @@ -339,6 +347,37 @@ TEST_F(TcpAdapterTest, StoreDataWithSeveralDevices_RestoreData) { } } +TEST_F(TcpAdapterTest, NotifyTransportConfigUpdated) { + MockTransportAdapterListener mock_adapter_listener; + + MockTCPTransportAdapter transport_adapter( + port, last_state_, transport_manager_settings); + transport_adapter.AddListener(&mock_adapter_listener); + + TransportConfig config; + config[tc_enabled] = std::string("true"); + config[tc_tcp_ip_address] = std::string("192.168.1.1"); + config[tc_tcp_port] = std::string("12345"); + + EXPECT_CALL(mock_adapter_listener, OnTransportConfigUpdated(_)).Times(1); + + transport_adapter.TransportConfigUpdated(config); +} + +TEST_F(TcpAdapterTest, GetTransportConfiguration) { + MockTCPTransportAdapter transport_adapter( + port, last_state_, transport_manager_settings); + + TransportConfig config; + config[tc_enabled] = std::string("true"); + config[tc_tcp_ip_address] = std::string("192.168.1.1"); + config[tc_tcp_port] = std::string("12345"); + + transport_adapter.TransportConfigUpdated(config); + + EXPECT_EQ(config, transport_adapter.GetTransportConfiguration()); +} + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/transport_adapter_listener_test.cc b/src/components/transport_manager/test/transport_adapter_listener_test.cc index 14b8850b49..a5d08035ae 100644 --- a/src/components/transport_manager/test/transport_adapter_listener_test.cc +++ b/src/components/transport_manager/test/transport_adapter_listener_test.cc @@ -129,7 +129,7 @@ TEST_F(TransportAdapterListenerTest, OnDataReceiveFailed) { TEST_F(TransportAdapterListenerTest, OnDataSendDone) { unsigned char data[3] = {0x20, 0x07, 0x01}; ::protocol_handler::RawMessagePtr data_container = - new ::protocol_handler::RawMessage(1, 1, data, 3); + std::make_shared< ::protocol_handler::RawMessage>(1, 1, data, 3); EXPECT_CALL(tr_mock, ReceiveEventFromDevice(IsEvent(EventTypeEnum::ON_SEND_DONE, @@ -145,7 +145,7 @@ TEST_F(TransportAdapterListenerTest, OnDataSendDone) { TEST_F(TransportAdapterListenerTest, OnDataSendFailed) { unsigned char data[3] = {0x20, 0x07, 0x01}; ::protocol_handler::RawMessagePtr data_container = - new ::protocol_handler::RawMessage(1, 1, data, 3); + std::make_shared< ::protocol_handler::RawMessage>(1, 1, data, 3); DataSendError err; EXPECT_CALL(tr_mock, @@ -230,6 +230,15 @@ TEST_F(TransportAdapterListenerTest, OnUnexpectedDisconnect) { &adapter_mock, dev_id, app_handle, err); } +TEST_F(TransportAdapterListenerTest, OnTransportConfigUpdated) { + EXPECT_CALL( + tr_mock, + ReceiveEventFromDevice(IsEvent( + EventTypeEnum::ON_TRANSPORT_CONFIG_UPDATED, &adapter_mock, "", 0))) + .WillOnce(Return(E_SUCCESS)); + transport_listener.OnTransportConfigUpdated(&adapter_mock); +} + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/transport_adapter_test.cc b/src/components/transport_manager/test/transport_adapter_test.cc index 6d709e0c17..9e602332c6 100644 --- a/src/components/transport_manager/test/transport_adapter_test.cc +++ b/src/components/transport_manager/test/transport_adapter_test.cc @@ -45,7 +45,7 @@ #include "transport_manager/transport_adapter/transport_adapter_controller.h" #include "transport_manager/transport_adapter/connection.h" #include "protocol/raw_message.h" -#include "utils/make_shared.h" + #include "resumption/last_state_impl.h" #include "config_profile/profile.h" @@ -156,10 +156,10 @@ TEST_F(TransportAdapterTest, SearchDeviceDone_DeviceExisting) { EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); - utils::SharedPtr<MockDevice> mockdev = new MockDevice(dev_id, uniq_id); + auto mockdev = std::make_shared<MockDevice>(dev_id, uniq_id); transport_adapter.AddDevice(mockdev); - std::vector<utils::SharedPtr<Device> > devList; + std::vector<std::shared_ptr<Device> > devList; devList.push_back(mockdev); EXPECT_CALL(*mockdev, IsSameAs(_)).WillOnce(Return(true)); @@ -189,8 +189,8 @@ TEST_F(TransportAdapterTest, AddDevice) { MockTransportAdapterListener mock_listener; transport_adapter.AddListener(&mock_listener); - utils::SharedPtr<MockDevice> mockdev = - utils::MakeShared<MockDevice>(dev_id, uniq_id); + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); EXPECT_CALL(mock_listener, OnDeviceListUpdated(&transport_adapter)); transport_adapter.AddDevice(mockdev); @@ -277,8 +277,8 @@ TEST_F(TransportAdapterTest, ConnectDevice_ServerNotAdded_DeviceAdded) { EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); - utils::SharedPtr<MockDevice> mockdev = - utils::MakeShared<MockDevice>(dev_id, uniq_id); + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -307,7 +307,7 @@ TEST_F(TransportAdapterTest, ConnectDevice_DeviceNotAdded) { EXPECT_CALL(*serverMock, IsInitialised()).Times(0); EXPECT_CALL(*serverMock, CreateConnection(_, _)).Times(0); EXPECT_CALL(transport_adapter, FindDevice(uniq_id)) - .WillOnce(Return(utils::SharedPtr<MockDevice>())); + .WillOnce(Return(std::shared_ptr<MockDevice>())); TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::BAD_PARAM, res); @@ -323,8 +323,8 @@ TEST_F(TransportAdapterTest, ConnectDevice_DeviceAdded) { EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); - utils::SharedPtr<MockDevice> mockdev = - utils::MakeShared<MockDevice>(dev_id, uniq_id); + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -354,8 +354,8 @@ TEST_F(TransportAdapterTest, ConnectDevice_DeviceAddedTwice) { EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); - utils::SharedPtr<MockDevice> mockdev = - utils::MakeShared<MockDevice>(dev_id, uniq_id); + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -401,7 +401,7 @@ TEST_F(TransportAdapterTest, Disconnect_ConnectDoneSuccess) { TransportAdapter::Error res = transport_adapter.Connect(dev_id, app_handle); EXPECT_EQ(TransportAdapter::OK, res); - MockConnection* mock_connection = new MockConnection(); + auto mock_connection = std::make_shared<MockConnection>(); transport_adapter.ConnectionCreated(mock_connection, dev_id, app_handle); EXPECT_CALL(transport_adapter, Store()); @@ -425,8 +425,8 @@ TEST_F(TransportAdapterTest, DisconnectDevice_DeviceAddedConnectionCreated) { EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); - utils::SharedPtr<MockDevice> mockdev = - utils::MakeShared<MockDevice>(dev_id, uniq_id); + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -443,7 +443,7 @@ TEST_F(TransportAdapterTest, DisconnectDevice_DeviceAddedConnectionCreated) { TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, res); - MockConnection* mock_connection = new MockConnection(); + auto mock_connection = std::make_shared<MockConnection>(); transport_adapter.ConnectionCreated(mock_connection, uniq_id, app_handle); EXPECT_CALL(*mock_connection, Disconnect()) @@ -467,8 +467,8 @@ TEST_F(TransportAdapterTest, DeviceDisconnected) { MockTransportAdapterListener mock_listener; transport_adapter.AddListener(&mock_listener); - utils::SharedPtr<MockDevice> mockdev = - utils::MakeShared<MockDevice>(dev_id, uniq_id); + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); EXPECT_CALL(mock_listener, OnDeviceListUpdated(&transport_adapter)); transport_adapter.AddDevice(mockdev); @@ -485,8 +485,8 @@ TEST_F(TransportAdapterTest, DeviceDisconnected) { TransportAdapter::Error res = transport_adapter.ConnectDevice(uniq_id); EXPECT_EQ(TransportAdapter::OK, res); - utils::SharedPtr<MockConnection> mock_connection = - utils::MakeShared<MockConnection>(); + std::shared_ptr<MockConnection> mock_connection = + std::make_shared<MockConnection>(); transport_adapter.ConnectionCreated(mock_connection, uniq_id, app_handle); EXPECT_CALL(mock_listener, OnDeviceListUpdated(&transport_adapter)); @@ -545,7 +545,7 @@ TEST_F(TransportAdapterTest, SendData) { TransportAdapter::Error res = transport_adapter.Connect(dev_id, app_handle); EXPECT_EQ(TransportAdapter::OK, res); - MockConnection* mock_connection = new MockConnection(); + auto mock_connection = std::make_shared<MockConnection>(); transport_adapter.ConnectionCreated(mock_connection, dev_id, app_handle); EXPECT_CALL(transport_adapter, Store()); @@ -553,7 +553,8 @@ TEST_F(TransportAdapterTest, SendData) { const unsigned int kSize = 3; unsigned char data[kSize] = {0x20, 0x07, 0x01}; - const RawMessagePtr kMessage = new RawMessage(1, 1, data, kSize); + const RawMessagePtr kMessage = + std::make_shared<RawMessage>(1, 1, data, kSize); EXPECT_CALL(*mock_connection, SendData(kMessage)) .WillOnce(Return(TransportAdapter::OK)); @@ -586,12 +587,13 @@ TEST_F(TransportAdapterTest, SendData_ConnectionNotEstablished) { TransportAdapter::Error res = transport_adapter.Connect(dev_id, app_handle); EXPECT_EQ(TransportAdapter::OK, res); - MockConnection* mock_connection = new MockConnection(); + auto mock_connection = std::make_shared<MockConnection>(); transport_adapter.ConnectionCreated(mock_connection, dev_id, app_handle); const unsigned int kSize = 3; unsigned char data[kSize] = {0x20, 0x07, 0x01}; - const RawMessagePtr kMessage = new RawMessage(1, 1, data, kSize); + const RawMessagePtr kMessage = + std::make_shared<RawMessage>(1, 1, data, kSize); EXPECT_CALL(*mock_connection, SendData(kMessage)).Times(0); res = transport_adapter.SendData(dev_id, app_handle, kMessage); @@ -712,8 +714,8 @@ TEST_F(TransportAdapterTest, GetDeviceAndApplicationLists) { EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); - utils::SharedPtr<MockDevice> mockdev = - utils::MakeShared<MockDevice>(dev_id, uniq_id); + std::shared_ptr<MockDevice> mockdev = + std::make_shared<MockDevice>(dev_id, uniq_id); transport_adapter.AddDevice(mockdev); std::vector<std::string> devList = transport_adapter.GetDeviceList(); @@ -744,7 +746,7 @@ TEST_F(TransportAdapterTest, FindEstablishedConnection) { TransportAdapter::Error res = transport_adapter.Connect(dev_id, app_handle); EXPECT_EQ(TransportAdapter::OK, res); - ConnectionSPtr mock_connection = new MockConnection(); + ConnectionSPtr mock_connection = std::make_shared<MockConnection>(); transport_adapter.ConnectionCreated(mock_connection, dev_id, app_handle); EXPECT_CALL(transport_adapter, Store()); @@ -763,14 +765,14 @@ TEST_F(TransportAdapterTest, RunAppOnDevice_NoDeviseWithAskedId_UNSUCCESS) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); - utils::SharedPtr<MockDevice> mock_device = - utils::MakeShared<MockDevice>("test_device_name", "test_device_uid0"); + std::shared_ptr<MockDevice> mock_device = + std::make_shared<MockDevice>("test_device_name", "test_device_uid0"); transport_adapter.AddDevice(mock_device); EXPECT_CALL(*mock_device, LaunchApp(bundle_id)).Times(0); EXPECT_CALL(transport_adapter, FindDevice("test_device_uid1")) - .WillOnce(Return(utils::SharedPtr<MockDevice>())); + .WillOnce(Return(std::shared_ptr<MockDevice>())); transport_adapter.RunAppOnDevice("test_device_uid1", bundle_id); } @@ -782,8 +784,8 @@ TEST_F(TransportAdapterTest, RunAppOnDevice_DeviseWithAskedIdWasFound_SUCCESS) { MockTransportAdapterImpl transport_adapter( NULL, NULL, NULL, last_state_, transport_manager_settings); - utils::SharedPtr<MockDevice> mock_device = - utils::MakeShared<MockDevice>("test_device_name", device_uid); + std::shared_ptr<MockDevice> mock_device = + std::make_shared<MockDevice>("test_device_name", device_uid); transport_adapter.AddDevice(mock_device); @@ -800,7 +802,7 @@ TEST_F(TransportAdapterTest, StopDevice) { EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); transport_adapter.Init(); - auto mockdev = utils::MakeShared<MockDevice>(dev_id, uniq_id); + auto mockdev = std::make_shared<MockDevice>(dev_id, uniq_id); transport_adapter.AddDevice(mockdev); EXPECT_CALL(transport_adapter, FindDevice(uniq_id)).WillOnce(Return(mockdev)); @@ -809,6 +811,35 @@ TEST_F(TransportAdapterTest, StopDevice) { transport_adapter.StopDevice(uniq_id); } +TEST_F(TransportAdapterTest, TransportConfigUpdated) { + MockTransportAdapterImpl transport_adapter( + NULL, NULL, NULL, last_state_, transport_manager_settings); + EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); + transport_adapter.Init(); + + MockTransportAdapterListener mock_listener; + transport_adapter.AddListener(&mock_listener); + + TransportConfig config; + config[tc_enabled] = std::string("true"); + config[tc_tcp_ip_address] = std::string("192.168.1.1"); + config[tc_tcp_port] = std::string("12345"); + + EXPECT_CALL(mock_listener, OnTransportConfigUpdated(_)); + transport_adapter.TransportConfigUpdated(config); +} + +TEST_F(TransportAdapterTest, GetTransportConfigration) { + MockTransportAdapterImpl transport_adapter( + NULL, NULL, NULL, last_state_, transport_manager_settings); + EXPECT_CALL(transport_adapter, Restore()).WillOnce(Return(true)); + transport_adapter.Init(); + + TransportConfig empty_config; + + EXPECT_EQ(empty_config, transport_adapter.GetTransportConfiguration()); +} + } // namespace transport_manager_test } // namespace components } // namespace test diff --git a/src/components/transport_manager/test/transport_manager_default_test.cc b/src/components/transport_manager/test/transport_manager_default_test.cc index d095a51cb6..8e8a964228 100644 --- a/src/components/transport_manager/test/transport_manager_default_test.cc +++ b/src/components/transport_manager/test/transport_manager_default_test.cc @@ -74,6 +74,10 @@ TEST(TestTransportManagerDefault, Init_LastStateNotUsed) { .WillRepeatedly(Return(false)); EXPECT_CALL(transport_manager_settings, transport_manager_tcp_adapter_port()) .WillRepeatedly(Return(12345u)); + std::string network_interface = ""; + EXPECT_CALL(transport_manager_settings, + transport_manager_tcp_adapter_network_interface()) + .WillRepeatedly(ReturnRef(network_interface)); transport_manager.Init(mock_last_state); transport_manager.Stop(); @@ -106,6 +110,10 @@ TEST(TestTransportManagerDefault, Init_LastStateUsed) { .WillRepeatedly(Return(true)); EXPECT_CALL(transport_manager_settings, transport_manager_tcp_adapter_port()) .WillRepeatedly(Return(12345u)); + std::string network_interface = ""; + EXPECT_CALL(transport_manager_settings, + transport_manager_tcp_adapter_network_interface()) + .WillRepeatedly(ReturnRef(network_interface)); transport_manager.Init(mock_last_state); transport_manager.Stop(); } @@ -137,6 +145,10 @@ TEST(TestTransportManagerDefault, Init_LastStateUsed_InvalidPort) { .WillRepeatedly(Return(true)); EXPECT_CALL(transport_manager_settings, transport_manager_tcp_adapter_port()) .WillRepeatedly(Return(1u)); + std::string network_interface = ""; + EXPECT_CALL(transport_manager_settings, + transport_manager_tcp_adapter_network_interface()) + .WillRepeatedly(ReturnRef(network_interface)); transport_manager.Init(mock_last_state); transport_manager.Stop(); } diff --git a/src/components/transport_manager/test/transport_manager_impl_test.cc b/src/components/transport_manager/test/transport_manager_impl_test.cc index eebb247908..5f13adcd44 100644 --- a/src/components/transport_manager/test/transport_manager_impl_test.cc +++ b/src/components/transport_manager/test/transport_manager_impl_test.cc @@ -42,8 +42,7 @@ #include "transport_manager/mock_transport_manager_impl.h" #include "transport_manager/mock_transport_manager_settings.h" #include "resumption/last_state_impl.h" -#include "utils/shared_ptr.h" -#include "utils/make_shared.h" + #include "utils/test_async_waiter.h" using ::testing::_; @@ -55,7 +54,7 @@ using ::testing::DoAll; using ::protocol_handler::RawMessage; using ::protocol_handler::RawMessagePtr; -using utils::MakeShared; +using std::make_shared; namespace test { namespace components { @@ -85,7 +84,7 @@ class TransportManagerImplTest : public ::testing::Test { "app_info_storage"); tm_.Init(last_state_); mock_adapter_ = new MockTransportAdapter(); - tm_listener_ = MakeShared<MockTransportManagerListener>(); + tm_listener_ = std::make_shared<MockTransportManagerListener>(); #ifdef TELEMETRY_MONITOR tm_.SetTelemetryObserver(&mock_metric_observer_); @@ -96,14 +95,14 @@ class TransportManagerImplTest : public ::testing::Test { EXPECT_EQ(E_SUCCESS, tm_.AddTransportAdapter(mock_adapter_)); connection_key_ = 1; - error_ = MakeShared<BaseError>(); + error_ = std::make_shared<BaseError>(); const unsigned int version_protocol_ = 1; const unsigned int kSize = 12; unsigned char data[kSize] = { 0x20, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - test_message_ = - MakeShared<RawMessage>(connection_key_, version_protocol_, data, kSize); + test_message_ = std::make_shared<RawMessage>( + connection_key_, version_protocol_, data, kSize); } DeviceInfo ConstructDeviceInfo(const std::string& mac_address, @@ -331,7 +330,7 @@ class TransportManagerImplTest : public ::testing::Test { #endif // TELEMETRY_MONITOR MockTransportAdapter* mock_adapter_; - utils::SharedPtr<MockTransportManagerListener> tm_listener_; + std::shared_ptr<MockTransportManagerListener> tm_listener_; MockTransportManagerImpl tm_; const ApplicationHandle application_id_ = 1; ConnectionUID connection_key_; @@ -1144,7 +1143,7 @@ TEST_F(TransportManagerImplTest, test_message_, error_)); - auto second_mock_adapter = utils::MakeShared<MockTransportAdapter>(); + auto second_mock_adapter = std::make_shared<MockTransportAdapter>(); const auto usb_serial = "USB_serial"; DeviceInfo second_device = @@ -1220,7 +1219,7 @@ TEST_F(TransportManagerImplTest, test_message_, error_)); - auto second_mock_adapter = utils::MakeShared<MockTransportAdapter>(); + auto second_mock_adapter = std::make_shared<MockTransportAdapter>(); DeviceInfo second_device = ConstructDeviceInfo("MA:CA:DR:ES:S", "USB_IOS", "SecondDeviceName"); @@ -1323,6 +1322,29 @@ TEST_F(TransportManagerImplTest, tm_.OnDeviceListUpdated(mock_adapter_); } +TEST_F(TransportManagerImplTest, OnTransportConfigUpdated) { + TransportAdapterEvent test_event(EventTypeEnum::ON_TRANSPORT_CONFIG_UPDATED, + mock_adapter_, + "", + 0, + test_message_, + error_); + + transport_adapter::TransportConfig config; + config[transport_manager::transport_adapter::tc_enabled] = + std::string("true"); + config[transport_manager::transport_adapter::tc_tcp_ip_address] = + std::string("192.168.1.1"); + config[transport_manager::transport_adapter::tc_tcp_port] = + std::string("12345"); + + EXPECT_CALL(*mock_adapter_, GetTransportConfiguration()) + .WillOnce(Return(config)); + + EXPECT_CALL(*tm_listener_, OnTransportConfigUpdated(config)); + tm_.TestHandle(test_event); +} + } // namespace transport_manager_test } // namespace components } // namespace test |