~ubuntu-branches/ubuntu/feisty/liquidwar/feisty

1 by Eduard Bloch
Import upstream version 5.4.5
1
/********************************************************************/
2
/*                                                                  */
3
/*            L   I  QQ  U U I DD    W   W  A  RR    555            */
4
/*            L   I Q  Q U U I D D   W   W A A R R   5              */
5
/*            L   I Q  Q U U I D D   W W W AAA RR    55             */
6
/*            L   I Q Q  U U I D D   WW WW A A R R     5            */
7
/*            LLL I  Q Q  U  I DD    W   W A A R R   55             */
8
/*                                                                  */
9
/*                             b                                    */
10
/*                             bb  y y                              */
11
/*                             b b yyy                              */
12
/*                             bb    y                              */
13
/*                                 yy                               */
14
/*                                                                  */
15
/*                     U U       FFF  O   O  TTT                    */
16
/*                     U U       F   O O O O  T                     */
17
/*                     U U TIRET FF  O O O O  T                     */
18
/*                     U U       F   O O O O  T                     */
19
/*                      U        F    O   O   T                     */
20
/*                                                                  */
21
/********************************************************************/
22
23
/*****************************************************************************/
24
/* Liquid War is a unique multiplayer wargame                                */
25
/* Copyright (C) 1998-2002 Christian Mauduit                                 */
26
/*                                                                           */
27
/* This program is free software; you can redistribute it and/or modify      */
28
/* it under the terms of the GNU General Public License as published by      */
29
/* the Free Software Foundation; either version 2 of the License, or         */
30
/* (at your option) any later version.                                       */
31
/*                                                                           */
32
/* This program is distributed in the hope that it will be useful,           */
33
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
34
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
35
/* GNU General Public License for more details.                              */
36
/*                                                                           */
37
/* You should have received a copy of the GNU General Public License         */
38
/* along with this program; if not, write to the Free Software               */
39
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
40
/*                                                                           */
41
/* Liquid War homepage : http://www.ufoot.org/liquidwar                      */
42
/* Contact author      : ufoot@ufoot.org                                     */
43
/*****************************************************************************/
44
45
/********************************************************************/
46
/* name          : sockw32.c                                        */
47
/* content       : simple wrappers on the winsock API               */
48
/* last update   : April 13th 2001                                  */
49
/********************************************************************/
50
51
/*==================================================================*/
52
/* includes                                                         */
53
/*==================================================================*/
54
55
#ifdef WIN32
56
#include <winsock.h>
57
#else
58
#include <netinet/in.h>
59
#include <arpa/inet.h>
60
#include <sys/socket.h>
61
#include <sys/types.h>
62
#include <sys/time.h>
63
#include <unistd.h>
64
#include <fcntl.h>
65
#include <signal.h>
66
#endif
67
68
#include <stdlib.h>
69
#include <time.h>
70
#include <string.h>
71
#include <ctype.h>
72
#include <errno.h>
73
74
#include "sockgen.h"
75
#include "log.h"
76
77
/*==================================================================*/
78
/* defines                                                          */
79
/*==================================================================*/
80
81
#define LW_SOCK_RECV_SEC                  8
82
#define LW_SOCK_RECV_USEC                 0 
83
#define LW_SOCK_SEND_SEC                  8
84
#define LW_SOCK_SEND_USEC                 0 
85
86
#define LW_SOCK_SEND_BUFFER_SIZE        100
87
#define LW_SOCK_RECV_BUFFER_SIZE        200
88
89
/*==================================================================*/
90
/* macros                                                           */
91
/*==================================================================*/
92
93
#ifndef MIN
94
#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
95
#endif
96
#ifndef MAX
97
#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
98
#endif
99
100
/*==================================================================*/
101
/* globals                                                          */
102
/*==================================================================*/
103
104
/*==================================================================*/
105
/* static fonctions                                                 */
106
/*==================================================================*/
107
108
static void clean_buffer(char *buffer,int len);
109
110
/*==================================================================*/
111
/* fonctions                                                        */
112
/*==================================================================*/
113
114
/*------------------------------------------------------------------*/
115
/*
116
 * Cleans up a message buffer from all characters which are not
117
 * plain standard ASCII. Used for logging information.
118
 */
119
static void clean_buffer(char *buffer,int len)
120
{
121
  int i;
122
123
  for (i=0;i<len;++i)
124
    {
125
      if (!isalnum(buffer[i]) && buffer[i]!='-' && buffer[i]!='+')
126
	{
127
	  buffer[i]='.';
128
	}
129
    }
130
}
131
132
/*------------------------------------------------------------------*/
133
/*
134
 * Returns true if the given number bytes is available on the socket
135
 */
