1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "sys/platform.h"
30 #include "framework/Common.h"
31 
32 #include "sys/win32/win_local.h"
33 
34 #include <iptypes.h>
35 #include <iphlpapi.h>
36 
37 static WSADATA	winsockdata;
38 static bool	winsockInitialized = false;
39 
40 idCVar net_ip( "net_ip", "localhost", CVAR_SYSTEM, "local IP address" );
41 idCVar net_port( "net_port", "0", CVAR_SYSTEM | CVAR_INTEGER, "local IP port number" );
42 idCVar net_forceLatency( "net_forceLatency", "0", CVAR_SYSTEM | CVAR_INTEGER, "milliseconds latency" );
43 idCVar net_forceDrop( "net_forceDrop", "0", CVAR_SYSTEM | CVAR_INTEGER, "percentage packet loss" );
44 
45 static SOCKET	ip_socket;
46 
47 typedef struct {
48 	unsigned long ip;
49 	unsigned long mask;
50 } net_interface;
51 
52 #define			MAX_INTERFACES	32
53 int				num_interfaces = 0;
54 net_interface	netint[MAX_INTERFACES];
55 
56 //=============================================================================
57 
58 
59 /*
60 ====================
61 NET_ErrorString
62 ====================
63 */
NET_ErrorString(void)64 const char *NET_ErrorString( void ) {
65 	int		code;
66 
67 	code = WSAGetLastError();
68 	switch( code ) {
69 	case WSAEINTR: return "WSAEINTR";
70 	case WSAEBADF: return "WSAEBADF";
71 	case WSAEACCES: return "WSAEACCES";
72 	case WSAEDISCON: return "WSAEDISCON";
73 	case WSAEFAULT: return "WSAEFAULT";
74 	case WSAEINVAL: return "WSAEINVAL";
75 	case WSAEMFILE: return "WSAEMFILE";
76 	case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
77 	case WSAEINPROGRESS: return "WSAEINPROGRESS";
78 	case WSAEALREADY: return "WSAEALREADY";
79 	case WSAENOTSOCK: return "WSAENOTSOCK";
80 	case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
81 	case WSAEMSGSIZE: return "WSAEMSGSIZE";
82 	case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
83 	case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
84 	case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
85 	case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
86 	case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
87 	case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
88 	case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
89 	case WSAEADDRINUSE: return "WSAEADDRINUSE";
90 	case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
91 	case WSAENETDOWN: return "WSAENETDOWN";
92 	case WSAENETUNREACH: return "WSAENETUNREACH";
93 	case WSAENETRESET: return "WSAENETRESET";
94 	case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
95 	case WSAECONNRESET: return "WSAECONNRESET";
96 	case WSAENOBUFS: return "WSAENOBUFS";
97 	case WSAEISCONN: return "WSAEISCONN";
98 	case WSAENOTCONN: return "WSAENOTCONN";
99 	case WSAESHUTDOWN: return "WSAESHUTDOWN";
100 	case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
101 	case WSAETIMEDOUT: return "WSAETIMEDOUT";
102 	case WSAECONNREFUSED: return "WSAECONNREFUSED";
103 	case WSAELOOP: return "WSAELOOP";
104 	case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
105 	case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
106 	case WSASYSNOTREADY: return "WSASYSNOTREADY";
107 	case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
108 	case WSANOTINITIALISED: return "WSANOTINITIALISED";
109 	case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
110 	case WSATRY_AGAIN: return "WSATRY_AGAIN";
111 	case WSANO_RECOVERY: return "WSANO_RECOVERY";
112 	case WSANO_DATA: return "WSANO_DATA";
113 	default: return "NO ERROR";
114 	}
115 }
116 
117 /*
118 ====================
119 Net_NetadrToSockadr
120 ====================
121 */
Net_NetadrToSockadr(const netadr_t * a,struct sockaddr * s)122 void Net_NetadrToSockadr( const netadr_t *a, struct sockaddr *s ) {
123 	memset( s, 0, sizeof(*s) );
124 
125 	if( a->type == NA_BROADCAST ) {
126 		((struct sockaddr_in *)s)->sin_family = AF_INET;
127 		((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
128 	}
129 	else if( a->type == NA_IP || a->type == NA_LOOPBACK ) {
130 		((struct sockaddr_in *)s)->sin_family = AF_INET;
131 		((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
132 	}
133 
134 	((struct sockaddr_in *)s)->sin_port = htons( (short)a->port );
135 }
136 
137 
138 /*
139 ====================
140 Net_SockadrToNetadr
141 ====================
142 */
Net_SockadrToNetadr(struct sockaddr * s,netadr_t * a)143 void Net_SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {
144 	unsigned int ip;
145 	if (s->sa_family == AF_INET) {
146 		ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
147 		*(unsigned int *)&a->ip = ip;
148 		a->port = htons( ((struct sockaddr_in *)s)->sin_port );
149 		// we store in network order, that loopback test is host order..
150 		ip = ntohl( ip );
151 		if ( ip == INADDR_LOOPBACK ) {
152 			a->type = NA_LOOPBACK;
153 		} else {
154 			a->type = NA_IP;
155 		}
156 	}
157 }
158 
159 /*
160 =============
161 Net_ExtractPort
162 =============
163 */
Net_ExtractPort(const char * src,char * buf,int bufsize,int * port)164 static bool Net_ExtractPort( const char *src, char *buf, int bufsize, int *port ) {
165 	char *p;
166 	strncpy( buf, src, bufsize );
167 	p = buf; p += Min( bufsize - 1, (int)strlen( src ) ); *p = '\0';
168 	p = strchr( buf, ':' );
169 	if ( !p ) {
170 		return false;
171 	}
172 	*p = '\0';
173 	*port = strtol( p+1, NULL, 10 );
174 	if ( errno == ERANGE ) {
175 		return false;
176 	}
177 	return true;
178 }
179 
180 /*
181 =============
182 Net_StringToSockaddr
183 =============
184 */
Net_StringToSockaddr(const char * s,struct sockaddr * sadr,bool doDNSResolve)185 static bool Net_StringToSockaddr( const char *s, struct sockaddr *sadr, bool doDNSResolve ) {
186 	struct hostent	*h;
187 	char buf[256];
188 	int port;
189 
190 	memset( sadr, 0, sizeof( *sadr ) );
191 
192 	((struct sockaddr_in *)sadr)->sin_family = AF_INET;
193 	((struct sockaddr_in *)sadr)->sin_port = 0;
194 
195 	if( s[0] >= '0' && s[0] <= '9' ) {
196 		unsigned long ret = inet_addr(s);
197 		if ( ret != INADDR_NONE ) {
198 			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = ret;
199 		} else {
200 			// check for port
201 			if ( !Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
202 				return false;
203 			}
204 			ret = inet_addr( buf );
205 			if ( ret == INADDR_NONE ) {
206 				return false;
207 			}
208 			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = ret;
209 			((struct sockaddr_in *)sadr)->sin_port = htons( port );
210 		}
211 	} else if ( doDNSResolve ) {
212 		// try to remove the port first, otherwise the DNS gets confused into multiple timeouts
213 		// failed or not failed, buf is expected to contain the appropriate host to resolve
214 		if ( Net_ExtractPort( s, buf, sizeof( buf ), &port ) ) {
215 			((struct sockaddr_in *)sadr)->sin_port = htons( port );
216 		}
217 		h = gethostbyname( buf );
218 		if ( h == 0 ) {
219 			return false;
220 		}
221 		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
222 	}
223 
224 	return true;
225 }
226 
227 /*
228 ====================
229 NET_IPSocket
230 ====================
231 */
NET_IPSocket(const char * net_interface,int port,netadr_t * bound_to)232 int NET_IPSocket( const char *net_interface, int port, netadr_t *bound_to ) {
233 	SOCKET				newsocket;
234 	struct sockaddr_in	address;
235 	unsigned long		_true = 1;
236 	int					i = 1;
237 	int					err;
238 
239 	if( net_interface ) {
240 		common->DPrintf( "Opening IP socket: %s:%i\n", net_interface, port );
241 	} else {
242 		common->DPrintf( "Opening IP socket: localhost:%i\n", port );
243 	}
244 
245 	if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
246 		err = WSAGetLastError();
247 		if( err != WSAEAFNOSUPPORT ) {
248 			common->Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() );
249 		}
250 		return 0;
251 	}
252 
253 	// make it non-blocking
254 	if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
255 		common->Printf( "WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
256 		return 0;
257 	}
258 
259 	// make it broadcast capable
260 	if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) {
261 		common->Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
262 		return 0;
263 	}
264 
265 	if( !net_interface || !net_interface[0] || !idStr::Icmp( net_interface, "localhost" ) ) {
266 		address.sin_addr.s_addr = INADDR_ANY;
267 	}
268 	else {
269 		Net_StringToSockaddr( net_interface, (struct sockaddr *)&address, true );
270 	}
271 
272 	if( port == PORT_ANY ) {
273 		address.sin_port = 0;
274 	}
275 	else {
276 		address.sin_port = htons( (short)port );
277 	}
278 
279 	address.sin_family = AF_INET;
280 
281 	if( bind( newsocket, (const struct sockaddr *)&address, sizeof(address) ) == SOCKET_ERROR ) {
282 		common->Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() );
283 		closesocket( newsocket );
284 		return 0;
285 	}
286 
287 	// if the port was PORT_ANY, we need to query again to know the real port we got bound to
288 	// ( this used to be in idPort::InitForPort )
289 	if ( bound_to ) {
290 		int len = sizeof( address );
291 		getsockname( newsocket, (sockaddr *)&address, &len );
292 		Net_SockadrToNetadr( (sockaddr *)&address, bound_to );
293 	}
294 
295 	return newsocket;
296 }
297 
298 /*
299 ==================
300 Net_WaitForUDPPacket
301 ==================
302 */
Net_WaitForUDPPacket(int netSocket,int timeout)303 bool Net_WaitForUDPPacket( int netSocket, int timeout ) {
304 	int					ret;
305 	fd_set				set;
306 	struct timeval		tv;
307 
308 	if ( !netSocket ) {
309 		return false;
310 	}
311 
312 	if ( timeout <= 0 ) {
313 		return true;
314 	}
315 
316 	FD_ZERO( &set );
317 	FD_SET( netSocket, &set );
318 
319 	tv.tv_sec = 0;
320 	tv.tv_usec = timeout * 1000;
321 
322 	ret = select( netSocket + 1, &set, NULL, NULL, &tv );
323 
324 	if ( ret == -1 ) {
325 		common->DPrintf( "Net_WaitForUPDPacket select(): %s\n", strerror( errno ) );
326 		return false;
327 	}
328 
329 	// timeout with no data
330 	if ( ret == 0 ) {
331 		return false;
332 	}
333 
334 	return true;
335 }
336 
337 /*
338 ==================
339 Net_GetUDPPacket
340 ==================
341 */
Net_GetUDPPacket(int netSocket,netadr_t & net_from,char * data,int & size,int maxSize)342 bool Net_GetUDPPacket( int netSocket, netadr_t &net_from, char *data, int &size, int maxSize ) {
343 	int				ret;
344 	struct sockaddr	from;
345 	int				fromlen;
346 	int				err;
347 
348 	if( !netSocket ) {
349 		return false;
350 	}
351 
352 	fromlen = sizeof(from);
353 	ret = recvfrom( netSocket, data, maxSize, 0, (struct sockaddr *)&from, &fromlen );
354 	if ( ret == SOCKET_ERROR ) {
355 		err = WSAGetLastError();
356 
357 		if( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) {
358 			return false;
359 		}
360 		char	buf[1024];
361 		sprintf( buf, "Net_GetUDPPacket: %s\n", NET_ErrorString() );
362 		OutputDebugString( buf );
363 		return false;
364 	}
365 
366 	if ( netSocket == ip_socket ) {
367 		memset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
368 	}
369 
370 	Net_SockadrToNetadr( &from, &net_from );
371 
372 	if( ret == maxSize ) {
373 		char	buf[1024];
374 		sprintf( buf, "Net_GetUDPPacket: oversize packet from %s\n", Sys_NetAdrToString( net_from ) );
375 		OutputDebugString( buf );
376 		return false;
377 	}
378 
379 	size = ret;
380 
381 	return true;
382 }
383 
384 /*
385 ==================
386 Net_SendUDPPacket
387 ==================
388 */
Net_SendUDPPacket(int netSocket,int length,const void * data,const netadr_t to)389 void Net_SendUDPPacket( int netSocket, int length, const void *data, const netadr_t to ) {
390 	int				ret;
391 	struct sockaddr	addr;
392 
393 	if( !netSocket ) {
394 		return;
395 	}
396 
397 	Net_NetadrToSockadr( &to, &addr );
398 	ret = sendto( netSocket, (const char *)data, length, 0, &addr, sizeof(addr) );
399 	if( ret == SOCKET_ERROR ) {
400 		int err = WSAGetLastError();
401 
402 		// wouldblock is silent
403 		if( err == WSAEWOULDBLOCK ) {
404 			return;
405 		}
406 
407 		// some PPP links do not allow broadcasts and return an error
408 		if( ( err == WSAEADDRNOTAVAIL ) && ( to.type == NA_BROADCAST ) ) {
409 			return;
410 		}
411 
412 		char	buf[1024];
413 		sprintf( buf, "Net_SendUDPPacket: %s\n", NET_ErrorString() );
414 		OutputDebugString( buf );
415 	}
416 }
417 
418 /*
419 ====================
420 Sys_InitNetworking
421 ====================
422 */
Sys_InitNetworking(void)423 void Sys_InitNetworking( void ) {
424 	int		r;
425 
426 	r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
427 	if( r ) {
428 		common->Printf( "WARNING: Winsock initialization failed, returned %d\n", r );
429 		return;
430 	}
431 
432 	winsockInitialized = true;
433 	common->Printf( "Winsock Initialized\n" );
434 
435 	PIP_ADAPTER_INFO pAdapterInfo;
436 	PIP_ADAPTER_INFO pAdapter = NULL;
437 	DWORD dwRetVal = 0;
438 	PIP_ADDR_STRING pIPAddrString;
439 	ULONG ulOutBufLen;
440 	bool foundloopback;
441 
442 	num_interfaces = 0;
443 	foundloopback = false;
444 
445 	pAdapterInfo = (IP_ADAPTER_INFO *)malloc( sizeof( IP_ADAPTER_INFO ) );
446 	if( !pAdapterInfo ) {
447 		common->FatalError( "Sys_InitNetworking: Couldn't malloc( %u )", (unsigned int)sizeof( IP_ADAPTER_INFO ) );
448 	}
449 	ulOutBufLen = sizeof( IP_ADAPTER_INFO );
450 
451 	// Make an initial call to GetAdaptersInfo to get
452 	// the necessary size into the ulOutBufLen variable
453 	if( GetAdaptersInfo( pAdapterInfo, &ulOutBufLen ) == ERROR_BUFFER_OVERFLOW ) {
454 		free( pAdapterInfo );
455 		pAdapterInfo = (IP_ADAPTER_INFO *)malloc( ulOutBufLen );
456 		if( !pAdapterInfo ) {
457 			common->FatalError( "Sys_InitNetworking: Couldn't malloc( %ld )", ulOutBufLen );
458 		}
459 	}
460 
461 	if( ( dwRetVal = GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) ) != NO_ERROR ) {
462 		// happens if you have no network connection
463 		common->Printf( "Sys_InitNetworking: GetAdaptersInfo failed (%ld).\n", dwRetVal );
464 	} else {
465 		pAdapter = pAdapterInfo;
466 		while( pAdapter ) {
467 			common->Printf( "Found interface: %s %s - ", pAdapter->AdapterName, pAdapter->Description );
468 			pIPAddrString = &pAdapter->IpAddressList;
469 			while( pIPAddrString ) {
470 				unsigned long ip_a, ip_m;
471 				if( !idStr::Icmp( "127.0.0.1", pIPAddrString->IpAddress.String ) ) {
472 					foundloopback = true;
473 				}
474 				ip_a = ntohl( inet_addr( pIPAddrString->IpAddress.String ) );
475 				ip_m = ntohl( inet_addr( pIPAddrString->IpMask.String ) );
476 				//skip null netmasks
477 				if( !ip_m ) {
478 					common->Printf( "%s NULL netmask - skipped\n", pIPAddrString->IpAddress.String );
479 					pIPAddrString = pIPAddrString->Next;
480 					continue;
481 				}
482 				common->Printf( "%s/%s\n", pIPAddrString->IpAddress.String, pIPAddrString->IpMask.String );
483 				netint[num_interfaces].ip = ip_a;
484 				netint[num_interfaces].mask = ip_m;
485 				num_interfaces++;
486 				if( num_interfaces >= MAX_INTERFACES ) {
487 					common->Printf( "Sys_InitNetworking: MAX_INTERFACES(%d) hit.\n", MAX_INTERFACES );
488 					free( pAdapterInfo );
489 					return;
490 				}
491 				pIPAddrString = pIPAddrString->Next;
492 			}
493 			pAdapter = pAdapter->Next;
494 		}
495 	}
496 	// for some retarded reason, win32 doesn't count loopback as an adapter...
497 	if( !foundloopback && num_interfaces < MAX_INTERFACES ) {
498 		common->Printf( "Sys_InitNetworking: adding loopback interface\n" );
499 		netint[num_interfaces].ip = ntohl( inet_addr( "127.0.0.1" ) );
500 		netint[num_interfaces].mask = ntohl( inet_addr( "255.0.0.0" ) );
501 		num_interfaces++;
502 	}
503 	free( pAdapterInfo );
504 }
505 
506 
507 /*
508 ====================
509 Sys_ShutdownNetworking
510 ====================
511 */
Sys_ShutdownNetworking(void)512 void Sys_ShutdownNetworking( void ) {
513 	if ( !winsockInitialized ) {
514 		return;
515 	}
516 	WSACleanup();
517 	winsockInitialized = false;
518 }
519 
520 /*
521 =============
522 Sys_StringToNetAdr
523 =============
524 */
Sys_StringToNetAdr(const char * s,netadr_t * a,bool doDNSResolve)525 bool Sys_StringToNetAdr( const char *s, netadr_t *a, bool doDNSResolve ) {
526 	struct sockaddr sadr;
527 
528 	if ( !Net_StringToSockaddr( s, &sadr, doDNSResolve ) ) {
529 		return false;
530 	}
531 
532 	Net_SockadrToNetadr( &sadr, a );
533 	return true;
534 }
535 
536 /*
537 =============
538 Sys_NetAdrToString
539 =============
540 */
Sys_NetAdrToString(const netadr_t a)541 const char *Sys_NetAdrToString( const netadr_t a ) {
542 	static int index = 0;
543 	static char buf[ 4 ][ 64 ];	// flip/flop
544 	char *s;
545 
546 	s = buf[index];
547 	index = (index + 1) & 3;
548 
549 	if ( a.type == NA_LOOPBACK ) {
550 		if ( a.port ) {
551 			idStr::snPrintf( s, 64, "localhost:%i", a.port );
552 		} else {
553 			idStr::snPrintf( s, 64, "localhost" );
554 		}
555 	} else if ( a.type == NA_IP ) {
556 		idStr::snPrintf( s, 64, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], a.port );
557 	}
558 	return s;
559 }
560 
561 /*
562 ==================
563 Sys_IsLANAddress
564 ==================
565 */
Sys_IsLANAddress(const netadr_t adr)566 bool Sys_IsLANAddress( const netadr_t adr ) {
567 #if ID_NOLANADDRESS
568 	common->Printf( "Sys_IsLANAddress: ID_NOLANADDRESS\n" );
569 	return false;
570 #endif
571 	if( adr.type == NA_LOOPBACK ) {
572 		return true;
573 	}
574 
575 	if( adr.type != NA_IP ) {
576 		return false;
577 	}
578 
579 	if( num_interfaces ) {
580 		int i;
581 		unsigned long *p_ip;
582 		unsigned long ip;
583 		p_ip = (unsigned long *)&adr.ip[0];
584 		ip = ntohl( *p_ip );
585 
586 		for( i=0; i < num_interfaces; i++ ) {
587 			if( ( netint[i].ip & netint[i].mask ) == ( ip & netint[i].mask ) ) {
588 				return true;
589 			}
590 		}
591 	}
592 	return false;
593 }
594 
595 /*
596 ===================
597 Sys_CompareNetAdrBase
598 
599 Compares without the port
600 ===================
601 */
Sys_CompareNetAdrBase(const netadr_t a,const netadr_t b)602 bool Sys_CompareNetAdrBase( const netadr_t a, const netadr_t b ) {
603 	if ( a.type != b.type ) {
604 		return false;
605 	}
606 
607 	if ( a.type == NA_LOOPBACK ) {
608 		return true;
609 	}
610 
611 	if ( a.type == NA_IP ) {
612 		if ( a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] ) {
613 			return true;
614 		}
615 		return false;
616 	}
617 
618 	common->Printf( "Sys_CompareNetAdrBase: bad address type\n" );
619 	return false;
620 }
621 
622 //=============================================================================
623 
624 
625 #define MAX_UDP_MSG_SIZE	1400
626 
627 typedef struct udpMsg_s {
628 	byte				data[MAX_UDP_MSG_SIZE];
629 	netadr_t			address;
630 	int					size;
631 	unsigned int		time;
632 	struct udpMsg_s *	next;
633 } udpMsg_t;
634 
635 class idUDPLag {
636 public:
637 						idUDPLag( void );
638 						~idUDPLag( void );
639 
640 	udpMsg_t *			sendFirst;
641 	udpMsg_t *			sendLast;
642 	udpMsg_t *			recieveFirst;
643 	udpMsg_t *			recieveLast;
644 	idBlockAlloc<udpMsg_t, 64> udpMsgAllocator;
645 };
646 
idUDPLag(void)647 idUDPLag::idUDPLag( void ) {
648 	sendFirst = sendLast = recieveFirst = recieveLast = NULL;
649 }
650 
~idUDPLag(void)651 idUDPLag::~idUDPLag( void ) {
652 	udpMsgAllocator.Shutdown();
653 }
654 
655 idUDPLag *udpPorts[65536];
656 
657 /*
658 ==================
659 idPort::idPort
660 ==================
661 */
idPort()662 idPort::idPort() {
663 	netSocket = 0;
664 	memset( &bound_to, 0, sizeof( bound_to ) );
665 }
666 
667 /*
668 ==================
669 idPort::~idPort
670 ==================
671 */
~idPort()672 idPort::~idPort() {
673 	Close();
674 }
675 
676 /*
677 ==================
678 InitForPort
679 ==================
680 */
InitForPort(int portNumber)681 bool idPort::InitForPort( int portNumber ) {
682 	netSocket = NET_IPSocket( net_ip.GetString(), portNumber, &bound_to );
683 	if ( netSocket <= 0 ) {
684 		netSocket = 0;
685 		memset( &bound_to, 0, sizeof( bound_to ) );
686 		return false;
687 	}
688 
689 	udpPorts[ bound_to.port ] = new idUDPLag;
690 
691 	return true;
692 }
693 
694 /*
695 ==================
696 idPort::Close
697 ==================
698 */
Close()699 void idPort::Close() {
700 	if ( netSocket ) {
701 		if ( udpPorts[ bound_to.port ] ) {
702 			delete udpPorts[ bound_to.port ];
703 			udpPorts[ bound_to.port ] = NULL;
704 		}
705 		closesocket( netSocket );
706 		netSocket = 0;
707 		memset( &bound_to, 0, sizeof( bound_to ) );
708 	}
709 }
710 
711 /*
712 ==================
713 idPort::GetPacket
714 ==================
715 */
GetPacket(netadr_t & from,void * data,int & size,int maxSize)716 bool idPort::GetPacket( netadr_t &from, void *data, int &size, int maxSize ) {
717 	udpMsg_t *msg;
718 	bool ret;
719 
720 	while( 1 ) {
721 
722 		ret = Net_GetUDPPacket( netSocket, from, (char *)data, size, maxSize );
723 		if ( !ret ) {
724 			break;
725 		}
726 
727 		if ( net_forceDrop.GetInteger() > 0 ) {
728 			if ( rand() < net_forceDrop.GetInteger() * RAND_MAX / 100 ) {
729 				continue;
730 			}
731 		}
732 
733 		packetsRead++;
734 		bytesRead += size;
735 
736 		if ( net_forceLatency.GetInteger() > 0 ) {
737 
738 			assert( size <= MAX_UDP_MSG_SIZE );
739 			msg = udpPorts[ bound_to.port ]->udpMsgAllocator.Alloc();
740 			memcpy( msg->data, data, size );
741 			msg->size = size;
742 			msg->address = from;
743 			msg->time = Sys_Milliseconds();
744 			msg->next = NULL;
745 			if ( udpPorts[ bound_to.port ]->recieveLast ) {
746 				udpPorts[ bound_to.port ]->recieveLast->next = msg;
747 			} else {
748 				udpPorts[ bound_to.port ]->recieveFirst = msg;
749 			}
750 			udpPorts[ bound_to.port ]->recieveLast = msg;
751 		} else {
752 			break;
753 		}
754 	}
755 
756 	if ( net_forceLatency.GetInteger() > 0 || ( udpPorts[ bound_to.port] && udpPorts[ bound_to.port ]->recieveFirst ) ) {
757 
758 		msg = udpPorts[ bound_to.port ]->recieveFirst;
759 		if ( msg && msg->time <= Sys_Milliseconds() - net_forceLatency.GetInteger() ) {
760 			memcpy( data, msg->data, msg->size );
761 			size = msg->size;
762 			from = msg->address;
763 			udpPorts[ bound_to.port ]->recieveFirst = udpPorts[ bound_to.port ]->recieveFirst->next;
764 			if ( !udpPorts[ bound_to.port ]->recieveFirst ) {
765 				udpPorts[ bound_to.port ]->recieveLast = NULL;
766 			}
767 			udpPorts[ bound_to.port ]->udpMsgAllocator.Free( msg );
768 			return true;
769 		}
770 		return false;
771 
772 	} else {
773 		return ret;
774 	}
775 }
776 
777 /*
778 ==================
779 idPort::GetPacketBlocking
780 ==================
781 */
GetPacketBlocking(netadr_t & from,void * data,int & size,int maxSize,int timeout)782 bool idPort::GetPacketBlocking( netadr_t &from, void *data, int &size, int maxSize, int timeout ) {
783 
784 	Net_WaitForUDPPacket( netSocket, timeout );
785 
786 	if ( GetPacket( from, data, size, maxSize ) ) {
787 		return true;
788 	}
789 
790 	return false;
791 }
792 
793 /*
794 ==================
795 idPort::SendPacket
796 ==================
797 */
SendPacket(const netadr_t to,const void * data,int size)798 void idPort::SendPacket( const netadr_t to, const void *data, int size ) {
799 	udpMsg_t *msg;
800 
801 	if ( to.type == NA_BAD ) {
802 		common->Warning( "idPort::SendPacket: bad address type NA_BAD - ignored" );
803 		return;
804 	}
805 
806 	packetsWritten++;
807 	bytesWritten += size;
808 
809 	if ( net_forceDrop.GetInteger() > 0 ) {
810 		if ( rand() < net_forceDrop.GetInteger() * RAND_MAX / 100 ) {
811 			return;
812 		}
813 	}
814 
815 	if ( net_forceLatency.GetInteger() > 0 || ( udpPorts[ bound_to.port ] && udpPorts[ bound_to.port ]->sendFirst ) ) {
816 
817 		assert( size <= MAX_UDP_MSG_SIZE );
818 		msg = udpPorts[ bound_to.port ]->udpMsgAllocator.Alloc();
819 		memcpy( msg->data, data, size );
820 		msg->size = size;
821 		msg->address = to;
822 		msg->time = Sys_Milliseconds();
823 		msg->next = NULL;
824 		if ( udpPorts[ bound_to.port ]->sendLast ) {
825 			udpPorts[ bound_to.port ]->sendLast->next = msg;
826 		} else {
827 			udpPorts[ bound_to.port ]->sendFirst = msg;
828 		}
829 		udpPorts[ bound_to.port ]->sendLast = msg;
830 
831 		for ( msg = udpPorts[ bound_to.port ]->sendFirst; msg && msg->time <= Sys_Milliseconds() - net_forceLatency.GetInteger(); msg = udpPorts[ bound_to.port ]->sendFirst ) {
832 			Net_SendUDPPacket( netSocket, msg->size, msg->data, msg->address );
833 			udpPorts[ bound_to.port ]->sendFirst = udpPorts[ bound_to.port ]->sendFirst->next;
834 			if ( !udpPorts[ bound_to.port ]->sendFirst ) {
835 				udpPorts[ bound_to.port ]->sendLast = NULL;
836 			}
837 			udpPorts[ bound_to.port ]->udpMsgAllocator.Free( msg );
838 		}
839 
840 	} else {
841 		Net_SendUDPPacket( netSocket, size, data, to );
842 	}
843 }
844 
845 
846 //=============================================================================
847 
848 /*
849 ==================
850 idTCP::idTCP
851 ==================
852 */
idTCP()853 idTCP::idTCP() {
854 	fd = 0;
855 	memset( &address, 0, sizeof( address ) );
856 }
857 
858 /*
859 ==================
860 idTCP::~idTCP
861 ==================
862 */
~idTCP()863 idTCP::~idTCP() {
864 	Close();
865 }
866 
867 /*
868 ==================
869 idTCP::Init
870 ==================
871 */
Init(const char * host,short port)872 bool idTCP::Init( const char *host, short port ) {
873 	unsigned long	_true = 1;
874 	struct sockaddr sadr;
875 
876 	if ( !Sys_StringToNetAdr( host, &address, true ) ) {
877 		common->Printf( "Couldn't resolve server name \"%s\"\n", host );
878 		return false;
879 	}
880 	address.type = NA_IP;
881 	if ( !address.port ) {
882 		address.port = port;
883 	}
884 	common->Printf( "\"%s\" resolved to %i.%i.%i.%i:%i\n", host,
885 					address.ip[0], address.ip[1], address.ip[2], address.ip[3], address.port );
886 	Net_NetadrToSockadr( &address, &sadr );
887 
888 	if ( fd ) {
889 		common->Warning( "idTCP::Init: already initialized?" );
890 	}
891 
892 	if ( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET ) {
893 		fd = 0;
894 		common->Printf( "ERROR: idTCP::Init: socket: %s\n", NET_ErrorString() );
895 		return false;
896 	}
897 
898 	if ( connect( fd, &sadr, sizeof(sadr)) == SOCKET_ERROR ) {
899 		common->Printf( "ERROR: idTCP::Init: connect: %s\n", NET_ErrorString() );
900 		closesocket( fd );
901 		fd = 0;
902 		return false;
903 	}
904 
905 	// make it non-blocking
906 	if( ioctlsocket( fd, FIONBIO, &_true ) == SOCKET_ERROR ) {
907 		common->Printf( "ERROR: idTCP::Init: ioctl FIONBIO: %s\n", NET_ErrorString() );
908 		closesocket( fd );
909 		fd = 0;
910 		return false;
911 	}
912 
913 	common->DPrintf( "Opened TCP connection\n" );
914 	return true;
915 }
916 
917 /*
918 ==================
919 idTCP::Close
920 ==================
921 */
Close()922 void idTCP::Close() {
923 	if ( fd ) {
924 		closesocket( fd );
925 	}
926 	fd = 0;
927 }
928 
929 /*
930 ==================
931 idTCP::Read
932 ==================
933 */
Read(void * data,int size)934 int idTCP::Read( void *data, int size ) {
935 	int nbytes;
936 
937 	if ( !fd ) {
938 		common->Printf("idTCP::Read: not initialized\n");
939 		return -1;
940 	}
941 
942 	if ( ( nbytes = recv( fd, (char *)data, size, 0 ) ) == SOCKET_ERROR ) {
943 		if ( WSAGetLastError() == WSAEWOULDBLOCK ) {
944 			return 0;
945 		}
946 		common->Printf( "ERROR: idTCP::Read: %s\n", NET_ErrorString() );
947 		Close();
948 		return -1;
949 	}
950 
951 	// a successful read of 0 bytes indicates remote has closed the connection
952 	if ( nbytes == 0 ) {
953 		common->DPrintf( "idTCP::Read: read 0 bytes - assume connection closed\n" );
954 		return -1;
955 	}
956 
957 	return nbytes;
958 }
959 
960 /*
961 ==================
962 idTCP::Write
963 ==================
964 */
Write(void * data,int size)965 int idTCP::Write( void *data, int size ) {
966 	int nbytes;
967 
968 	if ( !fd ) {
969 		common->Printf("idTCP::Write: not initialized\n");
970 		return -1;
971 	}
972 
973 	if ( ( nbytes = send( fd, (char *)data, size, 0 ) ) == SOCKET_ERROR ) {
974 		common->Printf( "ERROR: idTCP::Write: %s\n", NET_ErrorString() );
975 		Close();
976 		return -1;
977 	}
978 
979 	return nbytes;
980 }
981