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 }