Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -46,10 +46,11 @@ #import "OFInvalidArgumentException.h" #import "OFListenFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFOutOfMemoryException.h" +#import "OFOutOfRangeException.h" #import "OFSetOptionFailedException.h" #import "socket.h" #import "socket_helpers.h" #import "resolver.h" @@ -599,21 +600,26 @@ } #endif - (OFString *)remoteAddress { - OFString *ret; + of_socket_address_t address; if (_socket == INVALID_SOCKET) @throw [OFNotOpenException exceptionWithObject: self]; if (_address == NULL) @throw [OFInvalidArgumentException exception]; - of_address_to_string_and_port(_address, _addressLength, &ret, NULL); + if (_addressLength > sizeof(address.address)) + @throw [OFOutOfRangeException exception]; + + memset(&address, '\0', sizeof(address)); + memcpy(&address.address, _address, _addressLength); + address.length = _addressLength; - return ret; + return of_socket_address_ip_string(&address, NULL); } - (bool)isListening { return _listening; Index: src/OFUDPSocket.h ================================================================== --- src/OFUDPSocket.h +++ src/OFUDPSocket.h @@ -83,12 +83,12 @@ * * @brief A class which provides methods to create and use UDP sockets. * * Addresses are of type @ref of_socket_address_t. You can use * @ref resolveAddressForHost:port:address: to create an address for a host / - * port pair and @ref getHost:andPort:forAddress: to get the host / port pair - * for an address. If you want to compare two addresses, you can use + * port pair and @ref of_socket_address_ip_string to get the IP string / port + * pair for an address. If you want to compare two addresses, you can use * @ref of_socket_address_equal and you can use @ref of_socket_address_hash to * get a hash to use in e.g. @ref OFMapTable. * * @warning Even though the OFCopying protocol is implemented, it does *not* * return an independent copy of the socket, but instead retains it. @@ -159,23 +159,10 @@ port: (uint16_t)port block: (of_udp_socket_async_resolve_block_t)block; # endif #endif -/*! - * @brief Gets the host and port for the specified address. - * - * @param host A pointer to an @ref OFString *. If it is not NULL, it will be - * set to the host of the host / port pair. - * @param port A pointer to an uint16_t. If it is not NULL, the port of the - * host / port pair will be written to it. - * @param address The address for which the host and port should be retrieved - */ -+ (void)getHost: (OFString *__autoreleasing _Nonnull *_Nullable)host - andPort: (nullable uint16_t *)port - forAddress: (of_socket_address_t *)address; - /*! * @brief Binds the socket to the specified host and port. * * @param host The host to bind to. Use `@"0.0.0.0"` for IPv4 or `@"::"` for * IPv6 to bind to all. Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -250,18 +250,10 @@ objc_autoreleasePoolPop(pool); } # endif #endif -+ (void)getHost: (OFString *__autoreleasing *)host - andPort: (uint16_t *)port - forAddress: (of_socket_address_t *)address -{ - of_address_to_string_and_port( - (struct sockaddr *)&address->address, address->length, host, port); -} - - (instancetype)init { self = [super init]; _socket = INVALID_SOCKET; Index: src/resolver.h ================================================================== --- src/resolver.h +++ src/resolver.h @@ -51,25 +51,10 @@ * freed after use. */ extern of_resolver_result_t *_Nullable *_Nonnull of_resolve_host(OFString *host, uint16_t port, int protocol); -/*! - * @brief Converts the specified address to a string and port pair. - * - * @param address The address to convert to a string - * @param addressLength The length of the address to convert to a string - * @param host A pointer to an @ref OFString * which should be set to the host - * of the address or NULL if the host is not needed - * @param port A pointer to an uint16_t which should be set to the port of the - * address or NULL if the port is not needed - */ -extern void of_address_to_string_and_port(struct sockaddr *address, - socklen_t addressLength, - OFString *__autoreleasing _Nonnull *_Nullable host, - uint16_t *_Nullable port); - /*! * @brief Frees the results returned by @ref of_resolve_host. * * @param results The results returned by @ref of_resolve_host */ Index: src/resolver.m ================================================================== --- src/resolver.m +++ src/resolver.m @@ -252,88 +252,10 @@ #endif return ret; } -void -of_address_to_string_and_port(struct sockaddr *address, socklen_t addressLength, - OFString *__autoreleasing *host, uint16_t *port) -{ -#ifdef HAVE_GETADDRINFO - char hostCString[NI_MAXHOST]; - char portCString[NI_MAXSERV]; - -# if !defined(HAVE_THREADSAFE_GETADDRINFO) && defined(OF_HAVE_THREADS) - if (!of_mutex_lock(&mutex)) - @throw [OFLockFailedException exception]; - - @try { -# endif - int error; - - /* FIXME: Add NI_DGRAM for UDP? */ - if ((error = getnameinfo(address, addressLength, hostCString, - NI_MAXHOST, portCString, NI_MAXSERV, - NI_NUMERICHOST | NI_NUMERICSERV)) != 0) - @throw [OFAddressTranslationFailedException - exceptionWithError: error]; - - if (host != NULL) - *host = [OFString stringWithUTF8String: hostCString]; - - if (port != NULL) { - char *endptr; - long tmp; - - if ((tmp = strtol(portCString, &endptr, 10)) > - UINT16_MAX) - @throw [OFOutOfRangeException exception]; - - if (endptr != NULL && *endptr != '\0') - @throw [OFAddressTranslationFailedException - exception]; - - *port = (uint16_t)tmp; - } -# if !defined(HAVE_THREADSAFE_GETADDRINFO) && defined(OF_HAVE_THREADS) - } @finally { - if (!of_mutex_unlock(&mutex)) - @throw [OFUnlockFailedException exception]; - } -# endif -#else - char *hostCString; - - if (address->sa_family != AF_INET) - @throw [OFInvalidArgumentException exception]; - -# if OF_HAVE_THREADS - if (!of_mutex_lock(&mutex)) - @throw [OFLockFailedException exception]; - - @try { -# endif - if ((hostCString = inet_ntoa( - ((struct sockaddr_in *)(void *)address)->sin_addr)) == NULL) - @throw [OFAddressTranslationFailedException - exceptionWithError: h_errno]; - - if (host != NULL) - *host = [OFString stringWithUTF8String: hostCString]; - - if (port != NULL) - *port = OF_BSWAP16_IF_LE( - ((struct sockaddr_in *)(void *)address)->sin_port); -# if OF_HAVE_THREADS - } @finally { - if (!of_mutex_unlock(&mutex)) - @throw [OFUnlockFailedException exception]; - } -# endif -#endif -} - void of_resolver_free(of_resolver_result_t **results) { #ifdef HAVE_GETADDRINFO freeaddrinfo(results[0]->private_); Index: src/socket.h ================================================================== --- src/socket.h +++ src/socket.h @@ -149,10 +149,21 @@ * * @param address The address to hash * @return The hash for the specified of_socket_address_t */ extern uint32_t of_socket_address_hash(of_socket_address_t *address); + +/*! + * @brief Converts the specified of_socket_address_t to an IP string and port. + * + * @param address The address to convert to a string + * @param port A pointer to an uint16_t which should be set to the port of the + * address or NULL if the port is not needed + * @return The address as an IP string + */ +extern OFString *_Nonnull of_socket_address_ip_string( + const of_socket_address_t *_Nonnull address, uint16_t *_Nullable port); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -220,10 +220,70 @@ # endif return ret; } #endif + +static of_socket_address_t +parseIPv4(OFString *IPv4, uint16_t port) +{ + void *pool = objc_autoreleasePoolPush(); + of_socket_address_t ret; + struct sockaddr_in *sin = (struct sockaddr_in *)&ret.address; + + memset(&ret, '\0', sizeof(ret)); + ret.length = sizeof(struct sockaddr_in); + + sin->sin_family = AF_INET; + sin->sin_port = OF_BSWAP16_IF_LE(port); + + if (inet_pton(AF_INET, [IPv4 cStringWithEncoding: [OFLocale encoding]], + &sin->sin_addr) != 1) + @throw [OFInvalidFormatException exception]; + + objc_autoreleasePoolPop(pool); + + return ret; +} + +#ifdef HAVE_IPV6 +static of_socket_address_t +parseIPv6(OFString *IPv6, uint16_t port) +{ + void *pool = objc_autoreleasePoolPush(); + of_socket_address_t ret; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ret.address; + + memset(&ret, '\0', sizeof(ret)); + ret.length = sizeof(struct sockaddr_in6); + + sin6->sin6_family = AF_INET6; + sin6->sin6_port = OF_BSWAP16_IF_LE(port); + + if (inet_pton(AF_INET6, [IPv6 cStringWithEncoding: [OFLocale encoding]], + &sin6->sin_addr6) != 1) + @throw [OFInvalidFormatException exception]; + + objc_autoreleasePoolPop(pool); + + return ret; +} +#endif + +of_socket_address_t +of_socket_address_parse_ip(OFString *IP, uint16_t port) +{ +#ifdef HAVE_IPV6 + @try { + return parseIPv6(IP, port); + } @catch (OFInvalidFormatException *e) { +#endif + return parseIPv4(IP, port); +#ifdef HAVE_IPV6 + } +#endif +} bool of_socket_address_equal(of_socket_address_t *address1, of_socket_address_t *address2) { @@ -333,64 +393,56 @@ } return hash; } -static of_socket_address_t -parseIPv4(OFString *IPv4, uint16_t port) -{ - void *pool = objc_autoreleasePoolPush(); - of_socket_address_t ret; - struct sockaddr_in *sin = (struct sockaddr_in *)&ret.address; - - memset(&ret, '\0', sizeof(ret)); - ret.length = sizeof(struct sockaddr_in); - - sin->sin_family = AF_INET; - sin->sin_port = OF_BSWAP16_IF_LE(port); - - if (inet_pton(AF_INET, [IPv4 cStringWithEncoding: [OFLocale encoding]], - &sin->sin_addr) != 1) - @throw [OFInvalidFormatException exception]; - - objc_autoreleasePoolPop(pool); - - return ret; -} - -#ifdef HAVE_IPV6 -static of_socket_address_t -parseIPv6(OFString *IPv6, uint16_t port) -{ - void *pool = objc_autoreleasePoolPush(); - of_socket_address_t ret; - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ret.address; - - memset(&ret, '\0', sizeof(ret)); - ret.length = sizeof(struct sockaddr_in6); - - sin6->sin6_family = AF_INET6; - sin6->sin6_port = OF_BSWAP16_IF_LE(port); - - if (inet_pton(AF_INET6, [IPv6 cStringWithEncoding: [OFLocale encoding]], - &sin6->sin_addr6) != 1) - @throw [OFInvalidFormatException exception]; - - objc_autoreleasePoolPop(pool); - - return ret; -} -#endif - -of_socket_address_t -of_socket_address_parse_ip(OFString *IP, uint16_t port) -{ -#ifdef HAVE_IPV6 - @try { - return parseIPv6(IP, port); - } @catch (OFInvalidFormatException *e) { -#endif - return parseIPv4(IP, port); -#ifdef HAVE_IPV6 - } -#endif +static OFString * +IPv4String(const of_socket_address_t *address, uint16_t *port) +{ + const struct sockaddr_in *sin = + (const struct sockaddr_in *)&address->address; + char buffer[INET_ADDRSTRLEN]; + + if (inet_ntop(AF_INET, &sin->sin_addr, buffer, sizeof(buffer)) == NULL) + @throw [OFInvalidArgumentException exception]; + + if (port != NULL) + *port = OF_BSWAP16_IF_LE(sin->sin_port); + + return [OFString stringWithCString: buffer + encoding: [OFLocale encoding]]; +} + +#ifdef HAVE_IPV6 +static OFString * +IPv6String(const of_socket_address_t *address, uint16_t *port) +{ + const struct sockaddr_in6 *sin6 = + (const struct sockaddr_in6 *)&address->address; + char buffer[INET6_ADDRSTRLEN]; + + if (inet_ntop(AF_INET, &sin6->sin_addr6, buffer, sizeof(buffer)) == + NULL) + @throw [OFInvalidArgumentException exception]; + + if (port != NULL) + *port = OF_BSWAP16_IF_LE(sin6->sin_port); + + return [OFString stringWithCString: buffer + encoding: [OFLocale encoding]]; +} +#endif + +OFString * +of_socket_address_ip_string(const of_socket_address_t *address, uint16_t *port) +{ + switch (address->address.ss_family) { + case AF_INET: + return IPv4String(address, port); +#ifdef HAVE_IPV6 + case AF_INET6: + return IPv6String(address, port); +#endif + default: + @throw [OFInvalidArgumentException exception]; + } } Index: tests/OFUDPSocketTests.m ================================================================== --- tests/OFUDPSocketTests.m +++ tests/OFUDPSocketTests.m @@ -55,16 +55,12 @@ TEST(@"-[receiveIntoBuffer:length:sender:]", [sock receiveIntoBuffer: buf length: 6 sender: &addr2] == 6 && - !memcmp(buf, "Hello", 6)) - - TEST(@"+[getHost:andPort:forAddress:]", - R([OFUDPSocket getHost: &host - andPort: &port2 - forAddress: &addr2]) && + !memcmp(buf, "Hello", 6) && + (host = of_socket_address_ip_string(&addr2, &port2)) && [host isEqual: @"127.0.0.1"] && port2 == port1) [OFUDPSocket resolveAddressForHost: @"127.0.0.1" port: port1 + 1 address: &addr3];