Mercurial > ~darius > hgwebdir.cgi > paradise_server
diff src/fatudp.c @ 4:aa38447a4b21
First entry of Paradise Server 2.9 patch 10 Beta
author | darius |
---|---|
date | Sat, 06 Dec 1997 04:37:03 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fatudp.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,419 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include <stdio.h> +#include <sys/types.h> +#include <netinet/in.h> + +#include "defs.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" + +/* #define FATDIAG /* define to get LOTS of fat UDP debugging messages */ + + +/* this stuff is used for Fat UDP */ +typedef void *PTR; /* adjust this if you lack (void *) */ +typedef struct fat_node_t +{ + PTR packet; + int pkt_size; + struct fat_node_t *prev; + struct fat_node_t *next; +} FAT_NODE; + +FAT_NODE fat_kills[MAXPLAYER]; +FAT_NODE fat_torp_info[MAXPLAYER * MAXTORP]; +FAT_NODE fat_thingy_info[TOTALTHINGIES]; +FAT_NODE fat_phaser[MAXPLAYER]; +FAT_NODE fat_plasma_info[MAXPLAYER * MAXPLASMA]; +FAT_NODE fat_you; +#if 0 +FAT_NODE fat_status; +FAT_NODE fat_planet[MAXPLANETS]; +#else +FAT_NODE fat_status2; +FAT_NODE fat_planet2[MAXPLANETS]; +#endif +FAT_NODE fat_flags[MAXPLAYER]; +FAT_NODE fat_hostile[MAXPLAYER]; + +/* define the lists */ +#define MAX_FAT_LIST 5 /* tweakable; should be > 1 */ +typedef struct +{ + FAT_NODE *head; + FAT_NODE *tail; +} FAT_LIST; +FAT_LIST fatlist[MAX_FAT_LIST], tmplist[MAX_FAT_LIST]; +/* tweakable parameters; compare with UDPBUFSIZE */ +/* NOTE: FAT_THRESH + MAX_FAT_DATA must be < UDPBUFSIZE */ +/* MAX_FAT_DATA must be larger than biggest semi-critical packet */ +#define MAX_FAT_DATA 100 /* add at most this many bytes */ +#define MAX_NONFAT 10 /* if we have this much left, stop */ + + +void +reset_fat_list() +{ + int i; + for (i = 0; i < MAX_FAT_LIST; i++) + fatlist[i].head = fatlist[i].tail = (FAT_NODE *) NULL; +} +/* + * + * --------------------------------------------------------------------------- + * Fat City + * --------------------------------------------------------------------------- + * */ + +/* + * Remove a FAT_NODE from a queue. If it's at the head or the tail of a + * list, then we need to figure out which list it's in and update the head or + * tail pointer. It's easier to go searching than to maintain a queue number + * in every FAT_NODE. + * + * This routine looks too complex... there must be a simpler way to do this. + */ +void +dequeue(fatp) + FAT_NODE *fatp; +{ + int i; + +#ifdef V_FATDIAG + for (i = 0; i < MAX_FAT_LIST; i++) + { + printf("fatlist[i].head = 0x%.8lx tail = 0x%.8lx\n", + fatlist[i].head, fatlist[i].tail); + if ((fatlist[i].head == NULL && fatlist[i].tail != NULL) || + (fatlist[i].head != NULL && fatlist[i].tail == NULL)) + { + printf("before!\n"); + kill(getpid(), 15); + } + } +#endif + + + if (fatp->next == NULL) + { + /* it's at the head or not in a queue */ + for (i = 0; i < MAX_FAT_LIST; i++) + { + if (fatlist[i].head == fatp) + { + fatlist[i].head = fatp->prev; /* move head back */ + if (fatlist[i].head != NULL) + (fatlist[i].head)->next = NULL; /* amputate */ + break; + } + } + } + else + { + /* it's not at the head */ + if (fatp->prev != NULL) + fatp->prev->next = fatp->next; + } + + if (fatp->prev == NULL) + { + /* it's at the tail or not in a queue */ + for (i = 0; i < MAX_FAT_LIST; i++) + { + if (fatlist[i].tail == fatp) + { + fatlist[i].tail = fatp->next; /* move head fwd */ + if (fatlist[i].tail != NULL) + (fatlist[i].tail)->prev = NULL; /* amputate */ + break; + } + } + } + else + { + /* it's not at the tail */ + if (fatp->next != NULL) + fatp->next->prev = fatp->prev; + } + +#ifdef FATDIAG + printf("Removed 0x%.8lx...", fatp); /* FATDIAG */ + for (i = 0; i < MAX_FAT_LIST; i++) + { + if ((fatlist[i].head == NULL && fatlist[i].tail != NULL) || + (fatlist[i].head != NULL && fatlist[i].tail == NULL)) + { + printf("after: %d %.8lx %.8lx\n", i, fatlist[i].head, fatlist[i].tail); + kill(getpid(), 15); + } + } +#endif + fatp->prev = NULL; + fatp->next = NULL; +} + +/* + * Add a FAT_NODE to the tail of a temporary queue. The merge() routine + * merges the temporary queues with the fatlists once the transmission is + * sent. + */ +void +enqueue(fatp, list) + FAT_NODE *fatp; + int list; +{ +#ifdef FATDIAG + printf("added to tmplist %d\n", list); /* FATDIAG */ +#endif + + if (tmplist[list].tail == NULL) + { + /* list was empty */ + tmplist[list].tail = tmplist[list].head = fatp; + } + else + { + /* list wasn't empty */ + fatp->next = tmplist[list].tail; + fatp->next->prev = fatp; + tmplist[list].tail = fatp; + } +} + +/* + * This updates the "fat" tables; it's called from sendClientData(). + */ +void +updateFat(packet) +/* Pick a random type for the packet */ + struct player_spacket *packet; +{ + FAT_NODE *fatp; + struct kills_spacket *kp; + struct torp_info_spacket *tip; + struct thingy_info_spacket *thip; + struct phaser_spacket *php; + struct plasma_info_spacket *pip; + /* struct you_spacket *yp; */ + /* struct status_spacket2 *sp2; */ + /* struct planet_spacket *plp; */ + struct planet_spacket2 *plp2; + struct flags_spacket *fp; + struct hostile_spacket *hp; + int idx; + + /* step 1 : find the FAT_NODE for this packet */ + switch (packet->type) + { + case SP_KILLS: + kp = (struct kills_spacket *) packet; + idx = (int) kp->pnum; + fatp = &fat_kills[idx]; + break; + case SP_TORP_INFO: + tip = (struct torp_info_spacket *) packet; + idx = (int) ntohs(tip->tnum); + fatp = &fat_torp_info[idx]; + break; + case SP_THINGY_INFO: + thip = (struct thingy_info_spacket *) packet; + idx = (int) ntohs(thip->tnum); + fatp = &fat_thingy_info[idx]; + break; + case SP_PHASER: + php = (struct phaser_spacket *) packet; + idx = (int) php->pnum; + fatp = &fat_phaser[idx]; + break; + case SP_PLASMA_INFO: + pip = (struct plasma_info_spacket *) packet; + idx = (int) ntohs(pip->pnum); + fatp = &fat_plasma_info[idx]; + break; + case SP_YOU: + /* yp = (struct you_spacket *) packet; */ + fatp = &fat_you; + break; +#if 0 + case SP_STATUS: + /* sp = (struct status_spacket *) packet; */ + fatp = &fat_status; + break; + case SP_PLANET: + plp = (struct planet_spacket *) packet; + idx = plp->pnum; + fatp = &fat_planet[idx]; + break; +#else + case SP_STATUS2: + /* sp = (struct status_spacket *) packet; */ + fatp = &fat_status2; + break; + case SP_PLANET2: + plp2 = (struct planet_spacket2 *) packet; + idx = plp2->pnum; + fatp = &fat_planet2[idx]; + break; +#endif + case SP_FLAGS: + fp = (struct flags_spacket *) packet; + idx = (int) fp->pnum; + fatp = &fat_flags[idx]; + break; + case SP_HOSTILE: + hp = (struct hostile_spacket *) packet; + idx = (int) hp->pnum; + fatp = &fat_hostile[idx]; + break; + default: + fprintf(stderr, "Fat error: bad semi-critical type (%d) in updateFat\n", (CARD8) packet->type); + return; + } + + if (fatp->packet != (PTR) packet) + { + fprintf(stderr, "Fat error: fatp->packet=0x%.8lx, packet=0x%.8lx\n", + (unsigned long) fatp->packet, (unsigned long) packet); + return; + } + /* step 2 : move this dude to temporary list 0 */ + dequeue(fatp); + enqueue(fatp, 0); +} + +/* + * This fattens up the transmission, adding up to MAX_FAT_DATA bytes. The + * packets which get added will be moved to a higher queue, giving them less + * priority for next time. Note that they are added to a parallel temporary + * list (otherwise they'd could be sent several times in the same + * transmission as the algorithm steps through the queues), and merged later + * on. + * + * Packets are assigned from head to tail, on a first-fit basis. If a + * semi-critical packet is larger than MAX_FAT_DATA, this routine will never + * send it, but it will skip around it. + * + * This routine is called from flushSockBuf, before the transmission is sent. + * + * A possible improvement is to have certain packets "expire", never to be seen + * again. This way we don't keep resending torp packets for players who are + * long dead. This raises the possibility that the dead player's torps will + * never go away though. + */ +int +fatten() +{ + int bytesleft; + FAT_NODE *fatp, *nextfatp; + int list; + +#ifdef FATDIAG + printf("--- fattening\n"); +#endif + bytesleft = MAX_FAT_DATA; + for (list = 0; list < MAX_FAT_LIST; list++) + { + fatp = fatlist[list].head; + while (fatp != NULL) + { + nextfatp = fatp->prev; /* move toward tail */ +#ifdef FATDIAG + if (nextfatp == fatp) + { + printf("Hey! nextfatp == fatp!\n"); + kill(getpid(), 15); + } +#endif + if (fatp->pkt_size < bytesleft) + { + /* got one! */ + sendUDPbuffered(0, fatp->packet, fatp->pkt_size); + bytesleft -= fatp->pkt_size; + + packets_sent++; /* counts as a udp packet sent */ + + /* move the packet to a higher queue (if there is one) */ + dequeue(fatp); + if (list + 1 == MAX_FAT_LIST) + { + /* enqueue(fatp, list); *//* keep packets on high queue? */ + } + else + { + enqueue(fatp, list + 1); + } + + /* done yet? */ + if (bytesleft < MAX_NONFAT) + goto done; /* don't waste time searching anymore */ + } + fatp = nextfatp; + } + } + +done: + /* at this point, we either filled with fat or ran out of queued packets */ +#ifdef FATDIAG + printf("--- done\n"); +#endif + V_UDPDIAG(("- Added %d grams of fat\n", MAX_FAT_DATA - bytesleft)); + return (0); /* some compilers need something after a goto */ +} + + +/* + * This gets called from flushSockBuf after the transmission is sent. It + * appends all the packets sitting in temporary queues to the corresponding + * fat queues, where they will be eligible for fattening next transmission. + */ +void +fatMerge() +{ + int i; + + for (i = 0; i < MAX_FAT_LIST; i++) + { + if (tmplist[i].head == NULL) + continue; /* temp list is empty, nothing to do */ + + if (fatlist[i].head == NULL) + { + /* fatlist is empty; just copy pointers */ + fatlist[i].head = tmplist[i].head; + fatlist[i].tail = tmplist[i].tail; + + } + else + { + /* stuff in both */ + (tmplist[i].head)->next = fatlist[i].tail; /* fwd pointer */ + (fatlist[i].tail)->prev = tmplist[i].head; /* back pointer */ + fatlist[i].tail = tmplist[i].tail; /* move tail back */ + tmplist[i].head = tmplist[i].tail = NULL; /* clear the tmp list */ + } + tmplist[i].head = tmplist[i].tail = NULL; +#ifdef FATDIAG + printf("merged list %d: %.8lx %.8lx\n", i, fatlist[i].head, + fatlist[i].tail); +#endif + } +}