YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
NameServiceOnTriples.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
7#include <cstdlib>
8
9#include <yarp/os/Vocab.h>
11#include <yarp/os/Network.h>
12#include <yarp/os/Time.h>
13#include <yarp/os/SystemClock.h>
17
18using namespace yarp::os;
19using namespace yarp::serversql::impl;
20
21namespace {
22YARP_SERVERSQL_LOG_COMPONENT(NAMESERVICEONTRIPLES, "yarp.serversql.impl.NameServiceOnTriples")
23} // namespace
24
25
26Contact NameServiceOnTriples::query(const std::string& portName,
28 const std::string& prefix,
29 bool nested)
30{
31 if (!nested) {
32 lock();
33 }
34 Triple t;
35 t.setNameValue("port",portName.c_str());
36 int result = act.mem.find(t, nullptr);
37 TripleContext context;
38 context.setRid(result);
39 if (result!=-1) {
40 std::string host;
41 if (!std::string(prefix).empty()) {
42 printf("LOOKING AT IPS FOR %s\n", prefix.c_str());
43 t.setNameValue("ips","*");
44 std::list<Triple> lst = act.mem.query(t,&context);
45 for (auto& it : lst) {
46 printf("LOOKING AT IPS %s\n", it.value.c_str());
47 if (it.value.find(prefix)==0) {
48 host = it.value;
49 break;
50 }
51 }
52 }
53 if (host.empty()) {
54 t.setNameValue("host","*");
55 std::list<Triple> lst = act.mem.query(t,&context);
56 if (!lst.empty()) {
57 host = lst.begin()->value;
58 }
59 }
60 if (host.empty()) {
61 host = "localhost";
62 }
63 t.setNameValue("socket","*");
64 std::list<Triple> lst = act.mem.query(t,&context);
65 int sock = 10000;
66 if (!lst.empty()) {
67 sock = atoi(lst.begin()->value.c_str());
68 }
69 t.setNameValue("carrier","*");
70 std::string carrier = "tcp";
71 lst = act.mem.query(t,&context);
72 if (!lst.empty()) {
73 carrier = lst.begin()->value;
74 }
75 t.setNameValue("type","*");
76 std::string typ = "*";
77 lst = act.mem.query(t,&context);
78 if (!lst.empty()) {
79 typ = lst.begin()->value;
80 }
81 if (!nested) {
82 unlock();
83 }
84 Contact result = Contact(portName, carrier, host, sock);
85 if (!typ.empty() && typ!="*") {
87 nc.fromString(result.getName());
88 nc.setTypeName(typ);
89 result.setNestedContact(nc);
90 }
91 return result;
92 }
93 if (!nested) {
94 unlock();
95 }
96 if (delegate && !nested) {
97 return delegate->queryName(portName);
98 }
99 return Contact();
100}
101
102
104{
105 Contact check = Contact::fromString(port);
106 if (!check.getHost().empty()) {
107 return check;
108 }
109 Bottle cmd;
110 Bottle reply;
111 Bottle event;
112 Contact remote;
113 TripleSource& mem = *db;
114 NameTripleState act(cmd,reply,event,remote,mem);
115 return query(port,act,"");
116}
117
118
120{
121 std::string port = act.cmd.get(1).asString();
122
123 ParseName parser;
124 parser.apply(port);
125 port = parser.getPortName();
126
127 /*
128 // port names may be prefixed - sort that out
129 std::string base = port;
130 std::string pat = "";
131 if (base.find("/net=") == 0 || base.find("/NET=") == 0) {
132 int patStart = 5;
133 int patEnd = base.find('/',patStart);
134 if (patEnd>=patStart) {
135 pat = base.substr(patStart,patEnd-patStart);
136 base = base.substr(patEnd);
137 }
138 port = base;
139 }
140 */
141
142 if (act.reply.size()==0 && !act.bottleMode) {
143 act.reply.addString("old");
144 }
145 Bottle& q=(act.bottleMode&&!act.nestedMode)?
146 act.reply :
147 act.reply.addList();
148 Contact c = query(port, act, parser.getNetworkChoice(), nested);
149 std::string host = c.getHost();
150 std::string carrier = c.getCarrier();
151 int sock = c.getPort();
152 if (c.isValid()) {
153 if (!act.bottleMode) {
154 q.addString("registration");
155 q.addString("name");
156 q.addString(port);
157 q.addString("ip");
158 q.addString(host);
159 q.addString("port");
160 q.addInt32(sock);
161 q.addString("type");
162 q.addString(carrier);
163 } else {
165 bname.addString("name");
166 bname.addString(port);
167 Bottle bip;
168 bip.addString("ip");
169 bip.addString(host);
170 Bottle bnum;
171 bnum.addString("port_number");
172 bnum.addInt32(sock);
174 bcarrier.addString("carrier");
175 bcarrier.addString(carrier);
176 q.addString("port");
177 q.addList() = bname;
178 q.addList() = bip;
179 q.addList() = bnum;
180 q.addList() = bcarrier;
181 }
182 } else {
183 if (act.bottleMode) {
185 bstate.addString("error");
186 bstate.addInt32(-2);
187 bstate.addString("port not known");
188 q.addString("port");
189 q.addList() = bstate;
190 }
191 }
192 return true;
193}
194
196{
197 std::string port = act.cmd.get(1).asString();
198
199 lock();
200 Triple t;
201 t.setNameValue("port",port.c_str());
202 int result = act.mem.find(t, nullptr);
203 unlock();
204
205 if (result!=-1) {
206 // Hmm, we already have a registration.
207 // This could be fine - maybe program crashed or was abruptly
208 // terminated. Classically, that is what YARP would assume.
209 // Now, let us try checking instead to see if there is a port
210 // alive at the registered address. Note that this can lead
211 // to delays...
212#if 0
213 Contact c = query(port.c_str());
214 if (c.isValid()) {
215 if (gonePublic) {
216 printf(" ? checking prior registration, to avoid accidental collision\n");
217 Bottle cmd("[ver]"), reply;
218 double timeout = 3.0;
219 double pre = SystemClock::nowSystem();
220 bool ok = Network::write(c,cmd,reply,true,true,timeout);
221 double post = SystemClock::nowSystem();
222 if (post-pre>timeout-1) {
223 ok = false;
224 }
225 if (ok) {
226 printf(" ? prior registration seems to be live! Denying new registration.\n");
227 /*
228 printf("Got a live one! %s - said %s\n",
229 port.c_str(),
230 reply.toString().c_str());
231 */
232 // oops! there is a live port!
233 // give back a blank query
234 act.cmd.fromString("query");
235 return cmdQuery(act);
236 } else {
237 printf(" ! prior registration seems to be no longer valid, good!\n");
238 }
239 }
240 }
241#endif
243 act.reply.clear();
244 }
245
246 act.reply.addString("old");
247
248 size_t at = 2;
249 int sock = -1;
250 std::string carrier = "...";
251 std::string machine = "...";
252 std::string typ = "*";
253 if (act.cmd.size()>at) {
254 carrier = act.cmd.get(at).asString();
255 at++;
256 }
257 if (carrier=="...") {
258 carrier = "tcp";
259 }
260 if (act.cmd.size()>at) {
261 machine = act.cmd.get(at).asString();
262 at++;
263 }
264 if (machine == "...") {
265 if (carrier=="topic") {
266 machine = serverContact.getHost();
267 } else if (carrier!="mcast") {
268 std::string remote = act.remote.getHost();
269 if (remote.empty() || remote == "...") {
270 //fprintf(stderr,"Not detecting real remote machine name, guessing local\n");
271 machine = "localhost";
272 } else {
273 machine = remote;
274 }
275 }
276 }
277 if (act.cmd.size()>at) {
278 sock = act.cmd.get(at).asInt32();
279 at++;
280 } else {
281 if (carrier=="topic") {
282 sock = serverContact.getPort();
283 }
284 }
285 if (act.cmd.size()>at) {
286 typ = act.cmd.get(at).asString();
287 at++;
288 }
289 lock();
290 if (port=="..." || (port.length()>0 && port[0]=='=')) {
291 Contact c(port, carrier, machine, sock);
292 c = alloc->completePortName(c);
293 if (port =="...") {
294 port = c.getName();
295 } else {
296 port = c.getName() + port;
297 }
298 }
299 t.setNameValue("port",port.c_str());
300 act.mem.remove_query(t, nullptr);
301 act.mem.insert(t, nullptr);
302 result = act.mem.find(t, nullptr);
303 TripleContext context;
304 context.setRid(result);
305 t.setNameValue("carrier",carrier.c_str());
306 act.mem.update(t,&context);
307 char buf[100];
308 Contact c(port, carrier, machine, sock);
309 c = alloc->completeSocket(c);
310 sock = c.getPort();
311 machine = c.getHost();
312 t.setNameValue("host",machine.c_str());
313 act.mem.update(t,&context);
314 sprintf(buf,"%d",sock);
315 t.setNameValue("socket",buf);
316 act.mem.update(t,&context);
317 if (typ!="*") {
318 t.setNameValue("type",typ.c_str());
319 act.mem.update(t,&context);
320 }
321 // now, query to report that it worked
322 act.mem.reset();
323 act.cmd.clear();
324 act.cmd.addString("query");
325 act.cmd.addString(port);
326
327 if (carrier!="mcast") {
328 Bottle& event = act.event.addList();
329 event.addVocab32("add");
330 event.addString(port);
331 }
332 unlock();
333
334 return cmdQuery(act);
335}
336
337
338bool NameServiceOnTriples::announce(const std::string& name, int activity)
339{
340 if (subscriber != nullptr && gonePublic) {
341 subscriber->welcome(name,activity);
342 }
343 return true;
344}
345
347{
348 std::string port = act.cmd.get(1).asString();
349 //printf(" - unregister %s\n", port.c_str());
350 announce(port,-1);
351 lock();
352 Contact contact = query(port,act,"",true);
353 alloc->freePortResources(contact);
354 act.reply.addString("old");
355 Triple t;
356 t.setNameValue("port",port.c_str());
357 int result = act.mem.find(t, nullptr);
358 TripleContext context;
359 context.setRid(result);
360 if (result!=-1) {
361 t.setNameValue("owns","*");
362 std::list<Triple> lst = act.mem.query(t,&context);
363 unlock();
364 for (auto& it : lst) {
365 act.cmd.clear();
366 act.cmd.addString("unregister");
367 act.cmd.addString(it.value.c_str());
369 }
370 lock();
371 t.setNsNameValue("*","*","*");
372 act.mem.remove_query(t,&context);
373
374 t.setNameValue("port",port.c_str());
375 act.mem.remove_query(t, nullptr);
376 // now, query to report that there is nothing there
377
378 if (contact.getCarrier()!="mcast") {
379 Bottle& event = act.event.addList();
380 event.addVocab32("del");
381 event.addString(port);
382 }
383 }
384
385 act.mem.reset();
386 unlock();
387
388 return cmdQuery(act);
389}
390
392{ // this is a combination of cmdList and cmdCheck codes
393 if (!act.bottleMode)
394 {
395 act.reply.addString("old");
396 } else
397 {
398 act.reply.addString("ports");
399 }
400 lock();
401 Triple t;
402 t.setNameValue("port","*");
403
404 // obtain all ports names
405 std::list<Triple> lst = act.mem.query(t, nullptr);
406 act.nestedMode = true;
407
408 for (auto& it : lst)
409 { // check yarprun property for each port
410 std::string port = it.value;
411 act.mem.reset();
412
413 Triple t;
414 t.setNameValue("port",port.c_str());
415 int rid = act.mem.find(t, nullptr);
416 if (rid == -1) {
417 unlock();
418 return false;
419 }
420
421 // find all triples with yarprun = true for the specified RID (at most one)
422 TripleContext context;
423 context.setRid(rid);
424 t.setNameValue("yarprun","true");
425 std::list<Triple> lst = act.mem.query(t,&context);
426
427 if (!lst.empty())
428 { // if the port is a runner, do a classic query to build the reply with complete information about the port
429 act.cmd.clear();
430 act.cmd.addString("query");
431 act.cmd.addString(port);
432 act.mem.reset();
433 cmdQuery(act, true);
434 }
435 }
436 unlock();
437 return true;
438}
439
441{
442 if (!act.bottleMode) {
443 act.reply.addString("old");
444 } else {
445 act.reply.addString("ports");
446 }
447 lock();
448 Triple t;
449 t.setNameValue("port","*");
450 std::string prefix;
451 if (act.cmd.size()>1) {
452 prefix = act.cmd.get(1).asString();
453 }
454 std::list<Triple> lst = act.mem.query(t, nullptr);
455 act.nestedMode = true;
456 for (auto& it : lst) {
457 if (prefix.empty()) {
458 act.cmd.clear();
459 act.cmd.addString("query");
460 act.cmd.addString(it.value.c_str());
461 act.mem.reset();
462 cmdQuery(act,true);
463 } else {
464 std::string iname = it.value;
465 if (iname.find(prefix)==0) {
466 if (iname==prefix || iname[prefix.length()]=='/' ||
467 prefix[prefix.length()-1]=='/') {
468 act.cmd.clear();
469 act.cmd.addString("query");
470 act.cmd.addString(iname);
471 act.mem.reset();
472 cmdQuery(act,true);
473 }
474 }
475 }
476 }
477 unlock();
478 return true;
479}
480
481
483{
484 lock();
485 if (!act.bottleMode) {
486 act.reply.addString("old");
487 }
488 std::string port = act.cmd.get(1).asString();
489 std::string key = act.cmd.get(2).toString();
490 int at = 3;
491 int n = act.cmd.size() - at;
492 Triple t;
493 t.setNameValue("port", port.c_str());
494 int result = act.mem.find(t, nullptr);
495 if (result==-1) {
496 unlock();
497 return false;
498 }
499 TripleContext context;
500 context.setRid(result);
501 t.setNameValue(key.c_str(),"*");
502 act.mem.remove_query(t,&context);
503 for (int i=0; i<n; i++) {
504 t.setNameValue(key.c_str(),act.cmd.get(at).toString().c_str());
505 at++;
506 act.mem.insert(t,&context);
507 }
508 act.mem.reset();
509 act.cmd.clear();
510 act.cmd.addString("get");
511 act.cmd.addString(port);
512 act.cmd.addString(key);
513 unlock();
514 return cmdGet(act);
515}
516
517
519{
520 lock();
521 if (!act.bottleMode) {
522 if (act.reply.size()==0) {
523 act.reply.addString("old");
524 }
525 }
526 std::string port = act.cmd.get(1).asString();
527 std::string key = act.cmd.get(2).toString();
528 Triple t;
529 t.setNameValue("port",port.c_str());
530 int result = act.mem.find(t, nullptr);
531 if (result==-1) {
532 unlock();
533 return false;
534 }
535 TripleContext context;
536 context.setRid(result);
537 t.setNameValue(key.c_str(),"*");
538 std::list<Triple> lst = act.mem.query(t,&context);
539 Bottle& q = (act.bottleMode?act.reply:act.reply.addList());
540 if (!act.bottleMode) {
541 q.addString("port");
542 q.addString(port);
543 q.addString("property");
544 q.addString(key);
545 q.addString("=");
546 for (auto& it : lst) {
547 q.addString(it.value.c_str());
548 }
549 } else {
550 for (auto& it : lst) {
551 Value v;
552 v.fromString(it.value.c_str());
553 q.add(v);
554 }
555 }
556 unlock();
557 return true;
558}
559
560
562{
563 lock();
564 if (act.reply.size()==0) {
565 act.reply.addString("old");
566 }
567 std::string port = act.cmd.get(1).asString();
568 std::string key = act.cmd.get(2).toString();
569 std::string val = act.cmd.get(3).toString();
570 Triple t;
571 t.setNameValue("port",port.c_str());
572 int result = act.mem.find(t, nullptr);
573 if (result==-1) {
574 unlock();
575 return false;
576 }
577 TripleContext context;
578 context.setRid(result);
579 t.setNameValue(key.c_str(),"*");
580 std::list<Triple> lst = act.mem.query(t,&context);
581 Bottle& q = act.reply.addList();
582 q.addString("port");
583 q.addString(port);
584 q.addString("property");
585 q.addString(key);
586 q.addString("value");
587 q.addString(val);
588 q.addString("present");
589 std::string present = "false";
590 for (auto& it : lst) {
591 if (val == it.value) {
592 present = "true";
593 }
594 }
596 unlock();
597 return true;
598}
599
600
602{
603 if (act.reply.size()==0) {
604 act.reply.addString("old");
605 }
606 std::string port1 = act.cmd.get(1).asString();
607 std::string port2 = act.cmd.get(2).asString();
608 Bottle& q = act.reply.addList();
609 q.addString("port");
610 q.addString(port1);
611 q.addString("route");
612 q.addString(port2);
613 q.addString("=");
614 q.addString(std::string("tcp:/") + port2);
615 return true;
616}
617
619{
620 act.reply.addString("old");
621 Bottle& q = act.reply.addList();
622 // nothing needed
623 q.addString("garbage collection done.");
624 return true;
625}
626
627
629{
630 Bottle& bot = act.reply;
631 if (!act.bottleMode) {
632 bot.addString("old");
633 bot.addString("Here are some ways to use the name server:");
634 }
635 bot.addString("+ help");
636 bot.addString("+ list [$prefix]");
637 bot.addString("+ register $portname");
638 bot.addString("+ register $portname $carrier $ipAddress $portNumber");
639 bot.addString(" (if you want a field set automatically, write '...')");
640 bot.addString("+ unregister $portname");
641 bot.addString("+ query $portname");
642 bot.addString("+ set $portname $property $value");
643 bot.addString("+ get $portname $property");
644 bot.addString("+ check $portname $property");
645 bot.addString("+ route $port1 $port2");
646 bot.addString("+ runners");
647 bot.addString(" (to get a list of the yarprun ports)");
648 return true;
649}
650
652 yarp::os::Bottle& reply,
653 yarp::os::Bottle& event,
654 const yarp::os::Contact& remote)
655{
656 std::string key = cmd.get(0).toString();
657 std::string prefix = " * ";
658
659 access.wait();
660 if (key=="register") {
661 lastRegister = cmd.get(1).asString();
662 } else if (key=="set") {
663 if (cmd.get(1).asString()==lastRegister) {
664 prefix = " + ";
665 }
666 } else {
667 lastRegister = "";
668 }
669 if (!silent) {
670 yCInfo(NAMESERVICEONTRIPLES, "%s%s", prefix.c_str(), cmd.toString().c_str());
671 }
672 access.post();
673
674 TripleSource& mem = *db;
675 //mem.begin();
676 mem.reset();
677 reply.clear();
678 NameTripleState act(cmd,reply,event,remote,mem);
679
680 if (cmd.check("format")) {
681 if (cmd.find("format").asString()=="json") {
682 act.bottleMode = true;
683 }
684 }
685
686 if (key == "NAME_SERVER") {
687 cmd = cmd.tail();
688 key = cmd.get(0).asString();
689 }
690 if (key == "bot") {
691 act.bottleMode = true;
692 cmd = cmd.tail();
693 key = cmd.get(0).asString();
694 }
695
696 if (key=="register") {
697 return cmdRegister(act);
698 }
699 if (key=="unregister") {
700 return cmdUnregister(act);
701 }
702 if (key=="query") {
703 return cmdQuery(act);
704 }
705 if (key=="list") {
706 return cmdList(act);
707 }
708 if (key=="runners") {
709 return cmdListRunners(act);
710 }
711 if (key=="set") {
712 return cmdSet(act);
713 }
714 if (key=="get") {
715 return cmdGet(act);
716 }
717 if (key=="check") {
718 return cmdCheck(act);
719 }
720 if (key=="route") {
721 return cmdRoute(act);
722 }
723 if (key=="gc") {
724 return cmdGc(act);
725 }
726 if (key=="help") {
727 return cmdHelp(act);
728 }
729
730 // not understood
731 act.reply.addString("old");
732
733 //mem.end();
734
735 return true;
736}
737
738
739
741{
742 mutex.lock();
743 db->begin(nullptr);
744}
745
747{
748 db->end(nullptr);
749 mutex.unlock();
750}
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void add(const Value &value)
Add a Value to the bottle, at the end of the list.
Definition Bottle.cpp:309
Bottle & addList()
Places an empty nested list in the bottle, at the end of the list.
Definition Bottle.cpp:182
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:246
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition Bottle.cpp:277
Bottle tail() const
Get all but the first element of a bottle.
Definition Bottle.cpp:361
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
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition Bottle.cpp:287
A mini-server for performing network communication in the background.
std::string getName() const override
Get name of port.
Represents how to reach a part of a YARP network.
Definition Contact.h:33
void setNestedContact(const yarp::os::NestedContact &nestedContact)
Sets the NestedContact containing extra information for this Contact.
Definition Contact.cpp:266
std::string getName() const
Get the name associated with this Contact.
Definition Contact.cpp:205
static Contact fromString(const std::string &txt)
Factory method.
Definition Contact.cpp:139
int getPort() const
Get the port number associated with this Contact for socket communication.
Definition Contact.cpp:239
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
virtual Contact queryName(const std::string &name)=0
Map from port name to contact information.
A placeholder for rich contact information.
bool fromString(const std::string &nFullName)
void setTypeName(const std::string &nWireType)
void wait()
Decrement the counter, even if we must wait to do that.
Definition Semaphore.cpp:96
void post()
Increment the counter.
static double nowSystem()
A single value (typically within a Bottle).
Definition Value.h:43
std::string toString() const override
Return a standard text representation of the content of the object.
Definition Value.cpp:356
void fromString(const char *str)
Set value to correspond to a textual representation.
Definition Value.cpp:351
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
virtual yarp::os::Contact completePortName(const yarp::os::Contact &c)=0
virtual yarp::os::Contact completeSocket(const yarp::os::Contact &c)=0
virtual bool freePortResources(const yarp::os::Contact &c)=0
bool cmdQuery(NameTripleState &act, bool nested=false)
bool apply(yarp::os::Bottle &cmd, yarp::os::Bottle &reply, yarp::os::Bottle &event, const yarp::os::Contact &remote) override
bool announce(const std::string &name, int activity) override
yarp::os::Contact query(const std::string &portName, NameTripleState &act, const std::string &prefix, bool nested=false)
State information for a single name server operation on a database.
void apply(const std::string &str)
Definition ParseName.cpp:13
virtual bool welcome(const std::string &port, int activity)=0
Side information for controlling access to triples.
Abstract view of a database as a collection of triples.
virtual void end(TripleContext *context)=0
virtual void begin(TripleContext *context)=0
The basic unit of data the name server works with.
Definition Triple.h:23
void setNsNameValue(const char *ns, const char *name, const char *value)
Definition Triple.h:116
void setNameValue(const char *name, const char *value)
Definition Triple.h:123
#define yCInfo(component,...)
#define YARP_SERVERSQL_LOG_COMPONENT(name, name_string)
An interface to the operating system, including Port based communication.