136
int lw_sock_peek_ex(int sock,int len)
137
{
138
  int result=0;
139
  int res;
140
  fd_set read;
141
  struct timeval tv;
142
  char buffer[LW_SOCK_MESSAGE_SIZE];
143
144
  if (len<=LW_SOCK_MESSAGE_SIZE-1)
145
    {
146
      FD_ZERO(&read);
147
      FD_SET(sock,&read);
148
      tv.tv_sec=0;
149
      tv.tv_usec=0;
150
      res=select(sock+1,&read,NULL,NULL,&tv);
151
      if (res>0)
152
	{
153
	  if (FD_ISSET(sock,&read))
154
	    {
155
	      /* 
156
	       * First we test if there's enough data available
157
	       */
158
	      if (recv(sock,buffer,len,MSG_PEEK)==len)
159
		{
160
		  result=1;
161
		}
162
	    }
163
	}
164
    }
165
166
  return result;
167
}
168
169
/*------------------------------------------------------------------*/
170
/*
171
 * Sends a string on the network.
172
 * The advantage of this function over a raw "send" is that it does
173
 * a "strlen" automatically to know the length of the string, and
174
 * adds a tailing "\n" so that the message is "telnet compliant"
175
 */
176
int lw_sock_send_str_ex(int sock, char *str)
177
{
178
  int result=1;
179
  int len;
180
  char buffer[LW_SOCK_MESSAGE_SIZE];
181
  fd_set write;
182
  struct timeval tv;
183
  int res;
184
  int total_sent;
185
  int sent;
186
187
  /*
188
   * We put the string in a buffer, since we'll probably have
189
   * to modify it (cut if it's too long, add a tailing '\n').
190
   */
191
  len=strlen(str);
192
  len=MIN(len,LW_SOCK_MESSAGE_SIZE-2);
193
  strncpy(buffer,str,len);
194
  buffer[len]='\n';
195
  ++len;
196
  buffer[len]='\0';  
197
198
  total_sent=0;
199
  while (total_sent<len && result)
200
    {
201
      FD_ZERO(&write);
202
      FD_SET(sock,&write);
203
      tv.tv_sec=LW_SOCK_SEND_SEC;
204
      tv.tv_usec=LW_SOCK_SEND_USEC;
205
206
      errno=0;
207
      res=select(sock+1,NULL,&write,NULL,&tv);
208
209
      switch (res)
210
	{
211
	case -1:
212
	  if (errno!=EINTR)
213
	    {
214
	      result=0;
215
	    }
216
	  break;
217
	case 1:
218
	  if (FD_ISSET(sock,&write))
219
	    {
220
	      sent=send(sock,buffer+total_sent,len-total_sent,0);
221
	      if (sent>0 && sent<=len-total_sent)
222
		{
223
		  total_sent+=sent;
224
		}
225
	      else
226
		{
227
		  result=0;
228
		}
229
	    }
230
	  break;
231
	default:
232
	  result=0;
233
	}
234
    }
235
236
  if (LW_SOCK_LOG)
237
    {
238
      if (result)
239
	{
240
	  log_print_int(sock);
241
	  log_print_str(" > \"");
242
	  log_print_str(str);
243
	  log_print_str("\"");
244
	  log_println();
245
	  log_flush();
246
	}
247
      else
248
	{
249
	  log_print_int(sock);
250
	  log_print_str(" > timeout!");
251
	  log_println();
252
	}
253
    }
254
255
  return result;
256
}
257
258
/*------------------------------------------------------------------*/
259
/*
260
 * Receives some data from the network.
261
 * A tailing "\n" is expected. The routine handles both chr(10) and chr(13)
262
 * correctly so that the program can be used with telnet under UNIX or
263
 * windows without much trouble.
264
 * This tailing "\n" is removed, so the return string is just the exact
265
 * message which has been send with sock_send.
266
 * Buffer must be able to accept at least LW_SOCK_MESSAGE_SIZE chars.
267
 * Note that the function will not block forever, if there's no incoming
268
 * for more than a #define specified amount of time, it will return
269
 * an error.
270
 */
