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
8#include <yarp/os/Time.h>
12
13#include <vector>
14
15using namespace yarp::os;
16using namespace yarp::os::impl;
17
18namespace {
19YARP_OS_LOG_COMPONENT(MULTINAMESPACE, "yarp.os.MultiNamespace" )
20} // namespace
21
22using SpaceList = std::vector<NameSpace*>;
23
24// private implementation of a namespace container
26{
27public:
28 SpaceList spaces; // list of all namespaces
29
30 // a cache for common flags once we compute them
35
37 {
38 clear();
39 }
40
42 {
43 clear();
44 }
45
46 void clear()
47 {
48 // remove all namespaces and reset flags
49 for (auto ns : spaces) {
50 if (ns != nullptr) {
51 delete ns;
52 ns = nullptr;
53 }
54 }
55 spaces.clear();
56 _localOnly = true;
57 _usesCentralServer = false;
60 }
61
62 void scan()
63 {
64 // reset flags
65 _localOnly = true;
66 _usesCentralServer = false;
68 // now scan each namespace
69 for (auto ns : spaces) {
70 if (ns == nullptr) {
71 continue;
72 }
73 // if any namespace is nonlocal, combination is nonlocal
74 if (!ns->localOnly()) {
75 _localOnly = false;
76 }
77 // if any namespace uses a central server, combination also does
78 if (ns->usesCentralServer()) {
79 _usesCentralServer = true;
80 }
81 // if any namespace doesn't allocate port numbers, combination
82 // cannot be relied on to do so either
83 if (!ns->serverAllocatesPortNumbers()) {
85 }
86 // if any namespace lacks informed connections, combination
87 // cannot be relied on to be informed either
88 if (!ns->connectionHasNameOfEndpoints()) {
90 }
91 }
92 }
93
94 bool setLocalMode(bool flag)
95 {
96 // remove any existing namespaces
97 clear();
98 if (flag) {
99 // add a dummy local namespace
101 spaces.push_back(ns);
102 }
103 // cache flags
104 scan();
105 return true;
106 }
107
108 bool activate(bool force = false)
109 {
110 if (force) {
111 // wipe if forced
112 clear();
113 }
114 // return if namespaces already present
115 if (!spaces.empty()) {
116 return true;
117 }
118 // read namespace list from config file
119 NameConfig conf;
120 if (!conf.fromFile()) {
121 double now = SystemClock::nowSystem();
122 static double last_shown = now - 10;
123 if (now - last_shown > 3) {
124 last_shown = now;
125 yCWarning(MULTINAMESPACE, "YARP name server(s) not configured, ports will be anonymous\n");
126 yCWarning(MULTINAMESPACE, "check your namespace and settings with 'yarp detect'\n");
127 }
128 return false;
129 }
130 Bottle ns = conf.getNamespaces();
131 // loop through namespaces
132 for (size_t i = 0; i < ns.size(); i++) {
133 std::string n = ns.get(i).asString();
135 // read configuration of individual namespace
136 if (!conf2.fromFile(n.c_str())) {
137 yCWarning(MULTINAMESPACE, "Could not find namespace %s\n", n.c_str());
138 continue;
139 }
140 std::string mode = conf2.getMode();
141 Contact address = conf2.getAddress();
142 address.setName(n);
143 if (mode == "yarp" || mode == "//") {
144 // add a yarp namespace
145 NameSpace* ns = new YarpNameSpace(address);
146 spaces.push_back(ns);
147 } else if (mode == "local") {
149 spaces.push_back(ns);
150 } else {
151 // shrug
152 yCError(MULTINAMESPACE, "cannot deal with namespace of type %s", mode.c_str());
153 return false;
154 }
155 }
156 // cache flags
157 scan();
158 return true;
159 }
160
162 {
163 activate(); // make sure we've loaded namespace(s)
164 if (!spaces.empty()) {
165 // return first name server
166 return spaces[0]->getNameServerContact();
167 }
168 return Contact();
169 }
170
171 Contact queryName(const std::string& name)
172 {
173 activate();
174 // try query against each namespace in order
175 for (auto ns : spaces) {
176 if (ns == nullptr) {
177 continue;
178 }
179 if (ns->getNameServerName() == name) {
180 // optimization: return cached server address for
181 // port names that match name of namespace
182 return ns->getNameServerContact();
183 }
184 Contact result = ns->queryName(name);
185 // return a result once we get one, skipping any remaining
186 // namespaces
187 if (result.isValid()) {
188 return result;
189 }
190 }
191 return Contact();
192 }
193
194 // return one namespace, any namespace (in fact always first)
196 {
197 activate();
198 if (spaces.empty()) {
199 return nullptr;
200 }
201 return spaces[0];
202 }
203
204 // return full list of namespaces
206 {
207 activate();
208 return spaces;
209 }
210};
211
212#define HELPER(x) (*((MultiNameSpaceHelper*)((x)->system_resource)))
213
215{
216 altStore = nullptr;
217 system_resource = new MultiNameSpaceHelper;
218 yCAssert(MULTINAMESPACE, system_resource != nullptr);
219}
220
222{
223 if (system_resource != nullptr) {
224 delete &HELPER(this);
225 system_resource = nullptr;
226 }
227}
228
230{
231 return HELPER(this).setLocalMode(flag);
232}
233
235{
236 HELPER(this).activate();
237 return HELPER(this)._localOnly;
238}
239
241{
242 HELPER(this).activate();
243 return HELPER(this)._usesCentralServer;
244}
245
247{
248 HELPER(this).activate();
249 return HELPER(this)._connectionHasNameOfEndpoints;
250}
251
253{
254 altStore = store;
255}
256
258{
259 return altStore;
260}
261
263{
264 HELPER(this).activate();
265 return HELPER(this)._serverAllocatesPortNumbers;
266}
267
269{
270 return HELPER(this).activate(force);
271}
272
274{
275 return ((MultiNameSpaceHelper*)system_resource)->getNameServerContact();
276}
277
278Contact MultiNameSpace::queryName(const std::string& name)
279{
280 return HELPER(this).queryName(name);
281}
282
284 const Contact& dest,
285 const ContactStyle& style)
286{
287 NameSpace* ns = HELPER(this).getOne();
288 if (ns == nullptr) {
289 return false;
290 }
291 return ns->connectPortToTopic(src, dest, style);
292}
293
295 const Contact& dest,
296 const ContactStyle& style)
297{
298 NameSpace* ns = HELPER(this).getOne();
299 if (ns == nullptr) {
300 return false;
301 }
302 return ns->connectTopicToPort(src, dest, style);
303}
304
306 const Contact& dest,
307 const ContactStyle& style)
308{
309 NameSpace* ns = HELPER(this).getOne();
310 if (ns == nullptr) {
311 return false;
312 }
313 return ns->disconnectPortFromTopic(src, dest, style);
314}
315
317 const Contact& dest,
318 const ContactStyle& style)
319{
320 NameSpace* ns = HELPER(this).getOne();
321 if (ns == nullptr) {
322 return false;
323 }
324 return ns->disconnectTopicFromPort(src, dest, style);
325}
326
328 const Contact& dest,
329 const ContactStyle& style)
330{
331 NameSpace* ns = HELPER(this).getOne();
332 if (ns == nullptr) {
333 return false;
334 }
335 return ns->connectPortToPortPersistently(src, dest, style);
336}
337
339 const Contact& dest,
340 const ContactStyle& style)
341{
342 NameSpace* ns = HELPER(this).getOne();
343 if (ns == nullptr) {
344 return false;
345 }
346 return ns->disconnectPortToPortPersistently(src, dest, style);
347}
348
349Contact MultiNameSpace::registerName(const std::string& name)
350{
351 SpaceList lst = HELPER(this).getAll();
352 Contact result;
353 // loop through namespaces
354 for (size_t i = 0; i < lst.size(); i++) {
356 // Register name with namespace. If contact information is
357 // fleshed out while registering, we carry that along for
358 // registration with the next namespace.
359 if (result.getPort() <= 0) {
360 iresult = lst[i]->registerName(name);
361 } else {
362 iresult = lst[i]->registerContact(result);
363 }
364 if (i == 0 || result.getPort() <= 0) {
365 result = iresult;
366 }
367 }
368 return result;
369}
370
372{
373 SpaceList lst = HELPER(this).getAll();
374 Contact result;
375 for (size_t i = 0; i < lst.size(); i++) {
376 // we register in *all* namespaces (and query in *any*)
377 Contact iresult = lst[i]->registerContact(contact);
378 if (i == 0) {
379 result = iresult;
380 }
381 }
382 return result;
383}
384
386{
387 SpaceList lst = HELPER(this).getAll();
388 Contact result;
389 for (size_t i = 0; i < lst.size(); i++) {
390 // we unregister in *all* namespaces
391 Contact iresult = lst[i]->unregisterName(name);
392 if (i == 0) {
393 result = iresult;
394 }
395 }
396 return result;
397}
398
400{
401 SpaceList lst = HELPER(this).getAll();
402 Contact result;
403 for (size_t i = 0; i < lst.size(); i++) {
404 // we unregister in *all* namespaces
405 Contact iresult = lst[i]->unregisterContact(contact);
406 if (i == 0) {
407 result = iresult;
408 }
409 }
410 return result;
411}
412
413bool MultiNameSpace::setProperty(const std::string& name, const std::string& key, const Value& value)
414{
415 NameSpace* ns = HELPER(this).getOne();
416 if (ns == nullptr) {
417 return false;
418 }
419 return ns->setProperty(name, key, value);
420}
421
422Value* MultiNameSpace::getProperty(const std::string& name, const std::string& key)
423{
424 NameSpace* ns = HELPER(this).getOne();
425 if (ns == nullptr) {
426 return nullptr;
427 }
428 return ns->getProperty(name, key);
429}
430
432 bool& scanNeeded,
433 bool& serverUsed)
434{
435 // This code looks like a placeholder that never got replaced.
436 // Also, code duplication. Should spin this
437 // off into a proper plugin mechanism for namespaces.
438 std::string name = NetworkBase::getNameServerName();
439 Contact fake;
440 Contact r;
441 {
442 YarpNameSpace ns(fake);
444 if (r.isValid() && useDetectedServer && scanNeeded) {
445 HELPER(this).activate(true);
446 }
447 }
448 return r;
449}
450
451
453 PortReader& reply,
454 const ContactStyle& style)
455{
456 NameSpace* ns = HELPER(this).getOne();
457 if (ns == nullptr) {
458 return false;
459 }
460 return ns->writeToNameServer(cmd, reply, style);
461}
FeatureMode mode
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:65
size_type size() const
Gets the number of elements in the bottle.
Definition Bottle.cpp:257
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition Bottle.cpp:252
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
static double nowSystem()
A single value (typically within a Bottle).
Definition Value.h:44
virtual std::string asString() const
Get string value.
Definition Value.cpp:246
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.