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