YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
MultiNameSpace.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7
9#include <yarp/os/Time.h>
13
14#include <vector>
15
16using namespace yarp::os;
17using namespace yarp::os::impl;
18
19namespace {
20YARP_OS_LOG_COMPONENT(MULTINAMESPACE, "yarp.os.MultiNamespace" )
21} // namespace
22
23using SpaceList = std::vector<NameSpace*>;
24
25// private implementation of a namespace container
27{
28public:
29 SpaceList spaces; // list of all namespaces
30
31 // a cache for common flags once we compute them
36
38 {
39 clear();
40 }
41
43 {
44 clear();
45 }
46
47 void clear()
48 {
49 // remove all namespaces and reset flags
50 for (auto ns : spaces) {
51 if (ns != nullptr) {
52 delete ns;
53 ns = nullptr;
54 }
55 }
56 spaces.clear();
57 _localOnly = true;
58 _usesCentralServer = false;
61 }
62
63 void scan()
64 {
65 // reset flags
66 _localOnly = true;
67 _usesCentralServer = false;
69 // now scan each namespace
70 for (auto ns : spaces) {
71 if (ns == nullptr) {
72 continue;
73 }
74 // if any namespace is nonlocal, combination is nonlocal
75 if (!ns->localOnly()) {
76 _localOnly = false;
77 }
78 // if any namespace uses a central server, combination also does
79 if (ns->usesCentralServer()) {
80 _usesCentralServer = true;
81 }
82 // if any namespace doesn't allocate port numbers, combination
83 // cannot be relied on to do so either
84 if (!ns->serverAllocatesPortNumbers()) {
86 }
87 // if any namespace lacks informed connections, combination
88 // cannot be relied on to be informed either
89 if (!ns->connectionHasNameOfEndpoints()) {
91 }
92 }
93 }
94
95 bool setLocalMode(bool flag)
96 {
97 // remove any existing namespaces
98 clear();
99 if (flag) {
100 // add a dummy local namespace
102 spaces.push_back(ns);
103 }
104 // cache flags
105 scan();
106 return true;
107 }
108
109 bool activate(bool force = false)
110 {
111 if (force) {
112 // wipe if forced
113 clear();
114 }
115 // return if namespaces already present
116 if (!spaces.empty()) {
117 return true;
118 }
119 // read namespace list from config file
120 NameConfig conf;
121 if (!conf.fromFile()) {
122 double now = SystemClock::nowSystem();
123 static double last_shown = now - 10;
124 if (now - last_shown > 3) {
125 last_shown = now;
126 yCWarning(MULTINAMESPACE, "YARP name server(s) not configured, ports will be anonymous\n");
127 yCWarning(MULTINAMESPACE, "check your namespace and settings with 'yarp detect'\n");
128 }
129 return false;
130 }
131 Bottle ns = conf.getNamespaces();
132 // loop through namespaces
133 for (size_t i = 0; i < ns.size(); i++) {
134 std::string n = ns.get(i).asString();
136 // read configuration of individual namespace
137 if (!conf2.fromFile(n.c_str())) {
138 yCWarning(MULTINAMESPACE, "Could not find namespace %s\n", n.c_str());
139 continue;
140 }
141 std::string mode = conf2.getMode();
142 Contact address = conf2.getAddress();
143 address.setName(n);
144 if (mode == "yarp" || mode == "//") {
145 // add a yarp namespace
146 NameSpace* ns = new YarpNameSpace(address);
147 spaces.push_back(ns);
148 } else if (mode == "ros") {
149 // add a ros namespace
150 NameSpace* ns = new RosNameSpace(address);
151 spaces.push_back(ns);
152 } else if (mode == "local") {
154 spaces.push_back(ns);
155 } else {
156 // shrug
157 yCError(MULTINAMESPACE, "cannot deal with namespace of type %s", mode.c_str());
158 return false;
159 }
160 }
161 // cache flags
162 scan();
163 return true;
164 }
165
167 {
168 activate(); // make sure we've loaded namespace(s)
169 if (!spaces.empty()) {
170 // return first name server
171 return spaces[0]->getNameServerContact();
172 }
173 return Contact();
174 }
175
176 Contact queryName(const std::string& name)
177 {
178 activate();
179 // try query against each namespace in order
180 for (auto ns : spaces) {
181 if (ns == nullptr) {
182 continue;
183 }
184 if (ns->getNameServerName() == name) {
185 // optimization: return cached server address for
186 // port names that match name of namespace
187 return ns->getNameServerContact();
188 }
189 Contact result = ns->queryName(name);
190 // return a result once we get one, skipping any remaining
191 // namespaces
192 if (result.isValid()) {
193 return result;
194 }
195 }
196 return Contact();
197 }
198
199 // return one namespace, any namespace (in fact always first)
201 {
202 activate();
203 if (spaces.empty()) {
204 return nullptr;
205 }
206 return spaces[0];
207 }
208
209 // return full list of namespaces
211 {
212 activate();
213 return spaces;
214 }
215};
216
217#define HELPER(x) (*((MultiNameSpaceHelper*)((x)->system_resource)))
218
220{
221 altStore = nullptr;
222 system_resource = new MultiNameSpaceHelper;
223 yCAssert(MULTINAMESPACE, system_resource != nullptr);
224}
225
227{
228 if (system_resource != nullptr) {
229 delete &HELPER(this);
230 system_resource = nullptr;
231 }
232}
233
235{
236 return HELPER(this).setLocalMode(flag);
237}
238
240{
241 HELPER(this).activate();
242 return HELPER(this)._localOnly;
243}
244
246{
247 HELPER(this).activate();
248 return HELPER(this)._usesCentralServer;
249}
250
252{
253 HELPER(this).activate();
254 return HELPER(this)._connectionHasNameOfEndpoints;
255}
256
258{
259 altStore = store;
260}
261
263{
264 return altStore;
265}
266
268{
269 HELPER(this).activate();
270 return HELPER(this)._serverAllocatesPortNumbers;
271}
272
274{
275 return HELPER(this).activate(force);
276}
277
279{
280 return ((MultiNameSpaceHelper*)system_resource)->getNameServerContact();
281}
282
283Contact MultiNameSpace::queryName(const std::string& name)
284{
285 return HELPER(this).queryName(name);
286}
287
289 const Contact& dest,
290 const ContactStyle& style)
291{
292 NameSpace* ns = HELPER(this).getOne();
293 if (ns == nullptr) {
294 return false;
295 }
296 return ns->connectPortToTopic(src, dest, style);
297}
298
300 const Contact& dest,
301 const ContactStyle& style)
302{
303 NameSpace* ns = HELPER(this).getOne();
304 if (ns == nullptr) {
305 return false;
306 }
307 return ns->connectTopicToPort(src, dest, style);
308}
309
311 const Contact& dest,
312 const ContactStyle& style)
313{
314 NameSpace* ns = HELPER(this).getOne();
315 if (ns == nullptr) {
316 return false;
317 }
318 return ns->disconnectPortFromTopic(src, dest, style);
319}
320
322 const Contact& dest,
323 const ContactStyle& style)
324{
325 NameSpace* ns = HELPER(this).getOne();
326 if (ns == nullptr) {
327 return false;
328 }
329 return ns->disconnectTopicFromPort(src, dest, style);
330}
331
333 const Contact& dest,
334 const ContactStyle& style)
335{
336 NameSpace* ns = HELPER(this).getOne();
337 if (ns == nullptr) {
338 return false;
339 }
340 return ns->connectPortToPortPersistently(src, dest, style);
341}
342
344 const Contact& dest,
345 const ContactStyle& style)
346{
347 NameSpace* ns = HELPER(this).getOne();
348 if (ns == nullptr) {
349 return false;
350 }
351 return ns->disconnectPortToPortPersistently(src, dest, style);
352}
353
354Contact MultiNameSpace::registerName(const std::string& name)
355{
356 SpaceList lst = HELPER(this).getAll();
357 Contact result;
358 // loop through namespaces
359 for (size_t i = 0; i < lst.size(); i++) {
361 // Register name with namespace. If contact information is
362 // fleshed out while registering, we carry that along for
363 // registration with the next namespace.
364 if (result.getPort() <= 0) {
365 iresult = lst[i]->registerName(name);
366 } else {
367 iresult = lst[i]->registerContact(result);
368 }
369 if (i == 0 || result.getPort() <= 0) {
370 result = iresult;
371 }
372 }
373 return result;
374}
375
377{
378 SpaceList lst = HELPER(this).getAll();
379 Contact result;
380 for (size_t i = 0; i < lst.size(); i++) {
381 // we register in *all* namespaces (and query in *any*)
382 Contact iresult = lst[i]->registerContact(contact);
383 if (i == 0) {
384 result = iresult;
385 }
386 }
387 return result;
388}
389
391{
392 SpaceList lst = HELPER(this).getAll();
393 Contact result;
394 for (size_t i = 0; i < lst.size(); i++) {
395 // we unregister in *all* namespaces
396 Contact iresult = lst[i]->unregisterName(name);
397 if (i == 0) {
398 result = iresult;
399 }
400 }
401 return result;
402}
403
405{
406 SpaceList lst = HELPER(this).getAll();
407 Contact result;
408 for (size_t i = 0; i < lst.size(); i++) {
409 // we unregister in *all* namespaces
410 Contact iresult = lst[i]->unregisterContact(contact);
411 if (i == 0) {
412 result = iresult;
413 }
414 }
415 return result;
416}
417
418bool MultiNameSpace::setProperty(const std::string& name, const std::string& key, const Value& value)
419{
420 NameSpace* ns = HELPER(this).getOne();
421 if (ns == nullptr) {
422 return false;
423 }
424 return ns->setProperty(name, key, value);
425}
426
427Value* MultiNameSpace::getProperty(const std::string& name, const std::string& key)
428{
429 NameSpace* ns = HELPER(this).getOne();
430 if (ns == nullptr) {
431 return nullptr;
432 }
433 return ns->getProperty(name, key);
434}
435
437 bool& scanNeeded,
438 bool& serverUsed)
439{
440 // This code looks like a placeholder that never got replaced.
441 // It is using a heuristic that namespaces with "/ros" in the
442 // name are ros namespaces. There's no need for guesswork like
443 // that anymore. Also, code duplication. Should spin this
444 // off into a proper plugin mechanism for namespaces.
445 std::string name = NetworkBase::getNameServerName();
446 Contact fake;
447 Contact r;
448 if (name.find("/ros") != std::string::npos) {
449 RosNameSpace ns(fake);
451 if (r.isValid() && useDetectedServer && scanNeeded) {
452 HELPER(this).activate(true);
453 }
454 } else {
455 YarpNameSpace ns(fake);
457 if (r.isValid() && useDetectedServer && scanNeeded) {
458 HELPER(this).activate(true);
459 }
460 }
461 return r;
462}
463
464
466 PortReader& reply,
467 const ContactStyle& style)
468{
469 NameSpace* ns = HELPER(this).getOne();
470 if (ns == nullptr) {
471 return false;
472 }
473 return ns->writeToNameServer(cmd, reply, style);
474}
std::vector< NameSpace * > SpaceList
#define HELPER(x)
bool setLocalMode(bool flag)
Contact queryName(const std::string &name)
bool activate(bool force=false)
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
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
A mini-server for performing network communication in the background.
Preferences for how to communicate with a contact.
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
int getPort() const
Get the port number associated with this Contact for socket communication.
Definition Contact.cpp:239
void setName(const std::string &name)
Set the name associated with this Contact.
Definition Contact.cpp:222
Contact getNameServerContact() const override
Get an address for a name server that manages the name space, if available.
Contact registerName(const std::string &name) override
Record contact information to tie to a port name.
virtual bool connectPortToTopic(const Contact &src, const Contact &dest, const ContactStyle &style) override
Publish a port to a topic.
virtual NameStore * getQueryBypass()
Get any alternative place to make name queries, if one was set by queryBypass()
virtual bool connectTopicToPort(const Contact &src, const Contact &dest, const ContactStyle &style) override
Subscribe a port to a topic.
virtual bool connectPortToPortPersistently(const Contact &src, const Contact &dest, const ContactStyle &style) override
Connect two ports with persistence.
Value * getProperty(const std::string &name, const std::string &key) override
Get the value of a named key from a named port.
virtual bool disconnectTopicFromPort(const Contact &src, const Contact &dest, const ContactStyle &style) override
Stop subscribing a port to a topic.
virtual bool disconnectPortToPortPersistently(const Contact &src, const Contact &dest, const ContactStyle &style) override
Disconnect two ports, removing any persistence.
virtual void queryBypass(NameStore *store)
Set an alternative place to make name queries.
bool connectionHasNameOfEndpoints() const override
When connections are made involving ports managed by this NameSpace do the ports involved end up know...
Contact queryName(const std::string &name) override
Map from port name to contact information.
bool localOnly() const override
Check if the NameSpace is only valid for the current process ("local").
bool serverAllocatesPortNumbers() const override
Check if a central server is responsible for allocating port numbers, or if this should be left up to...
bool usesCentralServer() const override
Check if a central server is involved in managing the NameSpace.
bool activate(bool force=false)
virtual bool disconnectPortFromTopic(const Contact &src, const Contact &dest, const ContactStyle &style) override
Stop publishing a port to a topic.
Contact unregisterName(const std::string &name) override
Disassociate contact information from a port name.
Contact registerContact(const Contact &contact) override
Record contact information (should include a port name).
Contact unregisterContact(const Contact &contact) override
Disassociate contact information (should include a port name).
virtual bool setProperty(const std::string &name, const std::string &key, const Value &value) override
Associate a key/value pair with a named port.
virtual Contact detectNameServer(bool useDetectedServer, bool &scanNeeded, bool &serverUsed) override
Find a name server for this NameSpace, if applicable.
virtual bool writeToNameServer(PortWriter &cmd, PortReader &reply, const ContactStyle &style) override
Write a message to a name server for this NameSpace, if applicable.
An abstract name space for ports.
Definition NameSpace.h:22
virtual bool disconnectTopicFromPort(const Contact &src, const Contact &dest, const ContactStyle &style)=0
Stop subscribing a port to a topic.
virtual bool disconnectPortFromTopic(const Contact &src, const Contact &dest, const ContactStyle &style)=0
Stop publishing a port to a topic.
virtual bool connectPortToPortPersistently(const Contact &src, const Contact &dest, const ContactStyle &style)=0
Connect two ports with persistence.
virtual bool connectTopicToPort(const Contact &src, const Contact &dest, const ContactStyle &style)=0
Subscribe a port to a topic.
virtual bool writeToNameServer(PortWriter &cmd, PortReader &reply, const ContactStyle &style)=0
Write a message to a name server for this NameSpace, if applicable.
virtual bool connectPortToTopic(const Contact &src, const Contact &dest, const ContactStyle &style)=0
Publish a port to a topic.
virtual bool setProperty(const std::string &name, const std::string &key, const Value &value)=0
Associate a key/value pair with a named port.
virtual Value * getProperty(const std::string &name, const std::string &key)=0
Get the value of a named key from a named port.
virtual bool disconnectPortToPortPersistently(const Contact &src, const Contact &dest, const ContactStyle &style)=0
Disconnect two ports, removing any persistence.
Abstract interface for a database of port names.
Definition NameStore.h:19
static std::string getNameServerName()
Get the name of the port associated with the nameserver (usually "/root", but this can be overwritten...
Definition Network.cpp:1345
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition PortReader.h:24
Interface implemented by all objects that can write themselves to the network, such as Bottle objects...
Definition PortWriter.h:23
virtual Contact detectNameServer(bool useDetectedServer, bool &scanNeeded, bool &serverUsed) override
Find a name server for this NameSpace, if applicable.
static double nowSystem()
A single value (typically within a Bottle).
Definition Value.h:43
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
virtual Contact detectNameServer(bool useDetectedServer, bool &scanNeeded, bool &serverUsed) override
Find a name server for this NameSpace, if applicable.
Small helper class to help deal with legacy YARP configuration files.
Definition NameConfig.h:23
bool fromFile(const char *ns=nullptr)
yarp::os::Bottle getNamespaces(bool refresh=false)
#define yCError(component,...)
#define yCAssert(component, x)
#define yCWarning(component,...)
#define YARP_OS_LOG_COMPONENT(name, name_string)
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.