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