Mercurial > ~darius > hgwebdir.cgi > paradise_server
comparison 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 |
comparison
equal
deleted
inserted
replaced
3:cafa94d86546 | 4:aa38447a4b21 |
---|---|
1 /*-------------------------------------------------------------------------- | |
2 NETREK II -- Paradise | |
3 | |
4 Permission to use, copy, modify, and distribute this software and its | |
5 documentation, or any derivative works thereof, for any NON-COMMERCIAL | |
6 purpose and without fee is hereby granted, provided that this copyright | |
7 notice appear in all copies. No representations are made about the | |
8 suitability of this software for any purpose. This software is provided | |
9 "as is" without express or implied warranty. | |
10 | |
11 Xtrek Copyright 1986 Chris Guthrie | |
12 Netrek (Xtrek II) Copyright 1989 Kevin P. Smith | |
13 Scott Silvey | |
14 Paradise II (Netrek II) Copyright 1993 Larry Denys | |
15 Kurt Olsen | |
16 Brandon Gillespie | |
17 --------------------------------------------------------------------------*/ | |
18 | |
19 #include "config.h" | |
20 #include <stdio.h> | |
21 #include <sys/types.h> | |
22 #include <netinet/in.h> | |
23 | |
24 #include "defs.h" | |
25 #include "data.h" | |
26 #include "packets.h" | |
27 #include "shmem.h" | |
28 | |
29 /* #define FATDIAG /* define to get LOTS of fat UDP debugging messages */ | |
30 | |
31 | |
32 /* this stuff is used for Fat UDP */ | |
33 typedef void *PTR; /* adjust this if you lack (void *) */ | |
34 typedef struct fat_node_t | |
35 { | |
36 PTR packet; | |
37 int pkt_size; | |
38 struct fat_node_t *prev; | |
39 struct fat_node_t *next; | |
40 } FAT_NODE; | |
41 | |
42 FAT_NODE fat_kills[MAXPLAYER]; | |
43 FAT_NODE fat_torp_info[MAXPLAYER * MAXTORP]; | |
44 FAT_NODE fat_thingy_info[TOTALTHINGIES]; | |
45 FAT_NODE fat_phaser[MAXPLAYER]; | |
46 FAT_NODE fat_plasma_info[MAXPLAYER * MAXPLASMA]; | |
47 FAT_NODE fat_you; | |
48 #if 0 | |
49 FAT_NODE fat_status; | |
50 FAT_NODE fat_planet[MAXPLANETS]; | |
51 #else | |
52 FAT_NODE fat_status2; | |
53 FAT_NODE fat_planet2[MAXPLANETS]; | |
54 #endif | |
55 FAT_NODE fat_flags[MAXPLAYER]; | |
56 FAT_NODE fat_hostile[MAXPLAYER]; | |
57 | |
58 /* define the lists */ | |
59 #define MAX_FAT_LIST 5 /* tweakable; should be > 1 */ | |
60 typedef struct | |
61 { | |
62 FAT_NODE *head; | |
63 FAT_NODE *tail; | |
64 } FAT_LIST; | |
65 FAT_LIST fatlist[MAX_FAT_LIST], tmplist[MAX_FAT_LIST]; | |
66 /* tweakable parameters; compare with UDPBUFSIZE */ | |
67 /* NOTE: FAT_THRESH + MAX_FAT_DATA must be < UDPBUFSIZE */ | |
68 /* MAX_FAT_DATA must be larger than biggest semi-critical packet */ | |
69 #define MAX_FAT_DATA 100 /* add at most this many bytes */ | |
70 #define MAX_NONFAT 10 /* if we have this much left, stop */ | |
71 | |
72 | |
73 void | |
74 reset_fat_list() | |
75 { | |
76 int i; | |
77 for (i = 0; i < MAX_FAT_LIST; i++) | |
78 fatlist[i].head = fatlist[i].tail = (FAT_NODE *) NULL; | |
79 } | |
80 /* | |
81 * | |
82 * --------------------------------------------------------------------------- | |
83 * Fat City | |
84 * --------------------------------------------------------------------------- | |
85 * */ | |
86 | |
87 /* | |
88 * Remove a FAT_NODE from a queue. If it's at the head or the tail of a | |
89 * list, then we need to figure out which list it's in and update the head or | |
90 * tail pointer. It's easier to go searching than to maintain a queue number | |
91 * in every FAT_NODE. | |
92 * | |
93 * This routine looks too complex... there must be a simpler way to do this. | |
94 */ | |
95 void | |
96 dequeue(fatp) | |
97 FAT_NODE *fatp; | |
98 { | |
99 int i; | |
100 | |
101 #ifdef V_FATDIAG | |
102 for (i = 0; i < MAX_FAT_LIST; i++) | |
103 { | |
104 printf("fatlist[i].head = 0x%.8lx tail = 0x%.8lx\n", | |
105 fatlist[i].head, fatlist[i].tail); | |
106 if ((fatlist[i].head == NULL && fatlist[i].tail != NULL) || | |
107 (fatlist[i].head != NULL && fatlist[i].tail == NULL)) | |
108 { | |
109 printf("before!\n"); | |
110 kill(getpid(), 15); | |
111 } | |
112 } | |
113 #endif | |
114 | |
115 | |
116 if (fatp->next == NULL) | |
117 { | |
118 /* it's at the head or not in a queue */ | |
119 for (i = 0; i < MAX_FAT_LIST; i++) | |
120 { | |
121 if (fatlist[i].head == fatp) | |
122 { | |
123 fatlist[i].head = fatp->prev; /* move head back */ | |
124 if (fatlist[i].head != NULL) | |
125 (fatlist[i].head)->next = NULL; /* amputate */ | |
126 break; | |
127 } | |
128 } | |
129 } | |
130 else | |
131 { | |
132 /* it's not at the head */ | |
133 if (fatp->prev != NULL) | |
134 fatp->prev->next = fatp->next; | |
135 } | |
136 | |
137 if (fatp->prev == NULL) | |
138 { | |
139 /* it's at the tail or not in a queue */ | |
140 for (i = 0; i < MAX_FAT_LIST; i++) | |
141 { | |
142 if (fatlist[i].tail == fatp) | |
143 { | |
144 fatlist[i].tail = fatp->next; /* move head fwd */ | |
145 if (fatlist[i].tail != NULL) | |
146 (fatlist[i].tail)->prev = NULL; /* amputate */ | |
147 break; | |
148 } | |
149 } | |
150 } | |
151 else | |
152 { | |
153 /* it's not at the tail */ | |
154 if (fatp->next != NULL) | |
155 fatp->next->prev = fatp->prev; | |
156 } | |
157 | |
158 #ifdef FATDIAG | |
159 printf("Removed 0x%.8lx...", fatp); /* FATDIAG */ | |
160 for (i = 0; i < MAX_FAT_LIST; i++) | |
161 { | |
162 if ((fatlist[i].head == NULL && fatlist[i].tail != NULL) || | |
163 (fatlist[i].head != NULL && fatlist[i].tail == NULL)) | |
164 { | |
165 printf("after: %d %.8lx %.8lx\n", i, fatlist[i].head, fatlist[i].tail); | |
166 kill(getpid(), 15); | |
167 } | |
168 } | |
169 #endif | |
170 fatp->prev = NULL; | |
171 fatp->next = NULL; | |
172 } | |
173 | |
174 /* | |
175 * Add a FAT_NODE to the tail of a temporary queue. The merge() routine | |
176 * merges the temporary queues with the fatlists once the transmission is | |
177 * sent. | |
178 */ | |
179 void | |
180 enqueue(fatp, list) | |
181 FAT_NODE *fatp; | |
182 int list; | |
183 { | |
184 #ifdef FATDIAG | |
185 printf("added to tmplist %d\n", list); /* FATDIAG */ | |
186 #endif | |
187 | |
188 if (tmplist[list].tail == NULL) | |
189 { | |
190 /* list was empty */ | |
191 tmplist[list].tail = tmplist[list].head = fatp; | |
192 } | |
193 else | |
194 { | |
195 /* list wasn't empty */ | |
196 fatp->next = tmplist[list].tail; | |
197 fatp->next->prev = fatp; | |
198 tmplist[list].tail = fatp; | |
199 } | |
200 } | |
201 | |
202 /* | |
203 * This updates the "fat" tables; it's called from sendClientData(). | |
204 */ | |
205 void | |
206 updateFat(packet) | |
207 /* Pick a random type for the packet */ | |
208 struct player_spacket *packet; | |
209 { | |
210 FAT_NODE *fatp; | |
211 struct kills_spacket *kp; | |
212 struct torp_info_spacket *tip; | |
213 struct thingy_info_spacket *thip; | |
214 struct phaser_spacket *php; | |
215 struct plasma_info_spacket *pip; | |
216 /* struct you_spacket *yp; */ | |
217 /* struct status_spacket2 *sp2; */ | |
218 /* struct planet_spacket *plp; */ | |
219 struct planet_spacket2 *plp2; | |
220 struct flags_spacket *fp; | |
221 struct hostile_spacket *hp; | |
222 int idx; | |
223 | |
224 /* step 1 : find the FAT_NODE for this packet */ | |
225 switch (packet->type) | |
226 { | |
227 case SP_KILLS: | |
228 kp = (struct kills_spacket *) packet; | |
229 idx = (int) kp->pnum; | |
230 fatp = &fat_kills[idx]; | |
231 break; | |
232 case SP_TORP_INFO: | |
233 tip = (struct torp_info_spacket *) packet; | |
234 idx = (int) ntohs(tip->tnum); | |
235 fatp = &fat_torp_info[idx]; | |
236 break; | |
237 case SP_THINGY_INFO: | |
238 thip = (struct thingy_info_spacket *) packet; | |
239 idx = (int) ntohs(thip->tnum); | |
240 fatp = &fat_thingy_info[idx]; | |
241 break; | |
242 case SP_PHASER: | |
243 php = (struct phaser_spacket *) packet; | |
244 idx = (int) php->pnum; | |
245 fatp = &fat_phaser[idx]; | |
246 break; | |
247 case SP_PLASMA_INFO: | |
248 pip = (struct plasma_info_spacket *) packet; | |
249 idx = (int) ntohs(pip->pnum); | |
250 fatp = &fat_plasma_info[idx]; | |
251 break; | |
252 case SP_YOU: | |
253 /* yp = (struct you_spacket *) packet; */ | |
254 fatp = &fat_you; | |
255 break; | |
256 #if 0 | |
257 case SP_STATUS: | |
258 /* sp = (struct status_spacket *) packet; */ | |
259 fatp = &fat_status; | |
260 break; | |
261 case SP_PLANET: | |
262 plp = (struct planet_spacket *) packet; | |
263 idx = plp->pnum; | |
264 fatp = &fat_planet[idx]; | |
265 break; | |
266 #else | |
267 case SP_STATUS2: | |
268 /* sp = (struct status_spacket *) packet; */ | |
269 fatp = &fat_status2; | |
270 break; | |
271 case SP_PLANET2: | |
272 plp2 = (struct planet_spacket2 *) packet; | |
273 idx = plp2->pnum; | |
274 fatp = &fat_planet2[idx]; | |
275 break; | |
276 #endif | |
277 case SP_FLAGS: | |
278 fp = (struct flags_spacket *) packet; | |
279 idx = (int) fp->pnum; | |
280 fatp = &fat_flags[idx]; | |
281 break; | |
282 case SP_HOSTILE: | |
283 hp = (struct hostile_spacket *) packet; | |
284 idx = (int) hp->pnum; | |
285 fatp = &fat_hostile[idx]; | |
286 break; | |
287 default: | |
288 fprintf(stderr, "Fat error: bad semi-critical type (%d) in updateFat\n", (CARD8) packet->type); | |
289 return; | |
290 } | |
291 | |
292 if (fatp->packet != (PTR) packet) | |
293 { | |
294 fprintf(stderr, "Fat error: fatp->packet=0x%.8lx, packet=0x%.8lx\n", | |
295 (unsigned long) fatp->packet, (unsigned long) packet); | |
296 return; | |
297 } | |
298 /* step 2 : move this dude to temporary list 0 */ | |
299 dequeue(fatp); | |
300 enqueue(fatp, 0); | |
301 } | |
302 | |
303 /* | |
304 * This fattens up the transmission, adding up to MAX_FAT_DATA bytes. The | |
305 * packets which get added will be moved to a higher queue, giving them less | |
306 * priority for next time. Note that they are added to a parallel temporary | |
307 * list (otherwise they'd could be sent several times in the same | |
308 * transmission as the algorithm steps through the queues), and merged later | |
309 * on. | |
310 * | |
311 * Packets are assigned from head to tail, on a first-fit basis. If a | |
312 * semi-critical packet is larger than MAX_FAT_DATA, this routine will never | |
313 * send it, but it will skip around it. | |
314 * | |
315 * This routine is called from flushSockBuf, before the transmission is sent. | |
316 * | |
317 * A possible improvement is to have certain packets "expire", never to be seen | |
318 * again. This way we don't keep resending torp packets for players who are | |
319 * long dead. This raises the possibility that the dead player's torps will | |
320 * never go away though. | |
321 */ | |
322 int | |
323 fatten() | |
324 { | |
325 int bytesleft; | |
326 FAT_NODE *fatp, *nextfatp; | |
327 int list; | |
328 | |
329 #ifdef FATDIAG | |
330 printf("--- fattening\n"); | |
331 #endif | |
332 bytesleft = MAX_FAT_DATA; | |
333 for (list = 0; list < MAX_FAT_LIST; list++) | |
334 { | |
335 fatp = fatlist[list].head; | |
336 while (fatp != NULL) | |
337 { | |
338 nextfatp = fatp->prev; /* move toward tail */ | |
339 #ifdef FATDIAG | |
340 if (nextfatp == fatp) | |
341 { | |
342 printf("Hey! nextfatp == fatp!\n"); | |
343 kill(getpid(), 15); | |
344 } | |
345 #endif | |
346 if (fatp->pkt_size < bytesleft) | |
347 { | |
348 /* got one! */ | |
349 sendUDPbuffered(0, fatp->packet, fatp->pkt_size); | |
350 bytesleft -= fatp->pkt_size; | |
351 | |
352 packets_sent++; /* counts as a udp packet sent */ | |
353 | |
354 /* move the packet to a higher queue (if there is one) */ | |
355 dequeue(fatp); | |
356 if (list + 1 == MAX_FAT_LIST) | |
357 { | |
358 /* enqueue(fatp, list); *//* keep packets on high queue? */ | |
359 } | |
360 else | |
361 { | |
362 enqueue(fatp, list + 1); | |
363 } | |
364 | |
365 /* done yet? */ | |
366 if (bytesleft < MAX_NONFAT) | |
367 goto done; /* don't waste time searching anymore */ | |
368 } | |
369 fatp = nextfatp; | |
370 } | |
371 } | |
372 | |
373 done: | |
374 /* at this point, we either filled with fat or ran out of queued packets */ | |
375 #ifdef FATDIAG | |
376 printf("--- done\n"); | |
377 #endif | |
378 V_UDPDIAG(("- Added %d grams of fat\n", MAX_FAT_DATA - bytesleft)); | |
379 return (0); /* some compilers need something after a goto */ | |
380 } | |
381 | |
382 | |
383 /* | |
384 * This gets called from flushSockBuf after the transmission is sent. It | |
385 * appends all the packets sitting in temporary queues to the corresponding | |
386 * fat queues, where they will be eligible for fattening next transmission. | |
387 */ | |
388 void | |
389 fatMerge() | |
390 { | |
391 int i; | |
392 | |
393 for (i = 0; i < MAX_FAT_LIST; i++) | |
394 { | |
395 if (tmplist[i].head == NULL) | |
396 continue; /* temp list is empty, nothing to do */ | |
397 | |
398 if (fatlist[i].head == NULL) | |
399 { | |
400 /* fatlist is empty; just copy pointers */ | |
401 fatlist[i].head = tmplist[i].head; | |
402 fatlist[i].tail = tmplist[i].tail; | |
403 | |
404 } | |
405 else | |
406 { | |
407 /* stuff in both */ | |
408 (tmplist[i].head)->next = fatlist[i].tail; /* fwd pointer */ | |
409 (fatlist[i].tail)->prev = tmplist[i].head; /* back pointer */ | |
410 fatlist[i].tail = tmplist[i].tail; /* move tail back */ | |
411 tmplist[i].head = tmplist[i].tail = NULL; /* clear the tmp list */ | |
412 } | |
413 tmplist[i].head = tmplist[i].tail = NULL; | |
414 #ifdef FATDIAG | |
415 printf("merged list %d: %.8lx %.8lx\n", i, fatlist[i].head, | |
416 fatlist[i].tail); | |
417 #endif | |
418 } | |
419 } |