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