YARP
Yet Another Robot Platform
TcpConnector.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-FileCopyrightText: 2010 Anne van Rossum <anne@almende.com>
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <yarp/conf/system.h>
8 #ifndef YARP_HAS_ACE
9 
11 
12 // General files
13 # include <yarp/os/Log.h>
16 
17 # include <cstdio>
18 # include <fcntl.h>
19 # include <iostream>
20 # include <sys/socket.h>
21 
22 using namespace yarp::os::impl;
23 using namespace yarp::os;
24 
25 namespace {
26 YARP_OS_LOG_COMPONENT(TCPCONNECTOR_POSIX, "yarp.os.impl.TcpConnector.posix")
27 }
28 
29 /* **************************************************************************************
30  * Implementation of TcpConnector
31  * **************************************************************************************/
32 
33 TcpConnector::TcpConnector() = default;
34 
35 TcpConnector::~TcpConnector() = default;
36 
37 int TcpConnector::open(TcpStream& stream)
38 {
39  if ((stream.get_handle() == -1) && (stream.open() == -1)) {
40  return -1;
41  }
42  return 0;
43 }
44 
48 int TcpConnector::connect(TcpStream& new_stream, const Contact& address, YARP_timeval* timeout)
49 {
50  // printf("TCP/IP start in client mode\n");
51  // sockets.set_as_client();
52  // sockets.set_client_sockfd(sockfd);
53  if (open(new_stream) == -1) {
54  return -1;
55  }
56 
57  // Write sockaddr struct with given address...
58  sockaddr_in servAddr;
59  servAddr.sin_addr.s_addr = INADDR_ANY;
60  servAddr.sin_family = AF_INET;
61  servAddr.sin_port = htons(address.getPort());
62  memset(servAddr.sin_zero, '\0', sizeof servAddr.sin_zero);
63 
64  struct hostent* hostInfo = yarp::os::impl::gethostbyname(address.getHost().c_str());
65  if (hostInfo) {
66  bcopy(hostInfo->h_addr, reinterpret_cast<char*>(&servAddr.sin_addr), hostInfo->h_length);
67  } else {
68  inet_pton(AF_INET, address.getHost().c_str(), &servAddr.sin_addr);
69  }
70 
71  auto handle = new_stream.get_handle();
72 
73  yAssert(handle != -1);
74 
75  int res;
76  long arg;
77  fd_set myset;
78  int valopt;
79  socklen_t lon;
80 
81  // Set non-blocking
82  if ((arg = fcntl(handle, F_GETFL, NULL)) < 0) {
83  yCError(TCPCONNECTOR_POSIX, "connect fail: Error fcntl(..., F_GETFL): %d, %s", errno, strerror(errno));
84  return -1;
85  }
86  arg |= O_NONBLOCK;
87  if (fcntl(handle, F_SETFL, arg) < 0) {
88  yCError(TCPCONNECTOR_POSIX, "connect fail: Error fcntl(..., F_SETFL): %d, %s", errno, strerror(errno));
89  return -1;
90  }
91  // Trying to connect with timeout
92  res = ::connect(handle, reinterpret_cast<sockaddr*>(&servAddr), sizeof(servAddr));
93 
94  if (res < 0) {
95  if (errno == EINPROGRESS) {
96  FD_ZERO(&myset);
97  FD_SET(handle, &myset);
98  res = select(handle + 1, nullptr, &myset, nullptr, timeout);
99  if (res < 0 && errno != EINTR) {
100  yCError(TCPCONNECTOR_POSIX, "connect fail: Error connecting: %d, %s", errno, strerror(errno));
101  res = -1;
102  } else if (res > 0) {
103  res = 0;
104  // Socket selected for write
105  lon = sizeof(int);
106  if (getsockopt(handle, SOL_SOCKET, SO_ERROR, reinterpret_cast<void*>(&valopt), &lon) < 0) {
107  yCError(TCPCONNECTOR_POSIX, "connect fail: Error in getsockopt(): %d, %s", errno, strerror(errno));
108  res = -1;
109  }
110  // Check the value returned...
111  if (valopt) {
112  // connect fail: Error in delayed connection() -> the port doesn't exist
113  res = -1;
114  }
115  } else {
116  yCError(TCPCONNECTOR_POSIX, "connect fail: Timeout in select() - Cancelling!: %d, %s", errno, strerror(errno));
117  res = -1;
118  }
119  } else {
120  yCError(TCPCONNECTOR_POSIX, "connect fail: Error connecting: %d, %s", errno, strerror(errno));
121  res = -1;
122  }
123  }
124 
125  if (res != 0) {
126  char buf[INET_ADDRSTRLEN];
127  yCError(TCPCONNECTOR_POSIX,
128  "Connect [handle=%d] at %s:%d",
129  new_stream.get_handle(),
130  inet_ntop(AF_INET, &servAddr.sin_addr, buf, INET_ADDRSTRLEN),
131  servAddr.sin_port);;
132  return -1;
133  }
134 
135  // Set to blocking mode again...
136  if ((arg = fcntl(handle, F_GETFL, nullptr)) < 0) {
137  yCError(TCPCONNECTOR_POSIX, "connect fail: Error fcntl(..., F_GETFL): %d, %s", errno, strerror(errno));
138  return -1;
139  }
140  arg &= (~O_NONBLOCK);
141  if (fcntl(handle, F_SETFL, arg) < 0) {
142  yCError(TCPCONNECTOR_POSIX, "connect fail: Error fcntl(..., F_SETFL): %d, %s", errno, strerror(errno));
143  return -1;
144  }
145 
146  return res;
147 }
148 
149 #endif
#define yAssert(x)
Definition: Log.h:294
Represents how to reach a part of a YARP network.
Definition: Contact.h:36
int getPort() const
Get the port number associated with this Contact for socket communication.
Definition: Contact.cpp:239
std::string getHost() const
Get the host name associated with this Contact for socket communication.
Definition: Contact.cpp:228
#define yCError(component,...)
Definition: LogComponent.h:154
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:34
The components from which ports and connections are built.
struct timeval YARP_timeval
Definition: PlatformTime.h:32
An interface to the operating system, including Port based communication.