Simulator API
We have implemented a collection of C++ classes for interacting with the MapleSim simulator.  These classes encapsulate the details of building, sending, receiving, and parsing command messages, and can be extended as the user desires.  The classes have been successfully built and tested under Windows NT, Linux, and Solaris, and should be portable to other versions of Unix (contact us if you require assistance).  All of the communication used in the SimSpy demonstration makes use of these classes exclusively.
 

Class Organization

Two base classes, SimApi and SimCmd, handle all of the network i/o and message parsing.  The SimApi class maintains the network connection, and provides methods for sending and receiving data, and for handling exceptions.  From SimApi are derived two child classes, SimApiClient and SimApiServer, which handle the special needs of each side of the network connection.
The SimCmd class is used for sending and receiving commands.  From it are derived classes for each of the command types and responses.  Since each command has its own class with its particular arguments, syntactic errors are caught by the compiler as type mismatches.  The structure is also easily extensible, allowing new parameters or even entire commands to be added without changes to the base class.
 

SimApi family

class SimApi

This class defines the basic functionality of the network communication. The class cannot be created directly; create a  SimApiClient or SimApiServer instead.

MEMBER FUNCTIONS

void Send(const SimCmd &command)
Sends the supplied command across the network connection.  This function blocks only as long as it takes to deliver the command; it does not wait for the response.  command is usually one of the specific command classes inherited from the SimCmd base class.
SimCmd Receive()
Receives a command from the network connection.  The constructed command is returned to the caller.  If a command isn't waiting to be read this function will block until one becomes available.
bool CmdWaiting()
Returns true if the socket has data to be read, false otherwise.

class SimApiClient : public SimApi

MEMBER FUNCTIONS

SimApiClient(const std::string &hostname, unsigned short port )
Creates the client object.  Upon creation, the class attempts to establish a TCP/IP connection to hostname on port number port.  The connection will be maintained until there is either a network interruption (see exceptions thrown, below) or the class instance is destroyed.

class SimApiServer : public SimApi

MEMBER FUNCTIONS

SimApiServer(unsigned short port)
Creates the server object.  Upon creation, the class attempts to establish a TCP/IP server-side socket at port number port that is available to accept incoming connections.  The server socket will be maintained until the class instance is destroyed.

SimCmd family

class SimCmd

A SimCmd is a generic command, from which all other commands are derived.  It has a command type to distinguish what variety of command it is, and a data portion to hold the arguments to the command.  The contents of the data portion are defined by each of the derived classes for that command type.
Each new command created contains a unique message ID number, and each reply contains the matching ID number.  The ID can be used to pair-up responses with their corresponding requests if there are several pending commands at a time.
Since an application cannot predict what type of command its peer will send to it at any particular time, it must first read in the socket data as a generic SimCmd.  Once the SimCmd is read, its command type can be determined.  The SimCmd can then be passed to the constructor of the matching SimCmd child class, which knows how to interpret the data portion of the command in order to extract the command parameters.
When a SimCmd is read from a socket, it records the internal socket ID and the ip address and port number of the peer that sent the command.  These fields are useful in helping a server application determine which client has made the request.

MEMBER VARIABLES

const SOCKET socketid
The ID of the internal socket that the command was received from.  The ID will remain constant for a particular peer for as long as the connection remains up.  This field is valid only for received commands.
const string reason
The error message from the server explaining why the command failed. This field is valid only for received commands of type FAIL.
unsigned long peer_ip
The IP address of the peer that sent the command, in host byte order. This field is valid only for received commands.
unsigned short peer_port
The port number of the peer that sent the command, in host byte order. This field is valid only for received commands.

MEMBER FUNCTIONS

SIMCMD message_type()
Returns the enum value describing what type of command this is.  Once the enum type has been determined the application can pass the generic SimCmd to the corresponding derived-class constructor for that command type.
int message_id()
Returns the unique ID number for this command.  For new commands, this number is automatically assigned by each host.  For reply commands, the number matches the ID of the original request.  A client can record the ID numbers of command request it sends out, and then match up the responses with the requests based on the response ID number.
void ReplyDone()
Builds a generic SIMCMD_DONE message and sends it to the requesting party.  This function is normally not used, since it doesn't provide for any return parameters; use the specific ReplyDone() function defined for each child class.
void ReplyFail(const string &reason)
Builds a SIMCMD_FAIL message and sends it to the requesting party.  The supplied reason should identify to the requestor why the command failed.  This reply function can be used for any of the command types.
 

class SimCmdRegister

SimCmdRegister(std::string username, std::string userorg)
Registers the client with the server.  username and userorg are strings identifying the user to the server.  On success the server returns a command of type SIMCMD_REGISTER_DONE; on failure it returns type SIMCMD_FAIL.

class SimCmdRegisterDone

SimCmdRegisterDone(SimCmd &sc)
Processes a SimCmd of type SIMCMD_REGISTER_DONE.

class SimCmdGetMap

SimCmdGetMap()
Requests a copy of the road map from the simulation server.  On success the server returns a command of type SIMCMD_GETMAP_DONE; on failure it returns type SIMCMD_FAIL.

class SimCmdGetMapDone

