1 /* $Id$
2  *
3  * XPilot, a multiplayer gravity war game.  Copyright (C) 1991-95 by
4  *
5  *      Bjørn Stabell        (bjoerns@staff.cs.uit.no)
6  *      Ken Ronny Schouten   (kenrsc@stud.cs.uit.no)
7  *      Bert G sbers         (bert@mc.bio.uva.nl)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23 
24 #ifdef WIN32
25 
26 # include <winsock.h>
27 /* Hack - my errno doesn't include EWOULDBLOCK * - GP */
28 #ifndef DUMB_WIN
29 # define EWOULDBLOCK WSAEWOULDBLOCK
30 /* this next one redefines va_start and va_end, but it is necessary -GP*/
31 #ifndef _WINDOWS
32 # include <varargs.h>
33 #endif
34 #endif
35 #else
36 # include <unistd.h>
37 # include <stdlib.h>
38 # include <stdio.h>
39 # include <errno.h>
40 # include <sys/types.h>
41 # if defined(__hpux)
42 #  include <time.h>
43 # else
44 #  include <sys/time.h>
45 # endif
46 # ifdef __sgi
47 #  include <bstring.h>
48 # endif
49 #endif
50 
51 /* MinGW doesn't have EWOULDBLOCK either - mikaelh */
52 #ifdef MINGW
53 #define EWOULDBLOCK WSAEWOULDBLOCK
54 #endif
55 
56 
57 #include "angband.h"
58 #include "version.h"
59 #include "const.h"
60 /*#include "error.h"*/
61 #include "sockbuf.h"
62 #include "pack.h"
63 #include "bit.h"
64 
65 #ifdef MSDOS
66 #include "net-ibm.h"
67 #else
68 # ifdef WIN32
69 #  include "net-win.h"
70 # else
71 #  include "net-unix.h"
72 # endif /* WIN32 */
73 #endif /* MSDOS */
74 
75 char net_version[] = VERSION;
76 
Sockbuf_init(sockbuf_t * sbuf,int sock,int size,int state)77 int Sockbuf_init(sockbuf_t *sbuf, int sock, int size, int state)
78 {
79     if ((sbuf->buf = sbuf->ptr = (char *) malloc(size)) == NULL) {
80 	return -1;
81     }
82     sbuf->sock = sock;
83     sbuf->state = state;
84     sbuf->len = 0;
85     sbuf->size = size;
86     sbuf->ptr = sbuf->buf;
87     sbuf->state = state;
88     return 0;
89 }
90 
Sockbuf_cleanup(sockbuf_t * sbuf)91 int Sockbuf_cleanup(sockbuf_t *sbuf)
92 {
93     if (sbuf->buf != NULL) {
94 	free(sbuf->buf);
95     }
96     sbuf->buf = sbuf->ptr = NULL;
97     sbuf->size = sbuf->len = 0;
98     sbuf->state = 0;
99     return 0;
100 }
101 
Sockbuf_clear(sockbuf_t * sbuf)102 int Sockbuf_clear(sockbuf_t *sbuf)
103 {
104     sbuf->len = 0;
105     sbuf->ptr = sbuf->buf;
106     return 0;
107 }
108 
Sockbuf_advance(sockbuf_t * sbuf,int len)109 int Sockbuf_advance(sockbuf_t *sbuf, int len)
110 {
111     /*
112      * First do a few buffer consistency checks.
113      */
114     if (sbuf->ptr > sbuf->buf + sbuf->len) {
115 	errno = 0;
116 	plog("Sockbuf pointer too far");
117 	sbuf->ptr = sbuf->buf + sbuf->len;
118     }
119     if (sbuf->ptr < sbuf->buf) {
120 	errno = 0;
121 	plog("Sockbuf pointer bad");
122 	sbuf->ptr = sbuf->buf;
123     }
124     if (sbuf->len > sbuf->size) {
125 	errno = 0;
126 	plog("Sockbuf len too far");
127 	sbuf->len = sbuf->size;
128     }
129     if (sbuf->len < 0) {
130 	errno = 0;
131 	plog("Sockbuf len bad");
132 	sbuf->len = 0;
133     }
134     if (len <= 0) {
135 	if (len < 0) {
136 	    errno = 0;
137 	    plog(format("Sockbuf advance negative (%d)", len));
138 	}
139     }
140     else if (len >= sbuf->len) {
141 	if (len > sbuf->len) {
142 	    errno = 0;
143 	    plog("Sockbuf advancing too far");
144 	}
145 	sbuf->len = 0;
146 	sbuf->ptr = sbuf->buf;
147     } else {
148 #if defined(__hpux) || defined(VMS) || defined(__apollo) || defined(SVR4) || defined(_SEQUENT_) || defined(SYSV) || !defined(bcopy)
149 	memmove(sbuf->buf, sbuf->buf + len, sbuf->len - len);
150 #else
151 	bcopy(sbuf->buf + len, sbuf->buf, sbuf->len - len);
152 #endif
153 	sbuf->len -= len;
154 	if (sbuf->ptr - sbuf->buf <= len) {
155 	    sbuf->ptr = sbuf->buf;
156 	} else {
157 	    sbuf->ptr -= len;
158 	}
159     }
160     return 0;
161 }
162 
Sockbuf_rollback(sockbuf_t * sbuf,int len)163 int Sockbuf_rollback(sockbuf_t *sbuf, int len)
164 {
165     /*
166      * First do a few buffer consistency checks.
167      */
168     if (sbuf->ptr < sbuf->buf) {
169 	errno = 0;
170 	plog("Sockbuf pointer bad");
171 	sbuf->ptr = sbuf->buf;
172     }
173     if (len > sbuf->ptr - sbuf->buf) {
174 	plog("Sockbuf rollback too big");
175 	len = sbuf->ptr - sbuf->buf;
176     }
177     if (len < 0) {
178 	errno = 0;
179 	plog(format("Sockbuf rollback negative (%d)", len));
180     }
181     else {
182 	sbuf->ptr -= len;
183     }
184     return 0;
185 }
186 
Sockbuf_flush(sockbuf_t * sbuf)187 int Sockbuf_flush(sockbuf_t *sbuf)
188 {
189     int			len,
190 			i;
191 
192     if (BIT(sbuf->state, SOCKBUF_WRITE) == 0) {
193 	errno = 0;
194 	plog("No flush on non-writable socket buffer");
195 	plog(format("(state=%02x,buf=%08x,ptr=%08x,size=%d,len=%d,sock=%d)",
196 	    sbuf->state, sbuf->buf, sbuf->ptr, sbuf->size, sbuf->len,
197 	    sbuf->sock));
198 	return -1;
199     }
200     if (BIT(sbuf->state, SOCKBUF_LOCK) != 0) {
201 	errno = 0;
202 	plog(format("No flush on locked socket buffer (0x%02x)", sbuf->state));
203 	return -1;
204     }
205     if (sbuf->len <= 0) {
206 	if (sbuf->len < 0) {
207 	    errno = 0;
208 	    plog("Write socket buffer length negative");
209 	    sbuf->len = 0;
210 	    sbuf->ptr = sbuf->buf;
211 	}
212 	return 0;
213     }
214 
215 #if 0
216     /* maintain a few statistics */
217     {
218 	static int		max = 1024, avg, count;
219 
220 	avg += sbuf->len;
221 	count++;
222 	if (sbuf->len > max) {
223 	    max = sbuf->len;
224 	    printf("Max packet = %d, avg = %d\n", max, avg / count);
225 	}
226 	else if (max > 1024 && (count & 0x03) == 0) {
227 	    max--;
228 	}
229     }
230 #endif
231 
232     if (BIT(sbuf->state, SOCKBUF_DGRAM) != 0) {
233 	errno = 0;
234 	i = 0;
235 #if 0
236 	if (rand() % 12 == 0)	/* artificial packet loss */
237 	    len = sbuf->len;
238 	else
239 #endif
240 	while ((len = DgramWrite(sbuf->sock, sbuf->buf, sbuf->len)) <= 0) {
241 	    if (len == 0
242 		|| errno == EWOULDBLOCK
243 		|| errno == EAGAIN) {
244 		Sockbuf_clear(sbuf);
245 		return 0;
246 	    }
247 	    if (errno == EINTR) {
248 		errno = 0;
249 		continue;
250 	    }
251 #if 0
252 	    if (errno == ECONNREFUSED) {
253 		plog("Send refused");
254 		Sockbuf_clear(sbuf);
255 		return -1;
256 	    }
257 #endif
258 	    if (++i > MAX_SOCKBUF_RETRIES) {
259 		plog(format("Can't send on socket (%d,%d)", sbuf->sock, sbuf->len));
260 		Sockbuf_clear(sbuf);
261 		return -1;
262 	    }
263 	    { static int send_err;
264 		if ((send_err++ & 0x3F) == 0) {
265 		    /*plog(format("send (%d)", i));*/
266 		}
267 	    }
268 	    if (GetSocketError(sbuf->sock) == -1) {
269 		plog("GetSocketError send");
270 		return -1;
271 	    }
272 	    errno = 0;
273 	}
274 	if (len != sbuf->len) {
275 	    errno = 0;
276 	    plog(format("Can't write complete datagram (%d,%d)", len, sbuf->len));
277 	}
278 	Sockbuf_clear(sbuf);
279     } else {
280 	errno = 0;
281 	while ((len = DgramWrite(sbuf->sock, sbuf->buf, sbuf->len)) <= 0) {
282 	    if (errno == EINTR) {
283 		errno = 0;
284 		continue;
285 	    }
286 	    if (errno != EWOULDBLOCK
287 		&& errno != EAGAIN) {
288 		plog("Can't write on socket");
289 		return -1;
290 	    }
291 	    return 0;
292 	}
293 	Sockbuf_advance(sbuf, len);
294     }
295     return len;
296 }
297 
Sockbuf_write(sockbuf_t * sbuf,char * buf,int len)298 int Sockbuf_write(sockbuf_t *sbuf, char *buf, int len)
299 {
300     if (BIT(sbuf->state, SOCKBUF_WRITE) == 0) {
301 	errno = 0;
302 	plog("No write to non-writable socket buffer");
303 	return -1;
304     }
305     if (sbuf->size - sbuf->len < len) {
306 	if (BIT(sbuf->state, SOCKBUF_LOCK | SOCKBUF_DGRAM) != 0) {
307 	    errno = 0;
308 	    plog(format("No write to locked socket buffer (%d,%d,%d,%d)",
309 		sbuf->state, sbuf->size, sbuf->len, len));
310 	    return -1;
311 	}
312 	if (Sockbuf_flush(sbuf) == -1) {
313 	    return -1;
314 	}
315 	if (sbuf->size - sbuf->len < len) {
316 	    return 0;
317 	}
318     }
319     memcpy(sbuf->buf + sbuf->len, buf, len);
320     sbuf->len += len;
321 
322     return len;
323 }
324 
Sockbuf_read(sockbuf_t * sbuf)325 int Sockbuf_read(sockbuf_t *sbuf)
326 {
327     int			max,
328 			i,
329 			len;
330 
331     if (BIT(sbuf->state, SOCKBUF_READ) == 0) {
332 	errno = 0;
333 	plog(format("No read from non-readable socket buffer (%d)", sbuf->state));
334 	return -1;
335     }
336     if (BIT(sbuf->state, SOCKBUF_LOCK) != 0) {
337 	return 0;
338     }
339     if (sbuf->ptr > sbuf->buf) {
340 	Sockbuf_advance(sbuf, sbuf->ptr - sbuf->buf);
341     }
342     if ((max = sbuf->size - sbuf->len) <= 0) {
343 	static int before;
344 	if (before++ == 0) {
345 	    errno = 0;
346 	    plog(format("Read socket buffer not big enough (%d,%d)",
347 		  sbuf->size, sbuf->len));
348 	}
349 	return -1;
350     }
351     if (BIT(sbuf->state, SOCKBUF_DGRAM) != 0) {
352 	errno = 0;
353 	i = 0;
354 #if 0
355 	if (rand() % 12 == 0)		/* artificial packet loss */
356 	    len = sbuf->len;
357 	else
358 #endif
359 	while ((len = DgramRead(sbuf->sock, sbuf->buf + sbuf->len, max)) <= 0) {
360 	    if (len == 0) {
361 		return 0;
362 	    }
363 	    if (errno == EINTR) {
364 		errno = 0;
365 		continue;
366 	    }
367 	    if (errno == EWOULDBLOCK
368 		|| errno == EAGAIN) {
369 		return 0;
370 	    }
371 #if 0
372 	    if (errno == ECONNREFUSED) {
373 		plog("Receive refused");
374 		return -1;
375 	    }
376 #endif
377 	    if (++i > MAX_SOCKBUF_RETRIES) {
378 		plog("Can't recv on socket");
379 		return -1;
380 	    }
381 	    { static int recv_err;
382 		if ((recv_err++ & 0x3F) == 0) {
383 		    /*plog(format("recv (%d)", i));*/
384 		}
385 	    }
386 	    if (GetSocketError(sbuf->sock) == -1) {
387 		plog("GetSocketError recv");
388 		return -1;
389 	    }
390 	    errno = 0;
391 	}
392 	sbuf->len += len;
393     } else {
394 	errno = 0;
395 	while ((len = DgramRead(sbuf->sock, sbuf->buf + sbuf->len, max)) <= 0) {
396 	    if (len == 0) {
397 		return 0;
398 	    }
399 	    if (errno == EINTR) {
400 		errno = 0;
401 		continue;
402 	    }
403 	    if (errno != EWOULDBLOCK
404 		&& errno != EAGAIN) {
405 		plog("Can't read on socket");
406 		return -1;
407 	    }
408 	    return 0;
409 	}
410 	sbuf->len += len;
411     }
412 
413     return sbuf->len;
414 }
415 
Sockbuf_copy(sockbuf_t * dest,sockbuf_t * src,int len)416 int Sockbuf_copy(sockbuf_t *dest, sockbuf_t *src, int len)
417 {
418     if (len < dest->size - dest->len) {
419 	errno = 0;
420 	plog("Not enough room in destination copy socket buffer");
421 	return -1;
422     }
423     if (len < src->len) {
424 	errno = 0;
425 	plog("Not enough data in source copy socket buffer");
426 	return -1;
427     }
428     memcpy(dest->buf + dest->len, src->buf, len);
429     dest->len += len;
430 
431     return len;
432 }
433 
434 #if STDVA
Packet_printf(sockbuf_t * sbuf,char * fmt,...)435 int Packet_printf(sockbuf_t *sbuf, char *fmt, ...)
436 #else
437 int Packet_printf(va_alist)
438     va_dcl
439 #endif
440 {
441 #define PRINTF_FMT	1
442 #define PRINTF_IO	2
443 #define PRINTF_SIZE	3
444 
445     int			i,
446 			cval,
447 			ival,
448 			count,
449 			failure = 0,
450 			max_str_size;
451     unsigned		uval;
452     short int		sval;
453     unsigned short int	usval;
454     long int		lval;
455     unsigned long int	ulval;
456     char		*str,
457 			*end,
458 			*buf;
459     va_list		ap;
460 #if !STDVA
461     char		*fmt;
462     sockbuf_t		*sbuf;
463 
464     va_start(ap);
465     sbuf = va_arg(ap, sockbuf_t *);
466     fmt = va_arg(ap, char *);
467 #else
468     va_start(ap, fmt);
469 #endif
470 
471     /*
472      * Stream socket buffers should flush the buffer if running
473      * out of write space.  This is currently not needed cause
474      * only datagram sockets are used or the buffer is locked.
475      */
476 
477     /*
478      * Mark the end of the available buffer space.
479      */
480     end = sbuf->buf + sbuf->size;
481 
482     buf = sbuf->buf + sbuf->len;
483 
484     for (i = 0; failure == 0 && fmt[i] != '\0'; i++) {
485 	if (fmt[i] == '%') {
486 	    switch (fmt[++i]) {
487 	    case 'c':
488 		if (buf + 1 >= end) {
489 		    failure = PRINTF_SIZE;
490 		    break;
491 		}
492 		cval = va_arg(ap, int);
493 		*buf++ = cval;
494 		break;
495 	    case 'd':
496 		if (buf + 4 >= end) {
497 		    failure = PRINTF_SIZE;
498 		    break;
499 		}
500 		ival = va_arg(ap, int);
501 		*buf++ = ival >> 24;
502 		*buf++ = ival >> 16;
503 		*buf++ = ival >> 8;
504 		*buf++ = ival;
505 		break;
506 	    case 'u':
507 		if (buf + 4 >= end) {
508 		    failure = PRINTF_SIZE;
509 		    break;
510 		}
511 		uval = va_arg(ap, unsigned);
512 		*buf++ = uval >> 24;
513 		*buf++ = uval >> 16;
514 		*buf++ = uval >> 8;
515 		*buf++ = uval;
516 		break;
517 	    case 'h':
518 		if (buf + 2 >= end) {
519 		    failure = PRINTF_SIZE;
520 		    break;
521 		}
522 		switch (fmt[++i]) {
523 		case 'd':
524 		    sval = va_arg(ap, int);
525 		    *buf++ = sval >> 8;
526 		    *buf++ = sval;
527 		    break;
528 		case 'u':
529 		    usval = va_arg(ap, unsigned);
530 		    *buf++ = usval >> 8;
531 		    *buf++ = usval;
532 		    break;
533 		default:
534 		    failure = PRINTF_FMT;
535 		    break;
536 		}
537 		break;
538 	    case 'l':
539 		if (buf + 4 >= end) {
540 		    failure = PRINTF_SIZE;
541 		    break;
542 		}
543 		switch (fmt[++i]) {
544 		case 'd':
545 		    lval = va_arg(ap, long int);
546 		    *buf++ = lval >> 24;
547 		    *buf++ = lval >> 16;
548 		    *buf++ = lval >> 8;
549 		    *buf++ = lval;
550 		    break;
551 		case 'u':
552 		    ulval = va_arg(ap, unsigned long int);
553 		    *buf++ = ulval >> 24;
554 		    *buf++ = ulval >> 16;
555 		    *buf++ = ulval >> 8;
556 		    *buf++ = ulval;
557 		    break;
558 		default:
559 		    failure = PRINTF_FMT;
560 		    break;
561 		}
562 		break;
563 	    case 'S':	/* Big strings */
564 	    case 'I':	/* Semi-big strings: Item name (including inscription) */
565 	    case 's':	/* Small strings */
566 		max_str_size = (fmt[i] == 'S') ? MSG_LEN : ((fmt[i] == 'I') ? ONAME_LEN : MAX_CHARS);
567 		str = va_arg(ap, char *);
568 #if 1
569 		char *stop;
570 		if (buf + max_str_size >= end) {
571 		    stop = end;
572 		} else {
573 		    stop = buf + max_str_size;
574 		}
575 		/* Send the nul byte too */
576 		do {
577 		    if (buf >= stop) {
578 			break;
579 		    }
580 		} while ((*buf++ = *str++) != '\0');
581 		if (buf > stop) {
582 		    failure = PRINTF_SIZE;
583 		}
584 #else
585 		/* Optimized version - mikaelh */
586 		long len = strlen(str) + 1;
587 
588 		if (len > max_str_size) {
589 			len = max_str_size;
590 		}
591 
592 		if (buf + len > end) {
593 			failure = PRINTF_SIZE;
594 		} else {
595 			memcpy(buf, str, len);
596 			buf += len;
597 		}
598 #endif
599 		break;
600 	    default:
601 		failure = PRINTF_FMT;
602 		break;
603 	    }
604 	} else {
605 	    failure = PRINTF_FMT;
606 	}
607     }
608     if (failure != 0) {
609 	count = -1;
610 	if (failure == PRINTF_SIZE) {
611 #if 0
612 	    static int before;
613 	    if ((before++ & 0x0F) == 0) {
614 		printf("Write socket buffer not big enough (%d,%d,\"%s\")\n",
615 		    sbuf->size, sbuf->len, fmt);
616 	    }
617 #endif
618 	    if (BIT(sbuf->state, SOCKBUF_DGRAM) != 0) {
619 		count = 0;
620 		failure = 0;
621 	    }
622 	}
623 	else if (failure == PRINTF_FMT) {
624 	    errno = 0;
625 	    plog(format("Error in format string (\"%s\")", fmt));
626 	}
627     } else {
628 	count = buf - (sbuf->buf + sbuf->len);
629 	sbuf->len += count;
630     }
631 
632     va_end(ap);
633 
634     return count;
635 }
636 
637 #if STDVA
Packet_scanf(sockbuf_t * sbuf,char * fmt,...)638 int Packet_scanf(sockbuf_t *sbuf, char *fmt, ...)
639 #else
640 int Packet_scanf(va_alist)
641     va_dcl
642 #endif
643 {
644     int			i,
645 			j,
646 			*iptr,
647 			count = 0,
648 			failure = 0,
649 			max_str_size;
650     unsigned		*uptr;
651     short int		*sptr;
652     unsigned short int	*usptr;
653     long int		*lptr;
654     unsigned long int	*ulptr;
655     char		*cptr,
656 			*str;
657     va_list		ap;
658 #if !STDVA
659     char		*fmt;
660     sockbuf_t		*sbuf;
661 
662     va_start(ap);
663     sbuf = va_arg(ap, sockbuf_t *);
664     fmt = va_arg(ap, char *);
665 #else
666     va_start(ap, fmt);
667 #endif
668 
669     for (i = j = 0; failure == 0 && fmt[i] != '\0'; i++) {
670 	if (fmt[i] == '%') {
671 	    count++;
672 	    switch (fmt[++i]) {
673 	    case 'c':
674 		if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 1]) {
675 		    if (BIT(sbuf->state, SOCKBUF_DGRAM | SOCKBUF_LOCK) != 0) {
676 			failure = 3;
677 			break;
678 		    }
679 		    if (Sockbuf_read(sbuf) == -1) {
680 			failure = 2;
681 			break;
682 		    }
683 		    if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 1]) {
684 			failure = 3;
685 			break;
686 		    }
687 		}
688 		cptr = va_arg(ap, char *);
689 		*cptr = sbuf->ptr[j++];
690 		break;
691 	    case 'd':
692 		if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 4]) {
693 		    if (BIT(sbuf->state, SOCKBUF_DGRAM | SOCKBUF_LOCK) != 0) {
694 			failure = 3;
695 			break;
696 		    }
697 		    if (Sockbuf_read(sbuf) == -1) {
698 			failure = 2;
699 			break;
700 		    }
701 		    if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 4]) {
702 			failure = 3;
703 			break;
704 		    }
705 		}
706 		iptr = va_arg(ap, int *);
707 		*iptr = sbuf->ptr[j++] << 24;
708 		*iptr |= (sbuf->ptr[j++] & 0xFF) << 16;
709 		*iptr |= (sbuf->ptr[j++] & 0xFF) << 8;
710 		*iptr |= (sbuf->ptr[j++] & 0xFF);
711 		break;
712 	    case 'u':
713 		if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 4]) {
714 		    if (BIT(sbuf->state, SOCKBUF_DGRAM | SOCKBUF_LOCK) != 0) {
715 			failure = 3;
716 			break;
717 		    }
718 		    if (Sockbuf_read(sbuf) == -1) {
719 			failure = 2;
720 			break;
721 		    }
722 		    if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 4]) {
723 			failure = 3;
724 			break;
725 		    }
726 		}
727 		uptr = va_arg(ap, unsigned *);
728 		*uptr = (sbuf->ptr[j++] & 0xFF) << 24;
729 		*uptr |= (sbuf->ptr[j++] & 0xFF) << 16;
730 		*uptr |= (sbuf->ptr[j++] & 0xFF) << 8;
731 		*uptr |= (sbuf->ptr[j++] & 0xFF);
732 		break;
733 	    case 'h':
734 		if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 2]) {
735 		    if (BIT(sbuf->state, SOCKBUF_DGRAM | SOCKBUF_LOCK) != 0) {
736 			failure = 3;
737 			break;
738 		    }
739 		    if (Sockbuf_read(sbuf) == -1) {
740 			failure = 2;
741 			break;
742 		    }
743 		    if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 2]) {
744 			failure = 3;
745 			break;
746 		    }
747 		}
748 		switch (fmt[++i]) {
749 		case 'd':
750 		    sptr = va_arg(ap, short *);
751 		    *sptr = sbuf->ptr[j++] << 8;
752 		    *sptr |= (sbuf->ptr[j++] & 0xFF);
753 		    break;
754 		case 'u':
755 		    usptr = va_arg(ap, unsigned short *);
756 		    *usptr = (sbuf->ptr[j++] & 0xFF) << 8;
757 		    *usptr |= (sbuf->ptr[j++] & 0xFF);
758 		    break;
759 		default:
760 		    failure = 1;
761 		    break;
762 		}
763 		break;
764 	    case 'l':
765 		if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 4]) {
766 		    if (BIT(sbuf->state, SOCKBUF_DGRAM | SOCKBUF_LOCK) != 0) {
767 			failure = 3;
768 			break;
769 		    }
770 		    if (Sockbuf_read(sbuf) == -1) {
771 			failure = 2;
772 			break;
773 		    }
774 		    if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 4]) {
775 			failure = 3;
776 			break;
777 		    }
778 		}
779 		switch (fmt[++i]) {
780 		case 'd':
781 		    lptr = va_arg(ap, long int *);
782 		    *lptr = sbuf->ptr[j++] << 24;
783 		    *lptr |= (sbuf->ptr[j++] & 0xFF) << 16;
784 		    *lptr |= (sbuf->ptr[j++] & 0xFF) << 8;
785 		    *lptr |= (sbuf->ptr[j++] & 0xFF);
786 		    break;
787 		case 'u':
788 		    ulptr = va_arg(ap, unsigned long int *);
789 		    *ulptr = (sbuf->ptr[j++] & 0xFF) << 24;
790 		    *ulptr |= (sbuf->ptr[j++] & 0xFF) << 16;
791 		    *ulptr |= (sbuf->ptr[j++] & 0xFF) << 8;
792 		    *ulptr |= (sbuf->ptr[j++] & 0xFF);
793 		    break;
794 		default:
795 		    failure = 1;
796 		    break;
797 		}
798 		break;
799 	    case 'S':	/* Big strings (MSG_LEN) */
800 	    case 'I':	/* Semi-big strings: Item name (including inscription) (ONAME_LEN) */
801 	    case 's':	/* Small strings (MAX_CHARS) */
802 		max_str_size = (fmt[i] == 'S') ? MSG_LEN : ((fmt[i] == 'I') ? ONAME_LEN : MAX_CHARS);
803 		str = va_arg(ap, char *);
804 #if 1
805 		int k = 0;
806 		for (;;) {
807 		    if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 1]) {
808 			if (BIT(sbuf->state, SOCKBUF_DGRAM | SOCKBUF_LOCK) != 0) {
809 			    failure = 3;
810 			    break;
811 			}
812 			if (Sockbuf_read(sbuf) == -1) {
813 			    failure = 2;
814 			    break;
815 			}
816 			if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j + 1]) {
817 			    failure = 3;
818 			    break;
819 			}
820 		    }
821 		    if ((str[k++] = sbuf->ptr[j++]) == '\0') {
822 			break;
823 		    }
824 		    else if (k >= max_str_size) {
825 			/*
826 			 * What to do now is unclear to me.
827 			 * The server should drop the packet, but
828 			 * the client has more difficulty with that
829 			 * if this is the reliable data buffer.
830 			 */
831 			    /*
832 #ifndef SILENT
833 			errno = 0;
834 			plog(format("String overflow while scanning (%d,%d)",
835 			      k, max_str_size));
836 #endif
837 			if (BIT(sbuf->state, SOCKBUF_LOCK) != 0) {
838 			    failure = 2;
839 			} else {
840 			    failure = 3;
841 			}
842 			break;
843 			*/
844 			    /* Hack -- terminate our string and clear the sbuf -APD */
845 			    str[k-1] = '\0';
846 			    break;
847 		    }
848 		}
849 #else
850 		/* Optimized version - mikaelh */
851 
852 		/* Try to find a \0 in the socket buffer */
853 		cptr = memchr(&sbuf->ptr[j], '\0', sbuf->len + sbuf->buf - sbuf->ptr - j);
854 
855 		/* Are there enough bytes in the socket buffer anyway? */
856 		if (!cptr && &sbuf->ptr[j + max_str_size] <= &sbuf->buf[sbuf->len]) {
857 		    /* Set cptr to point to the last character */
858 		    cptr = &sbuf->ptr[j + max_str_size - 1];
859 		}
860 
861 		if (!cptr) {
862 		    if (BIT(sbuf->state, SOCKBUF_DGRAM | SOCKBUF_LOCK) != 0) {
863 			failure = 3;
864 		    }
865 		    if (Sockbuf_read(sbuf) == -1) {
866 			failure = 2;
867 		    }
868 
869 		    /* Try to find a \0 in the socket buffer */
870 		    cptr = memchr(&sbuf->ptr[j], '\0', sbuf->len + sbuf->buf - sbuf->ptr - j);
871 
872 		    /* Are there enough bytes in the socket buffer anyway? */
873 		    if (!cptr && &sbuf->ptr[j + max_str_size] <= &sbuf->buf[sbuf->len]) {
874 			/* Set cptr to point to the last character */
875 			cptr = &sbuf->ptr[j + max_str_size - 1];
876 		    }
877 
878 		    if (!cptr) {
879 			failure = 3;
880 		    }
881 		}
882 
883 		if (!failure) {
884 		    long len;
885 		    len = cptr - sbuf->ptr - j + 1;
886 
887 		    /* Limit the length to max_str_size (including the \0) */
888 		    if (len > max_str_size) {
889 			len = max_str_size;
890 		    }
891 
892 		    /* Copy the string */
893 		    memcpy(str, &sbuf->ptr[j], len);
894 
895 		    /* Terminate */
896 		    str[len - 1] = '\0';
897 
898 		    /* Consume the entire string in the socket buffer */
899 		    j += len;
900 		}
901 #endif
902 		if (failure) {
903 		    strcpy(str, "ErRoR");
904 		}
905 		break;
906 	    default:
907 		failure = 1;
908 		break;
909 	    }
910 	} else {
911 	    failure = 1;
912 	}
913     }
914     if (failure == 1) {
915 	errno = 0;
916 	plog(format("Error in format string (%s)", fmt));
917     }
918     else if (failure == 3) {
919 	/* Not enough input for one complete packet */
920 	count = 0;
921 	failure = 0;
922     }
923     else if (failure == 0) {
924 	if (&sbuf->buf[sbuf->len] < &sbuf->ptr[j]) {
925 	    errno = 0;
926 	    plog(format("Input buffer exceeded (%s)", fmt));
927 	    failure = 1;
928 	} else {
929 	    sbuf->ptr += j;
930 	}
931     }
932 
933     va_end(ap);
934 
935     return (failure) ? -1 : count;
936 }
937 
938