]> git.xonotic.org Git - xonotic/darkplaces.git/blob - lhnet.c
net_slist: update types, declarations
[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 const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress, char *ifname, size_t ifnamelength)
611 {
612 #ifndef NOSUPPORTIPV6
613         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
614
615         if (address && address->addresstype == LHNETADDRESSTYPE_INET6)
616         {
617 #ifndef _WIN32
618
619                 if (if_indextoname(address->addr.in6.sin6_scope_id, ifname) == ifname)
620                         return ifname;
621
622 #else
623
624                 // The Win32 API doesn't have if_indextoname() until Windows Vista,
625                 // but luckily it just uses the interface ID as the interface name
626
627                 if (dpsnprintf(ifname, ifnamelength, "%lu", address->addr.in6.sin6_scope_id) > 0)
628                         return ifname;
629
630 #endif
631         }
632 #endif
633
634         return NULL;
635 }
636
637 int LHNETADDRESS_GetPort(const lhnetaddress_t *address)
638 {
639         if (!address)
640                 return -1;
641         return address->port;
642 }
643
644 int LHNETADDRESS_SetPort(lhnetaddress_t *vaddress, int port)
645 {
646         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
647         if (!address)
648                 return 0;
649         address->port = port;
650         switch(address->addresstype)
651         {
652         case LHNETADDRESSTYPE_LOOP:
653                 return 1;
654         case LHNETADDRESSTYPE_INET4:
655                 address->addr.in.sin_port = htons((unsigned short)port);
656                 return 1;
657 #ifndef NOSUPPORTIPV6
658         case LHNETADDRESSTYPE_INET6:
659                 address->addr.in6.sin6_port = htons((unsigned short)port);
660                 return 1;
661 #endif
662         default:
663                 return 0;
664         }
665 }
666
667 int LHNETADDRESS_Compare(const lhnetaddress_t *vaddress1, const lhnetaddress_t *vaddress2)
668 {
669         lhnetaddressnative_t *address1 = (lhnetaddressnative_t *)vaddress1;
670         lhnetaddressnative_t *address2 = (lhnetaddressnative_t *)vaddress2;
671         if (!address1 || !address2)
672                 return 1;
673         if (address1->addresstype != address2->addresstype)
674                 return 1;
675         switch(address1->addresstype)
676         {
677         case LHNETADDRESSTYPE_LOOP:
678                 if (address1->port != address2->port)
679                         return -1;
680                 return 0;
681         case LHNETADDRESSTYPE_INET4:
682                 if (address1->addr.in.sin_family != address2->addr.in.sin_family)
683                         return 1;
684                 if (memcmp(&address1->addr.in.sin_addr, &address2->addr.in.sin_addr, sizeof(address1->addr.in.sin_addr)))
685                         return 1;
686                 if (address1->port != address2->port)
687                         return -1;
688                 return 0;
689 #ifndef NOSUPPORTIPV6
690         case LHNETADDRESSTYPE_INET6:
691                 if (address1->addr.in6.sin6_family != address2->addr.in6.sin6_family)
692                         return 1;
693                 if (memcmp(&address1->addr.in6.sin6_addr, &address2->addr.in6.sin6_addr, sizeof(address1->addr.in6.sin6_addr)))
694                         return 1;
695                 if (address1->port != address2->port)
696                         return -1;
697                 return 0;
698 #endif
699         default:
700                 return 1;
701         }
702 }
703
704 typedef struct lhnetpacket_s
705 {
706         void *data;
707         int length;
708         int sourceport;
709         int destinationport;
710         time_t timeout;
711 #ifndef STANDALONETEST
712         double sentdoubletime;
713 #endif
714         llist_t list;
715 }
716 lhnetpacket_t;
717
718 static int lhnet_active;
719 static lhnetsocket_t lhnet_socketlist;
720 static lhnetpacket_t lhnet_packetlist;
721 static int lhnet_default_dscp = 0;
722 #ifdef WIN32
723 static int lhnet_didWSAStartup = 0;
724 static WSADATA lhnet_winsockdata;
725 #endif
726
727 void LHNET_Init(void)
728 {
729         if (lhnet_active)
730                 return;
731         List_Create(&lhnet_socketlist.list);
732         List_Create(&lhnet_packetlist.list);
733         lhnet_active = 1;
734 #ifdef WIN32
735         lhnet_didWSAStartup = !WSAStartup(MAKEWORD(1, 1), &lhnet_winsockdata);
736         if (!lhnet_didWSAStartup)
737                 Con_Print("LHNET_Init: WSAStartup failed, networking disabled\n");
738 #endif
739 }
740
741 int LHNET_DefaultDSCP(int dscp)
742 {
743 #ifdef IP_TOS
744         int prev = lhnet_default_dscp;
745         if(dscp >= 0)
746                 lhnet_default_dscp = dscp;
747         return prev;
748 #else
749         return -1;
750 #endif
751 }
752
753 void LHNET_Shutdown(void)
754 {
755         lhnetsocket_t *s, *snext;
756         lhnetpacket_t *p, *pnext;
757         if (!lhnet_active)
758                 return;
759         List_For_Each_Entry_Safe(s, snext, &lhnet_socketlist.list, lhnetsocket_t, list)
760                 LHNET_CloseSocket(s);
761         List_For_Each_Entry_Safe(p, pnext, &lhnet_packetlist.list, lhnetpacket_t, list)
762         {
763                 List_Delete(&p->list);
764                 Z_Free(p);
765         }
766 #ifdef WIN32
767         if (lhnet_didWSAStartup)
768         {
769                 lhnet_didWSAStartup = 0;
770                 WSACleanup();
771         }
772 #endif
773         lhnet_active = 0;
774 }
775
776 static const char *LHNETPRIVATE_StrError(void)
777 {
778 #ifdef WIN32
779         int i = WSAGetLastError();
780         switch (i)
781         {
782                 case WSAEINTR:           return "WSAEINTR";
783                 case WSAEBADF:           return "WSAEBADF";
784                 case WSAEACCES:          return "WSAEACCES";
785                 case WSAEFAULT:          return "WSAEFAULT";
786                 case WSAEINVAL:          return "WSAEINVAL";
787                 case WSAEMFILE:          return "WSAEMFILE";
788                 case WSAEWOULDBLOCK:     return "WSAEWOULDBLOCK";
789                 case WSAEINPROGRESS:     return "WSAEINPROGRESS";
790                 case WSAEALREADY:        return "WSAEALREADY";
791                 case WSAENOTSOCK:        return "WSAENOTSOCK";
792                 case WSAEDESTADDRREQ:    return "WSAEDESTADDRREQ";
793                 case WSAEMSGSIZE:        return "WSAEMSGSIZE";
794                 case WSAEPROTOTYPE:      return "WSAEPROTOTYPE";
795                 case WSAENOPROTOOPT:     return "WSAENOPROTOOPT";
796                 case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
797                 case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
798                 case WSAEOPNOTSUPP:      return "WSAEOPNOTSUPP";
799                 case WSAEPFNOSUPPORT:    return "WSAEPFNOSUPPORT";
800                 case WSAEAFNOSUPPORT:    return "WSAEAFNOSUPPORT";
801                 case WSAEADDRINUSE:      return "WSAEADDRINUSE";
802                 case WSAEADDRNOTAVAIL:   return "WSAEADDRNOTAVAIL";
803                 case WSAENETDOWN:        return "WSAENETDOWN";
804                 case WSAENETUNREACH:     return "WSAENETUNREACH";
805                 case WSAENETRESET:       return "WSAENETRESET";
806                 case WSAECONNABORTED:    return "WSAECONNABORTED";
807                 case WSAECONNRESET:      return "WSAECONNRESET";
808                 case WSAENOBUFS:         return "WSAENOBUFS";
809                 case WSAEISCONN:         return "WSAEISCONN";
810                 case WSAENOTCONN:        return "WSAENOTCONN";
811                 case WSAESHUTDOWN:       return "WSAESHUTDOWN";
812                 case WSAETOOMANYREFS:    return "WSAETOOMANYREFS";
813                 case WSAETIMEDOUT:       return "WSAETIMEDOUT";
814                 case WSAECONNREFUSED:    return "WSAECONNREFUSED";
815                 case WSAELOOP:           return "WSAELOOP";
816                 case WSAENAMETOOLONG:    return "WSAENAMETOOLONG";
817                 case WSAEHOSTDOWN:       return "WSAEHOSTDOWN";
818                 case WSAEHOSTUNREACH:    return "WSAEHOSTUNREACH";
819                 case WSAENOTEMPTY:       return "WSAENOTEMPTY";
820                 case WSAEPROCLIM:        return "WSAEPROCLIM";
821                 case WSAEUSERS:          return "WSAEUSERS";
822                 case WSAEDQUOT:          return "WSAEDQUOT";
823                 case WSAESTALE:          return "WSAESTALE";
824                 case WSAEREMOTE:         return "WSAEREMOTE";
825                 case WSAEDISCON:         return "WSAEDISCON";
826                 case 0:                  return "no error";
827                 default:                 return "unknown WSAE error";
828         }
829 #else
830         return strerror(errno);
831 #endif
832 }
833
834 void LHNET_SleepUntilPacket_Microseconds(int microseconds)
835 {
836 #ifdef FD_SET
837         fd_set fdreadset;
838         struct timeval tv;
839         int lastfd;
840         lhnetsocket_t *s;
841         FD_ZERO(&fdreadset);
842         lastfd = 0;
843         List_For_Each_Entry(s, &lhnet_socketlist.list, lhnetsocket_t, list)
844         {
845                 if (s->address.addresstype == LHNETADDRESSTYPE_INET4 || s->address.addresstype == LHNETADDRESSTYPE_INET6)
846                 {
847                         if (lastfd < s->inetsocket)
848                                 lastfd = s->inetsocket;
849 #if defined(WIN32) && !defined(_MSC_VER)
850                         FD_SET((int)s->inetsocket, &fdreadset);
851 #else
852                         FD_SET((unsigned int)s->inetsocket, &fdreadset);
853 #endif
854                 }
855         }
856         tv.tv_sec = microseconds / 1000000;
857         tv.tv_usec = microseconds % 1000000;
858         select(lastfd + 1, &fdreadset, NULL, NULL, &tv);
859 #else
860         Sys_Sleep(microseconds);
861 #endif
862 }
863
864 lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address)
865 {
866         lhnetsocket_t *lhnetsocket, *s;
867         if (!address)
868                 return NULL;
869         lhnetsocket = (lhnetsocket_t *)Z_Malloc(sizeof(*lhnetsocket));
870         if (lhnetsocket)
871         {
872                 memset(lhnetsocket, 0, sizeof(*lhnetsocket));
873                 lhnetsocket->address = *address;
874                 switch(lhnetsocket->address.addresstype)
875                 {
876                 case LHNETADDRESSTYPE_LOOP:
877                         if (lhnetsocket->address.port == 0)
878                         {
879                                 // allocate a port dynamically
880                                 // this search will always terminate because there is never
881                                 // an allocated socket with port 0, so if the number wraps it
882                                 // will find the port is unused, and then refuse to use port
883                                 // 0, causing an intentional failure condition
884                                 lhnetsocket->address.port = 1024;
885                                 for (;;)
886                                 {
887                                         List_For_Each_Entry(s, &lhnet_socketlist.list, lhnetsocket_t, list)
888                                                 if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port)
889                                                         break;
890                                         if (s == &lhnet_socketlist)
891                                                 break;
892                                         lhnetsocket->address.port++;
893                                 }
894                         }
895                         // check if the port is available
896                         List_For_Each_Entry(s, &lhnet_socketlist.list, lhnetsocket_t, list)
897                                 if (s->address.addresstype == lhnetsocket->address.addresstype && s->address.port == lhnetsocket->address.port)
898                                         break;
899                         if (s == &lhnet_socketlist && lhnetsocket->address.port != 0)
900                         {
901                                 List_Add_Tail(&lhnetsocket->list, &lhnet_socketlist.list);
902                                 return lhnetsocket;
903                         }
904                         break;
905                 case LHNETADDRESSTYPE_INET4:
906 #ifndef NOSUPPORTIPV6
907                 case LHNETADDRESSTYPE_INET6:
908 #endif
909 #ifdef WIN32
910                         if (lhnet_didWSAStartup)
911                         {
912 #endif
913 #ifndef NOSUPPORTIPV6
914                                 if ((lhnetsocket->inetsocket = socket(address->addresstype == LHNETADDRESSTYPE_INET6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1)
915 #else
916                                 if ((lhnetsocket->inetsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1)
917 #endif
918                                 {
919 #ifdef WIN32
920                                         u_long _false = 0;
921 #endif
922 #ifdef MSG_DONTWAIT
923                                         if (1)
924 #else
925 #ifdef WIN32
926                                         u_long _true = 1;
927 #else
928                                         char _true = 1;
929 #endif
930                                         if (ioctlsocket(lhnetsocket->inetsocket, FIONBIO, &_true) != -1)
931 #endif
932                                         {
933 #ifdef IPV6_V6ONLY
934                                                 // We need to set this flag to tell the OS that we only listen on IPv6. If we don't
935                                                 // most OSes will create a dual-protocol socket that also listens on IPv4. In this case
936                                                 // if an IPv4 socket is already bound to the port we want, our bind() call will fail.
937                                                 int ipv6_only = 1;
938                                                 if (address->addresstype != LHNETADDRESSTYPE_INET6
939                                                         || setsockopt (lhnetsocket->inetsocket, IPPROTO_IPV6, IPV6_V6ONLY,
940                                                                                    (const char *)&ipv6_only, sizeof(ipv6_only)) == 0
941 #ifdef WIN32
942                                                         // The Win32 API only supports IPV6_V6ONLY since Windows Vista, but fortunately
943                                                         // the default value is what we want on Win32 anyway (IPV6_V6ONLY = true)
944                                                         || SOCKETERRNO == WSAENOPROTOOPT
945 #endif
946                                                         )
947 #endif
948                                                 {
949                                                         lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address;
950                                                         SOCKLEN_T namelen;
951                                                         int bindresult;
952
953 #if defined(SOL_RFC1149) && defined(RFC1149_1149ONLY)
954                                                         // we got reports of massive lags when this protocol was chosen as transport
955                                                         // so better turn it off
956                                                         {
957                                                                 int rfc1149only = 0;
958                                                                 int rfc1149enabled = 0;
959                                                                 if(setsockopt(lhnetsocket->inetsocket, SOL_RFC1149, RFC1149_1149ONLY, &rfc1149only))
960                                                                         Con_Printf(CON_ERROR "LHNET_OpenSocket_Connectionless: warning: setsockopt(RFC1149_1149ONLY) returned error: %s\n", LHNETPRIVATE_StrError());
961                                                                 if(setsockopt(lhnetsocket->inetsocket, SOL_RFC1149, RFC1149_ENABLED, &rfc1149enabled))
962                                                                         Con_Printf(CON_ERROR "LHNET_OpenSocket_Connectionless: warning: setsockopt(RFC1149_ENABLED) returned error: %s\n", LHNETPRIVATE_StrError());
963                                                         }
964 #endif
965
966 #ifndef NOSUPPORTIPV6
967                                                         if (address->addresstype == LHNETADDRESSTYPE_INET6)
968                                                         {
969                                                                 namelen = sizeof(localaddress->addr.in6);
970                                                                 bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen);
971                                                                 if (bindresult != -1)
972                                                                 {
973                                                                         if (getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen))
974                                                                         {
975                                                                                 // If getsockname failed, we can assume the bound socket is useless.
976                                                                                 bindresult = -1;
977                                                                         }
978                                                                 }
979                                                         }
980                                                         else
981 #endif
982                                                         {
983                                                                 namelen = sizeof(localaddress->addr.in);
984                                                                 bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen);
985                                                                 if (bindresult != -1)
986                                                                 {
987                                                                         if (getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen))
988                                                                         {
989                                                                                 // If getsockname failed, we can assume the bound socket is useless.
990                                                                                 bindresult = -1;
991                                                                         }
992                                                                 }
993                                                         }
994                                                         if (bindresult != -1)
995                                                         {
996                                                                 int i = 1;
997                                                                 // enable broadcast on this socket
998                                                                 setsockopt(lhnetsocket->inetsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i));
999 #ifdef IP_TOS
1000                                                                 {
1001                                                                         // enable DSCP for ToS support
1002                                                                         int tos = lhnet_default_dscp << 2;
1003                                                                         if (setsockopt(lhnetsocket->inetsocket, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)))
1004                                                                         {
1005                                                                                 // Error in setsockopt - fine, we'll simply set no TOS then.
1006                                                                         }
1007                                                                 }
1008 #endif
1009                                                                 List_Add_Tail(&lhnetsocket->list, &lhnet_socketlist.list);
1010 #ifdef WIN32
1011                                                                 if (ioctlsocket(lhnetsocket->inetsocket, SIO_UDP_CONNRESET, &_false) == -1)
1012                                                                         Con_DPrintf("LHNET_OpenSocket_Connectionless: ioctlsocket SIO_UDP_CONNRESET returned error: %s\n", LHNETPRIVATE_StrError());
1013 #endif
1014                                                                 return lhnetsocket;
1015                                                         }
1016                                                         else
1017                                                                 Con_Printf("LHNET_OpenSocket_Connectionless: bind returned error: %s\n", LHNETPRIVATE_StrError());
1018                                                 }
1019 #ifdef IPV6_V6ONLY
1020                                                 else
1021                                                         Con_Printf("LHNET_OpenSocket_Connectionless: setsockopt(IPV6_V6ONLY) returned error: %s\n", LHNETPRIVATE_StrError());
1022 #endif
1023                                         }
1024                                         else
1025                                                 Con_Printf("LHNET_OpenSocket_Connectionless: ioctlsocket returned error: %s\n", LHNETPRIVATE_StrError());
1026                                         closesocket(lhnetsocket->inetsocket);
1027                                 }
1028                                 else
1029                                         Con_Printf("LHNET_OpenSocket_Connectionless: socket returned error: %s\n", LHNETPRIVATE_StrError());
1030 #ifdef WIN32
1031                         }
1032                         else
1033                                 Con_Print("LHNET_OpenSocket_Connectionless: can't open a socket (WSAStartup failed during LHNET_Init)\n");
1034 #endif
1035                         break;
1036                 default:
1037                         break;
1038                 }
1039                 Z_Free(lhnetsocket);
1040         }
1041         return NULL;
1042 }
1043
1044 void LHNET_CloseSocket(lhnetsocket_t *lhnetsocket)
1045 {
1046         if (lhnetsocket)
1047         {
1048                 List_Delete(&lhnetsocket->list);
1049                 // no special close code for loopback, just inet
1050                 if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4 || lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6)
1051                 {
1052                         closesocket(lhnetsocket->inetsocket);
1053                 }
1054                 Z_Free(lhnetsocket);
1055         }
1056 }
1057
1058 lhnetaddress_t *LHNET_AddressFromSocket(lhnetsocket_t *sock)
1059 {
1060         if (sock)
1061                 return &sock->address;
1062         else
1063                 return NULL;
1064 }
1065
1066 int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, lhnetaddress_t *vaddress)
1067 {
1068         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
1069         int value = 0;
1070         if (!lhnetsocket || !address || !content || maxcontentlength < 1)
1071                 return -1;
1072         if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_LOOP)
1073         {
1074                 time_t currenttime;
1075                 lhnetpacket_t *p, *pnext;
1076                 // scan for any old packets to timeout while searching for a packet
1077                 // that is waiting to be delivered to this socket
1078                 currenttime = time(NULL);
1079                 List_For_Each_Entry_Safe(p, pnext, &lhnet_packetlist.list, lhnetpacket_t, list)
1080                 {
1081                         if (p->timeout < currenttime)
1082                         {
1083                                 // unlink and free
1084                                 List_Delete(&p->list);
1085                                 Z_Free(p);
1086                                 continue;
1087                         }
1088 #ifndef STANDALONETEST
1089                         if (net_fakelag.value && (host.realtime - net_fakelag.value * (1.0 / 2000.0)) < p->sentdoubletime)
1090                                 continue;
1091 #endif
1092                         if (value == 0 && p->destinationport == lhnetsocket->address.port)
1093                         {
1094                                 if (p->length <= maxcontentlength)
1095                                 {
1096                                         lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address;
1097                                         *address = *localaddress;
1098                                         address->port = p->sourceport;
1099                                         memcpy(content, p->data, p->length);
1100                                         value = p->length;
1101                                 }
1102                                 else
1103                                         value = -1;
1104                                 // unlink and free
1105                                 List_Delete(&p->list);
1106                                 Z_Free(p);
1107                         }
1108                 }
1109         }
1110         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4)
1111         {
1112                 SOCKLEN_T inetaddresslength;
1113                 address->addresstype = LHNETADDRESSTYPE_NONE;
1114                 inetaddresslength = sizeof(address->addr.in);
1115                 value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength);
1116                 if (value > 0)
1117                 {
1118                         address->addresstype = LHNETADDRESSTYPE_INET4;
1119                         address->port = ntohs(address->addr.in.sin_port);
1120                         return value;
1121                 }
1122                 else if (value < 0)
1123                 {
1124                         int e = SOCKETERRNO;
1125                         if (e == EWOULDBLOCK)
1126                                 return 0;
1127                         switch (e)
1128                         {
1129                                 case ECONNREFUSED:
1130                                         Con_Print("Connection refused\n");
1131                                         return 0;
1132                         }
1133                         Con_DPrintf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError());
1134                 }
1135         }
1136 #ifndef NOSUPPORTIPV6
1137         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6)
1138         {
1139                 SOCKLEN_T inetaddresslength;
1140                 address->addresstype = LHNETADDRESSTYPE_NONE;
1141                 inetaddresslength = sizeof(address->addr.in6);
1142                 value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength);
1143                 if (value > 0)
1144                 {
1145                         address->addresstype = LHNETADDRESSTYPE_INET6;
1146                         address->port = ntohs(address->addr.in6.sin6_port);
1147                         return value;
1148                 }
1149                 else if (value == -1)
1150                 {
1151                         int e = SOCKETERRNO;
1152                         if (e == EWOULDBLOCK)
1153                                 return 0;
1154                         switch (e)
1155                         {
1156                                 case ECONNREFUSED:
1157                                         Con_Print("Connection refused\n");
1158                                         return 0;
1159                         }
1160                         Con_DPrintf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError());
1161                 }
1162         }
1163 #endif
1164         return value;
1165 }
1166
1167 int LHNET_Write(lhnetsocket_t *lhnetsocket, const void *content, int contentlength, const lhnetaddress_t *vaddress)
1168 {
1169         lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress;
1170         int value = -1;
1171         if (!lhnetsocket || !address || !content || contentlength < 1)
1172                 return -1;
1173         if (lhnetsocket->address.addresstype != address->addresstype)
1174                 return -1;
1175         if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_LOOP)
1176         {
1177                 lhnetpacket_t *p;
1178                 p = (lhnetpacket_t *)Z_Malloc(sizeof(*p) + contentlength);
1179                 p->data = (void *)(p + 1);
1180                 memcpy(p->data, content, contentlength);
1181                 p->length = contentlength;
1182                 p->sourceport = lhnetsocket->address.port;
1183                 p->destinationport = address->port;
1184                 p->timeout = time(NULL) + 10;
1185                 List_Add_Tail(&p->list, &lhnet_packetlist.list);
1186
1187 #ifndef STANDALONETEST
1188                 p->sentdoubletime = host.realtime;
1189 #endif
1190                 value = contentlength;
1191         }
1192         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4)
1193         {
1194                 value = sendto(lhnetsocket->inetsocket, (char *)content, contentlength, LHNET_SENDTO_FLAGS, (struct sockaddr *)&address->addr.in, sizeof(struct sockaddr_in));
1195                 if (value == -1)
1196                 {
1197                         if (SOCKETERRNO == EWOULDBLOCK)
1198                                 return 0;
1199                         Con_DPrintf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError());
1200                 }
1201         }
1202 #ifndef NOSUPPORTIPV6
1203         else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6)
1204         {
1205                 value = sendto(lhnetsocket->inetsocket, (char *)content, contentlength, 0, (struct sockaddr *)&address->addr.in6, sizeof(struct sockaddr_in6));
1206                 if (value == -1)
1207                 {
1208                         if (SOCKETERRNO == EWOULDBLOCK)
1209                                 return 0;
1210                         Con_DPrintf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError());
1211                 }
1212         }
1213 #endif
1214         return value;
1215 }
1216
1217 #ifdef STANDALONETEST
1218 int main(int argc, char **argv)
1219 {
1220 #if 1
1221         char *buffer = "test", buffer2[1024];
1222         int blen = strlen(buffer);
1223         int b2len = 1024;
1224         lhnetsocket_t *sock1;
1225         lhnetsocket_t *sock2;
1226         lhnetaddress_t myaddy1;
1227         lhnetaddress_t myaddy2;
1228         lhnetaddress_t myaddy3;
1229         lhnetaddress_t localhostaddy1;
1230         lhnetaddress_t localhostaddy2;
1231         int test1;
1232         int test2;
1233
1234         printf("calling LHNET_Init\n");
1235         LHNET_Init();
1236
1237         printf("calling LHNET_FromPort twice to create two local addresses\n");
1238         LHNETADDRESS_FromPort(&myaddy1, LHNETADDRESSTYPE_INET4, 4000);
1239         LHNETADDRESS_FromPort(&myaddy2, LHNETADDRESSTYPE_INET4, 4001);
1240         LHNETADDRESS_FromString(&localhostaddy1, "127.0.0.1", 4000);
1241         LHNETADDRESS_FromString(&localhostaddy2, "127.0.0.1", 4001);
1242
1243         printf("calling LHNET_OpenSocket_Connectionless twice to create two local sockets\n");
1244         sock1 = LHNET_OpenSocket_Connectionless(&myaddy1);
1245         sock2 = LHNET_OpenSocket_Connectionless(&myaddy2);
1246
1247         printf("calling LHNET_Write to send a packet from the first socket to the second socket\n");
1248         test1 = LHNET_Write(sock1, buffer, blen, &localhostaddy2);
1249         printf("sleeping briefly\n");
1250 #ifdef WIN32
1251         Sleep (100);
1252 #else
1253         usleep (100000);
1254 #endif
1255         printf("calling LHNET_Read on the second socket to read the packet sent from the first socket\n");
1256         test2 = LHNET_Read(sock2, buffer2, b2len - 1, &myaddy3);
1257         if (test2 > 0)
1258                 Con_Printf("socket to socket test succeeded\n");
1259         else
1260                 Con_Printf("socket to socket test failed\n");
1261
1262 #ifdef WIN32
1263         printf("press any key to exit\n");
1264         getchar();
1265 #endif
1266
1267         printf("calling LHNET_Shutdown\n");
1268         LHNET_Shutdown();
1269         printf("exiting\n");
1270         return 0;
1271 #else
1272         lhnetsocket_t *sock[16], *sendsock;
1273         int i;
1274         int numsockets;
1275         int count;
1276         int length;
1277         int port;
1278         time_t oldtime;
1279         time_t newtime;
1280         char *sendmessage;
1281         int sendmessagelength;
1282         lhnetaddress_t destaddress;
1283         lhnetaddress_t receiveaddress;
1284         lhnetaddress_t sockaddress[16];
1285         char buffer[1536], addressstring[128], addressstring2[128];
1286         if ((argc == 2 || argc == 5) && (port = atoi(argv[1])) >= 1 && port < 65535)
1287         {
1288                 printf("calling LHNET_Init()\n");
1289                 LHNET_Init();
1290
1291                 numsockets = 0;
1292                 LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_LOOP, port);
1293                 LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_INET4, port);
1294                 LHNETADDRESS_FromPort(&sockaddress[numsockets++], LHNETADDRESSTYPE_INET6, port+1);
1295
1296                 sendsock = NULL;
1297                 sendmessage = NULL;
1298                 sendmessagelength = 0;
1299
1300                 for (i = 0;i < numsockets;i++)
1301                 {
1302                         LHNETADDRESS_ToString(&sockaddress[i], addressstring, sizeof(addressstring), 1);
1303                         printf("calling LHNET_OpenSocket_Connectionless(<%s>)\n", addressstring);
1304                         if ((sock[i] = LHNET_OpenSocket_Connectionless(&sockaddress[i])))
1305                         {
1306                                 LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1);
1307                                 printf("opened socket successfully (address \"%s\")\n", addressstring2);
1308                         }
1309                         else
1310                         {
1311                                 printf("failed to open socket\n");
1312                                 if (i == 0)
1313                                 {
1314                                         LHNET_Shutdown();
1315                                         return -1;
1316                                 }
1317                         }
1318                 }
1319                 count = 0;
1320                 if (argc == 5)
1321                 {
1322                         count = atoi(argv[2]);
1323                         if (LHNETADDRESS_FromString(&destaddress, argv[3], -1))
1324                         {
1325                                 sendmessage = argv[4];
1326                                 sendmessagelength = strlen(sendmessage);
1327                                 sendsock = NULL;
1328                                 for (i = 0;i < numsockets;i++)
1329                                         if (sock[i] && LHNETADDRESS_GetAddressType(&destaddress) == LHNETADDRESS_GetAddressType(&sockaddress[i]))
1330                                                 sendsock = sock[i];
1331                                 if (sendsock == NULL)
1332                                 {
1333                                         printf("Could not find an open socket matching the addresstype (%i) of destination address, switching to listen only mode\n", LHNETADDRESS_GetAddressType(&destaddress));
1334                                         argc = 2;
1335                                 }
1336                         }
1337                         else
1338                         {
1339                                 printf("LHNETADDRESS_FromString did not like the address \"%s\", switching to listen only mode\n", argv[3]);
1340                                 argc = 2;
1341                         }
1342                 }
1343                 printf("started, now listening for \"exit\" on the opened sockets\n");
1344                 oldtime = time(NULL);
1345                 for(;;)
1346                 {
1347 #ifdef WIN32
1348                         Sleep(1);
1349 #else
1350                         usleep(1);
1351 #endif
1352                         for (i = 0;i < numsockets;i++)
1353                         {
1354                                 if (sock[i])
1355                                 {
1356                                         length = LHNET_Read(sock[i], buffer, sizeof(buffer), &receiveaddress);
1357                                         if (length < 0)
1358                                                 printf("localsock read error: length < 0");
1359                                         else if (length > 0 && length < (int)sizeof(buffer))
1360                                         {
1361                                                 buffer[length] = 0;
1362                                                 LHNETADDRESS_ToString(&receiveaddress, addressstring, sizeof(addressstring), 1);
1363                                                 LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1);
1364                                                 printf("received message \"%s\" from \"%s\" on socket \"%s\"\n", buffer, addressstring, addressstring2);
1365                                                 if (!strcmp(buffer, "exit"))
1366                                                         break;
1367                                         }
1368                                 }
1369                         }
1370                         if (i < numsockets)
1371                                 break;
1372                         if (argc == 5 && count > 0)
1373                         {
1374                                 newtime = time(NULL);
1375                                 if (newtime != oldtime)
1376                                 {
1377                                         LHNETADDRESS_ToString(&destaddress, addressstring, sizeof(addressstring), 1);
1378                                         LHNETADDRESS_ToString(LHNET_AddressFromSocket(sendsock), addressstring2, sizeof(addressstring2), 1);
1379                                         printf("calling LHNET_Write(<%s>, \"%s\", %i, <%s>)\n", addressstring2, sendmessage, sendmessagelength, addressstring);
1380                                         length = LHNET_Write(sendsock, sendmessage, sendmessagelength, &destaddress);
1381                                         if (length == sendmessagelength)
1382                                                 printf("sent successfully\n");
1383                                         else
1384                                                 printf("LH_Write failed, returned %i (length of message was %i)\n", length, strlen(argv[4]));
1385                                         oldtime = newtime;
1386                                         count--;
1387                                         if (count <= 0)
1388                                                 printf("Done sending, still listening for \"exit\"\n");
1389                                 }
1390                         }
1391                 }
1392                 for (i = 0;i < numsockets;i++)
1393                 {
1394                         if (sock[i])
1395                         {
1396                                 LHNETADDRESS_ToString(LHNET_AddressFromSocket(sock[i]), addressstring2, sizeof(addressstring2), 1);
1397                                 printf("calling LHNET_CloseSocket(<%s>)\n", addressstring2);
1398                                 LHNET_CloseSocket(sock[i]);
1399                         }
1400                 }
1401                 printf("calling LHNET_Shutdown()\n");
1402                 LHNET_Shutdown();
1403                 return 0;
1404         }
1405         printf("Testing code for lhnet.c\nusage: lhnettest <localportnumber> [<sendnumberoftimes> <sendaddress:port> <sendmessage>]\n");
1406         return -1;
1407 #endif
1408 }
1409 #endif
1410