1 /*
2  * net_wins.c -- winsock udp driver
3  * $Id: net_wins.c 4767 2012-06-16 20:48:51Z sezero $
4  *
5  * Copyright (C) 1996-1997  Id Software, Inc.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or (at
10  * your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * See the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 #include "q_stdinc.h"
24 #include "arch_def.h"
25 #include "net_sys.h"
26 #include "quakedef.h"
27 #include "net_defs.h"
28 
29 static sys_socket_t net_acceptsocket = INVALID_SOCKET;	// socket for fielding new connections
30 static sys_socket_t net_controlsocket;
31 static sys_socket_t net_broadcastsocket = 0;
32 static struct sockaddr_in broadcastaddr;
33 
34 static struct in_addr	myAddr,		// the local address returned by the OS.
35 			localAddr,	// address to advertise by embedding in
36 					// CCREP_SERVER_INFO and CCREP_ACCEPT
37 					// response packets instead of the default
38 					// returned by the OS. from command line
39 					// argument -localip <ip_address>, used
40 					// by GetSocketAddr()
41 			bindAddr;	// the address that we bind to instead of
42 					// INADDR_ANY. from the command line args
43 					// -ip <ip_address>
44 
45 #include "net_wins.h"
46 
47 int winsock_initialized = 0;
48 WSADATA		winsockdata;
49 #define __wsaerr_static			/* not static: used by net_wipx.c too */
50 #include "wsaerror.h"
51 
52 //=============================================================================
53 
54 #if !defined(_USE_WINSOCK2)
55 static double	blocktime;
56 
BlockingHook(void)57 static INT_PTR PASCAL FAR BlockingHook (void)
58 {
59 	MSG	msg;
60 	BOOL	ret;
61 
62 	if ((Sys_DoubleTime() - blocktime) > 2.0)
63 	{
64 		WSACancelBlockingCall();
65 		return FALSE;
66 	}
67 
68 	/* get the next message, if any */
69 	ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
70 
71 	/* if we got one, process it */
72 	if (ret)
73 	{
74 		TranslateMessage(&msg);
75 		DispatchMessage(&msg);
76 	}
77 
78 	/* TRUE if we got a message */
79 	return ret;
80 }
81 #endif	/* ! _USE_WINSOCK2 */
82 
WINS_Init(void)83 sys_socket_t WINS_Init (void)
84 {
85 	int	i, err;
86 	char	*colon;
87 	char	buff[MAXHOSTNAMELEN];
88 	struct hostent		*local;
89 	struct qsockaddr	addr;
90 
91 	if (COM_CheckParm ("-noudp") || (winsock_initialized == -1))
92 		return INVALID_SOCKET;
93 
94 	if (winsock_initialized == 0)
95 	{
96 		err = WSAStartup(MAKEWORD(1,1), &winsockdata);
97 		if (err != 0)
98 		{
99 			winsock_initialized = -1;
100 			Con_SafePrintf("Winsock initialization failed (%s)\n",
101 					socketerror(err));
102 			return INVALID_SOCKET;
103 		}
104 	}
105 	winsock_initialized++;
106 
107 	// determine my name & address
108 	myAddr.s_addr = htonl(INADDR_LOOPBACK);
109 	if (gethostname(buff, MAXHOSTNAMELEN) != 0)
110 	{
111 		err = SOCKETERRNO;
112 		Con_SafePrintf("%s: WARNING: gethostname failed (%s)\n",
113 					__thisfunc__, socketerror(err));
114 	}
115 	else
116 	{
117 		buff[MAXHOSTNAMELEN - 1] = 0;
118 #if !defined(_USE_WINSOCK2)
119 		blocktime = Sys_DoubleTime();
120 		WSASetBlockingHook(BlockingHook);
121 #endif	/* ! _USE_WINSOCK2 */
122 		local = gethostbyname(buff);
123 		err = WSAGetLastError();
124 #if !defined(_USE_WINSOCK2)
125 		WSAUnhookBlockingHook();
126 #endif	/* ! _USE_WINSOCK2 */
127 		if (local == NULL)
128 		{
129 			Con_SafePrintf("%s: WARNING: gethostbyname failed (%s)\n",
130 					__thisfunc__, __WSAE_StrError(err));
131 		}
132 		else if (local->h_addrtype != AF_INET)
133 		{
134 			Con_SafePrintf("%s: address from gethostbyname not IPv4\n",
135 					__thisfunc__);
136 		}
137 		else
138 		{
139 			myAddr = *(struct in_addr *)local->h_addr_list[0];
140 		}
141 	}
142 	Con_SafePrintf("UDP, Local address: %s\n", inet_ntoa(myAddr));
143 
144 	// check for interface binding option
145 	i = COM_CheckParm("-ip");
146 	if (i == 0)
147 		i = COM_CheckParm("-bindip");
148 	if (i && i < com_argc - 1)
149 	{
150 		bindAddr.s_addr = inet_addr(com_argv[i + 1]);
151 		if (bindAddr.s_addr == INADDR_NONE)
152 		{
153 			Sys_Error("%s: %s is not a valid IP address",
154 					__thisfunc__, com_argv[i + 1]);
155 		}
156 		Con_SafePrintf("Binding to IP Interface Address of %s\n",
157 							com_argv[i + 1]);
158 	}
159 	else
160 	{
161 		bindAddr.s_addr = INADDR_NONE;
162 	}
163 
164 	// check for ip advertise option
165 	i = COM_CheckParm("-localip");
166 	if (i && i < com_argc - 1)
167 	{
168 		localAddr.s_addr = inet_addr(com_argv[i + 1]);
169 		if (localAddr.s_addr == INADDR_NONE)
170 		{
171 			Sys_Error("%s: %s is not a valid IP address",
172 					__thisfunc__, com_argv[i + 1]);
173 		}
174 		Con_SafePrintf("Advertising %s as the local IP in response packets\n",
175 							com_argv[i + 1]);
176 	}
177 	else
178 	{
179 		localAddr.s_addr = INADDR_NONE;
180 	}
181 
182 	if ((net_controlsocket = WINS_OpenSocket(0)) == INVALID_SOCKET)
183 	{
184 		Con_SafePrintf("%s: Unable to open control socket, UDP disabled\n",
185 				__thisfunc__);
186 		if (--winsock_initialized == 0)
187 			WSACleanup ();
188 		return INVALID_SOCKET;
189 	}
190 
191 	broadcastaddr.sin_family = AF_INET;
192 	broadcastaddr.sin_addr.s_addr = INADDR_BROADCAST;
193 	broadcastaddr.sin_port = htons((unsigned short)net_hostport);
194 
195 	WINS_GetSocketAddr (net_controlsocket, &addr);
196 	strcpy(my_tcpip_address, WINS_AddrToString (&addr));
197 	colon = strrchr (my_tcpip_address, ':');
198 	if (colon)
199 		*colon = 0;
200 
201 	Con_SafePrintf("UDP Initialized\n");
202 	tcpipAvailable = true;
203 
204 	return net_controlsocket;
205 }
206 
207 //=============================================================================
208 
WINS_Shutdown(void)209 void WINS_Shutdown (void)
210 {
211 	WINS_Listen (false);
212 	WINS_CloseSocket (net_controlsocket);
213 	if (--winsock_initialized == 0)
214 		WSACleanup ();
215 }
216 
217 //=============================================================================
218 
WINS_Listen(qboolean state)219 void WINS_Listen (qboolean state)
220 {
221 	// enable listening
222 	if (state)
223 	{
224 		if (net_acceptsocket != INVALID_SOCKET)
225 			return;
226 		if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == INVALID_SOCKET)
227 			Sys_Error ("%s: Unable to open accept socket", __thisfunc__);
228 		return;
229 	}
230 
231 	// disable listening
232 	if (net_acceptsocket == INVALID_SOCKET)
233 		return;
234 	WINS_CloseSocket (net_acceptsocket);
235 	net_acceptsocket = INVALID_SOCKET;
236 }
237 
238 //=============================================================================
239 
WINS_OpenSocket(int port)240 sys_socket_t WINS_OpenSocket (int port)
241 {
242 	sys_socket_t newsocket;
243 	struct sockaddr_in address;
244 	u_long _true = 1;
245 	int err;
246 
247 	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
248 	{
249 		err = SOCKETERRNO;
250 		Con_SafePrintf("%s: %s\n", __thisfunc__, socketerror(err));
251 		return INVALID_SOCKET;
252 	}
253 
254 	if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR)
255 		goto ErrorReturn;
256 
257 	memset(&address, 0, sizeof(struct sockaddr_in));
258 	address.sin_family = AF_INET;
259 	if (bindAddr.s_addr != INADDR_NONE)
260 		address.sin_addr.s_addr = bindAddr.s_addr;
261 	else
262 		address.sin_addr.s_addr = INADDR_ANY;
263 	address.sin_port = htons((unsigned short)port);
264 	if (bind (newsocket, (struct sockaddr *)&address, sizeof(address)) == 0)
265 		return newsocket;
266 
267 	if (tcpipAvailable)
268 	{
269 		err = SOCKETERRNO;
270 		Sys_Error ("Unable to bind to %s (%s)",
271 				WINS_AddrToString ((struct qsockaddr *) &address),
272 				socketerror(err));
273 		return INVALID_SOCKET;	/* not reached */
274 	}
275 	/* else: we are still in init phase, no need to error */
276 
277 ErrorReturn:
278 	err = SOCKETERRNO;
279 	Con_SafePrintf("%s: %s\n", __thisfunc__, socketerror(err));
280 	closesocket (newsocket);
281 	return INVALID_SOCKET;
282 }
283 
284 //=============================================================================
285 
WINS_CloseSocket(sys_socket_t socketid)286 int WINS_CloseSocket (sys_socket_t socketid)
287 {
288 	if (socketid == net_broadcastsocket)
289 		net_broadcastsocket = 0;
290 	return closesocket (socketid);
291 }
292 
293 //=============================================================================
294 
295 /*
296 ============
297 PartialIPAddress
298 
299 this lets you type only as much of the net address as required, using
300 the local network components to fill in the rest
301 ============
302 */
PartialIPAddress(const char * in,struct qsockaddr * hostaddr)303 static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr)
304 {
305 	char	buff[256];
306 	char	*b;
307 	int	addr, mask, num, port, run;
308 
309 	buff[0] = '.';
310 	b = buff;
311 	strcpy(buff+1, in);
312 	if (buff[1] == '.')
313 		b++;
314 
315 	addr = 0;
316 	mask = -1;
317 	while (*b == '.')
318 	{
319 		b++;
320 		num = 0;
321 		run = 0;
322 		while (!( *b < '0' || *b > '9'))
323 		{
324 			num = num*10 + *b++ - '0';
325 			if (++run > 3)
326 				return -1;
327 		}
328 		if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
329 			return -1;
330 		if (num < 0 || num > 255)
331 			return -1;
332 		mask <<= 8;
333 		addr = (addr<<8) + num;
334 	}
335 
336 	if (*b++ == ':')
337 		port = atoi(b);
338 	else
339 		port = net_hostport;
340 
341 	hostaddr->qsa_family = AF_INET;
342 	((struct sockaddr_in *)hostaddr)->sin_port = htons((unsigned short)port);
343 	((struct sockaddr_in *)hostaddr)->sin_addr.s_addr =
344 					(myAddr.s_addr & htonl(mask)) | htonl(addr);
345 
346 	return 0;
347 }
348 
349 //=============================================================================
350 
WINS_Connect(sys_socket_t socketid,struct qsockaddr * addr)351 int WINS_Connect (sys_socket_t socketid, struct qsockaddr *addr)
352 {
353 	return 0;
354 }
355 
356 //=============================================================================
357 
WINS_CheckNewConnections(void)358 sys_socket_t WINS_CheckNewConnections (void)
359 {
360 	char		buf[4096];
361 
362 	if (net_acceptsocket == INVALID_SOCKET)
363 		return INVALID_SOCKET;
364 
365 	if (recvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL)
366 								!= SOCKET_ERROR)
367 	{
368 		return net_acceptsocket;
369 	}
370 	return INVALID_SOCKET;
371 }
372 
373 //=============================================================================
374 
WINS_Read(sys_socket_t socketid,byte * buf,int len,struct qsockaddr * addr)375 int WINS_Read (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr)
376 {
377 	socklen_t addrlen = sizeof(struct qsockaddr);
378 	int ret;
379 
380 	ret = recvfrom (socketid, (char *)buf, len, 0, (struct sockaddr *)addr, &addrlen);
381 	if (ret == SOCKET_ERROR)
382 	{
383 		int err = SOCKETERRNO;
384 		if (err == NET_EWOULDBLOCK || err == NET_ECONNREFUSED)
385 			return 0;
386 		Con_SafeDPrintf ("%s, recvfrom: %s\n", __thisfunc__, socketerror(err));
387 	}
388 	return ret;
389 }
390 
391 //=============================================================================
392 
WINS_MakeSocketBroadcastCapable(sys_socket_t socketid)393 static int WINS_MakeSocketBroadcastCapable (sys_socket_t socketid)
394 {
395 	int	i = 1;
396 
397 	// make this socket broadcast capable
398 	if (setsockopt(socketid, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i))
399 								 == SOCKET_ERROR)
400 	{
401 		int err = SOCKETERRNO;
402 		Con_SafePrintf ("%s, setsockopt: %s\n", __thisfunc__, socketerror(err));
403 		return -1;
404 	}
405 	net_broadcastsocket = socketid;
406 
407 	return 0;
408 }
409 
410 //=============================================================================
411 
WINS_Broadcast(sys_socket_t socketid,byte * buf,int len)412 int WINS_Broadcast (sys_socket_t socketid, byte *buf, int len)
413 {
414 	int	ret;
415 
416 	if (socketid != net_broadcastsocket)
417 	{
418 		if (net_broadcastsocket != 0)
419 			Sys_Error("Attempted to use multiple broadcasts sockets");
420 		ret = WINS_MakeSocketBroadcastCapable (socketid);
421 		if (ret == -1)
422 		{
423 			Con_Printf("Unable to make socket broadcast capable\n");
424 			return ret;
425 		}
426 	}
427 
428 	return WINS_Write (socketid, buf, len, (struct qsockaddr *)&broadcastaddr);
429 }
430 
431 //=============================================================================
432 
WINS_Write(sys_socket_t socketid,byte * buf,int len,struct qsockaddr * addr)433 int WINS_Write (sys_socket_t socketid, byte *buf, int len, struct qsockaddr *addr)
434 {
435 	int	ret;
436 
437 	ret = sendto (socketid, (char *)buf, len, 0, (struct sockaddr *)addr,
438 							sizeof(struct qsockaddr));
439 	if (ret == SOCKET_ERROR)
440 	{
441 		int err = SOCKETERRNO;
442 		if (err == NET_EWOULDBLOCK)
443 			return 0;
444 		Con_SafeDPrintf ("%s, sendto: %s\n", __thisfunc__, socketerror(err));
445 	}
446 	return ret;
447 }
448 
449 //=============================================================================
450 
WINS_AddrToString(struct qsockaddr * addr)451 const char *WINS_AddrToString (struct qsockaddr *addr)
452 {
453 	static char buffer[22];
454 	int		haddr;
455 
456 	haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
457 	q_snprintf (buffer, sizeof(buffer), "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff,
458 			  (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff,
459 			  ntohs(((struct sockaddr_in *)addr)->sin_port));
460 	return buffer;
461 }
462 
463 //=============================================================================
464 
WINS_StringToAddr(const char * string,struct qsockaddr * addr)465 int WINS_StringToAddr (const char *string, struct qsockaddr *addr)
466 {
467 	int	ha1, ha2, ha3, ha4, hp, ipaddr;
468 
469 	sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
470 	ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
471 
472 	addr->qsa_family = AF_INET;
473 	((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
474 	((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
475 	return 0;
476 }
477 
478 //=============================================================================
479 
WINS_GetSocketAddr(sys_socket_t socketid,struct qsockaddr * addr)480 int WINS_GetSocketAddr (sys_socket_t socketid, struct qsockaddr *addr)
481 {
482 	socklen_t addrlen = sizeof(struct qsockaddr);
483 	struct sockaddr_in *address = (struct sockaddr_in *)addr;
484 	struct in_addr	a;
485 
486 	memset(addr, 0, sizeof(struct qsockaddr));
487 	getsockname(socketid, (struct sockaddr *)addr, &addrlen);
488 
489 	/*
490 	 * The returned IP is embedded in our repsonse to a broadcast
491 	 * request for server info from clients.  If the server admin
492 	 * wishes to advertise a specific IP, then allow the "default"
493 	 * address returned by the OS to be overridden.
494 	 */
495 	if (localAddr.s_addr != INADDR_NONE)
496 		address->sin_addr.s_addr = localAddr.s_addr;
497 	else
498 	{
499 		a = address->sin_addr;
500 		if (a.s_addr == 0 || a.s_addr == htonl(INADDR_LOOPBACK))
501 			address->sin_addr.s_addr = myAddr.s_addr;
502 	}
503 
504 	return 0;
505 }
506 
507 //=============================================================================
508 
WINS_GetNameFromAddr(struct qsockaddr * addr,char * name)509 int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name)
510 {
511 	struct hostent *hostentry;
512 
513 	hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr,
514 						sizeof(struct in_addr), AF_INET);
515 	if (hostentry)
516 	{
517 		strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
518 		return 0;
519 	}
520 
521 	strcpy (name, WINS_AddrToString (addr));
522 	return 0;
523 }
524 
525 //=============================================================================
526 
WINS_GetAddrFromName(const char * name,struct qsockaddr * addr)527 int WINS_GetAddrFromName (const 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 = gethostbyname (name);
535 	if (!hostentry)
536 		return -1;
537 
538 	addr->qsa_family = AF_INET;
539 	((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
540 	((struct sockaddr_in *)addr)->sin_addr.s_addr =
541 						*(in_addr_t *)hostentry->h_addr_list[0];
542 
543 	return 0;
544 }
545 
546 //=============================================================================
547 
WINS_AddrCompare(struct qsockaddr * addr1,struct qsockaddr * addr2)548 int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
549 {
550 	if (addr1->qsa_family != addr2->qsa_family)
551 		return -1;
552 
553 	if (((struct sockaddr_in *)addr1)->sin_addr.s_addr !=
554 	    ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
555 		return -1;
556 
557 	if (((struct sockaddr_in *)addr1)->sin_port !=
558 	    ((struct sockaddr_in *)addr2)->sin_port)
559 		return 1;
560 
561 	return 0;
562 }
563 
564 //=============================================================================
565 
WINS_GetSocketPort(struct qsockaddr * addr)566 int WINS_GetSocketPort (struct qsockaddr *addr)
567 {
568 	return ntohs(((struct sockaddr_in *)addr)->sin_port);
569 }
570 
571 
WINS_SetSocketPort(struct qsockaddr * addr,int port)572 int WINS_SetSocketPort (struct qsockaddr *addr, int port)
573 {
574 	((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
575 	return 0;
576 }
577 
578 //=============================================================================
579 
580