41 #define STR(x) STR_HELP(x).c_str()
57 NameRecord& rec = getNameRecord(prev.
getRegName());
58 if (rec.isReusablePort()) {
59 HostRecord& host = getHostRecord(prev.
getHost());
62 if (rec.isReusableIp()) {
63 if (rec.getAddress().getCarrier() ==
"mcast") {
64 mcastRecord.releaseAddress(rec.getAddress().getHost().c_str());
68 tmpNames.release(name);
72 event.addString(name.c_str());
77 return queryName(name);
83 const std::string& remote)
85 bool reusablePort =
false;
86 bool reusableIp =
false;
97 suggestion =
Contact(name,
"...",
"...", 0);
100 std::string portName = name;
101 if (portName ==
"...") {
102 portName = tmpNames.get();
105 std::string carrier = suggestion.
getCarrier();
106 if (carrier ==
"...") {
110 std::string machine = suggestion.
getHost();
111 int overridePort = 0;
112 if (machine ==
"...") {
113 if (carrier !=
"mcast") {
114 if (remote ==
"...") {
115 yCError(
NAMESERVER,
"remote machine name was not found! can only guess it is local...");
116 machine =
"127.0.0.1";
121 machine = mcastRecord.get();
122 overridePort = mcastRecord.lastPortNumber();
127 int port = suggestion.
getPort();
129 if (overridePort != 0) {
132 port = getHostRecord(machine).get();
137 suggestion =
Contact(portName, carrier, machine, port);
141 NameRecord& nameRecord = getNameRecord(suggestion.
getRegName());
142 nameRecord.setAddress(suggestion, reusablePort, reusableIp);
146 event.addString(suggestion.
getRegName().c_str());
149 return nameRecord.getAddress();
155 std::string base = name;
157 if (name.find(
"/net=") == 0) {
159 size_t patEnd = name.find(
'/', patStart);
160 if (patEnd >= patStart && patEnd != std::string::npos) {
161 pat = name.substr(patStart, patEnd - patStart);
162 base = name.substr(patEnd);
163 yCDebug(
NAMESERVER,
"Special query form %s (%s/%s)", name.c_str(), pat.c_str(), base.c_str());
167 NameRecord* rec = getNameRecord(base,
false);
168 if (rec !=
nullptr) {
170 std::string ip = rec->matchProp(
"ips", pat);
178 return rec->getAddress();
184 NameServer::NameRecord* NameServer::getNameRecord(
const std::string& name,
187 auto entry = nameMap.find(name);
188 if (entry == nameMap.end()) {
192 nameMap.emplace(name, NameRecord());
193 entry = nameMap.find(name);
196 return &(entry->second);
200 NameServer::HostRecord* NameServer::getHostRecord(
const std::string& name,
203 auto entry = hostMap.find(name);
204 if (entry == hostMap.end()) {
208 hostMap[name] = HostRecord();
209 entry = hostMap.find(name);
210 entry->second.setBase(basePort);
213 return &(entry->second);
226 void NameServer::setup()
231 dispatcher.add(
"register", &NameServer::cmdRegister);
232 dispatcher.add(
"unregister", &NameServer::cmdUnregister);
233 dispatcher.add(
"query", &NameServer::cmdQuery);
234 dispatcher.add(
"help", &NameServer::cmdHelp);
235 dispatcher.add(
"set", &NameServer::cmdSet);
236 dispatcher.add(
"get", &NameServer::cmdGet);
237 dispatcher.add(
"check", &NameServer::cmdCheck);
238 dispatcher.add(
"match", &NameServer::cmdMatch);
239 dispatcher.add(
"list", &NameServer::cmdList);
240 dispatcher.add(
"route", &NameServer::cmdRoute);
241 dispatcher.add(
"gc", &NameServer::cmdGarbageCollect);
242 dispatcher.add(
"bot", &NameServer::cmdBot);
243 dispatcher.add(
"announce", &NameServer::cmdAnnounce);
245 ndispatcher.add(
"list", &NameServer::ncmdList);
246 ndispatcher.add(
"query", &NameServer::ncmdQuery);
247 ndispatcher.add(
"version", &NameServer::ncmdVersion);
248 ndispatcher.add(
"set", &NameServer::ncmdSet);
249 ndispatcher.add(
"get", &NameServer::ncmdGet);
252 std::string NameServer::cmdRegister(
int argc,
char* argv[])
255 std::string remote = argv[0];
260 return "need at least one argument";
262 std::string portName =
STR(argv[0]);
264 std::string machine =
"...";
265 std::string carrier =
"...";
274 if (std::string(
"...") == argv[3]) {
281 Contact address = registerName(portName,
Contact(portName, carrier, machine, port), remote);
285 return terminate(textify(address));
289 std::string NameServer::cmdQuery(
int argc,
char* argv[])
296 return "need at least one argument";
298 std::string portName =
STR(argv[0]);
299 Contact address = queryName(portName);
300 return terminate(textify(address));
303 std::string NameServer::cmdUnregister(
int argc,
char* argv[])
310 return "need at least one argument";
312 std::string portName =
STR(argv[0]);
313 Contact address = unregisterName(portName);
314 return terminate(textify(address));
318 std::string NameServer::cmdAnnounce(
int argc,
char* argv[])
324 return terminate(
"ok\n");
327 std::string NameServer::cmdRoute(
int argc,
char* argv[])
334 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)");
336 std::string src =
STR(argv[0]);
337 std::string dest =
STR(argv[1]);
342 const char* altArgv[] = {
353 argv = (
char**)altArgv;
357 NameRecord& srcRec = getNameRecord(src);
358 NameRecord& destRec = getNameRecord(dest);
361 for (
int i = 0; i < argc; i++) {
362 std::string carrier = argv[i];
363 if (srcRec.checkProp(
"offers", carrier) && destRec.checkProp(
"accepts", carrier)) {
365 if (carrier ==
"local" || carrier ==
"shmem") {
366 if (srcRec.getProp(
"ips") == destRec.getProp(
"ips")) {
367 if (carrier ==
"local") {
368 if (srcRec.getProp(
"process") != destRec.getProp(
"process")) {
383 pref = pref +
":/" + dest;
388 std::string result =
"port ";
389 result += src +
" route " + dest +
" = " + pref +
"\n";
390 return terminate(result);
394 std::string NameServer::cmdHelp(
int argc,
char* argv[])
400 std::string result =
"Here are some ways to use the name server:\n";
406 result += std::string(
"+ help\n");
407 result += std::string(
"+ list\n");
408 result += std::string(
"+ register $portname\n");
409 result += std::string(
"+ register $portname $carrier $ipAddress $portNumber\n");
410 result += std::string(
" (if you want a field set automatically, write '...')\n");
411 result += std::string(
"+ unregister $portname\n");
412 result += std::string(
"+ query $portname\n");
413 result += std::string(
"+ set $portname $property $value\n");
414 result += std::string(
"+ get $portname $property\n");
415 result += std::string(
"+ check $portname $property\n");
416 result += std::string(
"+ match $portname $property $prefix\n");
417 result += std::string(
"+ route $port1 $port2\n");
418 result += std::string(
"+ gc\n");
419 return terminate(result);
423 std::string NameServer::cmdSet(
int argc,
char* argv[])
430 return "need at least two arguments: the port name, and a key";
432 std::string target =
STR(argv[0]);
433 std::string key = argv[1];
434 NameRecord& nameRecord = getNameRecord(target);
435 nameRecord.clearProp(key);
436 for (
int i = 2; i < argc; i++) {
437 nameRecord.addProp(key, argv[i]);
439 return terminate(std::string(
"port ") + target +
" property " + key +
" = " + nameRecord.getProp(key) +
"\n");
442 std::string NameServer::cmdGet(
int argc,
char* argv[])
449 return "need exactly two arguments: the port name, and a key";
451 std::string target =
STR(argv[0]);
452 std::string key = argv[1];
453 NameRecord& nameRecord = getNameRecord(target);
454 return terminate(std::string(
"port ") + target +
" property " + key +
" = " + nameRecord.getProp(key) +
"\n");
457 std::string NameServer::cmdMatch(
int argc,
char* argv[])
464 return "need exactly three arguments: the port name, a key, and a prefix";
466 std::string target =
STR(argv[0]);
467 std::string key = argv[1];
468 std::string prefix = argv[2];
469 NameRecord& nameRecord = getNameRecord(target);
470 return terminate(std::string(
"port ") + target +
" property " + key +
" = " + nameRecord.matchProp(key, prefix) +
"\n");
473 std::string NameServer::cmdCheck(
int argc,
char* argv[])
480 return "need at least two arguments: the port name, and a key";
482 std::string response;
483 std::string target =
STR(argv[0]);
484 std::string key = argv[1];
485 NameRecord& nameRecord = getNameRecord(target);
486 for (
int i = 2; i < argc; i++) {
487 std::string val =
"false";
488 if (nameRecord.checkProp(key, argv[i])) {
494 response.append(
"port ").append(target).append(
" property ").append(key).append(
" value ").append(argv[i]).append(
" present ").append(val);
497 return terminate(response);
501 std::string NameServer::cmdList(
int argc,
char* argv[])
505 std::string response;
507 std::multiset<std::string> lines;
508 for (
auto& it : nameMap) {
509 NameRecord& rec = it.second;
510 lines.insert(textify(rec.getAddress()));
514 for (
const auto& line : lines) {
518 return terminate(response);
522 std::string NameServer::cmdBot(
int argc,
char* argv[])
528 std::string key = argv[0];
531 Bottle result = ndispatcher.dispatch(
this, key.c_str(), argc, argv);
538 Bottle NameServer::ncmdList(
int argc,
char* argv[])
545 prefix =
STR(argv[0]);
549 for (
auto& it : nameMap) {
550 NameRecord& rec = it.second;
551 std::string iname = rec.getAddress().getRegName();
552 if (iname.find(prefix) == 0) {
553 if (iname == prefix || iname[prefix.length()] ==
'/' || prefix[prefix.length() - 1] ==
'/') {
554 if (rec.getAddress().isValid()) {
555 response.
addList() = botify(rec.getAddress());
569 std::string portName =
STR(argv[0]);
570 Contact address = queryName(portName);
571 response = botify(address);
593 std::string target =
STR(argv[0]);
594 std::string key =
STR(argv[1]);
595 NameRecord& nameRecord = getNameRecord(target);
596 nameRecord.clearProp(key);
597 for (
int i = 2; i < argc; i++) {
598 nameRecord.addProp(key, argv[i]);
609 std::string target =
STR(argv[0]);
610 std::string key = argv[1];
611 NameRecord& nameRecord = getNameRecord(target);
612 return Bottle(nameRecord.getProp(key));
618 std::string NameServer::cmdGarbageCollect(
int argc,
char* argv[])
622 std::string response;
624 response =
"No cleaning done.\n";
626 return terminate(response);
635 result =
"registration name ";
638 result =
"registration name ";
639 result = result + address.
getRegName() +
" ip " +
"none" +
" port " +
"none" +
" type " + address.
getCarrier() +
"\n";
682 return str +
"*** end of message";
693 std::string result =
"no command given";
697 if (ss.
size() >= 2) {
698 std::string key = ss.
get(1);
701 result = dispatcher.dispatch(
this, key.c_str(), ss.
size() - 1, (
char**)(ss.
get() + 1));
702 if (result.empty()) {
703 Bottle b = ndispatcher.dispatch(
this, key.c_str(), ss.
size() - 1, (
char**)(ss.
get() + 1));
705 if (!result.empty()) {
706 result = result +
"\n";
707 result = terminate(result);
724 std::string out = apply(in, remote);
730 #ifndef DOXYGEN_SHOULD_SKIP_THIS
732 class MainNameServerWorker :
741 this->server = server;
747 std::string ref =
"NAME_SERVER ";
749 std::string msg =
"?";
750 bool haveMessage =
false;
760 haveMessage = (!msg.empty());
763 if (reader.
isActive() && haveMessage) {
765 size_t index = msg.find(
"NAME_SERVER");
770 std::string result = server->
apply(msg, remote);
773 if (result.empty()) {
774 result =
ns_terminate(std::string(
"unknown command ") + msg +
"\n");
778 for (
char i : result) {
788 std::string resultSparse = result;
789 size_t end = resultSparse.find(
"\n*** end of message");
790 if (end != std::string::npos) {
791 resultSparse[end] =
'\0';
796 yCInfo(
NAMESERVER,
"Name server ignoring unknown command: %s", msg.c_str());
805 class MainNameServer :
813 MainNameServer(
int basePort,
Port* port =
nullptr) :
816 setBasePort(basePort);
819 void setPort(
Port& port)
824 void onEvent(
Bottle& event)
override
826 if (port !=
nullptr) {
833 return new MainNameServerWorker(
const_cast<MainNameServer*
>(
this));
838 #endif // DOXYGEN_SHOULD_SKIP_THIS