diff options
Diffstat (limited to 'src')
10 files changed, 1166 insertions, 702 deletions
diff --git a/src/components/transport_manager/CMakeLists.txt b/src/components/transport_manager/CMakeLists.txt index 4fa224393d..aa56aa810b 100644 --- a/src/components/transport_manager/CMakeLists.txt +++ b/src/components/transport_manager/CMakeLists.txt @@ -43,60 +43,85 @@ include_directories ( ${LOG4CXX_INCLUDE_DIRECTORY} ) -set(PATHS - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${CMAKE_CURRENT_SOURCE_DIR}/src -) - -set(EXCLUDE_PATHS) +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(LIBRARIES ProtocolLibrary Utils ) +set(SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/transport_manager_default.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/transport_manager_impl.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/network_interface_listener_impl.cc + + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/tcp_client_listener.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/tcp_connection_factory.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/tcp_device.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/tcp_server_originated_socket_connection.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/tcp_socket_connection.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/tcp_transport_adapter.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/tcp_transport_adapter.cc + + ${CMAKE_CURRENT_SOURCE_DIR}/src/transport_adapter/threaded_socket_connection.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/transport_adapter/transport_adapter_impl.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/transport_adapter/transport_adapter_listener_impl.cc + + ${CMAKE_CURRENT_SOURCE_DIR}/src/iap2_emulation/iap2_transport_adapter.cc + +) + +if (CMAKE_SYSTEM_NAME STREQUAL "QNX") + list(APPEND SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/platform_specific/qnx/platform_specific_network_interface_listener.cc + ) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/tcp/platform_specific/linux/platform_specific_network_interface_listener.cc + ) +endif () + if(BUILD_BT_SUPPORT) list(APPEND LIBRARIES bluetooth ) -else() - list(APPEND EXCLUDE_PATHS - ${COMPONENTS_DIR}/transport_manager/include/transport_manager/bluetooth - ${COMPONENTS_DIR}/transport_manager/src/bluetooth + list(APPEND SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/bluetooth/bluetooth_connection_factory.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/bluetooth/bluetooth_device.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/bluetooth/bluetooth_device_scanner.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/bluetooth/bluetooth_socket_connection.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/bluetooth/bluetooth_transport_adapter.cc ) endif() if(BUILD_USB_SUPPORT) + list(APPEND SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/usb_aoa_adapter.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/usb_connection_factory.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/usb_device_scanner.cc + ) if (CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(EXCLUDE_PATHS - ${COMPONENTS_DIR}/transport_manager/include/transport_manager/usb/qnx - ${COMPONENTS_DIR}/transport_manager/src/usb/qnx + list(APPEND SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/libusb/platform_usb_device.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/libusb/usb_connection.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/libusb/usb_handler.cc ) - elseif(CMAKE_SYSTEM_NAME STREQUAL "QNX") - set(EXCLUDE_PATHS - ${COMPONENTS_DIR}/transport_manager/include/transport_manager/usb/libusb - ${COMPONENTS_DIR}/transport_manager/src/usb/libusb - ) list(APPEND LIBRARIES usbdi ) + list(APPEND SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/qnx/platform_usb_device.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/qnx/usb_connection.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb/qnx/usb_handler.cc + ) endif() -else() - list(APPEND EXCLUDE_PATHS - ${COMPONENTS_DIR}/transport_manager/include/transport_manager/usb - ${COMPONENTS_DIR}/transport_manager/src/usb - ) -endif() - -if(NOT BUILD_TESTS) - list (APPEND EXCLUDE_PATH - ${CMAKE_CURRENT_SOURCE_DIR}/include/iap2_emulation/iap2_transport_adapter.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/iap2_emulation/iap2_transport_adapter.cc - ) endif() -collect_sources(SOURCES "${PATHS}" "${EXCLUDE_PATHS}") add_library("TransportManager" ${SOURCES}) target_link_libraries("TransportManager" ${LIBRARIES}) 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 index 6a9cf46762..11a9be05ed 100644 --- 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 @@ -33,17 +33,11 @@ #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 <map> #include <string> -#include <vector> +#include <memory> -#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; +#include "transport_manager/tcp/network_interface_listener.h" namespace transport_manager { namespace transport_adapter { @@ -51,43 +45,6 @@ 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) {} - ~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 NetworkInterfaceListenerImpl : public NetworkInterfaceListener { @@ -101,7 +58,7 @@ class NetworkInterfaceListenerImpl : public NetworkInterfaceListener { * network interface, specify its name */ NetworkInterfaceListenerImpl(TcpClientListener* tcp_client_listener, - const std::string designated_interface = ""); + const std::string designated_interface); /** * @brief Destructor @@ -128,96 +85,8 @@ class NetworkInterfaceListenerImpl : public NetworkInterfaceListener { */ 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) {} - }; - - // 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(NetworkInterfaceListenerImpl* parent); - virtual void threadMain(); - void exitThreadMain(); - - private: - NetworkInterfaceListenerImpl* parent_; - }; - - DISALLOW_COPY_AND_ASSIGN(NetworkInterfaceListenerImpl); + std::unique_ptr<NetworkInterfaceListener> platform_specific_impl_; }; } // namespace transport_adapter 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..8a2279003a --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/tcp/platform_specific/linux/platform_specific_network_interface_listener_impl.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#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) {} + ~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) {} + }; + + // 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..c5982853dc --- /dev/null +++ b/src/components/transport_manager/include/transport_manager/tcp/platform_specific/qnx/platform_specific_network_interface_listener_impl.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#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/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..e362ee8a73 --- /dev/null +++ b/src/components/transport_manager/src/tcp/network_interface_listener_impl.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#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/network_interface_listener_impl.cpp b/src/components/transport_manager/src/tcp/platform_specific/linux/platform_specific_network_interface_listener.cc index bcf5e21387..4669edd7b4 100644 --- a/src/components/transport_manager/src/tcp/network_interface_listener_impl.cpp +++ b/src/components/transport_manager/src/tcp/platform_specific/linux/platform_specific_network_interface_listener.cc @@ -30,7 +30,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "transport_manager/tcp/network_interface_listener_impl.h" +#include "transport_manager/tcp/platform_specific/linux/platform_specific_network_interface_listener_impl.h" #include <arpa/inet.h> #include <asm/types.h> @@ -42,10 +42,9 @@ #include <sys/types.h> #include <sys/select.h> #include <sys/socket.h> -#ifdef __linux__ + #include <linux/netlink.h> #include <linux/rtnetlink.h> -#endif // __linux__ #include "transport_manager/tcp/tcp_client_listener.h" #include "utils/logger.h" @@ -106,9 +105,10 @@ void InterfaceStatus::SetIPv6Address(struct in6_addr* addr) { } } -NetworkInterfaceListenerImpl::NetworkInterfaceListenerImpl( - TcpClientListener* tcp_client_listener, - const std::string designated_interface) +PlatformSpecificNetworkInterfaceListener:: + PlatformSpecificNetworkInterfaceListener( + TcpClientListener* tcp_client_listener, + const std::string designated_interface) : tcp_client_listener_(tcp_client_listener) , designated_interface_(designated_interface) , selected_interface_("") @@ -120,11 +120,12 @@ NetworkInterfaceListenerImpl::NetworkInterfaceListenerImpl( #endif // BUILD_TESTS { pipe_fds_[0] = pipe_fds_[1] = -1; - thread_ = threads::CreateThread("NetworkInterfaceListenerImpl", + thread_ = threads::CreateThread("PlatformSpecificNetworkInterfaceListener", new ListenerThreadDelegate(this)); } -NetworkInterfaceListenerImpl::~NetworkInterfaceListenerImpl() { +PlatformSpecificNetworkInterfaceListener:: + ~PlatformSpecificNetworkInterfaceListener() { LOG4CXX_AUTO_TRACE(logger_); Stop(); @@ -134,7 +135,7 @@ NetworkInterfaceListenerImpl::~NetworkInterfaceListenerImpl() { threads::DeleteThread(thread_); } -bool NetworkInterfaceListenerImpl::Init() { +bool PlatformSpecificNetworkInterfaceListener::Init() { LOG4CXX_AUTO_TRACE(logger_); if (socket_ >= 0) { @@ -180,7 +181,7 @@ bool NetworkInterfaceListenerImpl::Init() { return true; } -void NetworkInterfaceListenerImpl::Deinit() { +void PlatformSpecificNetworkInterfaceListener::Deinit() { LOG4CXX_AUTO_TRACE(logger_); if (socket_ >= 0) { @@ -197,7 +198,7 @@ void NetworkInterfaceListenerImpl::Deinit() { } } -bool NetworkInterfaceListenerImpl::Start() { +bool PlatformSpecificNetworkInterfaceListener::Start() { LOG4CXX_AUTO_TRACE(logger_); if (socket_ < 0) { @@ -219,7 +220,7 @@ bool NetworkInterfaceListenerImpl::Start() { return true; } -bool NetworkInterfaceListenerImpl::Stop() { +bool PlatformSpecificNetworkInterfaceListener::Stop() { LOG4CXX_AUTO_TRACE(logger_); if (!thread_->is_running()) { @@ -233,7 +234,7 @@ bool NetworkInterfaceListenerImpl::Stop() { return true; } -void NetworkInterfaceListenerImpl::Loop() { +void PlatformSpecificNetworkInterfaceListener::Loop() { LOG4CXX_AUTO_TRACE(logger_); InitializeStatus(); @@ -337,7 +338,7 @@ void NetworkInterfaceListenerImpl::Loop() { } } -bool NetworkInterfaceListenerImpl::StopLoop() { +bool PlatformSpecificNetworkInterfaceListener::StopLoop() { LOG4CXX_AUTO_TRACE(logger_); LOG4CXX_INFO(logger_, "Stopping network interface listener"); @@ -358,7 +359,7 @@ bool NetworkInterfaceListenerImpl::StopLoop() { return true; } -bool NetworkInterfaceListenerImpl::InitializeStatus() { +bool PlatformSpecificNetworkInterfaceListener::InitializeStatus() { LOG4CXX_AUTO_TRACE(logger_); #ifdef BUILD_TESTS @@ -417,7 +418,7 @@ bool NetworkInterfaceListenerImpl::InitializeStatus() { return true; } -bool NetworkInterfaceListenerImpl::UpdateStatus( +bool PlatformSpecificNetworkInterfaceListener::UpdateStatus( uint16_t type, std::vector<EventParam>& params) { LOG4CXX_AUTO_TRACE(logger_); @@ -486,7 +487,7 @@ bool NetworkInterfaceListenerImpl::UpdateStatus( return true; } -void NetworkInterfaceListenerImpl::NotifyIPAddresses() { +void PlatformSpecificNetworkInterfaceListener::NotifyIPAddresses() { LOG4CXX_AUTO_TRACE(logger_); std::string ipv4_addr; @@ -519,7 +520,7 @@ void NetworkInterfaceListenerImpl::NotifyIPAddresses() { } } -const std::string NetworkInterfaceListenerImpl::SelectInterface() { +const std::string PlatformSpecificNetworkInterfaceListener::SelectInterface() { LOG4CXX_AUTO_TRACE(logger_); if (!designated_interface_.empty()) { @@ -562,9 +563,9 @@ const std::string NetworkInterfaceListenerImpl::SelectInterface() { return selected_interface_; } -std::vector<NetworkInterfaceListenerImpl::EventParam> -NetworkInterfaceListenerImpl::ParseIFAddrMessage(struct ifaddrmsg* message, - unsigned int size) { +std::vector<PlatformSpecificNetworkInterfaceListener::EventParam> +PlatformSpecificNetworkInterfaceListener::ParseIFAddrMessage( + struct ifaddrmsg* message, unsigned int size) { LOG4CXX_AUTO_TRACE(logger_); std::vector<EventParam> params; @@ -619,7 +620,7 @@ NetworkInterfaceListenerImpl::ParseIFAddrMessage(struct ifaddrmsg* message, return params; } -void NetworkInterfaceListenerImpl::DumpTable() const { +void PlatformSpecificNetworkInterfaceListener::DumpTable() const { LOG4CXX_DEBUG(logger_, "Number of network interfaces: " << status_table_.size()); @@ -637,15 +638,17 @@ void NetworkInterfaceListenerImpl::DumpTable() const { } } -NetworkInterfaceListenerImpl::ListenerThreadDelegate::ListenerThreadDelegate( - NetworkInterfaceListenerImpl* parent) +PlatformSpecificNetworkInterfaceListener::ListenerThreadDelegate:: + ListenerThreadDelegate(PlatformSpecificNetworkInterfaceListener* parent) : parent_(parent) {} -void NetworkInterfaceListenerImpl::ListenerThreadDelegate::threadMain() { +void PlatformSpecificNetworkInterfaceListener::ListenerThreadDelegate:: + threadMain() { parent_->Loop(); } -void NetworkInterfaceListenerImpl::ListenerThreadDelegate::exitThreadMain() { +void PlatformSpecificNetworkInterfaceListener::ListenerThreadDelegate:: + exitThreadMain() { parent_->StopLoop(); } 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..9ca7890278 --- /dev/null +++ b/src/components/transport_manager/src/tcp/platform_specific/qnx/platform_specific_network_interface_listener.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the names of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#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/test/CMakeLists.txt b/src/components/transport_manager/test/CMakeLists.txt index 41aae296ac..8447ebe723 100644 --- a/src/components/transport_manager/test/CMakeLists.txt +++ b/src/components/transport_manager/test/CMakeLists.txt @@ -47,6 +47,11 @@ set(EXCLUDE_PATHS collect_sources(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}" "${EXCLUDE_PATHS}") +set ( + "${CMAKE_CURRENT_SOURCE_DIR}"/platform_specific/linux + "${SOURCES}" +) + set(LIBRARIES gmock ConfigProfile diff --git a/src/components/transport_manager/test/network_interface_listener_test.cc b/src/components/transport_manager/test/network_interface_listener_test.cc index 56512e5c98..7a5b0315ab 100644 --- a/src/components/transport_manager/test/network_interface_listener_test.cc +++ b/src/components/transport_manager/test/network_interface_listener_test.cc @@ -69,41 +69,10 @@ class NetworkInterfaceListenerTest : public ::testing::Test { unsigned int flags; }; - void Init(const std::string interface_name) { - interface_listener_impl_ = new NetworkInterfaceListenerImpl( - &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}; @@ -115,485 +84,6 @@ class NetworkInterfaceListenerTest : public ::testing::Test { 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/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..864cb9d657 --- /dev/null +++ b/src/components/transport_manager/test/platform_specific/linux/linux_network_interface_listener_test.cc @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2018 Xevo Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#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 |