271
int lw_sock_recv_str_ex(int sock, char *str)
272
{
273
  int result=1;
274
  int pos,l;
275
  int cr_found;
276
  char *cr;
277
  fd_set read;
278
  struct timeval tv;
279
  int res;
280
281
  /*
282
   * We keep on trying to get data until
283
   * - we get a '\n' character
284
   * - the size of incoming data exceeds LW_SOCK_MESSAGE_SIZE
285
   * - there's a reception low level error
286
   */
287
  cr_found=0;
288
  pos=0;
289
  str[0]='\0';
290
  while (!cr_found && pos<LW_SOCK_MESSAGE_SIZE-1 && result>0)
291
    {
292
      FD_ZERO(&read);
293
      FD_SET(sock,&read);
294
      tv.tv_sec=LW_SOCK_RECV_SEC;
295
      tv.tv_usec=LW_SOCK_RECV_USEC;
296
297
      errno=0;
298
      res=select(sock+1,&read,NULL,NULL,&tv);
299
300
      switch (res)
301
	{
302
	case -1:
303
	  if (errno!=EINTR)
304
	    {
305
	      result=0;
306
	    }
307
	  break;
308
	case 1:
309
	  /*
310
	   * We check that the event we just received concerns the socket
311
	   * we are polling. If the event is not for us, let's consider
312
	   * everything is fine...
313
	   */
314
	  if (!FD_ISSET(sock,&read))
315
	    {
316
	      result=1;
317
	    }
318
	  else
319
	    {
320
	      /*
321
	       * We get the caracters one by one. This is a performance
322
	       * killer but we don't care since this routine is only
323
	       * used at the very beginning of the game, when the players
324
	       * are connecting themselves. And it has the *big* advantage
325
	       * that "netkeys" are not eaten up by this routine. More
326
	       * precisely, there's used to be a bug because when reading
327
	       * the final "OK" message, the clients read some netkeys
328
	       * along with it, which caused some network inconsistency
329
	       * since the messages had "disappeared".
330
	       */
331
	      if ((l=recv(sock,str+pos,1,0))<=0)
332
		{
333
		  /*
334
		   * OK, now we have received a message on this socket
335
		   * but there's no data. In most of the cases this means
336
		   * the socket is dead, so we return -1 instead of 0
337
		   * so that the caller can make the difference between
338
		   * a timeout (0) and a dead socket (-1).
339
		   */ 
340
		  result=-1;
341
		}
342
	      else
343
		{
344
		  /*
345
		   * pos is an offset in the buffer. It is used to keep a
346
		   * trace of where new data should be appended in case we
347
		   * have to call recv several times to retrieve the whole
348
		   * message.
349
		   */
350
		  pos+=l;
351
		  /*
352
		   * We add a tailing '\0' so that the string is "C compliant"
353
		   */
354
		  str[pos]=0;
355
		  /*
356
		   * We seek for character 10, which should be '\n'
357
		   */
358
		  if ((cr=strchr(str,10))!=NULL)
359
		    {
360
		      cr_found=1;
361
		      /*
362
		       * We handle the special character '13' for very often,
363
		       * especially when using telnet, the strings come
364
		       * with char(13)chr(10) at the end. So if it happens
365
		       * that after removing the 10 there's still a 13, then
366
		       * we remove the 13 as well.
367
		       */
368
		      if ((cr-str)>=1 && (*(cr-1))==13)
369
			{
370
			  /*
371
			   * Let's cut this ugly "ascii 13" character
372
			   * along with "ascii 10"
373
			   */
374
			  (*(cr-1))=0;
375
			}
376
		      else
377
			{	
378
			  /*
379
			   * No "ascii 13" in sight, simply remove "ascii 10"
380
			   */
381
			  (*cr)=0;
382
			}
383
		    }
384
		  result=1;
385
		}
386
	    }
387
	  break;
388
	default:
389
	  result=0;
390
	}
391
    }
392
393
  if (LW_SOCK_LOG)
394
    {
395
      if (result)
396
	{
397
	  log_print_int(sock);
398
	  log_print_str(" < \"");
399
	  log_print_str(str);
400
	  log_print_str("\"");
401
	  log_println();
402
	  log_flush();
403
	}
404
      else
405
	{
406
	  log_print_int(sock);
407
	  log_print_str(" < timeout!");
408
	  log_println();
409
	}
410
    }
411
412
  return result;
413
}
414
415
/*------------------------------------------------------------------*/
416
/*
417
 * Sends a buffer on the network.
418
 * Only a standard send wrapper
419
 */
