message.c

Go to the documentation of this file.
00001 
00025 // sanity check
00026 #if defined(MSG_INF_TRIES) && defined(NDEBUG)
00027 #error Infinite message retries (MSG_INF_TRIES) may only be specified for debugging builds
00028 #endif
00029 
00030 #include "aatree.h"
00031 #include "vector.h"
00032 #include "game.h"
00033 #include "gameconfig.h"
00034 #include "playernet.h"
00035 #include "net.h"
00036 #include <assert.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <SDL.h>
00040 #ifndef WIN32
00041 #include <unistd.h>
00042 #include <sys/types.h>
00043 #include <sys/socket.h>
00044 #endif
00045 
00050 static AANode *inflightId = AA_ROOT_NODE;
00056 static Vector inflightTime;
00061 static Vector available;
00067 static Vector buffers;
00074 static Uint16 nextMessageId = 0;
00075 
00076 extern Uint32 frameTime;
00077 
00083 #define INIT_RESEND  192
00084 
00090 #define INIT_BUFFERS   16
00091 
00097 #define INIT_MESSAGES 32
00098 
00103 #define INIT_TRIES 4
00104 
00112 #define MIN_POINTERS  64 // half size for buffers
00113 
00118 #define MAX_BUFFERS   (Uint32)((networkState == NETSTATE_SERVER) ? 32 : 16)
00119 
00124 #define MAX_MESSAGES  (Uint32)((networkState == NETSTATE_SERVER) ? 128 : 64)
00125 
00137 static Bool TimeCompare(MsgDescr **lesser, MsgDescr **greater) {
00138     return (*lesser)->nextSend < (*greater)->nextSend;
00139 }
00140 
00148 static void MsgDescrDestructor(MsgDescr **msg) {
00149     // check for an allocated buffer
00150     if ((*msg)->buffer != NULL) {
00151         // free the buffer
00152         BufferFree((*msg)->buffer);
00153     }
00154     // deallocate the message descriptor
00155     free(*msg);
00156     #ifndef NDEBUG
00157     // give the pointer a bogus value
00158     *msg = (MsgDescr*)0xCDCDCDCD;
00159     #endif
00160 }
00161 
00162 void CancelAllMessages() {
00163     // alter the message vectors so that they will free all the message data
00164     inflightTime.destructOp = (DestructorOp)MsgDescrDestructor;
00165     // remove the messages that describe in-flight messages
00166     if (inflightId != AA_ROOT_NODE) {
00167         // destroy the tree
00168         AATreeDestroy(inflightId);
00169         // keep a valid tree
00170         inflightId = AA_ROOT_NODE;
00171     }
00172     VectorClear(&inflightTime);
00173     // reset the destructors
00174     inflightTime.destructOp = NULL;
00175 }
00176 
00177 int GetNumOutgoingMessages() {
00178     return inflightTime.items;
00179 }
00180 
00181 MsgDescr *MessageNew() {
00182     MsgDescr *msg;
00183     int loop;
00184     // check for an available message
00185     if ((msg = (MsgDescr*)VectorLast(&available)) != NULL) {
00186         // pointer fun to get the real value
00187         msg = *(MsgDescr**)msg;
00188         // got a message from the available list; now it is not available
00189         available.items--;  // the shortened version of VectorPop()
00190     }
00191     // no available messages, so make a new one
00192     else {
00193         msg = malloc(sizeof(MsgDescr));
00194     }
00195     #ifndef NDEBUG
00196     // fill the message with crud to force proper initialization of the data
00197     memset(msg, 0xCD, sizeof(MsgDescr));
00198     #endif
00199     // initalize the flags and the interval
00200     msg->flags = 0;
00206     msg->interval = INIT_RESEND;
00207     msg->triesLeft = INIT_TRIES;
00208     // clear the destination map
00209     loop = DESTMAPLEN;
00210     do {
00211         msg->destMap[--loop] = 0;
00212     } while (loop > 0);
00213     // give back the message
00214     return msg;
00215 }
00216 
00217 void MessageFree(MsgDescr *msg) {
00218     #ifndef NDEBUG
00219     int loop;
00220     // grab the first message
00221     MsgDescr **ptr = (MsgDescr**)(available.array);
00222     assert(msg != NULL);
00223     // loop through all the messages
00224     for (loop = available.items; loop > 0; loop--, ptr++) {
00225         // assure that the freed buffer is not already in the list (double free)
00226         assert(msg != *ptr);
00227     }
00228     #endif
00229     // check for an allocated buffer that needs to be reclaimed
00230     if ((msg->buffer != NULL) && !msg->buffLifeUnmanaged) {
00231         // free the buffer
00232         BufferFree(msg->buffer);
00233     }
00234     // check for a full list of available messages
00235     if (available.items >= MAX_MESSAGES) {
00236         // deallocate the message descriptor
00237         free(msg);
00238     }
00239     else {
00240         // clear the buffer pointer
00241         msg->buffer = NULL;
00242         // put it at the end of the available list
00243         VectorPush(&available, &msg);
00244     }
00245 }
00246 
00247 NetBuffer *BufferNew() {
00248     long *spot;
00249     NetBuffer *buff;
00250     // try to get an already allocated buffer from the list of buffers
00251     if ((spot = (long*)VectorLast(&buffers)) == NULL) {
00252         // no free buffers, so make one
00253         if ((buff = (NetBuffer*)malloc(sizeof(NetBuffer))) == NULL) {
00254             // no memory
00255             return NULL;
00256         }
00257     }
00258     else {
00259         // Adjust buff to point to the buffer and not a spot within the vector.
00260         // The buffers themselves must never move, so they cannot be within
00261         // the vector.
00262         buff = *(NetBuffer**)spot;
00263         // clear the item in the vector
00264         *spot = 0; //NULL;
00265         // remove the buffer from the list
00266         buffers.items--;
00267     }
00268     // initialize the length to show no data
00269     buff->length = 0;
00270     return (NetBuffer*)buff;
00271 }
00272 
00273 void BufferFree(NetBuffer *buff) {
00274     #ifndef NDEBUG
00275     int loop;
00276     // grab the first buffer
00277     NetBuffer **ptr = (NetBuffer**)(buffers.array);
00278     assert(buff != NULL);
00279     // loop through all the buffers
00280     for (loop = buffers.items; loop > 0; loop--, ptr++) {
00281         // assure that the freed buffer is not already in the free list
00282         assert(buff != *ptr);
00283     }
00284     #endif
00285     // check for a full list of available messages
00286     if (buffers.items >= MAX_BUFFERS) {
00287         // deallocate the message
00288         free(buff);
00289     }
00290     else {
00291         // put it at the end of the available list
00292         VectorPush(&buffers, &buff);
00293     }
00294 }
00295 
00296 void BufferVecDestr(void *buff) {
00297     BufferFree(*(NetBuffer **)buff);
00298 }
00299 
00300 extern int sock;
00301 
00302 /*
00303  * Constructs a message in a buffer in preperation for sending it over the
00304  * network.
00305  * @internal
00306  * @deprecated
00307  * @dot
00308  * digraph ConstrFlow {
00309  *   node [shape=record, fontname=Helvetica, fontsize=7, height=0.1];
00310  *   edge [fontname=Helvetica, fontsize=7];
00311  *   Start [ label="Start", shape="Mrecord" ];
00312  *   BuffCheck [ label="Allocated buffer with message?", shape="diamond",
00313  *     URL="\ref MsgDescr::buffer" ];
00314  *   Start -> BuffCheck;
00315  *   BufferObt [ label="Obtain a buffer" ];
00316  *   BuffCheck -> BufferObt [ label="No" ];
00317  *   ErrChk [ label="Success getting buffer?", shape="diamond" ];
00318  *   BufferObt ->ErrChk;
00319  *   Constr [ label="Construct the message by calling constrFunc",
00320  *     URL="\ref MsgDescr::constrFunc" ];
00321  *   ErrChk -> Constr [ label="Yes" ];
00322  *   BuffCheck -> Constr [ label="Yes" ];
00323  *   ConstrErrChk [ label="Was there an error?", shape="diamond" ];
00324  *   Constr -> ConstrErrChk;
00325  *   SetFlag [ label="Set the in-flight flag" ];
00326  *   ConstrErrChk -> SetFlag [ label="No" ];
00327  *   End [ label="End", shape="Mrecord" ];
00328  *   SetFlag -> End;
00329  *   EndErr [ label="End with error", shape="Mrecord" ];
00330  *   ConstrErrChk -> EndErr [ label="Yes" ];
00331  *   ErrChk -> EndErr [ label="No" ];
00332  * }
00333  * @enddot
00334  * @param msg  The message descriptor for the message to construct.
00335  * @return     True on success, false if either a buffer could not be allocated
00336  *             or the message's constructor failed to build the message.
00337  * @ingroup    NetMsgSys
00338  * @author     Jeff Jackowski
00339  */
00340  /*
00341 static Bool ConstructMessage(MsgDescr *msg) {
00342     // if there is no persistant buffer, or one has not been set,
00343     // obtain a buffer from the free list, if possible
00344     if (msg->buffer == NULL) {
00345         // if no buffer is set, there must be a constructor function
00346         assert(msg->constrFunc != NULL);
00347         // get a buffer from the list and check for failure
00348         if ((msg->buffer = BufferNew()) == NULL) {
00349             // no memory; can't send
00350             return FALSE;
00351         }
00352     }
00353     // construct the message
00354     if (msg->constrFunc) {
00355         (*(msg->constrFunc))(msg);
00356     }
00357     // check for an error
00358     if (msg->buffer->length < 0) {
00359         // cancel the message
00360         return FALSE;
00361     }
00362     // set the in-flight flag
00363     msg->inflight = TRUE;
00364     // success!
00365     return TRUE;
00366 }
00367 */
00368 
00458 static Bool Send(MsgDescr *msg, Bool inSys) {
00459     Uint32 now = SDL_GetTicks();
00460     // ----- Transmit the message -----
00461     // for clients (easy way)
00462     if ((networkState == NETSTATE_RCVCFG) ||
00463     (networkState == NETSTATE_CLIENT) || (networkState == NETSTATE_CLIDISCONN)) {
00464         // check for an acknowledgement
00465         if (msg->destMap[0] == 0)
00466             // done with this message
00467             goto Send_cancel;
00468         // one less try; see if this is the last try
00469         if (msg->triesLeft == 0) {
00470             // failed -- no acknowledgement
00471             if (msg->failFunc != NULL) {
00472                 (*(msg->failFunc))(msg, NULL);
00473             }
00474             goto Send_cancel;
00475         }
00476         // check for need to resend
00477         if (!msg->noResend) {
00478             // check for lack of approval to send this message
00479             if ((msg->approveFunc != NULL) && 
00480             !(*(msg->approveFunc))(msg, 0)) {
00481                 // no approval -- cancel this message
00482                 goto Send_cancel;
00483             }
00484             // send the message to the server and check for failure
00485             else if (sendto(sock, msg->buffer->data, msg->buffer->length, 0,
00486             &outgoingAddr.addr, outgoingAddr.length) != msg->buffer->length) {
00487                 // failed to construct or send message
00488                 if (msg->failFunc != NULL) {
00489                     (*(msg->failFunc))(msg, NULL);
00490                 }
00491                 goto Send_cancel;
00492             }
00493             msg->inflight = TRUE;
00494         }
00495     }
00496     // for servers (complex way)
00497     else {
00498         ClientData *client = clients;
00499         DESTMAPTYPE *sendFlags = &(msg->destMap[0]), sendFlagMask;
00500         int mappos = 0;  // index into MsgDescr::destMap
00501         int cid = 0;     // the client ID
00502         int processedClients = 0;
00503         Bool bcastSent = FALSE;  // records if a broadcast message was sent
00504         for (; mappos < DESTMAPLEN; mappos++, sendFlags++) {
00505             // see if there are no destination clients
00506             if (*sendFlags == 0) {
00507                 // advanve to the next block of clients
00508                 cid += sizeof(DESTMAPTYPE) * 8;
00509                 client += sizeof(DESTMAPTYPE) * 8;
00510                 continue;
00511             }
00512             sendFlagMask = 1;
00513             // cid through all the clients
00514             for (; sendFlagMask && (cid < MAX_PLAYERS);
00515             client++, cid++, sendFlagMask <<= 1) {
00516                 // check for a disconnecting client
00517                 if (!client->contact || (client->disconn &&
00518                 ((now - client->disconnTime) >= 4096))) {
00519                     // clear the flags
00520                     client->flags = 0;
00521                     // remove client from destination list
00522                     *sendFlags &= ~sendFlagMask;
00523                     // don't send to this client
00524                     continue;
00525                 }
00526                 else if (client->disconn &&
00527                 (msg->buffer->data[0] != MSG_TYPE_CONN_DISCONN))
00528                     continue;
00529                 // first check for an inactive client record or a client that
00530                 // does not need the message
00531                 if (!(*sendFlags & sendFlagMask) ||
00532                 // avoid sending to self
00533                 (localPlayer == cid) ||
00534                 // next, check for a client that receives broadcasts, and if a
00535                 // broadcast has already been sent
00536                 (bcastSent && client->bcast)) {
00537                     // no need to send to this client
00538                     continue;
00539                 }
00540                 // see if this is the last chance for a client to acknowledge
00541                 if (msg->triesLeft == 0) {
00542                     // this client is a destination for this message, but did
00543                     // not acknowledge the message, so call the failure handler
00544                     if (msg->failFunc != NULL) {
00545                         (*(msg->failFunc))(msg, client);
00546                     }
00547                     continue;
00548                 }
00549                 // for messages that can be re-transmitted . . .
00550                 if (!msg->noResend) {
00551                     // check for lack of approval to send this message
00552                     if ((msg->approveFunc != NULL) &&
00553                     !(*(msg->approveFunc))(msg, cid)) {
00554                         // no approval -- remove client from destination list
00555                         *sendFlags ^= sendFlagMask;
00556                         // do not send
00557                         continue;
00558                     }
00559                     // see if a broadcast should be sent to this client
00560                     if (msg->bcast && client->bcast) {
00561                         assert(outgoingAddr.ipv4.sin_addr.s_addr ==
00562                         htonl(INADDR_BROADCAST));
00563                         // send out the data and check for error
00564                         if (sendto(sock, msg->buffer->data, msg->buffer->length,
00565                         0, &outgoingAddr.addr,  outgoingAddr.length)
00566                         != msg->buffer->length) {
00567                             // failed to send a message to this client
00568                             goto Send_failure;
00569                         }
00570                         // flag that a broadcast was sent so it isn't
00571                         // rebroadcast to other clients that will receive
00572                         // broadcasts
00573                         bcastSent = TRUE;
00574                         msg->inflight = TRUE;
00575                     }
00576                     // a direct, unicast message needs to be sent to this client
00577                     else {
00578                         // set the socket to not broadcast
00579                         // needed?
00580                         // send out the data
00581                         if (sendto(sock, msg->buffer->data, msg->buffer->length,
00582                         0, &(client->addr.addr), client->addr.length)
00583                         != msg->buffer->length) {
00584                             Send_failure:
00585                             // Can't send to this client? Remove it from the
00586                             // destiniation list
00587                             *sendFlags ^= sendFlagMask;
00588                             // failed to send a message to this client
00589                             if (msg->failFunc != NULL) {
00590                                 (*(msg->failFunc))(msg, client);
00591                             }
00592                             // don't count sending this message
00593                             continue;
00594                         }
00595                         msg->inflight = TRUE;
00596                         // set the socket to broadcast
00597                     }
00598                 }
00599                 // processed another client
00600                 processedClients++;
00601             }
00602         }
00603         // check for no processed clients
00604         if (processedClients == 0) {
00605             // cancel this message
00606             goto Send_cancel;
00607         }
00608         #ifdef MSG_DEBUG
00609         else if (msg->destMap[0] <= 1) {
00610             printf("Message %i has no destination but went somewhere\n",
00611             msg->msgId);
00612         }
00613         #endif
00614     }
00615     // update the resend time
00616     msg->nextSend = SDL_GetTicks() + msg->interval;
00617     #ifdef MSG_INF_TRIES
00618     // check for what is normally the maximum number of attemps
00619     if (--msg->triesLeft == 0) {
00620         // do not let the value drop below zero
00621         msg->triesLeft++;
00622         // set the interval to a high value
00623         msg->interval = 16384;
00624     }
00625     else {
00626         // increase the resend time
00627         msg->interval <<= 1;
00628     }
00629     #else
00630     // one less attempt left
00631     msg->triesLeft--;
00632     // wait longer until the next send
00633     msg->interval <<= 1;
00634     #endif
00635     return TRUE;
00636     Send_cancel:
00637     // see if the buffer should not be maintained
00638     if (!msg->buffLifeUnmanaged) {
00639         // reclaim the buffer
00640         BufferFree(msg->buffer);
00641         msg->buffer = NULL;
00642     }
00643     if (inSys) {
00644         #ifdef MSG_DEBUG
00645         printf("Canceling message %i\n", msg->msgId);
00646         #endif
00647         // remove the message from the tree
00648         AATreeRemove(inflightId, msg->msgId);
00649     }
00650     MessageFree(msg);
00651     return FALSE;
00652 }
00653 
00654 Bool AddMessage(MsgDescr *msg) {
00655     AANode *node;
00656     // the message must include a buffer that is long enough to contain
00657     // something
00658     assert((msg->buffer != NULL) && (msg->buffer->length > 3));
00659     // assure the network state is valid for sending a message
00660     assert(networkState <= NETSTATE_SERVER);
00661     // assure that messages sent to the server have the correct destination
00662     assert((networkState != NETSTATE_CLIENT) || (msg->destMap[0] == 1));
00663     // assure there are tries left
00664     assert(msg->triesLeft > 0);
00665     // if the message needs an ID . . .
00666     if (!msg->doNotAddId) {
00667         // advance the next message ID -- 0xFFFF is an invalid value
00668         if (++nextMessageId == 0xFFFF) {
00669             // advance again
00670             nextMessageId++;
00671         }
00672         // set the message ID
00673         msg->msgId = nextMessageId;
00674         // write it into the buffer
00675         MSG_WRITE_16C(msg->buffer->data, 1, msg->msgId);
00676     }
00677     // first send out the message and check for success
00678     if (Send(msg, FALSE)) { 
00679         // put the message into the AA-tree
00680         node = AATreeAdd(&inflightId, msg->msgId);
00681         assert(node != NULL);
00682         node->data = msg;
00683         // put the message into the heap
00684         VectorHeapPush(&inflightTime, &msg);
00685         // success
00686         return TRUE;
00687     }
00688     // failed
00689     return FALSE;
00690 }
00691 
00692 void ServiceMessages() {
00693     MsgDescr *msg;
00694     Uint32 now = SDL_GetTicks();
00695     // assure the network state is valid for servicing messages
00696     assert((networkState >= NETSTATE_CONNECTING) ||
00697     (networkState <= NETSTATE_SERVER));
00698     // loop until all messages awaiting resend have been serviced
00699     while (1) {
00700         // check for no messages in the system or for messages not yet ready to
00701         // be resent
00702         if (((msg = VectorFirst(&inflightTime)) == NULL) ||
00703         (msg = *(MsgDescr**)msg, msg->nextSend > now)) {
00704             // nothing left to do
00705             return;
00706         }
00707         // take the message out of the priority queue
00708         VectorHeapPop(&inflightTime);
00709         #ifdef MSG_DEBUG
00710         printf("Send message %d, ", msg->msgId);
00711         
00712         {
00713             AANode *node;
00714             node = AATreeFind(inflightId, msg->msgId);
00715             if (node == NULL) {
00716                 printf("***** Message not in tree *****\n");
00717             }
00718             else if (node->data != msg) {
00719                 printf("***** Different message in tree, ID = %i *****\n",
00720                 node->key);
00721             }
00722             else if (node->key != msg->msgId) {
00723                 printf("***** Message in tree had different ID: %i *****\n",
00724                 node->key);
00725             }
00726         }
00727         
00728         #endif
00729         // send it again and check for success
00730         if (Send(msg, TRUE)) {
00731             // put it back into the priority queue
00732             VectorHeapPush(&inflightTime, &msg);
00733             #ifdef MSG_DEBUG
00734             printf("keeping for later\n");
00735             #endif
00736         }
00737         #ifdef MSG_DEBUG
00738         else printf("done with it\n");
00739         #endif
00740     }
00741 }
00742 
00743 Bool ValidateClient(SocketAddr *origin, Uint8 clientId) {
00744     ClientData *client;
00745     // the client is not this client
00746     if ((clientId == localPlayer) ||
00747     #if (MAX_PLAYERS < 256)
00748     // assure that the client ID is within bounds
00749     (clientId > MAX_PLAYERS) ||
00750     #endif
00751     // see if the client is inactive
00752     (!(client = &(clients[clientId]))->contact) ||
00753     // check for non-matching address
00754     !EqualAddresses(origin, &(client->addr)))  {
00755         return FALSE;
00756     }
00757     // matching address
00758     return TRUE;
00759 }
00760 
00761 Bool ValidateServer(SocketAddr *origin) {
00762     // only validate a server when connected to one, and make sure the address
00763     // is the same now as when the connection was made
00764     if (((networkState == NETSTATE_RCVCFG) ||
00765     (networkState == NETSTATE_CLIENT) || (networkState == NETSTATE_CLIDISCONN)) &&
00766     EqualAddresses(origin, &outgoingAddr)) {
00767         // looks like the server
00768         return TRUE;
00769     }
00770     return FALSE;
00771 }
00772 
00820 static Bool HandleAck(SocketAddr *origin, NetBuffer *buff, Uint8 *unused,
00821 Uint16 noid) {
00822     AANode *node;
00823     Uint8 *ptr = &(buff->data[3]);
00824     int loop;
00825     DESTMAPTYPE *map, flag;
00826     Uint16 msgId;
00827     Uint8 clientId;
00828     // get the client id
00829     clientId = buff->data[1];
00830     // validate the client or server
00831     if (((((networkState == NETSTATE_RCVCFG) ||
00832     (networkState == NETSTATE_CLIENT) || (networkState == NETSTATE_CLIDISCONN)) 
00833     && !ValidateServer(origin)) || (((networkState == NETSTATE_SERVER) ||
00834     (networkState == NETSTATE_SRVDISCONN)) &&
00835     !ValidateClient(origin, clientId))) ||
00836     // validate the length of the message
00837     (buff->length != (3 + buff->data[2] * 2))) {
00838         return FALSE;        // invalid origin or length
00839     }
00840     // loop through the acks
00841     for (loop = buff->data[2]; loop > 0; loop--) {
00842         // read in the ID of the acknowledged message
00843         MSG_READ_16(ptr, msgId);
00844         // find the corresponding message descriptor
00845         if ((node = AATreeFind(inflightId, msgId)) != NULL) {
00846             #ifdef MSG_DEBUG
00847             if (node->key != msgId) {
00848                 printf("***** Find got a node for a different key *****\n");
00849                 printf("\tLooking for %i, got %i\n", msgId, node->key);
00850             }
00851             if (((MsgDescr*)(node->data))->msgId != msgId) {
00852                 printf("***** Node's key differs from message ID *****\n");
00853                 printf("\tNode key is %i, ID is %i\n", node->key,
00854                 ((MsgDescr*)(node->data))->msgId);
00855             }
00856             #endif
00857             // get the location of the destination flag
00858             map = &(((MsgDescr*)(node->data))->destMap[
00859             GetDestMapIndex(clientId)]);
00860             flag = GetDestMapFlag(clientId);
00861             // see if this client is on the destination list
00862             if (*map & flag) {
00863                 // call the ack function
00864                 if ((*(((MsgDescr*)(node->data))->ackFunc)) != NULL) {
00865                     (*(((MsgDescr*)(node->data))->ackFunc))((MsgDescr*)
00866                     (node->data), clientId);
00867                 }
00868                 // remove the client from the destination list
00869                 *map &= ~flag;
00870                 #ifdef MSG_DEBUG
00871                 printf("Client #%d ack'ed message %d\n",
00872                 clientId, msgId);
00873                 #endif
00874             }
00875             #ifdef MSG_DEBUG
00876             else {
00877                 int ind;
00878                 DESTMAPTYPE bit;
00879                 printf("Client #%d RE-ack'ed message %d\nDest: ",
00880                 clientId, msgId);
00881                 for (ind = 0; ind < DESTMAPLEN; ind++) {
00882                     for (bit = 1; bit > 0; bit <<= 1) {
00883                         if (((MsgDescr*)(node->data))->destMap[ind] & bit)
00884                             putchar('1');
00885                         else
00886                             putchar('0');
00887                     }
00888                 }
00889                 putchar('\n');
00890             }
00891             #endif
00892         }
00893         #ifdef MSG_DEBUG
00894         else {
00895             printf("Client #%d ack'ed CANCELED message %d\n",
00896             clientId, msgId);
00897         }
00898         #endif
00899     }
00900     // never acknowledge acknowledgments
00901     return FALSE;
00902 }
00903 
00912 static void AckConnAccept(MsgDescr *msg, int cid) {
00913     // mark the client as active
00914     clients[cid].active = TRUE;
00915     // allow the same random ID to be reused
00916     clients[cid].randId = 0;
00917     // add the client to the config list
00918     AddToConfigList(&(clients[cid]));
00919     #ifndef NDEBUG
00920     // A debugging status message (console only) on the server that tells of a
00921     // newly connected client. Because this is only used in debug builds and
00922     // not on the GUI, translating it should be considered a low priority.
00923     // The first parameter (%1$d) is the ID number assigned to the client.
00924     // The second parameter (%2$d) is the broadcast capability flag which is
00925     // generally true for clients on the same LAN as the server.
00926     #ifdef USE_GETTEXT
00927     wprintf(L"Accepted new client, ID = %d, broadcast = %d\n", cid,
00928     clients[cid].bcast);
00929     #else
00930     printf("Accepted new client, ID = %d, broadcast = %d\n", cid,
00931     clients[cid].bcast);
00932     #endif
00933     #endif
00934 }
00935 
00945 static void FailConnAccept(MsgDescr *msg, ClientData *client) {
00946     // Send a denial message.
00947     char outbuff[5];
00948     // write the type ID
00949     outbuff[0] = MSG_TYPE_CONN_DENY;
00950     // write the random ID
00951     MSG_WRITE_32C(outbuff, 1, client->randId);
00952     // send it to the requestor and don't worry about errors
00953     sendto(sock, outbuff, 5, 0, &(client->addr.addr), client->addr.length);
00954     // mark the client as inactive
00955     client->flags = 0;
00956     #ifndef NDEBUG
00957     // A debugging status message (console only) on the server that provides
00958     // notification of a failed connection attempt. Because this is only used
00959     // in debug builds and not on the GUI, translating it should be considered
00960     // a low priority. The only parameter (%d) is the ID number assigned to the
00961     // client.
00962     #ifdef USE_GETTEXT
00963     wprintf(L"Attempted connection failed for client, ID = %d\n", client->cid);
00964     #else
00965     printf("Attempted connection failed for client, ID = %d\n", client->cid);
00966     #endif
00967     #endif
00968 }
00969 
01019 static Bool HandleConnReq(SocketAddr *origin, NetBuffer *buff, Uint8 *unused,
01020     Uint16 noid) {
01021     MsgDescr *msg;
01022     ClientData *client = NULL, *spot = clients;
01023     int clientId, loop;
01024     Uint32 randId, now = SDL_GetTicks();
01025     // read in the random ID
01026     MSG_READ_32C(buff->data, 2, randId);
01027     // find the next available client position
01028     for (loop = 0; loop < MAX_PLAYERS; loop++, spot++) {
01029         // see if this client has already attempted to connect
01030         if ((spot->randId == randId) && EqualAddresses(&(spot->addr), origin)) {
01031             // do nothing -- it was handled already
01032             return FALSE;
01033         }
01034         // see if this is an available spot
01035         if ((client == NULL) && (!spot->contact || (spot->disconn &&
01036         ((now - spot->disconnTime) >= 4096)))) {
01037             // clear the client flags
01038             spot->flags = 0;
01039             // record the client spot for later use
01040             client = spot;
01041             client->cid = clientId = loop;
01042         }
01043     }
01044     // if a client spot was not found, or if a new descriptor cannot be made,
01045     // or if a buffer for the message cannot be made . . .
01046     if ((client == NULL) || ((msg = MessageNew()) == NULL) ||
01047     ((msg->buffer = BufferNew()) == NULL)) {
01048         // . . . send a denial message
01049         char outbuff[5];
01050         // write the type ID
01051         outbuff[0] = MSG_TYPE_CONN_DENY;
01052         // write the random ID
01053         outbuff[1] = buff->data[2];
01054         outbuff[2] = buff->data[3];
01055         outbuff[3] = buff->data[4];
01056         outbuff[4] = buff->data[5];
01057         // send it to the requestor and don't worry about errors
01058         sendto(sock, outbuff, 5, 0, &(origin->addr), origin->length);
01059         // if a message descriptor was allocated, give it back
01060         if (msg != NULL) {
01061             MessageFree(msg);
01062         }
01063         // do not acknowledge this message
01064         return FALSE;
01065     }
01066     // mark the client as having contacted the server
01067     client->contact = TRUE;
01068     // record the broadcast reception flag
01069     client->bcast = 0;   // buff->data[1] > 0;
01070     // record the random identification value
01071     client->randId = randId;
01072     // record the originating address
01073     client->addr = *origin;
01074     // setup the message descriptor
01075     msg->approveFunc = NULL;
01076     msg->ackFunc =  AckConnAccept;
01077     msg->failFunc = FailConnAccept;
01078     msg->interval <<= 1;
01079     // build the response message
01080     msg->buffer->length = 8;
01081     msg->buffer->data[0] = MSG_TYPE_CONN_ACCEPT;
01082     msg->buffer->data[3] = clientId;
01083     // write the random ID
01084     MSG_WRITE_32C(msg->buffer->data, 4, client->randId);
01085     // set the destination
01086     msg->destMap[GetDestMapIndex(clientId)] = GetDestMapFlag(clientId);
01087     // one last check
01088     if (networkState == NETSTATE_SERVER) {
01089         // add the message to the system
01090         AddMessage(msg);
01091     }
01092     // do not acknowledge this message
01093     return FALSE;
01094 }
01095 
01107 static Bool HandleConnDeny(SocketAddr *origin, NetBuffer *buff, Uint8 *unused,
01108 Uint16 noid) {
01109     // see if this data is valid
01110     if ((networkState == NETSTATE_CONNECTING) && (buff->length == 5) &&
01111     ValidateServer(origin)) {
01112         // the connection has been denied
01113         networkState = NETSTATE_SRVDENY;
01114     }
01115     return FALSE;
01116 }
01117 
01136 static Bool HandleConnAccept(SocketAddr *origin, NetBuffer *buff, Uint8 *unused,
01137 Uint16 noid) {
01138     Uint32 randId;
01139     Uint8 cid;
01140     // this message is only valid when this process is trying to find or
01141     // connect to a server
01142     if ((networkState == NETSTATE_INIT) || (networkState >= NETSTATE_RCVCFG) ||
01143     // the message length must also be correct
01144     (buff->length != 8)) {
01145         // ignore this message
01146         return FALSE;
01147     }
01148     // read in the client ID
01149     cid = buff->data[3];
01150     #if (MAX_PLAYERS < 256)
01151     // check for an ID out of bounds
01152     if (cid >= MAX_PLAYERS) {
01153         // bad data; ignore it
01154         return FALSE;
01155     }
01156     #endif
01157     // read in the random ID
01158     MSG_READ_32C(buff->data, 4,randId);
01159     // check for a matching random ID
01160     if (clientRandId == randId) {
01161         int bcast = 0;
01162         // set the new ID value
01163         localPlayer = cid;
01164         // change the network status
01165         networkState = NETSTATE_RCVCFG;
01166         // do not broadcast
01167         setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&bcast,
01168         sizeof(int));
01169         // send future messages to the server
01170         outgoingAddr = *origin;
01171         // acknowledge the message
01172         return TRUE;
01173     }
01174     // message not for this host
01175     return FALSE;
01176 }
01177 
01178 extern int timeSyncState;
01179 
01180 void MsgFailDropConnection(MsgDescr *descr, ClientData *client) {
01181     // see if this process is a client or is disconnecting
01182     if ((networkState == NETSTATE_RCVCFG) ||
01183     (networkState == NETSTATE_CLIENT) || (networkState == NETSTATE_CLIDISCONN)) {
01184         // move this process to the initial networking state
01185         CloseSocket(sock);
01186         #ifndef NDEBUG
01187         if (networkState < NETSTATE_CLIDISCONN) {
01188             #ifndef NDEBUG
01189             #ifdef USE_GETTEXT
01190             wprintf(L"Lost connection to the server\n");
01191             #else
01192             printf("Lost connection to the server\n");
01193             #endif
01194             #endif
01195         }
01196         #endif
01197         networkState = timeSyncState = NETSTATE_INIT;
01198     }
01199     // see if this process is the server
01200     if (networkState == NETSTATE_SERVER) {
01201         // is this a disconnect message, and is
01202         // the failing client the disconnecting one?
01203         if ((descr->buffer->length == 4) &&
01204         (descr->buffer->data[0] == MSG_TYPE_CONN_DISCONN) &&
01205         (descr->buffer->data[3] == client->cid)) {
01206             // remove the offending client
01207             client->flags = 0;
01208             players[client->cid].flags = 0;
01209             // take the client out of the config list
01210             RemoveFromConfigList(client);
01211             #ifndef NDEBUG
01212             #ifdef USE_GETTEXT
01213             wprintf(L"Client #%d disconnected and stopped responding\n",
01214             client->cid);
01215             #else
01216             printf("Client #%d disconnected and stopped responding\n",
01217             client->cid);
01218             #endif
01219             #endif
01220         }
01221         // this client was told of another that disconnected
01222         else {
01223             #ifndef NDEBUG
01224             #ifdef USE_GETTEXT
01225             wprintf(L"Client #%d did not respond to a disconnect message\n",
01226             client->cid);
01227             #else
01228             printf("Client #%d did not respond to a disconnect message\n",
01229             client->cid);
01230             #endif
01231             #endif
01232             // send this client a disconnect since it isn't responding
01233             SendDisconnectMessage(client->cid);
01234             // take the client out of the config list
01235             RemoveFromConfigList(client);
01236         }
01237     }
01238     // see if this process is a disconnecting server
01239     //else if (networkState == NETSTATE_SRVDISCONN) {
01240         // change the network state to show that the process is complete
01241         
01242 }
01243 
01244 void MsgFailDisconnect(MsgDescr *descr, ClientData *client) {
01245     // for clients . . .
01246     if ((networkState == NETSTATE_RCVCFG) ||
01247     (networkState == NETSTATE_CLIENT)) {
01248         #ifndef NDEBUG
01249         #ifdef USE_GETTEXT
01250         wprintf(L"The server stopped responding\n");
01251         #else
01252         printf("The server stopped responding\n");
01253         #endif
01254         #endif
01255         // the server failed to respond, so leave the game
01256         SendDisconnectMessage(localPlayer);
01257         networkState = NETSTATE_CLIDISCONN;
01258     }
01259     else if (networkState == NETSTATE_SERVER) {
01260         #ifndef NDEBUG
01261         #ifdef USE_GETTEXT
01262         wprintf(L"Client #%d stopped responding; no ack to message %d\n",
01263         client->cid, descr->msgId);
01264         #else
01265         printf("Client #%d stopped responding; no ack to message %d\n",
01266         client->cid, descr->msgId);
01267         #endif
01268         #endif
01269         // flag the player and client as inactive
01270         RemovePlayer(&players[client->cid]);
01271         client->active = FALSE;
01272         // flag the client as disconnecting and record the time of the event
01273         client->disconn = TRUE;
01274         client->disconnTime = SDL_GetTicks();
01275         assert(client->contact == TRUE);
01276         // take the client out of the config list
01277         RemoveFromConfigList(client);
01278         // a client failed to respond, so eject it from the game
01279         SendDisconnectMessage(client->cid);
01280     }
01281 }
01282 
01296 static Bool HandleConnDisconn(SocketAddr *origin, NetBuffer *buff,
01297 Uint8 *clientId, Uint16 noid) {
01298     // see if this process is a client
01299     if (((networkState == NETSTATE_RCVCFG) || (networkState == NETSTATE_CLIENT))
01300     && ValidateServer(origin)) {
01301         // see if the disconnecting host is the server
01302         if (buff->data[3] == 0) {
01303             #ifndef NDEBUG
01304             #ifdef USE_GETTEXT
01305             wprintf(L"Server disconnected\n");
01306             #else
01307             printf("Server disconnected\n");
01308             #endif
01309             #endif
01310             // change the network state
01311             networkState = NETSTATE_DISCONN;
01312             // acknowledge the message
01313             return TRUE;
01314         }
01315         // see if this client was disconnected (communication troubles)
01316         if (buff->data[3] == localPlayer) {
01317             #ifndef NDEBUG
01318             #ifdef USE_GETTEXT
01319             wprintf(L"Server terminated connection\n");
01320             #else
01321             printf("Server terminated connection\n");
01322             #endif
01323             #endif
01324             // change the network state
01325             networkState++;
01326             // acknowledge the message
01327             return TRUE;
01328         }
01329         #if (MAX_PLAYERS < 256)
01330         // assure that the client ID is within bounds
01331         if (buff->data[3] >= MAX_PLAYERS) return FALSE;
01332         #endif
01333         // remove the corresponding player from the game
01334         RemovePlayer(&players[buff->data[3]]);
01335         // acknowledge the message
01336         return TRUE;
01337     }
01338     // see if this process is a server
01339     if ((networkState == NETSTATE_SERVER) &&
01340     ValidateClient(origin, buff->data[3])) {
01341         // flag the player and client as inactive
01342         RemovePlayer(&players[buff->data[3]]);
01343         clients[buff->data[3]].active = FALSE;
01344         // flag the client as disconnecting and record the time of the event
01345         clients[buff->data[3]].disconn = TRUE;
01346         clients[buff->data[3]].disconnTime = SDL_GetTicks();
01347         assert(clients[buff->data[3]].contact == TRUE);
01348         // acknowledge the message
01349         *clientId = buff->data[3];
01350         // take the client out of the config list
01351         RemoveFromConfigList(&clients[buff->data[3]]);
01352         #ifndef NDEBUG
01353         #ifdef USE_GETTEXT
01354         wprintf(L"Client #%d disconnected\n", buff->data[3]);
01355         #else
01356         printf("Client #%d disconnected\n", buff->data[3]);
01357         #endif
01358         #endif
01359         // send the repeated disconnect
01360         SendDisconnectMessage(buff->data[3]);
01361         // acknowledge the message
01362         return TRUE;
01363     }
01364     return FALSE;
01365 }
01366 
01367 Bool SendDisconnectMessage(Uint8 id) {
01368     MsgDescr *msg;
01369     // Send a message to all other clients to inform them of the disconnect.
01370     // get the descriptor
01371     if ((msg = MessageNew()) == NULL) {
01372         // failed; nothing more can be done
01373         return FALSE;
01374     }
01375     // get a buffer
01376     if ((msg->buffer = BufferNew()) == NULL) {
01377         // failed; relase the message
01378         MessageFree(msg);
01379         return FALSE;
01380     }
01381     // setup the message descriptor
01382     msg->approveFunc = NULL;
01383     msg->ackFunc = NULL;
01384     msg->failFunc = MsgFailDropConnection;
01385     msg->buffer->length = 4;
01386     //msg->interval = INIT_RESEND << 2;
01387     msg->triesLeft = INIT_TRIES << 1;
01388     // build the response message
01389     msg->buffer->data[0] = MSG_TYPE_CONN_DISCONN;
01390     msg->buffer->data[3] = id;
01391     msg->bcast = TRUE;  // broadcast OK
01392     // set the destination
01393     if (networkState == NETSTATE_SERVER) {
01394         // tell everyone of the departure, including the failed client in hopes
01395         // of making it more obvious to that client
01396         SetDestToAll(msg);
01397     }
01398     else {
01399         // this must be set to indicate the server is the destination
01400         msg->destMap[0] = 1;
01401         #ifndef NDEBUG
01402         #ifdef USE_GETTEXT
01403         wprintf(L"Disconnecting from server\n");
01404         #else
01405         printf("Disconnecting from server\n");
01406         #endif
01407         #endif
01408     }
01409     // add the message to the system
01410     return AddMessage(msg);
01411 }
01412 
01417 static const HandleMsg messageHandlers[MSG_TYPE_MAX] = {
01418     HandleAck,               // MSG_TYPE_ACK
01419     HandleConnReq,           // MSG_TYPE_CONN_REQ
01420     HandleConnDeny,          // MSG_TYPE_CONN_DENY
01421     HandleConnAccept,        // MSG_TYPE_CONN_ACCEPT
01422     HandleConnDisconn,       // MSG_TYPE_CONN_DISCONN
01423     HandleGameOption,        // MSG_TYPE_OPTION
01424     HandleObstacle,          // MSG_TYPE_OBSTACLE
01425     HandleArea,              // MSG_TYPE_SPAWN
01426     HandleArea,              // MSG_TYPE_GOAL
01427     // NULL,                    // MSG_TYPE_GAME_START
01428     // NULL,                    // MSG_TYPE_GAME_OVER
01429     HandleScoreUpdate,       // MSG_TYPE_SCORE
01430     HandlePlayerUpdate,      // MSG_TYPE_PLAYER_UPDATE
01431     HandlePlayerSpawn        // MSG_TYPE_PLAYER_SPAWN
01432 };
01433 
01438 #define MSG_MAX_ACK 15
01439 
01444 #define MSG_ACK_SIZE  ((MSG_MAX_ACK + 1) << 1)
01445 
01450 static NetBuffer inbuff;
01451 
01458 static Uint8 *ackbuff = NULL;
01459 
01467 static void SendAck(Uint8 *ack) {
01468     SocketAddr *dest;
01469     // find the destination
01470     if (networkState == NETSTATE_SERVER) {
01471         dest = &(clients[ack[1]].addr);
01472     }
01473     else {
01474         dest = &outgoingAddr;
01475     }
01476     // construct the rest of the ack message
01477     ack[0] = MSG_TYPE_ACK;
01478     ack[1] = localPlayer;
01479     // send it
01480     sendto(sock, ack, (ack[2] << 1) + 3, 0, &(dest->addr), dest->length);
01481     // reset the message counter
01482     ack[2] = 0;
01483 }
01484 
01485 Bool ReceiveMessages() {
01486     Uint8 *ack = ackbuff;
01487     SocketAddr origin;
01488     int error = 0;
01489     Uint16 msgId;
01490     Uint8 list[rounddivup(MAX_PLAYERS, 8)] = { 0 };
01491     Uint8 msgType, clientId = 0;
01492     // assure the network state is valid for receiving messages
01493     assert(networkState <= NETSTATE_SRVDISCONN);
01494     // loop while there are incomming messages to process
01495     while ((origin.length = sizeof(struct sockaddr_in6),  // set max length
01496     // receive data
01497     (inbuff.length = recvfrom(sock, inbuff.data, MSG_MAX_SIZE, 0, &origin.addr, 
01498     &origin.length)) > 0) || ((error = GetNetErrorVal()) == ECONNREFUSED)) {
01499         // check for an error caused by previously sending data somewhere
01500         if (error == ECONNREFUSED) {
01501             // clear the error value
01502             error = 0;
01503             // ignore the problem and try to receive more data
01504             continue;
01505         }
01506         // read in the type
01507         msgType = inbuff.data[0];
01508         // assure a valid type
01509         if (msgType < MSG_TYPE_MAX) {
01510             assert(messageHandlers[msgType] != NULL);
01511             // message includes an ID for itself?
01512             if (msgType >= MSG_TYPE_CONN_ACCEPT) {
01513                 // read in the message ID
01514                 MSG_READ_16C(inbuff.data, 1, msgId);
01515             }
01516             // branch based on type and see if acknowledgment is requested
01517             if ((*(messageHandlers[msgType]))(&origin, &inbuff, &clientId,
01518             msgId)) {
01519                 // if a server . . .
01520                 if (networkState == NETSTATE_SERVER) {
01521                     // assure the client ID is valid
01522                     assert(clientId < MAX_PLAYERS);
01523                     // get a reference to the right spot in the ack buffer
01524                     ack = &(ackbuff[clientId * MSG_ACK_SIZE]);
01525                 }
01526                 // assure the client ID has not changed when acting as a client
01527                 assert((networkState != NETSTATE_CLIENT) || (clientId == 0));
01528                 // add a message
01529                 MSG_WRITE_16C(ack, 3 + (ack[2] << 1), msgId);
01530                 // set the client ID
01531                 ack[1] = clientId;
01532                 // check for maximum stored messages
01533                 if (++ack[2] == MSG_MAX_ACK) {
01534                     // send it
01535                     SendAck(ack);
01536                     // the client no longer needs acknowledgment
01537                     list[clientId >> 3] &= ~(1 << (clientId & 7));
01538                 }
01539                 else {
01540                     // mark the client as needing an ack
01541                     list[clientId >> 3] |= 1 << (clientId & 7);
01542                 }
01543             }
01544             #ifdef MSG_DEBUG
01545             else if (msgType >= MSG_TYPE_CONN_ACCEPT) {
01546                 printf("Not ack'ing message #%i, type %i\n", msgId, msgType);
01547             }
01548             #endif
01549         }
01550         // if an invlaid type, ignore the whole message
01551         #ifdef MSG_DEBUG
01552         else {
01553             printf("Got bad message type\n");
01554         }
01555         #endif
01556     }
01557     // if a server . . .
01558     if (networkState == NETSTATE_SERVER) {
01559         int byteLoop = 0, bitLoop;
01560         clientId = 0;
01561         // loop through the bytes
01562         for (byteLoop = 0; byteLoop < rounddivup(MAX_PLAYERS, 8); byteLoop++) {
01563             // check for no acks in this block of 8
01564             if (list[byteLoop] == 0) {
01565                 // advance the client count past this block
01566                 clientId += 8;
01567                 // move to the next block
01568                 continue;
01569             }
01570             // loop through the bits
01571             for (bitLoop = 0; list[byteLoop] && (bitLoop < 8);
01572             bitLoop++, list[byteLoop] >>= 1, clientId++) {
01573                 // see if an ack should be sent to this client 
01574                 if (list[byteLoop] & 1) {
01575                     // send the ack message
01576                     SendAck(&(ackbuff[clientId * MSG_ACK_SIZE]));
01577                 }
01578             }
01579         }
01580     }
01581     // if a client and there are messages to acknowledge . . .
01582     else if (ack[2]) {
01583         // acknowledge the server
01584         SendAck(ack);
01585     }
01586     // check for a real error, not a blocking condition
01587     if ((error > 0) && (error != EWOULDBLOCK)) {
01588         #ifndef NDEBUG
01589         // output an error message
01590         #ifdef USE_GETTEXT
01591         printf("Error while trying to recive data:\n\t%ls\n",
01592         GetNetErrorString(error));
01593         #else
01594         printf("Error while trying to recive data:\n\t%s\n",
01595         GetNetErrorString(error));
01596         #endif
01597         #endif
01598         return FALSE;
01599     }
01600     return TRUE;
01601 }
01602 
01603 Bool MessageInit() {
01604     int loop;
01605     // setup the vectors for their intended use
01606     available.destructOp = inflightTime.destructOp = NULL;
01607     buffers.destructOp = GenericPointerFree; // not BufferVecDestr()!
01608     inflightTime.lessOp = (LessThanOp)TimeCompare;
01609     available.itemSize = inflightTime.itemSize =
01610     buffers.itemSize = sizeof(void *);
01611     available.minSize = inflightTime.minSize = MIN_POINTERS;
01612     buffers.minSize = MIN_POINTERS >> 1;
01613     // initalize a vector and check for failure
01614     if (!VectorInit(&inflightTime, MIN_POINTERS))
01615         return FALSE;
01616     // do it again with a different vector
01617     if (!VectorInit(&available, MIN_POINTERS))
01618         return FALSE;
01619     // one more time
01620     if (!VectorInit(&buffers, MIN_POINTERS >> 1))
01621         return FALSE;
01622     // allocate memory for the initial set of buffers
01623     for (loop = INIT_BUFFERS; loop > 0; loop--) {
01624         char **buff = VectorAdd(&buffers);
01625         if ((*buff = malloc(sizeof(NetBuffer))) == NULL) {
01626             return FALSE;
01627         }
01628     }
01629     // allocate memory for the initial set of messages
01630     for (loop = INIT_MESSAGES; loop > 0; loop--) {
01631         MsgDescr **msg = VectorAdd(&available);
01632         if ((*msg = malloc(sizeof(MsgDescr))) == NULL) {
01633             return FALSE;
01634         }
01635         // clear the flags
01636         (*msg)->flags = 0;
01637         // clear the buffer pointer
01638         (*msg)->buffer = NULL;
01639     }
01640     // allocate an acknowledge buffer for the client
01641     if ((ackbuff = calloc(1, MSG_ACK_SIZE)) == NULL) {
01642         return FALSE;
01643     }
01644     return TRUE;
01645 }
01646 
01647 void MessageUninit() {
01648     // alter the message vectors so that they will free all the message data
01649     available.destructOp = inflightTime.destructOp =
01650     (DestructorOp)MsgDescrDestructor;
01651     // remove the messages
01652     if (inflightId != AA_ROOT_NODE) {
01653         // destroy the tree
01654         AATreeDestroy(inflightId);
01655         // keep a valid tree
01656         inflightId = AA_ROOT_NODE;
01657     }
01658     VectorDestroy(&available);
01659     VectorDestroy(&inflightTime);
01660     // remove the buffers
01661     VectorDestroy(&buffers);
01662     free(ackbuff);
01663 }
01664 
01672 Bool MessageCliToSrv() {
01673     Uint8 *buff;
01674     // change the size of the acknowledge buffer to handle multiple clients
01675     if ((buff = realloc(ackbuff, MSG_ACK_SIZE * MAX_PLAYERS)) == NULL) {
01676         return FALSE;
01677     }
01678     // clear the acknowledge buffer
01679     memset(ackbuff = buff, 0, MSG_ACK_SIZE * MAX_PLAYERS);
01680     //  remove all messages in the system
01681     CancelAllMessages();
01682     return TRUE;
01683 }
01684 
01691 Bool MessageSrvToCli() {
01692     Uint8 *buff;
01693     // change the size of the acknowledge buffer to be just large enough for
01694     // one other system (the server)
01695     if ((buff = realloc(ackbuff, MSG_ACK_SIZE)) == NULL) {
01696         return FALSE;
01697     }
01698     // clear the acknowledge buffer
01699     memset(ackbuff = buff, 0, MSG_ACK_SIZE);
01700     //  remove all messages in the system
01701     CancelAllMessages();
01702     // no game option messages have been received yet
01703     gameOpts.totalMsgs = -1;
01704     gameOpts.rcvdMsgs = 0;
01705     return TRUE;
01706 }
01707 
01708 void ProcessNetworkMessages() {
01709     // if the network state uses the messaging system . . .
01710     if ((networkState >= NETSTATE_RCVCFG) &&
01711     (networkState <= NETSTATE_SERVER)) {
01712         // process incomming messages
01713         ReceiveMessages();
01714         // run through the game loop
01715         UpdatePlayers(frameTime);
01716         if (networkState == NETSTATE_SERVER) {
01717             // handle configuration messages
01718             ServiceGameConfig();
01719         }
01720         // process outgoing messages
01721         ServiceMessages();
01722     }
01723 }
01724 

Generated on Mon May 28 04:41:39 2007 for Retro Tank Super Attack by  doxygen 1.5.2