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