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