Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -86,39 +86,58 @@ ;; esac AC_CHECK_LIB(ws2_32, main, LIBS="$LIBS -lws2_32") +AC_MSG_CHECKING(for getaddrinfo) +AC_TRY_COMPILE([ + #include + #ifndef _WIN32 + #include + #include + #include + #else + #define _WIN32_WINNT 0x0501 + #include + #endif], [ + struct addrinfo ai; + getaddrinfo(NULL, NULL, NULL, NULL); + ], [have_getaddrinfo="yes"], [have_getaddrinfo="no"]) +AC_MSG_RESULT($have_getaddrinfo) +test x"$have_getaddrinfo" = x"yes" && \ + AC_DEFINE(HAVE_GETADDRINFO, 1, [Whether we have getaddrinfo]) + AC_MSG_CHECKING(whether we have IPv6 support) -AC_CACHE_VAL(ac_cv_have_ipv6, [ - AC_TRY_RUN([ - #ifndef _WIN32 - #include - #include - #include - #else - #include - #include - #endif - - #ifndef INVALID_SOCKET - #define INVALID_SOCKET -1 - #endif - - int - main() - { - int fd; - struct sockaddr_in6 addr; - - fd = socket(AF_INET6, SOCK_STREAM, 0); - - exit(fd != INVALID_SOCKET ? 0 : 1); - }], - ac_cv_have_ipv6="yes", - ac_cv_have_ipv6="no", - ac_cv_have_ipv6="no")]) +AS_IF([test x"$have_getaddrinfo" = x"yes"], [ + AC_CACHE_VAL(ac_cv_have_ipv6, [ + AC_TRY_RUN([ + #ifndef _WIN32 + #include + #include + #include + #else + #include + #include + #endif + + #ifndef INVALID_SOCKET + #define INVALID_SOCKET -1 + #endif + + int + main() + { + int fd; + struct sockaddr_in6 addr; + + fd = socket(AF_INET6, SOCK_STREAM, 0); + + exit(fd != INVALID_SOCKET ? 0 : 1); + }], + ac_cv_have_ipv6="yes", + ac_cv_have_ipv6="no", + ac_cv_have_ipv6="no")])], [ac_cv_have_ipv6="no"]) AC_MSG_RESULT($ac_cv_have_ipv6) test x"$ac_cv_have_ipv6" = x"yes" && \ AC_DEFINE(HAVE_IPV6, 1, "Whether we have IPv6 support") AC_CHECK_FUNC(madvise, [AC_DEFINE(HAVE_MADVISE, 1, [Whether we have madvise])]) Index: src/OFExceptions.m ================================================================== --- src/OFExceptions.m +++ src/OFExceptions.m @@ -28,19 +28,31 @@ #import "OFTCPSocket.h" #ifndef _WIN32 #include #define GET_ERR errno +#ifndef HAVE_GETADDRINFO +#define GET_AT_ERR h_errno +#else +#define GET_AT_ERR errno +#endif #define GET_SOCK_ERR errno #define ERRFMT "Error string was: %s" #define ERRPARAM strerror(err) +#ifndef HAVE_GETADDRINFO +#define AT_ERRPARAM hstrerror(err) +#else +#define AT_ERRPARAM strerror(err) +#endif #else #include #define GET_ERR GetLastError() +#define GET_AT_ERR WSAGetLastError() #define GET_SOCK_ERR WSAGetLastError() #define ERRFMT "Error code was: %d" #define ERRPARAM err +#define AT_ERRPARAM err #endif #ifndef HAVE_ASPRINTF #import "asprintf.h" #endif @@ -523,11 +535,11 @@ { self = [super initWithClass: class_]; node = [node_ retain]; service = [service_ retain]; - err = GET_SOCK_ERR; + err = GET_AT_ERR; return self; } - (void)dealloc @@ -550,11 +562,11 @@ @"on the node, there was a problem with the name " @"server, there was a problem with your network " @"connection or you specified an invalid node or " @"service. " ERRFMT, [service cString], [node cString], [class name], - ERRPARAM]; + AT_ERRPARAM]; return string; } - (int)errNo Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -12,19 +12,38 @@ #include "config.h" #include #include #include + +#ifndef HAVE_GETADDRINFO +#include +#include +#endif #import "OFTCPSocket.h" #import "OFExceptions.h" #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif + +#ifndef HAVE_GETADDRINFO +#import "OFThread.h" + +static OFObject *lock = nil; +#endif @implementation OFTCPSocket +#ifndef HAVE_GETADDRINFO ++ (void)initialize +{ + if (self == [OFTCPSocket class]) + lock = [[OFObject alloc] init]; +} +#endif + + socket { return [[[OFTCPSocket alloc] init] autorelease]; } @@ -47,15 +66,16 @@ } - connectToService: (OFString*)service onNode: (OFString*)node { - struct addrinfo hints, *res, *res0; - if (sock != INVALID_SOCKET) @throw [OFAlreadyConnectedException newWithClass: isa]; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *res, *res0; + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo([node cString], [service cString], &hints, &res0)) @@ -77,10 +97,62 @@ break; } freeaddrinfo(res0); +#else + BOOL connected = NO; + struct hostent *he; + struct servent *se; + struct sockaddr_in addr; + uint16_t port; + char **ip; + + @synchronized (lock) { + if ((he = gethostbyname([node cString])) == NULL) + @throw [OFAddressTranslationFailedException + newWithClass: isa + andNode: node + andService: service]; + + if ((se = getservbyname([service cString], "TCP")) != NULL) + port = se->s_port; + else if ((port = htons(atoi([service cString]))) == 0) + @throw [OFAddressTranslationFailedException + newWithClass: isa + andNode: node + andService: service]; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = port; + + if (he->h_addrtype != AF_INET || + (sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) + @throw [OFConnectionFailedException + newWithClass: isa + andNode: node + andService: service]; + + for (ip = he->h_addr_list; *ip != NULL; ip++) { + memcpy(&addr.sin_addr.s_addr, *ip, he->h_length); + + if (connect(sock, (struct sockaddr*)&addr, + sizeof(addr)) == -1) + continue; + + connected = YES; + + break; + } + + if (!connected) { + close(sock); + sock = INVALID_SOCKET; + } + } +#endif if (sock == INVALID_SOCKET) @throw [OFConnectionFailedException newWithClass: isa andNode: node andService: service]; @@ -90,21 +162,22 @@ - bindService: (OFString*)service onNode: (OFString*)node withFamily: (int)family { - struct addrinfo hints, *res; - if (sock != INVALID_SOCKET) @throw [OFAlreadyConnectedException newWithClass: isa]; if ((sock = socket(family, SOCK_STREAM, 0)) == INVALID_SOCKET) @throw [OFBindFailedException newWithClass: isa andNode: node andService: service andFamily: family]; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *res; + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo([node cString], [service cString], &hints, &res)) @@ -120,10 +193,56 @@ andService: service andFamily: family]; } freeaddrinfo(res); +#else + struct hostent *he; + struct servent *se; + struct sockaddr_in addr; + uint16_t port; + + if (family != AF_INET) + @throw [OFBindFailedException newWithClass: isa + andNode: node + andService: service + andFamily: family]; + + @synchronized (lock) { + if ((he = gethostbyname([node cString])) == NULL) + @throw [OFAddressTranslationFailedException + newWithClass: isa + andNode: node + andService: service]; + + if ((se = getservbyname([service cString], "TCP")) != NULL) + port = se->s_port; + else if ((port = htons(atoi([service cString]))) == 0) + @throw [OFAddressTranslationFailedException + newWithClass: isa + andNode: node + andService: service]; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = port; + + if (he->h_addrtype != AF_INET || he->h_addr_list[0] == NULL) + @throw [OFAddressTranslationFailedException + newWithClass: isa + andNode: node + andService: service]; + + memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length); + + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) + @throw [OFBindFailedException newWithClass: isa + andNode: node + andService: service + andFamily: family]; + } +#endif return self; } - listenWithBackLog: (int)backlog