VRPN main page

Obtaining VRPN

VRPN Support

Installing and Testing

Compiling and Modifying

Client code

Server code

Troubleshooting

Connections

Logging and Playback

Shared Objects

Clock Synchronization

Coming attractions & suggestions

UNC-specific information

Table of Contents


#ifndef	VRPN_CONNECTION_H
#define VRPN_CONNECTION_H

#include <stdio.h>  // for FILE

#ifndef VRPN_SHARED_H
#include "vrpn_Shared.h"
#endif

// NOTE: most users will want to use the vrpn_Synchronized_Connection
// class rather than the default connection class (either will work,
// a regular connection just has 0 as the client-server time offset)

typedef	struct {
	long		type;
	long		sender;
	struct timeval	msg_time;
	int		payload_len;
	const char	*buffer;
} vrpn_HANDLERPARAM;
typedef	int  (*vrpn_MESSAGEHANDLER)(void *userdata, vrpn_HANDLERPARAM p);


// bufs are aligned on 8 byte boundaries
#define vrpn_ALIGN                       (8)

// Types now have their storage dynamically allocated, so we can afford
// to have large tables.  We need at least 150-200 for the microscope
// project as of Jan 98, and will eventually need two to three times that
// number.
#define	vrpn_CONNECTION_MAX_SENDERS	(10)
#define	vrpn_CONNECTION_MAX_TYPES	(2000)

// vrpn_ANY_SENDER can be used to register callbacks on a given message
// type from any sender.

#define	vrpn_ANY_SENDER	(-1)

// vrpn_ANY_TYPE can be used to register callbacks for any USER type of
// message from a given sender.
#define vrpn_ANY_TYPE (-1)

// Buffer lengths for TCP and UDP.  UDP is set based on ethernet payload length
#define	vrpn_CONNECTION_TCP_BUFLEN	(64000)
#define	vrpn_CONNECTION_UDP_BUFLEN	(1500)

// System message types
#define	vrpn_CONNECTION_SENDER_DESCRIPTION	(-1)
#define	vrpn_CONNECTION_TYPE_DESCRIPTION	(-2)
#define	vrpn_CONNECTION_UDP_DESCRIPTION		(-3)
#define	vrpn_CONNECTION_LOG_DESCRIPTION		(-4)

// Classes of service for messages, specify multiple by ORing them together
// Priority of satisfying these should go from the top down (RELIABLE will
// override all others).
// These flags may be ignored, but RELIABLE is guaranteed to be available.
#define	vrpn_CONNECTION_RELIABLE		(1<<0)
#define	vrpn_CONNECTION_FIXED_LATENCY		(1<<1)
#define	vrpn_CONNECTION_LOW_LATENCY		(1<<2)
#define	vrpn_CONNECTION_FIXED_THROUGHPUT	(1<<3)
#define	vrpn_CONNECTION_HIGH_THROUGHPUT		(1<<4)

// What to log
#define vrpn_LOG_NONE				(0)
#define vrpn_LOG_INCOMING			(1<<0)
#define vrpn_LOG_OUTGOING			(1<<1)


#ifndef _WIN32
#define SOCKET int
#endif


// Default port to listen on for a server
#define vrpn_DEFAULT_LISTEN_PORT_NO             (4500)

// If defined, will filter out messages:  if the remote side hasn't
// registered a type, messages of that type won't be sent over the
// link.
//#define vrpn_FILTER_MESSAGES

#define vrpn_got_first_connection "VRPN Connection Got First Connection"
#define vrpn_got_connection "VRPN Connection Got Connection"
#define vrpn_dropped_connection "VRPN Connection Dropped Last Connection"
#define vrpn_dropped_last_connection "VRPN Connection Dropped Connection"

// vrpn_CONTROL is used for notification messages sent to the user
// from the local VRPN implementation (got_first_connection, etc.)
// and for control messages sent by auxiliary services.  (Such as
// class vrpn_Controller, which will be introduced in a future revision.)

#define vrpn_CONTROL "VRPN Control"

typedef char cName [100];


// Description of a callback entry for a user type.
struct vrpnMsgCallbackEntry {
  vrpn_MESSAGEHANDLER	handler;	// Routine to call
  void			* userdata;	// Passed along
  long			sender;		// Only if from sender
  vrpnMsgCallbackEntry	* next;		// Next handler
};

class vrpn_Connection
{
  public:
  // No public constructors because ...
  // Users should not create vrpn_Connection directly -- use 
  // vrpn_Synchronized_Connection (for servers) or 
  // vrpn_get_connection_by_name (for clients)

	//XXX Destructor should delete all entries from callback lists
	virtual ~vrpn_Connection (void);

	// Returns 1 if the connection is okay, 0 if not
	inline int doing_okay (void) { return (status >= 0); }
	virtual	int	connected (void) const;

	// Returns the name of the service that the connection was first
	// constructed to talk to, or NULL if it was built as a server.
	//inline const char * name (void) const { return my_name; }