420
int lw_sock_send_buffer_ex(int sock, char *buffer,int len)
421
{
422
  int result=1;
423
  char trace[LW_SOCK_MESSAGE_SIZE];
424
  fd_set write;
425
  struct timeval tv;
426
  int res;
427
  int total_sent;
428
  int sent;
429
430
  if (len<=LW_SOCK_MESSAGE_SIZE-1)
431
    {
432
      total_sent=0;
433
      while (total_sent<len && result)
434
	{
435
	  FD_ZERO(&write);
436
	  FD_SET(sock,&write);
437
	  tv.tv_sec=LW_SOCK_SEND_SEC;
438
	  tv.tv_usec=LW_SOCK_SEND_USEC;
439
440
	  errno=0;
441
	  res=select(sock+1,NULL,&write,NULL,&tv);
442
	  
443
	  switch (res)
444
	    {
445
	    case -1:
446
	      if (errno!=EINTR)
447
		{
448
		  result=0;
449
		}
450
	      break;
451
	    case 1:
452
	      if (FD_ISSET(sock,&write))
453
		{
454
		  sent=send(sock,
455
			    buffer+total_sent,
456
			    MIN(len-total_sent,
457
				LW_SOCK_SEND_BUFFER_SIZE),
458
			    0);
459
		  if (sent>0 && sent<=len-total_sent)
460
		    {
461
		      total_sent+=sent;
462
		    }
463
		  else
464
		    {
465
		      result=0;
466
		    }
467
		}
468
	      break;
469
	    default:
470
	      result=0;
471
	    }
472
	}
473
      
474
      if (LW_SOCK_LOG)
475
	{
476
	  if (result)
477
	    {
478
	      strncpy(trace,buffer,len);
479
	      trace[len]='\0';
480
	      log_print_int(sock);
481
	      log_print_str(" > [");
482
	      clean_buffer(trace,len);
483
	      log_print_str(trace);
484
	      log_print_str("]");
485
	      log_println();
486
	      log_flush();
487
	    }
488
	  else
489
	    {
490
	      log_print_int(sock);
491
	      log_print_str(" > timeout!");
492
	      log_println();
493
	    }
494
	}
495
    }
496
  else
497
    {
498
      result=0;
499
      if (LW_SOCK_LOG)
500
	{
501
	  log_print_int(sock);
502
	  log_print_str(" > message too large!");
503
	  log_println();
504
	}
505
    }
506
507
  return result;
508
}
509
510
/*------------------------------------------------------------------*/
511
/*
512
 * Receives a buffer on the network.
513
 * Only a standard recv wrapper
514
 */
515
int lw_sock_recv_buffer_ex(int sock, char *buffer,int len)
516
{
517
  int result=1;
518
  char trace[LW_SOCK_MESSAGE_SIZE];
519
  int res;
520
  fd_set read;
521
  struct timeval tv;
522
  int total_received;
523
  int received;
524
525
  if (len<=LW_SOCK_MESSAGE_SIZE-1)
526
    {
527
      total_received=0;
528
      while (total_received<len && result)
529
	{
530
	  FD_ZERO(&read);
531
	  FD_SET(sock,&read);
532
	  tv.tv_sec=LW_SOCK_RECV_SEC;
533
	  tv.tv_usec=LW_SOCK_RECV_USEC;
534
535
	  errno=0;
536
	  res=select(sock+1,&read,NULL,NULL,&tv);
537
538
	  switch (res)
539
	    {
540
	    case -1:
541
	      if (errno!=EINTR)
542
		{
543
		  result=0;
544
		}
545
	      break;
546
	    case 1:
547
	      if (FD_ISSET(sock,&read))
548
		{
549
		  received=recv(sock,
550
				buffer+total_received,
551
				MIN(len-total_received,
552
				    LW_SOCK_RECV_BUFFER_SIZE),
553
				0);
554
		  if (received>0 && received<=len-total_received)
555
		    {
556
		      total_received+=received;
557
		    }
558
		  else
559
		    {
560
		      result=0;
561
		    }
562
		}
563
	      break;
564
	    default:
565
	      result=0;
566
	    }
567
	}
568
      
569
      if (LW_SOCK_LOG)
570
	{
571
	  if (result)
572
	    {
573
	      strncpy(trace,buffer,len);
574
	      trace[len]='\0';
575
	      log_print_int(sock);
576
	      log_print_str(" < [");
577
	      clean_buffer(trace,len);
578
	      log_print_str(trace);
579
	      log_print_str("]");
580
	      log_println();
581
	      log_flush();
582
	    }
583
	  else
584
	    {
585
	      log_print_int(sock);
586
	      log_print_str(" < timeout!");
587
	      log_println();
588
	    }
589
	}
590
    }
591
  else
592
    {
593
      result=0;
594
      if (LW_SOCK_LOG)
595
	{
596
	  log_print_int(sock);
597
	  log_print_str(" < message too large!");
598
	  log_println();
599
	}
600
    }
601
602
  return result;
603
}
604
605