X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=lhnet.c;h=0b68712c739ba0e8d9c1ffeda4ec39e9dd380f11;hp=9026aca22d1af0799dcc86da5b48aa87f630ac44;hb=a482cfb7d5b84ffa1bd66759ee528a108793718a;hpb=3601d63f7b0038c6e2009ecf0857ad9d1a8d5252 diff --git a/lhnet.c b/lhnet.c index 9026aca2..0b68712c 100644 --- a/lhnet.c +++ b/lhnet.c @@ -1,6 +1,21 @@ // Written by Forest Hale 2003-06-15 and placed into public domain. +#ifdef WIN32 +#ifdef _MSC_VER +#pragma comment(lib, "ws2_32.lib") +#endif +# ifdef SUPPORTIPV6 +// Windows XP or higher is required for getaddrinfo, but the inclusion of wspiapi provides fallbacks for older versions +# define _WIN32_WINNT 0x0501 +# endif +# include +# include +# ifdef USE_WSPIAPI_H +# include +# endif +#endif + #ifndef STANDALONETEST #include "quakedef.h" #endif @@ -9,10 +24,7 @@ #include #include #include -#ifdef WIN32 -#include -#include -#else +#ifndef WIN32 #include #include #include @@ -21,8 +33,10 @@ #include #include #include +#ifdef SUPPORTIPV6 #include #endif +#endif #ifdef __MORPHOS__ #include @@ -67,6 +81,14 @@ #define SOCKLEN_T socklen_t #endif +#ifdef MSG_DONTWAIT +#define LHNET_RECVFROM_FLAGS MSG_DONTWAIT +#define LHNET_SENDTO_FLAGS 0 +#else +#define LHNET_RECVFROM_FLAGS 0 +#define LHNET_SENDTO_FLAGS 0 +#endif + typedef struct lhnetaddressnative_s { lhnetaddresstype_t addresstype; @@ -75,7 +97,9 @@ typedef struct lhnetaddressnative_s { struct sockaddr sock; struct sockaddr_in in; +#ifdef SUPPORTIPV6 struct sockaddr_in6 in6; +#endif } addr; } @@ -100,7 +124,7 @@ int LHNETADDRESS_FromPort(lhnetaddress_t *vaddress, lhnetaddresstype_t addressty switch(addresstype) { default: - return 0; + break; case LHNETADDRESSTYPE_LOOP: // local:port (loopback) memset(address, 0, sizeof(*address)); @@ -115,6 +139,7 @@ int LHNETADDRESS_FromPort(lhnetaddress_t *vaddress, lhnetaddresstype_t addressty address->addr.in.sin_family = AF_INET; address->addr.in.sin_port = htons((unsigned short)port); return 1; +#ifdef SUPPORTIPV6 case LHNETADDRESSTYPE_INET6: // [0:0:0:0:0:0:0:0]:port (IN6ADDR_ANY, binds to all interfaces) memset(address, 0, sizeof(*address)); @@ -123,10 +148,12 @@ int LHNETADDRESS_FromPort(lhnetaddress_t *vaddress, lhnetaddresstype_t addressty address->addr.in6.sin6_family = AF_INET6; address->addr.in6.sin6_port = htons((unsigned short)port); return 1; +#endif } return 0; } +#ifdef SUPPORTIPV6 int LHNETADDRESS_Resolve(lhnetaddressnative_t *address, const char *name, int port) { char port_buff [16]; @@ -146,7 +173,10 @@ int LHNETADDRESS_Resolve(lhnetaddressnative_t *address, const char *name, int po if (err != 0 || addrinf == NULL) return 0; if (addrinf->ai_addr->sa_family != AF_INET6 && addrinf->ai_addr->sa_family != AF_INET) + { + freeaddrinfo (addrinf); return 0; + } // great it worked if (addrinf->ai_addr->sa_family == AF_INET6) @@ -341,6 +371,165 @@ int LHNETADDRESS_FromString(lhnetaddress_t *vaddress, const char *string, int de namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; return resolved; } +#else +int LHNETADDRESS_FromString(lhnetaddress_t *vaddress, const char *string, int defaultport) +{ + lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; + int i, port, namelen, d1, d2, d3, d4; + struct hostent *hostentry; + unsigned char *a; + const char *colon; + char name[128]; +#ifdef STANDALONETEST + char string2[128]; +#endif + if (!address || !string || !*string) + return 0; + memset(address, 0, sizeof(*address)); + address->addresstype = LHNETADDRESSTYPE_NONE; + port = 0; + colon = strrchr(string, ':'); + if (colon && (colon == strchr(string, ':') || (string[0] == '[' && colon - string > 0 && colon[-1] == ']'))) + // EITHER: colon is the ONLY colon OR: colon comes after [...] delimited IPv6 address + // fixes misparsing of IPv6 addresses without port + { + port = atoi(colon + 1); + } + else + colon = string + strlen(string); + if (port == 0) + port = defaultport; + namelen = colon - string; + if (namelen > 127) + namelen = 127; + if (string[0] == '[' && namelen > 0 && string[namelen-1] == ']') // ipv6 + { + string++; + namelen -= 2; + } + memcpy(name, string, namelen); + name[namelen] = 0; + // handle loopback + if (!strcmp(name, "local")) + { + address->addresstype = LHNETADDRESSTYPE_LOOP; + address->port = port; + return 1; + } + // try to parse as dotted decimal ipv4 address first + // note this supports partial ip addresses + d1 = d2 = d3 = d4 = 0; +#if _MSC_VER >= 1400 +#define sscanf sscanf_s +#endif + 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) + { + // parsed a valid ipv4 address + address->addresstype = LHNETADDRESSTYPE_INET4; + address->port = port; + address->addr.in.sin_family = AF_INET; + address->addr.in.sin_port = htons((unsigned short)port); + a = (unsigned char *)&address->addr.in.sin_addr; + a[0] = d1; + a[1] = d2; + a[2] = d3; + a[3] = d4; +#ifdef STANDALONETEST + LHNETADDRESS_ToString(address, string2, sizeof(string2), 1); + printf("manual parsing of ipv4 dotted decimal address \"%s\" successful: %s\n", string, string2); +#endif + return 1; + } + for (i = 0;i < MAX_NAMECACHE;i++) + if (!strcmp(namecache[i].name, name)) + break; +#ifdef STANDALONETEST + if (i < MAX_NAMECACHE) +#else + if (i < MAX_NAMECACHE && realtime < namecache[i].expirationtime) +#endif + { + *address = namecache[i].address; + address->port = port; + if (address->addresstype == LHNETADDRESSTYPE_INET6) + { +#ifdef SUPPORTIPV6 + address->addr.in6.sin6_port = htons((unsigned short)port); + return 1; +#endif + } + else if (address->addresstype == LHNETADDRESSTYPE_INET4) + { + address->addr.in.sin_port = htons((unsigned short)port); + return 1; + } + return 0; + } + // try gethostbyname (handles dns and other ip formats) + hostentry = gethostbyname(name); + if (hostentry) + { + if (hostentry->h_addrtype == AF_INET6) + { +#ifdef SUPPORTIPV6 + // great it worked + address->addresstype = LHNETADDRESSTYPE_INET6; + address->port = port; + address->addr.in6.sin6_family = hostentry->h_addrtype; + address->addr.in6.sin6_port = htons((unsigned short)port); + memcpy(&address->addr.in6.sin6_addr, hostentry->h_addr_list[0], sizeof(address->addr.in6.sin6_addr)); + for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++) + namecache[namecacheposition].name[i] = name[i]; + namecache[namecacheposition].name[i] = 0; +#ifndef STANDALONETEST + namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours +#endif + namecache[namecacheposition].address = *address; + namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; +#ifdef STANDALONETEST + LHNETADDRESS_ToString(address, string2, sizeof(string2), 1); + printf("gethostbyname(\"%s\") returned ipv6 address %s\n", string, string2); +#endif + return 1; +#endif + } + else if (hostentry->h_addrtype == AF_INET) + { + // great it worked + address->addresstype = LHNETADDRESSTYPE_INET4; + address->port = port; + address->addr.in.sin_family = hostentry->h_addrtype; + address->addr.in.sin_port = htons((unsigned short)port); + memcpy(&address->addr.in.sin_addr, hostentry->h_addr_list[0], sizeof(address->addr.in.sin_addr)); + for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++) + namecache[namecacheposition].name[i] = name[i]; + namecache[namecacheposition].name[i] = 0; +#ifndef STANDALONETEST + namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours +#endif + namecache[namecacheposition].address = *address; + namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; +#ifdef STANDALONETEST + LHNETADDRESS_ToString(address, string2, sizeof(string2), 1); + printf("gethostbyname(\"%s\") returned ipv4 address %s\n", string, string2); +#endif + return 1; + } + } +#ifdef STANDALONETEST + printf("gethostbyname failed on address \"%s\"\n", name); +#endif + for (i = 0;i < (int)sizeof(namecache[namecacheposition].name)-1 && name[i];i++) + namecache[namecacheposition].name[i] = name[i]; + namecache[namecacheposition].name[i] = 0; +#ifndef STANDALONETEST + namecache[namecacheposition].expirationtime = realtime + 12 * 3600; // 12 hours +#endif + namecache[namecacheposition].address.addresstype = LHNETADDRESSTYPE_NONE; + namecacheposition = (namecacheposition + 1) % MAX_NAMECACHE; + return 0; +} +#endif int LHNETADDRESS_ToString(const lhnetaddress_t *vaddress, char *string, int stringbuffersize, int includeport) { @@ -390,6 +579,7 @@ int LHNETADDRESS_ToString(const lhnetaddress_t *vaddress, char *string, int stri } } break; +#ifdef SUPPORTIPV6 case LHNETADDRESSTYPE_INET6: a = (const unsigned char *)(&address->addr.in6.sin6_addr); if (includeport) @@ -409,6 +599,7 @@ int LHNETADDRESS_ToString(const lhnetaddress_t *vaddress, char *string, int stri } } break; +#endif } return 0; } @@ -423,6 +614,7 @@ int LHNETADDRESS_GetAddressType(const lhnetaddress_t *address) const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress) { +#ifdef SUPPORTIPV6 lhnetaddressnative_t *address = (lhnetaddressnative_t *)vaddress; if (address && address->addresstype == LHNETADDRESSTYPE_INET6) @@ -446,6 +638,7 @@ const char *LHNETADDRESS_GetInterfaceName(const lhnetaddress_t *vaddress) #endif } +#endif return NULL; } @@ -470,9 +663,11 @@ int LHNETADDRESS_SetPort(lhnetaddress_t *vaddress, int port) case LHNETADDRESSTYPE_INET4: address->addr.in.sin_port = htons((unsigned short)port); return 1; +#ifdef SUPPORTIPV6 case LHNETADDRESSTYPE_INET6: address->addr.in6.sin6_port = htons((unsigned short)port); return 1; +#endif default: return 0; } @@ -500,6 +695,7 @@ int LHNETADDRESS_Compare(const lhnetaddress_t *vaddress1, const lhnetaddress_t * if (address1->port != address2->port) return -1; return 0; +#ifdef SUPPORTIPV6 case LHNETADDRESSTYPE_INET6: if (address1->addr.in6.sin6_family != address2->addr.in6.sin6_family) return 1; @@ -508,6 +704,7 @@ int LHNETADDRESS_Compare(const lhnetaddress_t *vaddress1, const lhnetaddress_t * if (address1->port != address2->port) return -1; return 0; +#endif default: return 1; } @@ -633,6 +830,7 @@ static const char *LHNETPRIVATE_StrError(void) void LHNET_SleepUntilPacket_Microseconds(int microseconds) { +#ifdef FD_SET fd_set fdreadset; struct timeval tv; int lastfd; @@ -645,12 +843,19 @@ void LHNET_SleepUntilPacket_Microseconds(int microseconds) { if (lastfd < s->inetsocket) lastfd = s->inetsocket; +#if defined(WIN32) && !defined(_MSC_VER) + FD_SET((int)s->inetsocket, &fdreadset); +#else FD_SET((unsigned int)s->inetsocket, &fdreadset); +#endif } } tv.tv_sec = microseconds / 1000000; tv.tv_usec = microseconds % 1000000; select(lastfd + 1, &fdreadset, NULL, NULL, &tv); +#else + Sys_Sleep(microseconds); +#endif } lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) @@ -698,20 +903,32 @@ lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) } break; case LHNETADDRESSTYPE_INET4: +#ifdef SUPPORTIPV6 case LHNETADDRESSTYPE_INET6: +#endif #ifdef WIN32 if (lhnet_didWSAStartup) { #endif +#ifdef SUPPORTIPV6 if ((lhnetsocket->inetsocket = socket(address->addresstype == LHNETADDRESSTYPE_INET6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) +#else + if ((lhnetsocket->inetsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1) +#endif { #ifdef WIN32 - u_long _true = 1; u_long _false = 0; +#endif +#ifdef MSG_DONTWAIT + if (1) +#else +#ifdef WIN32 + u_long _true = 1; #else char _true = 1; #endif if (ioctlsocket(lhnetsocket->inetsocket, FIONBIO, &_true) != -1) +#endif { #ifdef IPV6_V6ONLY // We need to set this flag to tell the OS that we only listen on IPv6. If we don't @@ -720,7 +937,7 @@ lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) int ipv6_only = 1; if (address->addresstype != LHNETADDRESSTYPE_INET6 || setsockopt (lhnetsocket->inetsocket, IPPROTO_IPV6, IPV6_V6ONLY, - (const void *)&ipv6_only, sizeof(ipv6_only)) == 0 + (const char *)&ipv6_only, sizeof(ipv6_only)) == 0 #ifdef WIN32 // The Win32 API only supports IPV6_V6ONLY since Windows Vista, but fortunately // the default value is what we want on Win32 anyway (IPV6_V6ONLY = true) @@ -732,6 +949,7 @@ lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) lhnetaddressnative_t *localaddress = (lhnetaddressnative_t *)&lhnetsocket->address; SOCKLEN_T namelen; int bindresult; +#ifdef SUPPORTIPV6 if (address->addresstype == LHNETADDRESSTYPE_INET6) { namelen = sizeof(localaddress->addr.in6); @@ -740,6 +958,7 @@ lhnetsocket_t *LHNET_OpenSocket_Connectionless(lhnetaddress_t *address) getsockname(lhnetsocket->inetsocket, &localaddress->addr.sock, &namelen); } else +#endif { namelen = sizeof(localaddress->addr.in); bindresult = bind(lhnetsocket->inetsocket, &localaddress->addr.sock, namelen); @@ -867,17 +1086,17 @@ int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, } else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4) { - unsigned int inetaddresslength; + SOCKLEN_T inetaddresslength; address->addresstype = LHNETADDRESSTYPE_NONE; inetaddresslength = sizeof(address->addr.in); - value = recvfrom(lhnetsocket->inetsocket, content, maxcontentlength, 0, &address->addr.sock, &inetaddresslength); + value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength); if (value > 0) { address->addresstype = LHNETADDRESSTYPE_INET4; address->port = ntohs(address->addr.in.sin_port); return value; } - else if (value == -1) + else if (value < 0) { int e = SOCKETERRNO; if (e == EWOULDBLOCK) @@ -891,12 +1110,13 @@ int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, Con_Printf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); } } +#ifdef SUPPORTIPV6 else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6) { - unsigned int inetaddresslength; + SOCKLEN_T inetaddresslength; address->addresstype = LHNETADDRESSTYPE_NONE; inetaddresslength = sizeof(address->addr.in6); - value = recvfrom(lhnetsocket->inetsocket, content, maxcontentlength, 0, &address->addr.sock, &inetaddresslength); + value = recvfrom(lhnetsocket->inetsocket, (char *)content, maxcontentlength, LHNET_RECVFROM_FLAGS, &address->addr.sock, &inetaddresslength); if (value > 0) { address->addresstype = LHNETADDRESSTYPE_INET6; @@ -917,6 +1137,7 @@ int LHNET_Read(lhnetsocket_t *lhnetsocket, void *content, int maxcontentlength, Con_Printf("LHNET_Read: recvfrom returned error: %s\n", LHNETPRIVATE_StrError()); } } +#endif return value; } @@ -949,7 +1170,7 @@ int LHNET_Write(lhnetsocket_t *lhnetsocket, const void *content, int contentleng } else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET4) { - value = sendto(lhnetsocket->inetsocket, content, contentlength, 0, (struct sockaddr *)&address->addr.in, sizeof(struct sockaddr_in)); + value = sendto(lhnetsocket->inetsocket, (char *)content, contentlength, LHNET_SENDTO_FLAGS, (struct sockaddr *)&address->addr.in, sizeof(struct sockaddr_in)); if (value == -1) { if (SOCKETERRNO == EWOULDBLOCK) @@ -957,9 +1178,10 @@ int LHNET_Write(lhnetsocket_t *lhnetsocket, const void *content, int contentleng Con_Printf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError()); } } +#ifdef SUPPORTIPV6 else if (lhnetsocket->address.addresstype == LHNETADDRESSTYPE_INET6) { - value = sendto(lhnetsocket->inetsocket, content, contentlength, 0, (struct sockaddr *)&address->addr.in6, sizeof(struct sockaddr_in6)); + value = sendto(lhnetsocket->inetsocket, (char *)content, contentlength, 0, (struct sockaddr *)&address->addr.in6, sizeof(struct sockaddr_in6)); if (value == -1) { if (SOCKETERRNO == EWOULDBLOCK) @@ -967,6 +1189,7 @@ int LHNET_Write(lhnetsocket_t *lhnetsocket, const void *content, int contentleng Con_Printf("LHNET_Write: sendto returned error: %s\n", LHNETPRIVATE_StrError()); } } +#endif return value; }