Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. Copyright (C) 1996-1997 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 "quakedef.h"
  23. #include "winquake.h"
  24.  
  25. extern cvar_t hostname;
  26.  
  27. #define MAXHOSTNAMELEN          256
  28.  
  29. static int net_acceptsocket = -1;               // socket for fielding new connections
  30. static int net_controlsocket;
  31. static int net_broadcastsocket = 0;
  32. static struct qsockaddr broadcastaddr;
  33.  
  34. static unsigned long myAddr;
  35.  
  36. qboolean        winsock_lib_initialized;
  37.  
  38. int (PASCAL FAR *pWSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
  39. int (PASCAL FAR *pWSACleanup)(void);
  40. int (PASCAL FAR *pWSAGetLastError)(void);
  41. SOCKET (PASCAL FAR *psocket)(int af, int type, int protocol);
  42. int (PASCAL FAR *pioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
  43. int (PASCAL FAR *psetsockopt)(SOCKET s, int level, int optname,
  44.                                                           const char FAR * optval, int optlen);
  45. int (PASCAL FAR *precvfrom)(SOCKET s, char FAR * buf, int len, int flags,
  46.                                                         struct sockaddr FAR *from, int FAR * fromlen);
  47. int (PASCAL FAR *psendto)(SOCKET s, const char FAR * buf, int len, int flags,
  48.                                                   const struct sockaddr FAR *to, int tolen);
  49. int (PASCAL FAR *pclosesocket)(SOCKET s);
  50. int (PASCAL FAR *pgethostname)(char FAR * name, int namelen);
  51. struct hostent FAR * (PASCAL FAR *pgethostbyname)(const char FAR * name);
  52. struct hostent FAR * (PASCAL FAR *pgethostbyaddr)(const char FAR * addr,
  53.                                                                                                   int len, int type);
  54. int (PASCAL FAR *pgetsockname)(SOCKET s, struct sockaddr FAR *name,
  55.                                                            int FAR * namelen);
  56.  
  57. #include "net_wins.h"
  58.  
  59. int winsock_initialized = 0;
  60. WSADATA         winsockdata;
  61.  
  62. //=============================================================================
  63.  
  64. static double   blocktime;
  65.  
  66. BOOL PASCAL FAR BlockingHook(void)  
  67. {
  68.     MSG         msg;
  69.     BOOL        ret;
  70.  
  71.         if ((Sys_FloatTime() - blocktime) > 2.0)
  72.         {
  73.                 WSACancelBlockingCall();
  74.                 return FALSE;
  75.         }
  76.  
  77.     /* get the next message, if any */
  78.     ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
  79.  
  80.     /* if we got one, process it */
  81.     if (ret) {
  82.         TranslateMessage(&msg);
  83.         DispatchMessage(&msg);
  84.     }
  85.  
  86.     /* TRUE if we got a message */
  87.     return ret;
  88. }
  89.  
  90.  
  91. void WINS_GetLocalAddress()
  92. {
  93.         struct hostent  *local = NULL;
  94.         char                    buff[MAXHOSTNAMELEN];
  95.         unsigned long   addr;
  96.  
  97.         if (myAddr != INADDR_ANY)
  98.                 return;
  99.  
  100.         if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
  101.                 return;
  102.  
  103.         blocktime = Sys_FloatTime();
  104.         WSASetBlockingHook(BlockingHook);
  105.         local = pgethostbyname(buff);
  106.         WSAUnhookBlockingHook();
  107.         if (local == NULL)
  108.                 return;
  109.  
  110.         myAddr = *(int *)local->h_addr_list[0];
  111.  
  112.         addr = ntohl(myAddr);
  113.         sprintf(my_tcpip_address, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
  114. }
  115.  
  116.  
  117. int WINS_Init (void)
  118. {
  119.         int             i;
  120.         char    buff[MAXHOSTNAMELEN];
  121.         char    *p;
  122.         int             r;
  123.         WORD    wVersionRequested;
  124.         HINSTANCE hInst;
  125.  
  126. // initialize the Winsock function vectors (we do this instead of statically linking
  127. // so we can run on Win 3.1, where there isn't necessarily Winsock)
  128.     hInst = LoadLibrary("wsock32.dll");
  129.        
  130.         if (hInst == NULL)
  131.         {
  132.                 Con_SafePrintf ("Failed to load winsock.dll\n");
  133.                 winsock_lib_initialized = false;
  134.                 return -1;
  135.         }
  136.  
  137.         winsock_lib_initialized = true;
  138.  
  139.     pWSAStartup = (void *)GetProcAddress(hInst, "WSAStartup");
  140.     pWSACleanup = (void *)GetProcAddress(hInst, "WSACleanup");
  141.     pWSAGetLastError = (void *)GetProcAddress(hInst, "WSAGetLastError");
  142.     psocket = (void *)GetProcAddress(hInst, "socket");
  143.     pioctlsocket = (void *)GetProcAddress(hInst, "ioctlsocket");
  144.     psetsockopt = (void *)GetProcAddress(hInst, "setsockopt");
  145.     precvfrom = (void *)GetProcAddress(hInst, "recvfrom");
  146.     psendto = (void *)GetProcAddress(hInst, "sendto");
  147.     pclosesocket = (void *)GetProcAddress(hInst, "closesocket");
  148.     pgethostname = (void *)GetProcAddress(hInst, "gethostname");
  149.     pgethostbyname = (void *)GetProcAddress(hInst, "gethostbyname");
  150.     pgethostbyaddr = (void *)GetProcAddress(hInst, "gethostbyaddr");
  151.     pgetsockname = (void *)GetProcAddress(hInst, "getsockname");
  152.  
  153.     if (!pWSAStartup || !pWSACleanup || !pWSAGetLastError ||
  154.                 !psocket || !pioctlsocket || !psetsockopt ||
  155.                 !precvfrom || !psendto || !pclosesocket ||
  156.                 !pgethostname || !pgethostbyname || !pgethostbyaddr ||
  157.                 !pgetsockname)
  158.         {
  159.                 Con_SafePrintf ("Couldn't GetProcAddress from winsock.dll\n");
  160.                 return -1;
  161.         }
  162.  
  163.         if (COM_CheckParm ("-noudp"))
  164.                 return -1;
  165.  
  166.         if (winsock_initialized == 0)
  167.         {
  168.                 wVersionRequested = MAKEWORD(1, 1);
  169.  
  170.                 r = pWSAStartup (MAKEWORD(1, 1), &winsockdata);
  171.  
  172.                 if (r)
  173.                 {
  174.                         Con_SafePrintf ("Winsock initialization failed.\n");
  175.                         return -1;
  176.                 }
  177.         }
  178.         winsock_initialized++;
  179.  
  180.         // determine my name
  181.         if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
  182.         {
  183.                 Con_DPrintf ("Winsock TCP/IP Initialization failed.\n");
  184.                 if (--winsock_initialized == 0)
  185.                         pWSACleanup ();
  186.                 return -1;
  187.         }
  188.  
  189.         // if the quake hostname isn't set, set it to the machine name
  190.         if (Q_strcmp(hostname.string, "UNNAMED") == 0)
  191.         {
  192.                 // see if it's a text IP address (well, close enough)
  193.                 for (p = buff; *p; p++)
  194.                         if ((*p < '0' || *p > '9') && *p != '.')
  195.                                 break;
  196.  
  197.                 // if it is a real name, strip off the domain; we only want the host
  198.                 if (*p)
  199.                 {
  200.                         for (i = 0; i < 15; i++)
  201.                                 if (buff[i] == '.')
  202.                                         break;
  203.                         buff[i] = 0;
  204.                 }
  205.                 Cvar_Set ("hostname", buff);
  206.         }
  207.  
  208.         i = COM_CheckParm ("-ip");
  209.         if (i)
  210.         {
  211.                 if (i < com_argc-1)
  212.                 {
  213.                         myAddr = inet_addr(com_argv[i+1]);
  214.                         if (myAddr == INADDR_NONE)
  215.                                 Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
  216.                         strcpy(my_tcpip_address, com_argv[i+1]);
  217.                 }
  218.                 else
  219.                 {
  220.                         Sys_Error ("NET_Init: you must specify an IP address after -ip");
  221.                 }
  222.         }
  223.         else
  224.         {
  225.                 myAddr = INADDR_ANY;
  226.                 strcpy(my_tcpip_address, "INADDR_ANY");
  227.         }
  228.  
  229.         if ((net_controlsocket = WINS_OpenSocket (0)) == -1)
  230.         {
  231.                 Con_Printf("WINS_Init: Unable to open control socket\n");
  232.                 if (--winsock_initialized == 0)
  233.                         pWSACleanup ();
  234.                 return -1;
  235.         }
  236.  
  237.         ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
  238.         ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
  239.         ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport);
  240.  
  241.         Con_Printf("Winsock TCP/IP Initialized\n");
  242.         tcpipAvailable = true;
  243.  
  244.         return net_controlsocket;
  245. }
  246.  
  247. //=============================================================================
  248.  
  249. void WINS_Shutdown (void)
  250. {
  251.         WINS_Listen (false);
  252.         WINS_CloseSocket (net_controlsocket);
  253.         if (--winsock_initialized == 0)
  254.                 pWSACleanup ();
  255. }
  256.  
  257. //=============================================================================
  258.  
  259. void WINS_Listen (qboolean state)
  260. {
  261.         // enable listening
  262.         if (state)
  263.         {
  264.                 if (net_acceptsocket != -1)
  265.                         return;
  266.                 WINS_GetLocalAddress();
  267.                 if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1)
  268.                         Sys_Error ("WINS_Listen: Unable to open accept socket\n");
  269.                 return;
  270.         }
  271.  
  272.         // disable listening
  273.         if (net_acceptsocket == -1)
  274.                 return;
  275.         WINS_CloseSocket (net_acceptsocket);
  276.         net_acceptsocket = -1;
  277. }
  278.  
  279. //=============================================================================
  280.  
  281. int WINS_OpenSocket (int port)
  282. {
  283.         int newsocket;
  284.         struct sockaddr_in address;
  285.         u_long _true = 1;
  286.  
  287.         if ((newsocket = psocket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
  288.                 return -1;
  289.  
  290.         if (pioctlsocket (newsocket, FIONBIO, &_true) == -1)
  291.                 goto ErrorReturn;
  292.  
  293.         address.sin_family = AF_INET;
  294.         address.sin_addr.s_addr = myAddr;
  295.         address.sin_port = htons((unsigned short)port);
  296.         if( bind (newsocket, (void *)&address, sizeof(address)) == 0)
  297.                 return newsocket;
  298.  
  299.         Sys_Error ("Unable to bind to %s", WINS_AddrToString((struct qsockaddr *)&address));
  300. ErrorReturn:
  301.         pclosesocket (newsocket);
  302.         return -1;
  303. }
  304.  
  305. //=============================================================================
  306.  
  307. int WINS_CloseSocket (int socket)
  308. {
  309.         if (socket == net_broadcastsocket)
  310.                 net_broadcastsocket = 0;
  311.         return pclosesocket (socket);
  312. }
  313.  
  314.  
  315. //=============================================================================
  316. /*
  317. ============
  318. PartialIPAddress
  319.  
  320. this lets you type only as much of the net address as required, using
  321. the local network components to fill in the rest
  322. ============
  323. */
  324. static int PartialIPAddress (char *in, struct qsockaddr *hostaddr)
  325. {
  326.         char buff[256];
  327.         char *b;
  328.         int addr;
  329.         int num;
  330.         int mask;
  331.         int run;
  332.         int port;
  333.        
  334.         buff[0] = '.';
  335.         b = buff;
  336.         strcpy(buff+1, in);
  337.         if (buff[1] == '.')
  338.                 b++;
  339.  
  340.         addr = 0;
  341.         mask=-1;
  342.         while (*b == '.')
  343.         {
  344.                 b++;
  345.                 num = 0;
  346.                 run = 0;
  347.                 while (!( *b < '0' || *b > '9'))
  348.                 {
  349.                   num = num*10 + *b++ - '0';
  350.                   if (++run > 3)
  351.                         return -1;
  352.                 }
  353.                 if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
  354.                         return -1;
  355.                 if (num < 0 || num > 255)
  356.                         return -1;
  357.                 mask<<=8;
  358.                 addr = (addr<<8) + num;
  359.         }
  360.        
  361.         if (*b++ == ':')
  362.                 port = Q_atoi(b);
  363.         else
  364.                 port = net_hostport;
  365.  
  366.         hostaddr->sa_family = AF_INET;
  367.         ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);       
  368.         ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
  369.        
  370.         return 0;
  371. }
  372. //=============================================================================
  373.  
  374. int WINS_Connect (int socket, struct qsockaddr *addr)
  375. {
  376.         return 0;
  377. }
  378.  
  379. //=============================================================================
  380.  
  381. int WINS_CheckNewConnections (void)
  382. {
  383.         char buf[4096];
  384.  
  385.         if (net_acceptsocket == -1)
  386.                 return -1;
  387.  
  388.         if (precvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) > 0)
  389.         {
  390.                 return net_acceptsocket;
  391.         }
  392.         return -1;
  393. }
  394.  
  395. //=============================================================================
  396.  
  397. int WINS_Read (int socket, byte *buf, int len, struct qsockaddr *addr)
  398. {
  399.         int addrlen = sizeof (struct qsockaddr);
  400.         int ret;
  401.  
  402.         ret = precvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
  403.         if (ret == -1)
  404.         {
  405.                 int errno = pWSAGetLastError();
  406.  
  407.                 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
  408.                         return 0;
  409.  
  410.         }
  411.         return ret;
  412. }
  413.  
  414. //=============================================================================
  415.  
  416. int WINS_MakeSocketBroadcastCapable (int socket)
  417. {
  418.         int     i = 1;
  419.  
  420.         // make this socket broadcast capable
  421.         if (psetsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
  422.                 return -1;
  423.         net_broadcastsocket = socket;
  424.  
  425.         return 0;
  426. }
  427.  
  428. //=============================================================================
  429.  
  430. int WINS_Broadcast (int socket, byte *buf, int len)
  431. {
  432.         int ret;
  433.  
  434.         if (socket != net_broadcastsocket)
  435.         {
  436.                 if (net_broadcastsocket != 0)
  437.                         Sys_Error("Attempted to use multiple broadcasts sockets\n");
  438.                 WINS_GetLocalAddress();
  439.                 ret = WINS_MakeSocketBroadcastCapable (socket);
  440.                 if (ret == -1)
  441.                 {
  442.                         Con_Printf("Unable to make socket broadcast capable\n");
  443.                         return ret;
  444.                 }
  445.         }
  446.  
  447.         return WINS_Write (socket, buf, len, &broadcastaddr);
  448. }
  449.  
  450. //=============================================================================
  451.  
  452. int WINS_Write (int socket, byte *buf, int len, struct qsockaddr *addr)
  453. {
  454.         int ret;
  455.  
  456.         ret = psendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
  457.         if (ret == -1)
  458.                 if (pWSAGetLastError() == WSAEWOULDBLOCK)
  459.                         return 0;
  460.  
  461.         return ret;
  462. }
  463.  
  464. //=============================================================================
  465.  
  466. char *WINS_AddrToString (struct qsockaddr *addr)
  467. {
  468.         static char buffer[22];
  469.         int haddr;
  470.  
  471.         haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
  472.         sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
  473.         return buffer;
  474. }
  475.  
  476. //=============================================================================
  477.  
  478. int WINS_StringToAddr (char *string, struct qsockaddr *addr)
  479. {
  480.         int ha1, ha2, ha3, ha4, hp;
  481.         int ipaddr;
  482.  
  483.         sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
  484.         ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
  485.  
  486.         addr->sa_family = AF_INET;
  487.         ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
  488.         ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
  489.         return 0;
  490. }
  491.  
  492. //=============================================================================
  493.  
  494. int WINS_GetSocketAddr (int socket, struct qsockaddr *addr)
  495. {
  496.         int addrlen = sizeof(struct qsockaddr);
  497.         unsigned int a;
  498.  
  499.         Q_memset(addr, 0, sizeof(struct qsockaddr));
  500.         pgetsockname(socket, (struct sockaddr *)addr, &addrlen);
  501.         a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
  502.         if (a == 0 || a == inet_addr("127.0.0.1"))
  503.                 ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
  504.  
  505.         return 0;
  506. }
  507.  
  508. //=============================================================================
  509.  
  510. int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name)
  511. {
  512.         struct hostent *hostentry;
  513.  
  514.         hostentry = pgethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
  515.         if (hostentry)
  516.         {
  517.                 Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
  518.                 return 0;
  519.         }
  520.  
  521.         Q_strcpy (name, WINS_AddrToString (addr));
  522.         return 0;
  523. }
  524.  
  525. //=============================================================================
  526.  
  527. int WINS_GetAddrFromName(char *name, struct qsockaddr *addr)
  528. {
  529.         struct hostent *hostentry;
  530.  
  531.         if (name[0] >= '0' && name[0] <= '9')
  532.                 return PartialIPAddress (name, addr);
  533.        
  534.         hostentry = pgethostbyname (name);
  535.         if (!hostentry)
  536.                 return -1;
  537.  
  538.         addr->sa_family = AF_INET;
  539.         ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);  
  540.         ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
  541.  
  542.         return 0;
  543. }
  544.  
  545. //=============================================================================
  546.  
  547. int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
  548. {
  549.         if (addr1->sa_family != addr2->sa_family)
  550.                 return -1;
  551.  
  552.         if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
  553.                 return -1;
  554.  
  555.         if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
  556.                 return 1;
  557.  
  558.         return 0;
  559. }
  560.  
  561. //=============================================================================
  562.  
  563. int WINS_GetSocketPort (struct qsockaddr *addr)
  564. {
  565.         return ntohs(((struct sockaddr_in *)addr)->sin_port);
  566. }
  567.  
  568.  
  569. int WINS_SetSocketPort (struct qsockaddr *addr, int port)
  570. {
  571.         ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
  572.         return 0;
  573. }
  574.  
  575. //=============================================================================
  576.