]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - lhnet.c
Fixed IPv6 support, including the addition of the master server messages "getserversE...
[xonotic/darkplaces.git] / lhnet.c
1
2 // Written by Forest Hale 2003-06-15 and placed into public domain.
3
4 #ifndef STANDALONETEST
5 #include "quakedef.h"
6 #endif
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <time.h>
11 #include <string.h>
12 #ifdef WIN32
13 #include <winsock2.h>
14 #include <ws2tcpip.h>
15 #else
16 #include <unistd.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <sys/ioctl.h>
20 #include <errno.h>
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <net/if.h>
25 #endif
26
27 #ifdef __MORPHOS__
28 #include <proto/socket.h>
29 #endif
30
31 // for Z_Malloc/Z_Free in quake
32 #ifndef STANDALONETEST
33 #include "zone.h"
34 #include "sys.h"
35 #include "netconn.h"
36 #else
37 #define Con_Print printf
38 #define Con_Printf printf
39 #define Z_Malloc malloc
40 #define Z_Free free
41 #endif
42
43 #include "lhnet.h"
44
45 #if defined(WIN32)
46 #define EWOULDBLOCK WSAEWOULDBLOCK
47 #define ECONNREFUSED WSAECONNREFUSED
48
49 #define SOCKETERRNO WSAGetLastError()
50
51 #define IOC_VENDOR 0x18000000
52 #define _WSAIOW(x,y) (IOC_IN|(x)|(y))
53 #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
54
55 #define SOCKLEN_T int
56 #elif defined(__MORPHOS__)
57 #define ioctlsocket IoctlSocket
58 #define closesocket CloseSocket
59 #define SOCKETERRNO Errno()
60
61 #define SOCKLEN_T int
62 #else
63 #define ioctlsocket ioctl
64 #define closesocket close
65 #define SOCKETERRNO errno
66
67 #define SOCKLEN_T socklen_t
68 #endif
69
70 typedef struct lhnetaddressnative_s
71 {
72         lhnetaddresstype_t addresstype;
73         int port;
74         union
75         {
76                 struct sockaddr sock;
77                 struct sockaddr_in in;
78                 struct sockaddr_in6 in6;
79         }
80         addr;
81 }
82 lhnetaddressnative_t;
83
84 // to make LHNETADDRESS_FromString resolve repeated hostnames faster, cache them
85 #define MAX_NAMECACHE 64
86 static struct namecache_s
87 {
88         lhnetaddressnative_t address;
89         double expirationtime;
90         char name[64];
91 }
92 namecache[MAX_NAMECACHE];
93 static int namecacheposition = 0;
94
95 int LHNETADDRESS_FromPort(lhnetaddress_t *vaddress, lhnetaddresstype_t addresstype, int port)
96 {
97         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
98         if (!address)
99                 return 0;
100         switch(addresstype)
101         {
102         default:
103                 return 0;
104         case LHNETADDRESSTYPE_LOOP:
105                 // local:port  (loopback)
106                 memset(address, 0, sizeof(*address));
107                 address->addresstype = LHNETADDRESSTYPE_LOOP;
108                 address->port = port;
109                 return 1;
110         case LHNETADDRESSTYPE_INET4:
111                 // 0.0.0.0:port  (INADDR_ANY, binds to all interfaces)
112                 memset(address, 0, sizeof(*address));
113                 address->addresstype = LHNETADDRESSTYPE_INET4;
114                 address->port = port;
115                 address->addr.in.sin_family = AF_INET;
116                 address->addr.in.sin_port = htons((unsigned short)port);
117                 return 1;
118         case LHNETADDRESSTYPE_INET6:
119                 // [0:0:0:0:0:0:0:0]:port  (IN6ADDR_ANY, binds to all interfaces)
120                 memset(address, 0, sizeof(*address));
121                 address->addresstype = LHNETADDRESSTYPE_INET6;
122                 address->port = port;
123                 address->addr.in6.sin6_family = AF_INET6;
124                 address->addr.in6.sin6_port = htons((unsigned short)port);
125                 return 1;
126         }
127         return 0;
128 }
129
130 int LHNETADDRESS_Resolve(lhnetaddressnative_t *address, const char *name, int port)
131 {
132         char port_buff [16];
133         struct addrinfo hints;
134         struct addrinfo* addrinf;
135         int err;
136
137         dpsnprintf (port_buff, sizeof (port_buff), "%d", port);
138         port_buff[sizeof (port_buff) - 1] = '\0';
139
140         memset(&hints, 0, sizeof (hints));
141         hints.ai_family = AF_UNSPEC;
142         hints.ai_socktype = SOCK_DGRAM;
143         //hints.ai_flags = AI_PASSIVE;
144
145         err = getaddrinfo(name, port_buff, &hints, &addrinf);
146         if (err != 0 || addrinf == NULL)
147                 return 0;
148         if (addrinf->ai_addr->sa_family != AF_INET6 && addrinf->ai_addr->sa_family != AF_INET)
149                 return 0;
150
151         // great it worked
152         if (addrinf->ai_addr->sa_family == AF_INET6)
153         {
154                 address->addresstype = LHNETADDRESSTYPE_INET6;
155                 memcpy(&address->addr.in6, addrinf->ai_addr, sizeof(address->addr.in6));
156         }
157         else
158         {
159                 address->addresstype = LHNETADDRESSTYPE_INET4;
160                 memcpy(&address->addr.in, addrinf->ai_addr, sizeof(address->addr.in));
161         }
162         address->port = port;
163         
164         freeaddrinfo (addrinf);
165         return 1;
166 }
167
168 int LHNETADDRESS_FromString(lhnetaddress_t *vaddress, const char *string, int defaultport)
169 {
170         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
171         int i, port, d1, d2, d3, d4, resolved;
172         size_t namelen;
173         unsigned char *a;
174         char name[128];
175 #ifdef STANDALONETEST
176         char string2[128];
177 #endif
178         const char* addr_start;
179         const char* addr_end = NULL;
180         const char* port_name = NULL;
181         int addr_family = AF_UNSPEC;
182
183         if (!address || !string || !*string)
184                 return 0;
185         memset(address, 0, sizeof(*address));
186         address->addresstype = LHNETADDRESSTYPE_NONE;
187         port = 0;
188
189         // If it's a bracketed IPv6 address
190         if (string[0] == '[')
191         {
192                 const char* end_bracket = strchr(string, ']');
193
194                 if (end_bracket == NULL)
195                         return 0;
196
197                 if (end_bracket[1] == ':')
198                         port_name = end_bracket + 2;
199                 else if (end_bracket[1] != '\0')
200                         return 0;
201
202                 addr_family = AF_INET6;
203                 addr_start = &string[1];
204                 addr_end = end_bracket;
205         }
206         else
207         {
208                 const char* first_colon;
209
210                 addr_start = string;
211
212                 // If it's a numeric non-bracket IPv6 address (-> no port),
213                 // or it's a numeric IPv4 address, or a name, with a port
214                 first_colon = strchr(string, ':');
215                 if (first_colon != NULL)
216                 {
217                         const char* last_colon = strrchr(first_colon + 1, ':');
218
219                         // If it's an numeric IPv4 address, or a name, with a port
220                         if (last_colon == NULL)
221                         {
222                                 addr_end = first_colon;
223                                 port_name = first_colon + 1;
224                         }
225                         else
226                                 addr_family = AF_INET6;
227                 }
228         }
229
230         if (addr_end != NULL)
231                 namelen = addr_end - addr_start;
232         else
233                 namelen = strlen (addr_start);
234
235         if (namelen >= sizeof(name))
236                 namelen = sizeof(name) - 1;
237         memcpy (name, addr_start, namelen);
238         name[namelen] = 0;
239
240         if (port_name)
241                 port = atoi(port_name);
242
243         if (port == 0)
244                 port = defaultport;
245
246         // handle loopback
247         if (!strcmp(name, "local"))
248         {
249                 address->addresstype = LHNETADDRESSTYPE_LOOP;
250                 address->port = port;
251                 return 1;
252         }
253         // try to parse as dotted decimal ipv4 address first
254         // note this supports partial ip addresses
255         d1 = d2 = d3 = d4 = 0;
256 #if _MSC_VER >= 1400
257 #define sscanf sscanf_s
258 #endif
259         if (addr_family != AF_INET6 &&
260                 sscanf(name, "%d.%d.%d.%d", &d1, &d2, &d3, &d4) >= 1 && (unsigned int)d1 < 256 && (unsigned int)d2 < 256 && (unsigned int)d3 < 256 && (unsigned int)d4 < 256)
261         {
262                 // parsed a valid ipv4 address
263                 address->addresstype = LHNETADDRESSTYPE_INET4;
264                 address->port = port;
265                 address->addr.in.sin_family = AF_INET;
266                 address->addr.in.sin_port = htons((unsigned short)port);
267                 a = (unsigned char *)&address->addr.in.sin_addr;
268                 a[0] = d1;
269                 a[1] = d2;
270                 a[2] = d3;
271                 a[3] = d4;
272 #ifdef STANDALONETEST
273                 LHNETADDRESS_ToString(address, string2, sizeof(string2), 1);
274                 printf("manual parsing of ipv4 dotted decimal address \"%s\" successful: %s\n", string, string2);
275 #endif
276                 return 1;
277         }
278         for (i = 0;i < MAX_NAMECACHE;i++)
279                 if (!strcmp(namecache[i].name, name))
280                         break;
281 #ifdef STANDALONETEST
282         if (i < MAX_NAMECACHE)
283 #else
284         if (i < MAX_NAMECACHE && realtime < namecache[i].expirationtime)
285 #endif
286         {
287                 *address = namecache[i].address;
288                 address->port = port;
289                 if (address->addresstype == LHNETADDRESSTYPE_INET6)
290                 {
291                         address->addr.in6.sin6_port = htons((unsigned short)port);
292                         return 1;
293                 }
294                 else if (address->addresstype == LHNETADDRESSTYPE_INET4)
295                 {
296                         address->addr.in.sin_port = htons((unsigned short)port);
297                         return 1;
298                 }
299                 return 0;
300         }
301
302         for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++)
303                 namecache[namecacheposition].name[i] = name[i];
304         namecache[namecacheposition].name[i] = 0;
305 #ifndef STANDALONETEST
306         namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours
307 #endif
308
309         // try resolving the address (handles dns and other ip formats)
310         resolved = LHNETADDRESS_Resolve(address, name, port);
311         if (resolved)
312         {
313 #ifdef STANDALONETEST
314                 const char *protoname;
315
316                 switch (address->addresstype)
317                 {
318                         case LHNETADDRESSTYPE_INET6:
319                                 protoname = "ipv6";
320                                 break;
321                         case LHNETADDRESSTYPE_INET4:
322                                 protoname = "ipv4";
323                                 break;
324                         default:
325                                 protoname = "UNKNOWN";
326                                 break;
327                 }
328                 LHNETADDRESS_ToString(vaddress, string2, sizeof(string2), 1);
329                 Con_Printf("LHNETADDRESS_Resolve(\"%s\") returned %s address %s\n", string, protoname, string2);
330 #endif
331                 namecache[namecacheposition].address = *address;
332         }
333         else
334         {
335 #ifdef STANDALONETEST
336                 printf("name resolution failed on address \"%s\"\n", name);
337 #endif
338                 namecache[namecacheposition].address.addresstype = LHNETADDRESSTYPE_NONE;
339         }
340         
341         namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE;
342         return resolved;
343 }
344
345 int LHNETADDRESS_ToString(const lhnetaddress_t *vaddress, char *string, int stringbuffersize, int includeport)
346 {
347         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
348         const unsigned char *a;
349         *string = 0;
350         if (!address || !string || stringbuffersize < 1)
351                 return 0;
352         switch(address->addresstype)
353         {
354         default:
355                 break;
356         case LHNETADDRESSTYPE_LOOP:
357                 if (includeport)
358                 {
359                         if (stringbuffersize >= 12)
360                         {
361                                 dpsnprintf(string, stringbuffersize, "local:%d", address->port);
362                                 return 1;
363                         }
364                 }
365                 else
366                 {
367                         if (stringbuffersize >= 6)
368                         {
369                                 memcpy(string, "local", 6);
370                                 return 1;
371                         }
372                 }
373                 break;
374         case LHNETADDRESSTYPE_INET4:
375                 a = (const unsigned char *)(&address->addr.in.sin_addr);
376                 if (includeport)
377                 {
378                         if (stringbuffersize >= 22)
379                         {
380                                 dpsnprintf(string, stringbuffersize, "%d.%d.%d.%d:%d", a[0], a[1], a[2], a[3], address->port);
381                                 return 1;
382                         }
383                 }
384                 else
385                 {
386                         if (stringbuffersize >= 16)
387                         {
388                                 dpsnprintf(string, stringbuffersize, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
389                                 return 1;
390                         }
391                 }
392                 break;
393         case LHNETADDRESSTYPE_INET6:
394                 a = (const unsigned char *)(&address->addr.in6.sin6_addr);
395                 if (includeport)
396                 {
397                         if (stringbuffersize >= 88)
398                         {
399                                 dpsnprintf(string, stringbuffersize, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d", a[0] * 256 + a[1], a[2] * 256 + a[3], a[4] * 256 + a[5], a[6] * 256 + a[7], a[8] * 256 + a[9], a[10] * 256 + a[11], a[12] * 256 + a[13], a[14] * 256 + a[15], address->port);
400                                 return 1;
401                         }
402                 }
403                 else
404                 {
405                         if (stringbuffersize >= 80)
406                         {
407                                 dpsnprintf(string, stringbuffersize, "%x:%x:%x:%x:%x:%x:%x:%x", a[0] * 256 + a[1], a[2] * 256 + a[3], a[4] * 256 + a[5], a[6] * 256 + a[7], a[8] * 256 + a[9], a[10] * 256 + a[11], a[12] * 256 + a[13], a[14] * 256 + a[15]);
408                                 return 1;
409                         }
410                 }
411                 break;
412         }
413         return 0;
414 }
415
416 int LHNETADDRESS_GetAddressType(const lhnetaddress_t *address)
417 {
418         if (address)
419                 return address->addresstype;
420         else
421                 return LHNETADDRESSTYPE_NONE;
422 }
423
424 const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress)
425 {
426         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
427
428         if (address && address->addresstype == LHNETADDRESSTYPE_INET6)
429         {
430 #ifndef _WIN32
431
432                 static char ifname [IF_NAMESIZE];
433                 
434                 if (if_indextoname(address->addr.in6.sin6_scope_id, ifname) == ifname)
435                         return ifname;
436
437 #else
438
439                 // The Win32 API doesn't have if_indextoname() until Windows Vista,
440                 // but luckily it just uses the interface ID as the interface name
441
442                 static char ifname [16];
443
444                 if (dpsnprintf(ifname, sizeof(ifname), "%lu", address->addr.in6.sin6_scope_id) > 0)
445                         return ifname;
446
447 #endif
448         }
449
450         return NULL;
451 }
452
453 int LHNETADDRESS_GetPort(const lhnetaddress_t *address)
454 {
455         if (!address)
456                 return -1;
457         return address->port;
458 }
459
460 int LHNETADDRESS_SetPort(lhnetaddress_t *vaddress, int port)
461 {
462         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
463         if (!address)
464                 return 0;
465         address->port = port;
466         switch(address->addresstype)
467         {
468         case LHNETADDRESSTYPE_LOOP:
469                 return 1;
470         case LHNETADDRESSTYPE_INET4:
471                 address->addr.in.sin_port = htons((unsigned short)port);
472                 return 1;
473         case LHNETADDRESSTYPE_INET6:
474                 address->addr.in6.sin6_port = htons((unsigned short)port);
475                 return 1;
476         default:
477                 return 0;
478         }
479 }
480
481 int LHNETADDRESS_Compare(const lhnetaddress_t *vaddress1, const lhnetaddress_t *vaddress2)
482 {
483         lhnetaddressnative_t *address1 = (lhnetaddressnative_t *)vaddress1;
484         lhnetaddressnative_t *address2 = (lhnetaddressnative_t *)vaddress2;
485         if (!address1 || !address2)
486                 return 1;
487         if (address1->addresstype != address2->addresstype)
488                 return 1;
489         switch(address1->addresstype)
490         {
491         case LHNETADDRESSTYPE_LOOP:
492                 if (address1->port != address2->port)
493                         return -1;
494                 return 0;
495         case LHNETADDRESSTYPE_INET4:
496                 if (address1->addr.in.sin_family != address2->addr.in.sin_family)
497                         return 1;
498                 if (memcmp(&address1->addr.in.sin_addr, &address2->addr.in.sin_addr, sizeof(address1->addr.in.sin_addr)))
499                         return 1;
500                 if (address1->port != address2->port)
501                         return -1;
502                 return 0;
503         case LHNETADDRESSTYPE_INET6:
504                 if (address1->addr.in6.sin6_family != address2->addr.in6.sin6_family)
505                         return 1;
506                 if (memcmp(&address1->addr.in6.sin6_addr, &address2->addr.in6.sin6_addr, sizeof(address1->addr.in6.sin6_addr)))
507                         return 1;
508                 if (address1->port != address2->port)
509                         return -1;
510                 return 0;
511         default:
512                 return 1;
513         }
514 }
515
516 typedef struct lhnetpacket_s
517 {
518         void *data;
519         int length;
520         int sourceport;
521         int destinationport;
522         time_t timeout;
523 #ifndef STANDALONETEST
524         double sentdoubletime;
525 #endif
526         struct lhnetpacket_s *next, *prev;
527 }
528 lhnetpacket_t;
529
530 static int lhnet_active;
531 static lhnetsocket_t lhnet_socketlist;
532 static lhnetpacket_t lhnet_packetlist;
533 #ifdef WIN32
534 static int lhnet_didWSAStartup = 0;
535 static WSADATA lhnet_winsockdata;
536 #endif
537
538 void LHNET_Init(void)
539 {
540         if (lhnet_active)
541                 return;
542         lhnet_socketlist.next = lhnet_socketlist.prev = &lhnet_socketlist;
543         lhnet_packetlist.next = lhnet_packetlist.prev = &lhnet_packetlist;
544         lhnet_active = 1;
545 #ifdef WIN32
546         lhnet_didWSAStartup = !WSAStartup(MAKEWORD(1, 1), &lhnet_winsockdata);
547         if (!lhnet_didWSAStartup)
548                 Con_Print("LHNET_Init: WSAStartup failed, networking disabled\n");
549 #endif
550 }
551
552 void LHNET_Shutdown(void)
553 {
554         lhnetpacket_t *p;
555         if (!lhnet_active)
556                 return;
557         while (lhnet_socketlist.next != &lhnet_socketlist)
558                 LHNET_CloseSocket(lhnet_socketlist.next);
559         while (lhnet_packetlist.next != &lhnet_packetlist)
560         {
561                 p = lhnet_packetlist.next;
562                 p->prev->next = p->next;
563                 p->next->prev = p->prev;
564                 Z_Free(p);
565         }
566 #ifdef WIN32
567         if (lhnet_didWSAStartup)
568         {
569                 lhnet_didWSAStartup = 0;
570                 WSACleanup();
571         }
572 #endif
573         lhnet_active = 0;
574 }
575
576 static const char *LHNETPRIVATE_StrError(void)
577 {
578 #ifdef WIN32
579         int i = WSAGetLastError();
580         switch (i)
581         {
582                 case WSAEINTR:           return "WSAEINTR";
583                 case WSAEBADF:           return "WSAEBADF";
584                 case WSAEACCES:          return "WSAEACCES";
585                 case WSAEFAULT:          return "WSAEFAULT";
586                 case WSAEINVAL:          return "WSAEINVAL";
587                 case WSAEMFILE:          return "WSAEMFILE";
588                 case WSAEWOULDBLOCK:     return "WSAEWOULDBLOCK";
589                 case WSAEINPROGRESS:     return "WSAEINPROGRESS";
590                 case WSAEALREADY:        return "WSAEALREADY";
591                 case WSAENOTSOCK:        return "WSAENOTSOCK";
592                 case WSAEDESTADDRREQ:    return "WSAEDESTADDRREQ";
593                 case WSAEMSGSIZE:        return "WSAEMSGSIZE";
594                 case WSAEPROTOTYPE:      return "WSAEPROTOTYPE";
595                 case WSAENOPROTOOPT:     return "WSAENOPROTOOPT";
596                 case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
597                 case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
598                 case WSAEOPNOTSUPP:      return "WSAEOPNOTSUPP";
599                 case WSAEPFNOSUPPORT:    return "WSAEPFNOSUPPORT";
600                 case WSAEAFNOSUPPORT:    return "WSAEAFNOSUPPORT";
601                 case WSAEADDRINUSE:      return "WSAEADDRINUSE";
602                 case WSAEADDRNOTAVAIL:   return "WSAEADDRNOTAVAIL";
603                 case WSAENETDOWN:        return "WSAENETDOWN";
604                 case WSAENETUNREACH:     return "WSAENETUNREACH";
605                 case WSAENETRESET:       return "WSAENETRESET";
606                 case WSAECONNABORTED:    return "WSAECONNABORTED";
607                 case WSAECONNRESET:      return "WSAECONNRESET";
608                 case WSAENOBUFS:         return "WSAENOBUFS";
609                 case WSAEISCONN:         return "WSAEISCONN";
610                 case WSAENOTCONN:        return "WSAENOTCONN";
611                 case WSAESHUTDOWN:       return "WSAESHUTDOWN";
612                 case WSAETOOMANYREFS:    return "WSAETOOMANYREFS";
613                 case WSAETIMEDOUT:       return "WSAETIMEDOUT";
614                 case WSAECONNREFUSED:    return "WSAECONNREFUSED";
615                 case WSAELOOP:           return "WSAELOOP";
616                 case WSAENAMETOOLONG:    return "WSAENAMETOOLONG";
617                 case WSAEHOSTDOWN:       return "WSAEHOSTDOWN";
618                 case WSAEHOSTUNREACH:    return "WSAEHOSTUNREACH";
619                 case WSAENOTEMPTY:       return "WSAENOTEMPTY";
620                 case WSAEPROCLIM:        return "WSAEPROCLIM";
621                 case WSAEUSERS:          return "WSAEUSERS";
622                 case WSAEDQUOT:          return "WSAEDQUOT";
623                 case WSAESTALE:          return "WSAESTALE";
624                 case WSAEREMOTE:         return "WSAEREMOTE";
625                 case WSAEDISCON:         return "WSAEDISCON";
626                 case 0:                  return "no error";
627                 default:                 return "unknown WSAE error";
628         }
629 #else
630         return strerror(errno);
631 #endif
632 }
633
634 void LHNET_SleepUntilPacket_Microseconds(int microseconds)
635 {
636         fd_set fdreadset;
637         struct timeval tv;
638         int lastfd;
639         lhnetsocket_t *s;
640         FD_ZERO(&fdreadset);
641         lastfd = 0;
642         for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next)
643         {
644                 if (s->address.addresstype == LHNETADDRESSTYPE_INET4 || s->address.addresstype == LHNETADDRESSTYPE_INET6)
645                 {
646                         if (lastfd < s->inetsocket)
647                                 lastfd = s->inetsocket;
648                         FD_SET((unsigned int)s->inetsocket, &fdreadset);
649                 }
650         }
651         tv.tv_sec = microseconds / 1000000;
652         tv.tv_usec = microseconds % 1000000;
653         select(lastfd + 1, &fdreadset, NULL, NULL, &tv);
654 }
655
656 lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address)
657 {
658         lhnetsocket_t *lhnetsocket, *s;
659         if (!address)
660                 return NULL;
661         lhnetsocket = (lhnetsocket_t *)Z_Malloc(sizeof(*lhnetsocket));
662         if (lhnetsocket)
663         {
664                 memset(lhnetsocket, 0, sizeof(*lhnetsocket));
665                 lhnetsocket->address = *address;
666                 switch(lhnetsocket->address.addresstype)
667                 {
668                 case LHNETADDRESSTYPE_LOOP:
669                         if (lhnetsocket->address.port == 0)
670                         {
671                                 // allocate a port dynamically
672                                 // this search will always terminate because there is never
673                                 // an allocated socket with port 0, so if the number wraps it
674                                 // will find the port is unused, and then refuse to use port
675                                 // 0, causing an intentional failure condition
676                                 lhnetsocket->address.port = 1024;
677                                 for (;;)
678                                 {
679                                         for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next)
680                                                 if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port)
681                                                         break;
682                                         if (s == &lhnet_socketlist)
683                                                 break;
684                                         lhnetsocket->address.port++;
685                                 }
686                         }
687                         // check if the port is available
688                         for (s = lhnet_socketlist.next;s != &lhnet_socketlist;s = s->next)
689                                 if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port)
690                                         break;
691                         if (s == &lhnet_socketlist && lhnetsocket->address.port != 0)
692                         {
693                                 lhnetsocket->next = &lhnet_socketlist;
694                                 lhnetsocket->prev = lhnetsocket->next->prev;
695                                 lhnetsocket->next->prev = lhnetsocket;
696                                 lhnetsocket->prev->next = lhnetsocket;
697                                 return lhnetsocket;
698                         }
699                         break;
700                 case LHNETADDRESSTYPE_INET4:
701                 case LHNETADDRESSTYPE_INET6:
702 #ifdef WIN32
703                         if (lhnet_didWSAStartup)
704                         {
705 #endif
706                                 if ((lhnetsocket->inetsocket = socket(address->addresstype == LHNETADDRESSTYPE_INET6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1)
707                                 {
708 #ifdef WIN32
709                                         u_long _true = 1;
710                                         u_long _false = 0;
711 #else
712                                         char _true = 1;
713 #endif
714                                         if (ioctlsocket(lhnetsocket->inetsocket, FIONBIO, &_true) != -1)
715                                         {
716 #ifdef IPV6_V6ONLY
717                                                 // We need to set this flag to tell the OS that we only listen on IPv6. If we don't
718                                                 // most OSes will create a dual-protocol socket that also listens on IPv4. In this case
719                                                 // if an IPv4 socket is already bound to the port we want, our bind() call will fail.
720                                                 int ipv6_only = 1;
721                                                 if (address->addresstype != LHNETADDRESSTYPE_INET6
722                                                         || setsockopt (lhnetsocket->inetsocket, IPPROTO_IPV6, IPV6_V6ONLY,
723                                                                                    (const void *)&ipv6_only, sizeof(ipv6_only)) == 0
724 #ifdef WIN32
725                                                         // The Win32 API only supports IPV6_V6ONLY since Windows Vista, but fortunately
726                                                         // the default value is what we want on Win32 anyway (IPV6_V6ONLY = true)
727                                                         || SOCKETERRNO == WSAENOPROTOOPT
728 #endif
729                                                         )
730 #endif
731                                                 {
732                                                         lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address;
733                                                         SOCKLEN_T namelen;
734                                                         int bindresult;
735                                                         if (address->addresstype == LHNETADDRESSTYPE_INET6)
736                                                         {
737                                                                 namelen = sizeof(localaddress->addr.in6);
738                                                                 bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen);
739                                                                 if (bindresult != -1)
740                                                                         getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen);
741                                                         }
742                                                         else
743                                                         {
744                                                                 namelen = sizeof(localaddress->addr.in);
745                                                                 bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen);
746                                                                 if (bindresult != -1)
747                                                                         getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen);
748                                                         }
749                                                         if (bindresult != -1)
750                                                         {
751                                                                 int i = 1;
752                                                                 // enable broadcast on this socket
753                                                                 setsockopt(lhnetsocket->inetsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i));
754                                                                 lhnetsocket->next = &lhnet_socketlist;
755                                                                 lhnetsocket->prev = lhnetsocket->next->prev;
756                                                                 lhnetsocket->next->prev = lhnetsocket;
757                                                                 lhnetsocket->prev->next = lhnetsocket;
758 #ifdef WIN32
759                                                                 if (ioctlsocket(lhnetsocket->inetsocket, SIO_UDP_CONNRESET, &_false) == -1)
760                                                                         Con_DPrintf("LHNET_OpenSocket_Connectionless: ioctlsocket SIO_UDP_CONNRESET returned error: %s\n", LHNETPRIVATE_StrError());
761 #endif
762                                                                 return lhnetsocket;
763                                                         }
764                                                         else
765                                                                 Con_Printf("LHNET_OpenSocket_Connectionless: bind returned error: %s\n", LHNETPRIVATE_StrError());
766                                                 }
767 #ifdef IPV6_V6ONLY
768                                                 else
769                                                         Con_Printf("LHNET_OpenSocket_Connectionless: setsockopt(IPV6_V6ONLY) returned error: %s\n", LHNETPRIVATE_StrError());
770 #endif
771                                         }
772                                         else
773                                                 Con_Printf("LHNET_OpenSocket_Connectionless: ioctlsocket returned error: %s\n", LHNETPRIVATE_StrError());
774                                         closesocket(lhnetsocket->inetsocket);
775                                 }
776                                 else
777                                         Con_Printf("LHNET_OpenSocket_Connectionless: socket returned error: %s\n", LHNETPRIVATE_StrError());
778 #ifdef WIN32
779                         }
780                         else
781                                 Con_Print("LHNET_OpenSocket_Connectionless: can't open a socket (WSAStartup failed during LHNET_Init)\n");
782 #endif
783                         break;
784                 default:
785                         break;
786                 }
787                 Z_Free(lhnetsocket);
788         }
789         return NULL;
790 }
791
792 void LHNET_CloseSocket(lhnetsocket_t *lhnetsocket)
793 {
794         if (lhnetsocket)
795         {
796                 // unlink from socket list
797                 if (lhnetsocket->next == NULL)
798                         return; // invalid!
799                 lhnetsocket->next->prev = lhnetsocket->prev;
800                 lhnetsocket->prev->next = lhnetsocket->next;
801                 lhnetsocket->next = NULL;
802                 lhnetsocket->prev = NULL;
803
804                 // no special close code for loopback, just inet
805                 if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4 || lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6)
806                 {
807                         closesocket(lhnetsocket->inetsocket);
808                 }
809                 Z_Free(lhnetsocket);
810         }
811 }
812
813 lhnetaddress_t *LHNET_AddressFromSocket(lhnetsocket_t *sock)
814 {
815         if (sock)
816                 return &sock->address;
817         else
818                 return NULL;
819 }
820
821 int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, lhnetaddress_t *vaddress)
822 {
823         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
824         int value = 0;
825         if (!lhnetsocket || !address || !content || maxcontentlength < 1)
826                 return -1;
827         if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_LOOP)
828         {
829                 time_t currenttime;
830                 lhnetpacket_t *p, *pnext;
831                 // scan for any old packets to timeout while searching for a packet
832                 // that is waiting to be delivered to this socket
833                 currenttime = time(NULL);
834                 for (p = lhnet_packetlist.next;p != &lhnet_packetlist;p = pnext)
835                 {
836                         pnext = p->next;
837                         if (p->timeout < currenttime)
838                         {
839                                 // unlink and free
840                                 p->next->prev = p->prev;
841                                 p->prev->next = p->next;
842                                 Z_Free(p);
843                                 continue;
844                         }
845 #ifndef STANDALONETEST
846                         if (cl_netlocalping.value && (realtime - cl_netlocalping.value * (1.0 / 2000.0)) < p->sentdoubletime)
847                                 continue;
848 #endif
849                         if (value == 0 && p->destinationport == lhnetsocket->address.port)
850                         {
851                                 if (p->length <= maxcontentlength)
852                                 {
853                                         lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address;
854                                         *address = *localaddress;
855                                         address->port = p->sourceport;
856                                         memcpy(content, p->data, p->length);
857                                         value = p->length;
858                                 }
859                                 else
860                                         value = -1;
861                                 // unlink and free
862                                 p->next->prev = p->prev;
863                                 p->prev->next = p->next;
864                                 Z_Free(p);
865                         }
866                 }
867         }
868         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4)
869         {
870                 unsigned int inetaddresslength;
871                 address->addresstype = LHNETADDRESSTYPE_NONE;
872                 inetaddresslength = sizeof(address->addr.in);
873                 value = recvfrom(lhnetsocket->inetsocket, content, maxcontentlength, 0, &address->addr.sock, &inetaddresslength);
874                 if (value > 0)
875                 {
876                         address->addresstype = LHNETADDRESSTYPE_INET4;
877                         address->port = ntohs(address->addr.in.sin_port);
878                         return value;
879                 }
880                 else if (value == -1)
881                 {
882                         int e = SOCKETERRNO;
883                         if (e == EWOULDBLOCK)
884                                 return 0;
885                         switch (e)
886                         {
887                                 case ECONNREFUSED:
888                                         Con_Print("Connection refused\n");
889                                         return 0;
890                         }
891                         Con_Printf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError());
892                 }
893         }
894         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6)
895         {
896                 unsigned int inetaddresslength;
897                 address->addresstype = LHNETADDRESSTYPE_NONE;
898                 inetaddresslength = sizeof(address->addr.in6);
899                 value = recvfrom(lhnetsocket->inetsocket, content, maxcontentlength, 0, &address->addr.sock, &inetaddresslength);
900                 if (value > 0)
901                 {
902                         address->addresstype = LHNETADDRESSTYPE_INET6;
903                         address->port = ntohs(address->addr.in6.sin6_port);
904                         return value;
905                 }
906                 else if (value == -1)
907                 {
908                         int e = SOCKETERRNO;
909                         if (e == EWOULDBLOCK)
910                                 return 0;
911                         switch (e)
912                         {
913                                 case ECONNREFUSED:
914                                         Con_Print("Connection refused\n");
915                                         return 0;
916                         }
917                         Con_Printf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError());
918                 }
919         }
920         return value;
921 }
922
923 int LHNET_Write(lhnetsocket_t *lhnetsocket, const void *content, int contentlength, const lhnetaddress_t *vaddress)
924 {
925         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
926         int value = -1;
927         if (!lhnetsocket || !address || !content || contentlength < 1)
928                 return -1;
929         if (lhnetsocket->address.addresstype != address->addresstype)
930                 return -1;
931         if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_LOOP)
932         {
933                 lhnetpacket_t *p;
934                 p = (lhnetpacket_t *)Z_Malloc(sizeof(*p) + contentlength);
935                 p->data = (void *)(p + 1);
936                 memcpy(p->data, content, contentlength);
937                 p->length = contentlength;
938                 p->sourceport = lhnetsocket->address.port;
939                 p->destinationport = address->port;
940                 p->timeout = time(NULL) + 10;
941                 p->next = &lhnet_packetlist;
942                 p->prev = p->next->prev;
943                 p->next->prev = p;
944                 p->prev->next = p;
945 #ifndef STANDALONETEST
946                 p->sentdoubletime = realtime;
947 #endif
948                 value = contentlength;
949         }
950         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4)
951         {
952                 value = sendto(lhnetsocket->inetsocket, content, contentlength, 0, (struct sockaddr *)&address->addr.in, sizeof(struct sockaddr_in));
953                 if (value == -1)
954                 {
955                         if (SOCKETERRNO == EWOULDBLOCK)
956                                 return 0;
957                         Con_Printf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError());
958                 }
959         }
960         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6)
961         {
962                 value = sendto(lhnetsocket->inetsocket, content, contentlength, 0, (struct sockaddr *)&address->addr.in6, sizeof(struct sockaddr_in6));
963                 if (value == -1)
964                 {
965                         if (SOCKETERRNO == EWOULDBLOCK)
966                                 return 0;
967                         Con_Printf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError());
968                 }
969         }
970         return value;
971 }
972
973 #ifdef STANDALONETEST
974 int main(int argc, char **argv)
975 {
976 #if 1
977         char *buffer = "test", buffer2[1024];
978         int blen = strlen(buffer);
979         int b2len = 1024;
980         lhnetsocket_t *sock1;
981         lhnetsocket_t *sock2;
982         lhnetaddress_t myaddy1;
983         lhnetaddress_t myaddy2;
984         lhnetaddress_t myaddy3;
985         lhnetaddress_t localhostaddy1;
986         lhnetaddress_t localhostaddy2;
987         int test1;
988         int test2;
989
990         printf("calling LHNET_Init\n");
991         LHNET_Init();
992
993         printf("calling LHNET_FromPort twice to create two local addresses\n");
994         LHNETADDRESS_FromPort(&myaddy1, LHNETADDRESSTYPE_INET4, 4000);
995         LHNETADDRESS_FromPort(&myaddy2, LHNETADDRESSTYPE_INET4, 4001);
996         LHNETADDRESS_FromString(&localhostaddy1, "127.0.0.1", 4000);
997         LHNETADDRESS_FromString(&localhostaddy2, "127.0.0.1", 4001);
998
999         printf("calling LHNET_OpenSocket_Connectionless twice to create two local sockets\n");
1000         sock1 = LHNET_OpenSocket_Connectionless(&myaddy1);
1001         sock2 = LHNET_OpenSocket_Connectionless(&myaddy2);
1002
1003         printf("calling LHNET_Write to send a packet from the first socket to the second socket\n");
1004         test1 = LHNET_Write(sock1, buffer, blen, &localhostaddy2);
1005         printf("sleeping briefly\n");
1006 #ifdef WIN32
1007         Sleep (100);
1008 #else
1009         usleep (100000);
1010 #endif
1011         printf("calling LHNET_Read on the second socket to read the packet sent from the first socket\n");
1012         test2 = LHNET_Read(sock2, buffer2, b2len - 1, &myaddy3);
1013         if (test2 > 0)
1014                 Con_Printf("socket to socket test succeeded\n");
1015         else
1016                 Con_Printf("socket to socket test failed\n");
1017
1018 #ifdef WIN32
1019         printf("press any key to exit\n");
1020         getchar();
1021 #endif
1022
1023         printf("calling LHNET_Shutdown\n");
1024         LHNET_Shutdown();
1025         printf("exiting\n");
1026         return 0;
1027 #else
1028         lhnetsocket_t *sock[16], *sendsock;
1029         int i;
1030         int numsockets;
1031         int count;
1032         int length;
1033         int port;
1034         time_t oldtime;
1035         time_t newtime;
1036         char *sendmessage;
1037         int sendmessagelength;
1038         lhnetaddress_t destaddress;
1039         lhnetaddress_t receiveaddress;
1040         lhnetaddress_t sockaddress[16];
1041         char buffer[1536], addressstring[128], addressstring2[128];
1042         if ((argc == 2 || argc == 5) && (port = atoi(argv[1])) >= 1 && port < 65535)
1043         {
1044                 printf("calling LHNET_Init()\n");
1045                 LHNET_Init();
1046
1047                 numsockets = 0;
1048                 LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_LOOP, port);
1049                 LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_INET4, port);
1050                 LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_INET6, port+1);
1051
1052                 sendsock = NULL;
1053                 sendmessage = NULL;
1054                 sendmessagelength = 0;
1055
1056                 for (i = 0;i < numsockets;i++)
1057                 {
1058                         LHNETADDRESS_ToString(&sockaddress[i], addressstring, sizeof(addressstring), 1);
1059                         printf("calling LHNET_OpenSocket_Connectionless(<%s>)\n", addressstring);
1060                         if ((sock[i] = LHNET_OpenSocket_Connectionless(&sockaddress[i])))
1061                         {
1062                                 LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1);
1063                                 printf("opened socket successfully (address \"%s\")\n", addressstring2);
1064                         }
1065                         else
1066                         {
1067                                 printf("failed to open socket\n");
1068                                 if (i == 0)
1069                                 {
1070                                         LHNET_Shutdown();
1071                                         return -1;
1072                                 }
1073                         }
1074                 }
1075                 count = 0;
1076                 if (argc == 5)
1077                 {
1078                         count = atoi(argv[2]);
1079                         if (LHNETADDRESS_FromString(&destaddress, argv[3], -1))
1080                         {
1081                                 sendmessage = argv[4];
1082                                 sendmessagelength = strlen(sendmessage);
1083                                 sendsock = NULL;
1084                                 for (i = 0;i < numsockets;i++)
1085                                         if (sock[i] && LHNETADDRESS_GetAddressType(&destaddress) == LHNETADDRESS_GetAddressType(&sockaddress[i]))
1086                                                 sendsock = sock[i];
1087                                 if (sendsock == NULL)
1088                                 {
1089                                         printf("Could not find an open socket matching the addresstype (%i) of destination address, switching to listen only mode\n", LHNETADDRESS_GetAddressType(&destaddress));
1090                                         argc = 2;
1091                                 }
1092                         }
1093                         else
1094                         {
1095                                 printf("LHNETADDRESS_FromString did not like the address \"%s\", switching to listen only mode\n", argv[3]);
1096                                 argc = 2;
1097                         }
1098                 }
1099                 printf("started, now listening for \"exit\" on the opened sockets\n");
1100                 oldtime = time(NULL);
1101                 for(;;)
1102                 {
1103 #ifdef WIN32
1104                         Sleep(1);
1105 #else
1106                         usleep(1);
1107 #endif
1108                         for (i = 0;i < numsockets;i++)
1109                         {
1110                                 if (sock[i])
1111                                 {
1112                                         length = LHNET_Read(sock[i], buffer, sizeof(buffer), &receiveaddress);
1113                                         if (length < 0)
1114                                                 printf("localsock read error: length < 0");
1115                                         else if (length > 0 && length < (int)sizeof(buffer))
1116                                         {
1117                                                 buffer[length] = 0;
1118                                                 LHNETADDRESS_ToString(&receiveaddress, addressstring, sizeof(addressstring), 1);
1119                                                 LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1);
1120                                                 printf("received message \"%s\" from \"%s\" on socket \"%s\"\n", buffer, addressstring, addressstring2);
1121                                                 if (!strcmp(buffer, "exit"))
1122                                                         break;
1123                                         }
1124                                 }
1125                         }
1126                         if (i < numsockets)
1127                                 break;
1128                         if (argc == 5 && count > 0)
1129                         {
1130                                 newtime = time(NULL);
1131                                 if (newtime != oldtime)
1132                                 {
1133                                         LHNETADDRESS_ToString(&destaddress, addressstring, sizeof(addressstring), 1);
1134                                         LHNETADDRESS_ToString(LHNET_AddressFromSocket(sendsock), addressstring2, sizeof(addressstring2), 1);
1135                                         printf("calling LHNET_Write(<%s>, \"%s\", %i, <%s>)\n", addressstring2, sendmessage, sendmessagelength, addressstring);
1136                                         length = LHNET_Write(sendsock, sendmessage, sendmessagelength, &destaddress);
1137                                         if (length == sendmessagelength)
1138                                                 printf("sent successfully\n");
1139                                         else
1140                                                 printf("LH_Write failed, returned %i (length of message was %i)\n", length, strlen(argv[4]));
1141                                         oldtime = newtime;
1142                                         count--;
1143                                         if (count <= 0)
1144                                                 printf("Done sending, still listening for \"exit\"\n");
1145                                 }
1146                         }
1147                 }
1148                 for (i = 0;i < numsockets;i++)
1149                 {
1150                         if (sock[i])
1151                         {
1152                                 LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1);
1153                                 printf("calling LHNET_CloseSocket(<%s>)\n", addressstring2);
1154                                 LHNET_CloseSocket(sock[i]);
1155                         }
1156                 }
1157                 printf("calling LHNET_Shutdown()\n");
1158                 LHNET_Shutdown();
1159                 return 0;
1160         }
1161         printf("Testing code for lhnet.c\nusage: lhnettest <localportnumber> [<sendnumberoftimes> <sendaddress:port> <sendmessage>]\n");
1162         return -1;
1163 #endif
1164 }
1165 #endif
1166