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