fea9a91d20ba04086c7211463a701f5e31276ac4
[xonotic/darkplaces.git] / net_wins.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // net_wins.c
21
22 #include "quakedef.h"
23 #include "winquake.h"
24
25 #define MAXHOSTNAMELEN          256
26
27 static int net_acceptsocket = -1;               // socket for fielding new connections
28 static int net_controlsocket;
29 static int net_broadcastsocket = 0;
30 static struct qsockaddr broadcastaddr;
31
32 static unsigned long myAddr;
33
34 #include "net_wins.h"
35
36 WSADATA         winsockdata;
37
38 //=============================================================================
39
40 static double   blocktime;
41
42 BOOL PASCAL FAR BlockingHook(void)
43 {
44         MSG             msg;
45         BOOL    ret;
46
47         if ((Sys_DoubleTime() - blocktime) > 2.0)
48         {
49                 WSACancelBlockingCall();
50                 return false;
51         }
52
53         /* get the next message, if any */
54         ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
55
56         /* if we got one, process it */
57         if (ret) {
58                 TranslateMessage(&msg);
59                 DispatchMessage(&msg);
60         }
61
62         /* true if we got a message */
63         return ret;
64 }
65
66
67 void WINS_GetLocalAddress(void)
68 {
69         struct hostent  *local = NULL;
70         char                    buff[MAXHOSTNAMELEN];
71         unsigned long   addr;
72
73         if (myAddr != INADDR_ANY)
74                 return;
75
76         if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
77                 return;
78
79         blocktime = Sys_DoubleTime();
80         WSASetBlockingHook(BlockingHook);
81         local = gethostbyname(buff);
82         WSAUnhookBlockingHook();
83         if (local == NULL)
84                 return;
85
86         myAddr = *(int *)local->h_addr_list[0];
87
88         addr = ntohl(myAddr);
89         sprintf(my_tcpip_address, "%d.%d.%d.%d", (int) ((addr >> 24) & 0xff), (int) ((addr >> 16) & 0xff), (int) ((addr >> 8) & 0xff), (int) (addr & 0xff));
90 }
91
92
93 int WINS_Init (void)
94 {
95         int             i;
96         char    buff[MAXHOSTNAMELEN];
97         char    *p;
98         int             r;
99
100         if (COM_CheckParm ("-noudp"))
101                 return -1;
102
103         r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
104         if (r)
105         {
106                 Con_SafePrintf ("Winsock initialization failed.\n");
107                 return -1;
108         }
109
110         // determine my name
111         if (gethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
112         {
113                 Con_DPrintf ("Winsock TCP/IP Initialization failed.\n");
114                 WSACleanup ();
115                 return -1;
116         }
117
118         // if the quake hostname isn't set, set it to the machine name
119         if (strcmp(hostname.string, "UNNAMED") == 0)
120         {
121                 // see if it's a text IP address (well, close enough)
122                 for (p = buff; *p; p++)
123                         if ((*p < '0' || *p > '9') && *p != '.')
124                                 break;
125
126                 // if it is a real name, strip off the domain; we only want the host
127                 if (*p)
128                 {
129                         for (i = 0; i < 15; i++)
130                                 if (buff[i] == '.')
131                                         break;
132                         buff[i] = 0;
133                 }
134                 Cvar_Set ("hostname", buff);
135         }
136
137         i = COM_CheckParm ("-ip");
138         if (i)
139         {
140                 if (i < com_argc-1)
141                 {
142                         myAddr = inet_addr(com_argv[i+1]);
143                         if (myAddr == INADDR_NONE)
144                                 Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
145                         strcpy(my_tcpip_address, com_argv[i+1]);
146                 }
147                 else
148                 {
149                         Sys_Error ("NET_Init: you must specify an IP address after -ip");
150                 }
151         }
152         else
153         {
154                 myAddr = INADDR_ANY;
155                 strcpy(my_tcpip_address, "INADDR_ANY");
156         }
157
158         if ((net_controlsocket = WINS_OpenSocket (0)) == -1)
159         {
160                 Con_Printf("WINS_Init: Unable to open control socket\n");
161                 WSACleanup ();
162                 return -1;
163         }
164
165         ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
166         ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
167         ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport);
168
169         Con_Printf("Winsock TCP/IP Initialized\n");
170         tcpipAvailable = true;
171
172         return net_controlsocket;
173 }
174
175 //=============================================================================
176
177 void WINS_Shutdown (void)
178 {
179         WINS_Listen (false);
180         WINS_CloseSocket (net_controlsocket);
181         WSACleanup ();
182 }
183
184 //=============================================================================
185
186 void WINS_Listen (qboolean state)
187 {
188         // enable listening
189         if (state)
190         {
191                 if (net_acceptsocket != -1)
192                         return;
193                 WINS_GetLocalAddress();
194                 if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1)
195                         Sys_Error ("WINS_Listen: Unable to open accept socket\n");
196                 return;
197         }
198
199         // disable listening
200         if (net_acceptsocket == -1)
201                 return;
202         WINS_CloseSocket (net_acceptsocket);
203         net_acceptsocket = -1;
204 }
205
206 //=============================================================================
207
208 int WINS_OpenSocket (int port)
209 {
210         int newsocket;
211         struct sockaddr_in address;
212         u_long _true = 1;
213
214         if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
215                 return -1;
216
217         if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
218                 goto ErrorReturn;
219
220         address.sin_family = AF_INET;
221         address.sin_addr.s_addr = myAddr;
222         address.sin_port = htons((unsigned short)port);
223         if( bind (newsocket, (void *)&address, sizeof(address)) == 0)
224                 return newsocket;
225
226         Sys_Error ("Unable to bind to %s", WINS_AddrToString((struct qsockaddr *)&address));
227 ErrorReturn:
228         closesocket (newsocket);
229         return -1;
230 }
231
232 //=============================================================================
233
234 int WINS_CloseSocket (int socket)
235 {
236         if (socket == net_broadcastsocket)
237                 net_broadcastsocket = 0;
238         return closesocket (socket);
239 }
240
241
242 //=============================================================================
243 /*
244 ============
245 PartialIPAddress
246
247 this lets you type only as much of the net address as required, using
248 the local network components to fill in the rest
249 ============
250 */
251 static int PartialIPAddress (const char *in, struct qsockaddr *hostaddr)
252 {
253         char buff[256];
254         char *b;
255         int addr;
256         int num;
257         int mask;
258         int run;
259         int port;
260
261         buff[0] = '.';
262         b = buff;
263         strcpy(buff+1, in);
264         if (buff[1] == '.')
265                 b++;
266
267         addr = 0;
268         mask=-1;
269         while (*b == '.')
270         {
271                 b++;
272                 num = 0;
273                 run = 0;
274                 while (!( *b < '0' || *b > '9'))
275                 {
276                   num = num*10 + *b++ - '0';
277                   if (++run > 3)
278                         return -1;
279                 }
280                 if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
281                         return -1;
282                 if (num < 0 || num > 255)
283                         return -1;
284                 mask<<=8;
285                 addr = (addr<<8) + num;
286         }
287
288         if (*b++ == ':')
289                 port = atoi(b);
290         else
291                 port = net_hostport;
292
293         hostaddr->sa_family = AF_INET;
294         ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
295         ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
296
297         return 0;
298 }
299 //=============================================================================
300
301 int WINS_Connect (int socket, struct qsockaddr *addr)
302 {
303         return 0;
304 }
305
306 //=============================================================================
307
308 int WINS_CheckNewConnections (void)
309 {
310         char buf[4096];
311
312         if (net_acceptsocket == -1)
313                 return -1;
314
315         if (recvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) >= 0)
316                 return net_acceptsocket;
317         return -1;
318 }
319
320 //=============================================================================
321
322 int WINS_Recv (qbyte *buf, int len, struct qsockaddr *addr)
323 {
324         return WINS_Read (net_acceptsocket, buf, len, addr);
325 }
326
327 //=============================================================================
328
329 int WINS_Send (qbyte *buf, int len, struct qsockaddr *addr)
330 {
331         return WINS_Write (net_acceptsocket, buf, len, addr);
332 }
333
334 //=============================================================================
335
336 int WINS_Read (int socket, qbyte *buf, int len, struct qsockaddr *addr)
337 {
338         int addrlen = sizeof (struct qsockaddr);
339         int ret;
340         int errno;
341
342         ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
343         if (ret == -1)
344         {
345                 errno = WSAGetLastError();
346
347                 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
348                         return 0;
349
350         }
351         return ret;
352 }
353
354 //=============================================================================
355
356 int WINS_MakeSocketBroadcastCapable (int socket)
357 {
358         int     i = 1;
359
360         // make this socket broadcast capable
361         if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
362                 return -1;
363         net_broadcastsocket = socket;
364
365         return 0;
366 }
367
368 //=============================================================================
369
370 int WINS_Broadcast (int socket, qbyte *buf, int len)
371 {
372         int ret;
373
374         if (socket != net_broadcastsocket)
375         {
376                 if (net_broadcastsocket != 0)
377                         Sys_Error("Attempted to use multiple broadcasts sockets\n");
378                 WINS_GetLocalAddress();
379                 ret = WINS_MakeSocketBroadcastCapable (socket);
380                 if (ret == -1)
381                 {
382                         Con_Printf("Unable to make socket broadcast capable\n");
383                         return ret;
384                 }
385         }
386
387         return WINS_Write (socket, buf, len, &broadcastaddr);
388 }
389
390 //=============================================================================
391
392 int WINS_Write (int socket, qbyte *buf, int len, struct qsockaddr *addr)
393 {
394         int ret;
395
396         ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
397         if (ret == -1)
398                 if (WSAGetLastError() == WSAEWOULDBLOCK)
399                         return 0;
400
401         return ret;
402 }
403
404 //=============================================================================
405
406 char *WINS_AddrToString (const struct qsockaddr *addr)
407 {
408         static char buffer[22];
409         int haddr;
410
411         haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
412         sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
413         return buffer;
414 }
415
416 //=============================================================================
417
418 int WINS_StringToAddr (const char *string, struct qsockaddr *addr)
419 {
420         int ha1, ha2, ha3, ha4, hp;
421         int ipaddr;
422
423         sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
424         ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
425
426         addr->sa_family = AF_INET;
427         ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
428         ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
429         return 0;
430 }
431
432 //=============================================================================
433
434 int WINS_GetSocketAddr (int socket, struct qsockaddr *addr)
435 {
436         int addrlen = sizeof(struct qsockaddr);
437         unsigned int a;
438
439         memset(addr, 0, sizeof(struct qsockaddr));
440         getsockname(socket, (struct sockaddr *)addr, &addrlen);
441         a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
442         if (a == 0 || a == inet_addr("127.0.0.1"))
443                 ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
444
445         return 0;
446 }
447
448 //=============================================================================
449
450 int WINS_GetNameFromAddr (const struct qsockaddr *addr, char *name)
451 {
452         struct hostent *hostentry;
453
454         hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
455         if (hostentry)
456         {
457                 strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
458                 return 0;
459         }
460
461         strcpy (name, WINS_AddrToString (addr));
462         return 0;
463 }
464
465 //=============================================================================
466
467 int WINS_GetAddrFromName(const char *name, struct qsockaddr *addr)
468 {
469         struct hostent *hostentry;
470
471         if (name[0] >= '0' && name[0] <= '9')
472                 return PartialIPAddress (name, addr);
473
474         hostentry = gethostbyname (name);
475         if (!hostentry)
476                 return -1;
477
478         addr->sa_family = AF_INET;
479         ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
480         ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
481
482         return 0;
483 }
484
485 //=============================================================================
486
487 int WINS_AddrCompare (const struct qsockaddr *addr1, const struct qsockaddr *addr2)
488 {
489         if (addr1->sa_family != addr2->sa_family)
490                 return -1;
491
492         if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
493                 return -1;
494
495         if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
496                 return 1;
497
498         return 0;
499 }
500
501 //=============================================================================
502
503 int WINS_GetSocketPort (struct qsockaddr *addr)
504 {
505         return ntohs(((struct sockaddr_in *)addr)->sin_port);
506 }
507
508
509 int WINS_SetSocketPort (struct qsockaddr *addr, int port)
510 {
511         ((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
512         return 0;
513 }
514