4
|
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 }
|