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