SimCmdGetMapDone(SimCmd &sc)
Processes a SimCmd of type SIMCMD_REGISTER_DONE and extracts the road map from the data portion.

MEMBER VARIABLES

RoadNetwork roadnetwork
The road map returned from the server.

class SimCmdCreate

SimCmdCreate(SIM_AGENTTYPE type,SIM_LOCATION loc)
Creates a new type agent in the simulator at location.  SIM_AGENTTYPE and SIM_LOCATION are each enums defined in simdefs.h.  On success the server returns a command of type SIMCMD_CREATE_DONE; on failure it returns SIMCMD_FAIL.

class SimCmdCreateDone

SimCmdCreateDone(SimCmd &sc)
Processes a SimCmd of type SIMCMD_CREATE_DONE and extracts the new agent id from the data portion.

MEMBER VARIABLES

const unsigned int agentid
The identification number of the newly-created agent.

class SimCmdCreateXY

SimCmdCreateXY(SIM_AGENTTYPE type, double X, double Y, double X2, double Y2)
Creates a new type agent in the simulator at location (X,Y).  If the agent is of type SIMAGENT_AIRPLANE then the arguments X2,Y2 specify the target destination; otherwise they are ignored.  On success the server returns a SimCmd of type SIMCMD_CREATEXY_DONE; on failure it returns a SIMCMD_FAIL.

class SimCmdCreateXYDone

SimCmdCreateXYDone(SimCmd &sc)
Processes a SimCmd of type SIMCMD_CREATEXY_DONE and extracts the new agent id from the data portion.

MEMBER VARIABLES

const unsigned int agentid
The identification number of the newly-created agent.

class SimCmdQuery

SimCmdQuery(unsigned short id=0, double dist=0.0, SIM_AGENTTYPE type=SIMAGENT_NONE)
Queries the simulator for a report of all agents of id number id, within dist, and of agent type type.  Any or all of the arguments can be left out or set to zero in order to act as wildcards for that field.  On success the server returns a SimCmd of type SIMCMD_QUERY_DONE containing the agent details; on failure it returns a SIMCMD_FAIL.

class SimCmdQueryDone

SimCmdQueryDone(SimCmd &sc)
Processes a SimCmd of type SIMCMD_QUERY_DONE and extracts the agent state information from the data portion.

MEMBER VARIABLES

const SimAgentStates updates
A std::vector of SimAgentState information about the agents that matched the query.

class SimCmdMove

SimCmdMove(unsigned short id, int heading, int speed)
Requests the simulator to start moving agent number id towards heading at speed.  On success the server returns a SimCmd of type SIMCMD_MOVE_DONE; on failure it returns a SIMCMD_FAIL.

class SimCmdMoveDone

SimCmdMove(SimCmd &sc)
Processes a SimCmd of type SIMCMD_MOVE_DONE.

class SimCmdDestroy

SimCmdDestroy(unsigned short id)
Requests that the simulator remove agent number id from the simulation.  On success the server returns a SimCmd of type SIMCMD_DESTROY_DONE; on failure it returns a SIMCMD_FAIL.

class SimCmdDestroyDone

SimCmdDestroy(SimCmd &sc)
Processes a SimCmd of type SIMCMD_DESTROY_DONE.

SimCmdError exceptions

The SimApi and SimCmd classes throw exceptions under certain circumstances.  These exceptions can be caught and handled by the application in order to provide for robust error recovery, or they can be left to terminate the application in order to prevent serious problems.
All of the exception classes have a public member message which describes the reason for the exception.  The message value is suitable for printing to the end user in order to explain what went wrong in the cases that the exception cannot be handled by the application.
 

class SimCmdError

This exception can be thrown by the following functions under the circumstances described:
 
SimApi::SimApi()
Unable to locate compatible winsock.dll  (WindowsNT version only)
SimApiClient::SimApiClient()
Unable to resolve hostname to an IP address
Unable to create socket for communications
Unable to connect to the Simulation server
SimApiServer::SimApiServer()
Unable to create server socket
Unable to bind address to server socket
Unable to listen for new connections
SimApi::Send()
Output buffer overflow; message not sent
SimApi::Receive()
WSA Error number ####  encountered while retrieving peer IP address (WindowsNT version only)
SimApiServer::Receive()
Primary server socket received an error
Unable to accept new connection
SimApiServer::CmdWaiting()
Primary server socket received an error
SimCmd::message_type()
Invalid command type detected
SimCmd***::SimCmd***()  [any of the SimCmd*** constructors, when extracting from a generic SimCmd]
Mismatched command type
SimApiServer::Read()
Primary server socket received an error

class SimCmdSocketClosed

This exception is used to alert the application that the communications socket has closed during reading or writing.  The application can then take measures to re-establish communication (usually in the case of a client), or to free the other resources associated with the connection and wait for a reconnect (in the case of a server).  The public member variable closedsocket is set to the SOCKET id of the socket that closed.  By the time the application receives this exception SimApi has already closed the socket itself and freed any internal resources associated with it.

This exception can be thrown by the following functions:
 

SimApi::Send()
SimApi::Receive()
SimApiClient::CmdWaiting()
SimApiServer::CmdWaiting()
SimApiServer::Receive()

Last Updated May 8, 1999