YARP
Yet Another Robot Platform
NameConfig.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006, 2011 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 
12 
13 #include <yarp/conf/system.h>
14 #include <yarp/conf/filesystem.h>
15 #include <yarp/conf/environment.h>
16 
17 #include <yarp/os/Bottle.h>
18 #include <yarp/os/NetType.h>
19 #include <yarp/os/Network.h>
20 #include <yarp/os/Os.h>
21 #include <yarp/os/Property.h>
22 #include <yarp/os/ResourceFinder.h>
30 
31 #include <cstdio>
32 #include <cstdlib>
33 
34 #if defined(YARP_HAS_ACE)
35 # include <ace/INET_Addr.h>
36 # include <ace/Sock_Connect.h>
37 // In one the ACE headers there is a definition of "main" for WIN32
38 # ifdef main
39 # undef main
40 # endif
41 #elif defined(__unix__)
42 # include <arpa/inet.h>
43 # include <cstring>
44 # include <sys/socket.h>
45 # include <unistd.h>
46 #endif
47 
48 using namespace yarp::os::impl;
49 using namespace yarp::os;
50 
51 #define CONF_FILENAME YARP_CONFIG_FILENAME
52 
53 namespace {
54 YARP_OS_LOG_COMPONENT(NAMECONFIG, "yarp.os.impl.NameConfig")
55 } // namespace
56 
57 bool NameConfig::fromString(const std::string& txt)
58 {
59  address = Contact();
60  SplitString ss(txt.c_str());
61  if (ss.size() >= 1) {
62  if (ss.get(0)[0] == '[') {
63  // use Property format
64  Property config;
65  config.fromConfig(txt.c_str());
66 
67  Bottle& b = config.findGroup("name");
68  if (b.isNull()) {
69  yCError(NAMECONFIG, "Cannot find yarp group in config file");
70  std::exit(1);
71  }
72  address = Contact(b.find("host").asString(),
73  b.find("port").asInt32());
74  mode = b.check("mode", Value("yarp")).asString();
75  return (address.getPort() != 0);
76  }
77  }
78 
79  if (ss.size() >= 2) {
80  address = Contact(ss.get(0), NetType::toInt(ss.get(1)));
81  if (ss.size() >= 3) {
82  mode = ss.get(2);
83  } else {
84  mode = "yarp";
85  }
86  if (mode == "ros") {
87  address.setCarrier("xmlrpc");
88  }
89  return true;
90  }
91  return false;
92 }
93 
94 std::string NameConfig::expandFilename(const char* fname)
95 {
96  std::string root = ResourceFinder::getConfigHome();
97  std::string conf;
98  if (!root.empty()) {
99  conf = root + std::string{yarp::conf::filesystem::preferred_separator} + fname;
100  } else {
101  conf = fname;
102  }
103 
104  yCDebug(NAMECONFIG, "Configuration file: %s", conf.c_str());
105  return conf;
106 }
107 
108 std::string NameConfig::getSafeString(const std::string& txt)
109 {
110  std::string result = txt;
111  for (char& i : result) {
112  char ch = i;
113  if (!((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))) {
114  i = '_';
115  }
116  }
117  return result;
118 }
119 
120 std::string NameConfig::getConfigFileName(const char* stem, const char* ns)
121 {
122  std::string fname = (stem != nullptr) ? stem : CONF_FILENAME;
123  if (stem == nullptr) {
124  std::string space;
125  if (ns != nullptr) {
126  space = ns;
127  } else {
128  space = getNamespace();
129  }
130  if (space != "/root") {
131  // for non-default namespace, need a separate cache file
132  std::string base = getSafeString(space);
133  base += ".conf";
134  fname = base;
135  }
136  }
137  return expandFilename(fname.c_str());
138 }
139 
140 std::string NameConfig::readConfig(const std::string& fileName)
141 {
142  char buf[25600];
143  FILE* fin = fopen(fileName.c_str(), "r");
144  if (fin == nullptr) {
145  return {};
146  }
147  std::string result;
148  while (fgets(buf, sizeof(buf) - 1, fin) != nullptr) {
149  result += buf;
150  }
151  fclose(fin);
152  fin = nullptr;
153  return result;
154 }
155 
156 
157 bool NameConfig::fromFile(const char* ns)
158 {
159  std::string fname = getConfigFileName(nullptr, ns);
160  if (!fname.empty()) {
161  std::string txt = readConfig(fname);
162  if (!txt.empty()) {
163  return fromString(txt);
164  }
165  }
166  return false;
167 }
168 
169 
170 bool NameConfig::toFile(bool clean)
171 {
172  std::string fname = getConfigFileName();
173  if (!fname.empty()) {
174  std::string txt;
175  if (!clean) {
176  std::string m = (!mode.empty()) ? mode : "yarp";
177  txt += address.getHost() + " " + NetType::toString(address.getPort()) + " " + m + "\n";
178  }
179  return writeConfig(fname, txt);
180  }
181  return false;
182 }
183 
184 
186 {
187  return address;
188 }
189 
190 
191 bool NameConfig::writeConfig(const std::string& fileName, const std::string& text)
192 {
193  if (yarp::os::mkdir_p(fileName.c_str(), 1) != 0) {
194  return false;
195  }
196  FILE* fout = fopen(fileName.c_str(), "w");
197  if (fout == nullptr) {
198  return false;
199  }
200  fprintf(fout, "%s", text.c_str());
201  fclose(fout);
202  fout = nullptr;
203  return true;
204 }
205 
206 
207 std::string NameConfig::getHostName(bool prefer_loopback, const std::string& seed)
208 {
209  // try to pick a good host identifier
210 
211  std::string result = "127.0.0.1";
212  bool loopback = true;
213  bool found = false;
214 
215  // Pick an IPv4 address.
216  // Prefer non-local addresses, then seed, then shorter addresses.
217  // Avoid IPv6.
218 #ifdef YARP_HAS_ACE
219  ACE_INET_Addr* ips = nullptr;
220  size_t count = 0;
221  char hostAddress[256];
222  if (ACE::get_ip_interfaces(count, ips) >= 0) {
223  for (size_t i = 0; i < count; i++) {
224  std::string ip = ips[i].get_host_addr(hostAddress, 256);
225 #else
226  int family;
227  int s;
228  char hostname[NI_MAXHOST];
229  std::string ip;
230  struct ifaddrs *ifaddr;
231  struct ifaddrs *ifa;
232  if (yarp::os::impl::getifaddrs(&ifaddr) == -1) {
233  yCError(NAMECONFIG, "getifaddrs in getIps: %d, %s", errno, strerror(errno));
234  std::exit(EXIT_FAILURE);
235  }
236  for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
237  if (ifa->ifa_addr == nullptr) {
238  continue;
239  }
240  family = ifa->ifa_addr->sa_family;
241  if (family == AF_INET || family == AF_INET6) {
242  s = yarp::os::impl::getnameinfo(ifa->ifa_addr,
243  (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
244  hostname,
245  NI_MAXHOST,
246  nullptr,
247  0,
248  NI_NUMERICHOST);
249  if (s != 0) {
250  yCError(NAMECONFIG, "getnameinfo() failed: %s", yarp::os::impl::gai_strerror(s));
251  std::exit(EXIT_FAILURE);
252  }
253  ip = std::string(hostname);
254 #endif
255 
256  yCDebug(NAMECONFIG, "scanning network interface %s", ip.c_str());
257 
258  if (ip.find(':') != std::string::npos) {
259  continue;
260  }
261 
262 #if defined YARP_HAS_ACE
263  bool would_be_loopback = ips[i].is_loopback();
264 #else
265  bool would_be_loopback = (ip == "127.0.0.1" || ip == "127.1.0.1" || ip == "127.0.1.1");
266 #endif
267 
268  // If we haven't any interface yet, take this one
269  if (!found) {
270  result = ip;
271  loopback = would_be_loopback;
272  found = true;
273  continue;
274  }
275 
276  // We have an interface
277 
278  // If this isn't the right kind of interface, skip it
279  if (would_be_loopback != prefer_loopback) {
280  continue;
281  }
282 
283  // This is the right kind of interface
284 
285  // If we haven't the right kind of interface yet, take it
286  if (prefer_loopback != loopback) {
287  result = ip;
288  loopback = would_be_loopback;
289  continue;
290  }
291 
292  // If it matches the seed interface, take it
293  if (ip == seed) {
294  result = ip;
295  loopback = would_be_loopback;
296  continue;
297  }
298 
299  // If it is shorter, and what we have isn't the seed, take it
300  if (ip.length() < result.length() && result != seed) {
301  result = ip;
302  loopback = would_be_loopback;
303  continue;
304  }
305  }
306  }
307 #ifdef YARP_HAS_ACE
308  delete[] ips;
309 #else
310  freeifaddrs(ifaddr);
311 #endif
312 
313  return result;
314 }
315 
316 
317 bool NameConfig::isLocalName(const std::string& name)
318 {
319  bool result = false;
320 
321 #if defined(YARP_HAS_ACE)
322  ACE_INET_Addr* ips = nullptr;
323  size_t count = 0;
324  if (ACE::get_ip_interfaces(count, ips) >= 0) {
325  for (size_t i = 0; i < count; i++) {
326  std::string ip = ips[i].get_host_addr();
327  if (ip == name) {
328  result = true;
329  break;
330  }
331  }
332  delete[] ips;
333  }
334 #elif defined(__unix__)
335 
339  char hostname[HOST_NAME_MAX];
340  yarp::os::impl::gethostname(hostname, HOST_NAME_MAX);
341  if (strcmp(hostname, name.c_str()) == 0) {
342  result = true;
343  }
344  if (!result) {
345  Bottle lst = getIpsAsBottle();
346  for (size_t i = 0; i < lst.size(); i++) {
347  if (lst.get(i).asString() == name) {
348  result = true;
349  break;
350  }
351  }
352  }
353 #endif
354 
355  // just in case
356  if (name == "localhost" || name == "127.0.0.1") {
357  result = true;
358  }
359 
360  return result;
361 }
362 
364 {
365  yarp::os::Bottle result;
366 
367 #if defined(YARP_HAS_ACE)
368  ACE_INET_Addr* ips = nullptr;
369  size_t count = 0;
370  if (ACE::get_ip_interfaces(count, ips) >= 0) {
371  for (size_t i = 0; i < count; i++) {
372  std::string ip = ips[i].get_host_addr();
373  result.addString(ip.c_str());
374  }
375  delete[] ips;
376  }
377 #else
378  int family;
379  int s;
380  char host[NI_MAXHOST];
381  struct ifaddrs *ifaddr;
382  struct ifaddrs *ifa;
383  if (getifaddrs(&ifaddr) == -1) {
384  yCError(NAMECONFIG, "getifaddrs in getIpsAsBottle: %d, %s", errno, strerror(errno));
385  std::exit(EXIT_FAILURE);
386  }
387  for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
388  if (ifa->ifa_addr == nullptr) {
389  continue;
390  }
391  family = ifa->ifa_addr->sa_family;
392  if (family == AF_INET || family == AF_INET6) {
393  s = yarp::os::impl::getnameinfo(ifa->ifa_addr,
394  (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
395  host,
396  NI_MAXHOST,
397  nullptr,
398  0,
399  NI_NUMERICHOST);
400  if (s != 0) {
401  yCError(NAMECONFIG, "getnameinfo() failed: %s", yarp::os::impl::gai_strerror(s));
402  std::exit(EXIT_FAILURE);
403  }
404  result.addString(host);
405  }
406  }
407  freeifaddrs(ifaddr);
408 #endif
409 
410  return result;
411 }
412 
413 
414 std::string NameConfig::getIps()
415 {
416  yarp::os::Bottle bot = getIpsAsBottle();
417  std::string result;
418  for (size_t i = 0; i < bot.size(); i++) {
419  std::string ip = bot.get(i).asString();
420  if (i > 0) {
421  result += " ";
422  }
423  result += ip;
424  }
425  return result;
426 }
427 
428 
429 void NameConfig::setAddress(const Contact& address)
430 {
431  this->address = address;
432 }
433 
434 
435 void NameConfig::setNamespace(const std::string& ns)
436 {
437  space = ns;
438 }
439 
440 std::string NameConfig::getNamespace(bool refresh)
441 {
442  if (space.empty() || refresh) {
443  std::string senv = yarp::conf::environment::getEnvironment("YARP_NAMESPACE");
444  if (!senv.empty()) {
445  spaces.fromString(senv);
446  } else {
447  std::string fname = getConfigFileName(YARP_CONFIG_NAMESPACE_FILENAME);
448  spaces.fromString(readConfig(fname));
449  }
450  space = spaces.get(0).asString();
451  if (space.empty()) {
452  space = "/root";
453  }
454  if (spaces.size() == 0) {
455  spaces.addString("/root");
456  }
457  }
458  return space;
459 }
460 
462 {
463  getNamespace(refresh);
464  return spaces;
465 }
yarp::os::impl::NameConfig::getConfigFileName
std::string getConfigFileName(const char *stem=nullptr, const char *ns=nullptr)
Definition: NameConfig.cpp:120
filesystem.h
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
Network.h
yarp::os::Bottle::size
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:254
yarp::os::impl::NameConfig::isLocalName
static bool isLocalName(const std::string &name)
Definition: NameConfig.cpp:317
yarp::os::impl::SplitString
Split a string into pieces.
Definition: SplitString.h:27
yarp::conf::environment::getEnvironment
std::string getEnvironment(const char *key, bool *found=nullptr)
Read a variable from the environment.
Definition: environment.h:31
yarp::os::impl::NameConfig::writeConfig
bool writeConfig(const std::string &fileName, const std::string &text)
Definition: NameConfig.cpp:191
yarp::os::impl::NameConfig::getSafeString
std::string getSafeString(const std::string &txt)
Definition: NameConfig.cpp:108
PlatformIfaddrs.h
yarp::os::impl::NameConfig::getHostName
static std::string getHostName(bool prefer_loopback=false, const std::string &seed="")
Definition: NameConfig.cpp:207
yarp::os::impl::NameConfig::getIpsAsBottle
static yarp::os::Bottle getIpsAsBottle()
Definition: NameConfig.cpp:363
LogComponent.h
yarp::os::Bottle::find
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Bottle.cpp:290
yarp::os::impl::NameConfig::getNamespace
std::string getNamespace(bool refresh=false)
Definition: NameConfig.cpp:440
PlatformLimits.h
NetType.h
yarp::os::Bottle::check
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Bottle.cpp:280
yarp::os::impl::NameConfig::getIps
static std::string getIps()
Definition: NameConfig.cpp:414
yarp::os::impl::NameConfig::getAddress
Contact getAddress()
Definition: NameConfig.cpp:185
PlatformNetdb.h
yarp::os::ResourceFinder::getConfigHome
static std::string getConfigHome()
Location where user config files are stored.
Definition: ResourceFinder.h:314
yarp::os::Bottle::get
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
yarp::os::impl::NameConfig::setAddress
void setAddress(const Contact &address)
Definition: NameConfig.cpp:429
Property.h
yarp::os::impl::NameConfig::expandFilename
static std::string expandFilename(const char *fname)
Definition: NameConfig.cpp:94
yarp::os::Value::asString
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
Os.h
yarp::os::gethostname
void gethostname(char *hostname, size_t size)
Portable wrapper for the gethostname() function.
Definition: Os.cpp:100
NameConfig.h
yarp::os::impl::NameConfig::setNamespace
void setNamespace(const std::string &ns)
Definition: NameConfig.cpp:435
yarp::os::Bottle::addString
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:173
yarp::os::mkdir_p
int mkdir_p(const char *p, int ignoreLevels=0)
Create a directory and all parent directories needed.
Definition: Os.cpp:45
system.h
yarp::os::Bottle::isNull
bool isNull() const override
Checks if the object is invalid.
Definition: Bottle.cpp:373
yarp::os::impl::NameConfig::toFile
bool toFile(bool clean=false)
Definition: NameConfig.cpp:170
yarp::os::NetType::toString
static std::string toString(int x)
Definition: NetType.cpp:138
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yarp::os::impl::NameConfig::getNamespaces
yarp::os::Bottle getNamespaces(bool refresh=false)
Definition: NameConfig.cpp:461
yarp::os::Value::asInt32
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:207
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
PlatformSysStat.h
PlatformUnistd.h
environment.h
yarp::os::impl::NameConfig::readConfig
std::string readConfig(const std::string &fileName)
Definition: NameConfig.cpp:140
yarp::conf::filesystem::preferred_separator
static constexpr value_type preferred_separator
Definition: filesystem.h:28
yarp::os::Contact
Represents how to reach a part of a YARP network.
Definition: Contact.h:39
yarp::os::impl::NameConfig::fromFile
bool fromFile(const char *ns=nullptr)
Definition: NameConfig.cpp:157
yarp::os::Property::findGroup
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Property.cpp:1125
yarp::os::Property::fromConfig
void fromConfig(const char *txt, bool wipe=true)
Parses text in the configuration format described in fromConfigFile().
Definition: Property.cpp:1093
SplitString.h
YARP_CONFIG_NAMESPACE_FILENAME
#define YARP_CONFIG_NAMESPACE_FILENAME
Definition: NameConfig.h:21
yarp::os::Value
A single value (typically within a Bottle).
Definition: Value.h:47
YARP_OS_LOG_COMPONENT
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:37
CONF_FILENAME
#define CONF_FILENAME
Definition: NameConfig.cpp:51
yarp::os::impl
The components from which ports and connections are built.
Bottle.h
ResourceFinder.h
yarp::os::Property
A class for storing options and configuration information.
Definition: Property.h:37
yarp::os::NetType::toInt
static int toInt(const std::string &x)
Definition: NetType.cpp:160