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