Mercurial > ~darius > hgwebdir.cgi > paradise_server
comparison src/sockio.c @ 8:0836fb919dfa
First entry of Paradise Server 2.9 patch 10 Beta
author | darius |
---|---|
date | Sat, 06 Dec 1997 04:37:05 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
7:814de70c9f67 | 8:0836fb919dfa |
---|---|
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 | |
20 #include "config.h" | |
21 | |
22 #include <errno.h> | |
23 #include <stdio.h> | |
24 #include <sys/types.h> | |
25 #include <sys/time.h> | |
26 #include <netinet/in.h> | |
27 | |
28 #include "data.h" | |
29 #include "packets.h" | |
30 #include "shmem.h" | |
31 | |
32 #define BUFSIZE 16738 | |
33 static char buf[BUFSIZE]; /* Socket buffer */ | |
34 static char *bufptr = buf; | |
35 #define UDPBUFSIZE 960 /* (tweakable; should be under 1300) */ | |
36 static char udpbuf[UDPBUFSIZE]; /* UDP socket buffer */ | |
37 static char *udpbufptr = udpbuf; | |
38 #ifdef DOUBLE_UDP | |
39 static char scbuf[UDPBUFSIZE]; /* semi-critical UDP socket buffer */ | |
40 static char *scbufptr = scbuf; /* (only used for double UDP) */ | |
41 #endif | |
42 static long sequence; /* the holy sequence number */ | |
43 | |
44 #define FAT_THRESH 500 /* if more than this, don't add fat */ | |
45 | |
46 extern int udpMode; | |
47 | |
48 | |
49 extern int clientDead; | |
50 | |
51 int | |
52 buffersEmpty() | |
53 { | |
54 return bufptr == buf && | |
55 (commMode != COMM_UDP || udpbufptr == buf); | |
56 } | |
57 | |
58 void | |
59 resetUDPbuffer() | |
60 { | |
61 if (udpbufptr != udpbuf) | |
62 { | |
63 udpbufptr = udpbuf; /* clear out any old data */ | |
64 sequence--; /* we just killed a sequence packet */ | |
65 } | |
66 } | |
67 | |
68 void | |
69 resetUDPsequence() | |
70 { | |
71 sequence = 1; | |
72 } | |
73 | |
74 /* | |
75 * If we're in UDP mode, add a sequence number to the transmission buffer. | |
76 * Returns the #of bytes inserted. | |
77 * | |
78 * This will add a sequence # to transmissions on either channel. However, the | |
79 * current implementation doesn't put sequences on TCP transmissions because | |
80 * mixed TCP packets and UDP packets rarely arrive in the order in which they | |
81 * were sent. | |
82 */ | |
83 int | |
84 addSequence(outbuf) | |
85 char *outbuf; | |
86 { | |
87 struct sequence_spacket *ssp; | |
88 | |
89 if (commMode != COMM_UDP || udpMode == MODE_TCP) | |
90 return (0); | |
91 | |
92 packets_sent++; | |
93 | |
94 ssp = (struct sequence_spacket *) outbuf; | |
95 ssp->type = SP_SEQUENCE; | |
96 ssp->sequence = htons((unsigned short) sequence); | |
97 sequence++; | |
98 | |
99 return (sizeof(struct sequence_spacket)); | |
100 } | |
101 | |
102 /* Flush the socket buffer */ | |
103 void | |
104 flushSockBuf() | |
105 { | |
106 int cc; | |
107 | |
108 if (clientDead) | |
109 return; | |
110 if (bufptr != buf) | |
111 { | |
112 if ((cc = gwrite(sock, buf, bufptr - buf)) != bufptr - buf) | |
113 { | |
114 fprintf(stderr, "std flush gwrite failed (%d, error %d)\n", | |
115 cc, errno); | |
116 clientDead = 1; | |
117 } | |
118 bufptr = buf /* + addSequence(buf) */ ; | |
119 } | |
120 /* | |
121 * This is where we try to add fat. There's no point in checking at the | |
122 * other places which call gwrite(), because they only call it when the | |
123 * buffer is already full. | |
124 */ | |
125 if (udpSock >= 0 | |
126 && udpMode == MODE_FAT | |
127 && (udpbufptr - udpbuf) < FAT_THRESH) | |
128 fatten(); | |
129 | |
130 if (udpSock >= 0 && udpbufptr != udpbuf) | |
131 { | |
132 #ifdef BROKEN | |
133 /* debugging only!! */ | |
134 if (sequence % 5 == 0) | |
135 { | |
136 /* act as if we did the gwrite(), but don't */ | |
137 udpbufptr = udpbuf + addSequence(udpbuf); | |
138 goto foo; | |
139 } | |
140 #endif | |
141 if ((cc = gwrite(udpSock, udpbuf, udpbufptr - udpbuf)) != udpbufptr - udpbuf) | |
142 { | |
143 fprintf(stderr, "UDP flush gwrite failed (%d, error %d)\n", | |
144 cc, errno); | |
145 /* clientDead=1; */ | |
146 UDPDIAG(("*** UDP disconnected for %s\n", me->p_name)); | |
147 printUdpInfo(); | |
148 closeUdpConn(); | |
149 commMode = COMM_TCP; | |
150 } | |
151 #ifdef DOUBLE_UDP | |
152 sendSC(); | |
153 #endif | |
154 udpbufptr = udpbuf + addSequence(udpbuf); | |
155 } | |
156 #ifdef BROKEN | |
157 foo: | |
158 #endif | |
159 if (udpMode == MODE_FAT) | |
160 fatMerge(); | |
161 } | |
162 | |
163 void | |
164 build_select_masks(readfds, writefds) | |
165 fd_set *readfds, *writefds; | |
166 { | |
167 if (readfds) | |
168 { | |
169 FD_ZERO(readfds); | |
170 FD_SET(sock, readfds); | |
171 if (udpSock >= 0) | |
172 FD_SET(udpSock, readfds); | |
173 } | |
174 if (writefds) | |
175 { | |
176 FD_ZERO(writefds); | |
177 if (haveDeferredPackets()) | |
178 FD_SET(sock, writefds); | |
179 } | |
180 } | |
181 | |
182 int | |
183 socketPause() | |
184 { | |
185 struct timeval timeout; | |
186 fd_set readfds, writefds; | |
187 | |
188 timeout.tv_sec = 1; | |
189 timeout.tv_usec = 0; | |
190 | |
191 build_select_masks(&readfds, &writefds); | |
192 | |
193 return select(32, (fd_set *) & readfds, &writefds, 0, &timeout); | |
194 } | |
195 | |
196 int | |
197 socketWait() | |
198 { | |
199 fd_set readfds, writefds; | |
200 | |
201 build_select_masks(&readfds, &writefds); | |
202 | |
203 return select(32, &readfds, &writefds, 0, (struct timeval *) 0); | |
204 } | |
205 | |
206 int | |
207 gwrite(fd, wbuf, bytes) | |
208 int fd; | |
209 char *wbuf; | |
210 int bytes; | |
211 { | |
212 int orig = bytes; | |
213 int n; | |
214 char tempbuf[80]; | |
215 struct timeval to; | |
216 | |
217 | |
218 while (bytes) | |
219 { | |
220 n = write(fd, wbuf, bytes); | |
221 if (n < 0) | |
222 { | |
223 if (errno == ENOBUFS) | |
224 { | |
225 /* | |
226 * The man pages don't mention this as a possibility. Yet, it | |
227 * happens. I guess I just wait for 1/10 sec, and continue? | |
228 */ | |
229 /* | |
230 * I would use usleep() to do this, but this system ain't got it... | |
231 */ | |
232 /* note: changed from 100 ms to 20 ms. (HAK) */ | |
233 to.tv_sec = 0; | |
234 to.tv_usec = 20000; | |
235 select(0, NULL, NULL, NULL, &to); | |
236 continue; | |
237 } | |
238 if (errno == EINTR) /* interrupted by signal, restart */ | |
239 continue; | |
240 | |
241 if (fd == udpSock) | |
242 { | |
243 /* do we want Hiccup code here? */ | |
244 UDPDIAG(("Tried to write %d, 0x%lx, %d (error %d)\n", | |
245 fd, (unsigned long) wbuf, bytes, errno)); | |
246 printUdpInfo(); | |
247 logmessage("UDP gwrite failed:"); | |
248 } | |
249 sprintf(tempbuf, "Died in gwrite, n=%d, errno=%d <%s@%s>", | |
250 n, errno, me->p_login, me->p_full_hostname); | |
251 logmessage(tempbuf); | |
252 return (-1); | |
253 } | |
254 bytes -= n; | |
255 wbuf += n; | |
256 } | |
257 return (orig); | |
258 } | |
259 | |
260 | |
261 void | |
262 sendUDPbuffered(issc, packet, size) | |
263 int issc; /* is semi-critical */ | |
264 void *packet; | |
265 int size; | |
266 { | |
267 if (udpbufptr - udpbuf + size >= UDPBUFSIZE) | |
268 { | |
269 int cc; | |
270 if ((cc = gwrite(udpSock, udpbuf, udpbufptr - udpbuf)) != | |
271 udpbufptr - udpbuf) | |
272 { | |
273 fprintf(stderr, "UDP gwrite failed (%d, error %d)\n", | |
274 cc, errno); | |
275 /* clientDead=1; */ | |
276 UDPDIAG(("*** UDP disconnected for %s\n", me->p_name)); | |
277 printUdpInfo(); | |
278 closeUdpConn(); | |
279 commMode = COMM_TCP; | |
280 } | |
281 #ifdef DOUBLE_UDP | |
282 sendSC(); /* send semi-critical info, if needed */ | |
283 #endif | |
284 udpbufptr = udpbuf + addSequence(udpbuf); | |
285 } | |
286 memcpy(udpbufptr, packet, size); | |
287 udpbufptr += size; | |
288 | |
289 #ifdef DOUBLE_UDP | |
290 if (issc && udpMode == MODE_DOUBLE) | |
291 { | |
292 memcpy(scbufptr, packet, size); | |
293 scbufptr += size; | |
294 V_UDPDIAG((" adding SC\n")); | |
295 } | |
296 #endif | |
297 if (issc && udpMode == MODE_FAT) | |
298 { | |
299 updateFat(packet); | |
300 } | |
301 } | |
302 | |
303 | |
304 void | |
305 sendTCPbuffered(packet, size) | |
306 void *packet; | |
307 int size; | |
308 { | |
309 int cc; | |
310 /* these are critical packets; send them via TCP */ | |
311 #ifdef FEATURE_DIAG | |
312 /* check the packet & see if we're adding packet type 60 to the buffer */ | |
313 if (*((char *) packet) == SP_FEATURE) | |
314 { | |
315 fprintf(stderr, "Sending SP_FEATURE packet\n"); | |
316 } | |
317 #endif | |
318 if (bufptr - buf + size >= BUFSIZE) | |
319 { | |
320 #ifdef FEATURE_DIAG | |
321 if (*((char *) packet) == SP_FEATURE) | |
322 { | |
323 fprintf(stderr, "Sending TCP buffer, delaying write.\n"); | |
324 } | |
325 #endif | |
326 if ((cc = gwrite(sock, buf, bufptr - buf)) != bufptr - buf) | |
327 { | |
328 fprintf(stderr, "TCP gwrite failed (%d, error %d)\n", | |
329 cc, errno); | |
330 clientDead = 1; | |
331 } | |
332 bufptr = buf /* + addSequence(buf) */ ; | |
333 } | |
334 #ifdef FEATURE_DIAG | |
335 if (*((char *) packet) == SP_FEATURE) | |
336 { | |
337 fprintf(stderr, "Adding SP_FEATURE packet to buffer.\n"); | |
338 } | |
339 #endif | |
340 memcpy(bufptr, packet, size); | |
341 bufptr += size; | |
342 } | |
343 | |
344 /* Transmission of some packets can be delayed indefinitely */ | |
345 | |
346 struct deferred_packet | |
347 { | |
348 void *data; | |
349 int size; | |
350 struct deferred_packet *next; | |
351 }; | |
352 | |
353 struct deferred_packet *df_head, *df_tail; | |
354 | |
355 int | |
356 haveDeferredPackets() | |
357 { | |
358 return df_head != 0; | |
359 } | |
360 | |
361 /* Put a packet on the deferred queue. */ | |
362 | |
363 void | |
364 sendTCPdeferred(packet, size) | |
365 void *packet; | |
366 int size; | |
367 { | |
368 #if 1 | |
369 /* I'm having problems with UDP connection packet */ | |
370 sendTCPbuffered(packet, size); | |
371 #else | |
372 struct deferred_packet *pkt; | |
373 pkt = (struct deferred_packet *) malloc(sizeof(*pkt)); | |
374 pkt->data = malloc(size); | |
375 pkt->size = size; | |
376 memcpy(pkt->data, packet, size); | |
377 pkt->next = 0; | |
378 | |
379 if (df_tail) | |
380 { | |
381 df_tail->next = pkt; | |
382 } | |
383 else | |
384 { | |
385 df_head = pkt; | |
386 } | |
387 df_tail = pkt; | |
388 #endif | |
389 } | |
390 | |
391 /* | |
392 * When the socket is ready for write, toss a packet through the pipe | |
393 * Hopefully it won't block... | |
394 */ | |
395 | |
396 void | |
397 flushDeferred() | |
398 { | |
399 int rval; | |
400 | |
401 if (df_head == 0) | |
402 return; | |
403 | |
404 /* could block, oh well */ | |
405 rval = gwrite(sock, df_head->data, df_head->size); | |
406 | |
407 if (rval != df_head->size) | |
408 { | |
409 fprintf(stderr, "TCP gwrite (deferred) failed (%d, error %d)\n", | |
410 rval, errno); | |
411 clientDead = 1; | |
412 } | |
413 | |
414 { | |
415 struct deferred_packet *temp = df_head; | |
416 df_head = temp->next; | |
417 free(temp->data); | |
418 free(temp); | |
419 } | |
420 if (!df_head) | |
421 df_tail = 0; /* queue is empty */ | |
422 } | |
423 | |
424 /* sends all the deferred packets through the TCP buffer */ | |
425 void | |
426 undeferDeferred() | |
427 { | |
428 while (df_head) | |
429 { | |
430 sendTCPbuffered(df_head->data, df_head->size); | |
431 | |
432 { | |
433 struct deferred_packet *temp = df_head; | |
434 df_head = temp->next; | |
435 free(temp->data); | |
436 free(temp); | |
437 } | |
438 } | |
439 df_tail = 0; | |
440 } |