Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

net_wins.c (18761B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // net_wins.c
     21 
     22 #include "winsock.h"
     23 #include "wsipx.h"
     24 #include "../qcommon/qcommon.h"
     25 
     26 #define	MAX_LOOPBACK	4
     27 
     28 typedef struct
     29 {
     30 	byte	data[MAX_MSGLEN];
     31 	int		datalen;
     32 } loopmsg_t;
     33 
     34 typedef struct
     35 {
     36 	loopmsg_t	msgs[MAX_LOOPBACK];
     37 	int			get, send;
     38 } loopback_t;
     39 
     40 
     41 cvar_t		*net_shownet;
     42 static cvar_t	*noudp;
     43 static cvar_t	*noipx;
     44 
     45 loopback_t	loopbacks[2];
     46 int			ip_sockets[2];
     47 int			ipx_sockets[2];
     48 
     49 char *NET_ErrorString (void);
     50 
     51 //=============================================================================
     52 
     53 void NetadrToSockadr (netadr_t *a, struct sockaddr *s)
     54 {
     55 	memset (s, 0, sizeof(*s));
     56 
     57 	if (a->type == NA_BROADCAST)
     58 	{
     59 		((struct sockaddr_in *)s)->sin_family = AF_INET;
     60 		((struct sockaddr_in *)s)->sin_port = a->port;
     61 		((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
     62 	}
     63 	else if (a->type == NA_IP)
     64 	{
     65 		((struct sockaddr_in *)s)->sin_family = AF_INET;
     66 		((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
     67 		((struct sockaddr_in *)s)->sin_port = a->port;
     68 	}
     69 	else if (a->type == NA_IPX)
     70 	{
     71 		((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
     72 		memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4);
     73 		memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6);
     74 		((struct sockaddr_ipx *)s)->sa_socket = a->port;
     75 	}
     76 	else if (a->type == NA_BROADCAST_IPX)
     77 	{
     78 		((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
     79 		memset(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4);
     80 		memset(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6);
     81 		((struct sockaddr_ipx *)s)->sa_socket = a->port;
     82 	}
     83 }
     84 
     85 void SockadrToNetadr (struct sockaddr *s, netadr_t *a)
     86 {
     87 	if (s->sa_family == AF_INET)
     88 	{
     89 		a->type = NA_IP;
     90 		*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
     91 		a->port = ((struct sockaddr_in *)s)->sin_port;
     92 	}
     93 	else if (s->sa_family == AF_IPX)
     94 	{
     95 		a->type = NA_IPX;
     96 		memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
     97 		memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
     98 		a->port = ((struct sockaddr_ipx *)s)->sa_socket;
     99 	}
    100 }
    101 
    102 
    103 qboolean	NET_CompareAdr (netadr_t a, netadr_t b)
    104 {
    105 	if (a.type != b.type)
    106 		return false;
    107 
    108 	if (a.type == NA_LOOPBACK)
    109 		return TRUE;
    110 
    111 	if (a.type == NA_IP)
    112 	{
    113 		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] && a.port == b.port)
    114 			return true;
    115 		return false;
    116 	}
    117 
    118 	if (a.type == NA_IPX)
    119 	{
    120 		if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
    121 			return true;
    122 		return false;
    123 	}
    124 }
    125 
    126 /*
    127 ===================
    128 NET_CompareBaseAdr
    129 
    130 Compares without the port
    131 ===================
    132 */
    133 qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b)
    134 {
    135 	if (a.type != b.type)
    136 		return false;
    137 
    138 	if (a.type == NA_LOOPBACK)
    139 		return TRUE;
    140 
    141 	if (a.type == NA_IP)
    142 	{
    143 		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])
    144 			return true;
    145 		return false;
    146 	}
    147 
    148 	if (a.type == NA_IPX)
    149 	{
    150 		if ((memcmp(a.ipx, b.ipx, 10) == 0))
    151 			return true;
    152 		return false;
    153 	}
    154 }
    155 
    156 char	*NET_AdrToString (netadr_t a)
    157 {
    158 	static	char	s[64];
    159 
    160 	if (a.type == NA_LOOPBACK)
    161 		Com_sprintf (s, sizeof(s), "loopback");
    162 	else if (a.type == NA_IP)
    163 		Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
    164 	else
    165 		Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port));
    166 
    167 	return s;
    168 }
    169 
    170 
    171 /*
    172 =============
    173 NET_StringToAdr
    174 
    175 localhost
    176 idnewt
    177 idnewt:28000
    178 192.246.40.70
    179 192.246.40.70:28000
    180 =============
    181 */
    182 #define DO(src,dest)	\
    183 	copy[0] = s[src];	\
    184 	copy[1] = s[src + 1];	\
    185 	sscanf (copy, "%x", &val);	\
    186 	((struct sockaddr_ipx *)sadr)->dest = val
    187 
    188 qboolean	NET_StringToSockaddr (char *s, struct sockaddr *sadr)
    189 {
    190 	struct hostent	*h;
    191 	char	*colon;
    192 	int		val;
    193 	char	copy[128];
    194 	
    195 	memset (sadr, 0, sizeof(*sadr));
    196 
    197 	if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':'))	// check for an IPX address
    198 	{
    199 		((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
    200 		copy[2] = 0;
    201 		DO(0, sa_netnum[0]);
    202 		DO(2, sa_netnum[1]);
    203 		DO(4, sa_netnum[2]);
    204 		DO(6, sa_netnum[3]);
    205 		DO(9, sa_nodenum[0]);
    206 		DO(11, sa_nodenum[1]);
    207 		DO(13, sa_nodenum[2]);
    208 		DO(15, sa_nodenum[3]);
    209 		DO(17, sa_nodenum[4]);
    210 		DO(19, sa_nodenum[5]);
    211 		sscanf (&s[22], "%u", &val);
    212 		((struct sockaddr_ipx *)sadr)->sa_socket = htons((unsigned short)val);
    213 	}
    214 	else
    215 	{
    216 		((struct sockaddr_in *)sadr)->sin_family = AF_INET;
    217 		
    218 		((struct sockaddr_in *)sadr)->sin_port = 0;
    219 
    220 		strcpy (copy, s);
    221 		// strip off a trailing :port if present
    222 		for (colon = copy ; *colon ; colon++)
    223 			if (*colon == ':')
    224 			{
    225 				*colon = 0;
    226 				((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));	
    227 			}
    228 		
    229 		if (copy[0] >= '0' && copy[0] <= '9')
    230 		{
    231 			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
    232 		}
    233 		else
    234 		{
    235 			if (! (h = gethostbyname(copy)) )
    236 				return 0;
    237 			*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
    238 		}
    239 	}
    240 	
    241 	return true;
    242 }
    243 
    244 #undef DO
    245 
    246 /*
    247 =============
    248 NET_StringToAdr
    249 
    250 localhost
    251 idnewt
    252 idnewt:28000
    253 192.246.40.70
    254 192.246.40.70:28000
    255 =============
    256 */
    257 qboolean	NET_StringToAdr (char *s, netadr_t *a)
    258 {
    259 	struct sockaddr sadr;
    260 	
    261 	if (!strcmp (s, "localhost"))
    262 	{
    263 		memset (a, 0, sizeof(*a));
    264 		a->type = NA_LOOPBACK;
    265 		return true;
    266 	}
    267 
    268 	if (!NET_StringToSockaddr (s, &sadr))
    269 		return false;
    270 	
    271 	SockadrToNetadr (&sadr, a);
    272 
    273 	return true;
    274 }
    275 
    276 
    277 qboolean	NET_IsLocalAddress (netadr_t adr)
    278 {
    279 	return adr.type == NA_LOOPBACK;
    280 }
    281 
    282 /*
    283 =============================================================================
    284 
    285 LOOPBACK BUFFERS FOR LOCAL PLAYER
    286 
    287 =============================================================================
    288 */
    289 
    290 qboolean	NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
    291 {
    292 	int		i;
    293 	loopback_t	*loop;
    294 
    295 	loop = &loopbacks[sock];
    296 
    297 	if (loop->send - loop->get > MAX_LOOPBACK)
    298 		loop->get = loop->send - MAX_LOOPBACK;
    299 
    300 	if (loop->get >= loop->send)
    301 		return false;
    302 
    303 	i = loop->get & (MAX_LOOPBACK-1);
    304 	loop->get++;
    305 
    306 	memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
    307 	net_message->cursize = loop->msgs[i].datalen;
    308 	memset (net_from, 0, sizeof(*net_from));
    309 	net_from->type = NA_LOOPBACK;
    310 	return true;
    311 
    312 }
    313 
    314 
    315 void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
    316 {
    317 	int		i;
    318 	loopback_t	*loop;
    319 
    320 	loop = &loopbacks[sock^1];
    321 
    322 	i = loop->send & (MAX_LOOPBACK-1);
    323 	loop->send++;
    324 
    325 	memcpy (loop->msgs[i].data, data, length);
    326 	loop->msgs[i].datalen = length;
    327 }
    328 
    329 //=============================================================================
    330 
    331 qboolean	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
    332 {
    333 	int 	ret;
    334 	struct sockaddr from;
    335 	int		fromlen;
    336 	int		net_socket;
    337 	int		protocol;
    338 	int		err;
    339 
    340 	if (NET_GetLoopPacket (sock, net_from, net_message))
    341 		return true;
    342 
    343 	for (protocol = 0 ; protocol < 2 ; protocol++)
    344 	{
    345 		if (protocol == 0)
    346 			net_socket = ip_sockets[sock];
    347 		else
    348 			net_socket = ipx_sockets[sock];
    349 
    350 		if (!net_socket)
    351 			continue;
    352 
    353 		fromlen = sizeof(from);
    354 		ret = recvfrom (net_socket, net_message->data, net_message->maxsize
    355 			, 0, (struct sockaddr *)&from, &fromlen);
    356 		if (ret == -1)
    357 		{
    358 			err = WSAGetLastError();
    359 
    360 			if (err == WSAEWOULDBLOCK)
    361 				continue;
    362 			if (dedicated->value)	// let dedicated servers continue after errors
    363 				Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
    364 			else
    365 				Com_Error (ERR_DROP, "NET_GetPacket: %s", NET_ErrorString());
    366 			continue;
    367 		}
    368 
    369 		SockadrToNetadr (&from, net_from);
    370 
    371 		if (ret == net_message->maxsize)
    372 		{
    373 			Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
    374 			continue;
    375 		}
    376 
    377 		net_message->cursize = ret;
    378 		return true;
    379 	}
    380 
    381 	return false;
    382 }
    383 
    384 //=============================================================================
    385 
    386 void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
    387 {
    388 	int		ret;
    389 	struct sockaddr	addr;
    390 	int		net_socket;
    391 
    392 	if ( to.type == NA_LOOPBACK )
    393 	{
    394 		NET_SendLoopPacket (sock, length, data, to);
    395 		return;
    396 	}
    397 
    398 	if (to.type == NA_BROADCAST)
    399 	{
    400 		net_socket = ip_sockets[sock];
    401 		if (!net_socket)
    402 			return;
    403 	}
    404 	else if (to.type == NA_IP)
    405 	{
    406 		net_socket = ip_sockets[sock];
    407 		if (!net_socket)
    408 			return;
    409 	}
    410 	else if (to.type == NA_IPX)
    411 	{
    412 		net_socket = ipx_sockets[sock];
    413 		if (!net_socket)
    414 			return;
    415 	}
    416 	else if (to.type == NA_BROADCAST_IPX)
    417 	{
    418 		net_socket = ipx_sockets[sock];
    419 		if (!net_socket)
    420 			return;
    421 	}
    422 	else
    423 		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
    424 
    425 	NetadrToSockadr (&to, &addr);
    426 
    427 	ret = sendto (net_socket, data, length, 0, &addr, sizeof(addr) );
    428 	if (ret == -1)
    429 	{
    430 		int err = WSAGetLastError();
    431 
    432 		// wouldblock is silent
    433 		if (err == WSAEWOULDBLOCK)
    434 			return;
    435 
    436 		// some PPP links dont allow broadcasts
    437 		if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX)))
    438 			return;
    439 
    440 		if (dedicated->value)	// let dedicated servers continue after errors
    441 		{
    442 			Com_Printf ("NET_SendPacket ERROR: %s\n", NET_ErrorString());
    443 		}
    444 		else
    445 		{
    446 			if (err == WSAEADDRNOTAVAIL)
    447 			{
    448 				Com_DPrintf ("NET_SendPacket Warning: %s : %s\n", NET_ErrorString(), NET_AdrToString (to));
    449 			}
    450 			else
    451 			{
    452 				Com_Error (ERR_DROP, "NET_SendPacket ERROR: %s\n", NET_ErrorString());
    453 			}
    454 		}
    455 	}
    456 }
    457 
    458 
    459 //=============================================================================
    460 
    461 
    462 /*
    463 ====================
    464 NET_Socket
    465 ====================
    466 */
    467 int NET_IPSocket (char *net_interface, int port)
    468 {
    469 	int					newsocket;
    470 	struct sockaddr_in	address;
    471 	qboolean			_true = true;
    472 	int					i = 1;
    473 	int					err;
    474 
    475 	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    476 	{
    477 		err = WSAGetLastError();
    478 		if (err != WSAEAFNOSUPPORT)
    479 			Com_Printf ("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString());
    480 		return 0;
    481 	}
    482 
    483 	// make it non-blocking
    484 	if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
    485 	{
    486 		Com_Printf ("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
    487 		return 0;
    488 	}
    489 
    490 	// make it broadcast capable
    491 	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
    492 	{
    493 		Com_Printf ("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
    494 		return 0;
    495 	}
    496 
    497 	if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
    498 		address.sin_addr.s_addr = INADDR_ANY;
    499 	else
    500 		NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
    501 
    502 	if (port == PORT_ANY)
    503 		address.sin_port = 0;
    504 	else
    505 		address.sin_port = htons((short)port);
    506 
    507 	address.sin_family = AF_INET;
    508 
    509 	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
    510 	{
    511 		Com_Printf ("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
    512 		closesocket (newsocket);
    513 		return 0;
    514 	}
    515 
    516 	return newsocket;
    517 }
    518 
    519 
    520 /*
    521 ====================
    522 NET_OpenIP
    523 ====================
    524 */
    525 void NET_OpenIP (void)
    526 {
    527 	cvar_t	*ip;
    528 	int		port;
    529 	int		dedicated;
    530 
    531 	ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
    532 
    533 	dedicated = Cvar_VariableValue ("dedicated");
    534 
    535 	if (!ip_sockets[NS_SERVER])
    536 	{
    537 		port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value;
    538 		if (!port)
    539 		{
    540 			port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
    541 			if (!port)
    542 			{
    543 				port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
    544 			}
    545 		}
    546 		ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port);
    547 		if (!ip_sockets[NS_SERVER] && dedicated)
    548 			Com_Error (ERR_FATAL, "Couldn't allocate dedicated server IP port");
    549 	}
    550 
    551 
    552 	// dedicated servers don't need client ports
    553 	if (dedicated)
    554 		return;
    555 
    556 	if (!ip_sockets[NS_CLIENT])
    557 	{
    558 		port = Cvar_Get("ip_clientport", "0", CVAR_NOSET)->value;
    559 		if (!port)
    560 		{
    561 			port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
    562 			if (!port)
    563 				port = PORT_ANY;
    564 		}
    565 		ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, port);
    566 		if (!ip_sockets[NS_CLIENT])
    567 			ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, PORT_ANY);
    568 	}
    569 }
    570 
    571 
    572 /*
    573 ====================
    574 IPX_Socket
    575 ====================
    576 */
    577 int NET_IPXSocket (int port)
    578 {
    579 	int					newsocket;
    580 	struct sockaddr_ipx	address;
    581 	int					_true = 1;
    582 	int					err;
    583 
    584 	if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
    585 	{
    586 		err = WSAGetLastError();
    587 		if (err != WSAEAFNOSUPPORT)
    588 			Com_Printf ("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString());
    589 		return 0;
    590 	}
    591 
    592 	// make it non-blocking
    593 	if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
    594 	{
    595 		Com_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
    596 		return 0;
    597 	}
    598 
    599 	// make it broadcast capable
    600 	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
    601 	{
    602 		Com_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
    603 		return 0;
    604 	}
    605 
    606 	address.sa_family = AF_IPX;
    607 	memset (address.sa_netnum, 0, 4);
    608 	memset (address.sa_nodenum, 0, 6);
    609 	if (port == PORT_ANY)
    610 		address.sa_socket = 0;
    611 	else
    612 		address.sa_socket = htons((short)port);
    613 
    614 	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
    615 	{
    616 		Com_Printf ("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString());
    617 		closesocket (newsocket);
    618 		return 0;
    619 	}
    620 
    621 	return newsocket;
    622 }
    623 
    624 
    625 /*
    626 ====================
    627 NET_OpenIPX
    628 ====================
    629 */
    630 void NET_OpenIPX (void)
    631 {
    632 	int		port;
    633 	int		dedicated;
    634 
    635 	dedicated = Cvar_VariableValue ("dedicated");
    636 
    637 	if (!ipx_sockets[NS_SERVER])
    638 	{
    639 		port = Cvar_Get("ipx_hostport", "0", CVAR_NOSET)->value;
    640 		if (!port)
    641 		{
    642 			port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
    643 			if (!port)
    644 			{
    645 				port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
    646 			}
    647 		}
    648 		ipx_sockets[NS_SERVER] = NET_IPXSocket (port);
    649 	}
    650 
    651 	// dedicated servers don't need client ports
    652 	if (dedicated)
    653 		return;
    654 
    655 	if (!ipx_sockets[NS_CLIENT])
    656 	{
    657 		port = Cvar_Get("ipx_clientport", "0", CVAR_NOSET)->value;
    658 		if (!port)
    659 		{
    660 			port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
    661 			if (!port)
    662 				port = PORT_ANY;
    663 		}
    664 		ipx_sockets[NS_CLIENT] = NET_IPXSocket (port);
    665 		if (!ipx_sockets[NS_CLIENT])
    666 			ipx_sockets[NS_CLIENT] = NET_IPXSocket (PORT_ANY);
    667 	}
    668 }
    669 
    670 
    671 /*
    672 ====================
    673 NET_Config
    674 
    675 A single player game will only use the loopback code
    676 ====================
    677 */
    678 void	NET_Config (qboolean multiplayer)
    679 {
    680 	int		i;
    681 	static	qboolean	old_config;
    682 
    683 	if (old_config == multiplayer)
    684 		return;
    685 
    686 	old_config = multiplayer;
    687 
    688 	if (!multiplayer)
    689 	{	// shut down any existing sockets
    690 		for (i=0 ; i<2 ; i++)
    691 		{
    692 			if (ip_sockets[i])
    693 			{
    694 				closesocket (ip_sockets[i]);
    695 				ip_sockets[i] = 0;
    696 			}
    697 			if (ipx_sockets[i])
    698 			{
    699 				closesocket (ipx_sockets[i]);
    700 				ipx_sockets[i] = 0;
    701 			}
    702 		}
    703 	}
    704 	else
    705 	{	// open sockets
    706 		if (! noudp->value)
    707 			NET_OpenIP ();
    708 		if (! noipx->value)
    709 			NET_OpenIPX ();
    710 	}
    711 }
    712 
    713 // sleeps msec or until net socket is ready
    714 void NET_Sleep(int msec)
    715 {
    716     struct timeval timeout;
    717 	fd_set	fdset;
    718 	extern cvar_t *dedicated;
    719 	int i;
    720 
    721 	if (!dedicated || !dedicated->value)
    722 		return; // we're not a server, just run full speed
    723 
    724 	FD_ZERO(&fdset);
    725 	i = 0;
    726 	if (ip_sockets[NS_SERVER]) {
    727 		FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
    728 		i = ip_sockets[NS_SERVER];
    729 	}
    730 	if (ipx_sockets[NS_SERVER]) {
    731 		FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket
    732 		if (ipx_sockets[NS_SERVER] > i)
    733 			i = ipx_sockets[NS_SERVER];
    734 	}
    735 	timeout.tv_sec = msec/1000;
    736 	timeout.tv_usec = (msec%1000)*1000;
    737 	select(i+1, &fdset, NULL, NULL, &timeout);
    738 }
    739 
    740 //===================================================================
    741 
    742 
    743 static WSADATA		winsockdata;
    744 
    745 /*
    746 ====================
    747 NET_Init
    748 ====================
    749 */
    750 void NET_Init (void)
    751 {
    752 	WORD	wVersionRequested; 
    753 	int		r;
    754 
    755 	wVersionRequested = MAKEWORD(1, 1); 
    756 
    757 	r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
    758 
    759 	if (r)
    760 		Com_Error (ERR_FATAL,"Winsock initialization failed.");
    761 
    762 	Com_Printf("Winsock Initialized\n");
    763 
    764 	noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
    765 	noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
    766 
    767 	net_shownet = Cvar_Get ("net_shownet", "0", 0);
    768 }
    769 
    770 
    771 /*
    772 ====================
    773 NET_Shutdown
    774 ====================
    775 */
    776 void	NET_Shutdown (void)
    777 {
    778 	NET_Config (false);	// close sockets
    779 
    780 	WSACleanup ();
    781 }
    782 
    783 
    784 /*
    785 ====================
    786 NET_ErrorString
    787 ====================
    788 */
    789 char *NET_ErrorString (void)
    790 {
    791 	int		code;
    792 
    793 	code = WSAGetLastError ();
    794 	switch (code)
    795 	{
    796 	case WSAEINTR: return "WSAEINTR";
    797 	case WSAEBADF: return "WSAEBADF";
    798 	case WSAEACCES: return "WSAEACCES";
    799 	case WSAEDISCON: return "WSAEDISCON";
    800 	case WSAEFAULT: return "WSAEFAULT";
    801 	case WSAEINVAL: return "WSAEINVAL";
    802 	case WSAEMFILE: return "WSAEMFILE";
    803 	case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
    804 	case WSAEINPROGRESS: return "WSAEINPROGRESS";
    805 	case WSAEALREADY: return "WSAEALREADY";
    806 	case WSAENOTSOCK: return "WSAENOTSOCK";
    807 	case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
    808 	case WSAEMSGSIZE: return "WSAEMSGSIZE";
    809 	case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
    810 	case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
    811 	case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
    812 	case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
    813 	case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
    814 	case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
    815 	case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
    816 	case WSAEADDRINUSE: return "WSAEADDRINUSE";
    817 	case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
    818 	case WSAENETDOWN: return "WSAENETDOWN";
    819 	case WSAENETUNREACH: return "WSAENETUNREACH";
    820 	case WSAENETRESET: return "WSAENETRESET";
    821 	case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
    822 	case WSAECONNRESET: return "WSAECONNRESET";
    823 	case WSAENOBUFS: return "WSAENOBUFS";
    824 	case WSAEISCONN: return "WSAEISCONN";
    825 	case WSAENOTCONN: return "WSAENOTCONN";
    826 	case WSAESHUTDOWN: return "WSAESHUTDOWN";
    827 	case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
    828 	case WSAETIMEDOUT: return "WSAETIMEDOUT";
    829 	case WSAECONNREFUSED: return "WSAECONNREFUSED";
    830 	case WSAELOOP: return "WSAELOOP";
    831 	case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
    832 	case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
    833 	case WSASYSNOTREADY: return "WSASYSNOTREADY";
    834 	case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
    835 	case WSANOTINITIALISED: return "WSANOTINITIALISED";
    836 	case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
    837 	case WSATRY_AGAIN: return "WSATRY_AGAIN";
    838 	case WSANO_RECOVERY: return "WSANO_RECOVERY";
    839 	case WSANO_DATA: return "WSANO_DATA";
    840 	default: return "NO ERROR";
    841 	}
    842 }