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

« back to all changes in this revision

Viewing changes to src/sockex.c

  • Committer: Bazaar Package Importer
  • Author(s): Eduard Bloch
  • Date: 2002-03-15 10:25:19 UTC
  • Revision ID: james.westby@ubuntu.com-20020315102519-oh5c0i7s7j7pbtay
Tags: upstream-5.4.5
ImportĀ upstreamĀ versionĀ 5.4.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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