1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: net_winsock.cpp 4352 2010-12-20 03:14:10Z firebrand_kh $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 #include "winlocal.h"
29 #include <errno.h>
30 #include "gamedefs.h"
31 #include "net_local.h"
32 
33 // MACROS ------------------------------------------------------------------
34 
35 #define MAXHOSTNAMELEN		256
36 
37 // TYPES -------------------------------------------------------------------
38 
39 class VWinSockDriver : public VNetLanDriver
40 {
41 public:
42 	int				winsock_initialised;
43 	WSADATA			winsockdata;
44 
45 	static double	blocktime;
46 
47 	VWinSockDriver();
48 	int Init();
49 	void Shutdown();
50 	void Listen(bool);
51 	int OpenSocket(int);
52 	int CloseSocket(int);
53 	int Connect(int, sockaddr_t*);
54 	int CheckNewConnections();
55 	int Read(int, vuint8*, int, sockaddr_t*);
56 	int Write(int, vuint8*, int, sockaddr_t*);
57 	int Broadcast(int, vuint8*, int);
58 	char* AddrToString(sockaddr_t*);
59 	int StringToAddr(const char*, sockaddr_t*);
60 	int GetSocketAddr(int, sockaddr_t*);
61 	VStr GetNameFromAddr(sockaddr_t*);
62 	int GetAddrFromName(const char*, sockaddr_t*, int);
63 	int AddrCompare(sockaddr_t*, sockaddr_t*);
64 	int GetSocketPort(sockaddr_t*);
65 	int SetSocketPort(sockaddr_t*, int);
66 
67 	static BOOL PASCAL FAR BlockingHook();
68 	void GetLocalAddress();
69 
70 	int PartialIPAddress(const char*, sockaddr_t*, int);
71 };
72 
73 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
74 
75 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
76 
77 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
78 
79 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
80 
81 // PUBLIC DATA DEFINITIONS -------------------------------------------------
82 
83 // PRIVATE DATA DEFINITIONS ------------------------------------------------
84 
85 double		VWinSockDriver::blocktime;
86 
87 static VWinSockDriver	Impl;
88 
89 // CODE --------------------------------------------------------------------
90 
91 //==========================================================================
92 //
93 //	VWinSockDriver::VWinSockDriver
94 //
95 //==========================================================================
96 
VWinSockDriver()97 VWinSockDriver::VWinSockDriver()
98 : VNetLanDriver(0, "Winsock TCPIP")
99 , winsock_initialised(0)
100 {
101 }
102 
103 //==========================================================================
104 //
105 //  VWinSockDriver::Init
106 //
107 //==========================================================================
108 
Init()109 int VWinSockDriver::Init()
110 {
111 	guard(VWinSockDriver::Init);
112 	int		i;
113 	char	buff[MAXHOSTNAMELEN];
114 	char	*p;
115 	int		r;
116 
117 	if (GArgs.CheckParm("-noudp"))
118 		return -1;
119 
120 	if (winsock_initialised == 0)
121 	{
122 		//MAKEWORD(2, 2)
123 		r = WSAStartup(MAKEWORD(1, 1), &winsockdata);
124 
125 		if (r)
126 		{
127 			GCon->Log(NAME_Init, "Winsock initialisation failed.");
128 			return -1;
129 		}
130 	}
131 	winsock_initialised++;
132 
133 	// determine my name
134 	if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
135 	{
136 		GCon->Log(NAME_DevNet, "Winsock TCP/IP Initialisation failed.");
137 		if (--winsock_initialised == 0)
138 			WSACleanup();
139 		return -1;
140 	}
141 
142 	// if the Vavoom hostname isn't set, set it to the machine name
143 	if (VStr::Cmp(Net->HostName, "UNNAMED") == 0)
144 	{
145 		// see if it's a text IP address (well, close enough)
146 		for (p = buff; *p; p++)
147 			if ((*p < '0' || *p > '9') && *p != '.')
148 				break;
149 
150 		// if it is a real name, strip off the domain; we only want the host
151 		if (*p)
152 		{
153 			for (i = 0; i < 15; i++)
154 				if (buff[i] == '.')
155 					break;
156 			buff[i] = 0;
157 		}
158 		Net->HostName = buff;
159 	}
160 
161 	const char* pp = GArgs.CheckValue("-ip");
162 	if (pp)
163 	{
164 		myAddr = inet_addr(pp);
165 		if (myAddr == INADDR_NONE)
166 			Sys_Error("%s is not a valid IP address", pp);
167 		VStr::Cpy(Net->MyIpAddress, pp);
168 	}
169 	else
170 	{
171 		myAddr = INADDR_ANY;
172 		VStr::Cpy(Net->MyIpAddress, "INADDR_ANY");
173 	}
174 
175     net_controlsocket = OpenSocket(0);
176 	if (net_controlsocket == -1)
177 	{
178 		GCon->Log(NAME_Init, "WINS_Init: Unable to open control socket");
179 		if (--winsock_initialised == 0)
180 			WSACleanup();
181 		return -1;
182 	}
183 
184 	((sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
185 	((sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
186 	((sockaddr_in *)&broadcastaddr)->sin_port = htons((vuint16)Net->HostPort);
187 
188 	GCon->Log(NAME_Init, "Winsock TCP/IP Initialised");
189 	Net->IpAvailable = true;
190 
191 	return net_controlsocket;
192 	unguard;
193 }
194 
195 //==========================================================================
196 //
197 //  VWinSockDriver::Shutdown
198 //
199 //==========================================================================
200 
Shutdown()201 void VWinSockDriver::Shutdown()
202 {
203 	guard(VWinSockDriver::Shutdown);
204 	Listen(false);
205 	CloseSocket(net_controlsocket);
206 	if (--winsock_initialised == 0)
207 		WSACleanup();
208 	unguard;
209 }
210 
211 //==========================================================================
212 //
213 //  VWinSockDriver::BlockingHook
214 //
215 //==========================================================================
216 
BlockingHook()217 BOOL PASCAL FAR VWinSockDriver::BlockingHook()
218 {
219 	guard(VWinSockDriver::BlockingHook);
220 	MSG		msg;
221 	BOOL	ret;
222 
223 	if ((Sys_Time() - blocktime) > 2.0)
224 	{
225 		WSACancelBlockingCall();
226 		return FALSE;
227 	}
228 
229 	// get the next message, if any
230 	ret = (BOOL)PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
231 
232 	// if we got one, process it
233 	if (ret)
234 	{
235 		TranslateMessage(&msg);
236 		DispatchMessage(&msg);
237 	}
238 
239 	// TRUE if we got a message
240 	return ret;
241 	unguard;
242 }
243 
244 //==========================================================================
245 //
246 //  VWinSockDriver::GetLocalAddress
247 //
248 //==========================================================================
249 
GetLocalAddress()250 void VWinSockDriver::GetLocalAddress()
251 {
252 	guard(VWinSockDriver::GetLocalAddress);
253 	hostent		*local;
254 	char		buff[MAXHOSTNAMELEN];
255 	vuint32		addr;
256 
257 	if (myAddr != INADDR_ANY)
258 		return;
259 
260 	if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
261 		return;
262 
263 	blocktime = Sys_Time();
264 	WSASetBlockingHook(FARPROC(BlockingHook));
265 	local = gethostbyname(buff);
266 	WSAUnhookBlockingHook();
267 	if (local == NULL)
268 		return;
269 
270 	myAddr = *(int *)local->h_addr_list[0];
271 
272 	addr = ntohl(myAddr);
273 	sprintf(Net->MyIpAddress, "%d.%d.%d.%d", (addr >> 24) & 0xff,
274 		(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
275 	unguard;
276 }
277 
278 //==========================================================================
279 //
280 //  VWinSockDriver::Listen
281 //
282 //==========================================================================
283 
Listen(bool state)284 void VWinSockDriver::Listen(bool state)
285 {
286 	guard(VWinSockDriver::Listen);
287 	if (state)
288 	{
289 		// enable listening
290 		if (net_acceptsocket == -1)
291 		{
292 			GetLocalAddress();
293 			net_acceptsocket = OpenSocket(Net->HostPort);
294 			if (net_acceptsocket == -1)
295 				Sys_Error("WINS_Listen: Unable to open accept socket\n");
296 		}
297 	}
298 	else
299 	{
300 		// disable listening
301 		if (net_acceptsocket != -1)
302 		{
303 			CloseSocket(net_acceptsocket);
304 			net_acceptsocket = -1;
305 		}
306 	}
307 	unguard;
308 }
309 
310 
311 //==========================================================================
312 //
313 //  VWinSockDriver::OpenSocket
314 //
315 //==========================================================================
316 
OpenSocket(int port)317 int VWinSockDriver::OpenSocket(int port)
318 {
319 	guard(VWinSockDriver::OpenSocket);
320 	int				newsocket;
321 	sockaddr_in		address;
322 	DWORD			trueval = 1;
323 
324 	newsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
325 	if (newsocket == -1)
326 		return -1;
327 
328 	if (ioctlsocket(newsocket, FIONBIO, &trueval) == -1)
329 		goto ErrorReturn;
330 
331 	address.sin_family = AF_INET;
332 	address.sin_addr.s_addr = myAddr;
333 	address.sin_port = htons((word)port);
334 	if (bind(newsocket, (sockaddr *)&address, sizeof(address)) == 0)
335 		return newsocket;
336 
337 	Sys_Error("Unable to bind to %s", AddrToString((sockaddr_t *)&address));
338 
339 ErrorReturn:
340 	closesocket(newsocket);
341 	return -1;
342 	unguard;
343 }
344 
345 //==========================================================================
346 //
347 //  VWinSockDriver::CloseSocket
348 //
349 //==========================================================================
350 
CloseSocket(int socket)351 int VWinSockDriver::CloseSocket(int socket)
352 {
353 	guard(VWinSockDriver::CloseSocket);
354 	if (socket == net_broadcastsocket)
355 		net_broadcastsocket = 0;
356 	return closesocket(socket);
357 	unguard;
358 }
359 
360 //==========================================================================
361 //
362 //  VWinSockDriver::Connect
363 //
364 //==========================================================================
365 
Connect(int,sockaddr_t *)366 int VWinSockDriver::Connect(int , sockaddr_t *)
367 {
368 	return 0;
369 }
370 
371 //==========================================================================
372 //
373 //  VWinSockDriver::CheckNewConnections
374 //
375 //==========================================================================
376 
CheckNewConnections()377 int VWinSockDriver::CheckNewConnections()
378 {
379 	guard(VWinSockDriver::CheckNewConnections);
380 	char	buf[4096];
381 
382 	if (net_acceptsocket == -1)
383 		return -1;
384 
385 	if (recvfrom(net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) >= 0)
386 	{
387 		return net_acceptsocket;
388 	}
389 	return -1;
390 	unguard;
391 }
392 
393 //==========================================================================
394 //
395 //  VWinSockDriver::Read
396 //
397 //==========================================================================
398 
Read(int socket,vuint8 * buf,int len,sockaddr_t * addr)399 int VWinSockDriver::Read(int socket, vuint8* buf, int len, sockaddr_t* addr)
400 {
401 	guard(VWinSockDriver::Read);
402 	int addrlen = sizeof(sockaddr_t);
403 	int ret;
404 
405 	ret = recvfrom(socket, (char*)buf, len, 0, (sockaddr*)addr, &addrlen);
406 	if (ret == -1)
407 	{
408 		int e = WSAGetLastError();
409 
410 		if (e == WSAEWOULDBLOCK || e == WSAECONNREFUSED)
411 			return 0;
412 	}
413 	return ret;
414 	unguard;
415 }
416 
417 //==========================================================================
418 //
419 //  VWinSockDriver::Write
420 //
421 //==========================================================================
422 
Write(int socket,vuint8 * buf,int len,sockaddr_t * addr)423 int VWinSockDriver::Write(int socket, vuint8* buf, int len, sockaddr_t* addr)
424 {
425 	guard(VWinSockDriver::Write);
426 	int ret = sendto(socket, (char*)buf, len, 0, (sockaddr*)addr, sizeof(sockaddr_t));
427 	if (ret == -1)
428 		if (WSAGetLastError() == WSAEWOULDBLOCK)
429 			return 0;
430 
431 	return ret;
432 	unguard;
433 }
434 
435 //==========================================================================
436 //
437 //  VWinSockDriver::Broadcast
438 //
439 //==========================================================================
440 
Broadcast(int socket,vuint8 * buf,int len)441 int VWinSockDriver::Broadcast(int socket, vuint8* buf, int len)
442 {
443 	guard(VWinSockDriver::Broadcast);
444 	int	i = 1;
445 
446 	if (socket != net_broadcastsocket)
447 	{
448 		if (net_broadcastsocket != 0)
449 			Sys_Error("Attempted to use multiple broadcasts sockets\n");
450 
451 		GetLocalAddress();
452 
453 		// make this socket broadcast capable
454 		if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
455 		{
456 			GCon->Log(NAME_DevNet, "Unable to make socket broadcast capable");
457 			return -1;
458 		}
459 		net_broadcastsocket = socket;
460 	}
461 
462 	return Write(socket, buf, len, &broadcastaddr);
463 	unguard;
464 }
465 
466 //==========================================================================
467 //
468 //  VWinSockDriver::AddrToString
469 //
470 //==========================================================================
471 
AddrToString(sockaddr_t * addr)472 char* VWinSockDriver::AddrToString(sockaddr_t* addr)
473 {
474 	guard(VWinSockDriver::AddrToString);
475 	static char buffer[22];
476 	int haddr;
477 
478 	haddr = ntohl(((sockaddr_in *)addr)->sin_addr.s_addr);
479 	sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff,
480 		(haddr >> 16) & 0xff, (haddr >> 8) & 0xff,
481 		haddr & 0xff, ntohs(((sockaddr_in *)addr)->sin_port));
482 	return buffer;
483 	unguard;
484 }
485 
486 //==========================================================================
487 //
488 //  VWinSockDriver::StringToAddr
489 //
490 //==========================================================================
491 
StringToAddr(const char * string,sockaddr_t * addr)492 int VWinSockDriver::StringToAddr(const char* string, sockaddr_t* addr)
493 {
494 	guard(VWinSockDriver::StringToAddr);
495 	int ha1, ha2, ha3, ha4, hp;
496 	int ipaddr;
497 
498 	sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
499 	ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
500 
501 	addr->sa_family = AF_INET;
502 	((sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
503 	((sockaddr_in *)addr)->sin_port = htons((word)hp);
504 	return 0;
505 	unguard;
506 }
507 
508 //==========================================================================
509 //
510 //  VWinSockDriver::GetSocketAddr
511 //
512 //==========================================================================
513 
GetSocketAddr(int socket,sockaddr_t * addr)514 int VWinSockDriver::GetSocketAddr(int socket, sockaddr_t *addr)
515 {
516 	guard(VWinSockDriver::GetSocketAddr);
517 	int		addrlen = sizeof(sockaddr_t);
518 	vuint32	a;
519 
520 	memset(addr, 0, sizeof(sockaddr_t));
521 	getsockname(socket, (sockaddr *)addr, &addrlen);
522 	a = ((sockaddr_in *)addr)->sin_addr.s_addr;
523 	if (a == 0 || a == inet_addr("127.0.0.1"))
524 		((sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
525 
526 	return 0;
527 	unguard;
528 }
529 
530 //==========================================================================
531 //
532 //  VWinSockDriver::GetNameFromAddr
533 //
534 //==========================================================================
535 
GetNameFromAddr(sockaddr_t * addr)536 VStr VWinSockDriver::GetNameFromAddr(sockaddr_t* addr)
537 {
538 	guard(VWinSockDriver::GetNameFromAddr);
539 	hostent* hostentry = gethostbyaddr((char*)&((sockaddr_in*)addr)->sin_addr,
540 		sizeof(struct in_addr), AF_INET);
541 	if (hostentry)
542 	{
543 		return (char*)hostentry->h_name;
544 	}
545 
546 	return AddrToString(addr);
547 	unguard;
548 }
549 
550 //==========================================================================
551 //
552 //	VWinSockDriver::PartialIPAddress
553 //
554 //	This lets you type only as much of the net address as required, using
555 // the local network components to fill in the rest
556 //
557 //==========================================================================
558 
PartialIPAddress(const char * in,sockaddr_t * hostaddr,int DefaultPort)559 int VWinSockDriver::PartialIPAddress(const char *in, sockaddr_t *hostaddr,
560 	int DefaultPort)
561 {
562 	guard(PartialIPAddress);
563 	char buff[256];
564 	char *b;
565 	int addr;
566 	int num;
567 	int mask;
568 	int run;
569 	int port;
570 
571 	buff[0] = '.';
572 	b = buff;
573 	VStr::Cpy(buff + 1, in);
574 	if (buff[1] == '.')
575 		b++;
576 
577 	addr = 0;
578 	mask=-1;
579 	while (*b == '.')
580 	{
581 		b++;
582 		num = 0;
583 		run = 0;
584 		while (!( *b < '0' || *b > '9'))
585 		{
586 		  num = num*10 + *b++ - '0';
587 		  if (++run > 3)
588 		  	return -1;
589 		}
590 		if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
591 			return -1;
592 		if (num < 0 || num > 255)
593 			return -1;
594 		mask <<=8;
595 		addr = (addr << 8) + num;
596 	}
597 
598 	if (*b++ == ':')
599 		port = atoi(b);
600 	else
601 		port = DefaultPort;
602 
603 	hostaddr->sa_family = AF_INET;
604 	((sockaddr_in *)hostaddr)->sin_port = htons((short)port);
605 	((sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
606 
607 	return 0;
608 	unguard;
609 }
610 
611 //==========================================================================
612 //
613 //  VWinSockDriver::GetAddrFromName
614 //
615 //==========================================================================
616 
GetAddrFromName(const char * name,sockaddr_t * addr,int DefaultPort)617 int VWinSockDriver::GetAddrFromName(const char *name, sockaddr_t *addr,
618 	int DefaultPort)
619 {
620 	guard(VWinSockDriver::GetAddrFromName);
621 	hostent*	hostentry;
622 
623 	if (name[0] >= '0' && name[0] <= '9')
624 		return PartialIPAddress(name, addr, DefaultPort);
625 
626 	hostentry = gethostbyname(name);
627 	if (!hostentry)
628 		return -1;
629 
630 	addr->sa_family = AF_INET;
631 	((sockaddr_in *)addr)->sin_port = htons((vuint16)DefaultPort);
632 	((sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
633 
634 	return 0;
635 	unguard;
636 }
637 
638 //==========================================================================
639 //
640 //  VWinSockDriver::AddrCompare
641 //
642 //==========================================================================
643 
AddrCompare(sockaddr_t * addr1,sockaddr_t * addr2)644 int VWinSockDriver::AddrCompare(sockaddr_t* addr1, sockaddr_t* addr2)
645 {
646 	guard(VWinSockDriver::AddrCompare);
647 	if (addr1->sa_family != addr2->sa_family)
648 		return -1;
649 
650 	if (((sockaddr_in *)addr1)->sin_addr.s_addr != ((sockaddr_in *)addr2)->sin_addr.s_addr)
651 		return -1;
652 
653 	if (((sockaddr_in *)addr1)->sin_port != ((sockaddr_in *)addr2)->sin_port)
654 		return 1;
655 
656 	return 0;
657 	unguard;
658 }
659 
660 //==========================================================================
661 //
662 //  VWinSockDriver::GetSocketPort
663 //
664 //==========================================================================
665 
GetSocketPort(sockaddr_t * addr)666 int VWinSockDriver::GetSocketPort(sockaddr_t* addr)
667 {
668 	guard(VWinSockDriver::GetSocketPort);
669 	return ntohs(((sockaddr_in*)addr)->sin_port);
670 	unguard;
671 }
672 
673 //==========================================================================
674 //
675 //  VWinSockDriver::SetSocketPort
676 //
677 //==========================================================================
678 
SetSocketPort(sockaddr_t * addr,int port)679 int VWinSockDriver::SetSocketPort(sockaddr_t* addr, int port)
680 {
681 	guard(VWinSockDriver::SetSocketPort);
682 	((sockaddr_in*)addr)->sin_port = htons((word)port);
683 	return 0;
684 	unguard;
685 }
686