VRPN 06.04

VRPN main page

Obtaining VRPN

VRPN Support

Installing and Testing

Compiling and Modifying

Client code

Server code

Troubleshooting

Connections

Logging and Playback

Shared Objects

Sound

Clock Synchronization

Text Messages

Doxygen documentation

VRPN on PDAs

Coming attractions & suggestions

UNC-specific information

Establishing a connection

For the case of a network VRPN connection (currently the only case), there are two actions that need to occur for the connection to be initiated: creating a listening connection and creating a remote connection. Once these are both started, the connection is initialized and remains until one or the other sides exit, thus dropping the connection.

Creating a listening connection

First, a listening endpoint for the connection needs to be created (usually by a server) using either the default constructor for the vrpn_Connection class or else the constructor that takes one integer:

vrpn_Connection(unsigned short listen_port_no = vrpn_DEFAULT_LISTEN_PORT_NO);

This call creates a connection that will listen for requests on the UDP port that is specified as a parameter, or will use the default port if none is specified. This connection will check for incoming packets on this port whenever its mainloop() member function is called.

The current implementation of the listening connection will allow multiple simultaneous remote connections to one server, with all messages from the server duplicated to each endpoint. Messages coming in from one endpoint are not re-sent to the other endpoints.

Creating a remote connection

The application does not normally directly ask for a connection, but rather creates a device that handles getting its own connection. These remote devices get connections using the function (defined in vrpn_Connection.h):

vrpn_Connection * vrpn_get_connection_by_name (const char * cname, const char * local_logfile_name = NULL, long local_log_mode = vrpn_LOG_NONE, const char * remote_logfile_name = NULL, long remote_log_mode = vrpn_LOG_NONE, double dFreq = 4.0, int cOffsetWindow = 2);

This function is passed the complete name of the device that is to be opened (for example, Tracker0@ioglab.cs.unc.edu). The function will strip off the device name and @ character and then open the port. If the same program opens more than one device with the same connection, a pointer to the existing connection is returned. This is useful when the application opens more than one device connected to the same server.

vrpn_get_connection_by_name() works by passing as the second part of the device name (after the @) as a parameter to the constructor for the connection.

vrpn_get_connection_by_name() takes many optional parameters. The first four control logging; the last two control synchronization. A local logfile can have an arbitrary pathname and can log incoming messages, outgoing messages, or both. The same properties can be specified for a remote logfile. The difference between local and remote logging is especially significant when some messages are being sent unreliably, since what is sent by one end of the vrpn_Connection may not match what is received at the other.

Connection initialization

The connection negotiation is initiated by the remote connection, which opens a TCP socket for listening and then sends a UDP datagram to the well-known port on the listening connection that tells it the machine name and port number of the TCP socket. If there is no connection attempt within a small timeout period, another request is made. If several requests fail, the server is assumed to be down or already connected and the connection fails. This mechanism allows both fast connection and fast detection of failure to connect. Once the listening connection receives a UDP request for a connection, it establishes a TCP link to the remote connection.

Now that there exists a TCP link between the connections, each sends a "hello" message to the other, which tells what version of the VRPN protocol each is running. If the versions do not match, the connection fails and the TCP link is dropped. From this point, the behavior of the connections is symmetric; as if they were peers, until the link is shut down.

If the versions match, each side of the connection opens a new UDP port and sends a description of the port to the other across the TCP channel. Each then establishes a bound UDP port that connects to the other's (the original, well-known UDP port is not used for this). This allows a path for unreliable (and presumably lower-latency) traffic to flow between the connections. In the future, other protocols may be supported, with their descriptions sent over the TCP channel.

At this point, the connections describe to each other their local sender and message type information, as further described under registering a sender and registering a type.

Local devices can register a handler for the messages named by vrpn_got_connection or vrpn_got_first_connection. The vrpn_Connection will send a message whenever remote devices connect so that the local devices can react appropriately.

Connection shutdown

A vrpn_Connection detects that its peer has closed the connection when it receives an exception on one of its reads, writes, or selects. A select is performed on the TCP connection each time the mainloop() member function is called, so the determination will be fairly rapid unless the drop is caused by a network timeout. Once the connection has been dropped, a listening connection will begin accepting new requests on its well-known UDP socket while a remote connection simply stops sending messages.

Local devices can register a handler for the messages named by vrpn_dropped_connection or vrpn_dropped_last_connection. The vrpn_Connection will send a message whenever the remote device disconnects so that the local devices can react appropriately.