YARP
Yet Another Robot Platform
PortMonitor.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 
6 #include <yarp/os/Log.h>
7 #include <string>
10 #include <yarp/os/Route.h>
11 #include <yarp/os/Contactable.h>
12 #include <yarp/os/LogStream.h>
13 #include <yarp/os/Network.h>
14 
15 #include "PortMonitor.h"
16 #include "MonitorLogComponent.h"
17 
18 
19 
20 using namespace yarp::os;
21 
22 
27 // Read connection settings.
29 {
31 
32  portName = proto.getRoute().getToName();
33  sourceName = proto.getRoute().getFromName();
34  group = getPeers().add(portName,this);
35  if (!group) {
36  yCError(PORTMONITORCARRIER) << "Cannot find group";
37  return false;
38  }
39 
40  Property options;
41  options.fromString(proto.getSenderSpecifier());
42  options.put("source", sourceName);
43  options.put("destination", portName);
44  options.put("sender_side",
45  (proto.getContactable()->getName() == sourceName) ? 1 : 0);
46  options.put("receiver_side",
47  (proto.getContactable()->getName() == portName) ? 1 : 0);
48  options.put("carrier", proto.getRoute().getCarrierName());
49  return configureFromProperty(options);
50 }
51 
53 {
55 
56  delete binder;
57  binder = nullptr;
58 
59  std::string script = options.check("type", Value("lua")).asString();
60  std::string filename = options.check("file", Value("modifier")).asString();
61  std::string constraint = options.check("constraint", Value("")).asString();
62  // context is used to find the script files
63  std::string context = options.check("context", Value("")).asString();
64 
65  // check which monitor should be used
66  if((binder = MonitorBinding::create(script.c_str())) == nullptr)
67  {
68  yCError(PORTMONITORCARRIER, R"(Currently only 'lua' script and 'dll' object is supported by portmonitor)");
69  return false;
70  }
71 
72  // set the acceptance constraint
73  binder->setAcceptConstraint(constraint.c_str());
74 
75  std::string strFile = filename;
76 
77  if(script != "dll")
78  {
80  rf.setDefaultContext(context);
81  rf.configure(0, nullptr);
82  strFile = rf.findFile(filename);
83  if(strFile.empty()) {
84  strFile = rf.findFile(filename+".lua");
85  }
86  }
87 
88  // provide some useful information for the monitor object
89  // which can be accessed in the create() callback.
90  Property info;
91  info.clear();
92  info.put("filename", strFile);
93  info.put("type", script);
94  info.put("source", options.find("source").asString());
95  info.put("destination", options.find("destination").asString());
96  info.put("sender_side", options.find("sender_side").asInt32());
97  info.put("receiver_side",options.find("receiver_side").asInt32());
98  info.put("carrier", options.find("carrier").asString());
99 
101  bReady = binder->load(info);
103  return bReady;
104 }
105 
107 {
109 
110  if(!bReady) {
111  return;
112  }
114  binder->setParams(params);
116 }
117 
119 {
121 
122  if(!bReady) {
123  return;
124  }
126  binder->getParams(params);
128 }
129 
130 
132 {
134 
135  if(!bReady) {
136  return reader;
137  }
138 
139  // When we are here,
140  // the incoming data should be accessed using localReader.
141  // The reader passed to this function is infact empty.
142  // first check if we need to call the update callback
143  if(!binder->hasUpdate()) {
144  localReader->setParentConnectionReader(&reader);
145  return *localReader;
146  }
147 
149  yarp::os::Things thing;
150  thing.setConnectionReader(*localReader);
151  yarp::os::Things& result = binder->updateData(thing);
153  con.reset();
154  if(result.write(con.getWriter())) {
155  auto& cReader = con.getReader(reader.getWriter());
156  cReader.setParentConnectionReader(&reader);
157  if (result.getPortReader() != nullptr) {
158  cReader.getWriter()->setReplyHandler(*result.getPortReader());
159  }
160  return cReader;
161  }
162  return *localReader;
163 }
164 
166 {
168 
169  if(!bReady) {
170  return false;
171  }
172 
173  bool result = false;
174  localReader = &reader;
175  // If no accept callback avoid calling the binder
176  if(binder->hasAccept())
177  {
179  Things thing;
180  // set the reference connection reader
181  thing.setConnectionReader(reader);
182  result = binder->acceptData(thing);
184  if(!result) {
185  return false;
186  }
187 
188  // When data is read here using the reader passed to this functions,
189  // then it won't be available for modifyIncomingData(). Thus, we write
190  // it to a dummy connection and pass it to the modifyOutgoingData() using
191  // localReader.
192  // localReader points to a connection reader which contains
193  // either the original or modified data.
194  if(thing.hasBeenRead()) {
195  con.reset();
196  if(thing.write(con.getWriter())) {
197  localReader = &con.getReader(reader.getWriter());
198  }
199  }
200  }
201 
202  if(group!=nullptr) {
203  getPeers().lock();
204  result = group->acceptIncomingData(this);
205  getPeers().unlock();
206  }
207  return result;
208 }
209 
210 
212 {
214 
215  if(!bReady) {
216  return writer;
217  }
218 
219  // If no update callback avoid calling it
220  if(!binder->hasUpdate()) {
221  return writer;
222  }
223 
225  thing.reset();
226  thing.setPortWriter(const_cast<yarp::os::PortWriter*>(&writer));
227  yarp::os::Things& result = binder->updateData(thing);
229  return *result.getPortWriter();
230 }
231 
233 {
235 
236  if(!bReady) {
237  return false;
238  }
239 
240  // If no accept callback avoid calling it
241  if(!binder->hasAccept()) {
242  return true;
243  }
244 
246  yarp::os::Things thing;
247  thing.setPortWriter(const_cast<yarp::os::PortWriter*>(&writer));
248  bool result = binder->acceptData(thing);
250  return result;
251 }
252 
254 {
256 
257  if(!bReady) {
258  return reader;
259  }
260 
261  // If no updateReply callback avoid calling it
262  if(!binder->hasUpdateReply()) {
263  return reader;
264  }
265 
267  thing.reset();
268  thing.setPortReader(&reader);
269  yarp::os::Things& result = binder->updateReply(thing);
271  return *result.getPortReader();
272 }
273 
278 ElectionOf<PortMonitorGroup> *PortMonitor::peers = nullptr;
279 
280 // Make a singleton manager for finding peer carriers.
281 ElectionOf<PortMonitorGroup>& PortMonitor::getPeers()
282 {
284 
286  if (peers==nullptr) {
287  peers = new ElectionOf<PortMonitorGroup>;
290  } else {
292  }
293  return *peers;
294 }
295 
296 // Decide whether data should be accepted, for real.
298 {
300 
301  //bool accept = true;
302  for (auto& it : peerSet)
303  {
304  PortMonitor *peer = it.first;
305  if(peer != source)
306  {
307  peer->lock();
308  // TODO: check whether we should return false if
309  // the peer monitor object is not ready!
310  if(peer->getBinder()) {
311  peer->getBinder()->peerTrigged();
312  }
313  peer->unlock();
314  }
315  }
316  return source->getBinder()->canAccept();
317 }
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:51
void lock() const
Definition: PortMonitor.h:102
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:103
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:52
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:105
bool configure(yarp::os::ConnectionState &proto) override
Class PortMonitor.
Definition: PortMonitor.cpp:28
An interface for reading from a network connection.
virtual void setParentConnectionReader(ConnectionReader *parentConnectionReader)
Set ConnectionReader to be used for reading the envelope.
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
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:14
static void unlock()
Call post() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1464
static void lock()
Call wait() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1459
Interface implemented by all objects that can read themselves from the network, such as Bottle object...
Definition: PortReader.h:25
Interface implemented by all objects that can write themselves to the network, such as Bottle objects...
Definition: PortWriter.h:24
A class for storing options and configuration information.
Definition: Property.h:34
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:1051
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1063
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
void clear()
Remove all associations.
Definition: Property.cpp:1057
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:103
const std::string & getCarrierName() const
Get the carrier type of the route.
Definition: Route.cpp:123
const std::string & getFromName() const
Get the source of the route.
Definition: Route.cpp:93
Base class for generic things.
Definition: Things.h:19
bool setConnectionReader(yarp::os::ConnectionReader &reader)
set a reference to a ConnectionReader
Definition: Things.cpp:46
yarp::os::PortWriter * getPortWriter()
Definition: Things.cpp:31
yarp::os::PortReader * getPortReader()
Definition: Things.cpp:41
bool write(yarp::os::ConnectionWriter &connection)
Definition: Things.cpp:54
void setPortWriter(yarp::os::PortWriter *writer)
Set the reference to a PortWriter object.
Definition: Things.cpp:26
bool hasBeenRead()
Definition: Things.cpp:75
A single value (typically within a Bottle).
Definition: Value.h:45
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:204
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCAssert(component, x)
Definition: LogComponent.h:169
#define yCTrace(component,...)
Definition: LogComponent.h:85
An interface to the operating system, including Port based communication.