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