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;
38 //=============================================================================
40 static double blocktime;
42 BOOL PASCAL FAR BlockingHook(void)
47 if ((Sys_DoubleTime() - blocktime) > 2.0)
49 WSACancelBlockingCall();
53 /* get the next message, if any */
54 ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
56 /* if we got one, process it */
58 TranslateMessage(&msg);
59 DispatchMessage(&msg);
62 /* true if we got a message */
67 void WINS_GetLocalAddress(void)
69 struct hostent *local = NULL;
70 char buff[MAXHOSTNAMELEN];
73 if (myAddr != INADDR_ANY)
76 if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
79 blocktime = Sys_DoubleTime();
80 WSASetBlockingHook(BlockingHook);
81 local = gethostbyname(buff);
82 WSAUnhookBlockingHook();
86 myAddr = *(int *)local->h_addr_list[0];
89 sprintf(my_tcpip_address, "%d.%d.%d.%d", (int) ((addr >> 24) & 0xff), (int) ((addr >> 16) & 0xff), (int) ((addr >> 8) & 0xff), (int) (addr & 0xff));
96 char buff[MAXHOSTNAMELEN];
100 if (COM_CheckParm ("-noudp"))
103 r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
106 Con_SafePrintf ("Winsock initialization failed.\n");
111 if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
113 Con_DPrintf ("Winsock TCP/IP Initialization failed.\n");
118 // if the quake hostname isn't set, set it to the machine name
119 if (strcmp(hostname.string, "UNNAMED") == 0)
121 // see if it's a text IP address (well, close enough)
122 for (p = buff; *p; p++)
123 if ((*p < '0' || *p > '9') && *p != '.')
126 // if it is a real name, strip off the domain; we only want the host
129 for (i = 0; i < 15; i++)
134 Cvar_Set ("hostname", buff);
137 i = COM_CheckParm ("-ip");
142 myAddr = inet_addr(com_argv[i+1]);
143 if (myAddr == INADDR_NONE)
144 Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
145 strcpy(my_tcpip_address, com_argv[i+1]);
149 Sys_Error ("NET_Init: you must specify an IP address after -ip");
155 strcpy(my_tcpip_address, "INADDR_ANY");
158 if ((net_controlsocket = WINS_OpenSocket (0)) == -1)
160 Con_Printf("WINS_Init: Unable to open control socket\n");
165 ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
166 ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
167 ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport);
169 Con_Printf("Winsock TCP/IP Initialized\n");
170 tcpipAvailable = true;
172 return net_controlsocket;
175 //=============================================================================
177 void WINS_Shutdown (void)
180 WINS_CloseSocket (net_controlsocket);
184 //=============================================================================
186 void WINS_Listen (qboolean state)
191 if (net_acceptsocket != -1)
193 WINS_GetLocalAddress();
194 if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1)
195 Sys_Error ("WINS_Listen: Unable to open accept socket\n");
200 if (net_acceptsocket == -1)
202 WINS_CloseSocket (net_acceptsocket);
203 net_acceptsocket = -1;
206 //=============================================================================
208 int WINS_OpenSocket (int port)
211 struct sockaddr_in address;
214 if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
217 if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
220 address.sin_family = AF_INET;
221 address.sin_addr.s_addr = myAddr;
222 address.sin_port = htons((unsigned short)port);
223 if( bind (newsocket, (void *)&address, sizeof(address)) == 0)
226 Sys_Error ("Unable to bind to %s", WINS_AddrToString((struct qsockaddr *)&address));
228 closesocket (newsocket);
232 //=============================================================================
234 int WINS_CloseSocket (int socket)
236 if (socket == net_broadcastsocket)
237 net_broadcastsocket = 0;
238 return closesocket (socket);
242 //=============================================================================
247 this lets you type only as much of the net address as required, using
248 the local network components to fill in the rest
251 static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr)
274 while (!( *b < '0' || *b > '9'))
276 num = num*10 + *b++ - '0';
280 if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
282 if (num < 0 || num > 255)
285 addr = (addr<<8) + num;
293 hostaddr->sa_family = AF_INET;
294 ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
295 ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
299 //=============================================================================
301 int WINS_Connect (int socket, struct qsockaddr *addr)
306 //=============================================================================
308 int WINS_CheckNewConnections (void)
312 if (net_acceptsocket == -1)
315 if (recvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) >= 0)
316 return net_acceptsocket;
320 //=============================================================================
322 int WINS_Recv (qbyte *buf, int len, struct qsockaddr *addr)
324 return WINS_Read (net_acceptsocket, buf, len, addr);
327 //=============================================================================
329 int WINS_Send (qbyte *buf, int len, struct qsockaddr *addr)
331 return WINS_Write (net_acceptsocket, buf, len, addr);
334 //=============================================================================
336 int WINS_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr)
338 int addrlen = sizeof (struct qsockaddr);
342 ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
345 errno = WSAGetLastError();
347 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
354 //=============================================================================
356 int WINS_MakeSocketBroadcastCapable (int socket)
360 // make this socket broadcast capable
361 if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
363 net_broadcastsocket = socket;
368 //=============================================================================
370 int WINS_Broadcast (int socket, qbyte *buf, int len)
374 if (socket != net_broadcastsocket)
376 if (net_broadcastsocket != 0)
377 Sys_Error("Attempted to use multiple broadcasts sockets\n");
378 WINS_GetLocalAddress();
379 ret = WINS_MakeSocketBroadcastCapable (socket);
382 Con_Printf("Unable to make socket broadcast capable\n");
387 return WINS_Write (socket, buf, len, &broadcastaddr);
390 //=============================================================================
392 int WINS_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr)
396 ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
398 if (WSAGetLastError() == WSAEWOULDBLOCK)
404 //=============================================================================
406 char *WINS_AddrToString (const struct qsockaddr *addr)
408 static char buffer[22];
411 haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
412 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));
416 //=============================================================================
418 int WINS_StringToAddr (const char *string, struct qsockaddr *addr)
420 int ha1, ha2, ha3, ha4, hp;
423 sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
424 ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
426 addr->sa_family = AF_INET;
427 ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
428 ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
432 //=============================================================================
434 int WINS_GetSocketAddr (int socket, struct qsockaddr *addr)
436 int addrlen = sizeof(struct qsockaddr);
439 memset(addr, 0, sizeof(struct qsockaddr));
440 getsockname(socket, (struct sockaddr *)addr, &addrlen);
441 a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
442 if (a == 0 || a == inet_addr("127.0.0.1"))
443 ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
448 //=============================================================================
450 int WINS_GetNameFromAddr (const struct qsockaddr *addr, char *name)
452 struct hostent *hostentry;
454 hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
457 strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
461 strcpy (name, WINS_AddrToString (addr));
465 //=============================================================================
467 int WINS_GetAddrFromName(const char *name, struct qsockaddr *addr)
469 struct hostent *hostentry;
471 if (name[0] >= '0' && name[0] <= '9')
472 return PartialIPAddress (name, addr);
474 hostentry = gethostbyname (name);
478 addr->sa_family = AF_INET;
479 ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
480 ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
485 //=============================================================================
487 int WINS_AddrCompare (const struct qsockaddr *addr1, const struct qsockaddr *addr2)
489 if (addr1->sa_family != addr2->sa_family)
492 if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
495 if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
501 //=============================================================================
503 int WINS_GetSocketPort (struct qsockaddr *addr)
505 return ntohs(((struct sockaddr_in *)addr)->sin_port);
509 int WINS_SetSocketPort (struct qsockaddr *addr, int port)
511 ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);