@@ -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