39 #define STR(x) STR_HELP(x).c_str()
55 NameRecord& rec = getNameRecord(prev.
getRegName());
56 if (rec.isReusablePort()) {
57 HostRecord& host = getHostRecord(prev.
getHost());
60 if (rec.isReusableIp()) {
61 if (rec.getAddress().getCarrier() ==
"mcast") {
62 mcastRecord.releaseAddress(rec.getAddress().getHost().c_str());
66 tmpNames.release(name);
70 event.addString(name.c_str());
75 return queryName(name);
81 const std::string& remote)
83 bool reusablePort =
false;
84 bool reusableIp =
false;
95 suggestion =
Contact(name,
"...",
"...", 0);
98 std::string portName = name;
99 if (portName ==
"...") {
100 portName = tmpNames.get();
103 std::string carrier = suggestion.
getCarrier();
104 if (carrier ==
"...") {
108 std::string machine = suggestion.
getHost();
109 int overridePort = 0;
110 if (machine ==
"...") {
111 if (carrier !=
"mcast") {
112 if (remote ==
"...") {
113 yCError(
NAMESERVER,
"remote machine name was not found! can only guess it is local...");
114 machine =
"127.0.0.1";
119 machine = mcastRecord.get();
120 overridePort = mcastRecord.lastPortNumber();
125 int port = suggestion.
getPort();
127 if (overridePort != 0) {
130 port = getHostRecord(machine).get();
135 suggestion =
Contact(portName, carrier, machine, port);
139 NameRecord& nameRecord = getNameRecord(suggestion.
getRegName());
140 nameRecord.setAddress(suggestion, reusablePort, reusableIp);
144 event.addString(suggestion.
getRegName().c_str());
147 return nameRecord.getAddress();
153 std::string base = name;
155 if (name.find(
"/net=") == 0) {
156 constexpr
size_t patStart = 5;
157 size_t patEnd = name.find(
'/', patStart);
158 if (patEnd >= patStart && patEnd != std::string::npos) {
159 pat = name.substr(patStart, patEnd - patStart);
160 base = name.substr(patEnd);
161 yCDebug(
NAMESERVER,
"Special query form %s (%s/%s)", name.c_str(), pat.c_str(), base.c_str());
165 NameRecord* rec = getNameRecord(base,
false);
166 if (rec !=
nullptr) {
168 std::string ip = rec->matchProp(
"ips", pat);
176 return rec->getAddress();
182 NameServer::NameRecord* NameServer::getNameRecord(
const std::string& name,
185 auto entry = nameMap.find(name);
186 if (entry == nameMap.end()) {
190 nameMap.emplace(name, NameRecord());
191 entry = nameMap.find(name);
194 return &(entry->second);
198 NameServer::HostRecord* NameServer::getHostRecord(
const std::string& name,
201 auto entry = hostMap.find(name);
202 if (entry == hostMap.end()) {
206 hostMap[name] = HostRecord();
207 entry = hostMap.find(name);
208 entry->second.setBase(basePort);
211 return &(entry->second);
224 void NameServer::setup()
229 dispatcher.add(
"register", &NameServer::cmdRegister);
230 dispatcher.add(
"unregister", &NameServer::cmdUnregister);
231 dispatcher.add(
"query", &NameServer::cmdQuery);
232 dispatcher.add(
"help", &NameServer::cmdHelp);
233 dispatcher.add(
"set", &NameServer::cmdSet);
234 dispatcher.add(
"get", &NameServer::cmdGet);
235 dispatcher.add(
"check", &NameServer::cmdCheck);
236 dispatcher.add(
"match", &NameServer::cmdMatch);
237 dispatcher.add(
"list", &NameServer::cmdList);
238 dispatcher.add(
"route", &NameServer::cmdRoute);
239 dispatcher.add(
"gc", &NameServer::cmdGarbageCollect);
240 dispatcher.add(
"bot", &NameServer::cmdBot);
241 dispatcher.add(
"announce", &NameServer::cmdAnnounce);
243 ndispatcher.add(
"list", &NameServer::ncmdList);
244 ndispatcher.add(
"query", &NameServer::ncmdQuery);
245 ndispatcher.add(
"version", &NameServer::ncmdVersion);
246 ndispatcher.add(
"set", &NameServer::ncmdSet);
247 ndispatcher.add(
"get", &NameServer::ncmdGet);
250 std::string NameServer::cmdRegister(
int argc,
char* argv[])
253 std::string remote = argv[0];
258 return "need at least one argument";
260 std::string portName =
STR(argv[0]);
262 std::string machine =
"...";
263 std::string carrier =
"...";
272 if (std::string(
"...") == argv[3]) {
275 port = yarp::conf::numeric::from_string<int>(argv[3]);
279 Contact address = registerName(portName,
Contact(portName, carrier, machine, port), remote);
283 return terminate(textify(address));
287 std::string NameServer::cmdQuery(
int argc,
char* argv[])
294 return "need at least one argument";
296 std::string portName =
STR(argv[0]);
297 Contact address = queryName(portName);
298 return terminate(textify(address));
301 std::string NameServer::cmdUnregister(
int argc,
char* argv[])
308 return "need at least one argument";
310 std::string portName =
STR(argv[0]);
311 Contact address = unregisterName(portName);
312 return terminate(textify(address));
316 std::string NameServer::cmdAnnounce(
int argc,
char* argv[])
322 return terminate(
"ok\n");
325 std::string NameServer::cmdRoute(
int argc,
char* argv[])
332 return terminate(
"need at least two arguments: the source port and the target port\n(followed by an optional list of carriers in decreasing order of desirability)");
334 std::string src =
STR(argv[0]);
335 std::string dest =
STR(argv[1]);
340 const char* altArgv[] = {
351 argv = (
char**)altArgv;
355 NameRecord& srcRec = getNameRecord(src);
356 NameRecord& destRec = getNameRecord(dest);
359 for (
int i = 0; i < argc; i++) {
360 std::string carrier = argv[i];
361 if (srcRec.checkProp(
"offers", carrier) && destRec.checkProp(
"accepts", carrier)) {
363 if (carrier ==
"local" || carrier ==
"shmem") {
364 if (srcRec.getProp(
"ips") == destRec.getProp(
"ips")) {
365 if (carrier ==
"local") {
366 if (srcRec.getProp(
"process") != destRec.getProp(
"process")) {
381 pref = pref +
":/" + dest;
386 std::string result =
"port ";
387 result += src +
" route " + dest +
" = " + pref +
"\n";
388 return terminate(result);
392 std::string NameServer::cmdHelp(
int argc,
char* argv[])
398 std::string result =
"Here are some ways to use the name server:\n";
404 result += std::string(
"+ help\n");
405 result += std::string(
"+ list\n");
406 result += std::string(
"+ register $portname\n");
407 result += std::string(
"+ register $portname $carrier $ipAddress $portNumber\n");
408 result += std::string(
" (if you want a field set automatically, write '...')\n");
409 result += std::string(
"+ unregister $portname\n");
410 result += std::string(
"+ query $portname\n");
411 result += std::string(
"+ set $portname $property $value\n");
412 result += std::string(
"+ get $portname $property\n");
413 result += std::string(
"+ check $portname $property\n");
414 result += std::string(
"+ match $portname $property $prefix\n");
415 result += std::string(
"+ route $port1 $port2\n");
416 result += std::string(
"+ gc\n");
417 return terminate(result);
421 std::string NameServer::cmdSet(
int argc,
char* argv[])
428 return "need at least two arguments: the port name, and a key";
430 std::string target =
STR(argv[0]);
431 std::string key = argv[1];
432 NameRecord& nameRecord = getNameRecord(target);
433 nameRecord.clearProp(key);
434 for (
int i = 2; i < argc; i++) {
435 nameRecord.addProp(key, argv[i]);
437 return terminate(std::string(
"port ") + target +
" property " + key +
" = " + nameRecord.getProp(key) +
"\n");
440 std::string NameServer::cmdGet(
int argc,
char* argv[])
447 return "need exactly two arguments: the port name, and a key";
449 std::string target =
STR(argv[0]);
450 std::string key = argv[1];
451 NameRecord& nameRecord = getNameRecord(target);
452 return terminate(std::string(
"port ") + target +
" property " + key +
" = " + nameRecord.getProp(key) +
"\n");
455 std::string NameServer::cmdMatch(
int argc,
char* argv[])
462 return "need exactly three arguments: the port name, a key, and a prefix";
464 std::string target =
STR(argv[0]);
465 std::string key = argv[1];
466 std::string prefix = argv[2];
467 NameRecord& nameRecord = getNameRecord(target);
468 return terminate(std::string(
"port ") + target +
" property " + key +
" = " + nameRecord.matchProp(key, prefix) +
"\n");
471 std::string NameServer::cmdCheck(
int argc,
char* argv[])
478 return "need at least two arguments: the port name, and a key";
480 std::string response;
481 std::string target =
STR(argv[0]);
482 std::string key = argv[1];
483 NameRecord& nameRecord = getNameRecord(target);
484 for (
int i = 2; i < argc; i++) {
485 std::string val =
"false";
486 if (nameRecord.checkProp(key, argv[i])) {
492 response.append(
"port ").append(target).append(
" property ").append(key).append(
" value ").append(argv[i]).append(
" present ").append(val);
495 return terminate(response);
499 std::string NameServer::cmdList(
int argc,
char* argv[])
503 std::string response;
505 std::multiset<std::string> lines;
506 for (
auto& it : nameMap) {
507 NameRecord& rec = it.second;
508 lines.insert(textify(rec.getAddress()));
512 for (
const auto& line : lines) {
516 return terminate(response);
520 std::string NameServer::cmdBot(
int argc,
char* argv[])
526 std::string key = argv[0];
529 Bottle result = ndispatcher.dispatch(
this, key.c_str(), argc, argv);
536 Bottle NameServer::ncmdList(
int argc,
char* argv[])
543 prefix =
STR(argv[0]);
547 for (
auto& it : nameMap) {
548 NameRecord& rec = it.second;
549 std::string iname = rec.getAddress().getRegName();
550 if (iname.find(prefix) == 0) {
551 if (iname == prefix || iname[prefix.length()] ==
'/' || prefix[prefix.length() - 1] ==
'/') {
552 if (rec.getAddress().isValid()) {
553 response.
addList() = botify(rec.getAddress());
567 std::string portName =
STR(argv[0]);
568 Contact address = queryName(portName);
569 response = botify(address);
591 std::string target =
STR(argv[0]);
592 std::string key =
STR(argv[1]);
593 NameRecord& nameRecord = getNameRecord(target);
594 nameRecord.clearProp(key);
595 for (
int i = 2; i < argc; i++) {
596 nameRecord.addProp(key, argv[i]);
607 std::string target =
STR(argv[0]);
608 std::string key = argv[1];
609 NameRecord& nameRecord = getNameRecord(target);
610 return Bottle(nameRecord.getProp(key));
616 std::string NameServer::cmdGarbageCollect(
int argc,
char* argv[])
620 std::string response;
622 response =
"No cleaning done.\n";
624 return terminate(response);
633 result =
"registration name ";
636 result =
"registration name ";
637 result = result + address.
getRegName() +
" ip " +
"none" +
" port " +
"none" +
" type " + address.
getCarrier() +
"\n";
680 return str +
"*** end of message";
691 std::string result =
"no command given";
694 if (ss.size() >= 2) {
695 std::string key = ss.at(1);
700 std::vector<char*> args;
701 args.reserve(ss.size());
702 std::transform(ss.begin() + 1, ss.end(), std::back_inserter(args), [](
const std::string& str) { return const_cast<char*>(str.c_str()); });
703 args.push_back(
nullptr);
704 int argc =
static_cast<int>(args.size()) - 1;
705 char** argv = args.data();
707 result = dispatcher.dispatch(
this, key.c_str(), argc, argv);
708 if (result.empty()) {
709 Bottle b = ndispatcher.dispatch(
this, key.c_str(), argc, argv);
711 if (!result.empty()) {
712 result = result +
"\n";
713 result = terminate(result);
730 std::string out = apply(in, remote);
736 #ifndef DOXYGEN_SHOULD_SKIP_THIS
738 class MainNameServerWorker :
747 this->server = server;
753 std::string ref =
"NAME_SERVER ";
755 std::string msg =
"?";
756 bool haveMessage =
false;
766 haveMessage = (!msg.empty());
769 if (reader.
isActive() && haveMessage) {
771 size_t index = msg.find(
"NAME_SERVER");
776 std::string result = server->
apply(msg, remote);
779 if (result.empty()) {
780 result =
ns_terminate(std::string(
"unknown command ") + msg +
"\n");
784 for (
char i : result) {
794 std::string resultSparse = result;
795 size_t end = resultSparse.find(
"\n*** end of message");
796 if (end != std::string::npos) {
797 resultSparse[end] =
'\0';
802 yCInfo(
NAMESERVER,
"Name server ignoring unknown command: %s", msg.c_str());
811 class MainNameServer :
819 MainNameServer(
int basePort,
Port* port =
nullptr) :
822 setBasePort(basePort);
825 void setPort(
Port& port)
830 void onEvent(
Bottle& event)
override
832 if (port !=
nullptr) {
839 return new MainNameServerWorker(
const_cast<MainNameServer*
>(
this));
const yarp::os::LogComponent & NAMESERVER()
static std::string STR_HELP(const char *txt)
static std::string ns_terminate(const std::string &str)
A simple collection of objects that can be described and transmitted in a portable way.
void addVocab32(yarp::conf::vocab32_t x)
Places a vocabulary item in the bottle, at the end of the list.
void fromString(const std::string &text)
Initializes bottle from a string.
void append(const Bottle &alt)
Append the content of the given bottle to the current list.
Bottle & addList()
Places an empty nested list in the bottle, at the end of the list.
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
void addString(const char *str)
Places a string in the bottle, at the end of the list.
std::string toString() const override
Gives a human-readable textual representation of the bottle.
An interface for reading from a network connection.
virtual bool isTextMode() const =0
Check if the connection is text mode.
virtual std::string expectText(const char terminatingChar='\n')=0
Read some text from the network connection.
virtual Contact getRemoteContact() const =0
Gets information about who is supplying the data being read, if that information is available.
virtual bool isActive() const =0
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
An interface for writing to a network connection.
virtual void appendText(const std::string &str, const char terminate='\n')=0
Send a terminated string to the network connection.
static int getDefaultPortRange()
Under normal operation, YARP has a name server that manages a pool of (socket) ports starting at a po...
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
A mini-server for network communication.
bool write(const PortWriter &writer, const PortWriter *callback=nullptr) const override
Write an object to the port.
A single value (typically within a Bottle).
void fromString(const char *str)
Set value to correspond to a textual representation.
virtual std::string asString() const
Get string value.
Implementation of a YARP2-conforming name server.
static std::string textify(const Contact &address)
std::string apply(const std::string &txt, const Contact &remote) override
Contact queryName(const std::string &name)
static yarp::os::Bottle botify(const Contact &address)
Contact unregisterName(const std::string &name)
std::string terminate(const std::string &str)
Contact registerName(const std::string &name, const Contact &address)
#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 to_string(IntegerType x)
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.
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)