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