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