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 
9 #include <yarp/os/YarpPlugin.h>
10 #include <yarp/os/impl/FakeFace.h>
16 #include <yarp/os/impl/Protocol.h>
18 #include <yarp/os/impl/TcpFace.h>
21 
22 #include <vector>
23 #include <mutex>
24 
25 using namespace yarp::os::impl;
26 using namespace yarp::os;
27 
28 namespace {
29 YARP_OS_LOG_COMPONENT(CARRIERS, "yarp.os.Carriers")
30 } // namespace
31 
32 namespace {
33 std::string bytes_to_string(const Bytes& header)
34 {
35  std::string ret;
36  for (size_t i = 0; i < header.length(); i++) {
37  ret += yarp::conf::numeric::to_string(header.get()[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 }
53 
54 #ifndef DOXYGEN_SHOULD_SKIP_THIS
55 
56 class Carriers::Private : public YarpPluginSelector
57 {
58 public:
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 
76 std::mutex Carriers::Private::mutex{};
77 
78 Carrier* 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 
113 Carrier* 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 
138 bool 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 
167 bool 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 
182 bool 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 
196 bool 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 
204 Carriers::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 
218 Carriers::~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 
233 Carrier* Carriers::chooseCarrier(const std::string& name)
234 {
235  return getInstance().mPriv->chooseCarrier(name);
236 }
237 
238 Carrier* 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 
250 Face* Carriers::listen(const Contact& address)
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:74
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:25
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:45
virtual Carrier * create() const =0
Factory method.
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...
Collection of carriers, a singleton.
Definition: Carriers.h:30
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:36
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:21
virtual bool open(const Contact &address)=0
Start listening to the given address.
virtual OutputProtocol * write(const Contact &address)=0
Try to reach out and talk to someone.
static bool registerCarrier(const char *name, const char *dll)
Register a carrier to make available at runtime.
Definition: Network.cpp:1923
The output side of an active connection between two ports.
A class for storing options and configuration information.
Definition: Property.h:34
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:66
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
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:45
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
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:21
Communicating via http.
Definition: HttpCarrier.h:97
A carrier for communicating locally within a process.
Definition: LocalCarrier.h:88
Communicating between two ports via MCAST.
Definition: McastCarrier.h:26
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:21
Communicating with a port via TCP.
Definition: TcpFace.h:24
Communicating between two ports via a plain-text protocol.
Definition: TextCarrier.h:20
Communicating between two ports via UDP.
Definition: UdpCarrier.h:22
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCDebug(component,...)
Definition: LogComponent.h:109
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:35
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.