YARP
Yet Another Robot Platform
PortMonitor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #include <yarp/os/Log.h>
10 #include <string>
11 #include <yarp/os/ResourceFinder.h>
13 #include <yarp/os/Route.h>
14 #include <yarp/os/Contactable.h>
15 #include <yarp/os/Network.h>
16 
17 #include "PortMonitor.h"
18 #include "MonitorLogComponent.h"
19 
20 
21 
22 using namespace yarp::os;
23 
24 
29 // Read connection settings.
31 {
32  portName = proto.getRoute().getToName();
33  sourceName = proto.getRoute().getFromName();
34  group = getPeers().add(portName,this);
35  if (!group) {
36  return false;
37  }
38 
39  Property options;
40  options.fromString(proto.getSenderSpecifier());
41  options.put("source", sourceName);
42  options.put("destination", portName);
43  options.put("sender_side",
44  (proto.getContactable()->getName() == sourceName) ? 1 : 0);
45  options.put("receiver_side",
46  (proto.getContactable()->getName() == portName) ? 1 : 0);
47  options.put("carrier", proto.getRoute().getCarrierName());
48  return configureFromProperty(options);
49 }
50 
52 {
53  delete binder;
54  binder = nullptr;
55 
56  std::string script = options.check("type", Value("lua")).asString();
57  std::string filename = options.check("file", Value("modifier")).asString();
58  std::string constraint = options.check("constraint", Value("")).asString();
59  // context is used to find the script files
60  std::string context = options.check("context", Value("")).asString();
61 
62  // check which monitor should be used
63  if((binder = MonitorBinding::create(script.c_str())) == nullptr)
64  {
65  yCError(PORTMONITORCARRIER, R"(Currently only 'lua' script and 'dll' object is supported by portmonitor)");
66  return false;
67  }
68 
69  // set the acceptance constraint
70  binder->setAcceptConstraint(constraint.c_str());
71 
72  std::string strFile = filename;
73 
74  if(script != "dll")
75  {
77  rf.setDefaultContext(context);
78  rf.configure(0, nullptr);
79  strFile = rf.findFile(filename);
80  if(strFile.empty()) {
81  strFile = rf.findFile(filename+".lua");
82  }
83  }
84 
85  // provide some useful information for the monitor object
86  // which can be accessed in the create() callback.
87  Property info;
88  info.clear();
89  info.put("filename", strFile);
90  info.put("type", script);
91  info.put("source", options.find("source").asString());
92  info.put("destination", options.find("destination").asString());
93  info.put("sender_side", options.find("sender_side").asInt32());
94  info.put("receiver_side",options.find("receiver_side").asInt32());
95  info.put("carrier", options.find("carrier").asString());
96 
98  bReady = binder->load(info);
100  return bReady;
101 }
102 
104 {
105  if(!bReady) {
106  return;
107  }
109  binder->setParams(params);
111 }
112 
114 {
115  if(!bReady) {
116  return;
117  }
119  binder->getParams(params);
121 }
122 
123 
125 {
126  if(!bReady) {
127  return reader;
128  }
129 
130  // When we are here,
131  // the incoming data should be accessed using localReader.
132  // The reader passed to this function is infact empty.
133  // first check if we need to call the update callback
134  if(!binder->hasUpdate()) {
135  localReader->setParentConnectionReader(&reader);
136  return *localReader;
137  }
138 
140  yarp::os::Things thing;
141  thing.setConnectionReader(*localReader);
142  yarp::os::Things& result = binder->updateData(thing);
144  con.reset();
145  if(result.write(con.getWriter())) {
146  con.getReader().setParentConnectionReader(&reader);
147  return con.getReader();
148  }
149  return *localReader;
150 }
151 
153 {
154  if(!bReady) {
155  return false;
156  }
157 
158  bool result = false;
159  localReader = &reader;
160  // If no accept callback avoid calling the binder
161  if(binder->hasAccept())
162  {
164  Things thing;
165  // set the reference connection reader
166  thing.setConnectionReader(reader);
167  result = binder->acceptData(thing);
169  if(!result) {
170  return false;
171  }
172 
173  // When data is read here using the reader passed to this functions,
174  // then it won't be available for modifyIncomingData(). Thus, we write
175  // it to a dummy connection and pass it to the modifyOutgoingData() using
176  // localReader.
177  // localReader points to a connection reader which contains
178  // either the original or modified data.
179  if(thing.hasBeenRead()) {
180  con.reset();
181  if(thing.write(con.getWriter())) {
182  localReader = &con.getReader();
183  }
184  }
185  }
186 
187  if(group!=nullptr) {
188  getPeers().lock();
189  result = group->acceptIncomingData(this);
190  getPeers().unlock();
191  }
192  return result;
193 }
194 
195 
197 {
198  if(!bReady) {
199  return writer;
200  }
201 
202  // If no update callback avoid calling it
203  if(!binder->hasUpdate()) {
204  return writer;
205  }
206 
208  thing.reset();
209  thing.setPortWriter(const_cast<yarp::os::PortWriter*>(&writer));
210  yarp::os::Things& result = binder->updateData(thing);
212  return *result.getPortWriter();
213 }
214 
216 {
217  if(!bReady) {
218  return false;
219  }
220 
221  // If no accept callback avoid calling it
222  if(!binder->hasAccept()) {
223  return true;
224  }
225 
227  yarp::os::Things thing;
228  thing.setPortWriter(const_cast<yarp::os::PortWriter*>(&writer));
229  bool result = binder->acceptData(thing);
231  return result;
232 }
233 
235 {
236  if(!bReady) {
237  return reader;
238  }
239 
240  // If no updateReply callback avoid calling it
241  if(!binder->hasUpdateReply()) {
242  return reader;
243  }
244 
246  thing.reset();
247  thing.setPortReader(&reader);
248  yarp::os::Things& result = binder->updateReply(thing);
250  return *result.getPortReader();
251 }
252 
257 ElectionOf<PortMonitorGroup> *PortMonitor::peers = nullptr;
258 
259 // Make a singleton manager for finding peer carriers.
260 ElectionOf<PortMonitorGroup>& PortMonitor::getPeers()
261 {
263  if (peers==nullptr) {
264  peers = new ElectionOf<PortMonitorGroup>;
267  } else {
269  }
270  return *peers;
271 }
272 
273 // Decide whether data should be accepted, for real.
275 {
276  //bool accept = true;
277  for (auto& it : peerSet)
278  {
279  PortMonitor *peer = it.first;
280  if(peer != source)
281  {
282  peer->lock();
283  // TODO: check whether we should return false if
284  // the peer monitor object is not ready!
285  if(peer->getBinder()) {
286  peer->getBinder()->peerTrigged();
287  }
288  peer->unlock();
289  }
290  }
291  return source->getBinder()->canAccept();
292 }
const yarp::os::LogComponent & PORTMONITORCARRIER()
static MonitorBinding * create(const char *script_type)
factory method
virtual bool canAccept()=0
virtual bool peerTrigged()=0
virtual bool acceptIncomingData(PortMonitor *source)
Allow to monitor and modify port data from Lua script Under development.
Definition: PortMonitor.h:54
void lock() const
Definition: PortMonitor.h:105
void getCarrierParams(yarp::os::Property &params) const override
Get carrier configuration and deliver it by port administrative commands.
yarp::os::ConnectionReader & modifyIncomingData(yarp::os::ConnectionReader &reader) override
Modify incoming payload data, if appropriate.
void unlock() const
Definition: PortMonitor.h:106
const yarp::os::PortWriter & modifyOutgoingData(const yarp::os::PortWriter &writer) override
Modify outgoing payload data, if appropriate.
yarp::os::PortReader & modifyReply(yarp::os::PortReader &reader) override
Modify reply payload data, if appropriate.
void setCarrierParams(const yarp::os::Property &params) override
Configure carrier from port administrative commands.
bool configureFromProperty(yarp::os::Property &options) override
Definition: PortMonitor.cpp:51
bool acceptIncomingData(yarp::os::ConnectionReader &reader) override
Determine whether incoming data should be accepted.
bool acceptOutgoingData(const yarp::os::PortWriter &writer) override
Determine whether outgoing data should be accepted.
MonitorBinding * getBinder()
Definition: PortMonitor.h:108
bool configure(yarp::os::ConnectionState &proto) override
Class PortMonitor.
Definition: PortMonitor.cpp:30
An interface for reading from a network connection.
virtual void setParentConnectionReader(ConnectionReader *parentConnectionReader)
Set ConnectionReader to be used for reading the envelope.
The basic state of a connection - route, streams in use, etc.
virtual Contactable * getContactable() const =0
Get the port associated with the connection.
virtual const Route & getRoute() const =0
Get the route associated with this connection.
virtual std::string getSenderSpecifier() const =0
Extract a name for the sender, if the connection type supports that.
virtual std::string getName() const
Get name of port.
Definition: Contactable.cpp:17
static void unlock()
Call post() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1467
static void lock()
Call wait() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1462
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition: PortReader.h:28
Interface implemented by all objects that can write themselves to the network, such as Bottle objects...
Definition: PortWriter.h:27
A class for storing options and configuration information.
Definition: Property.h:37
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:1034
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1046
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:998
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:1024
void clear()
Remove all associations.
Definition: Property.cpp:1040
Helper class for finding config files and other external resources.
bool setDefaultContext(const std::string &contextName)
Sets the context for the current ResourceFinder object.
bool configure(int argc, char *argv[], bool skipFirstArgument=true)
Sets up the ResourceFinder.
std::string findFile(const std::string &name)
Find the full path to a file.
const std::string & getToName() const
Get the destination of the route.
Definition: Route.cpp:106
const std::string & getCarrierName() const
Get the carrier type of the route.
Definition: Route.cpp:126
const std::string & getFromName() const
Get the source of the route.
Definition: Route.cpp:96
Base class for generic things.
Definition: Things.h:22
bool setConnectionReader(yarp::os::ConnectionReader &reader)
set a reference to a ConnectionReader
Definition: Things.cpp:49
yarp::os::PortWriter * getPortWriter()
Definition: Things.cpp:34
yarp::os::PortReader * getPortReader()
Definition: Things.cpp:44
bool write(yarp::os::ConnectionWriter &connection)
Definition: Things.cpp:57
void setPortWriter(yarp::os::PortWriter *writer)
Set the reference to a PortWriter object.
Definition: Things.cpp:29
bool hasBeenRead()
Definition: Things.cpp:78
A single value (typically within a Bottle).
Definition: Value.h:47
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:207
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
#define yCError(component,...)
Definition: LogComponent.h:157
#define yCAssert(component, x)
Definition: LogComponent.h:172
An interface to the operating system, including Port based communication.