YARP
Yet Another Robot Platform
XmlRpcCarrier.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 "XmlRpcCarrier.h"
10 
11 #include "XmlRpcLogComponent.h"
12 
14 #include <yarp/os/Name.h>
15 #include <yarp/os/NetType.h>
16 #include <yarp/os/Bottle.h>
17 #include <yarp/os/Route.h>
18 #include <yarp/os/SizedWriter.h>
19 #include <yarp/os/Contactable.h>
20 #include <yarp/os/Network.h>
21 
22 #include <XmlRpc.h>
23 
24 #include <cstdio>
25 
26 using namespace yarp::os;
27 using YarpXmlRpc::XmlRpcValue;
28 using YarpXmlRpc::XmlRpcClient;
29 using YarpXmlRpc::XmlRpcServerConnection;
30 
31 void toXmlRpcValue(Value& vin, XmlRpcValue& vout)
32 {
33  if (vin.isInt32()) {
34  vout = vin.asInt32();
35  } else if (vin.isFloat64()) {
36  vout = vin.asFloat64();
37  } else if (vin.isString()) {
38  vout = std::string(vin.asString());
39  } else if (vin.isVocab()) {
40  vout = std::string("[") + std::string(vin.toString()) + "]";
41  } else if (vin.isList()) {
42  Bottle *bot = vin.asList();
43  bool struc = true;
44  int offset = 0;
45  std::string tag = bot->get(0).asString();
46  if (tag=="list") {
47  struc = false;
48  offset = 1;
49  } else if (tag=="dict") {
50  struc = true;
51  offset = 1;
52  } else {
53  // auto-detect
54  for (size_t i=0; i<bot->size(); i++) {
55  Value& vi = bot->get(i);
56  if (!vi.isList()) {
57  struc = false;
58  break;
59  }
60  if (vi.asList()->size()!=2) {
61  struc = false;
62  break;
63  }
64  }
65  }
66  if (struc) {
67  vout = XmlRpcValue();
68  for (size_t i=offset; i<bot->size(); i++) {
69  Bottle *boti = bot->get(i).asList();
70  XmlRpcValue& vouti=vout[std::string(boti->get(0).toString())]=XmlRpcValue();
71  toXmlRpcValue(boti->get(1),vouti);
72  }
73  } else {
74  vout = XmlRpcValue();
75  for (size_t i=offset; i<bot->size(); i++) {
76  XmlRpcValue& vouti = vout[i] = XmlRpcValue();
77  toXmlRpcValue(bot->get(i),vouti);
78  }
79  }
80  }
81 }
82 
84 {
85  Route route = proto.getRoute();
86  route.setFromName("rpc");
87  proto.setRoute(route);
88  return true;
89 }
90 
92 {
95  writer.write(sos);
96  sis.reset(sos.toString());
97  std::string header;
98  if (sender) {
99  header = sis.readLine();
100  }
101  std::string body = sis.readLine();
102  Value v;
103  if (header.length()>0 && header[0]=='q') {
104  body = "yarp.quit";
105  // XMLRPC does not need a quit message, this should get stripped
106  return false;
107  }
108  Bottle *bot = v.asList();
109  bot->fromString(body);
110  std::string methodName;
111  if (sender) {
112  methodName = bot->get(0).toString();
113  *bot = bot->tail();
114  }
115  XmlRpcValue args;
116  if (bot->size()==1) {
117  toXmlRpcValue(bot->get(0),args);
118  } else {
119  toXmlRpcValue(v,args);
120  }
121  std::string req;
122  if (sender) {
123  const Contact& addr = host.isValid()?host:proto.getStreams().getRemoteAddress();
124  XmlRpcClient c(addr.getHost().c_str(),(addr.getPort()>0)?addr.getPort():80);
125  c.generateRequest(methodName.c_str(),args);
126  req = c.getRequest();
127  } else {
128  XmlRpcServerConnection c(0, nullptr);
129  c.generateResponse(args.toXml());
130  req = c.getResponse();
131  }
132  int start = 0;
133  if (sender) {
134  if (req.length()<8) {
135  yCError(XMLRPCCARRIER, "XmlRpcCarrier fail");
136  return false;
137  }
138  for (char i : req) {
139  if (i == '\n') {
140  start++;
141  break;
142  }
143  start++;
144  }
145  if (!firstRound) {
146  Bytes b((char*)http.c_str(),http.length());
147  proto.os().write(b);
148  }
149  firstRound = false;
150  }
151  Bytes b((char*)req.c_str()+start,req.length()-start);
152  proto.os().write(b);
153 
154  return proto.os().isOk();
155 }
156 
157 
159 {
160  return write(proto,writer);
161 }
162 
163 
164 bool XmlRpcCarrier::shouldInterpretRosMessages(ConnectionState& proto)
165 {
166  // We need to set the interpretRos flag, which controls
167  // whether ROS-style admin messages are treated as
168  // admin messages or data messages in YARP.
169  // In the future, they should always be data messages.
170  // For now, they should be admin messages for all ports
171  // except ports tagged as corresponding to ros nodes.
172 
173  bool nodelike = false;
174  Contactable *port = proto.getContactable();
175  Property opt;
176  if (port) {
177  Property *pport = port->acquireProperties(true);
178  if (pport) {
179  opt = *pport;
180  }
181  port->releaseProperties(pport);
182  }
183  if (opt.check("node_like")) {
184  nodelike = true;
185  }
186 
187  Name n(proto.getRoute().getCarrierName() + "://test");
188  std::string rospass = n.getCarrierModifier("ros");
189  interpretRos = !nodelike;
190  if (rospass=="1"||rospass=="on") {
191  interpretRos = true;
192  }
193  if (rospass=="0"||rospass=="off") {
194  interpretRos = false;
195  }
196  return interpretRos;
197 }
198 
200 {
201  shouldInterpretRosMessages(proto);
202  std::string target = "POST /RPC2";
203  Name n(proto.getRoute().getCarrierName() + "://test");
204  std::string pathValue = n.getCarrierModifier("path");
205  if (pathValue!="") {
206  target = "POST /";
207  target += pathValue;
208  // on the wider web, we should provide real host names
209  host = NetworkBase::queryName(proto.getRoute().getToName());
210  }
211  target += " HTTP/1.1\n";
212  http = target;
213  Bytes b((char*)target.c_str(),target.length());
214  proto.os().write(b);
215  return true;
216 }
217 
218 
220 {
221  shouldInterpretRosMessages(proto);
222  sender = false;
223  auto* stream = new XmlRpcStream(proto.giveStreams(),
224  sender,
225  interpretRos);
226  if (stream == nullptr) {
227  return false;
228  }
229  proto.takeStreams(stream);
230  return true;
231 }
XmlRpcCarrier::respondToHeader
bool respondToHeader(yarp::os::ConnectionState &proto) override
Respond to the header.
Definition: XmlRpcCarrier.cpp:219
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
XmlRpcStream
Definition: XmlRpcStream.h:25
XmlRpcCarrier.h
Network.h
yarp::os::Route::getCarrierName
const std::string & getCarrierName() const
Get the carrier type of the route.
Definition: Route.cpp:126
yarp::os::Bottle::size
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:254
yarp::os::StringInputStream::reset
void reset()
Definition: StringInputStream.h:35
yarp::os::ConnectionState::giveStreams
virtual TwoWayStream * giveStreams()=0
Take ownership of the streams associated with the connection.
yarp::os::OutputStream::write
virtual void write(char ch)
Write a single byte to the stream.
Definition: OutputStream.cpp:17
XmlRpcCarrier::expectSenderSpecifier
bool expectSenderSpecifier(yarp::os::ConnectionState &proto) override
Expect the name of the sending port.
Definition: XmlRpcCarrier.cpp:83
yarp::os::StringOutputStream::toString
std::string toString() const
Definition: StringOutputStream.h:33
yarp::os::Contactable::releaseProperties
virtual void releaseProperties(Property *prop)=0
End access unstructured port properties.
yarp::os::Bottle::fromString
void fromString(const std::string &text)
Initializes bottle from a string.
Definition: Bottle.cpp:207
yarp::os::SizedWriter::write
virtual void write(OutputStream &os)
Definition: SizedWriter.cpp:19
yarp::os::Route
Information about a connection between two ports.
Definition: Route.h:32
yarp::os::StringOutputStream
An OutputStream that produces a string.
Definition: StringOutputStream.h:25
Name.h
NetType.h
yarp::os::Value::isString
virtual bool isString() const
Checks if value is a string.
Definition: Value.cpp:159
yarp::os::NetworkBase::queryName
static Contact queryName(const std::string &name)
Find out information about a registered name.
Definition: Network.cpp:998
yarp::os::ConnectionState::takeStreams
virtual void takeStreams(TwoWayStream *streams)=0
Provide streams to be used with the connection.
yarp::os::ConnectionState::os
OutputStream & os()
Shorthand for getOutputStream()
Definition: ConnectionState.h:117
yarp::os::ConnectionState::getRoute
virtual const Route & getRoute() const =0
Get the route associated with this connection.
Route.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::Contact::getPort
int getPort() const
Get the port number associated with this Contact for socket communication.
Definition: Contact.cpp:242
yarp::os::Value::isFloat64
virtual bool isFloat64() const
Checks if value is a 64-bit floating point number.
Definition: Value.cpp:153
XMLRPCCARRIER
const yarp::os::LogComponent & XMLRPCCARRIER()
Definition: XmlRpcLogComponent.cpp:16
yarp::os::ConnectionState::setRoute
virtual void setRoute(const Route &route)=0
Set the route associated with this connection.
yarp::os::Contactable::acquireProperties
virtual Property * acquireProperties(bool readOnly)=0
Access unstructured port properties.
yarp::os::Value::asString
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
yarp::os::Name::getCarrierModifier
std::string getCarrierModifier(const char *mod, bool *hasModifier=nullptr)
Definition: Name.cpp:47
yarp::os::InputStream::readLine
std::string readLine(const char terminal='\n', bool *success=nullptr)
Read a block of text terminated with a specific marker (or EOF).
Definition: InputStream.cpp:57
yarp::os::TwoWayStream::getRemoteAddress
virtual const Contact & getRemoteAddress() const =0
Get the address of the remote side of the stream.
yarp::os::Name
Simple abstraction for a YARP port name.
Definition: Name.h:22
yarp::os::StringInputStream
An InputStream that reads from a string.
Definition: StringInputStream.h:25
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::ConnectionState::getStreams
virtual TwoWayStream & getStreams()=0
Access the streams associated with the connection.
yarp::os::Bytes
A simple abstraction for a block of bytes.
Definition: Bytes.h:28
XmlRpcLogComponent.h
yarp::os::Value::isList
virtual bool isList() const
Checks if value is a list.
Definition: Value.cpp:165
yarp::os::Bottle::tail
Bottle tail() const
Get all but the first element of a bottle.
Definition: Bottle.cpp:391
StringOutputStream.h
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::Value::asInt32
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:207
XmlRpcCarrier::write
bool write(yarp::os::ConnectionState &proto, yarp::os::SizedWriter &writer) override
Write a message.
Definition: XmlRpcCarrier.cpp:91
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yarp::os::Route::setFromName
void setFromName(const std::string &fromName)
Set the source of the route.
Definition: Route.cpp:101
yarp::os::Contact::isValid
bool isValid() const
Checks if a Contact is tagged as valid.
Definition: Contact.cpp:301
yarp::os::Contact::getHost
std::string getHost() const
Get the host name associated with this Contact for socket communication.
Definition: Contact.cpp:231
yarp::os::Contact
Represents how to reach a part of a YARP network.
Definition: Contact.h:39
yarp::os::Route::getToName
const std::string & getToName() const
Get the destination of the route.
Definition: Route.cpp:106
yarp::os::Value::asList
virtual Bottle * asList() const
Get list value.
Definition: Value.cpp:243
XmlRpcCarrier::reply
bool reply(yarp::os::ConnectionState &proto, yarp::os::SizedWriter &writer) override
Definition: XmlRpcCarrier.cpp:158
yarp::os::ConnectionState::getContactable
virtual Contactable * getContactable() const =0
Get the port associated with the connection.
yarp::os::Value::toString
std::string toString() const override
Return a standard text representation of the content of the object.
Definition: Value.cpp:359
yarp::sig::file::write
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
Definition: ImageFile.cpp:971
yarp::os::Value
A single value (typically within a Bottle).
Definition: Value.h:47
XmlRpcCarrier::sendHeader
bool sendHeader(yarp::os::ConnectionState &proto) override
Write a header appropriate to the carrier to the connection, followed by any carrier-specific data.
Definition: XmlRpcCarrier.cpp:199
yarp::os::Value::asFloat64
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:225
SizedWriter.h
Bottle.h
yarp::os::SizedWriter
Minimal requirements for an efficient Writer.
Definition: SizedWriter.h:36
yarp::os::Value::isVocab
virtual bool isVocab() const
Checks if value is a vocabulary identifier.
Definition: Value.cpp:177
yarp::os::Property
A class for storing options and configuration information.
Definition: Property.h:37
Contactable.h
yarp::os::Contactable
An abstract port.
Definition: Contactable.h:38
toXmlRpcValue
void toXmlRpcValue(Value &vin, XmlRpcValue &vout)
Definition: XmlRpcCarrier.cpp:31
yarp::os::Value::isInt32
virtual bool isInt32() const
Checks if value is a 32-bit integer.
Definition: Value.cpp:135