Index: src/socket.h ================================================================== --- src/socket.h +++ src/socket.h @@ -125,10 +125,32 @@ * @return The parsed IP and port as an of_socket_address_t */ extern of_socket_address_t of_socket_address_parse_ip( OFString *IP, uint16_t port); +/*! + * @brief Parses the specified IPv4 and port into an of_socket_address_t. + * + * @param IP The IPv4 to parse + * @param port The port to use + * @return The parsed IPv4 and port as an of_socket_address_t + */ +extern of_socket_address_t of_socket_address_parse_ipv4( + OFString *IP, uint16_t port); + +#ifdef OF_HAVE_IPV6 +/*! + * @brief Parses the specified IPv6 and port into an of_socket_address_t. + * + * @param IP The IPv6 to parse + * @param port The port to use + * @return The parsed IPv6 and port as an of_socket_address_t + */ +extern of_socket_address_t of_socket_address_parse_ipv6( + OFString *IP, uint16_t port); +#endif + /*! * @brief Compares two of_socket_address_t for equality. * * @param address1 The address to compare with the second address * @param address2 The second address Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -21,11 +21,14 @@ # include /* For memalign() */ #endif #include +#import "OFArray.h" +#import "OFCharacterSet.h" #import "OFLocale.h" +#import "OFString.h" #import "OFException.h" /* For some E* -> WSAE* defines */ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFLockFailedException.h" @@ -221,49 +224,149 @@ return ret; } #endif -static of_socket_address_t -parseIPv4(OFString *IPv4, uint16_t port) +of_socket_address_t +of_socket_address_parse_ipv4(OFString *IPv4, uint16_t port) { + /* TODO: Support IPs that are not in the a.b.c.d format? */ + void *pool = objc_autoreleasePoolPush(); + OFCharacterSet *whitespaceCharacterSet = + [OFCharacterSet whitespaceCharacterSet]; of_socket_address_t ret; struct sockaddr_in *addrIn = (struct sockaddr_in *)&ret.address; + OFArray OF_GENERIC(OFString *) *components; + uint32_t addr; memset(&ret, '\0', sizeof(ret)); ret.length = sizeof(struct sockaddr_in); addrIn->sin_family = AF_INET; addrIn->sin_port = OF_BSWAP16_IF_LE(port); - if (inet_pton(AF_INET, [IPv4 cStringWithEncoding: [OFLocale encoding]], - &addrIn->sin_addr) != 1) + components = [IPv4 componentsSeparatedByString: @"."]; + + if ([components count] != 4) @throw [OFInvalidFormatException exception]; + addr = 0; + + for (OFString *component in components) { + intmax_t number; + + if ([component length] == 0) + @throw [OFInvalidFormatException exception]; + + if ([component indexOfCharacterFromSet: + whitespaceCharacterSet] != OF_NOT_FOUND) + @throw [OFInvalidFormatException exception]; + + number = [component decimalValue]; + + if (number < 0 || number > UINT8_MAX) + @throw [OFInvalidFormatException exception]; + + addr = (addr << 8) | (number & 0xFF); + } + + addrIn->sin_addr.s_addr = OF_BSWAP32_IF_LE(addr); + objc_autoreleasePoolPop(pool); return ret; } #ifdef OF_HAVE_IPV6 -static of_socket_address_t -parseIPv6(OFString *IPv6, uint16_t port) +static uint16_t +parseIPv6Component(OFString *component) +{ + uintmax_t number; + + if ([component indexOfCharacterFromSet: + [OFCharacterSet whitespaceCharacterSet]] != OF_NOT_FOUND) + @throw [OFInvalidFormatException exception]; + + number = [component hexadecimalValue]; + + if (number > UINT16_MAX) + @throw [OFInvalidFormatException exception]; + + return (uint16_t)number; +} + +of_socket_address_t +of_socket_address_parse_ipv6(OFString *IPv6, uint16_t port) { void *pool = objc_autoreleasePoolPush(); of_socket_address_t ret; struct sockaddr_in6 *addrIn6 = (struct sockaddr_in6 *)&ret.address; + size_t doubleColon; memset(&ret, '\0', sizeof(ret)); ret.length = sizeof(struct sockaddr_in6); addrIn6->sin6_family = AF_INET6; addrIn6->sin6_port = OF_BSWAP16_IF_LE(port); - if (inet_pton(AF_INET6, [IPv6 cStringWithEncoding: [OFLocale encoding]], - &addrIn6->sin6_addr) != 1) - @throw [OFInvalidFormatException exception]; + doubleColon = [IPv6 rangeOfString: @"::"].location; + + if (doubleColon != OF_NOT_FOUND) { + OFString *left = [IPv6 substringWithRange: + of_range(0, doubleColon)]; + OFString *right = [IPv6 substringWithRange: + of_range(doubleColon + 2, [IPv6 length] - doubleColon - 2)]; + OFArray OF_GENERIC(OFString *) *leftComponents; + OFArray OF_GENERIC(OFString *) *rightComponents; + size_t i; + + if ([right hasPrefix: @":"] || [right containsString: @"::"]) + @throw [OFInvalidFormatException exception]; + + leftComponents = [left componentsSeparatedByString: @":"]; + rightComponents = [right componentsSeparatedByString: @":"]; + + if ([leftComponents count] + [rightComponents count] > 7) + @throw [OFInvalidFormatException exception]; + + i = 0; + for (OFString *component in leftComponents) { + uint16_t number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[i++] = number >> 8; + addrIn6->sin6_addr.s6_addr[i++] = number; + } + + i = 16; + for (OFString *component in [rightComponents reversedArray]) { + uint16_t number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[--i] = number >> 8; + addrIn6->sin6_addr.s6_addr[--i] = number; + } + } else { + OFArray OF_GENERIC(OFString *) *components = + [IPv6 componentsSeparatedByString: @":"]; + size_t i; + + if ([components count] != 8) + @throw [OFInvalidFormatException exception]; + + i = 0; + for (OFString *component in components) { + uint16_t number; + + if ([component length] == 0) + @throw [OFInvalidFormatException exception]; + + number = parseIPv6Component(component); + + addrIn6->sin6_addr.s6_addr[i++] = number >> 8; + addrIn6->sin6_addr.s6_addr[i++] = number; + } + } objc_autoreleasePoolPop(pool); return ret; } @@ -272,14 +375,14 @@ of_socket_address_t of_socket_address_parse_ip(OFString *IP, uint16_t port) { #ifdef OF_HAVE_IPV6 @try { - return parseIPv6(IP, port); + return of_socket_address_parse_ipv6(IP, port); } @catch (OFInvalidFormatException *e) { #endif - return parseIPv4(IP, port); + return of_socket_address_parse_ipv4(IP, port); #ifdef OF_HAVE_IPV6 } #endif } @@ -398,40 +501,93 @@ static OFString * IPv4String(const of_socket_address_t *address, uint16_t *port) { const struct sockaddr_in *addrIn = (const struct sockaddr_in *)&address->address; - char buffer[INET_ADDRSTRLEN]; + uint32_t addr = OF_BSWAP32_IF_LE(addrIn->sin_addr.s_addr); + OFString *string; - if (inet_ntop(AF_INET, &addrIn->sin_addr, buffer, sizeof(buffer)) == - NULL) - @throw [OFInvalidArgumentException exception]; + string = [OFString stringWithFormat: @"%u.%u.%u.%u", + (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, + (addr & 0x0000FF00) >> 8, addr & 0x000000FF]; if (port != NULL) *port = OF_BSWAP16_IF_LE(addrIn->sin_port); - return [OFString stringWithCString: buffer - encoding: [OFLocale encoding]]; + return string; } #ifdef OF_HAVE_IPV6 static OFString * IPv6String(const of_socket_address_t *address, uint16_t *port) { + OFMutableString *string = [OFMutableString string]; const struct sockaddr_in6 *addrIn6 = (const struct sockaddr_in6 *)&address->address; - char buffer[INET6_ADDRSTRLEN]; + int_fast8_t zerosStart = -1, maxZerosStart = -1; + uint_fast8_t zerosCount = 0, maxZerosCount = 0; + bool first = true; + + for (uint_fast8_t i = 0; i < 16; i += 2) { + if (addrIn6->sin6_addr.s6_addr[i] == 0 && + addrIn6->sin6_addr.s6_addr[i + 1] == 0) { + if (zerosStart >= 0) + zerosCount++; + else { + zerosStart = i; + zerosCount = 1; + } + } else { + if (zerosCount > maxZerosCount) { + maxZerosStart = zerosStart; + maxZerosCount = zerosCount; + } + + zerosStart = -1; + } + } + if (zerosCount > maxZerosCount) { + maxZerosStart = zerosStart; + maxZerosCount = zerosCount; + } + + if (maxZerosCount >= 2) { + for (uint_fast8_t i = 0; i < maxZerosStart; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[i] << 8) | + addrIn6->sin6_addr.s6_addr[i + 1]]; + first = false; + } + + [string appendString: @"::"]; + first = true; + + for (uint_fast8_t i = maxZerosStart + (maxZerosCount * 2); + i < 16; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[i] << 8) | + addrIn6->sin6_addr.s6_addr[i + 1]]; + first = false; + } + } else { + for (uint_fast8_t i = 0; i < 16; i += 2) { + [string appendFormat: + (first ? @"%x" : @":%x"), + (addrIn6->sin6_addr.s6_addr[i] << 8) | + addrIn6->sin6_addr.s6_addr[i + 1]]; + first = false; + } + } - if (inet_ntop(AF_INET, &addrIn6->sin6_addr, buffer, sizeof(buffer)) == - NULL) - @throw [OFInvalidArgumentException exception]; + [string makeImmutable]; if (port != NULL) *port = OF_BSWAP16_IF_LE(addrIn6->sin6_port); - return [OFString stringWithCString: buffer - encoding: [OFLocale encoding]]; + return string; } #endif OFString * of_socket_address_ip_string(const of_socket_address_t *address, uint16_t *port) Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -55,11 +55,12 @@ OFSHA384HashTests.m \ OFSHA512HashTests.m SRCS_PLUGINS = OFPluginTests.m SRCS_SOCKETS = OFKernelEventObserverTests.m \ OFTCPSocketTests.m \ - OFUDPSocketTests.m + OFUDPSocketTests.m \ + SocketTests.m SRCS_THREADS = OFThreadTests.m IOS_USER ?= mobile IOS_TMP ?= /tmp/objfw-test ADDED tests/SocketTests.m Index: tests/SocketTests.m ================================================================== --- tests/SocketTests.m +++ tests/SocketTests.m @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFString.h" +#import "OFAutoreleasePool.h" + +#import "OFInvalidFormatException.h" + +#import "TestsAppDelegate.h" + +#import "socket.h" + +#define SOCKADDR_IN(a) (*(struct sockaddr_in *)&a.address) +#define SOCKADDR_IN6(a) (*(struct sockaddr_in6 *)&a.address) +#define COMPARE_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + (SOCKADDR_IN6(a).sin6_addr.s6_addr[0] == (a0 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[1] == (a0 & 0xFF) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[2] == (a1 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[3] == (a1 & 0xFF) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[4] == (a2 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[5] == (a2 & 0xFF) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[6] == (a3 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[7] == (a3 & 0xFF) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[8] == (a4 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[9] == (a4 & 0xFF) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[10] == (a5 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[11] == (a5 & 0xFF) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[12] == (a6 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[13] == (a6 & 0xFF) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[14] == (a7 >> 8) && \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[15] == (a7 & 0xFF)) +#define SET_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[0] = a0 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[1] = a0 & 0xFF; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[2] = a1 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[3] = a1 & 0xFF; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[4] = a2 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[5] = a2 & 0xFF; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[6] = a3 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[7] = a3 & 0xFF; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[8] = a4 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[9] = a4 & 0xFF; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[10] = a5 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[11] = a5 & 0xFF; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[12] = a6 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[13] = a6 & 0xFF; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[14] = a7 >> 8; \ + SOCKADDR_IN6(a).sin6_addr.s6_addr[15] = a7 & 0xFF; + +static OFString *module = @"Socket"; + +@implementation TestsAppDelegate (SocketTests) +- (void)socketTests +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + of_socket_address_t addr; + uint16_t port; + + TEST(@"Parsing an IPv4", + R(addr = of_socket_address_parse_ip(@"127.0.0.1", 1234)) && + OF_BSWAP32_IF_LE(SOCKADDR_IN(addr).sin_addr.s_addr) == 0x7F000001 && + OF_BSWAP16_IF_LE(SOCKADDR_IN(addr).sin_port) == 1234) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1", + OFInvalidFormatException, + of_socket_address_parse_ip(@"127.0.0.0.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2", + OFInvalidFormatException, + of_socket_address_parse_ip(@"127.0.0.256", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3", + OFInvalidFormatException, + of_socket_address_parse_ip(@"127.0.0. 1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4", + OFInvalidFormatException, + of_socket_address_parse_ip(@" 127.0.0.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5", + OFInvalidFormatException, + of_socket_address_parse_ip(@"127.0.a.1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6", + OFInvalidFormatException, + of_socket_address_parse_ip(@"127.0..1", 1234)) + + TEST(@"Converting an IPv4 to a string", + [of_socket_address_ip_string(&addr, &port) isEqual: @"127.0.0.1"] && + port == 1234) + +#ifdef OF_HAVE_IPV6 + TEST(@"Parsing an IPv6 #1", + R(addr = of_socket_address_parse_ip( + @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234)) && + COMPARE_V6(addr, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) && + OF_BSWAP16_IF_LE(SOCKADDR_IN6(addr).sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #2", + R(addr = of_socket_address_parse_ip(@"::", 1234)) && + COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) && + OF_BSWAP16_IF_LE(SOCKADDR_IN6(addr).sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #3", + R(addr = of_socket_address_parse_ip(@"aaAa::bBbb", 1234)) && + COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB) && + OF_BSWAP16_IF_LE(SOCKADDR_IN6(addr).sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #4", + R(addr = of_socket_address_parse_ip(@"aaAa::", 1234)) && + COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0) && + OF_BSWAP16_IF_LE(SOCKADDR_IN6(addr).sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #5", + R(addr = of_socket_address_parse_ip(@"::aaAa", 1234)) && + COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0xAAAA) && + OF_BSWAP16_IF_LE(SOCKADDR_IN6(addr).sin6_port) == 1234) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", + OFInvalidFormatException, + of_socket_address_parse_ip(@"1:::2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", + OFInvalidFormatException, + of_socket_address_parse_ip(@"1: ::2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3", + OFInvalidFormatException, + of_socket_address_parse_ip(@"1:: :2", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4", + OFInvalidFormatException, + of_socket_address_parse_ip(@"1::2::3", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5", + OFInvalidFormatException, + of_socket_address_parse_ip(@"10000::1", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6", + OFInvalidFormatException, + of_socket_address_parse_ip(@"::10000", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7", + OFInvalidFormatException, + of_socket_address_parse_ip(@"::1::", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8", + OFInvalidFormatException, + of_socket_address_parse_ip(@"1:2:3:4:5:6:7:", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9", + OFInvalidFormatException, + of_socket_address_parse_ip(@"1:2:3:4:5:6:7::", 1234)) + + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10", + OFInvalidFormatException, + of_socket_address_parse_ip(@"1:2", 1234)) + + SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) + TEST(@"Converting an IPv6 to a string #1", + [of_socket_address_ip_string(&addr, &port) isEqual: @"::"] && + port == 1234) + + SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 1) + TEST(@"Converting an IPv6 to a string #2", + [of_socket_address_ip_string(&addr, &port) isEqual: @"::1"] && + port == 1234) + + SET_V6(addr, 1, 0, 0, 0, 0, 0, 0, 0) + TEST(@"Converting an IPv6 to a string #3", + [of_socket_address_ip_string(&addr, &port) isEqual: @"1::"] && + port == 1234) + + SET_V6(addr, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #4", + [of_socket_address_ip_string(&addr, &port) isEqual: + @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"] && + port == 1234) + + SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0) + TEST(@"Converting an IPv6 to a string #5", + [of_socket_address_ip_string(&addr, &port) isEqual: + @"1122:3344:5566:7788:99aa:bbcc:ddee:0"] && + port == 1234) + + SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + TEST(@"Converting an IPv6 to a string #6", + [of_socket_address_ip_string(&addr, &port) isEqual: + @"1122:3344:5566:7788:99aa:bbcc::"] && + port == 1234) + + SET_V6(addr, 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #7", + [of_socket_address_ip_string(&addr, &port) isEqual: + @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"] && + port == 1234) + + SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #8", + [of_socket_address_ip_string(&addr, &port) isEqual: + @"::5566:7788:99aa:bbcc:ddee:ff00"] && + port == 1234) + + SET_V6(addr, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00) + TEST(@"Converting an IPv6 to a string #9", + [of_socket_address_ip_string(&addr, &port) isEqual: + @"0:0:5566::ddee:ff00"] && + port == 1234) + + SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + TEST(@"Converting an IPv6 to a string #10", + [of_socket_address_ip_string(&addr, &port) isEqual: + @"::5566:7788:99aa:bbcc:0:0"] && + port == 1234) +#endif + + [pool drain]; +} +@end Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -265,5 +265,9 @@ @end @interface TestsAppDelegate (PBKDF2Tests) - (void)PBKDF2Tests; @end + +@interface TestsAppDelegate (SocketTests) +- (void)socketTests; +@end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -406,10 +406,11 @@ [self scryptTests]; #if defined(OF_HAVE_FILES) && defined(HAVE_CODEPAGE_437) [self INIFileTests]; #endif #ifdef OF_HAVE_SOCKETS + [self socketTests]; [self TCPSocketTests]; [self UDPSocketTests]; [self kernelEventObserverTests]; #endif #ifdef OF_HAVE_THREADS