/* $Id: pkgcache.c,v 1.7 2003/11/08 06:27:59 stpohle Exp $ * Resendcache work, We need this to resend lost packets over the network. * we will keep every packet with the PKGF_ackreq flag as long as we haven't * got any answer from the destination host. And resend the packet after a givin * time. The maximum time for a resend is 10 times if we haven't got any reply * by then we delete the packet from the cache. By doing this the game will not * anymore sync. with all clients. */ #include "bomberclone.h" #include "network.h" #include "packets.h" /* set pointers at the giving pos */ void rscache_setpointer (int pos) { resend_cache.entry = (struct _rscache_entry *) (((char *) resend_cache.data) + pos); }; /* add a packet to the cache and sets the timestamp */ int rscache_add (_net_addr * addr, struct pkg *packet) { int newlen; if (resend_cache.fill + sizeof (struct _rscache_entry) > PKG_RESENDCACHE_SIZE) return -1; rscache_setpointer (resend_cache.fill); resend_cache.entry->retry = 0; resend_cache.entry->timestamp = timestamp; memcpy (&resend_cache.entry->addr, addr, sizeof (_net_addr)); memcpy (&resend_cache.entry->packet, packet, NTOH16 (packet->h.len)); newlen = resend_cache.fill + rscache_getcurlen (); resend_cache.fill = newlen; return 0; }; /* deletes the packet at current pointer in the cache */ void rscache_del () { int len, size; char *pos1; /* check if we are able to delete */ if ((char *) resend_cache.data > (char *) resend_cache.entry || (char *) resend_cache.entry > (char *) resend_cache.data + resend_cache.fill || resend_cache.fill == -1 || resend_cache.data == NULL) { d_printf ("rscache_del: something wrong with the cache\n"); exit (1); return; } /* newlen = size of the cacheentry we are going to delete */ len = rscache_getcurlen (); if (resend_cache.fill <= len) /* something went wrong, fill is smaler as the cacheentry, delete the cache */ resend_cache.fill = 0; else { pos1 = (char *) resend_cache.entry + len; size = PKG_RESENDCACHE_SIZE - (pos1 - resend_cache.data); if (resend_cache.fill < PKG_RESENDCACHE_SIZE) { memmove (resend_cache.entry, pos1, size); resend_cache.fill = resend_cache.fill - len; } } }; /* get the position in the cache where our needed packet is */ int rscache_getpos (_net_addr * addr, unsigned char typ, short int id) { int len, pos, done = 0; for (pos = 0; (pos < resend_cache.fill && done == 0);) { rscache_setpointer (pos); /* get size of the cacheentry */ len = rscache_getcurlen (); if (strcmp (addr->host, resend_cache.entry->addr.host) == 0 && strcmp (addr->port, resend_cache.entry->addr.port) == 0 && typ == resend_cache.entry->packet.h.typ && id == NTOH16 (resend_cache.entry->packet.h.id)) done = 1; /* we have found the old packet */ else pos = pos + len; } if (done == 0) /* we have found nothing */ return -1; return pos; }; /* get the len of the current entry */ int rscache_getcurlen () { int len; len = sizeof (struct _rscache_entry) - sizeof (struct pkg) + NTOH16 (resend_cache.entry->packet.h.len); return len; }; /* the loop for the cache.. to see what will have to be resend */ void rscache_loop () { int len, pos, timeout; if (bman.state==GS_running) timeout = RESENDCACHE_TIMEOUT; else timeout=RESENDCACHE_TIMEOUT_MENU; for (pos = 0; pos < resend_cache.fill && pos < PKG_RESENDCACHE_SIZE && pos >= 0;) { rscache_setpointer (pos); len = rscache_getcurlen (); if (timestamp - resend_cache.entry->timestamp >= timeout && resend_cache.entry->retry < RESENDCACHE_RETRY) { /* send it again */ d_printf ("Data Send Timeout (%s:%s) Resend now Package Fill %d, Pos %d\n", resend_cache.entry->addr.host, resend_cache.entry->addr.port, resend_cache.fill,pos); udp_send (bman.sock, (char *) &resend_cache.entry->packet, NTOH16 (resend_cache.entry->packet.h.len), &resend_cache.entry->addr.sAddr, bman.net_ai_family); resend_cache.entry->timestamp = timestamp; resend_cache.entry->retry++; if (resend_cache.entry->addr.pl_nr >= 0 && resend_cache.entry->addr.pl_nr < MAX_PLAYERS) players[resend_cache.entry->addr.pl_nr].net.pkgopt.to_2sec++; } if (timestamp - resend_cache.entry->timestamp >= timeout && resend_cache.entry->retry >= RESENDCACHE_RETRY) { d_printf ("Data Send Timeout (%s:%s) Delete now Package Fill %d, Pos %d\n", resend_cache.entry->addr.host, resend_cache.entry->addr.port, resend_cache.fill, pos); if (resend_cache.entry->addr.pl_nr >= 0 && resend_cache.entry->addr.pl_nr < MAX_PLAYERS) players[resend_cache.entry->addr.pl_nr].net.pkgopt.to_2sec++; rscache_del (); } else pos = pos + len; } };