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