File: win32\net_wins.c

    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 
  357                 SockadrToNetadr (&from, net_from);
  358 
  359                 if (ret == -1)
  360                 {
  361                         err = WSAGetLastError();
  362 
  363                         if (err == WSAEWOULDBLOCK)
  364                                 continue;
  365                         if (err == WSAEMSGSIZE) {
  366                                 Com_Printf ("Warning:  Oversize packet from %s\n",
  367                                                 NET_AdrToString(*net_from));
  368                                 continue;
  369                         }
  370 
  371                         if (dedicated->value)   // let dedicated servers continue after errors
  372                                 Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(),
  373                                                 NET_AdrToString(*net_from));
  374                         else
  375                                 Com_Error (ERR_DROP, "NET_GetPacket: %s from %s", 
  376                                                 NET_ErrorString(), NET_AdrToString(*net_from));
  377                         continue;
  378                 }
  379 
  380                 if (ret == net_message->maxsize)
  381                 {
  382                         Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
  383                         continue;
  384                 }
  385 
  386                 net_message->cursize = ret;
  387                 return true;
  388         }
  389 
  390         return false;
  391 }
  392 
  393 //=============================================================================
  394 
  395 void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
  396 {
  397         int             ret;
  398         struct sockaddr addr;
  399         int             net_socket;
  400 
  401         if ( to.type == NA_LOOPBACK )
  402         {
  403                 NET_SendLoopPacket (sock, length, data, to);
  404                 return;
  405         }
  406 
  407         if (to.type == NA_BROADCAST)
  408         {
  409                 net_socket = ip_sockets[sock];
  410                 if (!net_socket)
  411                         return;
  412         }
  413         else if (to.type == NA_IP)
  414         {
  415                 net_socket = ip_sockets[sock];
  416                 if (!net_socket)
  417                         return;
  418         }
  419         else if (to.type == NA_IPX)
  420         {
  421                 net_socket = ipx_sockets[sock];
  422                 if (!net_socket)
  423                         return;
  424         }
  425         else if (to.type == NA_BROADCAST_IPX)
  426         {
  427                 net_socket = ipx_sockets[sock];
  428                 if (!net_socket)
  429                         return;
  430         }
  431         else
  432                 Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
  433 
  434         NetadrToSockadr (&to, &addr);
  435 
  436         ret = sendto (net_socket, data, length, 0, &addr, sizeof(addr) );
  437         if (ret == -1)
  438         {
  439                 int err = WSAGetLastError();
  440 
  441                 // wouldblock is silent
  442                 if (err == WSAEWOULDBLOCK)
  443                         return;
  444 
  445                 // some PPP links dont allow broadcasts
  446                 if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX)))
  447                         return;
  448 
  449                 if (dedicated->value)   // let dedicated servers continue after errors
  450                 {
  451                         Com_Printf ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(),
  452                                 NET_AdrToString (to));
  453                 }
  454                 else
  455                 {
  456                         if (err == WSAEADDRNOTAVAIL)
  457                         {
  458                                 Com_DPrintf ("NET_SendPacket Warning: %s : %s\n", 
  459                                                 NET_ErrorString(), NET_AdrToString (to));
  460                         }
  461                         else
  462                         {
  463                                 Com_Error (ERR_DROP, "NET_SendPacket ERROR: %s to %s\n", 
  464                                                 NET_ErrorString(), NET_AdrToString (to));
  465                         }
  466                 }
  467         }
  468 }
  469 
  470 
  471 //=============================================================================
  472 
  473 
  474 /*
  475 ====================
  476 NET_Socket
  477 ====================
  478 */
  479 int NET_IPSocket (char *net_interface, int port)
  480 {
  481         int                                     newsocket;
  482         struct sockaddr_in      address;
  483         qboolean                        _true = true;
  484         int                                     i = 1;
  485         int                                     err;
  486 
  487         if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
  488         {
  489                 err = WSAGetLastError();
  490                 if (err != WSAEAFNOSUPPORT)
  491                         Com_Printf ("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString());
  492                 return 0;
  493         }
  494 
  495         // make it non-blocking
  496         if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
  497         {
  498                 Com_Printf ("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
  499                 return 0;
  500         }
  501 
  502         // make it broadcast capable
  503         if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
  504         {
  505                 Com_Printf ("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
  506                 return 0;
  507         }
  508 
  509         if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
  510                 address.sin_addr.s_addr = INADDR_ANY;
  511         else
  512                 NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
  513 
  514         if (port == PORT_ANY)
  515                 address.sin_port = 0;
  516         else
  517                 address.sin_port = htons((short)port);
  518 
  519         address.sin_family = AF_INET;
  520 
  521         if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
  522         {
  523                 Com_Printf ("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
  524                 closesocket (newsocket);
  525                 return 0;
  526         }
  527 
  528         return newsocket;
  529 }
  530 
  531 
  532 /*
  533 ====================
  534 NET_OpenIP
  535 ====================
  536 */
  537 void NET_OpenIP (void)
  538 {
  539         cvar_t  *ip;
  540         int             port;
  541         int             dedicated;
  542 
  543         ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
  544 
  545         dedicated = Cvar_VariableValue ("dedicated");
  546 
  547         if (!ip_sockets[NS_SERVER])
  548         {
  549                 port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value;
  550                 if (!port)
  551                 {
  552                         port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
  553                         if (!port)
  554                         {
  555                                 port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
  556                         }
  557                 }
  558                 ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port);
  559                 if (!ip_sockets[NS_SERVER] && dedicated)
  560                         Com_Error (ERR_FATAL, "Couldn't allocate dedicated server IP port");
  561         }
  562 
  563 
  564         // dedicated servers don't need client ports
  565         if (dedicated)
  566                 return;
  567 
  568         if (!ip_sockets[NS_CLIENT])
  569         {
  570                 port = Cvar_Get("ip_clientport", "0", CVAR_NOSET)->value;
  571                 if (!port)
  572                 {
  573                         port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
  574                         if (!port)
  575                                 port = PORT_ANY;
  576                 }
  577                 ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, port);
  578                 if (!ip_sockets[NS_CLIENT])
  579                         ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, PORT_ANY);
  580         }
  581 }
  582 
  583 
  584 /*
  585 ====================
  586 IPX_Socket
  587 ====================
  588 */
  589 int NET_IPXSocket (int port)
  590 {
  591         int                                     newsocket;
  592         struct sockaddr_ipx     address;
  593         int                                     _true = 1;
  594         int                                     err;
  595 
  596         if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
  597         {
  598                 err = WSAGetLastError();
  599                 if (err != WSAEAFNOSUPPORT)
  600                         Com_Printf ("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString());
  601                 return 0;
  602         }
  603 
  604         // make it non-blocking
  605         if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
  606         {
  607                 Com_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
  608                 return 0;
  609         }
  610 
  611         // make it broadcast capable
  612         if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
  613         {
  614                 Com_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
  615                 return 0;
  616         }
  617 
  618         address.sa_family = AF_IPX;
  619         memset (address.sa_netnum, 0, 4);
  620         memset (address.sa_nodenum, 0, 6);
  621         if (port == PORT_ANY)
  622                 address.sa_socket = 0;
  623         else
  624                 address.sa_socket = htons((short)port);
  625 
  626         if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
  627         {
  628                 Com_Printf ("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString());
  629                 closesocket (newsocket);
  630                 return 0;
  631         }
  632 
  633         return newsocket;
  634 }
  635 
  636 
  637 /*
  638 ====================
  639 NET_OpenIPX
  640 ====================
  641 */
  642 void NET_OpenIPX (void)
  643 {
  644         int             port;
  645         int             dedicated;
  646 
  647         dedicated = Cvar_VariableValue ("dedicated");
  648 
  649         if (!ipx_sockets[NS_SERVER])
  650         {
  651                 port = Cvar_Get("ipx_hostport", "0", CVAR_NOSET)->value;
  652                 if (!port)
  653                 {
  654                         port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
  655                         if (!port)
  656                         {
  657                                 port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
  658                         }
  659                 }
  660                 ipx_sockets[NS_SERVER] = NET_IPXSocket (port);
  661         }
  662 
  663         // dedicated servers don't need client ports
  664         if (dedicated)
  665                 return;
  666 
  667         if (!ipx_sockets[NS_CLIENT])
  668         {
  669                 port = Cvar_Get("ipx_clientport", "0", CVAR_NOSET)->value;
  670                 if (!port)
  671                 {
  672                         port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
  673                         if (!port)
  674                                 port = PORT_ANY;
  675                 }
  676                 ipx_sockets[NS_CLIENT] = NET_IPXSocket (port);
  677                 if (!ipx_sockets[NS_CLIENT])
  678                         ipx_sockets[NS_CLIENT] = NET_IPXSocket (PORT_ANY);
  679         }
  680 }
  681 
  682 
  683 /*
  684 ====================
  685 NET_Config
  686 
  687 A single player game will only use the loopback code
  688 ====================
  689 */
  690 void    NET_Config (qboolean multiplayer)
  691 {
  692         int             i;
  693         static  qboolean        old_config;
  694 
  695         if (old_config == multiplayer)
  696                 return;
  697 
  698         old_config = multiplayer;
  699 
  700         if (!multiplayer)
  701         {       // shut down any existing sockets
  702                 for (i=0 ; i<2 ; i++)
  703                 {
  704                         if (ip_sockets[i])
  705                         {
  706                                 closesocket (ip_sockets[i]);
  707                                 ip_sockets[i] = 0;
  708                         }
  709                         if (ipx_sockets[i])
  710                         {
  711                                 closesocket (ipx_sockets[i]);
  712                                 ipx_sockets[i] = 0;
  713                         }
  714                 }
  715         }
  716         else
  717         {       // open sockets
  718                 if (! noudp->value)
  719                         NET_OpenIP ();
  720                 if (! noipx->value)
  721                         NET_OpenIPX ();
  722         }
  723 }
  724 
  725 // sleeps msec or until net socket is ready
  726 void NET_Sleep(int msec)
  727 {
  728     struct timeval timeout;
  729         fd_set  fdset;
  730         extern cvar_t *dedicated;
  731         int i;
  732 
  733         if (!dedicated || !dedicated->value)
  734                 return; // we're not a server, just run full speed
  735 
  736         FD_ZERO(&fdset);
  737         i = 0;
  738         if (ip_sockets[NS_SERVER]) {
  739                 FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
  740                 i = ip_sockets[NS_SERVER];
  741         }
  742         if (ipx_sockets[NS_SERVER]) {
  743                 FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket
  744                 if (ipx_sockets[NS_SERVER] > i)
  745                         i = ipx_sockets[NS_SERVER];
  746         }
  747         timeout.tv_sec = msec/1000;
  748         timeout.tv_usec = (msec%1000)*1000;
  749         select(i+1, &fdset, NULL, NULL, &timeout);
  750 }
  751 
  752 //===================================================================
  753 
  754 
  755 static WSADATA          winsockdata;
  756 
  757 /*
  758 ====================
  759 NET_Init
  760 ====================
  761 */
  762 void NET_Init (void)
  763 {
  764         WORD    wVersionRequested; 
  765         int             r;
  766 
  767         wVersionRequested = MAKEWORD(1, 1); 
  768 
  769         r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
  770 
  771         if (r)
  772                 Com_Error (ERR_FATAL,"Winsock initialization failed.");
  773 
  774         Com_Printf("Winsock Initialized\n");
  775 
  776         noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
  777         noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
  778 
  779         net_shownet = Cvar_Get ("net_shownet", "0", 0);
  780 }
  781 
  782 
  783 /*
  784 ====================
  785 NET_Shutdown
  786 ====================
  787 */
  788 void    NET_Shutdown (void)
  789 {
  790         NET_Config (false);     // close sockets
  791 
  792         WSACleanup ();
  793 }
  794 
  795 
  796 /*
  797 ====================
  798 NET_ErrorString
  799 ====================
  800 */
  801 char *NET_ErrorString (void)
  802 {
  803         int             code;
  804 
  805         code = WSAGetLastError ();
  806         switch (code)
  807         {
  808         case WSAEINTR: return "WSAEINTR";
  809         case WSAEBADF: return "WSAEBADF";
  810         case WSAEACCES: return "WSAEACCES";
  811         case WSAEDISCON: return "WSAEDISCON";
  812         case WSAEFAULT: return "WSAEFAULT";
  813         case WSAEINVAL: return "WSAEINVAL";
  814         case WSAEMFILE: return "WSAEMFILE";
  815         case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
  816         case WSAEINPROGRESS: return "WSAEINPROGRESS";
  817         case WSAEALREADY: return "WSAEALREADY";
  818         case WSAENOTSOCK: return "WSAENOTSOCK";
  819         case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
  820         case WSAEMSGSIZE: return "WSAEMSGSIZE";
  821         case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
  822         case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
  823         case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
  824         case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
  825         case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
  826         case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
  827         case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
  828         case WSAEADDRINUSE: return "WSAEADDRINUSE";
  829         case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
  830         case WSAENETDOWN: return "WSAENETDOWN";
  831         case WSAENETUNREACH: return "WSAENETUNREACH";
  832         case WSAENETRESET: return "WSAENETRESET";
  833         case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
  834         case WSAECONNRESET: return "WSAECONNRESET";
  835         case WSAENOBUFS: return "WSAENOBUFS";
  836         case WSAEISCONN: return "WSAEISCONN";
  837         case WSAENOTCONN: return "WSAENOTCONN";
  838         case WSAESHUTDOWN: return "WSAESHUTDOWN";
  839         case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
  840         case WSAETIMEDOUT: return "WSAETIMEDOUT";
  841         case WSAECONNREFUSED: return "WSAECONNREFUSED";
  842         case WSAELOOP: return "WSAELOOP";
  843         case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
  844         case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
  845         case WSASYSNOTREADY: return "WSASYSNOTREADY";
  846         case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
  847         case WSANOTINITIALISED: return "WSANOTINITIALISED";
  848         case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
  849         case WSATRY_AGAIN: return "WSATRY_AGAIN";
  850         case WSANO_RECOVERY: return "WSANO_RECOVERY";
  851         case WSANO_DATA: return "WSANO_DATA";
  852         default: return "NO ERROR";
  853         }
  854 }
  855