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