Discussion for RPC improvements

From Wiki for iCub and Friends
Revision as of 19:24, 7 November 2008 by Paulfitz (talk | contribs) (Proposed changes to YARP)
Jump to: navigation, search

Introduction

We discuss here some problems of the current RPC-like implementation. Some suggestions for improvement are proposed below.

Problems with RPC

Technically YARP does not have an RPC implementation, what we usually call a RPC port is the result of using the port in a certain way. In fact it is impossible to know if a port is what we call an "RPC" port, unless we check the real implementation of the communication between client and server.

The only way a user has to determine if a port is an RPC is to check for the port name, since we often append :rpc to the name of the port. Clearly this is not enforced by YARP.

The user ignorance can cause troubles, because ports that implement RPCs do not behave like normal ports, mainly:

  • they do not support multiple output connection, it is easy to break a port by connecting a yarp read to it
  • it is difficult to observe the traffic traveling to/from a port
  • user will often make two connections between a pair of ports rather than just the one needed for RPC

Suggestions

Create a specific type for RPC ports. RPC ports could thus have their own properties and behavior. For example:

  • it could be impossible to connect more than one "output" connection
  • RPC ports could have a dedicated "sniffer" port that broadcast all traffic passing through it
  • RPC ports could enforce the use of only "point-to-point" carriers (refusing mcast connections, of maybe even udp)

Along this line (less important) we could create monodirectional streaming ports that do not allow to expect replies when writing a message. This could be useful to discourage the use of the current RPC mechanism.

Proposed changes to YARP

An easy change:

  • Common user action wanting to sniff the output of a port would be to connect an input to it. This doesn't work for a port expecting a reply right now, but it could easily be made to work, and should be.
  • This lets messages sent from an output RPC port be sniffed in an intuitive way.

But what about replies?

  • There is no way currently to sniff replies, except by using the "yarp forward" mechanism to put in a middleman.
  • Replies are just not available to be streamed right now in YARP, unlike ordinary messages.
  • One possibility would be to declare that an input RPC port would offer the replies it makes as streamed output, if connected to as an input.

With these two changes together, the command line interface would be as follows.

  • Suppose /src and /dest are two RPC ports, which are connected:
 yarp connect /src /dest
  • To read commands output on /src it would suffice to do:
 yarp read ... /src
  • (this is what a user would expect I guess, and it is just unfortunate that YARP doesn't do it right now)
  • Of course, what we really want is output and replies. There's no clean way of fitting that into the semantics of connecting to /src, but we could squeeze it into the semantics of connecting from /dest:
 yarp read ... /dest
  • Right now in YARP, this would give nothing, so there is space for making this mean what we want it to mean. It could give just replies, or (better) message/reply pairs. This output could be generated only when needed, so it wouldn't cause a general performance hit.

Implementing this behavior for /dest is very easy in current YARP. If we define types for RPC ports, then we can set it up and have it be standard behavior at the user level, without needing to change the existing port implementation.

Class sketch:

 // Contactable base class is an abstract interface specifying general port abilities common to e.g Port and BufferedPort
 class yarp::os::RpcInputPort : public yarp::os::Contactable {
    bool read(PortReader& input);
    bool reply(PortWriter& output);
    bool setReplier(RpcCallback& replier);  // make a callback for handling replies, defined below
 };
 class yarp::os::RpcOutputPort : public yarp::os::Contactable {
    bool write(PortWriter& output, PortReader& reply);
 };
 class yarp::os::RpcCallback {
    // this is like the usual read(ConnectionReader& reader) callback, except we prepare and supply
    // the writer needed for the reply rather than expecting the user to ask for it using getWriter()
    virtual bool reply(ConnectionReader& reader, ConnectionWriter& writer);
 };
 // could also offer typed versions RpcInputPortOf<Tmessage,Treply> and RpcOutputPortOf<Tmessage,Treply>
 // don't think it is really necessary though, what do you think?

Since YARP now knows which is an input and which is an output port, and that they are intended as an RPC pair, we can go ahead and give error messages for common mistakes. We can also go ahead and make an RpcInputPort provide a commentary on the messages it receives and replies to on its (unused) output.

RpcOutputPort should complain if anyone tries to send it data externally (to catch the case of a user feeling they have to connect RPC port pairs bidirectionally, which would now be a problem since the input port will actually now produce data if requested).