diff options
Diffstat (limited to 'src/components/transport_manager/src/tcp')
7 files changed, 1229 insertions, 117 deletions
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; |