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