This is the protocol used for a single connection from an output port to an input port. We discuss how this process gets initiated in the next section. At the point of creation of a connection, the following information is needed:
The connection protocol has several phases – header, index, and body.
This is the basic pattern of YARP communication between ports. Clearly different carriers have a lot of freedom in how they operate.
Y
A
0xE4
0x1E
0x00
0x00
R
P
}. Another possible variant is: {Y
A
0x64
0x1E
0x00
0x00
R
P
}. The first version identifies a connection that sends acknowledgements; the second is for connections that omit acknowledgements.Y
A
B1
B2
0x00
0x00
R
P
}, where (B1
,B2
) is a (little-endian) two-byte integer specifying a socket-port number (unused).Y
A
0x0A
0x00
0x00
0x00
R
P
}. This identifies the length of the "index header" as 10 (0x0A
).LEN
0x01
0xFF
0xFF
0xFF
0xFF
0xFF
0xFF
0xFF
0xFF
}. LEN
is the number of blocks of user data need to be sent. This byte-sequence says there are LEN
send blocks, 1 reply block expected, and that the sizes will be listed individually next (this odd format is for backward compatibility with older YARP versions).LEN
4-byte little-endian integers, one for each of the LEN
blocks of user data, giving the length of each block.0x00
0x00
0x00
0x00
}. This asks for a reply length of 0.Y
A
B1
B2
B3
B4
R
P
}, where (B1
,B2
,B3
,B4
) is a little-endian integer giving a length (could be 0). It then sends that number of extra bytes.Y
A
0x61
0x1E
0x00
0x00
R
P
}. The following variant of this should also be accepted: {Y
A
0xE1
0x1E
0x00
0x00
R
P
} (it is the same thing).Y
A
0x62
0x1E
0x00
0x00
R
P
}. The following variant of this should also be accepted: {Y
A
0xE2
0x1E
0x00
0x00
R
P
} (it is the same thing).C
O
N
N
E
C
T
}.\n
.\n
.This is essentially the same as the tcp carrier, except that there is no header reply, and there is a shift in protocol after header transmission on both sides to an ACE shared memory stream. This carrier is currently being reworked to make its specification independent of ACE, and to further improve efficiency in an existing implementation.
The advantage of this carrier is that it is fast – the best way to send messages between processes on a single machine. Of course, it doesn't work for processes on different machines.
This carrier is designed specifically for communication between threads in a single process. Giving a specification for the protocol it uses has low priority, since two such threads are unlikely to be using different YARP implementations.
Here are the currently known protocol specifiers. The "shmem" carrier is not yet documented, but is implemented in the C++ version of YARP.
8-byte magic number | protocol | variant |
---|---|---|
Y A 0x61 0x1E 0x00 0x00 R P | udp | |
Y A 0xE1 0x1E 0x00 0x00 R P | udp | |
Y A 0x62 0x1E 0x00 0x00 R P | mcast | |
Y A 0xE2 0x1E 0x00 0x00 R P | mcast | |
Y A 0x63 0x1E 0x00 0x00 R P | shmem | |
Y A 0xE3 0x1E 0x00 0x00 R P | shmem | |
Y A 0x64 0x1E 0x00 0x00 R P | tcp | without acks |
Y A 0xE4 0x1E 0x00 0x00 R P | tcp | with acks |
C O N N E C T | text | without acks |
C O N N A C K | text | with acks |
L O C A L I T Y | local |
Every port is always available for new connections from external entities - to request that new connections between ports be created, old connections be removed, to inquire after status, etc. % The protocol used for communicating with a port is layered on top of the protocol described in the previous section. Any carrier can be used. The "payload data" is as follows:
0x00
,0x00
,0x00
,0x00
,~
,CHAR
,0x00
,0x01
}.CHAR
is a character that identifies what the message is about.CHAR
= d
: this header is used to signal that user data is arriving next, as opposed to a port commandCHAR
= anything else: this signals that a port command follows.for the port command case (CHAR
= 0x00
) the remainder of the message is interpreted as a string S
.
S
begins with /
, e.g. /read
: this is a request to add a Connection to the named InputPort.S
begins with !
, e.g. !/read
: this is a request to remove a Connection to the named InputPort.S
begins with ~, e.g.
~/read`: this is a request to remove a Connection from the named OutputPort.S
is *
: this is a request for the port to dump information about what it is connected to.S
is q
: the specific connection that the command is received on should now shut down.S
is a
: this is like d
, signalling that data should be expected, but the data will not be passed on to the client of the port. Instead it will be processed internally according to The administrative interface to YARP ports. This is a more user-friendly interface for communicating with a port.Alternatively, with the "text" carrier, we send a string terminated in \n
. This is the string S
. The first letter is copied to be CHAR
.
Port names in YARP can contain multiple special elements. We've seen names such as /write
. We can also have names such as udp://write
which means "connect to the port
named `/write` using the udp carrier".
We can also prepend a network selector of the form /net=NETNAME/
. For example, a name such as udp://net=196/write
means "connect to the port named /write
using the udp carrier, and make the connection on the network with ip addresses beginning with 196
". This is useful in scenarios with multiple networks, where it may be desirable to route connections through particular networks (for example, to devote a network to time-critical traffic). This functionality is supported primarily with the help of the name server. The ip it reports for a machine is usually a reasonable default, but the user can choose using "net=" to request a name on a particular network.
Symbolic network names can be configured. This process is not yet specified. You can do it right now by setting properties of a fake port called networks
(no leading slash), where the properties are symbolic names and their values are the numeric network IP prefix. But this process will change.
An implementation of YARP2 must support at least the "tcp" carrier. Other carriers that may be supported: "text", "udp", "mcast", "shmem", "local".
As a place to start an implementation, the "text" carrier is very simple to implement, and can masquerade as "tcp" for the purposes of initial handshaking.
To see this, get the "netcat" program (available as debian package of the same name). In one terminal, run:
nc -l -p 9000
This starts a tcp listener on socket-port 9000, and prints out any data that arrives there. Then tell the name server to create an entry for this listener, and tag it as accepting text:
yarp name register /nc tcp ... 9000 yarp name set /nc accepts text
Now lets write some data to that port.
yarp write /write text://nc
Type something in, such as "hello world", and hit return. On the terminal running netcat you should see:
CONNECT /write d 0 "hello world"
This is what text mode looks like, for the particular data type used by yarp read and write ("bottles"). As we saw in an earlier section, we can also write to ports in text mode. And if we were to restart nc and then try the following:
yarp connect text://nc /foo
You should see:
CONNECT external /foo
This is what a command to connect looks like in YARP2. If we omit the text:/
then the tcp carrier may be used, which is compatible with YARP1 but is a bit less trivial to work with. Once our YARP implementations are up to date, the default command carrier will be switched to text.
Suppose we have created ports as follows by typing the following in different terminals:
yarp server yarp write /write yarp read /read yarp read /read2
We could connect and disconnect ports using the YARP companion utility, but here's how we could do the same thing "manually":
command: yarp where response: Name server is available at ip 192.168.0.3 port 10000 command: telnet 192.168.0.3 10000 type: NAME_SERVER query /write response: registration name /write ip 192.168.0.3 port 10001 type tcp *** end of message [connection closes] command: telnet 192.168.0.3 10001 type: CONNECT anonymous response: Welcome anonymous type: * response: This is /write There are no outgoing connections There is this connection from anonymous to /write using protocol tcp *** end of message type: /read response: Connected to /read type: * response: This is /write There is a connection from /write to /read using protocol tcp There is this connection from anonymous to /write using protocol tcp *** end of message type: !/read response: Removing connection from /write to /read type: /mcast://read response: Connected to /read type: /read2 response: Connected to /read2 type: * response: This is /write There is a connection from /write to /read using protocol mcast There is a connection from /write to /read2 using protocol tcp There is this connection from anonymous to /write using protocol tcp *** end of message type: q response: Bye bye [connection closes] command: telnet 192.168.0.3 10000 type: NAME_SERVER query /read response: registration name /write ip 192.168.0.3 port 10002 type tcp *** end of message [connection closes] command: telnet 192.168.0.3 10002 type: CONNECT anonymous response: Welcome anonymous type: * response: This is /read There are no outgoing connections There is a connection from /write to /read using protocol mcast There is this connection from anonymous to /read using protocol tcp *** end of message type: q response: Bye bye [connection closes]