2 * \file tcp_client_listener.cc
3 * \brief TcpClientListener class source file.
5 * Copyright (c) 2013, Ford Motor Company
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided with the
19 * Neither the name of the Ford Motor Company nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
36 #include "transport_manager/tcp/tcp_client_listener.h"
41 #include <arpa/inet.h>
43 #include <sys/types.h>
44 #include <sys/sysctl.h>
45 #include <sys/socket.h>
47 # include <linux/tcp.h>
49 # include <sys/time.h>
50 # include <netinet/in.h>
51 # include <netinet/tcp.h>
52 //# include <netinet/tcp_var.h>
55 #include "transport_manager/transport_adapter/transport_adapter_controller.h"
56 #include "transport_manager/tcp/tcp_device.h"
57 #include "transport_manager/tcp/tcp_socket_connection.h"
59 namespace transport_manager {
60 namespace transport_adapter {
62 TcpClientListener::TcpClientListener(TransportAdapterController* controller,
65 controller_(controller),
68 thread_started_(false),
69 shutdown_requested_(false),
70 thread_stop_requested_(false) {
73 void* tcpClientListenerThread(void* data) {
74 TcpClientListener* tcpClientListener = static_cast<TcpClientListener*>(data);
75 assert(tcpClientListener != 0);
76 tcpClientListener->Thread();
80 TransportAdapter::Error TcpClientListener::Init() {
81 return TransportAdapter::OK;
84 void TcpClientListener::Terminate() {
85 shutdown_requested_ = true;
86 if (TransportAdapter::OK != StopListening()) {
87 LOG4CXX_ERROR(logger_, "Cannot stop listening TCP");
91 bool TcpClientListener::IsInitialised() const {
95 TcpClientListener::~TcpClientListener() {
96 LOG4CXX_INFO(logger_, "destructor");
99 void TcpClientListener::Thread() {
100 LOG4CXX_INFO(logger_, "Tcp client listener thread started");
102 while (false == thread_stop_requested_) {
103 sockaddr_in client_address;
104 socklen_t client_address_size = sizeof(client_address);
105 const int connection_fd = accept(socket_,
106 (struct sockaddr*) &client_address,
107 &client_address_size);
108 if (thread_stop_requested_) break;
110 if (connection_fd < 0) {
111 LOG4CXX_ERROR_WITH_ERRNO(logger_, "accept() failed");
115 if (AF_INET != client_address.sin_family) {
116 LOG4CXX_ERROR(logger_, "Address of connected client is invalid");
120 char device_name[32];
121 strncpy(device_name, inet_ntoa(client_address.sin_addr),
122 sizeof(device_name) / sizeof(device_name[0]));
123 LOG4CXX_INFO(logger_, "Connected client " << device_name);
126 int keepidle = 3; // 3 seconds to disconnection detecting
129 int user_timeout = 7000; // milliseconds
131 setsockopt(connection_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
132 setsockopt(connection_fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
133 setsockopt(connection_fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
134 setsockopt(connection_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
135 setsockopt(connection_fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout, sizeof(user_timeout));
137 setsockopt(connection_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
138 setsockopt(connection_fd, IPPROTO_TCP, TCP_KEEPALIVE, &keepidle, sizeof(keepidle));
139 setsockopt(connection_fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
140 setsockopt(connection_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
141 setsockopt(connection_fd, IPPROTO_TCP, SO_RCVTIMEO, &user_timeout, sizeof(user_timeout));
142 // NOTE: may need to set SO_SNDTIMEO
144 // TODO (KKolodiy): Out of order!
145 const int kMidLength = 4;
151 mib[2] = IPPROTO_TCP;
152 mib[3] = TCPCTL_KEEPIDLE;
153 sysctl(mib, kMidLength, NULL, NULL, &keepidle, sizeof(keepidle));
157 mib[2] = IPPROTO_TCP;
158 mib[3] = TCPCTL_KEEPCNT;
159 sysctl(mib, kMidLength, NULL, NULL, &keepcnt, sizeof(keepcnt));
163 mib[2] = IPPROTO_TCP;
164 mib[3] = TCPCTL_KEEPINTVL;
165 sysctl(mib, kMidLength, NULL, NULL, &keepintvl, sizeof(keepintvl));
167 memset(&tval, sizeof(tval), 0);
168 tval.tv_sec = keepidle;
169 setsockopt(connection_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
170 setsockopt(connection_fd, IPPROTO_TCP, TCP_KEEPALIVE, &tval, sizeof(tval));
173 TcpDevice* tcp_device = new TcpDevice(client_address.sin_addr.s_addr, device_name);
174 DeviceSptr device = controller_->AddDevice(tcp_device);
175 tcp_device = static_cast<TcpDevice*>(device.get());
176 const ApplicationHandle app_handle = tcp_device->AddIncomingApplication(
179 TcpSocketConnection* connection(
180 new TcpSocketConnection(device->unique_device_id(), app_handle,
182 connection->set_socket(connection_fd);
183 const TransportAdapter::Error error = connection->Start();
184 if (error != TransportAdapter::OK) {
189 LOG4CXX_INFO(logger_, "Tcp client listener thread finished");
192 TransportAdapter::Error TcpClientListener::StartListening() {
194 return TransportAdapter::BAD_STATE;
196 socket_ = socket(AF_INET, SOCK_STREAM, 0);
199 LOG4CXX_ERROR_WITH_ERRNO(logger_, "Failed to create socket");
200 return TransportAdapter::FAIL;
203 sockaddr_in server_address;
204 memset(&server_address, 0, sizeof(server_address));
205 server_address.sin_family = AF_INET;
206 server_address.sin_port = htons(port_);
207 server_address.sin_addr.s_addr = INADDR_ANY;
210 setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
212 if (0 != bind(socket_, (sockaddr*) &server_address, sizeof(server_address))) {
213 LOG4CXX_ERROR_WITH_ERRNO(logger_, "bind() failed");
214 return TransportAdapter::FAIL;
217 if (0 != listen(socket_, 128)) {
218 LOG4CXX_ERROR_WITH_ERRNO(logger_, "listen() failed");
219 return TransportAdapter::FAIL;
222 const int thread_start_error = pthread_create(&thread_, 0,
223 &tcpClientListenerThread, this);
224 if (0 == thread_start_error) {
225 thread_started_ = true;
226 LOG4CXX_INFO(logger_, "Tcp client listener thread started");
230 "Tcp client listener thread start failed, error code "
231 << thread_start_error);
232 return TransportAdapter::FAIL;
234 return TransportAdapter::OK;
237 TransportAdapter::Error TcpClientListener::StopListening() {
238 if (!thread_started_)
239 return TransportAdapter::BAD_STATE;
241 thread_stop_requested_ = true;
242 int byebyesocket = socket(AF_INET, SOCK_STREAM, 0);
243 sockaddr_in server_address;
244 memset(&server_address, 0, sizeof(server_address));
245 server_address.sin_family = AF_INET;
246 server_address.sin_port = htons(port_);
247 server_address.sin_addr.s_addr = INADDR_ANY;
248 connect(byebyesocket, (sockaddr*)&server_address, sizeof(server_address));
249 shutdown(byebyesocket, SHUT_RDWR);
251 pthread_join(thread_, 0);
252 LOG4CXX_INFO(logger_, "Tcp client listener thread terminated");
255 thread_started_ = false;
256 thread_stop_requested_ = false;
257 return TransportAdapter::OK;
260 } // namespace transport_adapter
261 } // namespace transport_manager