1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_tcp.c 1548 2020-09-29 10:26:04Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2000 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: i_tcp.c,v $
20 // Revision 1.40 2004/04/20 00:34:26 andyp
21 // Linux compilation fixes and string cleanups
22 //
23 // Revision 1.39 2003/05/04 02:31:53 sburke
24 // Added many #ifdef, #ifndef SOLARIS.
25 //
26 // Revision 1.38 2003/01/19 21:24:26 bock
27 // Make sources buildable on FreeBSD 5-CURRENT.
28 //
29 // Revision 1.37 2001/08/26 15:27:29 bpereira
30 // added fov for glide and fixed newcoronas code
31 //
32 // Revision 1.36 2001/08/21 21:53:37 judgecutor
33 // Fixed incorect place of #include "d_main.h"
34 //
35 // Revision 1.35 2001/08/20 20:40:39 metzgermeister
36 //
37 // Revision 1.34 2001/05/16 22:33:34 bock
38 // Initial FreeBSD support.
39 //
40 // Revision 1.33 2001/02/24 13:35:20 bpereira
41 // Revision 1.32 2001/02/10 12:27:13 bpereira
42 //
43 // Revision 1.31 2001/01/05 18:17:43 hurdler
44 // fix master server bug
45 //
46 // Revision 1.30 2000/11/26 00:46:31 hurdler
47 // Revision 1.29 2000/10/21 08:43:29 bpereira
48 // Revision 1.28 2000/10/16 20:02:29 bpereira
49 // Revision 1.27 2000/10/08 13:30:00 bpereira
50 //
51 // Revision 1.26 2000/10/01 15:20:23 hurdler
52 // Add private server
53 //
54 // Revision 1.25 2000/09/28 20:57:15 bpereira
55 // Revision 1.24 2000/09/15 19:49:22 bpereira
56 // Revision 1.23 2000/09/10 10:43:21 metzgermeister
57 //
58 // Revision 1.22 2000/09/08 22:28:30 hurdler
59 // merge masterserver_ip/port in one cvar, add -private
60 //
61 // Revision 1.21 2000/09/01 18:23:42 hurdler
62 // fix some issues with latest network code changes
63 //
64 // Revision 1.20 2000/08/31 14:30:55 bpereira
65 //
66 // Revision 1.19 2000/08/29 15:53:47 hurdler
67 // Remove master server connect timeout on LAN (not connected to Internet)
68 //
69 // Revision 1.18 2000/08/21 11:06:44 hurdler
70 // Add ping and some fixes
71 //
72 // Revision 1.17 2000/08/17 23:18:05 hurdler
73 // fix bad port sent to master server when using -udpport
74 //
75 // Revision 1.16 2000/08/16 23:39:41 hurdler
76 // fix a bug with windows sockets
77 //
78 // Revision 1.15 2000/08/16 17:21:50 hurdler
79 // update master server code (bis)
80 //
81 // Revision 1.14 2000/08/16 15:44:18 hurdler
82 // update master server code
83 //
84 // Revision 1.13 2000/08/16 14:10:01 hurdler
85 // add master server code
86 //
87 // Revision 1.12 2000/08/10 14:55:56 ydario
88 // OS/2 port
89 //
90 // Revision 1.11 2000/08/10 14:08:48 hurdler
91 // Revision 1.10 2000/08/03 17:57:42 bpereira
92 //
93 // Revision 1.9 2000/04/21 13:03:27 hurdler
94 // apply Robert's patch for SOCK_Get error. Boris, can you verify this?
95 //
96 // Revision 1.8 2000/04/21 00:01:45 hurdler
97 // apply Robert's patch for SOCK_Get error. Boris, can you verify this?
98 //
99 // Revision 1.7 2000/04/16 18:38:07 bpereira
100 // Revision 1.6 2000/03/29 19:39:48 bpereira
101 //
102 // Revision 1.5 2000/03/08 14:44:52 hurdler
103 // fix "select" problem under linux
104 //
105 // Revision 1.4 2000/03/07 03:32:24 hurdler
106 // fix linux compilation
107 //
108 // Revision 1.3 2000/03/06 15:46:43 hurdler
109 // Revision 1.2 2000/02/27 00:42:10 hurdler
110 // Revision 1.1.1.1 2000/02/22 20:32:32 hurdler
111 // Initial import into CVS (v1.29 pr3)
112 //
113 //
114 // DESCRIPTION:
115 // NOTE: This is not realy Os dependant because all Os have the same Socket api
116 // Just use '#ifdef' for Os dependant stuffs
117 //
118 //-----------------------------------------------------------------------------
119
120 #include <stdlib.h>
121 #include <string.h>
122 #include <stdio.h>
123
124 #ifdef __OS2__
125 // sys/types.h is also included unconditionally by doomincl.h
126 # include <sys/types.h>
127 // [MB] 2020-06-18: Maybe required for old Unix too
128 # include <sys/time.h>
129 #endif // __OS2__
130
131 #include "doomincl.h"
132
133 #ifdef __WIN32__
134 # include <winsock2.h>
135 # include <ws2tcpip.h>
136 # ifdef USE_IPX
137 # include <wsipx.h>
138 # endif // USE_IPX
139
140 #else
141 // Not Windows
142
143 # if !defined(SCOUW2) && !defined(SCOUW7) && !defined(__OS2__)
144 # include <arpa/inet.h>
145 # endif
146
147 // non-windows includes
148 #include <sys/socket.h>
149 #include <netinet/in.h>
150 #include <fcntl.h>
151 // [MB] 2020-06-18: For fcntl()
152 #include <unistd.h>
153 #include <netdb.h>
154 #include <sys/ioctl.h>
155 #include <errno.h>
156 #include <time.h>
157
158
159 // Enable debug_Printf stmts
160 //#define NET_NODE_DEBUG 1
161
162 // Just some standard length for a char string
163 #define STD_STRING_LEN 256
164
165 // [WDJ] FIXME: Add some test of IPX headers being present.
166 // When someone puts an IPX package on their system, this will prevent
167 // using it.
168
169 #ifdef SOLARIS
170 // Previous code: Solaris did not have IPX.
171 # ifdef USE_IPX
172 # undef USE_IPX
173 # endif
174 #endif
175
176 #ifdef NETBSD
177 // NetBSD does not have IPX.
178 # ifdef USE_IPX
179 # undef USE_IPX
180 # endif
181 #endif
182
183 // Reported to be __OpenBSD__ , but it should be all caps and I am paranoid.
184 #if defined( __OpenBSD__ ) || defined( __OPENBSD__ )
185 // OpenBSD does not have IPX.
186 # ifdef USE_IPX
187 # undef USE_IPX
188 # endif
189 #endif
190
191 #ifdef __DJGPP__
192 #include <lsck/lsck.h>
193 #ifdef USE_IPX
194 //#define strerror lsck_strerror
195 // ipx not yet supported in libsocket (cut and pasted from wsipx.h (winsock)
196 // [WDJ] Updated to stdint
197 typedef struct sockaddr_ipx {
198 int16_t sa_family;
199 char sa_netnum[4];
200 char sa_nodenum[6];
201 uint16_t sa_socket;
202 } SOCKADDR_IPX, *PSOCKADDR_IPX;
203 #define NSPROTO_IPX 1000
204 #endif // USE_IPX
205 #endif // djgpp
206
207
208 #ifdef __OS2__
209 #ifdef USE_IPX
210 // ipx not yet supported in libsocket (cut and pasted from wsipx.h (winsock)
211 #define AF_IPX 23 /* Novell Internet Protocol */
212 // [WDJ] Updated to stdint.
213 typedef struct sockaddr_ipx {
214 int16_t sa_family;
215 char sa_netnum[4];
216 char sa_nodenum[6];
217 uint16_t sa_socket;
218 } SOCKADDR_IPX, *PSOCKADDR_IPX;
219 #define NSPROTO_IPX 1000
220 #endif // USE_IPX
221 #endif // os2
222
223 #ifdef MACOS_DI
224 // [WDJ] 4/2015 Merged macos/i_tcp.c here, very few significant differences.
225 // They did not have any IPX code. It would need includes.
226 # undef USE_IPX
227 #endif
228
229 #ifdef LINUX
230 # include <sys/time.h>
231 # ifdef USE_IPX
232 # ifdef __GLIBC__
233 # include <netipx/ipx.h>
234 # else
235 # ifdef FREEBSD
236 # include <netipx/ipx.h>
237 # else
238 # include <linux/ipx.h>
239 # endif
240 # endif // glibc
241 typedef struct sockaddr_ipx SOCKADDR_IPX, *PSOCKADDR_IPX;
242 # define NSPROTO_IPX PF_IPX
243 # endif // USE_IPX
244 #endif // linux
245
246 // END of Not Windows
247 #endif // win32
248
249 #ifdef __APPLE__
250 // IPX is not supported on macOS
251 # ifdef USE_IPX
252 # undef USE_IPX
253 # endif
254 #endif
255
256 #include "i_system.h"
257 #include "i_net.h"
258 #include "d_net.h"
259 #include "m_argv.h"
260 #include "command.h"
261 #include "d_main.h"
262
263 #include "doomstat.h"
264 #include "mserv.h" //Hurdler: support master server
265
266 #ifdef __WIN32__
267 // some undefined under win32
268 # ifdef errno
269 # undef errno
270 # endif
271 // some very strange things happen when not use h_error ?!?
272 # define errno h_errno
273 #else
274 // linux, djgpp, os2, non-windows
275 # define SOCKET int
276 # define INVALID_SOCKET -1
277 #endif
278
279 #if defined( WIN32) || defined( __DJGPP__ )
280 // win32 or djgpp
281 // winsock stuff (in winsock a socket is not a file)
282 # define ioctl ioctlsocket
283 # define close closesocket
284 #endif
285
286 #ifdef USE_IPX
287 static boolean ipx_select;
288 #endif
289
290 // Set default sock_port to 5029, which is necessary to find a server on the network.
291 // If this actually ever moved, we would have to ensure uniformity over all systems.
292 #ifdef IPPORT_USERRESERVED
293 # if IPPORT_USERRESERVED != 5000
294 # warning IPPORT_USERRESERVED non-standard, DoomLegacy uses sock port 5029.
295 # endif
296 #else
297 # define IPPORT_USERRESERVED 5000
298 #endif
299 // [WDJ] If there are variations, set it to 5029 to keep all servers uniform.
300 //#define IPPORT_SERVER 5029
301 #define IPPORT_SERVER (IPPORT_USERRESERVED +0x1d )
302
303 // Enable use of alternate client port range.
304 #define CLIENT_SOCK_PORT_SEARCH 1
305 // Alternate port addresses for clients.
306 #define IPPORT_CLIENT 7000
307 #define IPPORT_CLIENT_MAX 7099
308
309
310 // IP port numbers are 16 bit.
311 uint16_t server_sock_port = IPPORT_SERVER;
312 static uint16_t client_sock_port = IPPORT_SERVER; // default
313 static uint16_t my_sock_port = 0; // From UDP_Socket or IPX_Socket
314
315 static SOCKET mysocket = -1;
316
317
318 // A network address, kept in network byte order.
319 typedef union {
320 struct sockaddr_in ip;
321 #ifdef USE_IPX
322 struct sockaddr_ipx ipx;
323 #endif
324 } mysockaddr_t;
325
326 // Player and additional net nodes.
327 static mysockaddr_t clientaddress[MAX_CON_NETNODE];
328
329
330 // Enables node_hash functions.
331 // When off, use a generic node hash.
332 #define NODE_ADDR_HASHING
333
334 // Contains address hash, is 0 when unused. Hash is not allowed to be 0.
335 // Node connected when node_hash > 0.
336 // To receive, node_hash must have been set to hash of clientaddress.
337 // To send, any hash value > 0 will enable. Using 1 will not allow receive.
338 static byte node_hash[MAX_CON_NETNODE];
339
340 #ifdef NODE_ADDR_HASHING
341 // Customized hash function.
342 byte (*SOCK_hashaddr) (mysockaddr_t *a);
343 #else
344 // For all network types.
345 static
generic_hashaddr(mysockaddr_t * a)346 byte generic_hashaddr( mysockaddr_t *a )
347 {
348 // For any structure.
349 // Not allowed to be 0. Always node_hash is connected flag.
350 byte * p = &(a->ip);
351 return (p[0] ^ p[3]) | 0x80;
352 }
353 #endif
354
355
356
357 // Network is big-endian, 386,486,586 PC are little-endian.
358 // htons: host to net byte order
359 // ntohs: net to host byte order
360
361 #if defined( SOLARIS)
362 // [WDJ] Was using init_aton defined below ..., DoomLegacy 1.48 and before.
363 // [MB] 2020-06-18: Use native inet_aton() on Solaris
364 // Solaris has inet_aton() in libresolv since version 2.6 from 1997
365 #endif
366 #if defined( WIN32) || defined( __OS2__)
367 // [WDJ] Also defined in mserv.c, but too small, will be inlined anyway.
368 static inline
inet_aton(const char * hostname,struct in_addr * addr)369 int inet_aton(const char *hostname,
370 /* OUT */ struct in_addr *addr)
371 {
372 // [WDJ] This cannot handle 255.255.255.255, which == INADDR_NONE.
373 addr->s_addr = inet_addr(hostname);
374 return ( addr->s_addr != INADDR_NONE );
375 }
376 #endif
377
378 // To print error messages
SOCK_AddrToStr(mysockaddr_t * sk)379 char *SOCK_AddrToStr(mysockaddr_t *sk)
380 {
381 static char s[50];
382
383 if( sk->ip.sin_family==AF_INET)
384 {
385 // Internet address
386 sprintf(s,"%d.%d.%d.%d:%d",((byte *)(&(sk->ip.sin_addr.s_addr)))[0],
387 ((byte *)(&(sk->ip.sin_addr.s_addr)))[1],
388 ((byte *)(&(sk->ip.sin_addr.s_addr)))[2],
389 ((byte *)(&(sk->ip.sin_addr.s_addr)))[3],
390 ntohs(sk->ip.sin_port));
391 }
392 #ifdef USE_IPX
393 else
394 #ifdef LINUX
395 if( sk->ipx.sipx_family==AF_IPX )
396 {
397 # ifdef FREEBSD
398 // FreeBSD IPX
399 sprintf(s,"%s", ipx_ntoa(sk->ipx.sipx_addr));
400 # else
401 // Linux IPX, but Not FreeBSD
402 sprintf(s,"%08x.%02x%02x%02x%02x%02x%02x:%d",
403 # if 1
404 ntohl(sk->ipx.sipx_network), // big_endian, 32bit
405 # else
406 sk->ipx.sipx_network,
407 # endif
408 (byte)sk->ipx.sipx_node[0],
409 (byte)sk->ipx.sipx_node[1],
410 (byte)sk->ipx.sipx_node[2],
411 (byte)sk->ipx.sipx_node[3],
412 (byte)sk->ipx.sipx_node[4],
413 (byte)sk->ipx.sipx_node[5],
414 sk->ipx.sipx_port);
415 # endif
416 }
417 #else
418 // IPX Windows, OS2, DJGPP
419 if( sk->ipx.sa_family==AF_IPX )
420 {
421 // IPX address
422 sprintf(s,"%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%d",
423 (byte)sk->ipx.sa_netnum[0],
424 (byte)sk->ipx.sa_netnum[1],
425 (byte)sk->ipx.sa_netnum[2],
426 (byte)sk->ipx.sa_netnum[3],
427 (byte)sk->ipx.sa_nodenum[0],
428 (byte)sk->ipx.sa_nodenum[1],
429 (byte)sk->ipx.sa_nodenum[2],
430 (byte)sk->ipx.sa_nodenum[3],
431 (byte)sk->ipx.sa_nodenum[4],
432 (byte)sk->ipx.sa_nodenum[5],
433 sk->ipx.sa_socket);
434 }
435 #endif // linux
436 #endif // USE_IPX
437 else
438 sprintf(s,"Unknown type");
439 return s;
440 }
441
442 #ifdef USE_IPX
IPX_cmpaddr(mysockaddr_t * a,mysockaddr_t * b)443 boolean IPX_cmpaddr(mysockaddr_t *a, mysockaddr_t *b)
444 {
445 #ifdef LINUX
446 # ifdef FREEBSD
447 // FreeBSD: IPX address compare
448 return ipx_neteq( a->ipx.sipx_addr, b->ipx.sipx_addr) &&
449 ipx_hosteq( a->ipx.sipx_addr, b->ipx.sipx_addr );
450 # else
451 // Linux (except FreeBSD): IPX address compare
452 return ((memcmp(&(a->ipx.sipx_network) ,&(b->ipx.sipx_network) ,4)==0) &&
453 (memcmp(&(a->ipx.sipx_node),&(b->ipx.sipx_node),6)==0));
454 # endif
455 #else
456 // Windows, OS2, DJGPP: IPX address compare
457 return ((memcmp(&(a->ipx.sa_netnum) ,&(b->ipx.sa_netnum) ,4)==0) &&
458 (memcmp(&(a->ipx.sa_nodenum),&(b->ipx.sa_nodenum),6)==0));
459 #endif // linux
460 }
461
462 #ifdef NODE_ADDR_HASHING
IPX_hashaddr(mysockaddr_t * a)463 byte IPX_hashaddr(mysockaddr_t *a)
464 {
465 // Not allowed to be 0.
466 // Big endian, want final addr byte.
467 #ifdef LINUX
468 # ifdef FREEBSD
469 return ((byte)(a->ipx.sipx_addr.x_host.c_host[5])) | 0x80;
470 # else
471 // Linux: IPX address hash
472 return ((byte)(a->ipx.sipx_node[5])) | 0x80;
473 # endif
474 #else
475 // Windows, OS2, DJGPP: IPX address hash
476 return ((byte)(a->ipx.sa_nodenum[5])) | 0x80;
477 #endif // linux
478 }
479 #endif
480
481 #endif // USE_IPX
482
UDP_cmpaddr(mysockaddr_t * a,mysockaddr_t * b)483 boolean UDP_cmpaddr(mysockaddr_t *a, mysockaddr_t *b)
484 {
485 #ifdef MACOS_DI
486 return (a->ip.sin_addr.s_addr == b->ip.sin_addr.s_addr);
487 #else
488 return (a->ip.sin_addr.s_addr == b->ip.sin_addr.s_addr
489 && a->ip.sin_port == b->ip.sin_port);
490 #endif
491 }
492
493 #ifdef NODE_ADDR_HASHING
UDP_hashaddr(mysockaddr_t * a)494 byte UDP_hashaddr(mysockaddr_t *a)
495 {
496 // Not allowed to be 0.
497 // Big endian, want final addr byte.
498 return ((byte*)(&(a->ip.sin_addr.s_addr)))[3] | 0x80;
499 }
500 #endif
501
502
503 // Indirect function for net address compare.
504 boolean (*SOCK_cmpaddr) (mysockaddr_t *a, mysockaddr_t *b);
505
506
507 // Set address and port of utility net nodes.
508 // saddr: IP address in network byte order
509 // port: port number in host byte order
510 // Called by: Bind_Node_str, mserv:MS_open_UDP_Socket
UDP_Bind_Node(int nnode,unsigned int saddr,uint16_t port)511 void UDP_Bind_Node( int nnode, unsigned int saddr, uint16_t port )
512 {
513 clientaddress[nnode].ip.sin_family = AF_INET;
514 clientaddress[nnode].ip.sin_port = htons(port);
515 clientaddress[nnode].ip.sin_addr.s_addr = saddr;
516 #ifdef NODE_ADDR_HASHING
517 node_hash[nnode] = UDP_hashaddr( &clientaddress[nnode] );
518 #else
519 node_hash[nnode] = generic_hashaddr( &clientaddress[nnode] );
520 #endif
521 }
522
523
524 // Setup broadcast address to BROADCAST_NODE entry.
525 // To send broadcasts, PT_ASKINFO.
526 // [WDJ] Broadcast address for network "192.168.1.x" is "192.168.1.255".
527 // INADDR_BROADCAST is "255.255.255.255" which gives network unreachable.
528
529 // By Client.
530 // IPX or inet.
531 // Bind an inet or ipx address string to a net node.
532 // addrstr: net address in special format
533 // port: port number in host byte order
534 // Called by: CL_Broadcast_AskInfo
Bind_Node_str(int nnode,char * addrstr,uint16_t port)535 boolean Bind_Node_str( int nnode, char * addrstr, uint16_t port )
536 {
537 mysockaddr_t address;
538
539 if( addrstr == NULL ) goto addr_fail;
540 if( addrstr[0] < '0' ) goto addr_fail;
541
542 #ifdef USE_IPX
543 if(ipx_select)
544 {
545 // Network byte order is big-endian first.
546 int cnt;
547
548 # ifdef LINUX
549 // IPX address format (HEX) "7F20540F:5C0020040101"
550 // Keep it big-endian order, so do not have to convert.
551 byte ba[11];
552 cnt = sscanf(addrstr,
553 "%02hhx%02hhx%02hhx%02hhx.%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
554 &ba[0], &ba[1], &ba[2], &ba[3],
555 &ba[4], &ba[5], &ba[6], &ba[7], &ba[8], &ba[9] );
556 if( cnt != 10 ) goto addr_fail; // need exactly 10 digits
557
558 clientaddress[nnode].ipx.sipx_family = AF_IPX;
559 clientaddress[nnode].ipx.sipx_port = htons(port);
560 # ifdef FREEBSD
561 // FreeBSD
562 // network: ipx.sipx_addr.xnet.s_net[0..1] 16 bit, big endian
563 // addr: ipx.sipx_addr.x_host.c_host[0..5] 8 bit
564 memcpy(&clientaddress[nnode].ipx.sipx_addr.x_net.s_net[0], &ba[0], 4 );
565 memcpy(&clientaddress[nnode].ipx.sipx_addr.x_host.c_host[0], &ba[4], 6 );
566 # else
567 // Linux, but Not FreeBSD
568 // network: ipx.sipx_network 32 bit, big endian
569 // addr: ipx.sipx_node[0..5] 8 bit
570 memcpy(&clientaddress[nnode].ipx.sipx_network, &ba[0], 4 );
571 memcpy(&clientaddress[nnode].ipx.sipx_node[0], &ba[4], 6 );
572 # endif
573 # else
574 // Windows, etc.
575 // IPX address format (HEX) "7F20540F:5C0020040101"
576 // Keep it big-endian order, so do not have to convert.
577 // Windows is missing the hh conversion, at least in MINGW.
578 int i;
579 int ib[4], ic[6];
580 cnt = sscanf(addrstr,
581 "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x",
582 &ib[0], &ib[1], &ib[2], &ib[3],
583 &ic[0], &ic[1], &ic[2], &ic[3], &ic[4], &ic[5] );
584 if( cnt != 10 ) goto addr_fail; // need exactly 10 digits
585
586 // Convert int to byte, keeping BIG endian.
587 // network: ipx.sa_netnum[0..3] 8 bit
588 // addr: ipx.sa_nodenum[0..5] 8 bit
589 for( i=0; i<4; i++ )
590 clientaddress[nnode].ipx.sa_netnum[i] = ib[i];
591 for( i=0; i<6; i++ )
592 clientaddress[nnode].ipx.sa_nodenum[i] = ic[i];
593 # endif // linux
594
595 #if 0
596 # ifdef NODE_ADDR_HASHING
597 node_hash[nnode] = IPX_hashaddr( &clientaddress[nnode] );
598 # else
599 node_hash[nnode] = generic_hashaddr( &clientaddress[nnode] );
600 # endif
601 #else
602 node_hash[nnode] = 1; // send only
603 #endif
604 }
605 else
606 #endif // IPX
607 {
608 // INET
609 if( ! inet_aton( addrstr, &address.ip.sin_addr ) )
610 goto addr_fail;
611
612 UDP_Bind_Node( nnode, address.ip.sin_addr.s_addr, port );
613 }
614 #ifdef NET_NODE_DEBUG
615 // DEBUG
616 debug_Printf( "Bind Node %d to %s\n", nnode,
617 SOCK_AddrToStr( &clientaddress[nnode] ) );
618 #endif
619 return true;
620
621 addr_fail:
622 return false;
623 }
624
625
626 // Return net node. When nodes full, return 255.
get_freenode(void)627 static byte get_freenode( void )
628 {
629 byte nn;
630
631 // Only this range is dynamically allocated, the others are preallocated.
632 for( nn=1; nn<MAXNETNODES; nn++) // self is not free
633 {
634 if( node_hash[nn] == 0 )
635 {
636 node_hash[nn]=1; // enable send, but hash is needed to receive
637 return nn;
638 }
639 }
640 return 255;
641 }
642
643 // Function for I_NetFreeNode().
644 // IPX or inet.
645 static
SOCK_FreeNode(byte nnode)646 void SOCK_FreeNode( byte nnode )
647 {
648 // MAX_CON_NETNODE is preallocated.
649 // can't disconnect to self :)
650 if( (nnode == 0) || (nnode >= MAXNETNODES) )
651 return;
652
653 #ifdef DEBUGFILE
654 if( debugfile )
655 {
656 fprintf(debugfile,"Free node %d (%s)\n",
657 nnode, SOCK_AddrToStr(&clientaddress[nnode]));
658 }
659 #endif
660
661 // Disconnect and invalidate address.
662 node_hash[nnode] = 0;
663 memset(&clientaddress[nnode], 0, sizeof(clientaddress[nnode]));
664 }
665
666
667 //Hurdler: something is wrong with Robert's patch and win2k
668 // Function for I_NetGet().
669 // IPX or inet. Server and client.
670 // Return packet into doomcom struct.
671 // Return 0 when got packet, else net_error. Error in net_error.
672 // Called by: HGetPacket
673 static
SOCK_Get(void)674 byte SOCK_Get(void)
675 {
676 uint32_t errno2;
677 byte nnode; // index to net_nodes[]
678 #ifdef NODE_ADDR_HASHING
679 byte hashaddr;
680 #endif
681 int rcnt; // data bytes received
682 #ifdef MACOS_DI
683 size_t fromlen;
684 #else
685 socklen_t fromlen;
686 #endif
687 mysockaddr_t fromaddress;
688
689 fromlen = sizeof(fromaddress); // num bytes of addr for OUT
690 // fromaddress: OUT the actual address.
691 // fromlen: IN sizeof fromaddress, OUT the actual length of the address.
692 #ifdef LINUX
693 rcnt = recvfrom(mysocket,
694 &doomcom->data, // packet
695 MAXPACKETLENGTH, // packet length
696 0, // flags
697 /*OUT*/ (struct sockaddr *)&fromaddress, // net address
698 /*IN,OUT*/ &fromlen ); // net address length
699 #else
700 // winsock.h recvfrom(SOCKET, char*, int, int, struct sockaddr*, int*)
701 rcnt = recvfrom(mysocket,
702 // Some other port requires (char*), undocumented.
703 (char *)&doomcom->data,
704 MAXPACKETLENGTH, // packet length
705 0, // flags
706 /*OUT*/ (struct sockaddr *)&fromaddress, // net address
707 /*IN,OUT*/ &fromlen ); // net address length
708 #endif
709 if(rcnt < 0) goto recv_err;
710
711 // DEBFILE(va("Get from %s\n",SOCK_AddrToStr(&fromaddress)));
712
713 // Find remote node number, player nodes only.
714 #ifdef NODE_ADDR_HASHING
715 hashaddr = SOCK_hashaddr( &fromaddress ); // hash != 0
716 // debug_Printf( "hashaddr=%d\n", hashaddr );
717 #else
718 hashaddr = generic_hashaddr( &fromaddress ); // hash != 0
719 #endif
720 for (nnode=0; nnode<MAXNETNODES; nnode++)
721 {
722 // [WDJ] avoid testing null addresses.
723 if( node_hash[nnode] != hashaddr ) continue;
724
725 if( SOCK_cmpaddr(&fromaddress, &(clientaddress[nnode])) )
726 goto return_node; // found match
727 }
728
729 // Net node not found.
730 nnode = get_freenode(); // Find a free node.
731 if(nnode >= MAXNETNODES) goto no_nodes;
732
733 // clientaddress is IP addr and sock port.
734 // SOCK_Send will use nnode to send back to this clientaddress.
735 memcpy(&clientaddress[nnode], &fromaddress, fromlen);
736
737 // Set node_hash[nnode] to enable receive.
738 node_hash[nnode] = hashaddr;
739
740 #ifdef DEBUGFILE
741 if( debugfile )
742 {
743 fprintf(debugfile,"New node detected: node:%d address:%s\n",
744 nnode, SOCK_AddrToStr(&clientaddress[nnode]));
745 }
746 #endif
747
748 return_node:
749 doomcom->remotenode = nnode; // good packet from a game player
750 doomcom->datalength = rcnt;
751 return NE_success;
752
753 // Rare errors
754 recv_err:
755 errno2 = errno; // save it, print will overwrite it
756 // Send failed, determine the error.
757 #ifdef __WIN32__
758 if(errno2 == WSAEWOULDBLOCK || errno2 == WSATRY_AGAIN ) // no message
759 #else
760 if(errno2 == EWOULDBLOCK || errno2 == EAGAIN) // no message
761 #endif
762 {
763 net_error = NE_empty; // no packet
764 goto no_packet;
765 }
766
767 #ifdef __WIN32__
768 if( (errno2 == WSAEMSGSIZE) // message too large
769 || (errno2 == WSAECONNREFUSED) ) // connection refused
770 #else
771 if( (errno2 == EMSGSIZE) // message too large
772 || (errno2 == ECONNREFUSED) ) // connection refused
773 #endif
774 {
775 net_error = NE_fail;
776 goto no_packet;
777 }
778
779 I_SoftError("SOCK_Get: %s \n Error %x (%d)\n",
780 strerror(errno2), errno2, errno2);
781
782 // Recoverable conditions.
783 #ifdef __WIN32__
784 if( errno2 == WSAECONNRESET || errno2 == WSAECONNABORTED )
785 #else
786 // Linux
787 if( errno2 == ECONNRESET || errno2 == ECONNABORTED )
788 #endif
789 {
790 net_error = NE_network_reset; // transient condition
791 goto no_packet;
792 }
793
794 #ifdef __WIN32__
795 if( errno2 == WSAENETUNREACH || errno2 == WSAEFAULT || errno2 == WSAEBADF )
796 #else
797 if( errno2 == ENETUNREACH || errno2 == EFAULT || errno2 == EBADF )
798 #endif
799 {
800 // network unreachable
801 net_error = NE_network_unreachable; // allows test net without crashing
802 goto no_packet;
803 }
804 // Many other errors.
805 // Because of new errors, give it a chance to recover or reset.
806 net_error = NE_unknown_net_error;
807 goto no_packet;
808
809 no_nodes:
810 #ifdef DEBUGFILE
811 // node table full
812 if( debugfile )
813 fprintf(debugfile,"SOCK_Get: Free nodes all used.\n");
814 #endif
815 net_error = NE_nodes_exhausted;
816 goto no_packet;
817
818 no_packet:
819 doomcom->remotenode = -1; // no packet
820 return net_error;
821 }
822
823
824 static fd_set write_set; // Linux: modified by select
825
826 // Function for I_NetCanSend().
827 // Check if we can send (to save a buffer transfer).
828 static
SOCK_CanSend(void)829 boolean SOCK_CanSend(void)
830 {
831 // [WDJ] Linux: select modifies timeval, so it must be init with each call.
832 struct timeval timeval_0 = {0,0}; // immediate
833 int stat;
834
835 // [WDJ] Linux: write_set is modified by the select call, so it must
836 // be init each call. Smaller code with write_set static global.
837 FD_ZERO(&write_set);
838 FD_SET(mysocket, &write_set);
839 // huh Boris, are you sure about the 1th argument:
840 // it is the highest-numbered descriptor in any of the three
841 // sets, plus 1 (I suppose mysocket + 1).
842 // BP:ok, no prob since it is ignored in windows :)
843 // Linux: select man page specifies (highest file descriptor + 1).
844 // winsock.h: select(int, fd_set*, fd_set*, fd_set*, const struct timeval*)
845 // [WDJ] MACOS_DI had select( 1, ... ) but I do not think that was correct.
846 stat = select(mysocket + 1,
847 NULL, // read fd
848 /*IN,OUT*/ &write_set, // write fd to watch
849 NULL, // exceptions
850 /*IN,OUT*/ &timeval_0 // timeout
851 );
852 return ( stat > 0 );
853 }
854
855
856 // Function for I_NetSend().
857 // IPX or inet.
858 // Send packet from within doomcom struct.
859 // Return 0 when got packet, else net_error. Error in net_error.
SOCK_Send(void)860 byte SOCK_Send(void)
861 {
862 uint32_t errno2;
863 byte nnode = doomcom->remotenode;
864 int cnt; // chars sent
865
866 if( node_hash[nnode] == 0 ) goto node_unconnected;
867
868 // sockaddr is defined in sys/socket.h
869 // MSG_DONTROUTE: Do not use a gateway, local network only.
870 // MSG_DONTWAIT: Do not block.
871 #ifdef LINUX
872 cnt = sendto(mysocket,
873 &doomcom->data, doomcom->datalength, // packet
874 0, // flags
875 (struct sockaddr *)&clientaddress[nnode], // net address
876 sizeof(struct sockaddr)); // net address length
877 #else
878 // winsock.h: sendto(SOCKET, char*, int, int, struct sockaddr*, int)
879 cnt = sendto(mysocket,
880 // Some other port requires (char*), undocumented.
881 (char *)&doomcom->data, doomcom->datalength, // packet
882 0, // flags
883 (struct sockaddr *)&clientaddress[nnode], // net address
884 sizeof(struct sockaddr)); // net address length
885 #endif
886
887 // DEBFILE(va("send to %s\n",SOCK_AddrToStr(&clientaddress[doomcom->remotenode])));
888 if( cnt < 0 ) goto send_err;
889 return NE_success;
890
891 // Rare error.
892 send_err:
893 errno2 = errno; // save it, print will overwrite it
894 // if( errno2 == ENOBUFS ) // out of buffer space
895 #ifdef __WIN32__
896 if( errno2 == WSAEWOULDBLOCK || errno2 == WSATRY_AGAIN )
897 #else
898 // Linux
899 // ECONNREFUSED can be got in linux port.
900 if( errno2 == ECONNREFUSED || errno2 == EWOULDBLOCK || errno2 == EAGAIN )
901 #endif
902 {
903 net_error = NE_refused_again; // silent
904 goto err_return;
905 }
906
907 I_SoftError("SOCK_Send to node %d (%s): %s\n Error %x (%d)\n",
908 nnode, SOCK_AddrToStr(&clientaddress[nnode]),
909 strerror(errno2), errno2, errno2);
910
911 // Recoverable conditions.
912 #ifdef __WIN32__
913 if( errno2 == WSAECONNRESET || errno2 == WSAECONNABORTED )
914 #else
915 // Linux
916 if( errno2 == ECONNRESET || errno2 == ECONNABORTED )
917 #endif
918 {
919 net_error = NE_network_reset; // transient condition
920 goto err_return;
921 }
922
923 //#if defined(WIN32) && defined(__MINGW32__)
924 #ifdef __WIN32__
925 if( errno2 == WSAENETUNREACH || errno2 == WSAEFAULT || errno2 == WSAEBADF )
926 #else
927 // Linux
928 if( errno2 == ENETUNREACH || errno2 == EFAULT || errno2 == EBADF )
929 #endif
930 {
931 // network unreachable
932 net_error = NE_network_unreachable; // allows test net without crashing
933 goto err_return;
934 }
935 // Many other errors.
936 #if 1
937 // Because of new errors, give it a chance to recover or reset.
938 net_error = NE_unknown_net_error;
939 goto err_return;
940 #else
941 I_Error("SOCK_Send\n");
942 #endif
943
944 node_unconnected:
945 net_error = NE_node_unconnected;
946 goto err_return;
947
948 err_return:
949 return net_error;
950 }
951
952
953
954 // UDPsocket
955 // Server or Client.
956 //
957 // TCP, UDP: Called by SOCK_OpenSocket
958 // Called by: CL_Update_ServerList, Command_connect
UDP_Socket(void)959 static SOCKET UDP_Socket (void)
960 {
961 const char * msg = "";
962 SOCKET s;
963 struct sockaddr_in address;
964 #if defined(WIN32) && defined(__MINGW32__)
965 u_long trueval = true;
966 #else
967 int trueval = true;
968 #endif
969 int optval;
970 socklen_t optlen;
971 int stat;
972
973 // allocate a socket
974 s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
975 if (s<0 || s==INVALID_SOCKET)
976 {
977 msg = "Create socket failed";
978 goto no_socket;
979 }
980
981 memset (&address, 0, sizeof(address));
982 address.sin_family = AF_INET;
983 address.sin_addr.s_addr = INADDR_ANY;
984
985 #ifdef CLIENT_SOCK_PORT_SEARCH
986 retry_bind:
987 #endif
988
989 my_sock_port = (server)? server_sock_port : client_sock_port;
990 #ifdef NET_NODE_DEBUG
991 debug_Printf( "UDP_Socket my_sock_port = %d\n", my_sock_port );
992 #endif
993 address.sin_port = htons(my_sock_port);
994 stat = bind (s, (struct sockaddr *)&address, sizeof(address) );
995 if (stat == -1)
996 {
997 #ifdef CLIENT_SOCK_PORT_SEARCH
998 #ifdef WIN32
999 if( (errno == WSAEADDRINUSE)
1000 #else
1001 if( (errno == EADDRINUSE)
1002 #endif
1003 && ! server
1004 && (client_sock_port < IPPORT_CLIENT_MAX) )
1005 {
1006 // Try alternative client sock ports.
1007 client_sock_port = (client_sock_port < IPPORT_CLIENT)? IPPORT_CLIENT : client_sock_port+1;
1008 goto retry_bind;
1009 }
1010 #endif
1011 msg = "Bind failed";
1012 goto close_socket;
1013 }
1014 CONS_Printf("Network port: %d\n", my_sock_port);
1015
1016 // make it non blocking
1017 #ifdef LINUX
1018 // [MB] 2020-06-18: Use portable POSIX way to enable non-blocking mode
1019 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html
1020 // [WDJ] POSIX.1-2001 : F_SETFL
1021 // Windows: Winsock does not have fcntl.
1022 {
1023 int res = fcntl(s, F_SETFL, O_NONBLOCK);
1024 if( res == -1 )
1025 {
1026 msg = "Switch to non-blocking mode failed";
1027 goto close_socket;
1028 }
1029 }
1030 #else
1031 // [WDJ] DoomLegacy 1.48.4 and before.
1032 // Does not work on: SunOS (SmartOS and maybe Solaris).
1033 // Linux: still defined in asm-generic/ioctls.h
1034 // Needed for Windows, and older ports.
1035 ioctl (s, FIONBIO, &trueval);
1036 #endif
1037
1038 // make it broadcastable
1039 #ifdef LINUX
1040 stat = setsockopt(s, SOL_SOCKET, SO_BROADCAST,
1041 &trueval, // option value
1042 sizeof(trueval)); // length of value
1043 #else
1044 // [WDJ] They must treat optval as a char buffer.
1045 // winsock.h: getsockopt(SOCKET, int, int, char*, int*)
1046 stat = setsockopt(s, SOL_SOCKET, SO_BROADCAST,
1047 // Some other port requires (char*), undocumented.
1048 (char *)&trueval, // option value
1049 sizeof(trueval)); // length of value
1050 #endif
1051
1052 #ifdef NET_NODE_DEBUG
1053 // Set SO_DEBUG
1054 #ifdef LINUX
1055 stat = setsockopt(s, SOL_SOCKET, SO_DEBUG,
1056 &trueval, // option value
1057 sizeof(trueval)); // length of value
1058 #else
1059 // winsock.h: getsockopt(SOCKET, int, int, char*, int*)
1060 stat = setsockopt(s, SOL_SOCKET, SO_DEBUG,
1061 // Some other port requires (char*), undocumented.
1062 (char *)&trueval, // option value
1063 sizeof(trueval)); // length of value
1064 #endif
1065 #endif
1066
1067 // Set Network receive buffer size.
1068 optlen=sizeof(optval); // Linux: gets modified
1069 // optval: gets the value of the option
1070 // optlen: gets the actual length of the option
1071 #ifdef LINUX
1072 stat = getsockopt(s, SOL_SOCKET, SO_RCVBUF,
1073 /* OUT */ &optval, // option value
1074 /* IN,OUT */ &optlen); // available length
1075 #else
1076 // FIXME: so an int value is written to a (char *); portability!!!!!!!
1077 // [WDJ] They must treat optval as a char buffer.
1078 // winsock.h: getsockopt(SOCKET, int, int, char*, int*)
1079 stat = getsockopt(s, SOL_SOCKET, SO_RCVBUF,
1080 // Some other port requires (char*), undocumented.
1081 /* OUT */ (char *)&optval, // option value
1082 /* IN,OUT */ &optlen); // available length
1083 #endif
1084 CONS_Printf("Network receive buffer: %dKb\n", optval>>10);
1085
1086 if(optval < (64<<10)) // 64k
1087 {
1088 optval = (64<<10);
1089 #ifdef LINUX
1090 stat = setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1091 &optval,
1092 sizeof(optval));
1093 #else
1094 // winsock.h setsockopt(SOCKET, int, int, const char*, int)
1095 stat = setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1096 // Some other port requires (char*), undocumented.
1097 (char *)&optval,
1098 sizeof(optval));
1099 #endif
1100 if( stat < 0 )
1101 CONS_Printf("Network receive buffer: Failed to set buffer to 64k.\n");
1102 else
1103 CONS_Printf("Network receive buffer: set to %dKb\n", optval>>10);
1104 }
1105
1106 // ip + udp
1107 net_packetheader_length = 20 + 8; // for stats
1108
1109 // should not receive from self, but will set it up anyway.
1110 clientaddress[0].ip.sin_family = AF_INET;
1111 clientaddress[0].ip.sin_port = htons(my_sock_port);
1112 #ifdef MACOS_DI
1113 clientaddress[0].ip.sin_addr.s_addr = inet_addr("127.0.0.1");
1114 #else
1115 clientaddress[0].ip.sin_addr.s_addr = INADDR_LOOPBACK;
1116 // inet_addr("127.0.0.1");
1117 #endif
1118
1119 #ifdef NODE_ADDR_HASHING
1120 node_hash[0] = UDP_hashaddr( &clientaddress[0] );
1121 #else
1122 node_hash[0] = generic_hashaddr( &clientaddress[0] );
1123 #endif
1124
1125 // [WDJ] Broadcast is now setup at use by CL_Broadcast_AskInfo.
1126
1127 doomcom->extratics=1; // internet is very high ping
1128
1129 SOCK_cmpaddr=UDP_cmpaddr;
1130 #ifdef NODE_ADDR_HASHING
1131 SOCK_hashaddr=UDP_hashaddr;
1132 #endif
1133 return s;
1134
1135 close_socket:
1136 // Print error msg in no_socket.
1137 #ifdef __DJGPP__
1138 // bug in libsocket 0.7.4 beta 4 onder winsock 1.1 (win95)
1139 #else
1140 close(s);
1141 #endif
1142
1143 no_socket:
1144 // [WDJ] Common error, to control bloat.
1145 I_SoftError("UDP_socket: %s: %s\n", msg, strerror(errno));
1146 return -1;
1147 }
1148
1149
1150 #ifdef USE_IPX
1151 // Server or Client.
IPX_Socket(void)1152 static SOCKET IPX_Socket (void)
1153 {
1154 SOCKET s;
1155 SOCKADDR_IPX address;
1156 #if defined(WIN32) && defined(__MINGW32__)
1157 u_long trueval = true;
1158 #else
1159 int trueval = true;
1160 #endif
1161 int optval;
1162 socklen_t optlen;
1163 int stat;
1164
1165 // allocate a socket
1166 s = socket (AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
1167 if (s<0 || s==INVALID_SOCKET)
1168 {
1169 I_SoftError("IPX_socket: Create socket failed: %s\n", strerror(errno));
1170 goto no_ipx;
1171 }
1172
1173 #ifdef CLIENT_SOCK_PORT_SEARCH
1174 retry_bind:
1175 #endif
1176
1177 memset (&address, 0, sizeof(address));
1178 my_sock_port = (server)? server_sock_port : client_sock_port;
1179 #ifdef NET_NODE_DEBUG
1180 debug_Printf( "IPX_Socket my_sock_port = %d\n", my_sock_port );
1181 #endif
1182 #ifdef LINUX
1183 address.sipx_family = AF_IPX;
1184 address.sipx_port = htons(my_sock_port);
1185 #else
1186 address.sa_family = AF_IPX;
1187 address.sa_socket = htons(my_sock_port);
1188 #endif // linux
1189
1190 stat = bind (s, (struct sockaddr *)&address, sizeof(address));
1191 if( stat == -1)
1192 {
1193 #ifdef CLIENT_SOCK_PORT_SEARCH
1194 #ifdef WIN32
1195 if( (errno == WSAEADDRINUSE)
1196 #else
1197 if( (errno == EADDRINUSE)
1198 #endif
1199 && ! server
1200 && (client_sock_port < IPPORT_CLIENT_MAX) )
1201 {
1202 client_sock_port = (client_sock_port < IPPORT_CLIENT)? IPPORT_CLIENT : client_sock_port+1;
1203 goto retry_bind;
1204 }
1205 #endif
1206 I_SoftError("IPX_Socket: Bind failed: %s\n", strerror(errno));
1207 goto close_socket;
1208 }
1209 CONS_Printf("Network port: %d\n", my_sock_port);
1210
1211 // make it non blocking
1212 ioctl (s, FIONBIO, &trueval);
1213
1214 // make it broadcastable
1215 #ifdef LINUX
1216 stat = setsockopt(s, SOL_SOCKET, SO_BROADCAST,
1217 &trueval, // option value
1218 sizeof(trueval));
1219 #else
1220 // winsock.h: setsockopt(SOCKET, int, int, const char*, int)
1221 stat = setsockopt(s, SOL_SOCKET, SO_BROADCAST,
1222 // Some other port requires (char*), undocumented.
1223 (char *)&trueval, // option value
1224 sizeof(trueval));
1225 #endif
1226
1227 // Set Network receive buffer size.
1228 optlen=sizeof(optval); // gets modified
1229 // optval: gets the value of the option
1230 // optlen: gets the actual length of the option
1231 #ifdef LINUX
1232 stat = getsockopt(s, SOL_SOCKET, SO_RCVBUF,
1233 /* OUT */ &optval, // option value
1234 /* IN,OUT */ &optlen); // available length
1235 #else
1236 // FIXME: so an int value is written to a (char *); portability!!!!!!!
1237 // winsock.h getsockopt(SOCKET, int, int, char*, int*)
1238 stat = getsockopt(s, SOL_SOCKET, SO_RCVBUF,
1239 // Some other port requires (char*), undocumented.
1240 /* OUT */ (char *)&optval, // option value
1241 /* IN,OUT */ &optlen); // available length
1242 #endif
1243 // [WDJ] Had remnants of 64K. Set to 128K.
1244 CONS_Printf("Network receive buffer: %dKb\n", optval>>10);
1245 if(optval < (128<<10)) // 128K
1246 {
1247 optval = (128<<10);
1248 stat = setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1249 (char *)&optval,
1250 sizeof(optval));
1251 if( stat < 0 )
1252 CONS_Printf("Network receive buffer: Failed to set buffer to 128k.\n");
1253 else
1254 CONS_Printf("Network receive buffer: set to %dKb\n", optval>>10);
1255 }
1256
1257 // ipx header
1258 net_packetheader_length=30; // for stats
1259
1260 // [WDJ] Broadcast is now setup at use by CL_Broadcast_AskInfo.
1261
1262 SOCK_cmpaddr=IPX_cmpaddr;
1263 #ifdef NODE_ADDR_HASHING
1264 SOCK_hashaddr=IPX_hashaddr;
1265 #endif
1266 return s;
1267
1268 close_socket:
1269 #ifdef __DJGPP__
1270 // bug in libsocket 0.7.4 beta 4 onder winsock 1.1 (win95)
1271 #else
1272 close(s);
1273 #endif
1274
1275 no_ipx:
1276 return -1;
1277 }
1278 #endif // USE_IPX
1279
1280 //Hurdler: temporary addition and changes for master server
1281
1282 static byte TCP_driver_flag = 0;
1283
I_Init_TCP_Driver(void)1284 void I_Init_TCP_Driver(void)
1285 {
1286 if (!TCP_driver_flag)
1287 {
1288 #ifdef __WIN32__
1289 WSADATA winsockdata;
1290 if( WSAStartup(MAKEWORD(1,1),&winsockdata) )
1291 I_Error("No TCP/IP driver detected");
1292 #endif
1293 #ifdef __DJGPP_
1294 if( !__lsck_init() )
1295 I_Error("No TCP/IP driver detected");
1296 #endif
1297 TCP_driver_flag = 1;
1298 }
1299 }
1300
1301
1302 // Function for I_NetCloseSocket().
1303 // IPX or inet.
1304 static
SOCK_CloseSocket(void)1305 void SOCK_CloseSocket( void )
1306 {
1307 if( mysocket>=0 )
1308 {
1309 //if( server )
1310 // UnregisterServer();
1311 #ifdef __DJGPP__
1312 // quick fix bug in libsocket 0.7.4 beta 4 onder winsock 1.1 (win95)
1313 #else
1314 // Not DJGPP
1315 close(mysocket);
1316 #endif
1317 mysocket = -1;
1318 }
1319 }
1320
I_Shutdown_TCP_Driver(void)1321 void I_Shutdown_TCP_Driver(void)
1322 {
1323 //A.J. possible bug fix. I_ShutdownTcpDriver never used in Mac version
1324 if( mysocket!=-1 )
1325 SOCK_CloseSocket();
1326
1327 if ( TCP_driver_flag )
1328 {
1329 #ifdef __WIN32__
1330 WSACleanup();
1331 #endif
1332 #ifdef __DJGPP__
1333 __lsck_uninit();
1334 #endif
1335 TCP_driver_flag = 0;
1336 }
1337 }
1338
1339
1340 // Function for I_NetMakeNode().
1341 // Make a node for server address.
1342 // IPX or inet.
1343 // Called by CL_Update_ServerList
1344 // port is in the hostname
1345 // Called by Command_connect
1346 // connect to server at hostname (which may have port)
1347 // Called by mserv: MS_open_UDP_Socket if using player socket to contact MasterServer.
1348 // port is ping_port which is in the hostname.
1349 // Param:
1350 // hostname : string with network address of remote server
1351 // example "192.168.127.34:5034"
1352 // example "doomservers.net"
1353 // Return the net node number, or network_error_e > MAXNETNODES.
1354 static
SOCK_NetMakeNode(char * hostname)1355 byte SOCK_NetMakeNode (char *hostname)
1356 {
1357 byte newnode;
1358 mysockaddr_t newaddr;
1359 char * namestr; // owned copy of hostname string
1360 char *portchar;
1361 int portnum = server_sock_port; // target server port
1362
1363 // [WDJ] From command line can get "192.168.127.34:5234:"
1364 // From console only get ""192.168.127.34", the port portion is stripped.
1365 namestr = strdup(hostname);
1366 //debug_Printf( "Parm hostname=%s\n", namestr );
1367 // Split into ip address and port.
1368 char * st = namestr;
1369 strtok(st,":"); // overwrite the colon with a 0.
1370 portchar = strtok(NULL,":");
1371 if( portchar )
1372 {
1373 portnum = atoi(portchar);
1374 }
1375 // debug_Printf( " hostname=%s port=%i\n", namestr, portnum );
1376 CONS_Printf( " hostname=%s port=%i\n", namestr, portnum );
1377
1378 // server address only in ip
1379 #ifdef USE_IPX
1380 if(ipx_select)
1381 {
1382 // ipx only
1383 free(namestr);
1384 return BROADCAST_NODE;
1385 }
1386 #endif
1387
1388 // TCP/IP
1389 // Previous operation on namestr already parsed out the ip addr.
1390 //debug_Printf( " ip hostname=%s\n", namestr );
1391
1392 // Too early, but avoids resolving names we cannot use.
1393 newnode = get_freenode();
1394 if( newnode >= MAXNETNODES )
1395 goto no_nodes; // out of nodes
1396
1397 // Find the IP of the server.
1398 // [WDJ] This cannot handle addr 255.255.255.255 which == INADDR_NONE.
1399 newaddr.ip.sin_addr.s_addr = inet_addr(namestr);
1400 if(newaddr.ip.sin_addr.s_addr==INADDR_NONE) // not a ip, ask the dns
1401 {
1402 struct hostent * hostentry; // host information entry
1403 CONS_Printf("Resolving %s\n",namestr);
1404 hostentry = gethostbyname (namestr);
1405 if (!hostentry)
1406 {
1407 CONS_Printf ("%s unknown\n", namestr);
1408 I_NetFreeNode(newnode); // release the newnode
1409 goto abort_makenode;
1410 }
1411 newaddr.ip.sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
1412 }
1413 CONS_Printf("Resolved %s\n",
1414 inet_ntoa(*(struct in_addr *)&newaddr.ip.sin_addr.s_addr));
1415
1416 // Commit to the new node.
1417 clientaddress[newnode].ip.sin_family = AF_INET;
1418 clientaddress[newnode].ip.sin_port = htons(portnum);
1419 clientaddress[newnode].ip.sin_addr.s_addr = newaddr.ip.sin_addr.s_addr;
1420 #ifdef NODE_ADDR_HASHING
1421 node_hash[newnode] = SOCK_hashaddr( &newaddr ); // hash != 0
1422 #else
1423 node_hash[newnode] = generic_hashaddr( &newaddr ); // hash != 0
1424 #endif
1425
1426 clean_ret:
1427 free(namestr);
1428 return newnode;
1429
1430 // Rare errors.
1431 abort_makenode:
1432 newnode = NE_fail; // > MAXNETNODES
1433 goto clean_ret;
1434
1435 no_nodes:
1436 newnode = NE_nodes_exhausted; // > MAXNETNODES
1437 goto clean_ret;
1438 }
1439
1440
1441 // Function for I_NetOpenSocket().
1442 // Server or Client.
1443 // IPX or inet.
1444 // Called by: CL_Update_ServerList, Command_connect, SV_SpawnServer
1445 static
SOCK_OpenSocket(void)1446 boolean SOCK_OpenSocket( void )
1447 {
1448 memset(clientaddress,0,sizeof(clientaddress));
1449 #if 0
1450 memset(node_hash, 0, sizeof(node_hash));
1451 #else
1452 int i;
1453 for(i=1; i<MAX_CON_NETNODE; i++)
1454 node_hash[i] = 0;
1455 #endif
1456 node_hash[0] = 0x81; // always connected to self
1457
1458 I_NetSend = SOCK_Send;
1459 I_NetGet = SOCK_Get;
1460 I_NetCloseSocket = SOCK_CloseSocket;
1461 I_NetFreeNode = SOCK_FreeNode;
1462 I_NetMakeNode = SOCK_NetMakeNode;
1463
1464 #ifdef __WIN32__
1465 // seem like not work with libsocket nor linux :(
1466 I_NetCanSend = SOCK_CanSend;
1467 #else
1468 // [WDJ] Fixed, Linux can change select time.
1469 I_NetCanSend = SOCK_CanSend;
1470 #endif
1471
1472 // build the socket
1473 // Setup up Broadcast.
1474 #ifdef USE_IPX
1475 if(ipx_select) {
1476 mysocket = IPX_Socket ();
1477 net_bandwidth = 800000;
1478 hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
1479 }
1480 else
1481 #endif // USE_IPX
1482 {
1483 // TCP, UDP
1484 mysocket = UDP_Socket ();
1485 // if (server && cv_internetserver.value)
1486 // RegisterServer(mysocket, sock_port);
1487 }
1488
1489 return (mysocket >= 0);
1490 }
1491
1492
1493 // Called by D_Startup_NetGame
1494 // IPX or inet.
1495 // Called by: D_Startup_NetGame, MS_Connect
I_Init_TCP_Network(void)1496 void I_Init_TCP_Network( void )
1497 {
1498 char serverhostname[255];
1499
1500 #ifdef USE_IPX
1501 ipx_select = M_CheckParm("-ipx");
1502 #endif
1503
1504 // Initialize the driver.
1505 I_Init_TCP_Driver();
1506 #ifdef MACOS_DI
1507 // [WDJ] Do not know why they did not use I_Shutdown_TCP_Driver.
1508 #else
1509 I_AddExitFunc (I_Shutdown_TCP_Driver);
1510 #endif
1511
1512 if ( M_CheckParm ("-udpport") )
1513 {
1514 if( !M_IsNextParm() )
1515 I_Error("syntax : -udpport <portnum>");
1516 server_sock_port = atoi(M_GetNextParm());
1517 #ifdef NET_NODE_DEBUG
1518 debug_Printf( "Init_TCP server_sock_port = %d\n", server_sock_port );
1519 #endif
1520 }
1521
1522 //[WDJ]: Moved here so can be used for IPX too.
1523 //Hurdler: I'd like to put a server and a client on the same computer
1524 //BP: in fact for client we can use any free port we want, i have read
1525 // in some doc that connect in udp can do it for us...
1526 if( M_CheckParm ("-clientport") )
1527 {
1528 if( !M_IsNextParm() )
1529 I_Error("syntax : -clientport <portnum>");
1530 client_sock_port = atoi(M_GetNextParm());
1531 // If this this client port is in use, it may be changed.
1532 }
1533
1534 // parse network game options,
1535 if ( server )
1536 {
1537 // FIXME:
1538 // ??? and now ?
1539 // server on a big modem ??? 4*isdn
1540 net_bandwidth = 16000;
1541
1542 #ifdef MACOS_DI
1543 hardware_MAXPACKETLENGTH = 512;
1544 #else
1545 hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
1546 #endif
1547 }
1548 else if( M_CheckParm ("-connect") )
1549 {
1550 if(M_IsNextParm())
1551 strcpy(serverhostname,M_GetNextParm());
1552 else
1553 serverhostname[0]=0; // assuming server in the LAN, use broadcast to detect it
1554
1555 // server address only in ip
1556 if(serverhostname[0]
1557 #ifdef USE_IPX
1558 && !ipx_select
1559 #endif
1560 )
1561 {
1562 COM_BufAddText(va("connect \"%s\"\n", serverhostname ));
1563
1564 // probably modem
1565 hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
1566 }
1567 else
1568 {
1569 // so we're on a LAN
1570 COM_BufAddText("connect any\n");
1571
1572 net_bandwidth = 800000;
1573 hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
1574 }
1575 }
1576
1577 I_NetOpenSocket = SOCK_OpenSocket;
1578 }
1579