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