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