2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
25 #define MAXHOSTNAMELEN 256
27 static int net_acceptsocket = -1; // socket for fielding new connections
28 static int net_controlsocket;
29 static int net_broadcastsocket = 0;
30 static struct qsockaddr broadcastaddr;
32 static unsigned long myAddr;
34 qboolean winsock_lib_initialized;
36 int (PASCAL FAR *pWSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
37 int (PASCAL FAR *pWSACleanup)(void);
38 int (PASCAL FAR *pWSAGetLastError)(void);
39 SOCKET (PASCAL FAR *psocket)(int af, int type, int protocol);
40 int (PASCAL FAR *pioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
41 int (PASCAL FAR *psetsockopt)(SOCKET s, int level, int optname,
42 const char FAR * optval, int optlen);
43 int (PASCAL FAR *precvfrom)(SOCKET s, char FAR * buf, int len, int flags,
44 struct sockaddr FAR *from, int FAR * fromlen);
45 int (PASCAL FAR *psendto)(SOCKET s, const char FAR * buf, int len, int flags,
46 const struct sockaddr FAR *to, int tolen);
47 int (PASCAL FAR *pclosesocket)(SOCKET s);
48 int (PASCAL FAR *pgethostname)(char FAR * name, int namelen);
49 struct hostent FAR * (PASCAL FAR *pgethostbyname)(const char FAR * name);
50 struct hostent FAR * (PASCAL FAR *pgethostbyaddr)(const char FAR * addr,
52 int (PASCAL FAR *pgetsockname)(SOCKET s, struct sockaddr FAR *name,
57 int winsock_initialized = 0;
60 //=============================================================================
62 static double blocktime;
64 BOOL PASCAL FAR BlockingHook(void)
69 if ((Sys_DoubleTime() - blocktime) > 2.0)
71 WSACancelBlockingCall();
75 /* get the next message, if any */
76 ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
78 /* if we got one, process it */
80 TranslateMessage(&msg);
81 DispatchMessage(&msg);
84 /* true if we got a message */
89 void WINS_GetLocalAddress(void)
91 struct hostent *local = NULL;
92 char buff[MAXHOSTNAMELEN];
95 if (myAddr != INADDR_ANY)
98 if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
101 blocktime = Sys_DoubleTime();
102 WSASetBlockingHook(BlockingHook);
103 local = pgethostbyname(buff);
104 WSAUnhookBlockingHook();
108 myAddr = *(int *)local->h_addr_list[0];
110 addr = ntohl(myAddr);
111 sprintf(my_tcpip_address, "%d.%d.%d.%d", (int) ((addr >> 24) & 0xff), (int) ((addr >> 16) & 0xff), (int) ((addr >> 8) & 0xff), (int) (addr & 0xff));
118 char buff[MAXHOSTNAMELEN];
121 WORD wVersionRequested;
124 // initialize the Winsock function vectors (we do this instead of statically linking
125 // so we can run on Win 3.1, where there isn't necessarily Winsock)
126 hInst = LoadLibrary("wsock32.dll");
130 Con_SafePrintf ("Failed to load wsock32.dll\n");
131 winsock_lib_initialized = false;
135 winsock_lib_initialized = true;
137 pWSAStartup = (void *)GetProcAddress(hInst, "WSAStartup");
138 pWSACleanup = (void *)GetProcAddress(hInst, "WSACleanup");
139 pWSAGetLastError = (void *)GetProcAddress(hInst, "WSAGetLastError");
140 psocket = (void *)GetProcAddress(hInst, "socket");
141 pioctlsocket = (void *)GetProcAddress(hInst, "ioctlsocket");
142 psetsockopt = (void *)GetProcAddress(hInst, "setsockopt");
143 precvfrom = (void *)GetProcAddress(hInst, "recvfrom");
144 psendto = (void *)GetProcAddress(hInst, "sendto");
145 pclosesocket = (void *)GetProcAddress(hInst, "closesocket");
146 pgethostname = (void *)GetProcAddress(hInst, "gethostname");
147 pgethostbyname = (void *)GetProcAddress(hInst, "gethostbyname");
148 pgethostbyaddr = (void *)GetProcAddress(hInst, "gethostbyaddr");
149 pgetsockname = (void *)GetProcAddress(hInst, "getsockname");
151 if (!pWSAStartup || !pWSACleanup || !pWSAGetLastError ||
152 !psocket || !pioctlsocket || !psetsockopt ||
153 !precvfrom || !psendto || !pclosesocket ||
154 !pgethostname || !pgethostbyname || !pgethostbyaddr ||
157 Con_SafePrintf ("Couldn't GetProcAddress from wsock32.dll\n");
161 if (COM_CheckParm ("-noudp"))
164 if (winsock_initialized == 0)
166 wVersionRequested = MAKEWORD(1, 1);
168 r = pWSAStartup (MAKEWORD(1, 1), &winsockdata);
172 Con_SafePrintf ("Winsock initialization failed.\n");
176 winsock_initialized++;
179 if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
181 Con_DPrintf ("Winsock TCP/IP Initialization failed.\n");
182 if (--winsock_initialized == 0)
187 // if the quake hostname isn't set, set it to the machine name
188 if (strcmp(hostname.string, "UNNAMED") == 0)
190 // see if it's a text IP address (well, close enough)
191 for (p = buff; *p; p++)
192 if ((*p < '0' || *p > '9') && *p != '.')
195 // if it is a real name, strip off the domain; we only want the host
198 for (i = 0; i < 15; i++)
203 Cvar_Set ("hostname", buff);
206 i = COM_CheckParm ("-ip");
211 myAddr = inet_addr(com_argv[i+1]);
212 if (myAddr == INADDR_NONE)
213 Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
214 strcpy(my_tcpip_address, com_argv[i+1]);
218 Sys_Error ("NET_Init: you must specify an IP address after -ip");
224 strcpy(my_tcpip_address, "INADDR_ANY");
227 if ((net_controlsocket = WINS_OpenSocket (0)) == -1)
229 Con_Printf("WINS_Init: Unable to open control socket\n");
230 if (--winsock_initialized == 0)
235 ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
236 ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
237 ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport);
239 Con_Printf("Winsock TCP/IP Initialized\n");
240 tcpipAvailable = true;
242 return net_controlsocket;
245 //=============================================================================
247 void WINS_Shutdown (void)
250 WINS_CloseSocket (net_controlsocket);
251 if (--winsock_initialized == 0)
255 //=============================================================================
257 void WINS_Listen (qboolean state)
262 if (net_acceptsocket != -1)
264 WINS_GetLocalAddress();
265 if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1)
266 Sys_Error ("WINS_Listen: Unable to open accept socket\n");
271 if (net_acceptsocket == -1)
273 WINS_CloseSocket (net_acceptsocket);
274 net_acceptsocket = -1;
277 //=============================================================================
279 int WINS_OpenSocket (int port)
282 struct sockaddr_in address;
285 if ((newsocket = psocket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
288 if (pioctlsocket (newsocket, FIONBIO, &_true) == -1)
291 address.sin_family = AF_INET;
292 address.sin_addr.s_addr = myAddr;
293 address.sin_port = htons((unsigned short)port);
294 if( bind (newsocket, (void *)&address, sizeof(address)) == 0)
297 Sys_Error ("Unable to bind to %s", WINS_AddrToString((struct qsockaddr *)&address));
299 pclosesocket (newsocket);
303 //=============================================================================
305 int WINS_CloseSocket (int socket)
307 if (socket == net_broadcastsocket)
308 net_broadcastsocket = 0;
309 return pclosesocket (socket);
313 //=============================================================================
318 this lets you type only as much of the net address as required, using
319 the local network components to fill in the rest
322 static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr)
345 while (!( *b < '0' || *b > '9'))
347 num = num*10 + *b++ - '0';
351 if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
353 if (num < 0 || num > 255)
356 addr = (addr<<8) + num;
364 hostaddr->sa_family = AF_INET;
365 ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
366 ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
370 //=============================================================================
372 int WINS_Connect (int socket, struct qsockaddr *addr)
377 //=============================================================================
379 int WINS_CheckNewConnections (void)
383 if (net_acceptsocket == -1)
386 if (precvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) >= 0)
388 return net_acceptsocket;
393 //=============================================================================
395 int WINS_Recv (qbyte *buf, int len, struct qsockaddr *addr)
397 return WINS_Read (net_acceptsocket, buf, len, addr);
400 //=============================================================================
402 int WINS_Send (qbyte *buf, int len, struct qsockaddr *addr)
404 return WINS_Write (net_acceptsocket, buf, len, addr);
407 //=============================================================================
409 int WINS_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr)
411 int addrlen = sizeof (struct qsockaddr);
415 ret = precvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
418 errno = pWSAGetLastError();
420 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
427 //=============================================================================
429 int WINS_MakeSocketBroadcastCapable (int socket)
433 // make this socket broadcast capable
434 if (psetsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
436 net_broadcastsocket = socket;
441 //=============================================================================
443 int WINS_Broadcast (int socket, qbyte *buf, int len)
447 if (socket != net_broadcastsocket)
449 if (net_broadcastsocket != 0)
450 Sys_Error("Attempted to use multiple broadcasts sockets\n");
451 WINS_GetLocalAddress();
452 ret = WINS_MakeSocketBroadcastCapable (socket);
455 Con_Printf("Unable to make socket broadcast capable\n");
460 return WINS_Write (socket, buf, len, &broadcastaddr);
463 //=============================================================================
465 int WINS_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr)
469 ret = psendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
471 if (pWSAGetLastError() == WSAEWOULDBLOCK)
477 //=============================================================================
479 char *WINS_AddrToString (const struct qsockaddr *addr)
481 static char buffer[22];
484 haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
485 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));
489 //=============================================================================
491 int WINS_StringToAddr (const char *string, struct qsockaddr *addr)
493 int ha1, ha2, ha3, ha4, hp;
496 sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
497 ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
499 addr->sa_family = AF_INET;
500 ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
501 ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
505 //=============================================================================
507 int WINS_GetSocketAddr (int socket, struct qsockaddr *addr)
509 int addrlen = sizeof(struct qsockaddr);
512 memset(addr, 0, sizeof(struct qsockaddr));
513 pgetsockname(socket, (struct sockaddr *)addr, &addrlen);
514 a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
515 if (a == 0 || a == inet_addr("127.0.0.1"))
516 ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
521 //=============================================================================
523 int WINS_GetNameFromAddr (const struct qsockaddr *addr, char *name)
525 struct hostent *hostentry;
527 hostentry = pgethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
530 strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
534 strcpy (name, WINS_AddrToString (addr));
538 //=============================================================================
540 int WINS_GetAddrFromName(const char *name, struct qsockaddr *addr)
542 struct hostent *hostentry;
544 if (name[0] >= '0' && name[0] <= '9')
545 return PartialIPAddress (name, addr);
547 hostentry = pgethostbyname (name);
551 addr->sa_family = AF_INET;
552 ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
553 ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
558 //=============================================================================
560 int WINS_AddrCompare (const struct qsockaddr *addr1, const struct qsockaddr *addr2)
562 if (addr1->sa_family != addr2->sa_family)
565 if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
568 if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
574 //=============================================================================
576 int WINS_GetSocketPort (struct qsockaddr *addr)
578 return ntohs(((struct sockaddr_in *)addr)->sin_port);
582 int WINS_SetSocketPort (struct qsockaddr *addr, int port)
584 ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);