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