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