YARP
Yet Another Robot Platform
NameServer.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
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 #ifndef YARP_OS_IMPL_NAMESERVER_H
11 #define YARP_OS_IMPL_NAMESERVER_H
12 
13 #include <yarp/conf/string.h>
14 #include <yarp/conf/numeric.h>
15 
16 #include <yarp/os/Bottle.h>
17 #include <yarp/os/Contact.h>
18 #include <yarp/os/LogComponent.h>
19 #include <yarp/os/NetType.h>
20 #include <yarp/os/Time.h>
22 
23 #include <map>
24 #include <mutex>
25 #include <string>
26 #include <vector>
27 
29 
30 namespace yarp {
31 namespace os {
32 namespace impl {
33 
38 {
39 public:
40  virtual ~NameServerStub() = default;
41  virtual std::string apply(const std::string& txt, const Contact& remote) = 0;
42 };
43 
48 {
49 public:
51  mutex()
52  {
53  setup();
54  }
55 
56  virtual ~NameServer() = default;
57 
58  // address may be partial - partial information gets filled in
59  // (not YARP2 compliant yet, won't do fill-in)
60  Contact registerName(const std::string& name,
61  const Contact& address)
62  {
63  return registerName(name, address, "...");
64  }
65 
66  Contact registerName(const std::string& name,
67  const Contact& address,
68  const std::string& remote);
69 
70  Contact registerName(const std::string& name)
71  {
72  return registerName(name, Contact());
73  }
74 
75  Contact queryName(const std::string& name);
76 
77  Contact unregisterName(const std::string& name);
78 
79  std::string apply(const std::string& txt, const Contact& remote) override;
80 
81  bool apply(const yarp::os::Bottle& cmd, yarp::os::Bottle& result, const Contact& remote);
82 
83  std::string apply(const std::string& txt)
84  {
85  return apply(txt, Contact());
86  }
87 
88  virtual void onEvent(yarp::os::Bottle& event)
89  {
90  YARP_UNUSED(event);
91  }
92 
93  static std::string textify(const Contact& address);
94  static yarp::os::Bottle botify(const Contact& address);
95 
96  void setBasePort(int basePort)
97  {
98  this->basePort = basePort;
99  mcastRecord.setBasePort(basePort);
100  }
101 
102 
103 private:
104  void setup();
105 
106  template <class T>
107  class ReusableRecord
108  {
109  private:
110  std::vector<T> reuse;
111 
112  public:
113  virtual ~ReusableRecord() = default;
114 
115  virtual T fresh() = 0;
116 
117  void release(const T& o)
118  {
119  reuse.push_back(o);
120  }
121 
122  T getFree()
123  {
124  if (reuse.size() >= 1) {
125  T result = reuse[reuse.size() - 1];
126  reuse.pop_back();
127  return result;
128  }
129  return fresh();
130  }
131  };
132 
133 
134  class DisposableNameRecord : public ReusableRecord<int>
135  {
136  private:
137  int base;
138  std::string prefix;
139 
140  public:
141  DisposableNameRecord()
142  {
143  base = 1;
144  prefix = "/tmp/port/";
145  }
146 
147  std::string get()
148  {
149  return prefix + yarp::conf::numeric::to_string(getFree());
150  }
151 
152  int fresh() override
153  {
154  int result = base;
155  base++;
156  return result;
157  }
158 
159  bool release(const std::string& name)
160  {
161  if (name.find(prefix) == 0) {
162  std::string num = name.substr(prefix.length());
163  int x = yarp::conf::numeric::from_string<int>(num);
164  ReusableRecord<int>::release(x);
165  return true;
166  }
167  return false;
168  }
169  };
170 
171 
172  class HostRecord : public ReusableRecord<int>
173  {
174  private:
175  int base;
176 
177  public:
178  HostRecord()
179  {
180  // FIXME HostRecord has hardcoded base
181  base = 0;
182  }
183 
184  void setBase(int base)
185  {
186  this->base = base;
187  }
188 
189  int get()
190  {
191  int result = ReusableRecord<int>::getFree();
192  yCTrace(NAMESERVER, "host record says %d is free", result);
193  return result;
194  }
195 
196  int fresh() override
197  {
198  int result = base++;
199  return result;
200  }
201  };
202 
203 
204  class McastRecord : public ReusableRecord<int>
205  {
206  private:
207  int base;
208  int last;
209  int basePort;
210 
211  public:
212  McastRecord()
213  {
214  // FIXME: mcast records are never reused
215  base = 0;
216  basePort = 0;
217  last = 0;
218  }
219 
220  void setBasePort(int basePort)
221  {
222  this->basePort = basePort;
223  }
224 
225  int fresh() override
226  {
227  int result = base;
228  base++;
229  return result;
230  }
231 
232  std::string get()
233  {
234  int x = getFree();
235  last = x;
236  int v1 = x % 255;
237  int v2 = x / 255;
238  yCAssert(NAMESERVER, v2 < 255);
239  return std::string("224.1.") + yarp::conf::numeric::to_string(v2 + 1) + "." + yarp::conf::numeric::to_string(v1 + 1);
240  }
241 
242  int lastPortNumber()
243  {
244  return basePort + last;
245  }
246 
247  void releaseAddress(const char* addr)
248  {
249  auto ss = yarp::conf::string::split(addr, '.');
250  constexpr size_t ipv4_size = 4;
251  int ip[] = {224, 3, 1, 1};
252  yCAssert(NAMESERVER, ss.size() == ipv4_size);
253  for (size_t i = 0; i < ipv4_size; ++i) {
254  ip[i] = yarp::conf::numeric::from_string<int>(ss[i]);
255  }
256 
257  int v2 = ip[2] - 1;
258  int v1 = ip[3] - 1;
259  int x = v2 * 255 + v1;
260  yCInfo(NAMESERVER, "Releasing %s %d %d:%d\n", addr, x, v2, v1);
261  release(x);
262  }
263  };
264 
265 
266  class PropertyRecord
267  {
268  private:
269  std::vector<std::string> prop;
270 
271  public:
272  PropertyRecord()
273  {
274  }
275 
276  void clear()
277  {
278  prop.clear();
279  }
280 
281  void add(const std::string& p)
282  {
283  prop.push_back(p);
284  }
285 
286  bool check(const std::string& p)
287  {
288  for (unsigned int i = 0; i < prop.size(); i++) {
289  if (prop[i] == p) {
290  return true;
291  }
292  }
293  return false;
294  }
295 
296  std::string match(const std::string& str)
297  {
298  std::string base = "";
299  bool needSpace = false;
300  for (unsigned int i = 0; i < prop.size(); i++) {
301  if (prop[i].find(str) == 0) {
302  if (needSpace) {
303  base += " ";
304  }
305  base += prop[i];
306  needSpace = true;
307  }
308  }
309  return base;
310  }
311 
312  std::string toString() const
313  {
314  std::string base = "";
315  for (unsigned int i = 0; i < prop.size(); i++) {
316  if (i > 0) {
317  base += " ";
318  }
319  base += prop[i];
320  }
321  return base;
322  }
323  };
324 
325  class NameRecord
326  {
327  private:
328  bool reusablePort;
329  bool reusableIp;
330  std::map<std::string, PropertyRecord> propMap;
331  Contact address;
332 
333  public:
334  NameRecord() :
335  address()
336  {
337  reusableIp = false;
338  reusablePort = false;
339  }
340 
341  NameRecord(const NameRecord& alt) :
342  address()
343  {
344  YARP_UNUSED(alt);
345  reusableIp = false;
346  reusablePort = false;
347  }
348 
349  bool isReusablePort()
350  {
351  return reusablePort;
352  }
353 
354  bool isReusableIp()
355  {
356  return reusableIp;
357  }
358 
359  void clear()
360  {
361  propMap.clear();
362  address = Contact();
363  reusableIp = false;
364  reusablePort = false;
365  }
366 
367  void setAddress(const Contact& address,
368  bool reusablePort = false,
369  bool reusableIp = false)
370  {
371  this->address = address;
372  this->reusablePort = reusablePort;
373  this->reusableIp = reusableIp;
374  }
375 
376  Contact getAddress()
377  {
378  return address;
379  }
380 
381 
382  PropertyRecord* getPR(const std::string& key, bool create = true)
383  {
384  std::map<std::string, PropertyRecord>::iterator entry = propMap.find(key);
385  if (entry == propMap.end()) {
386  if (!create) {
387  return nullptr;
388  }
389  propMap[key] = PropertyRecord();
390  entry = propMap.find(key);
391  }
392  yCAssert(NAMESERVER, entry != propMap.end());
393  return &(entry->second);
394  }
395 
396  void clearProp(const std::string& key)
397  {
398  getPR(key)->clear();
399  }
400 
401  void addProp(const std::string& key, const std::string& val)
402  {
403  getPR(key)->add(val);
404  }
405 
406  std::string getProp(const std::string& key)
407  {
408  PropertyRecord* rec = getPR(key, false);
409  if (rec != nullptr) {
410  return rec->toString();
411  }
412  return {};
413  }
414 
415  bool checkProp(const std::string& key, const std::string& val)
416  {
417  PropertyRecord* rec = getPR(key, false);
418  if (rec != nullptr) {
419  return rec->check(val);
420  }
421  return false;
422  }
423 
424  std::string matchProp(const std::string& key, const std::string& val)
425  {
426  PropertyRecord* rec = getPR(key, false);
427  if (rec != nullptr) {
428  return rec->match(val);
429  }
430  return {};
431  }
432  };
433 
434 
435  std::string cmdRegister(int argc, char* argv[]);
436  std::string cmdQuery(int argc, char* argv[]);
437  std::string cmdUnregister(int argc, char* argv[]);
438  std::string cmdAnnounce(int argc, char* argv[]);
439  std::string cmdHelp(int argc, char* argv[]);
440  std::string cmdSet(int argc, char* argv[]);
441  std::string cmdGet(int argc, char* argv[]);
442  std::string cmdCheck(int argc, char* argv[]);
443  std::string cmdMatch(int argc, char* argv[]);
444  std::string cmdList(int argc, char* argv[]);
445  std::string cmdRoute(int argc, char* argv[]);
446  std::string cmdGarbageCollect(int argc, char* argv[]);
447  std::string cmdBot(int argc, char* argv[]);
448 
449  // making a more easy to parse interface
450  yarp::os::Bottle ncmdList(int argc, char* argv[]);
451  yarp::os::Bottle ncmdQuery(int argc, char* argv[]);
452  yarp::os::Bottle ncmdVersion(int argc, char* argv[]);
453  yarp::os::Bottle ncmdSet(int argc, char* argv[]);
454  yarp::os::Bottle ncmdGet(int argc, char* argv[]);
455 
456  std::map<std::string, NameRecord> nameMap;
457  std::map<std::string, HostRecord> hostMap;
458 
459  McastRecord mcastRecord;
460  DisposableNameRecord tmpNames;
461 
462  NameRecord* getNameRecord(const std::string& name, bool create);
463 
464  NameRecord& getNameRecord(const std::string& name)
465  {
466  NameRecord* result = getNameRecord(name, true);
467  yCAssert(NAMESERVER, result != nullptr);
468  return *result;
469  }
470 
471  HostRecord* getHostRecord(const std::string& name, bool create);
472 
473  HostRecord& getHostRecord(const std::string& name)
474  {
475  HostRecord* result = getHostRecord(name, true);
476  yCAssert(NAMESERVER, result != nullptr);
477  return *result;
478  }
479 
480  Dispatcher<NameServer, std::string> dispatcher;
481  Dispatcher<NameServer, yarp::os::Bottle> ndispatcher;
482 
483 protected:
484  std::string terminate(const std::string& str);
485 
486  int basePort;
487 
488 private:
489  std::mutex mutex;
490 };
491 
492 } // namespace impl
493 } // namespace os
494 } // namespace yarp
495 
496 #endif // YARP_OS_IMPL_NAMESERVER_H
const yarp::os::LogComponent & NAMESERVER()
Definition: NameServer.cpp:33
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:76
Represents how to reach a part of a YARP network.
Definition: Contact.h:39
Stub for a YARP2-conforming name server.
Definition: NameServer.h:38
virtual std::string apply(const std::string &txt, const Contact &remote)=0
virtual ~NameServerStub()=default
Implementation of a YARP2-conforming name server.
Definition: NameServer.h:48
std::string apply(const std::string &txt)
Definition: NameServer.h:83
virtual ~NameServer()=default
virtual void onEvent(yarp::os::Bottle &event)
Definition: NameServer.h:88
Contact registerName(const std::string &name, const Contact &address)
Definition: NameServer.h:60
Contact registerName(const std::string &name)
Definition: NameServer.h:70
void setBasePort(int basePort)
Definition: NameServer.h:96
std::string toString(const T &value)
convert an arbitrary type to string.
#define yCInfo(component,...)
Definition: LogComponent.h:135
#define yCAssert(component, x)
Definition: LogComponent.h:172
#define yCTrace(component,...)
Definition: LogComponent.h:88
#define YARP_DECLARE_LOG_COMPONENT(name)
Definition: LogComponent.h:77
std::string to_string(Integer x)
Definition: numeric.h:118
ContainerT split(const typename ContainerT::value_type &s, std::basic_regex< typename ContainerT::value_type::value_type > regex)
Utility to split a string by a separator, into a vector of strings.
Definition: string.h:30
The main, catch-all namespace for YARP.
Definition: environment.h:25
#define YARP_UNUSED(var)
Definition: api.h:159
#define YARP_os_impl_API
Definition: api.h:45