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 }