ARGONNE NATIONAL LABORATORY
9700 South Cass Avenue
Argonne, IL 60439
-----------------
ANL/MCS-TM-218
-----------------

CAVEcomm Users Manual


by
Terrence L. Disz, Michael E. Papka, Michael Pellegrino
Mathematics and Computer Science Division, ANL
and
Matthew Szymanski
The Electronic Visualization Laboratory, University of Illinois at Chicago

Mathematics and Computer Science Division, ANL
Technical Memorandum No. 218


September 1996

This work was supported by the Mathematical, Information, and Computational Sciences Division subprogram of the Office of Computational and Technology Research, U.S. Department of Energy, under Contract W-31-109-Eng-38.


Abstract

The CAVEcomm library is a set of routines designed to generalize the communications between virtual environments and supercomputers.

Library Model

The model for the library is that of a client/server. Somewhere at a known URL is a broker whose purpose is to mediate the communications between various client applications (CAVE, simulations, etc.).

The Broker

The broker maintains tables of all clients and of all sessions (applications) that are registered with it.

The table of clients includes such elementary information as the client's capabilities (machine type, model, etc.) as well as basic application information (CAVE application, IBM simulation, etc.). Clients can query the broker for this information.

The table of sessions includes information on all sessions (applications) that any registered client can run. The table maintains such information as executable names, data files, command line arguments, etc. Of course, clients cannot attach to sessions outside of the realm of their physical machine. For example, clients cannot run a CAVE application unless CAVE functiexists onality on their machine. Clients can query the broker for this session information.

The broker executable is in the bin subdirectory within the CAVEcomm distribution.

To run the broker, type ./c2cbroker - commandline arguments

