Project : Netrek Metaserver Overhaul 1995 Document : Design Specification Revision : BX2 Dated : 1-Aug-1996 Approved : (nobody)
The following processes are defined on the diagram;
So, an example packet would be;
The keywords and their meanings are;
There is no direct relationship between the data flow diagram and the program structure.
main() { /* read configuration */ man_initialise(); /* open log file */ log_open(); /* open network */ ... /* process packets and requests */ while ( TRUE ) { /* process UDP packets */ inc_handle(); /* process TCP connections */ rep_handle(); } } /* main() */
log_open() { } log_send(char *something) { } log_close() { }
Only the main thread will update the database. The forked threads for handling TCP connections will read the database. Some form of synchronisation must be used to ensure that a reader does not see a view of the database that is inconsistent due to concurrent updates. (Discussion)
The packet format is human readable. For this reason, the data format in the disk file should also be human readable. Some information about the packet does not arrive in the packet, and must be stored with the packet. This includes actual source IP address, and date time of receipt. The internal representation of this data is to be described by a packet structure.
struct packet { char *buffer; /* pointer to packet buffer */ size_t length; /* byte length of buffer */ time_t received; /* date time packet received */ addr_t source; /* ip address of packet source */ struct server /* pointers within packet buffer to server items */ { char *address, *type, *port, *players, *free, *tmode, *comment; } server; struct player /* pointers within packet buffer to player items */ { char *slot, *team, *class, *rank, *name, *login; } player[MAXPLAYER]; };The external data represenation in the disk file is to be identical to the packet format as it arrived from the server, with the following exceptions;
The start of each record will be identified by a special character followed by the textual date time received and the textual IP address.
The index is to consist of a set of single dimension array of pointers into the packet structures. A primary index array will provide ordering by IP address and port number. Secondary index arrays, if required, will provide ordering in a request specific manner.
(bsearch() and qsort() will be used)
/* Sets up empty packet list pointer array */ dat_initialise() { } /* Find a packet with the same key as a received packet */ struct packet *dat_find(struct packet *packet) { } /* Insert a new packet into the list */ struct packet *dat_insert(struct packet *packet) { } /* Replace an old packet with a new packet */ void dat_replace(struct packet *old, *new) { } /* Expire and delete old packets */ void dat_expire() { } /* Traverse list for client request */ void dat_traverse ( int ((*compar)(const struct packet *, const struct packet *)), int ((*action)(const struct packet *) ) { /* allocate a private copy of the packet list */ auto struct packet *ours[MAXSERVERS]; /* copy the real one into our copy */ memcpy ( ours, packets, sizeof ( struct packet * ) * MAXSERVERS); /* sort the copy using the caller's comparison routine */ qsort ( ours, MAXSERVERS, sizeof ( struct packet * ), compar ); /* call the caller's action routine for every packet */ for ( i=0; i<MAXSERVERS; i++ ) if ( ours[i] != NULL ) action ( ours[i] ); } /* Save packet list structure to file */ int dat_save() { } /* Load packet list structure from file */ int dat_load() { }
/* ** Handle an incoming UDP packet, validate it, ** and update the server packet database. */ inc_handle( char *buffer, size_t length, addr_t source ) { struct *packet new, old; new = inc_decode ( buffer, length, source ); if ( new == NULL ) return; old = dat_find ( new ); if ( old == NULL ) dat_insert ( new ); else dat_update ( old, new ); } /* ** Build struct of pointers into data fields within packet. Return either ** NULL for an invalid packet, or a pointer to the allocated struct. */ struct *packet inc_decode ( char *buffer, size_t length, addr_t source ) { struct packet packet, *returned; packet.buffer = buffer; packet.length = length; packet.source = source; packet.received = time ( NULL ); packet.server.address = strtok ( buffer, delimiter ); if ( packet.server.address == NULL ) return NULL; packet.server.type = strtok ( NULL, delimiter ); if ( packet.server.type == NULL ) return NULL; packet.server.port = strtok ( NULL, delimiter ); if ( packet.server.port == NULL ) return NULL; packet.server.players = strtok ( NULL, delimiter ); if ( packet.server.players == NULL ) return NULL; packet.server.free = strtok ( NULL, delimiter ); if ( packet.server.free == NULL ) return NULL; packet.server.tmode = strtok ( NULL, delimiter ); if ( packet.server.tmode == NULL ) return NULL; packet.server.comment = strtok ( NULL, delimiter ); if ( packet.server.comment == NULL ) return NULL; /* ... player stuff ... */ returned = malloc ( sizeof ( struct packet ) ); if ( returned == NULL ) return NULL; memcpy ( returned, packet, sizeof ( struct packet ) ); return returned; }
rep_handle(int socket, int port) { }
/* Read configuration file */ man_initialise() { } -- James Cameron Digital Equipment Corporation (Australia) Pty. Ltd. A.C.N. 000 446 800 (cameron@stl.dec.com)