YARP
Yet Another Robot Platform
Contact.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4  * SPDX-FileCopyrightText: 2006, 2011 Anne van Rossum <anne@almende.com>
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <yarp/os/Contact.h>
9 #include <yarp/os/NetType.h>
10 #include <yarp/os/Searchable.h>
11 #include <yarp/os/Value.h>
15 
16 #include <cstdio>
17 #include <cstdlib>
18 #include <cstring>
19 #include <utility>
20 
21 #if defined(YARP_HAS_ACE)
22 # include <ace/INET_Addr.h>
23 // In one the ACE headers there is a definition of "main" for WIN32
24 # ifdef main
25 # undef main
26 # endif
27 #else
28 # include <arpa/inet.h>
29 # include <sys/socket.h>
30 # include <sys/types.h>
31 #endif
32 
33 
34 using yarp::os::Contact;
36 using yarp::os::NetType;
38 using yarp::os::Value;
40 
41 #if !defined(YARP_HAS_ACE)
42 namespace {
43 YARP_OS_LOG_COMPONENT(CONTACT, "yarp.os.Contact" )
44 }
45 #endif
46 
47 #ifndef DOXYGEN_SHOULD_SKIP_THIS
48 
49 class Contact::Private
50 {
51 public:
52  Private(std::string regName,
53  std::string carrier,
54  std::string hostname,
55  int port) :
56  regName(std::move(regName)),
57  carrier(std::move(carrier)),
58  hostname(std::move(hostname)),
59  port(port),
60  timeout(-1)
61  {
62  }
63 
64  std::string regName;
65  std::string carrier;
66  std::string hostname;
67  NestedContact nestedContact;
68 
69  int port;
70  float timeout;
71 };
72 
73 #endif // DOXYGEN_SHOULD_SKIP_THIS
74 
75 
76 Contact::Contact(const std::string& hostname,
77  int port) :
78  mPriv(new Private(std::string(), std::string(), hostname, port))
79 {
80 }
81 
82 Contact::Contact(const std::string& carrier,
83  const std::string& hostname,
84  int port) :
85  mPriv(new Private(std::string(), carrier, hostname, port))
86 {
87 }
88 
89 Contact::Contact(const std::string& name,
90  const std::string& carrier,
91  const std::string& hostname,
92  int port) :
93  mPriv(new Private(name, carrier, hostname, port))
94 {
95 }
96 
98  mPriv(new Private(*(rhs.mPriv)))
99 {
100 }
101 
102 Contact::Contact(Contact&& rhs) noexcept :
103  mPriv(rhs.mPriv)
104 {
105  rhs.mPriv = nullptr;
106 }
107 
109 {
110  delete mPriv;
111 }
112 
114 {
115  if (&rhs != this) {
116  *mPriv = *(rhs.mPriv);
117  }
118  return *this;
119 }
120 
122 {
123  if (&rhs != this) {
124  std::swap(mPriv, rhs.mPriv);
125  }
126  return *this;
127 }
128 
130 {
131  Contact result;
132  result.mPriv->port = config.check("port_number", Value(-1)).asInt32();
133  result.mPriv->hostname = config.check("ip", Value("")).asString();
134  result.mPriv->regName = config.check("name", Value("")).asString();
135  result.mPriv->carrier = config.check("carrier", Value("tcp")).asString();
136  return result;
137 }
138 
139 Contact Contact::fromString(const std::string& txt)
140 {
141  std::string str(txt);
142  Contact c;
143  std::string::size_type start = 0;
144  std::string::size_type base = str.find("://");
145  std::string::size_type offset = 2;
146  if (base == std::string::npos) {
147  base = str.find(":/");
148  offset = 1;
149  }
150  if (base == std::string::npos) {
151  if (str.length() > 0 && str[0] == '/') {
152  base = 0;
153  offset = 0;
154  }
155  }
156  if (base != std::string::npos) {
157  c.mPriv->carrier = str.substr(0, base);
158  start = base + offset;
159  // check if we have a direct machine:NNN syntax
160  std::string::size_type colon = std::string::npos;
161  int mode = 0;
162  int nums = 0;
163  std::string::size_type i;
164  for (i = start + 1; i < str.length(); i++) {
165  char ch = str[i];
166  if (ch == ':') {
167  if (mode == 0) {
168  colon = i;
169  mode = 1;
170  continue;
171  }
172  mode = -1;
173  break;
174  }
175  if (ch == '/') {
176  break;
177  }
178  if (mode == 1) {
179  if (ch >= '0' && ch <= '9') {
180  nums++;
181  continue;
182  }
183  mode = -1;
184  break;
185  }
186  }
187  if (mode == 1 && nums >= 1) {
188  // yes, machine:nnn
189  if (c.mPriv->carrier.empty()) {
190  c.mPriv->carrier = "tcp";
191  }
192  c.mPriv->hostname = str.substr(start + 1, colon - start - 1);
193  c.mPriv->port = atoi(str.substr(colon + 1, nums).c_str());
194  start = i;
195  }
196  }
197  std::string rname = str.substr(start);
198  if (rname != "/") {
199  c.mPriv->regName = rname;
200  }
201  return c;
202 }
203 
204 
205 std::string Contact::getName() const
206 {
207  if (!mPriv->regName.empty()) {
208  return mPriv->regName;
209  }
210  if (!mPriv->hostname.empty() && mPriv->port >= 0) {
211  std::string name = std::string("/") + mPriv->hostname + ":" + yarp::conf::numeric::to_string(mPriv->port);
212  return name;
213  }
214  return {};
215 }
216 
217 std::string Contact::getRegName() const
218 {
219  return mPriv->regName;
220 }
221 
222 void Contact::setName(const std::string& name)
223 {
224  mPriv->regName = name;
225 }
226 
227 
228 std::string Contact::getHost() const
229 {
230  return mPriv->hostname;
231 }
232 
233 void Contact::setHost(const std::string& hostname)
234 {
235  this->mPriv->hostname = hostname;
236 }
237 
238 
239 int Contact::getPort() const
240 {
241  return mPriv->port;
242 }
243 
244 void Contact::setPort(int port)
245 {
246  mPriv->port = port;
247 }
248 
249 
250 std::string Contact::getCarrier() const
251 {
252  return mPriv->carrier;
253 }
254 
255 void Contact::setCarrier(const std::string& carrier)
256 {
257  mPriv->carrier = carrier;
258 }
259 
260 
262 {
263  return mPriv->nestedContact;
264 }
265 
267 {
268  this->mPriv->nestedContact = nestedContact;
269 }
270 
271 
273 {
274  return mPriv->timeout >= 0;
275 }
276 
277 float Contact::getTimeout() const
278 {
279  return mPriv->timeout;
280 }
281 
282 void Contact::setTimeout(float timeout)
283 {
284  this->mPriv->timeout = timeout;
285 }
286 
287 
288 void Contact::setSocket(const std::string& carrier,
289  const std::string& hostname,
290  int port)
291 {
292  mPriv->carrier = carrier;
293  mPriv->hostname = hostname;
294  mPriv->port = port;
295 }
296 
297 
298 bool Contact::isValid() const
299 {
300  return mPriv->port >= 0;
301 }
302 
303 std::string Contact::toString() const
304 {
305  std::string name = getName();
306  if (!mPriv->carrier.empty()) {
307  return mPriv->carrier + ":/" + name;
308  }
309  return name;
310 }
311 
312 
313 std::string Contact::toURI(bool includeCarrier) const
314 {
315  std::string result;
316  if (includeCarrier && !mPriv->carrier.empty()) {
317  result += mPriv->carrier;
318  result += ":/";
319  }
320  if (!mPriv->hostname.empty() && mPriv->port >= 0) {
321  result += "/";
322  result += mPriv->hostname;
323  result += ":";
324  result += yarp::conf::numeric::to_string(mPriv->port);
325  result += "/";
326  }
327  return result;
328 }
329 
330 
331 std::string Contact::convertHostToIp(const char* name)
332 {
333 #if defined(YARP_HAS_ACE)
334  ACE_INET_Addr addr((u_short)0, name);
335  char ipstr[256];
336  addr.get_host_addr(ipstr, sizeof(ipstr));
337 
338 #else
339  char ipstr[INET6_ADDRSTRLEN];
340  int status;
341  struct addrinfo hints, *res, *p;
342 
343  memset(&hints, 0, sizeof hints); // make sure the struct is empty
344  hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
345  hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
346  hints.ai_flags = AI_PASSIVE; // fill in my IP for me
347 
348  if ((status = yarp::os::impl::getaddrinfo(name, "http", &hints, &res)) != 0) {
349  yCError(CONTACT, "getaddrinfo error: %s\n", yarp::os::impl::gai_strerror(status));
350  std::exit(1);
351  }
352 
353  for (p = res; p != nullptr; p = p->ai_next) {
354  void* addr;
355 
356  if (p->ai_family == AF_INET) { // IPv4
357  auto* ipv4 = reinterpret_cast<struct sockaddr_in*>(p->ai_addr);
358  addr = &(ipv4->sin_addr);
359  } else { // IPv6
360  auto* ipv6 = reinterpret_cast<struct sockaddr_in6*>(p->ai_addr);
361  addr = &(ipv6->sin6_addr);
362  }
363 
364  // convert the IP to a string and print it:
365  inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
366  }
367  yarp::os::impl::freeaddrinfo(res);
368 #endif
369 
370  if (NameConfig::isLocalName(ipstr)) {
371  return NameConfig::getHostName();
372  }
373  return ipstr;
374 }
Represents how to reach a part of a YARP network.
Definition: Contact.h:36
void setCarrier(const std::string &carrier)
Set the carrier to use for this Contact.
Definition: Contact.cpp:255
void setHost(const std::string &hostname)
Set the host name to be the input parameter.
Definition: Contact.cpp:233
const NestedContact & getNested() const
Get the NestedContact containing extra information for this Contact.
Definition: Contact.cpp:261
static Contact fromConfig(const Searchable &config)
Factory method.
Definition: Contact.cpp:129
void setNestedContact(const yarp::os::NestedContact &nestedContact)
Sets the NestedContact containing extra information for this Contact.
Definition: Contact.cpp:266
bool hasTimeout() const
Check if this Contact has a timeout.
Definition: Contact.cpp:272
bool isValid() const
Checks if a Contact is tagged as valid.
Definition: Contact.cpp:298
Contact(const std::string &name=std::string(), const std::string &carrier=std::string(), const std::string &hostname=std::string(), int port=-1)
Constructor.
Definition: Contact.cpp:89
std::string getName() const
Get the name associated with this Contact.
Definition: Contact.cpp:205
std::string getRegName() const
Get the name associated with this Contact.
Definition: Contact.cpp:217
std::string toString() const
Get a textual representation of the Contact.
Definition: Contact.cpp:303
Contact & operator=(const Contact &rhs)
Copy assignment operator.
Definition: Contact.cpp:113
static Contact fromString(const std::string &txt)
Factory method.
Definition: Contact.cpp:139
void setPort(int port)
Set the port number to be the input parameter.
Definition: Contact.cpp:244
static std::string convertHostToIp(const char *name)
If the host is a machine name, convert it to a plausible IP address.
Definition: Contact.cpp:331
std::string toURI(bool includeCarrier=true) const
Get a representation of the Contact as a URI.
Definition: Contact.cpp:313
int getPort() const
Get the port number associated with this Contact for socket communication.
Definition: Contact.cpp:239
virtual ~Contact()
Destructor.
Definition: Contact.cpp:108
void setSocket(const std::string &carrier, const std::string &hostname, int port)
Set information to a Contact about how to reach it using socket communication.
Definition: Contact.cpp:288
void setName(const std::string &name)
Set the name associated with this Contact.
Definition: Contact.cpp:222
float getTimeout() const
Get timeout for this Address.
Definition: Contact.cpp:277
void setTimeout(float timeout)
Set timeout for this Contact.
Definition: Contact.cpp:282
std::string getCarrier() const
Get the carrier associated with this Contact for socket communication.
Definition: Contact.cpp:250
std::string getHost() const
Get the host name associated with this Contact for socket communication.
Definition: Contact.cpp:228
A placeholder for rich contact information.
Definition: NestedContact.h:24
Various utilities related to types and formats.
Definition: NetType.h:26
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
A single value (typically within a Bottle).
Definition: Value.h:45
Small helper class to help deal with legacy YARP configuration files.
Definition: NameConfig.h:25
#define yCError(component,...)
Definition: LogComponent.h:154
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:34
std::string to_string(IntegerType x)
Definition: numeric.h:115