YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
NameClient.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-License-Identifier: BSD-3-Clause
5 */
6
8
10
11#include <yarp/os/Bottle.h>
12#include <yarp/os/Carriers.h>
13#include <yarp/os/NameStore.h>
14#include <yarp/os/NetType.h>
15#include <yarp/os/Network.h>
16#include <yarp/os/Os.h>
22
23#include <cstdio>
24#include <mutex>
25
26using namespace yarp::os::impl;
27using namespace yarp::os;
28
29namespace {
30YARP_OS_LOG_COMPONENT(NAMECLIENT, "yarp.os.impl.NameClient")
31
32/*
33 Old class for splitting string based on spaces
34*/
35class Params
36{
37private:
38 static constexpr size_t MAX_ARG_CT =20;
39 static constexpr size_t MAX_ARG_LEN = 256;
40
41 int argc;
42 const char* argv[MAX_ARG_CT];
43 char buf[MAX_ARG_CT][MAX_ARG_LEN];
44
45public:
46 Params()
47 {
48 argc = 0;
49 for (auto& i : argv) {
50 i = nullptr;
51 }
52 }
53
54 Params(const char* command)
55 {
56 apply(command);
57 }
58
59 int size()
60 {
61 return argc;
62 }
63
64 const char* get(int idx)
65 {
66 return buf[idx];
67 }
68
69 void apply(const char* command)
70 {
71 size_t at = 0;
72 size_t sub_at = 0;
73 unsigned int i;
74 for (i = 0; i < strlen(command) + 1; i++) {
75 if (at < MAX_ARG_CT) {
76 char ch = command[i];
77 if (ch >= 32 || ch == '\0' || ch == '\n') {
78 if (ch == ' ' || ch == '\n') {
79 ch = '\0';
80 }
81 if (sub_at < MAX_ARG_LEN) {
82 buf[at][sub_at] = ch;
83 sub_at++;
84 }
85 }
86 if (ch == '\0') {
87 if (sub_at > 1) {
88 at++;
89 }
90 sub_at = 0;
91 }
92 }
93 }
94 for (i = 0; i < MAX_ARG_CT; i++) {
95 argv[i] = buf[i];
96 buf[i][MAX_ARG_LEN - 1] = '\0';
97 }
98
99 argc = at;
100 }
101};
102} // namespace
103
104
105NameClient::NameClient() :
106 fake(false),
107 fakeServer(nullptr),
108 allowScan(false),
109 allowSaveScan(false),
110 reportScan(false),
111 reportSaveScan(false),
112 isSetup(false),
113 altStore(nullptr)
114{
115}
116
118{
119 if (fakeServer != nullptr) {
120 delete fakeServer;
121 fakeServer = nullptr;
122 }
123}
124
126{
127 static NameClient instance;
128 return instance;
129}
130
132{
133 return new NameClient();
134}
135
136
138{
139 setup();
140 return address;
141}
142
143Contact NameClient::queryName(const std::string& name)
144{
145 size_t i1 = name.find(':');
146 if (i1 != std::string::npos) {
147 Contact c = c.fromString(name);
148 if (c.isValid() && c.getPort() > 0) {
149 return c;
150 }
151 }
152
153 if (altStore != nullptr) {
154 Contact c = altStore->query(name);
155 return c;
156 }
157
158 std::string q("NAME_SERVER query ");
159 q += name;
160 return probe(q);
161}
162
163Contact NameClient::registerName(const std::string& name)
164{
165 return registerName(name, Contact());
166}
167
168Contact NameClient::registerName(const std::string& name, const Contact& suggest)
169{
170 Bottle cmd;
171 cmd.addString("register");
172 if (!name.empty()) {
173 cmd.addString(name);
174 } else {
175 cmd.addString("...");
176 }
177 std::string prefix = yarp::conf::environment::get_string("YARP_IP");
178 const NestedContact& nc = suggest.getNested();
179 std::string typ = nc.getTypeNameStar();
180 if (suggest.isValid() || !prefix.empty() || typ != "*") {
181 if (!suggest.getCarrier().empty()) {
182 cmd.addString(suggest.getCarrier().c_str());
183 } else {
184 cmd.addString("...");
185 }
186 if (!suggest.getHost().empty()) {
187 cmd.addString(suggest.getHost().c_str());
188 } else {
189 if (!prefix.empty()) {
191 for (size_t i = 0; i < ips.size(); i++) {
192 std::string ip = ips.get(i).asString();
193 if (ip.find(prefix) == 0) {
194 prefix = ip;
195 break;
196 }
197 }
198 }
199 cmd.addString((!prefix.empty()) ? prefix : "...");
200 }
201 if (suggest.getPort() != 0) {
202 cmd.addInt32(suggest.getPort());
203 } else {
204 cmd.addString("...");
205 }
206 if (typ != "*") {
207 cmd.addString(typ);
208 }
209 } else {
210 if (!suggest.getCarrier().empty()) {
211 cmd.addString(suggest.getCarrier().c_str());
212 }
213 }
214 Bottle reply;
215
216 yCDebug(NAMECLIENT, "Sending command: %s", cmd.toString().c_str());
217 send(cmd, reply);
218 yCDebug(NAMECLIENT, "Received reply: %s", reply.toString().c_str());
219
220 Contact address = extractAddress(reply);
221 if (address.isValid()) {
222 std::string reg = address.getRegName();
223
224
225 std::string cmdOffers = "set /port offers ";
227 for (size_t i = 0; i < lst.size(); i++) {
228 cmdOffers.append(" ").append(lst.get(i).asString());
229 }
230
231
233 cmd.get(1) = Value(reg);
234 send(cmd, reply);
235
236 // accept the same set of carriers
237 cmd.get(2) = Value("accepts");
238 send(cmd, reply);
239
240 cmd.clear();
241 cmd.addString("set");
242 cmd.addString(reg.c_str());
243 cmd.addString("ips");
245 send(cmd, reply);
246
247 cmd.clear();
248 cmd.addString("set");
249 cmd.addString(reg.c_str());
250 cmd.addString("process");
252 send(cmd, reply);
253 }
254 return address;
255}
256
257Contact NameClient::unregisterName(const std::string& name)
258{
259 std::string q("NAME_SERVER unregister ");
260 q += name;
261 return probe(q);
262}
263
264Contact NameClient::probe(const std::string& cmd)
265{
266 std::string result = send(cmd);
267 return extractAddress(result);
268}
269
270Contact NameClient::extractAddress(const std::string& txt)
271{
272 Params p(txt.c_str());
273 if (p.size() >= 9) {
274 // registration name /bozo ip 5.255.112.225 port 10002 type tcp
275 if (std::string(p.get(0)) == "registration") {
276 const char* regName = p.get(2);
277 const char* ip = p.get(4);
278 int port = atoi(p.get(6));
279 const char* carrier = p.get(8);
280 return Contact(regName, carrier, ip, port);
281 }
282 }
283 return Contact();
284}
285
287{
288 if (bot.size() >= 9) {
289 if (bot.get(0).asString() == "registration") {
290 return Contact(bot.get(2).asString(), // regname
291 bot.get(8).asString(), // carrier
292 bot.get(4).asString(), // ip
293 bot.get(6).asInt32()); // port number
294 }
295 }
296 return Contact();
297}
298
299std::string NameClient::send(const std::string& cmd, bool multi, const ContactStyle& style)
300{
301 yCTrace(NAMECLIENT, "*** OLD YARP command %s", cmd.c_str());
302 setup();
303
304 if (NetworkBase::getQueryBypass() != nullptr) {
305 ContactStyle style;
306 Bottle bcmd(cmd);
307 Bottle reply;
309 std::string si = reply.toString();
310 std::string so;
311 for (char i : si) {
312 if (i != '\"') {
313 so += i;
314 }
315 }
316 return so;
317 }
318 bool retried = false;
319 bool retry = false;
320 std::string result;
322 float timeout = 10;
323 if (style.timeout > 0) {
324 timeout = style.timeout;
325 }
326 server.setTimeout(timeout);
327
328 do {
329
330 yCDebug(NAMECLIENT, "sending to nameserver: %s", cmd.c_str());
331
332 if (isFakeMode()) {
333 yCDebug(NAMECLIENT, "fake mode nameserver");
334 return getServer().apply(cmd, Contact("tcp", "127.0.0.1", NetworkBase::getDefaultPortRange())) + "\n";
335 }
336
338 yCDebug(NAMECLIENT, "connecting to %s", getAddress().toURI().c_str());
339 OutputProtocol* ip = nullptr;
340 if (!retry) {
341 ip = face.write(server);
342 } else {
343 retried = true;
344 }
345 if (ip == nullptr) {
346 yCInfo(NAMECLIENT, "No connection to nameserver");
347 if (!allowScan) {
348 yCInfo(NAMECLIENT, "*** try running: yarp detect ***");
349 }
350 Contact alt;
351 if (!isFakeMode()) {
352 if (allowScan) {
353 yCInfo(NAMECLIENT, "no connection to nameserver, scanning mcast");
354 reportScan = true;
356 }
357 }
358 if (alt.isValid()) {
359 address = alt;
360 if (allowSaveScan) {
361 NameConfig nc;
362 nc.setAddress(alt);
363 if (nc.toFile())
364 {
365 yCInfo(NAMECLIENT, "New configuration stored to file");
366 reportSaveScan = true;
367 }
368 else
369 {
370 yCError(NAMECLIENT, "Unable to write configuration");
371 }
372 }
373 server = getAddress();
374 server.setTimeout(timeout);
375 ip = face.write(server);
376 if (ip == nullptr) {
377 yCError(NAMECLIENT, "no connection to nameserver, scanning mcast");
378 return {};
379 }
380 } else {
381 return {};
382 }
383 }
384 std::string cmdn = cmd + "\n";
385 Bytes b((char*)cmdn.c_str(), cmdn.length());
386 ip->getOutputStream().write(b);
387 ip->getOutputStream().flush();
388 bool more = multi;
389 while (more) {
390 std::string line;
391 line = ip->getInputStream().readLine();
392 if (!(ip->isOk())) {
393 retry = true;
394 break;
395 }
396 if (line.length() > 1) {
397 if (line[0] == '*' || line[0] == '[') {
398 more = false;
399 }
400 }
401 result += line + "\n";
402 }
403 ip->close();
404 delete ip;
405 yCDebug(NAMECLIENT, "<<< received from nameserver: %s", result.c_str());
406 } while (retry && !retried);
407
408 return result;
409}
410
412{
413 setup();
414 if (NetworkBase::getQueryBypass() != nullptr) {
415 ContactStyle style;
416 NetworkBase::writeToNameServer(cmd, reply, style);
417 return true;
418 }
419 if (isFakeMode()) {
420 yCDebug(NAMECLIENT, "fake mode nameserver");
421 return getServer().apply(cmd, reply, Contact("tcp", "127.0.0.1", NetworkBase::getDefaultPortRange()));
422 }
424 ContactStyle style;
425 style.carrier = "name_ser";
426 return NetworkBase::write(server, cmd, reply, style);
427}
428
430{
431 this->fake = fake;
432}
433
435{
436 return fake;
437}
438
440{
441 allowScan = allow;
442}
443
445{
446 allowSaveScan = allow;
447}
448
450{
451 return reportScan;
452}
453
455{
456 return reportSaveScan;
457}
458
460{
461 NameConfig conf;
462 address = Contact();
463 mode = "yarp";
464 if (conf.fromFile()) {
465 address = conf.getAddress();
466 mode = conf.getMode();
467 return true;
468 }
469 return false;
470}
471
473{
474 if (!contact.isValid()) {
475 fake = true;
476 }
477 address = contact;
478 mode = "yarp";
479 isSetup = true;
480 return true;
481}
482
484{
485 altStore = store;
486}
487
489{
490 return altStore;
491}
492
494{
495 return mode;
496}
497
499{
500 return nodes;
501}
502
503NameServer& NameClient::getServer()
504{
505 if (fakeServer == nullptr) {
506 fakeServer = new NameServer;
507 }
508 yCAssert(NAMECLIENT, fakeServer != nullptr);
509 return *fakeServer;
510}
511
512void NameClient::setup()
513{
514 static std::mutex mutex;
515 mutex.lock();
516 if ((!fake) && (!isSetup)) {
517 if (!updateAddress()) {
518 yCError(NAMECLIENT, "Cannot find name server");
519 }
520
521 yCDebug(NAMECLIENT, "name server address is %s", address.toURI().c_str());
522 isSetup = true;
523 }
524 mutex.unlock();
525}
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void fromString(const std::string &text)
Initializes bottle from a string.
Definition Bottle.cpp:204
void append(const Bottle &alt)
Append the content of the given bottle to the current list.
Definition Bottle.cpp:353
size_type size() const
Gets the number of elements in the bottle.
Definition Bottle.cpp:251
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:246
void clear()
Empties the bottle of any objects it contains.
Definition Bottle.cpp:121
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition Bottle.cpp:140
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition Bottle.cpp:170
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition Bottle.cpp:211
A mini-server for performing network communication in the background.
void write(bool forceStrict=false)
Write the current object being returned by BufferedPort::prepare.
A simple abstraction for a block of bytes.
Definition Bytes.h:24
static Bottle listCarriers()
Definition Carriers.cpp:317
Preferences for how to communicate with a contact.
double timeout
Set a timeout for communication (in units of seconds, fractional seconds allowed).
std::string carrier
Request that communication be made using a particular carrier.
Represents how to reach a part of a YARP network.
Definition Contact.h:33
bool isValid() const
Checks if a Contact is tagged as valid.
Definition Contact.cpp:298
std::string getRegName() const
Get the name associated with this Contact.
Definition Contact.cpp:217
std::string toURI(bool includeCarrier=true) const
Get a representation of the Contact as a URI.
Definition Contact.cpp:313
Abstract interface for a database of port names.
Definition NameStore.h:19
virtual Contact query(const std::string &name)=0
A placeholder for rich contact information.
std::string getTypeNameStar() const
static NameStore * getQueryBypass()
Definition Network.cpp:1405
static int getDefaultPortRange()
Under normal operation, YARP has a name server that manages a pool of (socket) ports starting at a po...
Definition Network.cpp:1961
static bool writeToNameServer(PortWriter &cmd, PortReader &reply, const ContactStyle &style)
Variant write method specialized to name server.
Definition Network.cpp:1942
static bool write(const Contact &contact, PortWriter &cmd, PortReader &reply, bool admin=false, bool quiet=false, double timeout=-1)
Send a single command to a port and await a single response.
Definition Network.cpp:1219
The Nodes class.
Definition Nodes.h:29
The output side of an active connection between two ports.
virtual OutputStream & getOutputStream()=0
Access the output stream associated with the connection.
virtual void close()=0
Negotiate an end to operations.
virtual InputStream & getInputStream()=0
Access the input stream associated with the connection.
virtual bool isOk() const =0
Check if the connection is valid and can be used.
A single value (typically within a Bottle).
Definition Value.h:43
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition Value.cpp:204
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
Client for YARP name server.
Definition NameClient.h:33
Contact unregisterName(const std::string &name)
Register disassociation of name from port.
static NameClient & getNameClient()
Get an instance of the name client.
bool didScan()
Check whether the name client scanned for the address of the name server.
yarp::os::Nodes & getNodes()
static NameClient * create()
Contact probe(const std::string &cmd)
Send a message to the name server, and interpret the result as an address.
static Contact extractAddress(const std::string &txt)
Extract an address from its text representation.
bool didSave()
Check whether the name client saved the address of the name server.
void queryBypass(NameStore *store)
Contact getAddress()
The address of the name server.
bool updateAddress()
Force the name client to reread the cached location of the name server.
bool setContact(const yarp::os::Contact &contact)
std::string send(const std::string &cmd, bool multi=true, const ContactStyle &style=ContactStyle())
Send a text message to the nameserver, and return the result.
Contact queryName(const std::string &name)
Look up the address of a named port.
void setFakeMode(bool fake=true)
For testing, the nameclient can be set to use a "fake" name server rather than communicating with an ...
bool isFakeMode() const
Check whether a fake name server is being used.
virtual ~NameClient()
Destructor.
void setScan(bool allow=true)
Control whether the name client should scan for the name server if the cached connection information ...
Contact registerName(const std::string &name)
Register a port with a given name.
void setSave(bool allow=true)
Control whether the name client can save the address of the name server in a cache file.
Small helper class to help deal with legacy YARP configuration files.
Definition NameConfig.h:23
bool fromFile(const char *ns=nullptr)
static yarp::os::Bottle getIpsAsBottle()
void setAddress(const Contact &address)
bool toFile(bool clean=false)
Implementation of a YARP2-conforming name server.
Definition NameServer.h:43
std::string apply(const std::string &txt, const Contact &remote) override
Communicating with a port via TCP.
Definition TcpFace.h:22
#define yCInfo(component,...)
#define yCError(component,...)
#define yCAssert(component, x)
#define yCTrace(component,...)
#define yCDebug(component,...)
#define YARP_OS_LOG_COMPONENT(name, name_string)
std::string get_string(const std::string &key, bool *found=nullptr)
Read a string from an environment variable.
Definition environment.h:66
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.
int getpid()
Portable wrapper for the getppid() function.
Definition Os.cpp:84