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