YARP
Yet Another Robot Platform
Carriers.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 <yarp/os/Carriers.h>
8
21
22#include <vector>
23#include <mutex>
24
25using namespace yarp::os::impl;
26using namespace yarp::os;
27
28namespace {
29YARP_OS_LOG_COMPONENT(CARRIERS, "yarp.os.Carriers")
30} // namespace
31
32namespace {
33std::string bytes_to_string(const Bytes& header)
34{
35 std::string ret;
36 for (size_t i = 0; i < header.length(); i++) {
38 ret += " ";
39 }
40 ret += "[";
41 for (size_t i = 0; i < header.length(); i++) {
42 char ch = header.get()[i];
43 if (ch >= 32) {
44 ret += ch;
45 } else {
46 ret += '.';
47 }
48 }
49 ret += "]";
50 return ret;
51}
52} // namespace
53
54#ifndef DOXYGEN_SHOULD_SKIP_THIS
55
56class Carriers::Private : public YarpPluginSelector
57{
58public:
59 static std::mutex mutex;
60
61 std::vector<Carrier*> delegates;
62
63 Carrier* chooseCarrier(const std::string& name,
64 bool load_if_needed = true,
65 bool return_template = false);
66 Carrier* chooseCarrier(const Bytes& header,
67 bool load_if_needed = true);
68
69 static bool matchCarrier(const Bytes& header, Bottle& code);
70 static bool checkForCarrier(const Bytes& header, Searchable& group);
71 static bool scanForCarrier(const Bytes& header);
72
73 bool select(Searchable& options) override;
74};
75
76std::mutex Carriers::Private::mutex{};
77
78Carrier* Carriers::Private::chooseCarrier(const std::string& name,
79 bool load_if_needed,
80 bool return_template)
81{
82 auto pos = name.find('+');
83 if (pos != std::string::npos) {
84 return chooseCarrier(name.substr(0, pos), load_if_needed, return_template);
85 }
86
87 for (auto& delegate : delegates) {
88 Carrier& c = *delegate;
89 if (name == c.getName()) {
90 if (!return_template) {
91 return c.create();
92 }
93 return &c;
94 }
95 }
96
97 if (load_if_needed) {
98 // ok, we didn't find a carrier, but we have a name.
99 // let's try to register it, and see if a dll is found.
100 if (NetworkBase::registerCarrier(name.c_str(), nullptr)) {
101 // We made progress, let's try again...
102 return Carriers::Private::chooseCarrier(name, false);
103 }
104 }
105
106 yCError(CARRIERS,
107 "Could not find carrier \"%s\"",
108 (!name.empty()) ? name.c_str() : "[bytes]");
109
110 return nullptr;
111}
112
113Carrier* Carriers::Private::chooseCarrier(const Bytes& header,
114 bool load_if_needed)
115{
116 for (auto& delegate : delegates) {
117 Carrier& c = *delegate;
118 if (c.checkHeader(header)) {
119 return c.create();
120 }
121 }
122
123 if (load_if_needed) {
124 if (scanForCarrier(header)) {
125 // We made progress, let's try again...
126 return Carriers::Private::chooseCarrier(header, false);
127 }
128 }
129
130 yCError(CARRIERS,
131 "Could not find carrier for a connection starting with: %s",
132 bytes_to_string(header).c_str());
133
134 return nullptr;
135}
136
137
138bool Carriers::Private::matchCarrier(const Bytes& header, Bottle& code)
139{
140 size_t at = 0;
141 bool success = true;
142 bool done = false;
143 for (size_t i = 0; i < code.size() && !done; i++) {
144 Value& v = code.get(i);
145 if (v.isString()) {
146 std::string str = v.asString();
147 for (char j : str) {
148 if (header.length() <= at) {
149 success = false;
150 done = true;
151 break;
152 }
153 if (j != header.get()[at]) {
154 success = false;
155 done = true;
156 break;
157 }
158 at++;
159 }
160 } else {
161 at++;
162 }
163 }
164 return success;
165}
166
167bool Carriers::Private::checkForCarrier(const Bytes& header, Searchable& group)
168{
169 Bottle code = group.findGroup("code").tail();
170 if (code.size() == 0) {
171 return false;
172 }
173 if (matchCarrier(header, code)) {
174 std::string name = group.find("name").asString();
175 if (NetworkBase::registerCarrier(name.c_str(), nullptr)) {
176 return true;
177 }
178 }
179 return false;
180}
181
182bool Carriers::Private::scanForCarrier(const Bytes& header)
183{
184 yCDebug(CARRIERS, "Scanning for a carrier by header.");
185 YarpPluginSelector selector;
186 selector.scan();
187 Bottle lst = selector.getSelectedPlugins();
188 for (size_t i = 0; i < lst.size(); i++) {
189 if (checkForCarrier(header, lst.get(i))) {
190 return true;
191 }
192 }
193 return false;
194}
195
196bool Carriers::Private::select(Searchable& options)
197{
198 return options.check("type", Value("none")).asString() == "carrier";
199}
200
201#endif // DOXYGEN_SHOULD_SKIP_THIS
202
203
204Carriers::Carriers() :
205 mPriv(new Private)
206{
207 mPriv->delegates.emplace_back(new HttpCarrier());
208 mPriv->delegates.emplace_back(new NameserCarrier());
209 mPriv->delegates.emplace_back(new LocalCarrier());
210 mPriv->delegates.emplace_back(new TcpCarrier());
211 mPriv->delegates.emplace_back(new TcpCarrier(false));
212 mPriv->delegates.emplace_back(new McastCarrier());
213 mPriv->delegates.emplace_back(new UdpCarrier());
214 mPriv->delegates.emplace_back(new TextCarrier());
215 mPriv->delegates.emplace_back(new TextCarrier(true));
216}
217
218Carriers::~Carriers()
219{
220 clear();
221 delete mPriv;
222}
223
225{
226 for (auto& delegate : mPriv->delegates) {
227 delete delegate;
228 delegate = nullptr;
229 }
230 mPriv->delegates.clear();
231}
232
233Carrier* Carriers::chooseCarrier(const std::string& name)
234{
235 return getInstance().mPriv->chooseCarrier(name);
236}
237
238Carrier* Carriers::getCarrierTemplate(const std::string& name)
239{
240 return getInstance().mPriv->chooseCarrier(name, true, true);
241}
242
243
245{
246 return getInstance().mPriv->chooseCarrier(bytes);
247}
248
249
251{
252 Face* face = nullptr;
253 Carrier* c = nullptr;
254
255 if (address.getCarrier() == "fake") //for backward compatibility
256 {
257 face = new FakeFace();
258 }
259
260 else {
261 if (!address.getCarrier().empty()) {
262 c = getCarrierTemplate(address.getCarrier());
263 }
264
265 if (c != nullptr) {
266 face = c->createFace();
267 } else {
268 //if address hasn't carrier then use the default one (tcpFace)
269 face = new TcpFace();
270 }
271 }
272
273 bool ok = face->open(address);
274 if (!ok) {
275 delete face;
276 face = nullptr;
277 }
278 return face;
279}
280
281
283{
284 yarp::os::Face* face = nullptr;
285 Carrier* c = nullptr;
286
287 if (!address.getCarrier().empty()) {
288 c = getCarrierTemplate(address.getCarrier());
289 }
290 if (c != nullptr) {
291 face = c->createFace();
292 } else {
293 //if address hasn't carrier than use the default one (tcpFace)
294 face = new TcpFace();
295 }
296
297 OutputProtocol* proto = face->write(address);
298 delete face;
299 return proto;
300}
301
302
304{
305 getInstance().mPriv->delegates.emplace_back(carrier);
306 return true;
307}
308
309
311{
312 static Carriers instance;
313 return instance;
314}
315
316
318{
319 Carriers& instance = getInstance();
320 std::lock_guard<std::mutex> guard(Private::mutex);
321
322 Bottle lst;
323 Property done;
324
325 std::vector<Carrier*>& delegates = instance.mPriv->delegates;
326 for (auto& delegate : delegates) {
327 Carrier& c = *delegate;
328 lst.addString(c.getName());
329 done.put(c.getName(), 1);
330 }
331
332 instance.mPriv->scan();
333 Bottle plugins = instance.mPriv->getSelectedPlugins();
334 for (size_t i = 0; i < plugins.size(); i++) {
335 Value& options = plugins.get(i);
336 std::string name = options.check("name", Value("untitled")).asString();
337 if (done.check(name)) {
338 continue;
339 }
340
342 YarpPluginSettings settings;
343 settings.setSelector(*instance.mPriv);
344 settings.readFromSearchable(options, name);
345 settings.open(lib);
346 if (lib.getName().empty()) {
347 continue;
348 }
349 lst.addString(name);
350 done.put(name, 1);
351 }
352
353 return lst;
354}
bool ret
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
Bottle tail() const
Get all but the first element of a bottle.
Definition: Bottle.cpp:388
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:170
A simple abstraction for a block of bytes.
Definition: Bytes.h:24
size_t length() const
Definition: Bytes.cpp:22
const char * get() const
Definition: Bytes.cpp:27
A base class for connection types (tcp, mcast, shmem, ...) which are called carriers in YARP.
Definition: Carrier.h:44
virtual yarp::os::Face * createFace() const
Create new Face object that the carrier needs.
Definition: Carrier.cpp:132
virtual bool checkHeader(const Bytes &header)=0
Given the first 8 bytes received on a connection, decide if this is the right carrier type to use for...
virtual Carrier * create() const =0
Factory method.
Collection of carriers, a singleton.
Definition: Carriers.h:29
static Bottle listCarriers()
Definition: Carriers.cpp:317
static Face * listen(const Contact &address)
Create a "proto-carrier" interface object that waits for incoming connections prior to a carrier bein...
Definition: Carriers.cpp:250
static Carrier * getCarrierTemplate(const std::string &name)
Get template for carrier.
Definition: Carriers.cpp:238
static bool addCarrierPrototype(Carrier *carrier)
Add a new connection type.
Definition: Carriers.cpp:303
static Carrier * chooseCarrier(const std::string &name)
Select a carrier by name.
Definition: Carriers.cpp:233
static Carriers & getInstance()
Definition: Carriers.cpp:310
static OutputProtocol * connect(const Contact &address)
Initiate a connection to an address.
Definition: Carriers.cpp:282
void clear()
Remove all carriers.
Definition: Carriers.cpp:224
virtual std::string getName() const =0
Get the name of this connection type ("tcp", "mcast", "shmem", ...)
Represents how to reach a part of a YARP network.
Definition: Contact.h:33
std::string getCarrier() const
Get the carrier associated with this Contact for socket communication.
Definition: Contact.cpp:250
The initial point-of-contact with a port.
Definition: Face.h:20
virtual OutputProtocol * write(const Contact &address)=0
Try to reach out and talk to someone.
virtual bool open(const Contact &address)=0
Start listening to the given address.
The output side of an active connection between two ports.
A class for storing options and configuration information.
Definition: Property.h:33
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:1041
A base class for nested structures that can be searched.
Definition: Searchable.h:56
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
A wrapper for a named factory method in a named shared library.
std::string getName() const
Get the name associated with this factory.
A single value (typically within a Bottle).
Definition: Value.h:43
virtual bool isString() const
Checks if value is a string.
Definition: Value.cpp:156
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Value.cpp:321
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
Pick out a set of relevant plugins.
void scan()
Find plugin configuration files, and run [plugin] sections through the select method.
Definition: YarpPlugin.cpp:210
virtual bool select(Searchable &options)
Determine whether a plugin is of interest.
Collect hints for finding a particular plugin.
bool setSelector(YarpPluginSelector &selector)
Use a selector to find a plugin or plugins.
bool open(SharedLibraryFactory &factory)
Initialize a factory object based on the hints available.
Definition: YarpPlugin.cpp:80
bool readFromSearchable(Searchable &options, const std::string &name)
Configure settings from a configuration file or other searchable object.
A dummy Face for testing purposes.
Definition: FakeFace.h:19
Communicating via http.
Definition: HttpCarrier.h:95
A carrier for communicating locally within a process.
Definition: LocalCarrier.h:86
Communicating between two ports via MCAST.
Definition: McastCarrier.h:24
Communicating between two ports via a variant plain-text protocol originally designed for the yarp na...
Communicating between two ports via TCP.
Definition: TcpCarrier.h:19
Communicating with a port via TCP.
Definition: TcpFace.h:22
Communicating between two ports via a plain-text protocol.
Definition: TextCarrier.h:18
Communicating between two ports via UDP.
Definition: UdpCarrier.h:20
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCDebug(component,...)
Definition: LogComponent.h:128
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:29
std::string to_string(IntegerType x)
Definition: numeric.h:115
The components from which ports and connections are built.
An interface to the operating system, including Port based communication.