	// Call each time through program main loop to handle receiving any
	// incoming messages and sending any packed messages.
	// Returns -1 when connection dropped due to error, 0 otherwise.
	// (only returns -1 once per connection drop).
	virtual int mainloop(void);

	// Get a token to use for the string name of the sender or type.
	// Remember to check for -1 meaning failure.
	virtual long register_sender (const char * name);
	virtual long register_message_type (const char * name);

	// Set up (or remove) a handler for a message of a given type.
	// Optionally, specify which sender to handle messages from.
	// Handlers will be called during mainloop().
	// Your handler should return 0 or a communication error is assumed
	// and the connection will be shut down.
	virtual int register_handler(long type, vrpn_MESSAGEHANDLER handler,
			void *userdata, long sender = vrpn_ANY_SENDER);
	virtual	int unregister_handler(long type, vrpn_MESSAGEHANDLER handler,
			void *userdata, long sender = vrpn_ANY_SENDER);

	// Pack a message that will be sent the next time mainloop() is called.
	// Turn off the RELIABLE flag if you want low-latency (UDP) send.
	virtual int pack_message(int len, struct timeval time,
				 long type, long sender, const char * buffer,
				 unsigned long class_of_service);

	// Returns the time since the connection opened.
	// Some subclasses may redefine time.
	virtual int time_since_connection_open
	                        (struct timeval * elapsed_time);

	// Returns the name of the specified sender/type, or NULL
	// if the parameter is invalid.  Only works for user
	// messages (type >= 0).
	virtual const char * sender_name (long sender);
	virtual const char * message_type_name (long type);

  protected:
  // Users should not create vrpn_Connection directly -- use 
  // vrpn_Synchronized_Connection (for servers) or 
  // vrpn_get_connection_by_name (for clients)

	// Create a connection to listen for incoming connections on a port
	vrpn_Connection (unsigned short listen_port_no =
		         vrpn_DEFAULT_LISTEN_PORT_NO);

	//   Create a connection -  if server_name is not a file: name,
	// makes an SDI-like connection to the named remote server
	// (otherwise functions as a non-networked messaging hub).
	// Port less than zero forces default.
	vrpn_Connection (const char * server_name,
                         int port = vrpn_DEFAULT_LISTEN_PORT_NO,
                         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);

	//char *	my_name;
	int	status;			// Status of the connection

        // Encapsulation of the data for a single connection
        // since we're thinking about having many clients talking to
        // a single server.
        struct vrpn_OneConnection {

          vrpn_OneConnection (void);
          vrpn_OneConnection (const SOCKET, const SOCKET);

          SOCKET tcp_sock;
          SOCKET udp_sock;
          char rhostname [150];
        };

	// Sockets used to talk to remote Connection(s)
	vrpn_OneConnection	endpoint;
	SOCKET		udp_inbound;
	unsigned short	udp_portnum;  // need to keep this around now!
		// design expects to only have one udp_inbound
		// for receipt from all remote hosts

	int	num_live_connections;

	// Only used for a vrpn_Connection that awaits incoming connections
	int	listen_udp_sock;	// Connect requests come here

	// The senders we know about and the message types we know about
	// that have been declared by the local version.

	struct vrpnLocalMapping {
		cName			* name;		// Name of type
		vrpnMsgCallbackEntry	* who_cares;	// Callbacks
		int			cCares;		// TCH 28 Oct 97
	};
	cName			* my_senders [vrpn_CONNECTION_MAX_SENDERS];
	int			num_my_senders;
	vrpnLocalMapping	my_types [vrpn_CONNECTION_MAX_TYPES];
	int			num_my_types;

	// Callbacks on vrpn_ANY_TYPE
	vrpnMsgCallbackEntry	* generic_callbacks;	

	// The senders and types we know about that have been described by
	// the other side.  Also, record the local mapping for ones that have
	// been described with the same name locally.
	struct cRemoteMapping {
		cName	* name;
		int	local_id;
	};
	cRemoteMapping	other_senders [vrpn_CONNECTION_MAX_SENDERS];
	int		num_other_senders;
	cRemoteMapping	other_types [vrpn_CONNECTION_MAX_TYPES];
	int		num_other_types;

	// Output buffers storing messages to be sent
	char	tcp_outbuf [vrpn_CONNECTION_TCP_BUFLEN];
	char	udp_outbuf [vrpn_CONNECTION_UDP_BUFLEN];
	int	tcp_num_out;
	int	udp_num_out;

	// Routines to handle incoming messages on file descriptors
	int	handle_udp_messages (int fd);
	int	handle_tcp_messages (int fd);

	// Routines that handle system messages
	static int handle_sender_message (void * userdata, vrpn_HANDLERPARAM p);
	static int handle_type_message (void * userdata, vrpn_HANDLERPARAM p);
	static int handle_UDP_message (void * userdata, vrpn_HANDLERPARAM p);
	static int handle_log_message (void * userdata, vrpn_HANDLERPARAM p);

