1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22
23 #include "../qcommon/q_shared.h"
24 #include "../qcommon/qcommon.h"
25
26 #ifdef _WIN32
27 #include <winsock2.h>
28 #include <ws2tcpip.h>
29 #if WINVER < 0x501
30 #include <wspiapi.h>
31 #else
32 #include <ws2spi.h>
33 #endif
34
35 typedef int socklen_t;
36 #ifdef ADDRESS_FAMILY
37 #define sa_family_t ADDRESS_FAMILY
38 #else
39 typedef unsigned short sa_family_t;
40 #endif
41
42 #define EAGAIN WSAEWOULDBLOCK
43 #define EADDRNOTAVAIL WSAEADDRNOTAVAIL
44 #define EAFNOSUPPORT WSAEAFNOSUPPORT
45 #define ECONNRESET WSAECONNRESET
46 #define socketError WSAGetLastError( )
47
48 static WSADATA winsockdata;
49 static qboolean winsockInitialized = qfalse;
50
51 #else
52
53 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
54 // needed for socklen_t on OSX 10.2
55 # define _BSD_SOCKLEN_T_
56 #endif
57
58 #include <sys/types.h>
59 #include <sys/socket.h>
60 #include <arpa/inet.h>
61 #include <errno.h>
62 #include <netdb.h>
63 #include <netinet/in.h>
64 #include <net/if.h>
65 #include <sys/ioctl.h>
66 #include <sys/time.h>
67 #include <unistd.h>
68 #if !defined(__sun) && !defined(__sgi)
69 #include <ifaddrs.h>
70 #endif
71
72 #ifdef __sun
73 #include <sys/filio.h>
74 #endif
75
76 typedef int SOCKET;
77 #define INVALID_SOCKET -1
78 #define SOCKET_ERROR -1
79 #define closesocket close
80 #define ioctlsocket ioctl
81 #define socketError errno
82
83 #endif
84
85 static qboolean usingSocks = qfalse;
86 static int networkingEnabled = 0;
87
88 #define NET_ENABLEV4 0x01
89 #define NET_ENABLEV6 0x02
90 // if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found.
91 #define NET_PRIOV6 0x04
92 // disables ipv6 multicast support if set.
93 #define NET_DISABLEMCAST 0x08
94
95 static cvar_t *net_enabled;
96
97 static cvar_t *net_socksEnabled;
98 static cvar_t *net_socksServer;
99 static cvar_t *net_socksPort;
100 static cvar_t *net_socksUsername;
101 static cvar_t *net_socksPassword;
102
103 static cvar_t *net_ip;
104 static cvar_t *net_ip6;
105 static cvar_t *net_port;
106 static cvar_t *net_port6;
107 static cvar_t *net_mcast6addr;
108 static cvar_t *net_mcast6iface;
109
110 static struct sockaddr socksRelayAddr;
111
112 static SOCKET ip_socket = INVALID_SOCKET;
113 static SOCKET ip6_socket = INVALID_SOCKET;
114 static SOCKET socks_socket = INVALID_SOCKET;
115 static SOCKET multicast6_socket = INVALID_SOCKET;
116
117 // Keep track of currently joined multicast group.
118 static struct ipv6_mreq curgroup;
119 // And the currently bound address.
120 static struct sockaddr_in6 boundto;
121
122 #ifndef IF_NAMESIZE
123 #define IF_NAMESIZE 16
124 #endif
125
126 // use an admin local address per default so that network admins can decide on how to handle quake3 traffic.
127 #define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533"
128
129 #define MAX_IPS 32
130
131 typedef struct
132 {
133 char ifname[IF_NAMESIZE];
134
135 netadrtype_t type;
136 sa_family_t family;
137 struct sockaddr_storage addr;
138 struct sockaddr_storage netmask;
139 } nip_localaddr_t;
140
141 static nip_localaddr_t localIP[MAX_IPS];
142 static int numIP;
143
144
145 //=============================================================================
146
147
148 /*
149 ====================
150 NET_ErrorString
151 ====================
152 */
NET_ErrorString(void)153 char *NET_ErrorString( void ) {
154 #ifdef _WIN32
155 //FIXME: replace with FormatMessage?
156 switch( socketError ) {
157 case WSAEINTR: return "WSAEINTR";
158 case WSAEBADF: return "WSAEBADF";
159 case WSAEACCES: return "WSAEACCES";
160 case WSAEDISCON: return "WSAEDISCON";
161 case WSAEFAULT: return "WSAEFAULT";
162 case WSAEINVAL: return "WSAEINVAL";
163 case WSAEMFILE: return "WSAEMFILE";
164 case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
165 case WSAEINPROGRESS: return "WSAEINPROGRESS";
166 case WSAEALREADY: return "WSAEALREADY";
167 case WSAENOTSOCK: return "WSAENOTSOCK";
168 case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
169 case WSAEMSGSIZE: return "WSAEMSGSIZE";
170 case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
171 case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
172 case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
173 case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
174 case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
175 case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
176 case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
177 case WSAEADDRINUSE: return "WSAEADDRINUSE";
178 case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
179 case WSAENETDOWN: return "WSAENETDOWN";
180 case WSAENETUNREACH: return "WSAENETUNREACH";
181 case WSAENETRESET: return "WSAENETRESET";
182 case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
183 case WSAECONNRESET: return "WSAECONNRESET";
184 case WSAENOBUFS: return "WSAENOBUFS";
185 case WSAEISCONN: return "WSAEISCONN";
186 case WSAENOTCONN: return "WSAENOTCONN";
187 case WSAESHUTDOWN: return "WSAESHUTDOWN";
188 case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
189 case WSAETIMEDOUT: return "WSAETIMEDOUT";
190 case WSAECONNREFUSED: return "WSAECONNREFUSED";
191 case WSAELOOP: return "WSAELOOP";
192 case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
193 case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
194 case WSASYSNOTREADY: return "WSASYSNOTREADY";
195 case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
196 case WSANOTINITIALISED: return "WSANOTINITIALISED";
197 case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
198 case WSATRY_AGAIN: return "WSATRY_AGAIN";
199 case WSANO_RECOVERY: return "WSANO_RECOVERY";
200 case WSANO_DATA: return "WSANO_DATA";
201 default: return "NO ERROR";
202 }
203 #else
204 return strerror (errno);
205 #endif
206 }
207
NetadrToSockadr(netadr_t * a,struct sockaddr * s)208 static void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) {
209 if( a->type == NA_BROADCAST ) {
210 ((struct sockaddr_in *)s)->sin_family = AF_INET;
211 ((struct sockaddr_in *)s)->sin_port = a->port;
212 ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
213 }
214 else if( a->type == NA_IP ) {
215 ((struct sockaddr_in *)s)->sin_family = AF_INET;
216 ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
217 ((struct sockaddr_in *)s)->sin_port = a->port;
218 }
219 else if( a->type == NA_IP6 ) {
220 ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
221 ((struct sockaddr_in6 *)s)->sin6_addr = * ((struct in6_addr *) &a->ip6);
222 ((struct sockaddr_in6 *)s)->sin6_port = a->port;
223 }
224 else if(a->type == NA_MULTICAST6)
225 {
226 ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6;
227 ((struct sockaddr_in6 *)s)->sin6_addr = curgroup.ipv6mr_multiaddr;
228 ((struct sockaddr_in6 *)s)->sin6_port = a->port;
229 }
230 }
231
232
SockadrToNetadr(struct sockaddr * s,netadr_t * a)233 static void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {
234 if (s->sa_family == AF_INET) {
235 a->type = NA_IP;
236 *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
237 a->port = ((struct sockaddr_in *)s)->sin_port;
238 }
239 else if(s->sa_family == AF_INET6)
240 {
241 a->type = NA_IP6;
242 memcpy(a->ip6, &((struct sockaddr_in6 *)s)->sin6_addr, sizeof(a->ip6));
243 a->port = ((struct sockaddr_in6 *)s)->sin6_port;
244 }
245 }
246
247
SearchAddrInfo(struct addrinfo * hints,sa_family_t family)248 static struct addrinfo *SearchAddrInfo(struct addrinfo *hints, sa_family_t family)
249 {
250 while(hints)
251 {
252 if(hints->ai_family == family)
253 return hints;
254
255 hints = hints->ai_next;
256 }
257
258 return NULL;
259 }
260
261 /*
262 =============
263 Sys_StringToSockaddr
264 =============
265 */
Sys_StringToSockaddr(const char * s,struct sockaddr * sadr,int sadr_len,sa_family_t family)266 static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int sadr_len, sa_family_t family)
267 {
268 struct addrinfo hints, *res = NULL, *search;
269 int retval;
270
271 memset(sadr, '\0', sizeof(*sadr));
272 memset(&hints, '\0', sizeof(hints));
273
274 hints.ai_family = family;
275
276 retval = getaddrinfo(s, NULL, &hints, &res);
277
278 if(!retval)
279 {
280 if(family == AF_UNSPEC)
281 {
282 // Decide here and now which protocol family to use
283 if((net_enabled->integer & NET_ENABLEV6) && (net_enabled->integer & NET_PRIOV6))
284 search = SearchAddrInfo(res, AF_INET6);
285 else
286 search = SearchAddrInfo(res, AF_INET);
287
288 if(!search)
289 {
290 if((net_enabled->integer & NET_ENABLEV6) &&
291 (net_enabled->integer & NET_PRIOV6) &&
292 (net_enabled->integer & NET_ENABLEV4))
293 search = SearchAddrInfo(res, AF_INET);
294 else if(net_enabled->integer & NET_ENABLEV6)
295 search = SearchAddrInfo(res, AF_INET6);
296 }
297 }
298 else
299 search = SearchAddrInfo(res, family);
300
301 if(search)
302 {
303 if(res->ai_addrlen > sadr_len)
304 res->ai_addrlen = sadr_len;
305
306 memcpy(sadr, res->ai_addr, res->ai_addrlen);
307 freeaddrinfo(res);
308
309 return qtrue;
310 }
311 else
312 Com_Printf("Sys_StringToSockaddr: Error resolving %s: No address of required type found.\n", s);
313 }
314 else
315 Com_Printf("Sys_StringToSockaddr: Error resolving %s: %s\n", s, gai_strerror(retval));
316
317 if(res)
318 freeaddrinfo(res);
319
320 return qfalse;
321 }
322
323 /*
324 =============
325 Sys_SockaddrToString
326 =============
327 */
Sys_SockaddrToString(char * dest,int destlen,struct sockaddr * input,int inputlen)328 static void Sys_SockaddrToString(char *dest, int destlen, struct sockaddr *input, int inputlen)
329 {
330 getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST);
331 }
332
333 /*
334 =============
335 Sys_StringToAdr
336 =============
337 */
Sys_StringToAdr(const char * s,netadr_t * a,netadrtype_t family)338 qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) {
339 struct sockaddr_storage sadr;
340 sa_family_t fam;
341
342 switch(family)
343 {
344 case NA_IP:
345 fam = AF_INET;
346 break;
347 case NA_IP6:
348 fam = AF_INET6;
349 break;
350 default:
351 fam = AF_UNSPEC;
352 break;
353 }
354 if( !Sys_StringToSockaddr(s, (struct sockaddr *) &sadr, sizeof(sadr), fam ) ) {
355 return qfalse;
356 }
357
358 SockadrToNetadr( (struct sockaddr *) &sadr, a );
359 return qtrue;
360 }
361
362 /*
363 ===================
364 NET_CompareBaseAdr
365
366 Compares without the port
367 ===================
368 */
NET_CompareBaseAdr(netadr_t a,netadr_t b)369 qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
370 {
371 if (a.type != b.type)
372 return qfalse;
373
374 if (a.type == NA_LOOPBACK)
375 return qtrue;
376
377 if (a.type == NA_IP)
378 {
379 if(!memcmp(a.ip, b.ip, sizeof(a.ip)))
380 return qtrue;
381
382 return qfalse;
383 }
384
385 if (a.type == NA_IP6)
386 {
387 if(!memcmp(a.ip6, b.ip6, sizeof(a.ip6)))
388 return qtrue;
389
390 return qfalse;
391 }
392
393 Com_Printf ("NET_CompareBaseAdr: bad address type\n");
394 return qfalse;
395 }
396
NET_AdrToString(netadr_t a)397 const char *NET_AdrToString (netadr_t a)
398 {
399 static char s[NET_ADDRSTRMAXLEN];
400
401 if (a.type == NA_LOOPBACK) {
402 Com_sprintf (s, sizeof(s), "loopback");
403 } else if (a.type == NA_BOT) {
404 Com_sprintf (s, sizeof(s), "bot");
405 }
406 else if (a.type == NA_IP || a.type == NA_IP6)
407 {
408 struct sockaddr_storage sadr;
409
410 memset(&sadr, 0, sizeof(sadr));
411 NetadrToSockadr(&a, (struct sockaddr *) &sadr);
412 Sys_SockaddrToString(s, sizeof(s), (struct sockaddr *) &sadr, sizeof(sadr));
413 }
414
415 return s;
416 }
417
NET_AdrToStringwPort(netadr_t a)418 const char *NET_AdrToStringwPort (netadr_t a)
419 {
420 static char s[NET_ADDRSTRMAXLEN];
421
422 if (a.type == NA_LOOPBACK) {
423 Com_sprintf (s, sizeof(s), "loopback");
424 } else if (a.type == NA_BOT) {
425 Com_sprintf (s, sizeof(s), "bot");
426 }
427 else if (a.type == NA_IP || a.type == NA_IP6)
428 {
429 if(a.type == NA_IP)
430 Com_sprintf(s, sizeof(s), "%s:%hu", NET_AdrToString(a), ntohs(a.port));
431 else if(a.type == NA_IP6)
432 Com_sprintf(s, sizeof(s), "[%s]:%hu", NET_AdrToString(a), ntohs(a.port));
433 }
434
435 return s;
436 }
437
438
NET_CompareAdr(netadr_t a,netadr_t b)439 qboolean NET_CompareAdr (netadr_t a, netadr_t b)
440 {
441 if(!NET_CompareBaseAdr(a, b))
442 return qfalse;
443
444 if (a.type == NA_IP || a.type == NA_IP6)
445 {
446 if (a.port == b.port)
447 return qtrue;
448 }
449 else
450 return qtrue;
451
452 return qfalse;
453 }
454
455
NET_IsLocalAddress(netadr_t adr)456 qboolean NET_IsLocalAddress( netadr_t adr ) {
457 return adr.type == NA_LOOPBACK;
458 }
459
460 //=============================================================================
461
462 /*
463 ==================
464 Sys_GetPacket
465
466 Never called by the game logic, just the system event queing
467 ==================
468 */
469 #ifdef _DEBUG
470 int recvfromCount;
471 #endif
472
Sys_GetPacket(netadr_t * net_from,msg_t * net_message)473 qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
474 int ret;
475 struct sockaddr_storage from;
476 socklen_t fromlen;
477 int err;
478
479 #ifdef _DEBUG
480 recvfromCount++; // performance check
481 #endif
482
483 if(ip_socket != INVALID_SOCKET)
484 {
485 fromlen = sizeof(from);
486 ret = recvfrom( ip_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen );
487
488 if (ret == SOCKET_ERROR)
489 {
490 err = socketError;
491
492 if( err != EAGAIN && err != ECONNRESET )
493 Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
494 }
495 else
496 {
497
498 memset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
499
500 if ( usingSocks && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) {
501 if ( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 ) {
502 return qfalse;
503 }
504 net_from->type = NA_IP;
505 net_from->ip[0] = net_message->data[4];
506 net_from->ip[1] = net_message->data[5];
507 net_from->ip[2] = net_message->data[6];
508 net_from->ip[3] = net_message->data[7];
509 net_from->port = *(short *)&net_message->data[8];
510 net_message->readcount = 10;
511 }
512 else {
513 SockadrToNetadr( (struct sockaddr *) &from, net_from );
514 net_message->readcount = 0;
515 }
516
517 if( ret == net_message->maxsize ) {
518 Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
519 return qfalse;
520 }
521
522 net_message->cursize = ret;
523 return qtrue;
524 }
525 }
526
527 if(ip6_socket != INVALID_SOCKET)
528 {
529 fromlen = sizeof(from);
530 ret = recvfrom(ip6_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
531
532 if (ret == SOCKET_ERROR)
533 {
534 err = socketError;
535
536 if( err != EAGAIN && err != ECONNRESET )
537 Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
538 }
539 else
540 {
541 SockadrToNetadr((struct sockaddr *) &from, net_from);
542 net_message->readcount = 0;
543
544 if(ret == net_message->maxsize)
545 {
546 Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
547 return qfalse;
548 }
549
550 net_message->cursize = ret;
551 return qtrue;
552 }
553 }
554
555 if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket)
556 {
557 fromlen = sizeof(from);
558 ret = recvfrom(multicast6_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen);
559
560 if (ret == SOCKET_ERROR)
561 {
562 err = socketError;
563
564 if( err != EAGAIN && err != ECONNRESET )
565 Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
566 }
567 else
568 {
569 SockadrToNetadr((struct sockaddr *) &from, net_from);
570 net_message->readcount = 0;
571
572 if(ret == net_message->maxsize)
573 {
574 Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
575 return qfalse;
576 }
577
578 net_message->cursize = ret;
579 return qtrue;
580 }
581 }
582
583
584 return qfalse;
585 }
586
587 //=============================================================================
588
589 static char socksBuf[4096];
590
591 /*
592 ==================
593 Sys_SendPacket
594 ==================
595 */
Sys_SendPacket(int length,const void * data,netadr_t to)596 void Sys_SendPacket( int length, const void *data, netadr_t to ) {
597 int ret = SOCKET_ERROR;
598 struct sockaddr_storage addr;
599
600 if( to.type != NA_BROADCAST && to.type != NA_IP && to.type != NA_IP6 && to.type != NA_MULTICAST6)
601 {
602 Com_Error( ERR_FATAL, "Sys_SendPacket: bad address type" );
603 return;
604 }
605
606 if( (ip_socket == INVALID_SOCKET && to.type == NA_IP) ||
607 (ip6_socket == INVALID_SOCKET && to.type == NA_IP6) ||
608 (ip6_socket == INVALID_SOCKET && to.type == NA_MULTICAST6) )
609 return;
610
611 if(to.type == NA_MULTICAST6 && (net_enabled->integer & NET_DISABLEMCAST))
612 return;
613
614 memset(&addr, 0, sizeof(addr));
615 NetadrToSockadr( &to, (struct sockaddr *) &addr );
616
617 if( usingSocks && to.type == NA_IP ) {
618 socksBuf[0] = 0; // reserved
619 socksBuf[1] = 0;
620 socksBuf[2] = 0; // fragment (not fragmented)
621 socksBuf[3] = 1; // address type: IPV4
622 *(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr;
623 *(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port;
624 memcpy( &socksBuf[10], data, length );
625 ret = sendto( ip_socket, socksBuf, length+10, 0, &socksRelayAddr, sizeof(socksRelayAddr) );
626 }
627 else {
628 if(addr.ss_family == AF_INET)
629 ret = sendto( ip_socket, data, length, 0, (struct sockaddr *) &addr, sizeof(struct sockaddr_in) );
630 else if(addr.ss_family == AF_INET6)
631 ret = sendto( ip6_socket, data, length, 0, (struct sockaddr *) &addr, sizeof(struct sockaddr_in6) );
632 }
633 if( ret == SOCKET_ERROR ) {
634 int err = socketError;
635
636 // wouldblock is silent
637 if( err == EAGAIN ) {
638 return;
639 }
640
641 // some PPP links do not allow broadcasts and return an error
642 if( ( err == EADDRNOTAVAIL ) && ( ( to.type == NA_BROADCAST ) ) ) {
643 return;
644 }
645
646 Com_Printf( "NET_SendPacket: %s\n", NET_ErrorString() );
647 }
648 }
649
650
651 //=============================================================================
652
653 /*
654 ==================
655 Sys_IsLANAddress
656
657 LAN clients will have their rate var ignored
658 ==================
659 */
Sys_IsLANAddress(netadr_t adr)660 qboolean Sys_IsLANAddress( netadr_t adr ) {
661 int index, run, addrsize;
662 qboolean differed;
663 byte *compareadr, *comparemask, *compareip;
664
665 if( adr.type == NA_LOOPBACK ) {
666 return qtrue;
667 }
668
669 if( adr.type == NA_IP )
670 {
671 // RFC1918:
672 // 10.0.0.0 - 10.255.255.255 (10/8 prefix)
673 // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
674 // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
675 if(adr.ip[0] == 10)
676 return qtrue;
677 if(adr.ip[0] == 172 && (adr.ip[1]&0xf0) == 16)
678 return qtrue;
679 if(adr.ip[0] == 192 && adr.ip[1] == 168)
680 return qtrue;
681
682 if(adr.ip[0] == 127)
683 return qtrue;
684 }
685 else if(adr.type == NA_IP6)
686 {
687 if(adr.ip6[0] == 0xfe && (adr.ip6[1] & 0xc0) == 0x80)
688 return qtrue;
689 if((adr.ip6[0] & 0xfe) == 0xfc)
690 return qtrue;
691 }
692
693 // Now compare against the networks this computer is member of.
694 for(index = 0; index < numIP; index++)
695 {
696 if(localIP[index].type == adr.type)
697 {
698 if(adr.type == NA_IP)
699 {
700 compareip = (byte *) &((struct sockaddr_in *) &localIP[index].addr)->sin_addr.s_addr;
701 comparemask = (byte *) &((struct sockaddr_in *) &localIP[index].netmask)->sin_addr.s_addr;
702 compareadr = adr.ip;
703
704 addrsize = sizeof(adr.ip);
705 }
706 else
707 {
708 compareip = (byte *) &((struct sockaddr_in6 *) &localIP[index].addr)->sin6_addr;
709 comparemask = (byte *) &((struct sockaddr_in6 *) &localIP[index].netmask)->sin6_addr;
710 compareadr = adr.ip6;
711
712 addrsize = sizeof(adr.ip6);
713 }
714
715 differed = qfalse;
716 for(run = 0; run < addrsize; run++)
717 {
718 if((compareip[run] & comparemask[run]) != (compareadr[run] & comparemask[run]))
719 {
720 differed = qtrue;
721 break;
722 }
723 }
724
725 if(!differed)
726 return qtrue;
727
728 }
729 }
730
731 return qfalse;
732 }
733
734 /*
735 ==================
736 Sys_ShowIP
737 ==================
738 */
Sys_ShowIP(void)739 void Sys_ShowIP(void) {
740 int i;
741 char addrbuf[NET_ADDRSTRMAXLEN];
742
743 for(i = 0; i < numIP; i++)
744 {
745 Sys_SockaddrToString(addrbuf, sizeof(addrbuf), (struct sockaddr *) &localIP[i].addr, sizeof((*localIP).addr));
746
747 if(localIP[i].type == NA_IP)
748 Com_Printf( "IP: %s\n", addrbuf);
749 else if(localIP[i].type == NA_IP6)
750 Com_Printf( "IP6: %s\n", addrbuf);
751 }
752 }
753
754
755 //=============================================================================
756
757
758 /*
759 ====================
760 NET_IPSocket
761 ====================
762 */
NET_IPSocket(char * net_interface,int port,int * err)763 int NET_IPSocket( char *net_interface, int port, int *err ) {
764 SOCKET newsocket;
765 struct sockaddr_in address;
766 qboolean _true = qtrue;
767 int i = 1;
768
769 *err = 0;
770
771 if( net_interface ) {
772 Com_Printf( "Opening IP socket: %s:%i\n", net_interface, port );
773 }
774 else {
775 Com_Printf( "Opening IP socket: localhost:%i\n", port );
776 }
777
778 if( ( newsocket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
779 *err = socketError;
780 Com_Printf( "WARNING: NET_IPSocket: socket: %s\n", NET_ErrorString() );
781 return newsocket;
782 }
783 // make it non-blocking
784 if( ioctlsocket( newsocket, FIONBIO, (u_long *)&_true ) == SOCKET_ERROR ) {
785 Com_Printf( "WARNING: NET_IPSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
786 *err = socketError;
787 closesocket(newsocket);
788 return INVALID_SOCKET;
789 }
790
791 // make it broadcast capable
792 if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *) &i, sizeof(i) ) == SOCKET_ERROR ) {
793 Com_Printf( "WARNING: NET_IPSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
794
795 // it is not that bad if this one fails.
796 // return newsocket;
797 }
798
799 if( !net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost") ) {
800 address.sin_family = AF_INET;
801 address.sin_addr.s_addr = INADDR_ANY;
802 }
803 else
804 {
805 if(!Sys_StringToSockaddr( net_interface, (struct sockaddr *)&address, sizeof(address), AF_INET))
806 {
807 closesocket(newsocket);
808 return INVALID_SOCKET;
809 }
810 }
811
812 if( port == PORT_ANY ) {
813 address.sin_port = 0;
814 }
815 else {
816 address.sin_port = htons( (short)port );
817 }
818
819 if( bind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {
820 Com_Printf( "WARNING: NET_IPSocket: bind: %s\n", NET_ErrorString() );
821 *err = socketError;
822 closesocket( newsocket );
823 return INVALID_SOCKET;
824 }
825
826 return newsocket;
827 }
828
829 /*
830 ====================
831 NET_IP6Socket
832 ====================
833 */
NET_IP6Socket(char * net_interface,int port,struct sockaddr_in6 * bindto,int * err)834 int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) {
835 SOCKET newsocket;
836 struct sockaddr_in6 address;
837 qboolean _true = qtrue;
838 int i = 1;
839
840 *err = 0;
841
842 if( net_interface )
843 {
844 // Print the name in brackets if there is a colon:
845 if(Q_CountChar(net_interface, ':'))
846 Com_Printf( "Opening IP6 socket: [%s]:%i\n", net_interface, port );
847 else
848 Com_Printf( "Opening IP6 socket: %s:%i\n", net_interface, port );
849 }
850 else
851 Com_Printf( "Opening IP6 socket: localhost:%i\n", port );
852
853 if( ( newsocket = socket( PF_INET6, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
854 *err = socketError;
855 Com_Printf( "WARNING: NET_IP6Socket: socket: %s\n", NET_ErrorString() );
856 return newsocket;
857 }
858
859 // make it non-blocking
860 if( ioctlsocket( newsocket, FIONBIO, (u_long *)&_true ) == SOCKET_ERROR ) {
861 Com_Printf( "WARNING: NET_IP6Socket: ioctl FIONBIO: %s\n", NET_ErrorString() );
862 *err = socketError;
863 closesocket(newsocket);
864 return INVALID_SOCKET;
865 }
866
867 #ifdef IPV6_V6ONLY
868 // ipv4 addresses should not be allowed to connect via this socket.
869 if(setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &i, sizeof(i)) == SOCKET_ERROR)
870 {
871 // win32 systems don't seem to support this anyways.
872 Com_DPrintf("WARNING: NET_IP6Socket: setsockopt IPV6_V6ONLY: %s\n", NET_ErrorString());
873 }
874 #endif
875
876 if( !net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost") ) {
877 address.sin6_family = AF_INET6;
878 address.sin6_addr = in6addr_any;
879 }
880 else
881 {
882 if(!Sys_StringToSockaddr( net_interface, (struct sockaddr *)&address, sizeof(address), AF_INET6))
883 {
884 closesocket(newsocket);
885 return INVALID_SOCKET;
886 }
887 }
888
889 if( port == PORT_ANY ) {
890 address.sin6_port = 0;
891 }
892 else {
893 address.sin6_port = htons( (short)port );
894 }
895
896 if( bind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {
897 Com_Printf( "WARNING: NET_IP6Socket: bind: %s\n", NET_ErrorString() );
898 *err = socketError;
899 closesocket( newsocket );
900 return INVALID_SOCKET;
901 }
902
903 if(bindto)
904 *bindto = address;
905
906 return newsocket;
907 }
908
909 /*
910 ====================
911 NET_SetMulticast
912 Set the current multicast group
913 ====================
914 */
NET_SetMulticast6(void)915 void NET_SetMulticast6(void)
916 {
917 struct sockaddr_in6 addr;
918
919 if(!*net_mcast6addr->string || !Sys_StringToSockaddr(net_mcast6addr->string, (struct sockaddr *) &addr, sizeof(addr), AF_INET6))
920 {
921 Com_Printf("WARNING: NET_JoinMulticast6: Incorrect multicast address given, "
922 "please set cvar %s to a sane value.\n", net_mcast6addr->name);
923
924 Cvar_SetValue(net_enabled->name, net_enabled->integer | NET_DISABLEMCAST);
925
926 return;
927 }
928
929 memcpy(&curgroup.ipv6mr_multiaddr, &addr.sin6_addr, sizeof(curgroup.ipv6mr_multiaddr));
930
931 if(*net_mcast6iface->string)
932 {
933 #ifdef _WIN32
934 curgroup.ipv6mr_interface = atoi(net_mcast6iface->string);
935 #else
936 curgroup.ipv6mr_interface = if_nametoindex(net_mcast6iface->string);
937 #endif
938 }
939 else
940 curgroup.ipv6mr_interface = 0;
941 }
942
943 /*
944 ====================
945 NET_JoinMulticast
946 Join an ipv6 multicast group
947 ====================
948 */
NET_JoinMulticast6(void)949 void NET_JoinMulticast6(void)
950 {
951 int err;
952
953 if(ip6_socket == INVALID_SOCKET || multicast6_socket != INVALID_SOCKET || (net_enabled->integer & NET_DISABLEMCAST))
954 return;
955
956 if(IN6_IS_ADDR_MULTICAST(&boundto.sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&boundto.sin6_addr))
957 {
958 // The way the socket was bound does not prohibit receiving multi-cast packets. So we don't need to open a new one.
959 multicast6_socket = ip6_socket;
960 }
961 else
962 {
963 if((multicast6_socket = NET_IP6Socket(net_mcast6addr->string, ntohs(boundto.sin6_port), NULL, &err)) == INVALID_SOCKET)
964 {
965 // If the OS does not support binding to multicast addresses, like WinXP, at least try with the normal file descriptor.
966 multicast6_socket = ip6_socket;
967 }
968 }
969
970 if(curgroup.ipv6mr_interface)
971 {
972 if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
973 (char *) &curgroup.ipv6mr_interface, sizeof(curgroup.ipv6mr_interface)) < 0)
974 {
975 Com_Printf("NET_JoinMulticast6: Couldn't set scope on multicast socket: %s\n", NET_ErrorString());
976
977 if(multicast6_socket != ip6_socket)
978 {
979 closesocket(multicast6_socket);
980 multicast6_socket = INVALID_SOCKET;
981 return;
982 }
983 }
984 }
985
986 if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &curgroup, sizeof(curgroup)))
987 {
988 Com_Printf("NET_JoinMulticast6: Couldn't join multicast group: %s\n", NET_ErrorString());
989
990 if(multicast6_socket != ip6_socket)
991 {
992 closesocket(multicast6_socket);
993 multicast6_socket = INVALID_SOCKET;
994 return;
995 }
996 }
997 }
998
NET_LeaveMulticast6()999 void NET_LeaveMulticast6()
1000 {
1001 if(multicast6_socket != INVALID_SOCKET)
1002 {
1003 if(multicast6_socket != ip6_socket)
1004 closesocket(multicast6_socket);
1005 else
1006 setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &curgroup, sizeof(curgroup));
1007
1008 multicast6_socket = INVALID_SOCKET;
1009 }
1010 }
1011
1012 /*
1013 ====================
1014 NET_OpenSocks
1015 ====================
1016 */
NET_OpenSocks(int port)1017 void NET_OpenSocks( int port ) {
1018 struct sockaddr_in address;
1019 int err;
1020 struct hostent *h;
1021 int len;
1022 qboolean rfc1929;
1023 unsigned char buf[64];
1024
1025 usingSocks = qfalse;
1026
1027 Com_Printf( "Opening connection to SOCKS server.\n" );
1028
1029 if ( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) {
1030 err = socketError;
1031 Com_Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() );
1032 return;
1033 }
1034
1035 h = gethostbyname( net_socksServer->string );
1036 if ( h == NULL ) {
1037 err = socketError;
1038 Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() );
1039 return;
1040 }
1041 if ( h->h_addrtype != AF_INET ) {
1042 Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" );
1043 return;
1044 }
1045 address.sin_family = AF_INET;
1046 address.sin_addr.s_addr = *(int *)h->h_addr_list[0];
1047 address.sin_port = htons( (short)net_socksPort->integer );
1048
1049 if ( connect( socks_socket, (struct sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) {
1050 err = socketError;
1051 Com_Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() );
1052 return;
1053 }
1054
1055 // send socks authentication handshake
1056 if ( *net_socksUsername->string || *net_socksPassword->string ) {
1057 rfc1929 = qtrue;
1058 }
1059 else {
1060 rfc1929 = qfalse;
1061 }
1062
1063 buf[0] = 5; // SOCKS version
1064 // method count
1065 if ( rfc1929 ) {
1066 buf[1] = 2;
1067 len = 4;
1068 }
1069 else {
1070 buf[1] = 1;
1071 len = 3;
1072 }
1073 buf[2] = 0; // method #1 - method id #00: no authentication
1074 if ( rfc1929 ) {
1075 buf[2] = 2; // method #2 - method id #02: username/password
1076 }
1077 if ( send( socks_socket, buf, len, 0 ) == SOCKET_ERROR ) {
1078 err = socketError;
1079 Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
1080 return;
1081 }
1082
1083 // get the response
1084 len = recv( socks_socket, buf, 64, 0 );
1085 if ( len == SOCKET_ERROR ) {
1086 err = socketError;
1087 Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
1088 return;
1089 }
1090 if ( len != 2 || buf[0] != 5 ) {
1091 Com_Printf( "NET_OpenSocks: bad response\n" );
1092 return;
1093 }
1094 switch( buf[1] ) {
1095 case 0: // no authentication
1096 break;
1097 case 2: // username/password authentication
1098 break;
1099 default:
1100 Com_Printf( "NET_OpenSocks: request denied\n" );
1101 return;
1102 }
1103
1104 // do username/password authentication if needed
1105 if ( buf[1] == 2 ) {
1106 int ulen;
1107 int plen;
1108
1109 // build the request
1110 ulen = strlen( net_socksUsername->string );
1111 plen = strlen( net_socksPassword->string );
1112
1113 buf[0] = 1; // username/password authentication version
1114 buf[1] = ulen;
1115 if ( ulen ) {
1116 memcpy( &buf[2], net_socksUsername->string, ulen );
1117 }
1118 buf[2 + ulen] = plen;
1119 if ( plen ) {
1120 memcpy( &buf[3 + ulen], net_socksPassword->string, plen );
1121 }
1122
1123 // send it
1124 if ( send( socks_socket, buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) {
1125 err = socketError;
1126 Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
1127 return;
1128 }
1129
1130 // get the response
1131 len = recv( socks_socket, buf, 64, 0 );
1132 if ( len == SOCKET_ERROR ) {
1133 err = socketError;
1134 Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
1135 return;
1136 }
1137 if ( len != 2 || buf[0] != 1 ) {
1138 Com_Printf( "NET_OpenSocks: bad response\n" );
1139 return;
1140 }
1141 if ( buf[1] != 0 ) {
1142 Com_Printf( "NET_OpenSocks: authentication failed\n" );
1143 return;
1144 }
1145 }
1146
1147 // send the UDP associate request
1148 buf[0] = 5; // SOCKS version
1149 buf[1] = 3; // command: UDP associate
1150 buf[2] = 0; // reserved
1151 buf[3] = 1; // address type: IPV4
1152 *(int *)&buf[4] = INADDR_ANY;
1153 *(short *)&buf[8] = htons( (short)port ); // port
1154 if ( send( socks_socket, buf, 10, 0 ) == SOCKET_ERROR ) {
1155 err = socketError;
1156 Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
1157 return;
1158 }
1159
1160 // get the response
1161 len = recv( socks_socket, buf, 64, 0 );
1162 if( len == SOCKET_ERROR ) {
1163 err = socketError;
1164 Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
1165 return;
1166 }
1167 if( len < 2 || buf[0] != 5 ) {
1168 Com_Printf( "NET_OpenSocks: bad response\n" );
1169 return;
1170 }
1171 // check completion code
1172 if( buf[1] != 0 ) {
1173 Com_Printf( "NET_OpenSocks: request denied: %i\n", buf[1] );
1174 return;
1175 }
1176 if( buf[3] != 1 ) {
1177 Com_Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] );
1178 return;
1179 }
1180 ((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET;
1181 ((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4];
1182 ((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8];
1183 memset( ((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 );
1184
1185 usingSocks = qtrue;
1186 }
1187
1188
1189 /*
1190 =====================
1191 NET_GetLocalAddress
1192 =====================
1193 */
NET_AddLocalAddress(char * ifname,struct sockaddr * addr,struct sockaddr * netmask)1194 void NET_AddLocalAddress(char *ifname, struct sockaddr *addr, struct sockaddr *netmask)
1195 {
1196 int addrlen;
1197 sa_family_t family;
1198
1199 // only add addresses that have all required info.
1200 if(!addr || !netmask || !ifname)
1201 return;
1202
1203 family = addr->sa_family;
1204
1205 if(numIP < MAX_IPS)
1206 {
1207 if(family == AF_INET)
1208 {
1209 addrlen = sizeof(struct sockaddr_in);
1210 localIP[numIP].type = NA_IP;
1211 }
1212 else if(family == AF_INET6)
1213 {
1214 addrlen = sizeof(struct sockaddr_in6);
1215 localIP[numIP].type = NA_IP6;
1216 }
1217 else
1218 return;
1219
1220 Q_strncpyz(localIP[numIP].ifname, ifname, sizeof(localIP[numIP].ifname));
1221
1222 localIP[numIP].family = family;
1223
1224 memcpy(&localIP[numIP].addr, addr, addrlen);
1225 memcpy(&localIP[numIP].netmask, netmask, addrlen);
1226
1227 numIP++;
1228 }
1229 }
1230
1231 #if defined(__linux__) || defined(MACOSX) || defined(__BSD__)
NET_GetLocalAddress(void)1232 void NET_GetLocalAddress(void)
1233 {
1234 struct ifaddrs *ifap, *search;
1235
1236 if(getifaddrs(&ifap))
1237 Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces: %s\n", NET_ErrorString());
1238 else
1239 {
1240 for(search = ifap; search; search = search->ifa_next)
1241 {
1242 // Only add interfaces that are up.
1243 if(ifap->ifa_flags & IFF_UP)
1244 NET_AddLocalAddress(search->ifa_name, search->ifa_addr, search->ifa_netmask);
1245 }
1246
1247 freeifaddrs(ifap);
1248
1249 Sys_ShowIP();
1250 }
1251 }
1252 #else
NET_GetLocalAddress(void)1253 void NET_GetLocalAddress( void ) {
1254 char hostname[256];
1255 struct addrinfo hint;
1256 struct addrinfo *res = NULL;
1257 struct addrinfo *search;
1258 struct sockaddr_in mask4;
1259 struct sockaddr_in6 mask6;
1260
1261 if(gethostname( hostname, 256 ) == SOCKET_ERROR)
1262 return;
1263
1264 Com_Printf( "Hostname: %s\n", hostname );
1265
1266 memset(&hint, 0, sizeof(hint));
1267
1268 hint.ai_family = AF_UNSPEC;
1269 hint.ai_socktype = SOCK_DGRAM;
1270
1271 if(getaddrinfo(hostname, NULL, &hint, &res))
1272 return;
1273
1274 /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a
1275 * netmask with all bits set. */
1276
1277 memset(&mask4, 0, sizeof(mask4));
1278 memset(&mask6, 0, sizeof(mask6));
1279 mask4.sin_family = AF_INET;
1280 memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr));
1281 mask6.sin6_family = AF_INET6;
1282 memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr));
1283
1284 // add all IPs from returned list.
1285 for(search = res; search; search = search->ai_next)
1286 {
1287 if(search->ai_family == AF_INET)
1288 NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask4);
1289 else if(search->ai_family == AF_INET6)
1290 NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask6);
1291 }
1292
1293 Sys_ShowIP();
1294 }
1295 #endif
1296
1297 /*
1298 ====================
1299 NET_OpenIP
1300 ====================
1301 */
NET_OpenIP(void)1302 void NET_OpenIP( void ) {
1303 int i;
1304 int err;
1305 int port;
1306 int port6;
1307
1308 net_ip = Cvar_Get( "net_ip", "localhost", CVAR_LATCH );
1309 net_ip6 = Cvar_Get( "net_ip6", "localhost", CVAR_LATCH );
1310 net_port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH );
1311 net_port6 = Cvar_Get( "net_port6", va( "%i", PORT_SERVER ), CVAR_LATCH );
1312
1313 port = net_port->integer;
1314 port6 = net_port6->integer;
1315
1316 NET_GetLocalAddress();
1317
1318 // automatically scan for a valid port, so multiple
1319 // dedicated servers can be started without requiring
1320 // a different net_port for each one
1321 if(net_enabled->integer & NET_ENABLEV4)
1322 {
1323 for( i = 0 ; i < 10 ; i++ ) {
1324 ip_socket = NET_IPSocket( net_ip->string, port + i, &err );
1325 if (ip_socket != INVALID_SOCKET) {
1326 Cvar_SetValue( "net_port", port + i );
1327
1328 if (net_socksEnabled->integer)
1329 NET_OpenSocks( port + i );
1330
1331 break;
1332 }
1333 else
1334 {
1335 if(err == EAFNOSUPPORT)
1336 break;
1337 }
1338 }
1339
1340 if(ip_socket == INVALID_SOCKET)
1341 Com_Printf( "WARNING: Couldn't bind to a v4 ip address.\n");
1342 }
1343
1344 if(net_enabled->integer & NET_ENABLEV6)
1345 {
1346 for( i = 0 ; i < 10 ; i++ )
1347 {
1348 ip6_socket = NET_IP6Socket(net_ip6->string, port6 + i, &boundto, &err);
1349 if (ip6_socket != INVALID_SOCKET)
1350 {
1351 Cvar_SetValue( "net_port6", port6 + i );
1352 break;
1353 }
1354 else
1355 {
1356 if(err == EAFNOSUPPORT)
1357 break;
1358 }
1359 }
1360 if(ip6_socket == INVALID_SOCKET)
1361 Com_Printf( "WARNING: Couldn't bind to a v6 ip address.\n");
1362 }
1363 }
1364
1365
1366 //===================================================================
1367
1368
1369 /*
1370 ====================
1371 NET_GetCvars
1372 ====================
1373 */
NET_GetCvars(void)1374 static qboolean NET_GetCvars( void ) {
1375 qboolean modified;
1376
1377 modified = qfalse;
1378
1379 if( net_enabled && net_enabled->modified ) {
1380 modified = qtrue;
1381 }
1382
1383 #ifdef DEDICATED
1384 // I want server owners to explicitly turn on ipv6 support.
1385 net_enabled = Cvar_Get( "net_enabled", "1", CVAR_LATCH | CVAR_ARCHIVE );
1386 #else
1387 /* End users have it enabled so they can connect to ipv6-only hosts, but ipv4 will be
1388 * used if available due to ping */
1389 net_enabled = Cvar_Get( "net_enabled", "3", CVAR_LATCH | CVAR_ARCHIVE );
1390 #endif
1391
1392 // Some cvars for configuring multicast options which facilitates scanning for servers on local subnets.
1393 if( net_mcast6addr && net_mcast6addr->modified ) {
1394 modified = qtrue;
1395 }
1396 net_mcast6addr = Cvar_Get( "net_mcast6addr", NET_MULTICAST_IP6, CVAR_LATCH | CVAR_ARCHIVE );
1397
1398 if( net_mcast6iface && net_mcast6iface->modified ) {
1399 modified = qtrue;
1400 }
1401 net_mcast6iface = Cvar_Get( "net_mcast6iface", "0", CVAR_LATCH | CVAR_ARCHIVE );
1402
1403 if( net_socksEnabled && net_socksEnabled->modified ) {
1404 modified = qtrue;
1405 }
1406 net_socksEnabled = Cvar_Get( "net_socksEnabled", "0", CVAR_LATCH | CVAR_ARCHIVE );
1407
1408 if( net_socksServer && net_socksServer->modified ) {
1409 modified = qtrue;
1410 }
1411 net_socksServer = Cvar_Get( "net_socksServer", "", CVAR_LATCH | CVAR_ARCHIVE );
1412
1413 if( net_socksPort && net_socksPort->modified ) {
1414 modified = qtrue;
1415 }
1416 net_socksPort = Cvar_Get( "net_socksPort", "1080", CVAR_LATCH | CVAR_ARCHIVE );
1417
1418 if( net_socksUsername && net_socksUsername->modified ) {
1419 modified = qtrue;
1420 }
1421 net_socksUsername = Cvar_Get( "net_socksUsername", "", CVAR_LATCH | CVAR_ARCHIVE );
1422
1423 if( net_socksPassword && net_socksPassword->modified ) {
1424 modified = qtrue;
1425 }
1426 net_socksPassword = Cvar_Get( "net_socksPassword", "", CVAR_LATCH | CVAR_ARCHIVE );
1427
1428
1429 return modified;
1430 }
1431
1432
1433 /*
1434 ====================
1435 NET_Config
1436 ====================
1437 */
NET_Config(qboolean enableNetworking)1438 void NET_Config( qboolean enableNetworking ) {
1439 qboolean modified;
1440 qboolean stop;
1441 qboolean start;
1442
1443 // get any latched changes to cvars
1444 modified = NET_GetCvars();
1445
1446 if( !net_enabled->integer ) {
1447 enableNetworking = 0;
1448 }
1449
1450 // if enable state is the same and no cvars were modified, we have nothing to do
1451 if( enableNetworking == networkingEnabled && !modified ) {
1452 return;
1453 }
1454
1455 if( enableNetworking == networkingEnabled ) {
1456 if( enableNetworking ) {
1457 stop = qtrue;
1458 start = qtrue;
1459 }
1460 else {
1461 stop = qfalse;
1462 start = qfalse;
1463 }
1464 }
1465 else {
1466 if( enableNetworking ) {
1467 stop = qfalse;
1468 start = qtrue;
1469 }
1470 else {
1471 stop = qtrue;
1472 start = qfalse;
1473 }
1474 networkingEnabled = enableNetworking;
1475 }
1476
1477 if( stop ) {
1478 if ( ip_socket != INVALID_SOCKET ) {
1479 closesocket( ip_socket );
1480 ip_socket = INVALID_SOCKET;
1481 }
1482
1483 if(multicast6_socket)
1484 {
1485 if(multicast6_socket != ip6_socket)
1486 closesocket(multicast6_socket);
1487
1488 multicast6_socket = INVALID_SOCKET;
1489 }
1490
1491 if ( ip6_socket != INVALID_SOCKET ) {
1492 closesocket( ip6_socket );
1493 ip6_socket = INVALID_SOCKET;
1494 }
1495
1496 if ( socks_socket != INVALID_SOCKET ) {
1497 closesocket( socks_socket );
1498 socks_socket = INVALID_SOCKET;
1499 }
1500
1501 }
1502
1503 if( start )
1504 {
1505 if (net_enabled->integer)
1506 {
1507 NET_OpenIP();
1508 NET_SetMulticast6();
1509 }
1510 }
1511 }
1512
1513
1514 /*
1515 ====================
1516 NET_Init
1517 ====================
1518 */
NET_Init(void)1519 void NET_Init( void ) {
1520 #ifdef _WIN32
1521 int r;
1522
1523 r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
1524 if( r ) {
1525 Com_Printf( "WARNING: Winsock initialization failed, returned %d\n", r );
1526 return;
1527 }
1528
1529 winsockInitialized = qtrue;
1530 Com_Printf( "Winsock Initialized\n" );
1531 #endif
1532
1533 // this is really just to get the cvars registered
1534 NET_GetCvars();
1535
1536 NET_Config( qtrue );
1537 }
1538
1539
1540 /*
1541 ====================
1542 NET_Shutdown
1543 ====================
1544 */
NET_Shutdown(void)1545 void NET_Shutdown( void ) {
1546 if ( !networkingEnabled ) {
1547 return;
1548 }
1549
1550 NET_Config( qfalse );
1551
1552 #ifdef _WIN32
1553 WSACleanup();
1554 winsockInitialized = qfalse;
1555 #endif
1556 }
1557
1558
1559 /*
1560 ====================
1561 NET_Sleep
1562
1563 Sleeps msec or until something happens on the network
1564 ====================
1565 */
NET_Sleep(int msec)1566 void NET_Sleep( int msec ) {
1567 struct timeval timeout;
1568 fd_set fdset;
1569 int highestfd = -1;
1570
1571 if (!com_dedicated->integer)
1572 return; // we're not a server, just run full speed
1573
1574 if (ip_socket == INVALID_SOCKET && ip6_socket == INVALID_SOCKET)
1575 return;
1576
1577 if (msec < 0 )
1578 return;
1579
1580 FD_ZERO(&fdset);
1581
1582 if(ip_socket != INVALID_SOCKET)
1583 {
1584 FD_SET(ip_socket, &fdset);
1585
1586 if(ip_socket > highestfd)
1587 highestfd = ip_socket;
1588 }
1589 if(ip6_socket != INVALID_SOCKET)
1590 {
1591 FD_SET(ip6_socket, &fdset);
1592
1593 if(ip6_socket > highestfd)
1594 highestfd = ip6_socket;
1595 }
1596
1597 timeout.tv_sec = msec/1000;
1598 timeout.tv_usec = (msec%1000)*1000;
1599 select(ip_socket+1, &fdset, NULL, NULL, &timeout);
1600 }
1601
1602
1603 /*
1604 ====================
1605 NET_Restart_f
1606 ====================
1607 */
NET_Restart(void)1608 void NET_Restart( void ) {
1609 NET_Config( networkingEnabled );
1610 }
1611