Commandline arguments include the following:

  • -c2cdbg { 100-140 }
    Specifies the level of debuging messages output by the broker, 100 being the lowest level of c2c internal messages and 140 being the greatest.

  • -c2curl_filename { my_url_file }
    Contains the URL for the broker, the idea being that this file lives in some common shared file space that all users of a given instance can access.

  • -c2c_port { port number }
    Specifies the particular port that the broker will be listening on, thereby allowing users to pick an arbitrary port number and use that port over and over, thus eliminating the need to change the config files.

  • Example: ./c2cbroker -c2c_port 10001 -c2cdbg 140

    This command will start a broker process on the machine from which it is run, listening on port 10001, and printing out all the internal c2c debug messages available.

    The Client

    Each CAVEcomm client is an application (CAVE, simulation, etc.) that has the power to attach to any other application on the broker. A simulation that is registered with the broker can be accessed by any other application on the broker such as visualization applications or virtual environments.

    Communications Transport

    The CAVEcomm library uses the Nexus communications library developed at the Mathematics and Computer Science Division at Argonne National Laboratory.

    While Nexus is the communications transport, the user does not need any prerequisite knowledge in using it. All Nexus communications calls are encapsulated in the library; thus, the user is unaware of the Nexus presence.

    By using Nexus, the CAVEcomm library is able to support various communications protocols such as TCP/IP sockets and shared memory, as well as various message-passing libraries.


    CAVEcomm Library

    All functions in the CAVEcomm library start with the prefix c2c. The CAVEcomm library contains functions that are broken down into various sections.

    General Routines

    int c2cGetDebugLevel(void);
    Get the current maximum debugging level in an application.

    void c2cInit(int *argc, char *argv[],CaveEnv *env);
    Start all communications functionality. Its arguments are the argument count, argument vector, and a structure describing the application's operating environment. It must be the first CAVEcomm library call made (except for c2cReadConfigFile or if the world routines are used). If the CAVEcomm library is used with the CAVE library, the call to c2cInit must occur after the call to CAVEInit is made.

    void c2cPrintf(int level, char *format, ...);
    Print the text. The text consists of a chracter string describing how to format the text and any applicable variables contained in the format. This function is similar to the printf function found in the standard I/O C library. The level parameter tells the library at what level to print the text.

    int c2cReadConfigFile(char *filename,c2cConfig *config);
    Read filename for application definitions. The definitions are placed into config, which contains all known application definitions. If filename is null, the default file .c2cConfig is attempted to be opened. If filename or .c2cConfig cannot be opened; E_OPEN_CONFIG_FILE is returned, otherwise, E_SUCCESS is returned.

    void c2cSetDebugLevel(int level);
    Set the current maximum debugging level in an application.

    void c2cTerminate(void);
    End all communications functionality. It is the last CAVEcomm library call made (unless the world routines are used).

    Broker Routines

    HostId c2cBrokerAttach(URL url);
    Attach to the broker listed by url. The URL must be of the format c2cBroker://{ip hostname}:{ip port}/. Supplying a URL of a different format will give unpredictable results. A HostId is returned uniquely describing that broker.

    int c2cBrokerDetach(HostId host);
    Detach from the broker specified by host. No further references can be made to host after it is detached. E_INVALID_HOST is returned if HostId does not match a host that was previously attatched with c2cBrokerAttach; otherwise, E_SUCCESS is returned.

    int c2cBrokerKill(HostId host);
    Terminate the broker specified by host. All database information on the broker is disposed of, and all programs connected are terminated. Most programs will never issue this call. E_INVALID_HOST is returned if HostId does not match a host that was previously attached with c2cBrokerAttach; otherwise, E_SUCCESS is returned.

    CAVEId c2cGetClientId(HostId host,char *name);
    Query the broker host, and return the assigned CAVEId of the client name. The CAVEId is returned if the client name is found; otherwise, E_INVALID_CLIENT is returned. If the host is invalid, E_INVALID_HOST is returned.

    int c2cGetClients(HostId host,int *num_clients,CaveEnv **client_list);
    Retrieve a list of all clients currently registered on broker host. The number of clients registered is returned is in num_clients along with an array of all the registered CaveEnv structures. E_INVALID_HOST is returned if HostId does not match a host that was previously attatched to with c2cBrokerAttach; otherwise, E_SUCCESS is returned.

    SessionId c2cGetSessionId(HostId host,char *name);
    Query the broker host, and return the assigned SessionId of the session name. The SessionId is returned if the session name is found; otherwise, E_INVALID_SESSION is returned. If the host is invalid, E_INVALID_HOST is returned.

    int c2cGetSessions(HostId host,int *num_sessions,CaveSession **session_list);
    Retrieve a list of all sessions currently registered on broker host. The number of sessions registered is returned is in num_sessions along with an array of all the registered CaveSession structures. E_INVALID_HOST is returned if HostId does not match a host that was previously attatched to with c2cBrokerAttach; otherwise, E_SUCCESS is returned.

    int c2cKillSession(HostId host,SessionId session,CAVEId cave);
    Not yet implemented.

    CAVEId c2cRegister(HostId host,CaveEnv *env);
    Register the application on broker host with the environment env. All subsequent queries to the broker with respect to clients will reflect that application's presence. E_INVALID_HOST is returned if HostId does not match a host that was previously attatched with c2cBrokerAttach; E_CLIENT_EXISTS is returned if the client name is already used on the broker. If there are no errors, a CAVEId (0 or higher) is returned.

    int c2cSessionAttach(HostId host,SessionId session, CAVEId cave);
    Not yet implemented.

    SessionId c2cSessionCreate(HostId host,CaveSession *ses);
    Create a session on broker host with session ses. All subsequent queries to the broker with respect to sessions will reflect that application session's presence. E_INVALID_HOST is returned if HostId does not match a host that was previously attached with c2cBrokerAttach. E_SESSION_EXISTS is returned if the session name is already used on the broker. If all goes well, E_SUCCESS is returned.

    int c2cSessionDetach(HostId host,CAVEId cave);
    Not yet implemented.

    int c2cSubscribe(HostId host,CAVEId datasource,StreamType stream,void *callback);
    Inform the broker host that your application would like receive stream data of type stream from datasource, and call callback when any incoming data is to be processed. The remote application will then start streaming the requested data to the application. E_INVALID_HOST is returned if HostId does not match a host that was previously attatched with c2cBrokerAttach. E_INVALID_CAVE_ID is returned if datasource is invalid on host. E_INVALID_STREAM is returned if datasource does not have stream available. E_SUCCESS is returned upon successful subscription to stream.

    int c2cUnregister(HostId host,CAVEId cave);
    Tell the broker host to remove an application from the client list. All subsequent queries to the broker with respect to clients will not reflect that application's presence. E_INVALID_HOST is returned if HostId does not match a host that was previously attatched with c2cBrokerAttach. E_INVALID_CAVE_ID is returned if cave is invalid on host. E_SUCCESS is returned upon successful subscription to stream.

    int c2cUnsubscribe(HostId host,CAVEId datasource,StreamType stream,void *callback);
    Inform broker host that an application would like cancel the streaming of data of type stream from datasource with the matching callback callback. The remote application no longer streams data to that application. E_INVALID_HOST is returned if HostId does not match a host that was previously attatched with c2cBrokerAttach. E_INVALID_CAVE_ID is returned if datasource is invalid on host. E_INVALID_STREAM is returned if datasource does not have stream available. E_INVALID_CALLBACK is returned if a callback is given that was not used for a subscription to stream. E_SUCCESS is returned upon successful unsubscription to stream.

    Data Routines

    void c2cFreeDataBuffer(void *buffer);
    Free the data buffer bufffer (accessed with c2cGetn calls) from memory.

    void c2cFreePackBuffer(c2cBuffer **buffer);
    Free the data buffer buffer (accessed with c2cPackn calls) from memory.

    void c2cGetChar(void *buffer,char *data,int size);
    Get size characters from buffer, and put them into data.

    void c2cGetDouble(void *buffer,double *data,int size);
    Get size doubles from buffer, and put them into data.

    void c2cGetFloat(void *buffer,float *data,int size);
    Get size floats from buffer, and put them into data.

    void c2cGetInt(void *buffer,int *data,int size);
    Get size integers from buffer, and put them into data.

    void c2cGetLong(void *buffer,long *data,int size);
    Get size long integers from buffer, and put them into data.

    void c2cInitPackBuffer(c2cBuffer **buffer);
    Initialize data buffer buffer for future packing.

    void c2cPackChar(c2cBuffer **buffer,char *data,int size);
    Add size blocks of character data to buffer for broadcast later.

    void c2cPackDouble(c2cBuffer **buffer,double *data,int size);
    Add size blocks of double data to buffer for broadcast later.

    void c2cPackFloat(c2cBuffer **buffer,float *data,int size);
    Add size blocks of float data to buffer for broadcast later.

    void c2cPackInt(c2cBuffer **buffer,int *data,int size);
    Add size blocks of integer data to buffer for broadcast later.

    void c2cPackLong(c2cBuffer **buffer,long *data,int size);
    Add size blocks of long data to buffer for broadcast later.

    int c2cRegisterStream(StreamType stream,void *subscribecallback,void *unsubscribecallback);
    Register a stream in an application. No streams can be subscribed to until they are registered. If subscribecallback is supplied (it is not null), that callback will be executed every time the stream is subscribed to. If unsubscribecallback is supplied (it is not null), that callback will be executed every time the stream is unsubscribed to. E_STREAM_REGISTERED is returned if the stream is already registered. E_SUCCESS is returned otherwise.

    int c2cSendStream(CAVEId sourceid, c2cBuffer **buffer,StreamType stream);
    Cast a buffer of data buffer (previously packed with c2cPackn routines) of stream type stream to all applications subscribed to that stream with a source identifier of sourceid. The source identifier tells the remote processes who sent them the stream. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    int c2cSendHeadTracker(float x,float y,float z,float a,float e,float r);
    Cast local CAVE head tracker information (passed via parameters) to all applications subscribed to the stream S_HEAD_TRACKER. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    int c2cSendUser(CAVEId sourceId, CAVEUser *user);
    Cast local CAVE user (all trackers, buttons, joystick and world info) to all applications subscribed to the stream S_CAVE_USER. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    int c2cSendWandButtons(CAVEId sourceId, int b1,int b2,int b3,int b4);
    Cast local CAVE wand button information (passed via parameters) to all applications subscribed to the stream S_WAND_BUTTON. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    int c2cSendWandJoystick(CAVEId sourceId, float joyx,float joyy);
    Cast local CAVE wand joystick information (passed via parameters) to all applications subscribed to the stream S_WAND_JOYSTICK. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    int c2cSendWandTracker(float x,float y,float z,float a,float e,float r);
    Cast local CAVE wand tracker information (passed via parameters) to all applications subscribed to the stream S_WAND_TRACKER. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    int c2cSendWorldPosition(float x,float y,float z,float a,float e,float r);
    Cast local CAVE world position (passed via parameters) to all applications subscribed to the stream S_WORLD_POSITION. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    int c2cUnregisterStream(StreamType stream)
    Unregister a stream with an application. No remote applications can subscribe to a stream once it is unregistered. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    World Routines

    void c2cDrawAllUsers(void);
    Draw all users that are tracked via c2cTrackUserInit.

    void c2cDrawSomeUsers(int count,char *users[]);
    Draw a list of users that are tracked via c2cTrackUserInit. The number of users in the list as well as the application names of the users to draw are passed as parameters.

    int c2cDrawUser(char *user);
    Draw a user that is tracked via c2cTrackUserInit. The user to draw is specified by giving his applicaion name for user. E_INVALID_CLIENT is returned if an invalid client name is given. E_SUCCESS is returned otherwise.

    void c2cTrackUserInit(char *user,void *callback);
    Start tracking user (specified by application name). The rendering of the user can be user defined by supplying a callback. Whenever a draw command is issued, this callback will be executed. If null is given as the callback, a default stick-man representation of the user will be rendered. E_INVALID_CLIENT is returned if user is invalid. E_INVALID_STREAM is returned if user does not have tracking available. E_SUCCESS is returned upon successful tracking initializaion.

    int c2cTrackUserExit(char *user,void *callback);
    Cancel the tracking of user (specified by application name). The callback of the tracked user must match that given when initiated. E_INVALID_CLIENT is returned if user is invalid. E_INVALID_STREAM is returned if user does not have tracking available. E_SUCCESS is returned upon successful tracking exiting.

    void c2cWorldDataInit(void);
    Initialize necessary data structures needed for world communications. This must be the first CAVEcomm library call issued in an application (except for c2cReadConfigFile). If the application running is a CAVE application, it must occur before the call to CAVEInit is made. In addition, if any CAVEcomm application wishes to use the user-tracking facilities, it must make a call to c2cWorldDataInit (whether the application is CAVE based or not).

    void c2cWorldDataSubscribe(char *user,StreamType stream,void *callback);
    Subscribe to user (specified by application name) for data stream stream and to call callback when the data is received. E_INVALID_CLIENT is returned if user is invalid. E_INVALID_STREAM is returned if user does not have stream available. E_SUCCESS is returned upon successful data subscription.

    void c2cWorldDataUnsubscribe(char *user,StreamType stream,void *callback);
    Unsubscribe to the data stream stream that was previously subscribed to from user (specified by his application name) with callback. E_INVALID_CLIENT is returned if user is invalid. E_INVALID_STREAM is returned if user does not have stream available. E_INVALID_CALLBACK is returned if a callback is given that was not used for a subscription to stream. E_SUCCESS is returned upon successful data unsubscription.

    void c2cWorldExit(void);
    Terminate all World functionality. This must be the last CAVEcomm library call issued in an application.

    CAVEId c2cWorldGetClientId(char *name);
    Query the broker, and return the assigned CAVEId of the client name. The CAVEId is returned if the client name is found; otherwise, E_INVALID_CLIENT is returned.

    SessionId c2cWorldGetSessionId(char *name);
    Query the broker, and return the assigned SessionId of the session name. The SessionId is returned if the session name is found; otherwise, E_INVALID_SESSION is returned.

    void c2cWorldInit(int *argc,char *argv[]);
    Initiate all World functionality. If the CAVEcomm library is used with the CAVE library, it must occur after the call to CAVEInit is made.

    int c2cWorldSendStream(c2cBuffer **buffer,StreamType stream);
    Cast a buffer of data buffer (previously packed with c2cPackn routines) of stream type stream to all applications subscribed to that stream. E_INVALID_STREAM is returned if the stream was not registered; otherwise, E_SUCCESS is returned.

    Global Variables

    The CAVEcomm library maintains the following global variable that the user can access:
    CaveEnv c2cEnv
    This variable maintains all local environment information that was registered with c2cInit.

    Data Structures

    The CAVEcomm library has data structures that are accessible by the user.

    CaveEnv

    /* Structure defining CAVE environment */
    typedef struct caveenv
    {
      char name[C2C_NAME_SIZE];	/* Unique name for this CAVE */
      int type;			/* Type of session this is (CAVE, I-Desk, etc...) */
      int id;			/* Id of the client */
    }CaveEnv;
    

    CaveSession

    /* Structure describing a CAVE session */
    typedef struct cavesession
    {
      CAVEId owner;		        /* Who owns the session on the broker */
      char name[C2C_NAME_SIZE];	/* Unique name describing the session */
      char pathname[C2C_PATH_SIZE];	/* Where to find the application */
      char execname[C2C_EXE_SIZE];	/* Executable name */
      char args[C2C_ARGS_SIZE];	/* Command line arguments */
      int id;                       /* Id of the session */
    }CaveSession;
    

    CAVEUser

    /* Structure defining CAVE user */
    typedef struct caveuser
    {
      float headx,heady,headz,	/* Head tracker location */
            heada,heade,headr,	/* Head tracker orientation */
    	wandx,wandy,wandz,	/* Wand tracker location */
    	wanda,wande,wandr,	/* Wand tracker orientation */
    	worldx,worldy,worldz,	/* World location */
    	worlda,worlde,worldr;	/* World orientation */
      int   but1,but2,		/* Button information */
            but3,but4;
      float joyx,joyy;		/* joystick information */
    }CAVEUser;
    

    c2cConfig

    /* Structure defining a CAVEcomm session */
    typedef struct c2cconfig
    {
      URL broker;			/* URL to connect to broker with */
      CaveEnv env;			/* Local environment parameters */
      CaveSession session;		/* Session info for this CAVE app */
    }c2cConfig;
    


    CAVEcomm Configuration File

    The CAVEcomm library looks for a configuration file (.c2cConfig by default) that defines certain aspects of the application. The format for the configuration file is keyword [option]. Keywords are not case sensitive. Application definitions are as follows:
    Broker "Broker URL"
    A known URL of the broker that one is to register and attach to. The broker URL must be of the format c2cBroker://{ip hostname}:{ip port}/.

    DebugLevel level
    The level for debugging the application. Debugging will be set at level as soon as the parser finishes processing the DebugLevel keyword.

    ClientName "Client application name"
    The name of the application that is used when registering on the broker.

    ClientAppType type
    The application type describing what type of application it is (CAVE, ImmersaDesk, simulation).

    SessionName "Session name"
    Name of the session given to the broker upon session creation.

    SessionPath "Pathname to application"
    Pathname of the executable for the session. It is given to the broker upon session creation.

    SessionExe "Session executable name"
    Executable name of the application for the session. It is given to the broker upon session creation.

    SessionArgs "Command line arguments"
    Command line arguments needed to run the application. They are given to the broker upon session creation.


    CAVEcomm Constants

    Stream Types

    S_HEAD_TRACKER
    Head tracker information
    S_WAND_TRACKER
    Wand tracker information
    S_WAND_BUTTON
    Button information
    S_WAND_JOYSTICK
    Joystick information
    S_WORLD_POSITION
    CAVE location in the world
    S_CAVE_USER
    User information (trackers/buttons etc... all in one)

    Session Types

    ST_CAVE
    CAVE session
    ST_CAVE_SIMULATOR
    CAVE simulator session
    ST_IMMERSADESK
    ImmersaDesk session
    ST_SIMULATION
    Data simulation of some sort

    Data Types

    DT_CHAR
    Character data
    DT_INT
    Integer data
    DT_LONG
    Long integer data
    DT_FLOAT
    Float data
    DT_DOUBLE
    Double data

    Error Messages As Seen by User

    E_SUCCESS
    No error at all
    E_BROKER_ATTACH
    Attach to the broker failed
    E_SUBSCRIBE_NO_STREAM
    Subscribe to non-existant stream
    E_INVALID_HOSTID
    Bad host id given
    E_INVALID_CALLBACK
    Bad callback given
    E_INVALID_STREAM
    Stream never registeged
    E_STREAM_REGISTERED
    Stream already registered
    E_INVALID_HOST
    Invalid host id given
    E_INVALID_CAVEID
    Invalid CAVE id given
    E_INVALID_BROKER_URL
    Invalid broker URL given
    E_INVALID_CLIENT
    Invalid client name given
    E_INVALID_SESSION
    Invalid session name given
    E_CLIENT_EXISTS
    Client already registered on broker
    E_SESSION_EXISTS
    Session already created on broker
    E_OPEN_CONFIG_FILE
    Error opening configuration file

    Various Array Sizes

    C2C_NAME_SIZE
    Size of session string
    C2C_URL_SIZE
    Size of a URL string
    C2C_PATH_SIZE
    Size of path string
    C2C_EXE_SIZE
    Size of exe string
    C2C_ARGS_SIZE
    Size of argument string

    Miscellaneous Constant Definitions

    C2C_CONFIG_FILE
    Default config file to open if none is given
    C2C_BROKER_URL_FILE
    Default filename to house broker URL
    CONFIG_FILE_LINE_SIZE
    Max size of a file line in configuration file
    CONFIG_OPTION_SIZE
    Max size of an option in configuration file
    C2C_SUBSCRIBE
    Flag for World subscribe operation
    C2C_UNSUBSCRIBE
    Flag for World unsubscribe operation


    Sample Applications

    New Samples

    Multiple CAVE OpenGL Application
    Makefile
    CAVE One Code
    CAVE Two Code
    CAVE Three Code

    Inventor CAVE Application
    Client C++ Code
    Client Header Code
    Server C++ Code
    Server Header Code

    Supercomputer to CAVE Application
    CAVE Side C Code
    CAVE Side Header Code
    Supercomputer Side C Code
    Supercomputer Side Header Code

    Old Samples

    Multiple CAVE GL Application
    Makefile
    CAVE One Code
    CAVE Two Code

    Client Server Application
    Client C Code
    Server C Code

    Sample applications

    New Samples

    Multiple CAVE OpenGL Application
    Makefile
    CAVE One Code
    CAVE Two Code
    CAVE Three Code

    Inventor CAVE Application
    Client C++ Code
    Client Header Code
    Server C++ Code
    Server Header Code

    Supercomputer to CAVE Application
    CAVE Side C Code
    CAVE Side Header Code
    Supercomputer Side C Code
    Supercomputer Side Header Code

    Old Samples

    Multiple CAVE GL Application
    Makefile
    CAVE One Code
    CAVE Two Code

    Client Server Application
    Client C Code
    Server C Code


    Acknowledgments

    The following people have contributed to the development of the CAVEcomm library: Terry Disz, Ian Foster, Terry Franguiadakis, Jonathan Geisler, Dan Heath, Ivan Judson, Bob Olson, Mike Papka, Mike Pellegrino, Rick Stevens, Matthew Szymanski, and Steve Tuecke.