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