	// Pointers to the handlers for system messages
	vrpn_MESSAGEHANDLER	system_messages [vrpn_CONNECTION_MAX_TYPES];

	virtual	void	init (void);	// Called by all constructors

	virtual	int	send_pending_reports (void);
	virtual	void	check_connection (void);
	virtual	int	setup_for_new_connection (void);
		// set up data
	virtual	int	setup_new_connection (long logmode = 0L,
	                                      const char * logfile = NULL);
		// set up network
	virtual	void	drop_connection (void);
	virtual	int	pack_sender_description (int which);
	virtual	int	pack_type_description (int which);
	virtual	int	pack_udp_description (int portno);
	virtual int	pack_log_description (long mode,
                                              const char * filename);
	inline	int	outbound_udp_open (void) const
				{ return endpoint.udp_sock != -1; }
	virtual	int	marshall_message (char * outbuf, int outbuf_size,
				int initial_out, int len, struct timeval time,
				long type, long sender, const char * buffer);

	virtual	int	connect_tcp_to (const char * msg);

	virtual	int	do_callbacks_for (long type, long sender,
				struct timeval time, int len,
	                        const char * buffer);

	// Returns message type ID, or -1 if unregistered
	int		message_type_is_registered (const char *) const;

	// offset of clocks on connected machines -- local - remote
	// (this should really not be here, it should be in adjusted time
	// connection, but this makes it a lot easier
        struct timeval tvClockOffset;

	// Thread safety modifications - TCH 19 May 98

	// Input buffers
	int d_TCPbuflen;
	char * d_TCPbuf;
	double d_UDPinbufToAlignRight
			[vrpn_CONNECTION_UDP_BUFLEN/sizeof(double)+1];
	char *d_UDPinbuf;

	// Logging - TCH 11 June 98

	struct vrpn_LOGLIST {
	  vrpn_HANDLERPARAM data;
	  vrpn_LOGLIST * next;
	  vrpn_LOGLIST * prev;
	};

	vrpn_LOGLIST * d_logbuffer;  // last entry in log
	vrpn_LOGLIST * d_first_log_entry;  // first entry in log
	char * d_logname;            // name of file to write log to
	long d_logmode;              // logging incoming, outgoing, or both
	int d_logfile_handle;
	FILE * d_logfile;

	virtual int log_message (int payload_len, struct timeval time,
	                         long type, long sender, const char * buffer);
	virtual int close_log (void);
	virtual int open_log (void);

	// Timekeeping - TCH 30 June 98
	struct timeval start_time;

};

// forward decls
class vrpn_Clock_Server;
class vrpn_Clock_Remote;

// NOTE: the clock offset is calculated only if the freq is >= 0
// if it is -1, then the offset is only calced and used if the
// client specifically calls fullSync on the vrpn_Clock_Remote.
// if the freq is -2, then the offset is calced immediately using
// full sync.
// Time stamp for messages on the connection server are never
// adjusted (only the clients get adjusted time stamps).

// NOTE: eventually this should just be another system message type
//       rather than a separate class, but right now i don't have time
//       for that.

class vrpn_Synchronized_Connection : public vrpn_Connection
{
  public:
    // Create a connection to listen for incoming connections on a port
    // server call
    vrpn_Synchronized_Connection (unsigned short listen_port_no =
		  vrpn_DEFAULT_LISTEN_PORT_NO);
    vrpn_Clock_Server * pClockServer;

    // Create a connection makes an SDI connection to a remote server
    // client call
    // freq is the frequency of clock syncs (<0 means only on user request)
    // cOffsetWindow is how many syncs to include in search window for min
    // roundtrip.  Higher values are more accurate but result in a sync
    // which accumulates drift error more quickly.
    vrpn_Synchronized_Connection
	 (const char * server_name,
          int port = vrpn_DEFAULT_LISTEN_PORT_NO,
          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);
    // fullSync will perform an accurate sync on the connection for the
    // user and return the current offset
    struct timeval fullSync();
    vrpn_Clock_Remote * pClockRemote;
    virtual int mainloop (void);
};

// 1hz sync connection by default, windowed over last three bounces 
// WARNING:  vrpn_get_connection_by_name() may not be thread safe.
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 = 1.0, int cSyncWindow = 3);


// Utility routines to parse names (<service>@<location specifier>)
// Both return new char [], and it is the caller's responsibility
// to delete this memory!
char * vrpn_copy_service_name (const char * fullname);
char * vrpn_copy_service_location (const char * fullname);

// Utility routines to parse file specifiers
//   file:<filename>
//   file://<hostname>/<filename>
//   file:///<filename>
char * vrpn_copy_file_name (const char * filespecifier);

// Utility routines to parse host specifiers
//   <hostname>
//   <hostname>:<port number>
//   x-vrpn://<hostname>
//   x-vrpn://<hostname>:<port number>
char * vrpn_copy_machine_name (const char * hostspecifier);
int vrpn_get_port_number (const char * hostspecifier);

#endif // VRPN_CONNECTION_H