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