/* $Id: pkgcache.c,v 1.10 2006/08/13 21:26:50 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" struct _resend_cache rscache; /* reset the counter for the resendcache */ void rscache_init () { rscache.count = 0; }; /* add a new packet to the list struct _rscache_entry { Uint32 timestamp; // pointer to the timestamp signed char retry; // retry's how many times we tryed this _net_addr addr; // the address char packet[MAX_UDPDATA]; // the packet } __attribute__((packed)); */ void rscache_add (_net_addr *addr, struct pkg *packet) { int len; d_printf ("rscache_add: addr %p, pkg %p\n", addr, packet); /* check if there is still some free space left. */ if (rscache.count >= PKG_RESENDCACHE_SIZE) { d_printf ("rscache_add no free rscache entry left.\n"); return; } /* copy all the data we need. */ rscache.entry[rscache.count].timestamp = timestamp; rscache.entry[rscache.count].retry = 0; memcpy (&rscache.entry[rscache.count].addr, addr, sizeof (_net_addr)); len = NTOH16 (packet->h.len); if (MAX_UDPDATA < len) len = MAX_UDPDATA; memcpy (&rscache.entry[rscache.count].packet, packet, MAX_UDPDATA); rscache.count ++; }; /* delete the packet from the cache */ void rscache_del (_net_addr *addr, unsigned char typ, short unsigned int id) { int i; d_printf ("rscache_del: addr %p\n", addr); for (i = 0; (i < rscache.count) && (i < PKG_RESENDCACHE_SIZE); i++) { if (rscache.entry[i].addr.pl_nr == addr->pl_nr && NTOH16(rscache.entry[i].packet.h.id) == id && ((struct pkg)rscache.entry[i].packet).h.typ == typ) { // found element int a; for (a = i; a < rscache.count - 1; a++) rscache.entry[i] = rscache.entry[i+1]; rscache.count--; break; } } }; /* test for old packets where we haven't got a ackreq packet for. * If the timeout is up resend the packet again until RESENDCACHE_RETRY * has reached then delete the packet. */ void rscache_loop () { int i; int timeout; if (bman.state==GS_running) timeout = RESENDCACHE_TIMEOUT; else timeout=RESENDCACHE_TIMEOUT_MENU; for (i = 0; (i < rscache.count) && (i < PKG_RESENDCACHE_SIZE); i++) { if (timestamp - rscache.entry[i].timestamp >= timeout && rscache.entry[i].retry < RESENDCACHE_RETRY) { /* send it again */ d_printf ("Data Send Timeout (%s:%s) Resend now Package Fill %d, Pos %d\n", rscache.entry[i].addr.host, rscache.entry[i].addr.port, rscache.count,i); udp_send (bman.sock, (char *) &rscache.entry[i].packet, NTOH16 (rscache.entry[i].packet.h.len), &rscache.entry[i].addr.sAddr, bman.net_ai_family); rscache.entry[i].timestamp = timestamp; rscache.entry[i].retry++; if (rscache.entry[i].addr.pl_nr >= 0 && rscache.entry[i].addr.pl_nr < MAX_PLAYERS) players[rscache.entry[i].addr.pl_nr].net.pkgopt.to_2sec++; } if (timestamp - rscache.entry[i].timestamp >= timeout && rscache.entry[i].retry >= RESENDCACHE_RETRY) { d_printf ("Data Send Timeout (%s:%s) Delete now Package Fill %d, Pos %d\n", rscache.entry[i].addr.host, rscache.entry[i].addr.port, rscache.count, i); if (rscache.entry[i].addr.pl_nr >= 0 && rscache.entry[i].addr.pl_nr < MAX_PLAYERS) players[rscache.entry[i].addr.pl_nr].net.pkgopt.to_2sec++; rscache_del (&rscache.entry[i].addr, rscache.entry[i].packet.h.typ, NTOH16(rscache.entry[i].packet.h.id)); } } };