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 |