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