Using VAST


Using VAST is simple. For the C++ code, you just need to include "VASTVerse.h", the factory class for VAST, and optionally "VASTsim.h", if you also want to use some existing utility to read parameters.

VAST defines certain base data types and base classes (you can refer to "/common/VASTTypes.h for details). For example, the following are the most basic ones:

// hostID (globally unique) or nodeID (unique within each world)
typedef uint64_t  id_t;
 
// timestamp type, stores the timestamp obtained from system
typedef uint32_t  timestamp_t;
 
// the number of layers in the overlay (0 - 65535)
typedef uint16_t  layer_t;
 
// position inside the virtual world, consists of x, y, z coordinates
class Position
 
// an area, can be either a circle (center & radius), or a rectangle (center, width, and height)
class Area
 
// IP address, consisting of host and port
class IPaddr
 
// a VAST node's host address, consisting of hostID, and IP address
class Addr
 
// a VAST node, consisting of its hostID, last time of access, AOI, and host address
class Node
 
// a subscription, consisting of hostID, subscriptionID, layer, last time of use, AOI, and the relay
class Subscription
 
// a user message sent between nodes, consisting of a message type, priority number, data, and targets
class Message
 
 

The easiest way to create an instance of VAST, is to call the following function in the VASTVerse class (the factory class for VAST nodes):
bool createVASTNode (const IPaddr &gateway, Area &area, layer_t layer);

where gateway refers to the IP address of the Gateway node, area refers to the initial subscribed area, and layer refers to which layer to subscribe (VAST supports from 1 to 65,535 different user-defined layer numbers). A VAST node will only receive publications fall within its subscribed area, but also at the same layer. Once a subscription request is made, the application can just keep calling the following function to obtain a pointer to the created VAST node (NULL is returned before the VAST node has joined successfully).

VAST *getVASTNode ();

Once the VAST node is obtained, the application can called the following two simple functions to initialize:

bool join (const IPaddr &gateway);
 
bool subscribe (Area &area, layer_t layer);

join() adds the VAST node to an existing P2P network of nodes, whose first node (the gateway) is specified in the IP address parameter, so that subscriptions can be performed. This 'gateway' can be the same as the one used in createVASTNode (), or a different one. The reason is that a VAST node such that it can switch the 'gateway' while running, effectively joining into a different virtual space (and perform new subscriptions subsequently). Application can then subscribe () to an area at a specific layer. The application then needs to call the following to make sure a subscription ID is obtained, before moving on.
id_t getSubscriptionID ();

Finally, to interact within the P2P network, the application calls one of the following:
Area *move (id_t subID, Area &aoi);
 
bool publish (Area &area, layer_t layer, Message &message);
 
vector<Node *>& list ();
 
int send (Message &message);
move () basically changes the subscribed area for the given subscription ID. publish () sends a message to an area at a specific layer. and send () sends a custom message to one or more nodes stored within the Message's targets.


Socket Communications


Direct socket communications are also provided by VAST if the application needs to use them. You can pass an IP/port info to open a TCP connection to a remote server (with optional SSL encryption), and to send and receive any byte string once the connection is opened. The four main functions to use are:

// open a new socket specified given in the IPaddr, a socket id is returned
id_t openSocket (IPaddr &ip_port, bool is_secure = false);
 
// send a message of a given size to the socket (based on its id)
bool sendSocket (id_t socket, const char *msg, size_t size);
 
// receive messages, by passing in references to receive socket id and message size
// NULL is received is no more messages
char *receiveSocket (id_t &socket, size_t &size);
 
// close up an existing socket
bool closeSocket (id_t socket);
 
// check whether a given socket is still connected
bool isSocketConnected (id_t socket);
 

Sample Program


We use the sample code in "/Demo/demo_console/demo_console.cpp" as a skeleton to explain what a minimal VAST-based program might look like. Note that this is only a skeleton, you will want to fill in other parts to suit your particular needs. The sample serves to provide an idea of how to initialize a VAST node, and how the main loop should run VAST.

#include "VASTVerse.h"
#include "VASTsim.h"
 
#define VAST_EVENT_LAYER    1                   // layer ID for sending events
#define VAST_UPDATE_LAYER   2                   // layer ID for sending updates
 
using namespace Vast;
using namespace std;
 
int main (int argc, char *argv[])
{
    VASTPara_Net    netpara;              // network parameters
    NodeState       state     = ABSENT;   // the join state of this node
    Area            aoi;                  // my AOI (with center as current position)
    Addr            gateway;              // address for gateway
 
    VASTVerse *     world     = NULL;
    VAST *          self      = NULL;
    id_t            sub_no    = 0;        // subscription # for my client (peer)
 
    // store default gateway address
    string str ("127.0.0.1:1037");
    gateway = *VASTVerse::translateAddress (str);
 
    // list of entry points
    vector<IPaddr> entries;
 
    // initialize network parameters and entry points (stored in netpara)
    entries.push_back (gateway.publicIP);
 
    // create VAST node factory
    world = new VASTVerse (entries, &netpara, NULL);
    world->createVASTNode (gateway.publicIP, aoi, VAST_EVENT_LAYER);
 
    bool finished = false;
 
    // record beginning of main loop
    while (!finished)
    {
        if (state != JOINED)
        {
            if ((self = world->getVASTNode ()) != NULL)
            {
                sub_no = self->getSubscriptionID ();
                state = JOINED;
            }
        }
 
        else
        {
            // obtain input from user, will store inside 'aoi'
            getInput ();
            self->move (sub_no, aoi);
        }
 
        // perform some per-second tasks
 
        // process incoming message and perform routine tasks
        world->tick ();
 
        // sleep a little if there's unused time
    }
 
    // depart
    self->leave ();
    world->destroyVASTNode (self);
 
    delete world;
 
    return 0;
}