Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

win_net.c (25227B)


      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 Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // net_wins.c
     23 
     24 #include "../game/q_shared.h"
     25 #include "../qcommon/qcommon.h"
     26 #include "win_local.h"
     27 
     28 static WSADATA	winsockdata;
     29 static qboolean	winsockInitialized = qfalse;
     30 static qboolean usingSocks = qfalse;
     31 static qboolean networkingEnabled = qfalse;
     32 
     33 static cvar_t	*net_noudp;
     34 static cvar_t	*net_noipx;
     35 
     36 static cvar_t	*net_socksEnabled;
     37 static cvar_t	*net_socksServer;
     38 static cvar_t	*net_socksPort;
     39 static cvar_t	*net_socksUsername;
     40 static cvar_t	*net_socksPassword;
     41 static struct sockaddr	socksRelayAddr;
     42 
     43 static SOCKET	ip_socket;
     44 static SOCKET	socks_socket;
     45 static SOCKET	ipx_socket;
     46 
     47 #define	MAX_IPS		16
     48 static	int		numIP;
     49 static	byte	localIP[MAX_IPS][4];
     50 
     51 //=============================================================================
     52 
     53 
     54 /*
     55 ====================
     56 NET_ErrorString
     57 ====================
     58 */
     59 char *NET_ErrorString( void ) {
     60 	int		code;
     61 
     62 	code = WSAGetLastError();
     63 	switch( code ) {
     64 	case WSAEINTR: return "WSAEINTR";
     65 	case WSAEBADF: return "WSAEBADF";
     66 	case WSAEACCES: return "WSAEACCES";
     67 	case WSAEDISCON: return "WSAEDISCON";
     68 	case WSAEFAULT: return "WSAEFAULT";
     69 	case WSAEINVAL: return "WSAEINVAL";
     70 	case WSAEMFILE: return "WSAEMFILE";
     71 	case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
     72 	case WSAEINPROGRESS: return "WSAEINPROGRESS";
     73 	case WSAEALREADY: return "WSAEALREADY";
     74 	case WSAENOTSOCK: return "WSAENOTSOCK";
     75 	case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
     76 	case WSAEMSGSIZE: return "WSAEMSGSIZE";
     77 	case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
     78 	case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
     79 	case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
     80 	case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
     81 	case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
     82 	case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
     83 	case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
     84 	case WSAEADDRINUSE: return "WSAEADDRINUSE";
     85 	case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
     86 	case WSAENETDOWN: return "WSAENETDOWN";
     87 	case WSAENETUNREACH: return "WSAENETUNREACH";
     88 	case WSAENETRESET: return "WSAENETRESET";
     89 	case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
     90 	case WSAECONNRESET: return "WSAECONNRESET";
     91 	case WSAENOBUFS: return "WSAENOBUFS";
     92 	case WSAEISCONN: return "WSAEISCONN";
     93 	case WSAENOTCONN: return "WSAENOTCONN";
     94 	case WSAESHUTDOWN: return "WSAESHUTDOWN";
     95 	case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
     96 	case WSAETIMEDOUT: return "WSAETIMEDOUT";
     97 	case WSAECONNREFUSED: return "WSAECONNREFUSED";
     98 	case WSAELOOP: return "WSAELOOP";
     99 	case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
    100 	case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
    101 	case WSASYSNOTREADY: return "WSASYSNOTREADY";
    102 	case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
    103 	case WSANOTINITIALISED: return "WSANOTINITIALISED";
    104 	case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
    105 	case WSATRY_AGAIN: return "WSATRY_AGAIN";
    106 	case WSANO_RECOVERY: return "WSANO_RECOVERY";
    107 	case WSANO_DATA: return "WSANO_DATA";
    108 	default: return "NO ERROR";
    109 	}
    110 }
    111 
    112 void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) {
    113 	memset( s, 0, sizeof(*s) );
    114 
    115 	if( a->type == NA_BROADCAST ) {
    116 		((struct sockaddr_in *)s)->sin_family = AF_INET;
    117 		((struct sockaddr_in *)s)->sin_port = a->port;
    118 		((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
    119 	}
    120 	else if( a->type == NA_IP ) {
    121 		((struct sockaddr_in *)s)->sin_family = AF_INET;
    122 		((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
    123 		((struct sockaddr_in *)s)->sin_port = a->port;
    124 	}
    125 	else if( a->type == NA_IPX ) {
    126 		((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
    127 		memcpy( ((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4 );
    128 		memcpy( ((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6 );
    129 		((struct sockaddr_ipx *)s)->sa_socket = a->port;
    130 	}
    131 	else if( a->type == NA_BROADCAST_IPX ) {
    132 		((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
    133 		memset( ((struct sockaddr_ipx *)s)->sa_netnum, 0, 4 );
    134 		memset( ((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6 );
    135 		((struct sockaddr_ipx *)s)->sa_socket = a->port;
    136 	}
    137 }
    138 
    139 
    140 void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) {
    141 	if (s->sa_family == AF_INET) {
    142 		a->type = NA_IP;
    143 		*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
    144 		a->port = ((struct sockaddr_in *)s)->sin_port;
    145 	}
    146 	else if( s->sa_family == AF_IPX ) {
    147 		a->type = NA_IPX;
    148 		memcpy( &a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4 );
    149 		memcpy( &a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6 );
    150 		a->port = ((struct sockaddr_ipx *)s)->sa_socket;
    151 	}
    152 }
    153 
    154 
    155 /*
    156 =============
    157 Sys_StringToAdr
    158 
    159 idnewt
    160 192.246.40.70
    161 12121212.121212121212
    162 =============
    163 */
    164 #define DO(src,dest)	\
    165 	copy[0] = s[src];	\
    166 	copy[1] = s[src + 1];	\
    167 	sscanf (copy, "%x", &val);	\
    168 	((struct sockaddr_ipx *)sadr)->dest = val
    169 
    170 qboolean Sys_StringToSockaddr( const char *s, struct sockaddr *sadr ) {
    171 	struct hostent	*h;
    172 	int		val;
    173 	char	copy[MAX_STRING_CHARS];
    174 	
    175 	memset( sadr, 0, sizeof( *sadr ) );
    176 
    177 	// check for an IPX address
    178 	if( ( strlen( s ) == 21 ) && ( s[8] == '.' ) ) {
    179 		((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
    180 		((struct sockaddr_ipx *)sadr)->sa_socket = 0;
    181 		copy[2] = 0;
    182 		DO(0, sa_netnum[0]);
    183 		DO(2, sa_netnum[1]);
    184 		DO(4, sa_netnum[2]);
    185 		DO(6, sa_netnum[3]);
    186 		DO(9, sa_nodenum[0]);
    187 		DO(11, sa_nodenum[1]);
    188 		DO(13, sa_nodenum[2]);
    189 		DO(15, sa_nodenum[3]);
    190 		DO(17, sa_nodenum[4]);
    191 		DO(19, sa_nodenum[5]);
    192 	}
    193 	else {
    194 		((struct sockaddr_in *)sadr)->sin_family = AF_INET;
    195 		((struct sockaddr_in *)sadr)->sin_port = 0;
    196 
    197 		if( s[0] >= '0' && s[0] <= '9' ) {
    198 			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s);
    199 		} else {
    200 			if( ( h = gethostbyname( s ) ) == 0 ) {
    201 				return 0;
    202 			}
    203 			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
    204 		}
    205 	}
    206 	
    207 	return qtrue;
    208 }
    209 
    210 #undef DO
    211 
    212 /*
    213 =============
    214 Sys_StringToAdr
    215 
    216 idnewt
    217 192.246.40.70
    218 =============
    219 */
    220 qboolean Sys_StringToAdr( const char *s, netadr_t *a ) {
    221 	struct sockaddr sadr;
    222 	
    223 	if ( !Sys_StringToSockaddr( s, &sadr ) ) {
    224 		return qfalse;
    225 	}
    226 	
    227 	SockadrToNetadr( &sadr, a );
    228 	return qtrue;
    229 }
    230 
    231 //=============================================================================
    232 
    233 /*
    234 ==================
    235 Sys_GetPacket
    236 
    237 Never called by the game logic, just the system event queing
    238 ==================
    239 */
    240 int	recvfromCount;
    241 
    242 qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) {
    243 	int 	ret;
    244 	struct sockaddr from;
    245 	int		fromlen;
    246 	int		net_socket;
    247 	int		protocol;
    248 	int		err;
    249 
    250 	for( protocol = 0 ; protocol < 2 ; protocol++ )	{
    251 		if( protocol == 0 ) {
    252 			net_socket = ip_socket;
    253 		}
    254 		else {
    255 			net_socket = ipx_socket;
    256 		}
    257 
    258 		if( !net_socket ) {
    259 			continue;
    260 		}
    261 
    262 		fromlen = sizeof(from);
    263 		recvfromCount++;		// performance check
    264 		ret = recvfrom( net_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen );
    265 		if (ret == SOCKET_ERROR)
    266 		{
    267 			err = WSAGetLastError();
    268 
    269 			if( err == WSAEWOULDBLOCK || err == WSAECONNRESET ) {
    270 				continue;
    271 			}
    272 			Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() );
    273 			continue;
    274 		}
    275 
    276 		if ( net_socket == ip_socket ) {
    277 			memset( ((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
    278 		}
    279 
    280 		if ( usingSocks && net_socket == ip_socket && memcmp( &from, &socksRelayAddr, fromlen ) == 0 ) {
    281 			if ( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 ) {
    282 				continue;
    283 			}
    284 			net_from->type = NA_IP;
    285 			net_from->ip[0] = net_message->data[4];
    286 			net_from->ip[1] = net_message->data[5];
    287 			net_from->ip[2] = net_message->data[6];
    288 			net_from->ip[3] = net_message->data[7];
    289 			net_from->port = *(short *)&net_message->data[8];
    290 			net_message->readcount = 10;
    291 		}
    292 		else {
    293 			SockadrToNetadr( &from, net_from );
    294 			net_message->readcount = 0;
    295 		}
    296 
    297 		if( ret == net_message->maxsize ) {
    298 			Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) );
    299 			continue;
    300 		}
    301 
    302 		net_message->cursize = ret;
    303 		return qtrue;
    304 	}
    305 
    306 	return qfalse;
    307 }
    308 
    309 //=============================================================================
    310 
    311 static char socksBuf[4096];
    312 
    313 /*
    314 ==================
    315 Sys_SendPacket
    316 ==================
    317 */
    318 void Sys_SendPacket( int length, const void *data, netadr_t to ) {
    319 	int				ret;
    320 	struct sockaddr	addr;
    321 	SOCKET			net_socket;
    322 
    323 	if( to.type == NA_BROADCAST ) {
    324 		net_socket = ip_socket;
    325 	}
    326 	else if( to.type == NA_IP ) {
    327 		net_socket = ip_socket;
    328 	}
    329 	else if( to.type == NA_IPX ) {
    330 		net_socket = ipx_socket;
    331 	}
    332 	else if( to.type == NA_BROADCAST_IPX ) {
    333 		net_socket = ipx_socket;
    334 	}
    335 	else {
    336 		Com_Error( ERR_FATAL, "Sys_SendPacket: bad address type" );
    337 		return;
    338 	}
    339 
    340 	if( !net_socket ) {
    341 		return;
    342 	}
    343 
    344 	NetadrToSockadr( &to, &addr );
    345 
    346 	if( usingSocks && to.type == NA_IP ) {
    347 		socksBuf[0] = 0;	// reserved
    348 		socksBuf[1] = 0;
    349 		socksBuf[2] = 0;	// fragment (not fragmented)
    350 		socksBuf[3] = 1;	// address type: IPV4
    351 		*(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr;
    352 		*(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port;
    353 		memcpy( &socksBuf[10], data, length );
    354 		ret = sendto( net_socket, socksBuf, length+10, 0, &socksRelayAddr, sizeof(socksRelayAddr) );
    355 	}
    356 	else {
    357 		ret = sendto( net_socket, data, length, 0, &addr, sizeof(addr) );
    358 	}
    359 	if( ret == SOCKET_ERROR ) {
    360 		int err = WSAGetLastError();
    361 
    362 		// wouldblock is silent
    363 		if( err == WSAEWOULDBLOCK ) {
    364 			return;
    365 		}
    366 
    367 		// some PPP links do not allow broadcasts and return an error
    368 		if( ( err == WSAEADDRNOTAVAIL ) && ( ( to.type == NA_BROADCAST ) || ( to.type == NA_BROADCAST_IPX ) ) ) {
    369 			return;
    370 		}
    371 
    372 		Com_Printf( "NET_SendPacket: %s\n", NET_ErrorString() );
    373 	}
    374 }
    375 
    376 
    377 //=============================================================================
    378 
    379 /*
    380 ==================
    381 Sys_IsLANAddress
    382 
    383 LAN clients will have their rate var ignored
    384 ==================
    385 */
    386 qboolean Sys_IsLANAddress( netadr_t adr ) {
    387 	int		i;
    388 
    389 	if( adr.type == NA_LOOPBACK ) {
    390 		return qtrue;
    391 	}
    392 
    393 	if( adr.type == NA_IPX ) {
    394 		return qtrue;
    395 	}
    396 
    397 	if( adr.type != NA_IP ) {
    398 		return qfalse;
    399 	}
    400 
    401 	// choose which comparison to use based on the class of the address being tested
    402 	// any local adresses of a different class than the address being tested will fail based on the first byte
    403 
    404 	if( adr.ip[0] == 127 && adr.ip[1] == 0 && adr.ip[2] == 0 && adr.ip[3] == 1 ) {
    405 		return qtrue;
    406 	}
    407 
    408 	// Class A
    409 	if( (adr.ip[0] & 0x80) == 0x00 ) {
    410 		for ( i = 0 ; i < numIP ; i++ ) {
    411 			if( adr.ip[0] == localIP[i][0] ) {
    412 				return qtrue;
    413 			}
    414 		}
    415 		// the RFC1918 class a block will pass the above test
    416 		return qfalse;
    417 	}
    418 
    419 	// Class B
    420 	if( (adr.ip[0] & 0xc0) == 0x80 ) {
    421 		for ( i = 0 ; i < numIP ; i++ ) {
    422 			if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) {
    423 				return qtrue;
    424 			}
    425 			// also check against the RFC1918 class b blocks
    426 			if( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 ) {
    427 				return qtrue;
    428 			}
    429 		}
    430 		return qfalse;
    431 	}
    432 
    433 	// Class C
    434 	for ( i = 0 ; i < numIP ; i++ ) {
    435 		if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) {
    436 			return qtrue;
    437 		}
    438 		// also check against the RFC1918 class c blocks
    439 		if( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) {
    440 			return qtrue;
    441 		}
    442 	}
    443 	return qfalse;
    444 }
    445 
    446 /*
    447 ==================
    448 Sys_ShowIP
    449 ==================
    450 */
    451 void Sys_ShowIP(void) {
    452 	int i;
    453 
    454 	for (i = 0; i < numIP; i++) {
    455 		Com_Printf( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] );
    456 	}
    457 }
    458 
    459 
    460 //=============================================================================
    461 
    462 
    463 /*
    464 ====================
    465 NET_IPSocket
    466 ====================
    467 */
    468 int NET_IPSocket( char *net_interface, int port ) {
    469 	SOCKET				newsocket;
    470 	struct sockaddr_in	address;
    471 	qboolean			_true = qtrue;
    472 	int					i = 1;
    473 	int					err;
    474 
    475 	if( net_interface ) {
    476 		Com_Printf( "Opening IP socket: %s:%i\n", net_interface, port );
    477 	}
    478 	else {
    479 		Com_Printf( "Opening IP socket: localhost:%i\n", port );
    480 	}
    481 
    482 	if( ( newsocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) {
    483 		err = WSAGetLastError();
    484 		if( err != WSAEAFNOSUPPORT ) {
    485 			Com_Printf( "WARNING: UDP_OpenSocket: socket: %s\n", NET_ErrorString() );
    486 		}
    487 		return 0;
    488 	}
    489 
    490 	// make it non-blocking
    491 	if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
    492 		Com_Printf( "WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString() );
    493 		return 0;
    494 	}
    495 
    496 	// make it broadcast capable
    497 	if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR ) {
    498 		Com_Printf( "WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
    499 		return 0;
    500 	}
    501 
    502 	if( !net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost") ) {
    503 		address.sin_addr.s_addr = INADDR_ANY;
    504 	}
    505 	else {
    506 		Sys_StringToSockaddr( net_interface, (struct sockaddr *)&address );
    507 	}
    508 
    509 	if( port == PORT_ANY ) {
    510 		address.sin_port = 0;
    511 	}
    512 	else {
    513 		address.sin_port = htons( (short)port );
    514 	}
    515 
    516 	address.sin_family = AF_INET;
    517 
    518 	if( bind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {
    519 		Com_Printf( "WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString() );
    520 		closesocket( newsocket );
    521 		return 0;
    522 	}
    523 
    524 	return newsocket;
    525 }
    526 
    527 
    528 /*
    529 ====================
    530 NET_OpenSocks
    531 ====================
    532 */
    533 void NET_OpenSocks( int port ) {
    534 	struct sockaddr_in	address;
    535 	int					err;
    536 	struct hostent		*h;
    537 	int					len;
    538 	qboolean			rfc1929;
    539 	unsigned char		buf[64];
    540 
    541 	usingSocks = qfalse;
    542 
    543 	Com_Printf( "Opening connection to SOCKS server.\n" );
    544 
    545 	if ( ( socks_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == INVALID_SOCKET ) {
    546 		err = WSAGetLastError();
    547 		Com_Printf( "WARNING: NET_OpenSocks: socket: %s\n", NET_ErrorString() );
    548 		return;
    549 	}
    550 
    551 	h = gethostbyname( net_socksServer->string );
    552 	if ( h == NULL ) {
    553 		err = WSAGetLastError();
    554 		Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString() );
    555 		return;
    556 	}
    557 	if ( h->h_addrtype != AF_INET ) {
    558 		Com_Printf( "WARNING: NET_OpenSocks: gethostbyname: address type was not AF_INET\n" );
    559 		return;
    560 	}
    561 	address.sin_family = AF_INET;
    562 	address.sin_addr.s_addr = *(int *)h->h_addr_list[0];
    563 	address.sin_port = htons( (short)net_socksPort->integer );
    564 
    565 	if ( connect( socks_socket, (struct sockaddr *)&address, sizeof( address ) ) == SOCKET_ERROR ) {
    566 		err = WSAGetLastError();
    567 		Com_Printf( "NET_OpenSocks: connect: %s\n", NET_ErrorString() );
    568 		return;
    569 	}
    570 
    571 	// send socks authentication handshake
    572 	if ( *net_socksUsername->string || *net_socksPassword->string ) {
    573 		rfc1929 = qtrue;
    574 	}
    575 	else {
    576 		rfc1929 = qfalse;
    577 	}
    578 
    579 	buf[0] = 5;		// SOCKS version
    580 	// method count
    581 	if ( rfc1929 ) {
    582 		buf[1] = 2;
    583 		len = 4;
    584 	}
    585 	else {
    586 		buf[1] = 1;
    587 		len = 3;
    588 	}
    589 	buf[2] = 0;		// method #1 - method id #00: no authentication
    590 	if ( rfc1929 ) {
    591 		buf[2] = 2;		// method #2 - method id #02: username/password
    592 	}
    593 	if ( send( socks_socket, buf, len, 0 ) == SOCKET_ERROR ) {
    594 		err = WSAGetLastError();
    595 		Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
    596 		return;
    597 	}
    598 
    599 	// get the response
    600 	len = recv( socks_socket, buf, 64, 0 );
    601 	if ( len == SOCKET_ERROR ) {
    602 		err = WSAGetLastError();
    603 		Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
    604 		return;
    605 	}
    606 	if ( len != 2 || buf[0] != 5 ) {
    607 		Com_Printf( "NET_OpenSocks: bad response\n" );
    608 		return;
    609 	}
    610 	switch( buf[1] ) {
    611 	case 0:	// no authentication
    612 		break;
    613 	case 2: // username/password authentication
    614 		break;
    615 	default:
    616 		Com_Printf( "NET_OpenSocks: request denied\n" );
    617 		return;
    618 	}
    619 
    620 	// do username/password authentication if needed
    621 	if ( buf[1] == 2 ) {
    622 		int		ulen;
    623 		int		plen;
    624 
    625 		// build the request
    626 		ulen = strlen( net_socksUsername->string );
    627 		plen = strlen( net_socksPassword->string );
    628 
    629 		buf[0] = 1;		// username/password authentication version
    630 		buf[1] = ulen;
    631 		if ( ulen ) {
    632 			memcpy( &buf[2], net_socksUsername->string, ulen );
    633 		}
    634 		buf[2 + ulen] = plen;
    635 		if ( plen ) {
    636 			memcpy( &buf[3 + ulen], net_socksPassword->string, plen );
    637 		}
    638 
    639 		// send it
    640 		if ( send( socks_socket, buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR ) {
    641 			err = WSAGetLastError();
    642 			Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
    643 			return;
    644 		}
    645 
    646 		// get the response
    647 		len = recv( socks_socket, buf, 64, 0 );
    648 		if ( len == SOCKET_ERROR ) {
    649 			err = WSAGetLastError();
    650 			Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
    651 			return;
    652 		}
    653 		if ( len != 2 || buf[0] != 1 ) {
    654 			Com_Printf( "NET_OpenSocks: bad response\n" );
    655 			return;
    656 		}
    657 		if ( buf[1] != 0 ) {
    658 			Com_Printf( "NET_OpenSocks: authentication failed\n" );
    659 			return;
    660 		}
    661 	}
    662 
    663 	// send the UDP associate request
    664 	buf[0] = 5;		// SOCKS version
    665 	buf[1] = 3;		// command: UDP associate
    666 	buf[2] = 0;		// reserved
    667 	buf[3] = 1;		// address type: IPV4
    668 	*(int *)&buf[4] = INADDR_ANY;
    669 	*(short *)&buf[8] = htons( (short)port );		// port
    670 	if ( send( socks_socket, buf, 10, 0 ) == SOCKET_ERROR ) {
    671 		err = WSAGetLastError();
    672 		Com_Printf( "NET_OpenSocks: send: %s\n", NET_ErrorString() );
    673 		return;
    674 	}
    675 
    676 	// get the response
    677 	len = recv( socks_socket, buf, 64, 0 );
    678 	if( len == SOCKET_ERROR ) {
    679 		err = WSAGetLastError();
    680 		Com_Printf( "NET_OpenSocks: recv: %s\n", NET_ErrorString() );
    681 		return;
    682 	}
    683 	if( len < 2 || buf[0] != 5 ) {
    684 		Com_Printf( "NET_OpenSocks: bad response\n" );
    685 		return;
    686 	}
    687 	// check completion code
    688 	if( buf[1] != 0 ) {
    689 		Com_Printf( "NET_OpenSocks: request denied: %i\n", buf[1] );
    690 		return;
    691 	}
    692 	if( buf[3] != 1 ) {
    693 		Com_Printf( "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] );
    694 		return;
    695 	}
    696 	((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET;
    697 	((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4];
    698 	((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8];
    699 	memset( ((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 );
    700 
    701 	usingSocks = qtrue;
    702 }
    703 
    704 
    705 /*
    706 =====================
    707 NET_GetLocalAddress
    708 =====================
    709 */
    710 void NET_GetLocalAddress( void ) {
    711 	char				hostname[256];
    712 	struct hostent		*hostInfo;
    713 	int					error;
    714 	char				*p;
    715 	int					ip;
    716 	int					n;
    717 
    718 	if( gethostname( hostname, 256 ) == SOCKET_ERROR ) {
    719 		error = WSAGetLastError();
    720 		return;
    721 	}
    722 
    723 	hostInfo = gethostbyname( hostname );
    724 	if( !hostInfo ) {
    725 		error = WSAGetLastError();
    726 		return;
    727 	}
    728 
    729 	Com_Printf( "Hostname: %s\n", hostInfo->h_name );
    730 	n = 0;
    731 	while( ( p = hostInfo->h_aliases[n++] ) != NULL ) {
    732 		Com_Printf( "Alias: %s\n", p );
    733 	}
    734 
    735 	if ( hostInfo->h_addrtype != AF_INET ) {
    736 		return;
    737 	}
    738 
    739 	numIP = 0;
    740 	while( ( p = hostInfo->h_addr_list[numIP] ) != NULL && numIP < MAX_IPS ) {
    741 		ip = ntohl( *(int *)p );
    742 		localIP[ numIP ][0] = p[0];
    743 		localIP[ numIP ][1] = p[1];
    744 		localIP[ numIP ][2] = p[2];
    745 		localIP[ numIP ][3] = p[3];
    746 		Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff );
    747 		numIP++;
    748 	}
    749 }
    750 
    751 /*
    752 ====================
    753 NET_OpenIP
    754 ====================
    755 */
    756 void NET_OpenIP( void ) {
    757 	cvar_t	*ip;
    758 	int		port;
    759 	int		i;
    760 
    761 	ip = Cvar_Get( "net_ip", "localhost", CVAR_LATCH );
    762 	port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH )->integer;
    763 
    764 	// automatically scan for a valid port, so multiple
    765 	// dedicated servers can be started without requiring
    766 	// a different net_port for each one
    767 	for( i = 0 ; i < 10 ; i++ ) {
    768 		ip_socket = NET_IPSocket( ip->string, port + i );
    769 		if ( ip_socket ) {
    770 			Cvar_SetValue( "net_port", port + i );
    771 			if ( net_socksEnabled->integer ) {
    772 				NET_OpenSocks( port + i );
    773 			}
    774 			NET_GetLocalAddress();
    775 			return;
    776 		}
    777 	}
    778 	Com_Printf( "WARNING: Couldn't allocate IP port\n");
    779 }
    780 
    781 
    782 /*
    783 ====================
    784 NET_IPXSocket
    785 ====================
    786 */
    787 int NET_IPXSocket( int port ) {
    788 	SOCKET				newsocket;
    789 	struct sockaddr_ipx	address;
    790 	int					_true = 1;
    791 	int					err;
    792 
    793 	if( ( newsocket = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX ) ) == INVALID_SOCKET ) {
    794 		err = WSAGetLastError();
    795 		if (err != WSAEAFNOSUPPORT) {
    796 			Com_Printf( "WARNING: IPX_Socket: socket: %s\n", NET_ErrorString() );
    797 		}
    798 		return 0;
    799 	}
    800 
    801 	// make it non-blocking
    802 	if( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
    803 		Com_Printf( "WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString() );
    804 		return 0;
    805 	}
    806 
    807 	// make it broadcast capable
    808 	if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof( _true ) ) == SOCKET_ERROR ) {
    809 		Com_Printf( "WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() );
    810 		return 0;
    811 	}
    812 
    813 	address.sa_family = AF_IPX;
    814 	memset( address.sa_netnum, 0, 4 );
    815 	memset( address.sa_nodenum, 0, 6 );
    816 	if( port == PORT_ANY ) {
    817 		address.sa_socket = 0;
    818 	}
    819 	else {
    820 		address.sa_socket = htons( (short)port );
    821 	}
    822 
    823 	if( bind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR ) {
    824 		Com_Printf( "WARNING: IPX_Socket: bind: %s\n", NET_ErrorString() );
    825 		closesocket( newsocket );
    826 		return 0;
    827 	}
    828 
    829 	return newsocket;
    830 }
    831 
    832 
    833 /*
    834 ====================
    835 NET_OpenIPX
    836 ====================
    837 */
    838 void NET_OpenIPX( void ) {
    839 	int		port;
    840 
    841 	port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH )->integer;
    842 	ipx_socket = NET_IPXSocket( port );
    843 }
    844 
    845 
    846 
    847 //===================================================================
    848 
    849 
    850 /*
    851 ====================
    852 NET_GetCvars
    853 ====================
    854 */
    855 static qboolean NET_GetCvars( void ) {
    856 	qboolean	modified;
    857 
    858 	modified = qfalse;
    859 
    860 	if( net_noudp && net_noudp->modified ) {
    861 		modified = qtrue;
    862 	}
    863 	net_noudp = Cvar_Get( "net_noudp", "0", CVAR_LATCH | CVAR_ARCHIVE );
    864 
    865 	if( net_noipx && net_noipx->modified ) {
    866 		modified = qtrue;
    867 	}
    868 	net_noipx = Cvar_Get( "net_noipx", "0", CVAR_LATCH | CVAR_ARCHIVE );
    869 
    870 
    871 	if( net_socksEnabled && net_socksEnabled->modified ) {
    872 		modified = qtrue;
    873 	}
    874 	net_socksEnabled = Cvar_Get( "net_socksEnabled", "0", CVAR_LATCH | CVAR_ARCHIVE );
    875 
    876 	if( net_socksServer && net_socksServer->modified ) {
    877 		modified = qtrue;
    878 	}
    879 	net_socksServer = Cvar_Get( "net_socksServer", "", CVAR_LATCH | CVAR_ARCHIVE );
    880 
    881 	if( net_socksPort && net_socksPort->modified ) {
    882 		modified = qtrue;
    883 	}
    884 	net_socksPort = Cvar_Get( "net_socksPort", "1080", CVAR_LATCH | CVAR_ARCHIVE );
    885 
    886 	if( net_socksUsername && net_socksUsername->modified ) {
    887 		modified = qtrue;
    888 	}
    889 	net_socksUsername = Cvar_Get( "net_socksUsername", "", CVAR_LATCH | CVAR_ARCHIVE );
    890 
    891 	if( net_socksPassword && net_socksPassword->modified ) {
    892 		modified = qtrue;
    893 	}
    894 	net_socksPassword = Cvar_Get( "net_socksPassword", "", CVAR_LATCH | CVAR_ARCHIVE );
    895 
    896 
    897 	return modified;
    898 }
    899 
    900 
    901 /*
    902 ====================
    903 NET_Config
    904 ====================
    905 */
    906 void NET_Config( qboolean enableNetworking ) {
    907 	qboolean	modified;
    908 	qboolean	stop;
    909 	qboolean	start;
    910 
    911 	// get any latched changes to cvars
    912 	modified = NET_GetCvars();
    913 
    914 	if( net_noudp->integer && net_noipx->integer ) {
    915 		enableNetworking = qfalse;
    916 	}
    917 
    918 	// if enable state is the same and no cvars were modified, we have nothing to do
    919 	if( enableNetworking == networkingEnabled && !modified ) {
    920 		return;
    921 	}
    922 
    923 	if( enableNetworking == networkingEnabled ) {
    924 		if( enableNetworking ) {
    925 			stop = qtrue;
    926 			start = qtrue;
    927 		}
    928 		else {
    929 			stop = qfalse;
    930 			start = qfalse;
    931 		}
    932 	}
    933 	else {
    934 		if( enableNetworking ) {
    935 			stop = qfalse;
    936 			start = qtrue;
    937 		}
    938 		else {
    939 			stop = qtrue;
    940 			start = qfalse;
    941 		}
    942 		networkingEnabled = enableNetworking;
    943 	}
    944 
    945 	if( stop ) {
    946 		if ( ip_socket && ip_socket != INVALID_SOCKET ) {
    947 			closesocket( ip_socket );
    948 			ip_socket = 0;
    949 		}
    950 
    951 		if ( socks_socket && socks_socket != INVALID_SOCKET ) {
    952 			closesocket( socks_socket );
    953 			socks_socket = 0;
    954 		}
    955 
    956 		if ( ipx_socket && ipx_socket != INVALID_SOCKET ) {
    957 			closesocket( ipx_socket );
    958 			ipx_socket = 0;
    959 		}
    960 	}
    961 
    962 	if( start ) {
    963 		if (! net_noudp->integer ) {
    964 			NET_OpenIP();
    965 		}
    966 		if (! net_noipx->integer ) {
    967 			NET_OpenIPX();
    968 		}
    969 	}
    970 }
    971 
    972 
    973 /*
    974 ====================
    975 NET_Init
    976 ====================
    977 */
    978 void NET_Init( void ) {
    979 	int		r;
    980 
    981 	r = WSAStartup( MAKEWORD( 1, 1 ), &winsockdata );
    982 	if( r ) {
    983 		Com_Printf( "WARNING: Winsock initialization failed, returned %d\n", r );
    984 		return;
    985 	}
    986 
    987 	winsockInitialized = qtrue;
    988 	Com_Printf( "Winsock Initialized\n" );
    989 
    990 	// this is really just to get the cvars registered
    991 	NET_GetCvars();
    992 
    993 	//FIXME testing!
    994 	NET_Config( qtrue );
    995 }
    996 
    997 
    998 /*
    999 ====================
   1000 NET_Shutdown
   1001 ====================
   1002 */
   1003 void NET_Shutdown( void ) {
   1004 	if ( !winsockInitialized ) {
   1005 		return;
   1006 	}
   1007 	NET_Config( qfalse );
   1008 	WSACleanup();
   1009 	winsockInitialized = qfalse;
   1010 }
   1011 
   1012 
   1013 /*
   1014 ====================
   1015 NET_Sleep
   1016 
   1017 sleeps msec or until net socket is ready
   1018 ====================
   1019 */
   1020 void NET_Sleep( int msec ) {
   1021 }
   1022 
   1023 
   1024 /*
   1025 ====================
   1026 NET_Restart_f
   1027 ====================
   1028 */
   1029 void NET_Restart( void ) {
   1030 	NET_Config( networkingEnabled );
   1031 }