1 /*
2  * net_udp.c -- network UDP driver
3  * $Id: net_udp.c 5758 2016-12-17 20:00:41Z sezero $
4  *
5  * Copyright (C) 1996-1997  Id Software, Inc.
6  * Copyright (C) 1997-1998  Raven Software Corp.
7  * Copyright (C) 2005-2012  O.Sezer <sezero@users.sourceforge.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or (at
12  * your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17  *
18  * See the GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  */
24 
25 #include "q_stdinc.h"
26 #include "arch_def.h"
27 #if defined(PLATFORM_UNIX) ||		\
28     defined(PLATFORM_OS2) ||		\
29     defined(PLATFORM_AMIGA) ||		\
30     defined(__DJGPP__) ||		\
31     defined(PLATFORM_RISCOS)
32 #include <sys/time.h>	/* struct timeval */
33 #endif
34 #include "net_sys.h"
35 #include "quakedef.h"
36 #include "huffman.h"
37 
38 //=============================================================================
39 
40 int LastCompMessageSize = 0;
41 
42 netadr_t	net_local_adr;
43 netadr_t	net_loopback_adr;
44 netadr_t	net_from;
45 sizebuf_t	net_message;
46 
47 static sys_socket_t	net_socket = INVALID_SOCKET;
48 
49 #if defined(PLATFORM_AMIGA)
50 struct Library	*SocketBase;
51 #endif
52 #ifdef PLATFORM_WINDOWS
53 #include "wsaerror.h"
54 static WSADATA	winsockdata;
55 #endif
56 
57 #define	MAX_UDP_PACKET	(MAX_MSGLEN + 9)	/* one more than msg + header */
58 static byte	net_message_buffer[MAX_UDP_PACKET];
59 
60 
61 //=============================================================================
62 
NetadrToSockadr(const netadr_t * a,struct sockaddr_in * s)63 static void NetadrToSockadr (const netadr_t *a, struct sockaddr_in *s)
64 {
65 	memset (s, 0, sizeof(*s));
66 	s->sin_family = AF_INET;
67 
68 	memcpy (&s->sin_addr, a->ip, 4);
69 	s->sin_port = a->port;
70 }
71 
SockadrToNetadr(const struct sockaddr_in * s,netadr_t * a)72 static void SockadrToNetadr (const struct sockaddr_in *s, netadr_t *a)
73 {
74 	memcpy (a->ip, &s->sin_addr, 4);
75 	a->port = s->sin_port;
76 }
77 
NET_CompareBaseAdr(const netadr_t * a,const netadr_t * b)78 qboolean NET_CompareBaseAdr (const netadr_t *a, const netadr_t *b)
79 {
80 	if (a->ip[0] == b->ip[0] && a->ip[1] == b->ip[1] &&
81 	    a->ip[2] == b->ip[2] && a->ip[3] == b->ip[3])
82 	{
83 		return true;
84 	}
85 	return false;
86 }
87 
NET_CompareAdr(const netadr_t * a,const netadr_t * b)88 qboolean NET_CompareAdr (const netadr_t *a, const netadr_t *b)
89 {
90 	if (a->ip[0] == b->ip[0] && a->ip[1] == b->ip[1] &&
91 	    a->ip[2] == b->ip[2] && a->ip[3] == b->ip[3] &&
92 	    a->port == b->port)
93 	{
94 		return true;
95 	}
96 	return false;
97 }
98 
NET_AdrToString(const netadr_t * a)99 const char *NET_AdrToString (const netadr_t *a)
100 {
101 	static	char	s[64];
102 
103 	sprintf (s, "%i.%i.%i.%i:%i", a->ip[0], a->ip[1], a->ip[2], a->ip[3],
104 							ntohs(a->port));
105 
106 	return s;
107 }
108 
NET_BaseAdrToString(const netadr_t * a)109 const char *NET_BaseAdrToString (const netadr_t *a)
110 {
111 	static	char	s[64];
112 
113 	sprintf (s, "%i.%i.%i.%i", a->ip[0], a->ip[1], a->ip[2], a->ip[3]);
114 
115 	return s;
116 }
117 
118 /*
119 =============
120 NET_StringToAdr
121 =============
122 */
NET_StringToAdr(const char * s,netadr_t * a)123 qboolean NET_StringToAdr (const char *s, netadr_t *a)
124 {
125 	struct hostent		*h;
126 	struct sockaddr_in	sadr;
127 	char	*colon;
128 	char	copy[128];
129 
130 	memset (&sadr, 0, sizeof(sadr));
131 	sadr.sin_family = AF_INET;
132 	sadr.sin_port = 0;
133 
134 	strncpy (copy, s, sizeof(copy) - 1);
135 	copy[sizeof(copy) - 1] = '\0';
136 	// strip off a trailing :port if present
137 	for (colon = copy ; *colon ; colon++)
138 	{
139 		if (*colon == ':')
140 		{
141 			*colon = 0;
142 			sadr.sin_port = htons((short)atoi(colon+1));
143 		}
144 	}
145 
146 	if (copy[0] >= '0' && copy[0] <= '9')
147 	{
148 		sadr.sin_addr.s_addr = inet_addr(copy);
149 	}
150 	else
151 	{
152 		h = gethostbyname (copy);
153 		if (!h)
154 			return false;
155 		sadr.sin_addr.s_addr = *(in_addr_t *)h->h_addr_list[0];
156 	}
157 
158 	SockadrToNetadr (&sadr, a);
159 
160 	return true;
161 }
162 
163 
164 //=============================================================================
165 
166 static unsigned char huffbuff[65536];
167 
NET_GetPacket(void)168 int NET_GetPacket (void)
169 {
170 	int	ret;
171 	struct sockaddr_in	from;
172 	socklen_t		fromlen;
173 
174 	fromlen = sizeof(from);
175 	ret = recvfrom(net_socket, (char *)huffbuff, sizeof(net_message_buffer), 0,
176 			(struct sockaddr *)&from, &fromlen);
177 	if (ret == SOCKET_ERROR)
178 	{
179 		int err = SOCKETERRNO;
180 		if (err == NET_EWOULDBLOCK)
181 			return 0;
182 		if (err == NET_ECONNREFUSED)
183 		{
184 			Con_Printf ("%s: Connection refused\n", __thisfunc__);
185 			return 0;
186 		}
187 # ifdef PLATFORM_WINDOWS
188 		if (err == WSAEMSGSIZE)
189 		{
190 			Con_Printf ("Oversize packet from %s\n",
191 					NET_AdrToString (&net_from));
192 			return 0;
193 		}
194 		if (err == WSAECONNRESET)
195 		{
196 			Con_Printf ("Connection reset by peer %s\n",
197 					NET_AdrToString (&net_from));
198 			return 0;
199 		}
200 # endif	/* _WINDOWS */
201 		Sys_Error ("%s: %s", __thisfunc__, socketerror(err));
202 	}
203 
204 	SockadrToNetadr (&from, &net_from);
205 
206 	if (ret == (int) sizeof(net_message_buffer))
207 	{
208 		Con_Printf ("Oversize packet from %s\n",
209 					NET_AdrToString (&net_from));
210 		return 0;
211 	}
212 
213 	LastCompMessageSize += ret;	/* debug: bytes actually received */
214 
215 	HuffDecode(huffbuff, net_message_buffer, ret, &ret,
216 				sizeof(net_message_buffer));
217 	if (ret > (int) sizeof(net_message_buffer))
218 	{
219 		Con_Printf ("Oversize compressed data from %s\n",
220 					NET_AdrToString (&net_from));
221 		return 0;
222 	}
223 	net_message.cursize = ret;
224 
225 	return ret;
226 }
227 
228 
229 //=============================================================================
230 
NET_SendPacket(int length,void * data,const netadr_t * to)231 void NET_SendPacket (int length, void *data, const netadr_t *to)
232 {
233 	int	ret, outlen;
234 	struct sockaddr_in	addr;
235 
236 	NetadrToSockadr (to, &addr);
237 	HuffEncode((unsigned char *)data, huffbuff, length, &outlen);
238 
239 	ret = sendto (net_socket, (char *) huffbuff, outlen, 0,
240 				(struct sockaddr *)&addr, sizeof(addr) );
241 	if (ret == SOCKET_ERROR)
242 	{
243 		int err = SOCKETERRNO;
244 		if (err == NET_EWOULDBLOCK)
245 			return;
246 		if (err == NET_ECONNREFUSED)
247 		{
248 			Con_Printf ("%s: Connection refused\n", __thisfunc__);
249 			return;
250 		}
251 		Con_Printf ("%s ERROR: %s\n", __thisfunc__, socketerror(err));
252 	}
253 }
254 
255 
256 //=============================================================================
257 
NET_CheckReadTimeout(long sec,long usec)258 int NET_CheckReadTimeout (long sec, long usec)
259 {
260 	fd_set		readfds;
261 	struct timeval	timeout;
262 
263 	FD_ZERO (&readfds);
264 	FD_SET (net_socket, &readfds);
265 	timeout.tv_sec = sec;
266 	timeout.tv_usec = usec;
267 
268 	return selectsocket(net_socket + 1, &readfds, NULL, NULL, &timeout);
269 }
270 
271 //=============================================================================
272 
UDP_OpenSocket(int port)273 static sys_socket_t UDP_OpenSocket (int port)
274 {
275 	int		i;
276 	sys_socket_t	newsocket;
277 	struct sockaddr_in	address;
278 #if defined(PLATFORM_WINDOWS) || defined(PLATFORM_DOS)
279 	u_long	_true = 1;
280 #else
281 	int	_true = 1;
282 #endif
283 	int		err;
284 
285 	newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
286 	if (newsocket == INVALID_SOCKET)
287 	{
288 		err = SOCKETERRNO;
289 		Sys_Error ("%s: socket: %s", __thisfunc__, socketerror(err));
290 	}
291 
292 	if (ioctlsocket (newsocket, FIONBIO, IOCTLARG_P(&_true)) == SOCKET_ERROR)
293 	{
294 		err = SOCKETERRNO;
295 		Sys_Error ("%s: ioctl FIONBIO: %s", __thisfunc__, socketerror(err));
296 	}
297 
298 	memset(&address, 0, sizeof(struct sockaddr_in));
299 	address.sin_family = AF_INET;
300 	//ZOID -- check for interface binding option
301 	i = COM_CheckParm("-ip");
302 	if (!i)
303 		i = COM_CheckParm("-bindip");
304 	if (i && i < com_argc-1)
305 	{
306 		address.sin_addr.s_addr = inet_addr(com_argv[i+1]);
307 		if (address.sin_addr.s_addr == INADDR_NONE)
308 			Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
309 		Con_Printf("Binding to IP Interface Address of %s\n", inet_ntoa(address.sin_addr));
310 	}
311 	else
312 	{
313 		address.sin_addr.s_addr = INADDR_ANY;
314 	}
315 
316 	if (port == PORT_ANY)
317 		address.sin_port = 0;
318 	else
319 		address.sin_port = htons((short)port);
320 
321 	if (bind(newsocket, (struct sockaddr *)&address, sizeof(address)) == SOCKET_ERROR)
322 	{
323 		err = SOCKETERRNO;
324 		Sys_Error ("%s: bind: %s", __thisfunc__, socketerror(err));
325 	}
326 
327 	return newsocket;
328 }
329 
NET_GetLocalAddress(void)330 static void NET_GetLocalAddress (void)
331 {
332 	char	buff[MAXHOSTNAMELEN];
333 	struct sockaddr_in	address;
334 	socklen_t		namelen;
335 	int		err;
336 
337 	if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
338 	{
339 		err = SOCKETERRNO;
340 		Sys_Error ("%s: gethostname: %s", __thisfunc__, socketerror(err));
341 	}
342 	buff[MAXHOSTNAMELEN-1] = 0;
343 
344 	NET_StringToAdr (buff, &net_local_adr);
345 
346 	namelen = sizeof(address);
347 	if (getsockname (net_socket, (struct sockaddr *)&address, &namelen) == SOCKET_ERROR)
348 	{
349 		err = SOCKETERRNO;
350 		Sys_Error ("%s: getsockname: %s", __thisfunc__, socketerror(err));
351 	}
352 	net_local_adr.port = address.sin_port;
353 
354 	Con_SafePrintf("IP address %s\n", NET_AdrToString(&net_local_adr));
355 }
356 
357 /*
358 ====================
359 NET_Init
360 ====================
361 */
NET_Init(int port)362 void NET_Init (int port)
363 {
364 	in_addr_t a = htonl(INADDR_LOOPBACK);
365 #ifdef PLATFORM_WINDOWS
366 	int err = WSAStartup(MAKEWORD(1,1), &winsockdata);
367 	if (err != 0)
368 		Sys_Error ("Winsock initialization failed (%s)", socketerror(err));
369 #endif
370 #ifdef PLATFORM_AMIGA
371 	SocketBase = OpenLibrary("bsdsocket.library", 0);
372 	if (!SocketBase)
373 		Sys_Error ("Can't open bsdsocket.library.");
374 #endif
375 #if defined(PLATFORM_OS2) && !defined(__EMX__)
376 	if (sock_init() < 0)
377 		Sys_Error ("Can't initialize IBM OS/2 sockets");
378 #endif /* OS/2 */
379 #if defined(PLATFORM_DOS) && defined(USE_WATT32)
380 	int i, err;
381 
382 /*	dbug_init();*/
383 	i = _watt_do_exit;
384 	_watt_do_exit = 0;
385 	err = sock_init();
386 	_watt_do_exit = i;
387 	if (err != 0)
388 		Sys_Error ("WATTCP initialization failed (%s)", sock_init_err(err));
389 #endif	/* WatTCP  */
390 
391 	// open the single socket to be used for all communications
392 	net_socket = UDP_OpenSocket (port);
393 
394 	// init the message buffer
395 	SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
396 
397 	// determine my name & address
398 	NET_GetLocalAddress ();
399 
400 	memset (&net_loopback_adr, 0, sizeof(netadr_t));
401 	memcpy (net_loopback_adr.ip, &a, 4);
402 
403 	Con_SafePrintf("UDP Initialized\n");
404 }
405 
406 /*
407 ====================
408 NET_Shutdown
409 ====================
410 */
NET_Shutdown(void)411 void	NET_Shutdown (void)
412 {
413 	if (net_socket != INVALID_SOCKET)
414 	{
415 		closesocket (net_socket);
416 		net_socket = INVALID_SOCKET;
417 	}
418 #ifdef PLATFORM_WINDOWS
419 	WSACleanup ();
420 #endif
421 #ifdef PLATFORM_AMIGA
422 	if (SocketBase)
423 	{
424 		CloseLibrary(SocketBase);
425 		SocketBase = NULL;
426 	}
427 #endif
428 }
429 
430