Index: .travis.yml ================================================================== --- .travis.yml +++ .travis.yml @@ -27,10 +27,33 @@ compiler: clang dist: trusty sudo: required # macOS + - os: osx + osx_image: xcode11.2 + language: objective-c + env: + - no32bit=1 + - noruntime=1 # Broken compiler in this version of Xcode + - os: osx + osx_image: xcode11.1 + language: objective-c + env: + - no32bit=1 + - noruntime=1 # Broken compiler in this version of Xcode + - os: osx + osx_image: xcode11 + language: objective-c + env: + - no32bit=1 + - noruntime=1 # Broken compiler in this version of Xcode + - os: osx + osx_image: xcode10.3 + language: objective-c + env: + - no32bit=1 - os: osx osx_image: xcode10.2 language: objective-c env: - no32bit=1 @@ -64,10 +87,45 @@ - os: osx osx_image: xcode7.3 language: objective-c # iOS + - os: osx + osx_image: xcode11.2 + language: objective-c + env: + - config=ios + - os: osx + osx_image: xcode11.1 + language: objective-c + env: + - config=ios + - os: osx + osx_image: xcode11 + language: objective-c + env: + - config=ios + - os: osx + osx_image: xcode10.3 + language: objective-c + env: + - config=ios + - os: osx + osx_image: xcode10.2 + language: objective-c + env: + - config=ios + - os: osx + osx_image: xcode10.1 + language: objective-c + env: + - config=ios + - os: osx + osx_image: xcode10 + language: objective-c + env: + - config=ios - os: osx osx_image: xcode9.4 language: objective-c env: - config=ios @@ -106,14 +164,14 @@ language: objective-c env: - config=ios # AmigaOS - #- os: linux - # dist: trusty - # env: - # - config=amigaos + - os: linux + dist: trusty + env: + - config=amigaos # Nintendo 3DS - os: linux dist: trusty env: @@ -124,15 +182,14 @@ dist: trusty env: - config=nintendo_ds # Nintendo Wii - # TODO: Enable once libogc is updated - #- os: linux - # dist: trusty - # env: - # - config=wii + - os: linux + dist: trusty + env: + - config=wii before_install: - if [ "$TRAVIS_OS_NAME" = "linux" -a -z "$config" ]; then if ! sudo apt-get -qq update >/tmp/apt_log 2>&1; then cat /tmp/apt_log; @@ -236,23 +293,28 @@ build_mac_32_64 --disable-threads --disable-sockets --disable-files; build_mac_32_64 --disable-sockets; build_mac_32_64 --disable-sockets --disable-files; build_mac_32_64 --disable-files; build_mac_32_64 --disable-shared; - build_mac_32_64 --enable-runtime; - build_mac_32_64 --enable-runtime --enable-seluid24; - build_mac_32_64 --enable-runtime --disable-threads; - build_mac_32_64 --enable-runtime --disable-threads - --disable-sockets; - build_mac_32_64 --enable-runtime --disable-threads --disable-files; - build_mac_32_64 --enable-runtime --disable-threads - --disable-sockets --disable-files; - build_mac_32_64 --enable-runtime --disable-sockets; - build_mac_32_64 --enable-runtime --disable-sockets --disable-files; - build_mac_32_64 --enable-runtime --disable-files; - build_mac_32_64 --enable-runtime --disable-shared; - build_mac_32_64 --enable-runtime --disable-shared --enable-seluid24; + if [ -z "$noruntime" ]; then + build_mac_32_64 --enable-runtime; + build_mac_32_64 --enable-runtime --enable-seluid24; + build_mac_32_64 --enable-runtime --disable-threads; + build_mac_32_64 --enable-runtime --disable-threads + --disable-sockets; + build_mac_32_64 --enable-runtime --disable-threads + --disable-files; + build_mac_32_64 --enable-runtime --disable-threads + --disable-sockets --disable-files; + build_mac_32_64 --enable-runtime --disable-sockets; + build_mac_32_64 --enable-runtime --disable-sockets + --disable-files; + build_mac_32_64 --enable-runtime --disable-files; + build_mac_32_64 --enable-runtime --disable-shared; + build_mac_32_64 --enable-runtime --disable-shared + --enable-seluid24; + fi; fi - if [ "$config" = "ios" ]; then if xcodebuild -version | grep 'Xcode 6' >/dev/null; then export CPPFLAGS="-D_Nullable=__nullable @@ -259,17 +321,17 @@ -D_Nonnull=__nonnull -D_Null_unspecified=__null_unspecified"; fi; export IPHONEOS_DEPLOYMENT_TARGET="9.0"; - clang="clang --sysroot $(xcrun --sdk iphoneos --show-sdk-path)"; + clang="clang -isysroot $(xcrun --sdk iphoneos --show-sdk-path)"; export OBJC="$clang -arch armv7 -arch arm64"; export OBJCPP="$clang -arch armv7 -E"; build --host=arm-apple-darwin --enable-static; sysroot="$(xcrun --sdk iphonesimulator --show-sdk-path)"; - clang="clang --sysroot $sysroot"; + clang="clang -isysroot $sysroot"; export OBJC="$clang -arch i386 -arch x86_64"; export OBJCPP="$clang -arch i386 -E"; build WRAPPER=true --host=i386-apple-darwin --enable-static; fi Index: README.md ================================================================== --- README.md +++ README.md @@ -51,22 +51,22 @@ When building for macOS or iOS, everything is built as a `.framework` by default if `--disable-shared` has not been specified to `configure`. To build for iOS, use something like this: - $ clang="clang --sysroot $(xcrun --sdk iphoneos --show-sdk-path)" + $ clang="clang -isysroot $(xcrun --sdk iphoneos --show-sdk-path)" $ export OBJC="$clang -arch armv7 -arch arm64" $ export OBJCPP="$clang -arch armv7 -E" - $ export IPHONEOS_DEPLOYMENT_TARGET="10.0" + $ export IPHONEOS_DEPLOYMENT_TARGET="9.0" $ ./configure --prefix=/usr/local/ios --host=arm-apple-darwin To build for the iOS simulator, use something like this: - $ clang="clang --sysroot $(xcrun --sdk iphonesimulator --show-sdk-path)" + $ clang="clang -isysroot $(xcrun --sdk iphonesimulator --show-sdk-path)" $ export OBJC="$clang -arch i386 -arch x86_64" $ export OBJCPP="$clang -arch i386 -E" - $ export IPHONEOS_DEPLOYMENT_TARGET="10.0" + $ export IPHONEOS_DEPLOYMENT_TARGET="9.0" $ ./configure --prefix=/usr/local/iossim --host=i386-apple-darwin ### Using the macOS or iOS framework in Xcode To use the macOS framework in Xcode, you need to add the `.framework`s to Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -3,11 +3,10 @@ AC_CONFIG_AUX_DIR(build-aux) AC_CONFIG_MACRO_DIR(build-aux/m4) AC_DEFINE(OBJFW_VERSION_MAJOR, 1, [The major version of ObjFW]) AC_DEFINE(OBJFW_VERSION_MINOR, 0, [The minor version of ObjFW]) -dnl This may only be set to 0.91 once 0.91 is released AC_SUBST(BUNDLE_VERSION, 1.0.0) AC_SUBST(BUNDLE_SHORT_VERSION, 1.0) for i in configure.ac build-aux/m4/*; do AS_IF([test $i -nt configure], [ @@ -1182,10 +1181,11 @@ ;; *) AC_CHECK_TYPE(off64_t, [ AC_DEFINE(OF_HAVE_OFF64_T, 1, [Whether we have off64_t]) + AC_CHECK_FUNCS([lseek64 lstat64 open64 stat64]) ]) ;; esac AC_CHECK_HEADERS([pwd.h grp.h]) Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -8,11 +8,11 @@ OBJFWRT_SHARED_LIB = @OBJFWRT_SHARED_LIB@ OBJFWRT_STATIC_LIB = @OBJFWRT_STATIC_LIB@ OBJFWRT_FRAMEWORK = @OBJFWRT_FRAMEWORK@ OBJFWRT_AMIGA_LIB = @OBJFWRT_AMIGA_LIB@ -OBJFWRT_LIB_MAJOR = 0 +OBJFWRT_LIB_MAJOR = 1 OBJFWRT_LIB_MINOR = 0 OBJFWRT_LIB_MAJOR_MINOR = ${OBJFWRT_LIB_MAJOR}.${OBJFWRT_LIB_MINOR} OBJFWBRIDGE_SHARED_LIB = @OBJFWBRIDGE_SHARED_LIB@ OBJFWBRIDGE_STATIC_LIB = @OBJFWBRIDGE_STATIC_LIB@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -26,11 +26,10 @@ OFFileManager.m \ OFGZIPStream.m \ OFHMAC.m \ OFInflate64Stream.m \ OFInflateStream.m \ - OFIntrospection.m \ OFInvocation.m \ OFLHAArchive.m \ OFLHAArchiveEntry.m \ OFList.m \ OFLocale.m \ @@ -121,12 +120,14 @@ OFINICategory.m \ OFINIFile.m \ OFSettings.m \ OFString+PathAdditions.m SRCS_PLUGINS = OFPlugin.m -SRCS_SOCKETS = OFDNSResolver.m \ +SRCS_SOCKETS = OFDNSQuery.m \ + OFDNSResolver.m \ OFDNSResourceRecord.m \ + OFDNSResponse.m \ OFHTTPClient.m \ OFHTTPCookie.m \ OFHTTPCookieManager.m \ OFHTTPRequest.m \ OFHTTPResponse.m \ @@ -197,11 +198,13 @@ ${AUTORELEASE_M} \ ${INSTANCE_M} \ ${LIBBASES_M} SRCS_FILES += OFFileURLHandler.m \ OFINIFileSettings.m -SRCS_SOCKETS += OFHTTPURLHandler.m \ +SRCS_SOCKETS += OFDNSResolverSettings.m \ + OFHTTPURLHandler.m \ + OFHostAddressResolver.m \ OFKernelEventObserver.m \ ${OFEPOLLKERNELEVENTOBSERVER_M} \ ${OFKQUEUEKERNELEVENTOBSERVER_M} \ ${OFPOLLKERNELEVENTOBSERVER_M} \ ${OFSELECTKERNELEVENTOBSERVER_M} Index: src/OFAdjacentArray.h ================================================================== --- src/OFAdjacentArray.h +++ src/OFAdjacentArray.h @@ -19,13 +19,12 @@ OF_ASSUME_NONNULL_BEGIN @class OFMutableData; -OF_SUBCLASSING_RESTRICTED @interface OFAdjacentArray: OFArray { OFMutableData *_array; } @end OF_ASSUME_NONNULL_END Index: src/OFAdjacentSubarray.h ================================================================== --- src/OFAdjacentSubarray.h +++ src/OFAdjacentSubarray.h @@ -17,10 +17,9 @@ #import "OFSubarray.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFAdjacentSubarray: OFSubarray @end OF_ASSUME_NONNULL_END Index: src/OFApplication.h ================================================================== --- src/OFApplication.h +++ src/OFApplication.h @@ -128,13 +128,10 @@ OFString *_programName; OFArray OF_GENERIC(OFString *) *_arguments; OFMutableDictionary OF_GENERIC(OFString *, OFString *) *_environment; int *_argc; char ***_argv; -#ifdef OF_APPLICATION_M -@public -#endif id _Nullable _delegate; void (*_Nullable _SIGINTHandler)(id, SEL); #ifndef OF_WINDOWS void (*_Nullable _SIGHUPHandler)(id, SEL); void (*_Nullable _SIGUSR1Handler)(id, SEL); Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -15,12 +15,10 @@ * file. */ #include "config.h" -#define OF_APPLICATION_M - #include #include #include #include @@ -99,29 +97,10 @@ #if defined(OF_HAVE_THREADS) && defined(OF_HAVE_SOCKETS) && defined(OF_AMIGAOS) of_socket_deinit(); #endif } -#define SIGNAL_HANDLER(signal) \ - static void \ - handle##signal(int sig) \ - { \ - app->_##signal##Handler(app->_delegate, \ - @selector(applicationDidReceive##signal)); \ - } -SIGNAL_HANDLER(SIGINT) -#ifdef SIGHUP -SIGNAL_HANDLER(SIGHUP) -#endif -#ifdef SIGUSR1 -SIGNAL_HANDLER(SIGUSR1) -#endif -#ifdef SIGUSR2 -SIGNAL_HANDLER(SIGUSR2) -#endif -#undef SIGNAL_HANDLER - int of_application_main(int *argc, char **argv[], id delegate) { #ifdef OF_WINDOWS @@ -156,10 +135,29 @@ @synthesize environment = _environment; #ifdef OF_HAVE_SANDBOX @synthesize activeSandbox = _activeSandbox; @synthesize activeSandboxForChildProcesses = _activeSandboxForChildProcesses; #endif + +#define SIGNAL_HANDLER(signal) \ + static void \ + handle##signal(int sig) \ + { \ + app->_##signal##Handler(app->_delegate, \ + @selector(applicationDidReceive##signal)); \ + } +SIGNAL_HANDLER(SIGINT) +#ifdef SIGHUP +SIGNAL_HANDLER(SIGHUP) +#endif +#ifdef SIGUSR1 +SIGNAL_HANDLER(SIGUSR1) +#endif +#ifdef SIGUSR2 +SIGNAL_HANDLER(SIGUSR2) +#endif +#undef SIGNAL_HANDLER + (OFApplication *)sharedApplication { return app; } ADDED src/OFArray+Private.h Index: src/OFArray+Private.h ================================================================== --- src/OFArray+Private.h +++ src/OFArray+Private.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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. + */ + +#import "OFArray.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFArrayEnumerator: OFEnumerator +{ + OFArray *_array; + size_t _count; + unsigned long _mutations; + unsigned long *_Nullable _mutationsPtr; + size_t _position; +} + +- (instancetype)initWithArray: (OFArray *)data + mutationsPtr: (nullable unsigned long *)mutationsPtr; +@end + +OF_ASSUME_NONNULL_END Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -90,14 +90,10 @@ * @note Subclasses must implement @ref count and @ref objectAtIndex:. */ @interface OFArray OF_GENERIC(ObjectType): OFObject -{ - OF_RESERVE_IVARS(4) -} - #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif /*! * @brief The objects of the array as a C array. @@ -494,26 +490,13 @@ #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # undef ObjectType #endif @end -@interface OFArrayEnumerator: OFEnumerator -{ - OFArray *_array; - size_t _count; - unsigned long _mutations; - unsigned long *_Nullable _mutationsPtr; - size_t _position; -} - -- (instancetype)initWithArray: (OFArray *)data - mutationsPtr: (nullable unsigned long *)mutationsPtr; -@end - OF_ASSUME_NONNULL_END #import "OFMutableArray.h" #if !defined(NSINTEGER_DEFINED) && !__has_feature(modules) /* Required for array literals to work */ @compatibility_alias NSArray OFArray; #endif Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -21,10 +21,11 @@ #include #include #import "OFArray.h" +#import "OFArray+Private.h" #import "OFAdjacentArray.h" #import "OFData.h" #import "OFNull.h" #import "OFString.h" #import "OFSubarray.h" Index: src/OFBitSetCharacterSet.h ================================================================== --- src/OFBitSetCharacterSet.h +++ src/OFBitSetCharacterSet.h @@ -17,14 +17,13 @@ #import "OFCharacterSet.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFBitSetCharacterSet: OFCharacterSet { unsigned char *_bitset; size_t _size; } @end OF_ASSUME_NONNULL_END Index: src/OFBlock.m ================================================================== --- src/OFBlock.m +++ src/OFBlock.m @@ -69,43 +69,46 @@ - (void)release; @end #ifdef OF_OBJFW_RUNTIME /* Begin of ObjC module */ -static struct objc_abi_class _NSConcreteStackBlock_metaclass = { - (struct objc_abi_class *)(void *)"OFBlock", "OFBlock", "OFStackBlock", - 8, OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_abi_class), NULL, NULL -}; - -struct objc_abi_class _NSConcreteStackBlock = { - &_NSConcreteStackBlock_metaclass, "OFBlock", "OFStackBlock", - 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL -}; - -static struct objc_abi_class _NSConcreteGlobalBlock_metaclass = { - (struct objc_abi_class *)(void *)"OFBlock", "OFBlock", "OFGlobalBlock", - 8, OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_abi_class), NULL, NULL -}; - -struct objc_abi_class _NSConcreteGlobalBlock = { - &_NSConcreteGlobalBlock_metaclass, "OFBlock", "OFGlobalBlock", - 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL -}; - -static struct objc_abi_class _NSConcreteMallocBlock_metaclass = { - (struct objc_abi_class *)(void *)"OFBlock", "OFBlock", "OFMallocBlock", - 8, OBJC_CLASS_INFO_METACLASS, sizeof(struct objc_abi_class), NULL, NULL -}; - -struct objc_abi_class _NSConcreteMallocBlock = { - &_NSConcreteMallocBlock_metaclass, "OFBlock", "OFMallocBlock", - 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), NULL, NULL +static struct objc_class _NSConcreteStackBlock_metaclass = { + Nil, Nil, "OFStackBlock", 8, OBJC_CLASS_INFO_METACLASS, + sizeof(_NSConcreteStackBlock_metaclass), NULL, NULL +}; + +struct objc_class _NSConcreteStackBlock = { + &_NSConcreteStackBlock_metaclass, (Class)(void *)"OFBlock", + "OFStackBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), + NULL, NULL +}; + +static struct objc_class _NSConcreteGlobalBlock_metaclass = { + Nil, Nil, "OFGlobalBlock", 8, OBJC_CLASS_INFO_METACLASS, + sizeof(_NSConcreteGlobalBlock_metaclass), NULL, NULL +}; + +struct objc_class _NSConcreteGlobalBlock = { + &_NSConcreteGlobalBlock_metaclass, (Class)(void *)"OFBlock", + "OFGlobalBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), + NULL, NULL +}; + +static struct objc_class _NSConcreteMallocBlock_metaclass = { + Nil, Nil, "OFMallocBlock", 8, OBJC_CLASS_INFO_METACLASS, + sizeof(_NSConcreteMallocBlock_metaclass), NULL, NULL +}; + +struct objc_class _NSConcreteMallocBlock = { + &_NSConcreteMallocBlock_metaclass, (Class)(void *)"OFBlock", + "OFMallocBlock", 8, OBJC_CLASS_INFO_CLASS, sizeof(of_block_literal_t), + NULL, NULL }; static struct { unsigned long unknown; - struct objc_abi_selector *selectorRefs; + struct objc_selector *selectorRefs; uint16_t classDefsCount, categoryDefsCount; void *defs[4]; } symtab = { 0, NULL, 3, 0, { @@ -112,12 +115,12 @@ &_NSConcreteStackBlock, &_NSConcreteGlobalBlock, &_NSConcreteMallocBlock, NULL } }; -static struct objc_abi_module module = { - 8, sizeof(module), NULL, (struct objc_abi_symtab *)&symtab +static struct objc_module module = { + 8, sizeof(module), NULL, (struct objc_symtab *)&symtab }; OF_CONSTRUCTOR() { __objc_exec_class(&module); Index: src/OFBytesValue.h ================================================================== --- src/OFBytesValue.h +++ src/OFBytesValue.h @@ -17,15 +17,14 @@ #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFBytesValue: OFValue { size_t _size; void *_bytes; const char *_objCType; } @end OF_ASSUME_NONNULL_END Index: src/OFColor.m ================================================================== --- src/OFColor.m +++ src/OFColor.m @@ -60,10 +60,13 @@ } - (bool)isEqual: (id)object { OFColor *other; + + if (object == self) + return true; if (![object isKindOfClass: [OFColor class]]) return false; other = object; Index: src/OFCountedMapTableSet.h ================================================================== --- src/OFCountedMapTableSet.h +++ src/OFCountedMapTableSet.h @@ -19,13 +19,12 @@ OF_ASSUME_NONNULL_BEGIN @class OFMapTable; -OF_SUBCLASSING_RESTRICTED @interface OFCountedMapTableSet: OFCountedSet { OFMapTable *_mapTable; } @end OF_ASSUME_NONNULL_END Index: src/OFCountedSet.h ================================================================== --- src/OFCountedSet.h +++ src/OFCountedSet.h @@ -46,14 +46,10 @@ @interface OFCountedSet OF_GENERIC(ObjectType): OFMutableSet OF_GENERIC(ObjectType) #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief Returns how often the object is in the set. * * @return How often the object is in the set */ ADDED src/OFDNSQuery.h Index: src/OFDNSQuery.h ================================================================== --- src/OFDNSQuery.h +++ src/OFDNSQuery.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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. + */ + +#import "OFObject.h" +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFString; + +/*! + * @class OFDNSQuery OFDNSQuery.h ObjFW/OFDNSQuery.h + * + * @brief A class representing a DNS query. + */ +@interface OFDNSQuery: OFObject +{ + OFString *_domainName; + of_dns_class_t _DNSClass; + of_dns_record_type_t _recordType; + OF_RESERVE_IVARS(4) +} + +/*! + * @brief The domain name of the query. + */ +@property (readonly, nonatomic) OFString *domainName; + +/*! + * @brief The DNS class of the query. + */ +@property (readonly, nonatomic) of_dns_class_t DNSClass; + +/*! + * @brief The record type of the query. + */ +@property (readonly, nonatomic) of_dns_record_type_t recordType; + +/*! + * @brief Creates a new, autoreleased OFDNSQuery. + * + * @param domainName The domain name to query + * @param DNSClass The DNS class of the query + * @param recordType The record type of the query + * @return A new, autoreleased OFDNSQuery + */ ++ (instancetype)queryWithDomainName: (OFString *)domainName + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType; + +/*! + * @brief Initializes an already allocated OFDNSQuery. + * + * @param domainName The domain name to query + * @param DNSClass The DNS class of the query + * @param recordType The record type of the query + * @return An initialized OFDNSQuery + */ +- (instancetype)initWithDomainName: (OFString *)domainName + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType + OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFDNSQuery.m Index: src/OFDNSQuery.m ================================================================== --- src/OFDNSQuery.m +++ src/OFDNSQuery.m @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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 "OFDNSQuery.h" +#import "OFString.h" + +@implementation OFDNSQuery +@synthesize domainName = _domainName, DNSClass = _DNSClass; +@synthesize recordType = _recordType; + ++ (instancetype)queryWithDomainName: (OFString *)domainName + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType +{ + return [[[self alloc] initWithDomainName: domainName + DNSClass: DNSClass + recordType: recordType] autorelease]; +} + +- (instancetype)initWithDomainName: (OFString *)domainName + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + + if (![domainName hasSuffix: @"."]) + domainName = [domainName stringByAppendingString: @"."]; + + _domainName = [domainName copy]; + _DNSClass = DNSClass; + _recordType = recordType; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_domainName release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFDNSQuery *query; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFDNSQuery class]]) + return false; + + query = object; + + if (query->_domainName != _domainName && + ![query->_domainName isEqual: _domainName]) + return false; + if (query->_DNSClass != _DNSClass) + return false; + if (query->_recordType != _recordType) + return false; + + return true; +} + +- (uint32_t)hash +{ + uint32_t hash; + + OF_HASH_INIT(hash); + OF_HASH_ADD_HASH(hash, _domainName.hash); + OF_HASH_ADD(hash, _DNSClass); + OF_HASH_ADD(hash, _recordType); + OF_HASH_FINALIZE(hash); + + return hash; +} + +- (id)copy +{ + return [self retain]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@ %@ %@ %@>", + self.className, _domainName, of_dns_class_to_string(_DNSClass), + of_dns_record_type_to_string(_recordType)]; +} +@end Index: src/OFDNSResolver.h ================================================================== --- src/OFDNSResolver.h +++ src/OFDNSResolver.h @@ -14,21 +14,24 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFDNSQuery.h" #import "OFDNSResourceRecord.h" +#import "OFDNSResponse.h" #import "OFRunLoop.h" #import "OFString.h" OF_ASSUME_NONNULL_BEGIN #define OF_DNS_RESOLVER_BUFFER_LENGTH 512 @class OFArray OF_GENERIC(ObjectType); @class OFDNSResolver; -@class OFDNSResolverQuery; +@class OFDNSResolverContext; +@class OFDNSResolverSettings; @class OFDate; @class OFDictionary OF_GENERIC(KeyType, ObjectType); @class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); @class OFNumber; @class OFUDPSocket; @@ -62,55 +65,51 @@ OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED, /*! The server refused the query */ OF_DNS_RESOLVER_ERROR_SERVER_REFUSED } of_dns_resolver_error_t; -typedef OFDictionary OF_GENERIC(OFString *, - OFArray OF_GENERIC(OFDNSResourceRecord *) *) *of_dns_resolver_records_t; - -/*! - * @protocol OFDNSResolverDelegate OFDNSResolver.h ObjFW/OFDNSResolver.h - * - * @brief A delegate for OFDNSResolver. - */ -@protocol OFDNSResolverDelegate -@optional -/*! - * @brief This method is called when a DNS resolver resolved a domain name. +/*! + * @protocol OFDNSResolverQueryDelegate OFDNSResolver.h ObjFW/OFDNSResolver.h + * + * @brief A delegate for performed DNS queries. + */ +@protocol OFDNSResolverQueryDelegate +/*! + * @brief This method is called when a DNS resolver performed a query. * * @param resolver The acting resolver - * @param domainName The fully qualified domain name used to resolve the host - * @param answerRecords The answer records from the name server, grouped by - * domain name - * @param authorityRecords The authority records from the name server, grouped - * by domain name - * @param additionalRecords Additional records sent by the name server, grouped - * by domain name + * @param query The query performed by the resolver + * @param response The response from the DNS server, or nil on error * @param exception An exception that happened during resolving, or nil on * success */ -- (void)resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - answerRecords: (nullable of_dns_resolver_records_t)answerRecords - authorityRecords: (nullable of_dns_resolver_records_t)authorityRecords - additionalRecords: (nullable of_dns_resolver_records_t)additionalRecords - exception: (nullable id)exception; +- (void)resolver: (OFDNSResolver *)resolver + didPerformQuery: (OFDNSQuery *)query + response: (nullable OFDNSResponse *)response + exception: (nullable id)exception; +@end /*! - * @brief This method is called when a DNS resolver resolved a domain name to - * socket addresses. + * @protocol OFDNSResolverQueryDelegate OFDNSResolver.h ObjFW/OFDNSResolver.h + * + * @brief A delegate for resolved hosts. + */ +@protocol OFDNSResolverHostDelegate +/*! + * @brief This method is called when a DNS resolver resolved a host to + * addresses. * * @param resolver The acting resolver - * @param domainName The fully qualified domain name used to resolve the host - * @param socketAddresses OFData containing several of_socket_address_t + * @param host The host the resolver resolved + * @param addresses OFData containing several of_socket_address_t * @param exception The exception that occurred during resolving, or nil on * success */ -- (void)resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - socketAddresses: (nullable OFData *)socketAddresses - exception: (nullable id)exception; +- (void)resolver: (OFDNSResolver *)resolver + didResolveHost: (OFString *)host + addresses: (nullable OFData *)addresses + exception: (nullable id)exception; @end /*! * @class OFDNSResolver OFDNSResolver.h ObjFW/OFDNSResolver.h * @@ -122,26 +121,17 @@ * reload. */ OF_SUBCLASSING_RESTRICTED @interface OFDNSResolver: OFObject { - OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC(OFString *) *) - *_staticHosts; - OFArray OF_GENERIC(OFString *) *_nameServers; - OFString *_Nullable _localDomain; - OFArray OF_GENERIC(OFString *) *_searchDomains; - of_time_interval_t _timeout; - unsigned int _maxAttempts, _minNumberOfDotsInAbsoluteName; - bool _usesTCP; - of_time_interval_t _configReloadInterval; - OFDate *_lastConfigReload; + OFDNSResolverSettings *_settings; OFUDPSocket *_IPv4Socket; #ifdef OF_HAVE_IPV6 OFUDPSocket *_IPv6Socket; #endif char _buffer[OF_DNS_RESOLVER_BUFFER_LENGTH]; - OFMutableDictionary OF_GENERIC(OFNumber *, OFDNSResolverQuery *) + OFMutableDictionary OF_GENERIC(OFNumber *, OFDNSResolverContext *) *_queries; } /*! * @brief A dictionary of static hosts. @@ -207,97 +197,74 @@ * @brief Initializes an already allocated OFDNSResolver. */ - (instancetype)init; /*! - * @brief Asynchronously resolves the specified host. - * - * @param host The host to resolve - * @param delegate The delegate to use for callbacks - */ -- (void)asyncResolveHost: (OFString *)host - delegate: (id )delegate; - -/*! - * @brief Asynchronously resolves the specified host. - * - * @param host The host to resolve - * @param recordClass The desired class of the records to query - * @param recordType The desired type of the records to query - * @param delegate The delegate to use for callbacks - */ -- (void)asyncResolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - delegate: (id )delegate; - -/*! - * @brief Asynchronously resolves the specified host. - * - * @param host The host to resolve - * @param recordClass The desired class of the records to query - * @param recordType The desired type of the records to query + * @brief Asynchronously performs the specified query. + * + * @param query The query to perform + * @param delegate The delegate to use for callbacks + */ +- (void)asyncPerformQuery: (OFDNSQuery *)query + delegate: (id )delegate; + +/*! + * @brief Asynchronously performs the specified query. + * + * @param query The query to perform * @param runLoopMode The run loop mode in which to resolve * @param delegate The delegate to use for callbacks */ -- (void)asyncResolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - runLoopMode: (of_run_loop_mode_t)runLoopMode - delegate: (id )delegate; +- (void)asyncPerformQuery: (OFDNSQuery *)query + runLoopMode: (of_run_loop_mode_t)runLoopMode + delegate: (id )delegate; /*! * @brief Asynchronously resolves the specified host to socket addresses. * * @param host The host to resolve * @param delegate The delegate to use for callbacks */ -- (void)asyncResolveSocketAddressesForHost: (OFString *)host - delegate: (id ) - delegate; +- (void)asyncResolveAddressesForHost: (OFString *)host + delegate: (id )delegate; /*! * @brief Asynchronously resolves the specified host to socket addresses. * * @param host The host to resolve * @param addressFamily The desired socket address family * @param delegate The delegate to use for callbacks */ -- (void)asyncResolveSocketAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t) - addressFamily - delegate: (id ) - delegate; +- (void)asyncResolveAddressesForHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily + delegate: (id )delegate; /*! * @brief Asynchronously resolves the specified host to socket addresses. * * @param host The host to resolve * @param addressFamily The desired socket address family * @param runLoopMode The run loop mode in which to resolve * @param delegate The delegate to use for callbacks */ -- (void)asyncResolveSocketAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t) - addressFamily - runLoopMode: (of_run_loop_mode_t)runLoopMode - delegate: (id ) - delegate; +- (void)asyncResolveAddressesForHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily + runLoopMode: (of_run_loop_mode_t)runLoopMode + delegate: (id )delegate; /*! * @brief Synchronously resolves the specified host to socket addresses. * * @param host The host to resolve * @param addressFamily The desired socket address family * @return OFData containing several of_socket_address_t */ -- (OFData *)resolveSocketAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t) - addressFamily; +- (OFData *)resolveAddressesForHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily; /*! - * @brief Closes all sockets and cancels all ongoing requests. + * @brief Closes all sockets and cancels all ongoing queries. */ - (void)close; @end OF_ASSUME_NONNULL_END Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -15,54 +15,36 @@ * file. */ #include "config.h" -#include #include -#include "unistd_wrapper.h" #import "OFDNSResolver.h" #import "OFArray.h" -#import "OFCharacterSet.h" +#import "OFDNSQuery.h" +#import "OFDNSResolverSettings.h" +#import "OFDNSResponse.h" #import "OFData.h" #import "OFDate.h" #import "OFDictionary.h" -#import "OFFile.h" -#import "OFLocale.h" +#import "OFHostAddressResolver.h" #import "OFNumber.h" #import "OFPair.h" #import "OFString.h" #import "OFTimer.h" #import "OFUDPSocket.h" #import "OFUDPSocket+Private.h" -#ifdef OF_WINDOWS -# import "OFWindowsRegistryKey.h" -#endif +#import "OFDNSQueryFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFInvalidServerReplyException.h" -#import "OFOpenItemFailedException.h" -#import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "OFResolveHostFailedException.h" #import "OFTruncatedDataException.h" -#ifdef OF_WINDOWS -# define interface struct -# include -# undef interface -#endif - -#import "socket_helpers.h" - -#ifdef OF_NINTENDO_3DS -# include <3ds.h> -#endif - #ifndef SOCK_DNS # define SOCK_DNS 0 #endif #define BUFFER_LENGTH OF_DNS_RESOLVER_BUFFER_LENGTH @@ -75,226 +57,39 @@ */ #define MAX_ALLOWED_POINTERS 16 #define CNAME_RECURSION 3 -#if defined(OF_HAIKU) -# define HOSTS_PATH @"/system/settings/network/hosts" -# define RESOLV_CONF_PATH @"/system/settings/network/resolv.conf" -#elif defined(OF_MORPHOS) -# define HOSTS_PATH @"ENV:sys/net/hosts" -# define RESOLV_CONF_PATH @"ENV:sys/net/resolv.conf" -#elif defined(OF_AMIGAOS4) -# define HOSTS_PATH @"DEVS:Internet/hosts" -#elif defined(OF_AMIGAOS) -# define HOSTS_PATH @"AmiTCP:db/hosts" -# define RESOLV_CONF_PATH @"AmiTCP:db/resolv.conf" -#else -# define HOSTS_PATH @"/etc/hosts" -# define RESOLV_CONF_PATH @"/etc/resolv.conf" -#endif - /* * TODO: * * - Fallback to TCP */ -static const of_run_loop_mode_t resolveRunLoopMode = - @"of_dns_resolver_resolve_mode"; - -@interface OFDNSResolverSettings: OFObject -{ -@public - OFArray OF_GENERIC(OFString *) *_nameServers, *_searchDomains; - of_time_interval_t _timeout; - unsigned int _maxAttempts, _minNumberOfDotsInAbsoluteName; -} - -- (instancetype) - initWithNameServers: (OFArray *)nameServers - searchDomains: (OFArray *)searchDomains - timeout: (of_time_interval_t)timeout - maxAttempts: (unsigned int)maxAttempts - minNumberOfDotsInAbsoluteName: (unsigned int)minNumberOfDotsInAbsoluteName; -@end - -@interface OFDNSResolverQuery: OFObject -{ -@public - OFString *_host, *_domainName; - of_dns_resource_record_class_t _recordClass; - of_dns_resource_record_type_t _recordType; - OFNumber *_ID; - OFDNSResolverSettings *_settings; - size_t _nameServersIndex, _searchDomainsIndex; - unsigned int _attempt; - id _target; - SEL _selector; - id _context; +@interface OFDNSResolver () +- (void)of_contextTimedOut: (OFDNSResolverContext *)context; +@end + +@interface OFDNSResolverContext: OFObject +{ +@public + OFDNSQuery *_query; + OFNumber *_ID; + OFDNSResolverSettings *_settings; + size_t _nameServersIndex; + unsigned int _attempt; + id _delegate; OFData *_queryData; of_socket_address_t _usedNameServer; OFTimer *_cancelTimer; } -- (instancetype)initWithHost: (OFString *)host - domainName: (OFString *)domainName - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - ID: (OFNumber *)ID - settings: (OFDNSResolverSettings *)settings - nameServersIndex: (size_t)nameServersIndex - searchDomainsIndex: (size_t)searchDomainsIndex - target: (id)target - selector: (SEL)selector - context: (id)context; -@end - -@interface OFDNSResolverAsyncResolveSocketAddressesContext: OFObject -{ - OFString *_host; - id _delegate; - OFMutableArray OF_GENERIC(OF_KINDOF(OFDNSResourceRecord *)) *_records; - OFDNSResolver *_resolver; - OFString *_domainName; -@public - unsigned int _expectedResponses; -} - -- (instancetype)initWithHost: (OFString *)host - delegate: (id)delegate; -- (bool)parseRecords: (OFArray *)records - answerRecords: (OFDictionary *)answerRecords - additionalRecords: (OFDictionary *)additionalRecords - recordType: (of_dns_resource_record_type_t)recordType - recursion: (unsigned int)recursion - result: (OFMutableArray *)result; -- (void)resolveCNAME: (OFCNAMEDNSResourceRecord *)CNAME - answerRecords: (OFDictionary *)answerRecords - additionalRecords: (OFDictionary *)additionalRecords - recordType: (of_dns_resource_record_type_t)recordType - recursion: (unsigned int)recursion - result: (OFMutableArray *)result; -- (void)resolver: (OFDNSResolver *)resolver - didResolveCNAME: (OFString *)CNAME - answerRecords: (OFDictionary *)answerRecords - authorityRecords: (OFDictionary *)authorityRecords - additionalRecords: (OFDictionary *)additionalRecords - context: (OFNumber *)context - exception: (id)exception; -- (void)done; -- (void)resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - answerRecords: (OFDictionary *)answerRecords - authorityRecords: (OFDictionary *)authorityRecords - additionalRecords: (OFDictionary *)additionalRecords - context: (OFNumber *)context - exception: (id)exception; -@end - -@interface OFDNSResolverResolveSocketAddressesDelegate: OFObject - -{ -@public - bool _done; - OFData *_socketAddresses; - id _exception; -} -@end - -@interface OFDNSResolver () -- (void)of_setDefaults; -- (void)of_obtainSystemConfig; -#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_3DS) -- (void)of_parseHosts: (OFString *)path; -# if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS4) -- (void)of_parseResolvConf: (OFString *)path; -- (void)of_parseResolvConfOption: (OFString *)option; -# endif -#endif -#ifdef OF_WINDOWS -- (void)of_obtainWindowsSystemConfig; -#endif -#ifdef OF_AMIGAOS4 -- (void)of_obtainAmigaOS4SystemConfig; -#endif -#ifdef OF_NINTENDO_3DS -- (void)of_obtainNintendo3DSSytemConfig; -#endif -- (void)of_reloadSystemConfig; -- (void)of_resolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - settings: (OFDNSResolverSettings *)settings - nameServersIndex: (size_t)nameServersIndex - searchDomainsIndex: (size_t)searchDomainsIndex - runLoopMode: (of_run_loop_mode_t)runLoopMode - target: (id)target - selector: (SEL)selector - context: (id)context; -- (void)of_asyncResolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - runLoopMode: (of_run_loop_mode_t)runLoopMode - target: (id)target - selector: (SEL)selector - context: (id)context; -- (void)of_sendQuery: (OFDNSResolverQuery *)query - runLoopMode: (of_run_loop_mode_t)runLoopMode; -- (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query; -@end - -#ifndef OF_WII -static OFString * -domainFromHostname(void) -{ - char hostname[256]; - OFString *domain; - - if (gethostname(hostname, 256) != 0) - return nil; - - domain = [OFString stringWithCString: hostname - encoding: [OFLocale encoding]]; - - @try { - of_socket_address_parse_ip(domain, 0); - - /* - * If we are still here, the host name is a valid IP address. - * We can't use that as local domain. - */ - return nil; - } @catch (OFInvalidFormatException *e) { - /* Not an IP address -> we can use it if it contains a dot. */ - size_t pos = [domain rangeOfString: @"."].location; - - if (pos == OF_NOT_FOUND) - return nil; - - return [domain substringWithRange: - of_range(pos + 1, domain.length - pos - 1)]; - } -} -#endif - -static bool -isFQDN(OFString *host, OFDNSResolverSettings *settings) -{ - const char *UTF8String = host.UTF8String; - size_t length = host.UTF8StringLength; - unsigned int dots = 0; - - if ([host hasSuffix: @"."]) - return true; - - for (size_t i = 0; i < length; i++) - if (UTF8String[i] == '.') - dots++; - - return (dots >= settings->_minNumberOfDotsInAbsoluteName); -} +- (instancetype)initWithQuery: (OFDNSQuery *)query + ID: (OFNumber *)ID + settings: (OFDNSResolverSettings *)settings + delegate: (id )delegate; +@end static OFString * parseString(const unsigned char *buffer, size_t length, size_t *i) { uint8_t stringLength; @@ -372,16 +167,15 @@ return [components componentsJoinedByString: @"."]; } static OF_KINDOF(OFDNSResourceRecord *) -parseResourceRecord(OFString *name, of_dns_resource_record_class_t recordClass, - of_dns_resource_record_type_t recordType, uint32_t TTL, - const unsigned char *buffer, size_t length, size_t i, uint16_t dataLength) +parseResourceRecord(OFString *name, of_dns_class_t DNSClass, + of_dns_record_type_t recordType, uint32_t TTL, const unsigned char *buffer, + size_t length, size_t i, uint16_t dataLength) { - if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_A && - recordClass == OF_DNS_RESOURCE_RECORD_CLASS_IN) { + if (recordType == OF_DNS_RECORD_TYPE_A && DNSClass == OF_DNS_CLASS_IN) { of_socket_address_t address; if (dataLength != 4) @throw [OFInvalidServerReplyException exception]; @@ -394,37 +188,37 @@ return [[[OFADNSResourceRecord alloc] initWithName: name address: &address TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_NS) { + } else if (recordType == OF_DNS_RECORD_TYPE_NS) { size_t j = i; OFString *authoritativeHost = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFNSDNSResourceRecord alloc] initWithName: name - recordClass: recordClass + DNSClass: DNSClass authoritativeHost: authoritativeHost TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_CNAME) { + } else if (recordType == OF_DNS_RECORD_TYPE_CNAME) { size_t j = i; OFString *alias = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFCNAMEDNSResourceRecord alloc] initWithName: name - recordClass: recordClass + DNSClass: DNSClass alias: alias TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_SOA) { + } else if (recordType == OF_DNS_RECORD_TYPE_SOA) { size_t j = i; OFString *primaryNameServer = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); OFString *responsiblePerson; uint32_t serialNumber, refreshInterval, retryInterval; @@ -452,33 +246,33 @@ minTTL = (buffer[j + 16] << 24) | (buffer[j + 17] << 16) | (buffer[j + 18] << 8) | buffer[j + 19]; return [[[OFSOADNSResourceRecord alloc] initWithName: name - recordClass: recordClass + DNSClass: DNSClass primaryNameServer: primaryNameServer responsiblePerson: responsiblePerson serialNumber: serialNumber refreshInterval: refreshInterval retryInterval: retryInterval expirationInterval: expirationInterval minTTL: minTTL TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_PTR) { + } else if (recordType == OF_DNS_RECORD_TYPE_PTR) { size_t j = i; OFString *domainName = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFPTRDNSResourceRecord alloc] initWithName: name - recordClass: recordClass + DNSClass: DNSClass domainName: domainName TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_HINFO) { + } else if (recordType == OF_DNS_RECORD_TYPE_HINFO) { size_t j = i; OFString *CPU = parseString(buffer, length, &j); OFString *OS; if (j > i + dataLength) @@ -489,15 +283,15 @@ if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFHINFODNSResourceRecord alloc] initWithName: name - recordClass: recordClass + DNSClass: DNSClass CPU: CPU OS: OS TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_MX) { + } else if (recordType == OF_DNS_RECORD_TYPE_MX) { uint16_t preference; size_t j; OFString *mailExchange; if (dataLength < 2) @@ -511,25 +305,25 @@ if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFMXDNSResourceRecord alloc] - initWithName: name - recordClass: recordClass - preference: preference - mailExchange: mailExchange - TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_TXT) { + initWithName: name + DNSClass: DNSClass + preference: preference + mailExchange: mailExchange + TTL: TTL] autorelease]; + } else if (recordType == OF_DNS_RECORD_TYPE_TXT) { OFData *textData = [OFData dataWithItems: &buffer[i] count: dataLength]; return [[[OFTXTDNSResourceRecord alloc] initWithName: name - recordClass: recordClass + DNSClass: DNSClass textData: textData TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_RP) { + } else if (recordType == OF_DNS_RECORD_TYPE_RP) { size_t j = i; OFString *mailbox = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); OFString *TXTDomainName; @@ -541,17 +335,17 @@ if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFRPDNSResourceRecord alloc] - initWithName: name - recordClass: recordClass - mailbox: mailbox - TXTDomainName: TXTDomainName - TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_AAAA && - recordClass == OF_DNS_RESOURCE_RECORD_CLASS_IN) { + initWithName: name + DNSClass: DNSClass + mailbox: mailbox + TXTDomainName: TXTDomainName + TTL: TTL] autorelease]; + } else if (recordType == OF_DNS_RECORD_TYPE_AAAA && + DNSClass == OF_DNS_CLASS_IN) { of_socket_address_t address; if (dataLength != 16) @throw [OFInvalidServerReplyException exception]; @@ -568,12 +362,12 @@ return [[[OFAAAADNSResourceRecord alloc] initWithName: name address: &address TTL: TTL] autorelease]; - } else if (recordType == OF_DNS_RESOURCE_RECORD_TYPE_SRV && - recordClass == OF_DNS_RESOURCE_RECORD_CLASS_IN) { + } else if (recordType == OF_DNS_RECORD_TYPE_SRV && + DNSClass == OF_DNS_CLASS_IN) { uint16_t priority, weight, port; size_t j; OFString *target; if (dataLength < 6) @@ -588,20 +382,20 @@ if (j != i + dataLength) @throw [OFInvalidServerReplyException exception]; return [[[OFSRVDNSResourceRecord alloc] - initWithName: name - priority: priority - weight: weight - target: target - port: port - TTL: TTL] autorelease]; + initWithName: name + priority: priority + weight: weight + target: target + port: port + TTL: TTL] autorelease]; } else return [[[OFDNSResourceRecord alloc] initWithName: name - recordClass: recordClass + DNSClass: DNSClass recordType: recordType TTL: TTL] autorelease]; } static OFDictionary * @@ -613,31 +407,31 @@ OFMutableArray *array; for (uint_fast16_t j = 0; j < count; j++) { OFString *name = parseName(buffer, length, i, MAX_ALLOWED_POINTERS); - of_dns_resource_record_class_t recordClass; - of_dns_resource_record_type_t recordType; + of_dns_class_t DNSClass; + of_dns_record_type_t recordType; uint32_t TTL; uint16_t dataLength; OFDNSResourceRecord *record; if (*i + 10 > length) @throw [OFTruncatedDataException exception]; recordType = (buffer[*i] << 16) | buffer[*i + 1]; - recordClass = (buffer[*i + 2] << 16) | buffer[*i + 3]; + DNSClass = (buffer[*i + 2] << 16) | buffer[*i + 3]; TTL = (buffer[*i + 4] << 24) | (buffer[*i + 5] << 16) | (buffer[*i + 6] << 8) | buffer[*i + 7]; dataLength = (buffer[*i + 8] << 16) | buffer[*i + 9]; *i += 10; if (*i + dataLength > length) @throw [OFTruncatedDataException exception]; - record = parseResourceRecord(name, recordClass, recordType, TTL, + record = parseResourceRecord(name, DNSClass, recordType, TTL, buffer, length, *i, dataLength); *i += dataLength; array = [ret objectForKey: name]; @@ -657,93 +451,33 @@ [ret makeImmutable]; return ret; } -static void callback(id target, SEL selector, OFDNSResolver *resolver, - OFString *domainName, OFDictionary *answerRecords, - OFDictionary *authorityRecords, OFDictionary *additionalRecords, id context, - id exception) -{ - void (*method)(id, SEL, OFDNSResolver *, OFString *, OFDictionary *, - OFDictionary *, OFDictionary *, id, id) = (void (*)(id, SEL, - OFDNSResolver *, OFString *, OFDictionary *, OFDictionary *, - OFDictionary *, id, id))[target methodForSelector: selector]; - - method(target, selector, resolver, domainName, answerRecords, - authorityRecords, additionalRecords, context, exception); -} - -@implementation OFDNSResolverSettings -- (instancetype)initWithNameServers: (OFArray *)nameServers - searchDomains: (OFArray *)searchDomains - timeout: (of_time_interval_t)timeout - maxAttempts: (unsigned int)maxAttempts - minNumberOfDotsInAbsoluteName: (unsigned int)minNumberOfDotsInAbsoluteName -{ - self = [super init]; - - @try { - _nameServers = [nameServers copy]; - _searchDomains = [searchDomains copy]; - _timeout = timeout; - _maxAttempts = maxAttempts; - _minNumberOfDotsInAbsoluteName = minNumberOfDotsInAbsoluteName; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_nameServers release]; - [_searchDomains release]; - - [super dealloc]; -} -@end - -@implementation OFDNSResolverQuery -- (instancetype)initWithHost: (OFString *)host - domainName: (OFString *)domainName - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - ID: (OFNumber *)ID - settings: (OFDNSResolverSettings *)settings - nameServersIndex: (size_t)nameServersIndex - searchDomainsIndex: (size_t)searchDomainsIndex - target: (id)target - selector: (SEL)selector - context: (id)context +@implementation OFDNSResolverContext +- (instancetype)initWithQuery: (OFDNSQuery *)query + ID: (OFNumber *)ID + settings: (OFDNSResolverSettings *)settings + delegate: (id )delegate { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); OFMutableData *queryData; uint16_t tmp; - _host = [host copy]; - _domainName = [domainName copy]; - _recordClass = recordClass; - _recordType = recordType; + _query = [query copy]; _ID = [ID retain]; - _settings = [settings retain]; - _nameServersIndex = nameServersIndex; - _searchDomainsIndex = searchDomainsIndex; - _target = [target retain]; - _selector = selector; - _context = [context retain]; + _settings = [settings copy]; + _delegate = [delegate retain]; queryData = [OFMutableData dataWithCapacity: 512]; /* Header */ - tmp = OF_BSWAP16_IF_LE(ID.uInt16Value); + tmp = OF_BSWAP16_IF_LE(_ID.uInt16Value); [queryData addItems: &tmp count: 2]; /* RD */ tmp = OF_BSWAP16_IF_LE(1u << 8); @@ -760,11 +494,11 @@ /* Question */ /* QNAME */ for (OFString *component in - [domainName componentsSeparatedByString: @"."]) { + [_query.domainName componentsSeparatedByString: @"."]) { size_t length = component.UTF8StringLength; uint8_t length8; if (length > 63 || queryData.count + length > 512) @throw [OFOutOfRangeException exception]; @@ -774,18 +508,18 @@ [queryData addItems: component.UTF8String count: length]; } /* QTYPE */ - tmp = OF_BSWAP16_IF_LE(recordType); + tmp = OF_BSWAP16_IF_LE(_query.recordType); [queryData addItems: &tmp count: 2]; /* QCLASS */ - tmp = OF_BSWAP16_IF_LE(recordClass); + tmp = OF_BSWAP16_IF_LE(_query.DNSClass); [queryData addItems: &tmp - count: 2]; + count: 2]; [queryData makeImmutable]; _queryData = [queryData copy]; @@ -798,329 +532,22 @@ return self; } - (void)dealloc { - [_host release]; - [_domainName release]; + [_query release]; [_ID release]; [_settings release]; - [_target release]; - [_context release]; + [_delegate release]; [_queryData release]; [_cancelTimer release]; [super dealloc]; } @end -@implementation OFDNSResolverAsyncResolveSocketAddressesContext -- (instancetype)initWithHost: (OFString *)host - delegate: (id)delegate -{ - self = [super init]; - - @try { - _host = [host copy]; - _delegate = [delegate retain]; - - _records = [[OFMutableArray alloc] init]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_host release]; - [_delegate release]; - [_records release]; - [_resolver release]; - [_domainName release]; - - [super dealloc]; -} - -- (bool)parseRecords: (OFArray *)records - answerRecords: (OFDictionary *)answerRecords - additionalRecords: (OFDictionary *)additionalRecords - recordType: (of_dns_resource_record_type_t)recordType - recursion: (unsigned int)recursion - result: (OFMutableArray *)result -{ - bool found = false; - - for (OFDNSResourceRecord *record in records) { - if (record.recordClass != OF_DNS_RESOURCE_RECORD_CLASS_IN) - continue; - - if (record.recordType == recordType) { - [result addObject: record]; - found = true; - } else if (record.recordType == - OF_DNS_RESOURCE_RECORD_TYPE_CNAME) { - [self resolveCNAME: (OFCNAMEDNSResourceRecord *)record - answerRecords: answerRecords - additionalRecords: additionalRecords - recordType: recordType - recursion: recursion - result: result]; - found = true; - } - } - - return found; -} - -- (void)resolveCNAME: (OFCNAMEDNSResourceRecord *)CNAME - answerRecords: (OFDictionary *)answerRecords - additionalRecords: (OFDictionary *)additionalRecords - recordType: (of_dns_resource_record_type_t)recordType - recursion: (unsigned int)recursion - result: (OFMutableArray *)result -{ - OFString *alias = CNAME.alias; - bool found = false; - - if (recursion == 0) - return; - - if ([self parseRecords: [answerRecords objectForKey: alias] - answerRecords: answerRecords - additionalRecords: additionalRecords - recordType: recordType - recursion: recursion - 1 - result: result]) - found = true; - - if ([self parseRecords: [additionalRecords objectForKey: alias] - answerRecords: answerRecords - additionalRecords: additionalRecords - recordType: recordType - recursion: recursion - 1 - result: result]) - found = true; - - if (!found) { - of_run_loop_mode_t runLoopMode = - [OFRunLoop currentRunLoop].currentMode; - OFNumber *recordTypeNumber = - [OFNumber numberWithInt: recordType]; - - _expectedResponses++; - - [result addObject: - [OFPair pairWithFirstObject: CNAME - secondObject: recordTypeNumber]]; - - [_resolver of_asyncResolveHost: alias - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: recordType - runLoopMode: runLoopMode - target: self - selector: @selector(resolver: - didResolveCNAME: - answerRecords: - authorityRecords: - additionalRecords:context: - exception:) - context: recordTypeNumber]; - } -} - -- (void)resolver: (OFDNSResolver *)resolver - didResolveCNAME: (OFString *)CNAME - answerRecords: (OFDictionary *)answerRecords - authorityRecords: (OFDictionary *)authorityRecords - additionalRecords: (OFDictionary *)additionalRecords - context: (OFNumber *)context - exception: (id)exception -{ - /* - * TODO: Error handling could be improved. Ignore error if there are - * responses, otherwise propagate error. - */ - - of_dns_resource_record_type_t recordType = context.unsignedIntValue; - bool found = false; - OFMutableArray *records; - size_t count; - - OF_ENSURE(resolver == _resolver); - - _expectedResponses--; - - if (exception != nil) { - if (_expectedResponses == 0) - [self done]; - - return; - } - - records = [OFMutableArray array]; - - if ([self parseRecords: [answerRecords objectForKey: CNAME] - answerRecords: answerRecords - additionalRecords: additionalRecords - recordType: recordType - recursion: CNAME_RECURSION - result: records]) - found = true; - - if ([self parseRecords: [additionalRecords objectForKey: CNAME] - answerRecords: answerRecords - additionalRecords: additionalRecords - recordType: recordType - recursion: CNAME_RECURSION - result: records]) - found = true; - - if (!found) { - if (_expectedResponses == 0) - [self done]; - - return; - } - - count = _records.count; - for (size_t i = 0; i < count; i++) { - id object = [_records objectAtIndex: i]; - - if (![object isKindOfClass: [OFPair class]]) - continue; - - if (![[[object firstObject] alias] isEqual: CNAME]) - continue; - - if ([[object secondObject] unsignedIntValue] != recordType) - continue; - - [_records removeObjectAtIndex: i]; - [_records insertObjectsFromArray: records - atIndex: i]; - i += records.count - 1; - } - - if (_expectedResponses == 0) - [self done]; -} - -- (void)done -{ - OFMutableData *addresses = - [OFMutableData dataWithItemSize: sizeof(of_socket_address_t)]; - id exception = nil; - - for (id record in _records) { - if (![record isKindOfClass: [OFDNSResourceRecord class]]) - continue; - - switch ([record recordType]) { - case OF_DNS_RESOURCE_RECORD_TYPE_A: - case OF_DNS_RESOURCE_RECORD_TYPE_AAAA: - [addresses addItem: [record address]]; - break; - default: - break; - } - } - - [addresses makeImmutable]; - - if (addresses.count == 0) - exception = [OFResolveHostFailedException - exceptionWithHost: _host - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: 0 - error: OF_DNS_RESOLVER_ERROR_UNKNOWN]; - - if ([_delegate respondsToSelector: @selector( - resolver:didResolveDomainName:socketAddresses:exception:)]) - [_delegate resolver: _resolver - didResolveDomainName: _domainName - socketAddresses: (exception == nil ? addresses : nil) - exception: exception]; -} - -- (void)resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - answerRecords: (OFDictionary *)answerRecords - authorityRecords: (OFDictionary *)authorityRecords - additionalRecords: (OFDictionary *)additionalRecords - context: (OFNumber *)context - exception: (id)exception -{ - /* - * TODO: Error handling could be improved. Ignore error if there are - * responses, otherwise propagate error. - */ - - of_dns_resource_record_type_t recordType = context.unsignedIntValue; - - if (_resolver != nil) - OF_ENSURE(resolver == _resolver); - else - _resolver = [resolver retain]; - - _expectedResponses--; - - if (_domainName != nil) { - if (![domainName isEqual: _domainName]) - /* Did the config change between requests? */ - return; - } else - _domainName = [domainName copy]; - - if (exception != nil) { - if (_expectedResponses == 0) - [self done]; - - return; - } - - [self parseRecords: [answerRecords objectForKey: _domainName] - answerRecords: answerRecords - additionalRecords: additionalRecords - recordType: recordType - recursion: CNAME_RECURSION - result: _records]; - - if (_expectedResponses == 0) - [self done]; -} -@end - -@implementation OFDNSResolverResolveSocketAddressesDelegate -- (void)dealloc -{ - [_socketAddresses release]; - [_exception release]; - - [super dealloc]; -} - -- (void)resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - socketAddresses: (OFData *)socketAddresses - exception: (id)exception -{ - _socketAddresses = [socketAddresses retain]; - _exception = [exception retain]; - _done = true; -} -@end - @implementation OFDNSResolver -@synthesize staticHosts = _staticHosts, nameServers = _nameServers; -@synthesize localDomain = _localDomain, searchDomains = _searchDomains; -@synthesize timeout = _timeout, maxAttempts = _maxAttempts; -@synthesize minNumberOfDotsInAbsoluteName = _minNumberOfDotsInAbsoluteName; -@synthesize usesTCP = _usesTCP, configReloadInterval = _configReloadInterval; - #ifdef OF_AMIGAOS + (void)initialize { if (self != [OFDNSResolver class]) return; @@ -1139,114 +566,27 @@ - (instancetype)init { self = [super init]; @try { + _settings = [[OFDNSResolverSettings alloc] init]; _queries = [[OFMutableDictionary alloc] init]; - [self of_obtainSystemConfig]; + [_settings reload]; } @catch (id e) { [self release]; @throw e; } return self; } -- (void)of_setDefaults -{ - _timeout = 2; - _maxAttempts = 3; - _minNumberOfDotsInAbsoluteName = 1; - _usesTCP = false; -#ifndef OF_NINTENDO_3DS - _configReloadInterval = 2; -#else - _configReloadInterval = 0; -#endif -} - -- (void)of_obtainSystemConfig -{ - void *pool = objc_autoreleasePoolPush(); -#ifdef OF_WINDOWS - OFString *path; -#endif - - [self of_setDefaults]; - -#if defined(OF_WINDOWS) -# ifdef OF_HAVE_FILES - path = [[OFWindowsRegistryKey localMachineKey] - stringForValue: @"DataBasePath" - subkeyPath: @"SYSTEM\\CurrentControlSet\\Services\\" - @"Tcpip\\Parameters"]; - path = [path stringByAppendingPathComponent: @"hosts"]; - - if (path != nil) - [self of_parseHosts: path]; -# endif - - [self of_obtainWindowsSystemConfig]; -#elif defined(OF_AMIGAOS4) - [self of_parseHosts: HOSTS_PATH]; - [self of_obtainAmigaOS4SystemConfig]; -#elif defined(OF_NINTENDO_3DS) - [self of_obtainNintendo3DSSytemConfig]; -#elif defined(OF_HAVE_FILES) - [self of_parseHosts: HOSTS_PATH]; - [self of_parseResolvConf: RESOLV_CONF_PATH]; -#endif - - if (_staticHosts == nil) { - OFArray *localhost = -#ifdef OF_HAVE_IPV6 - [OFArray arrayWithObjects: @"::1", @"127.0.0.1", nil]; -#else - [OFArray arrayWithObject: @"127.0.0.1"]; -#endif - - _staticHosts = [[OFDictionary alloc] - initWithObject: localhost - forKey: @"localhost"]; - } - - if (_nameServers == nil) -#ifdef OF_HAVE_IPV6 - _nameServers = [[OFArray alloc] - initWithObjects: @"127.0.0.1", @"::1", nil]; -#else - _nameServers = [[OFArray alloc] initWithObject: @"127.0.0.1"]; -#endif - -#ifndef OF_WII - if (_localDomain == nil) - _localDomain = [domainFromHostname() copy]; -#endif - - if (_searchDomains == nil) { - if (_localDomain != nil) - _searchDomains = [[OFArray alloc] - initWithObject: _localDomain]; - else - _searchDomains = [[OFArray alloc] init]; - } - - _lastConfigReload = [[OFDate alloc] init]; - - objc_autoreleasePoolPop(pool); -} - - (void)dealloc { [self close]; - [_staticHosts release]; - [_nameServers release]; - [_localDomain release]; - [_searchDomains release]; - [_lastConfigReload release]; + [_settings release]; [_IPv4Socket cancelAsyncRequests]; [_IPv4Socket release]; #ifdef OF_HAVE_IPV6 [_IPv6Socket cancelAsyncRequests]; [_IPv6Socket release]; @@ -1254,528 +594,128 @@ [_queries release]; [super dealloc]; } -#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_3DS) -- (void)of_parseHosts: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFCharacterSet *whitespaceCharacterSet = - [OFCharacterSet whitespaceCharacterSet]; - OFMutableDictionary *staticHosts; - OFFile *file; - OFString *line; - OFEnumerator *enumerator; - OFMutableArray *addresses; - - @try { - file = [OFFile fileWithPath: path - mode: @"r"]; - } @catch (OFOpenItemFailedException *e) { - objc_autoreleasePoolPop(pool); - return; - } - - staticHosts = [OFMutableDictionary dictionary]; - - while ((line = [file readLine]) != nil) { - void *pool2 = objc_autoreleasePoolPush(); - OFArray *components, *hosts; - size_t pos; - OFString *address; - - pos = [line rangeOfString: @"#"].location; - if (pos != OF_NOT_FOUND) - line = [line substringWithRange: of_range(0, pos)]; - - components = [line - componentsSeparatedByCharactersInSet: whitespaceCharacterSet - options: OF_STRING_SKIP_EMPTY]; - - if (components.count < 2) { - objc_autoreleasePoolPop(pool2); - continue; - } - - address = components.firstObject; - hosts = [components objectsInRange: - of_range(1, components.count - 1)]; - - for (OFString *host in hosts) { - addresses = [staticHosts objectForKey: host]; - - if (addresses == nil) { - addresses = [OFMutableArray array]; - [staticHosts setObject: addresses - forKey: host]; - } - - [addresses addObject: address]; - } - - objc_autoreleasePoolPop(pool2); - } - - enumerator = [staticHosts objectEnumerator]; - while ((addresses = [enumerator nextObject]) != nil) - [addresses makeImmutable]; - - [staticHosts makeImmutable]; - - [_staticHosts release]; - _staticHosts = [staticHosts copy]; - - objc_autoreleasePoolPop(pool); -} - -# if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS4) -- (void)of_parseResolvConf: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFCharacterSet *whitespaceCharacterSet = - [OFCharacterSet whitespaceCharacterSet]; - OFCharacterSet *commentCharacters = [OFCharacterSet - characterSetWithCharactersInString: @"#;"]; - OFMutableArray *nameServers = [[_nameServers mutableCopy] autorelease]; - OFFile *file; - OFString *line; - - @try { - file = [OFFile fileWithPath: path - mode: @"r"]; - } @catch (OFOpenItemFailedException *e) { - objc_autoreleasePoolPop(pool); - return; - } - - if (nameServers == nil) - nameServers = [OFMutableArray array]; - - while ((line = [file readLine]) != nil) { - void *pool2 = objc_autoreleasePoolPush(); - size_t pos; - OFArray *components, *arguments; - OFString *option; - - pos = [line indexOfCharacterFromSet: commentCharacters]; - if (pos != OF_NOT_FOUND) - line = [line substringWithRange: of_range(0, pos)]; - - components = [line - componentsSeparatedByCharactersInSet: whitespaceCharacterSet - options: OF_STRING_SKIP_EMPTY]; - - if (components.count < 2) { - objc_autoreleasePoolPop(pool2); - continue; - } - - option = components.firstObject; - arguments = [components objectsInRange: - of_range(1, components.count - 1)]; - - if ([option isEqual: @"nameserver"]) { - if (arguments.count != 1) { - objc_autoreleasePoolPop(pool2); - continue; - } - - [nameServers addObject: [arguments firstObject]]; - } else if ([option isEqual: @"domain"]) { - if (arguments.count != 1) { - objc_autoreleasePoolPop(pool2); - continue; - } - - [_localDomain release]; - _localDomain = [arguments.firstObject copy]; - } else if ([option isEqual: @"search"]) { - [_searchDomains release]; - _searchDomains = [arguments copy]; - } else if ([option isEqual: @"options"]) - for (OFString *argument in arguments) - [self of_parseResolvConfOption: argument]; - - objc_autoreleasePoolPop(pool2); - } - - [nameServers makeImmutable]; - - [_nameServers release]; - _nameServers = [nameServers copy]; - - objc_autoreleasePoolPop(pool); -} - -- (void)of_parseResolvConfOption: (OFString *)option -{ - @try { - if ([option hasPrefix: @"ndots:"]) { - option = [option substringWithRange: - of_range(6, option.length - 6)]; - - _minNumberOfDotsInAbsoluteName = - (unsigned int)option.decimalValue; - } else if ([option hasPrefix: @"timeout:"]) { - option = [option substringWithRange: - of_range(8, option.length - 8)]; - - _timeout = option.decimalValue; - } else if ([option hasPrefix: @"attempts:"]) { - option = [option substringWithRange: - of_range(9, option.length - 9)]; - - _maxAttempts = (unsigned int)option.decimalValue; - } else if ([option hasPrefix: @"reload-period:"]) { - option = [option substringWithRange: - of_range(14, option.length - 14)]; - - _configReloadInterval = option.decimalValue; - } else if ([option isEqual: @"tcp"]) - _usesTCP = true; - } @catch (OFInvalidFormatException *e) { - } -} -# endif -#endif - -#ifdef OF_WINDOWS -- (void)of_obtainWindowsSystemConfig -{ - of_string_encoding_t encoding = [OFLocale encoding]; - OFMutableArray *nameServers; - /* - * We need more space than FIXED_INFO in case we have more than one - * name server, but we also want it to be properly aligned, meaning we - * can't just get a buffer of bytes. Thus, we just get space for 8. - */ - FIXED_INFO fixedInfo[8]; - ULONG length = sizeof(fixedInfo); - PIP_ADDR_STRING iter; - - if (GetNetworkParams(fixedInfo, &length) != ERROR_SUCCESS) - return; - - nameServers = [OFMutableArray array]; - - for (iter = &fixedInfo->DnsServerList; iter != NULL; iter = iter->Next) - [nameServers addObject: - [OFString stringWithCString: iter->IpAddress.String - encoding: encoding]]; - - if (nameServers.count > 0) { - [nameServers makeImmutable]; - _nameServers = [nameServers copy]; - } - - if (fixedInfo->DomainName[0] != '\0') - _localDomain = [[OFString alloc] - initWithCString: fixedInfo->DomainName - encoding: encoding]; -} -#endif - -#ifdef OF_AMIGAOS4 -- (void)of_obtainAmigaOS4SystemConfig -{ - OFMutableArray *nameServers = [OFMutableArray array]; - of_string_encoding_t encoding = [OFLocale encoding]; - struct List *nameServerList = ObtainDomainNameServerList(); - char buffer[MAXHOSTNAMELEN]; - - if (nameServerList == NULL) - @throw [OFOutOfMemoryException exception]; - - @try { - struct DomainNameServerNode *iter = - (struct DomainNameServerNode *)&nameServerList->lh_Head; - - while (iter->dnsn_MinNode.mln_Succ != NULL) { - if (iter->dnsn_UseCount != 0 && - iter->dnsn_Address != NULL) { - OFString *address = [OFString - stringWithCString: iter->dnsn_Address - encoding: encoding]; - - [nameServers addObject: address]; - } - - iter = (struct DomainNameServerNode *) - iter->dnsn_MinNode.mln_Succ; - } - } @finally { - ReleaseDomainNameServerList(nameServerList); - } - - if (nameServers.count > 0) { - [nameServers makeImmutable]; - _nameServers = [nameServers copy]; - } - - if (GetDefaultDomainName(buffer, sizeof(buffer))) - _localDomain = [[OFString alloc] initWithCString: buffer - encoding: encoding]; -} -#endif - -#ifdef OF_NINTENDO_3DS -- (void)of_obtainNintendo3DSSytemConfig -{ - OFMutableArray *nameServers = [OFMutableArray array]; - union { - /* - * For some unknown reason, this needs a 336 bytes buffer and - * always returns 336 bytes. - */ - char bytes[336]; - SOCU_DNSTableEntry entries[2]; - } buffer; - socklen_t optLen = sizeof(buffer); - - if (SOCU_GetNetworkOpt(SOL_CONFIG, NETOPT_DNS_TABLE, - &buffer, &optLen) != 0) - return; - - /* - * We're fine if this gets smaller in a future release (unlikely), as - * long as two entries still fit. - */ - if (optLen < sizeof(buffer.entries)) - return; - - for (uint_fast8_t i = 0; i < 2; i++) { - uint32_t ip = OF_BSWAP32_IF_LE(buffer.entries[i].ip.s_addr); - - if (ip == 0) - continue; - - [nameServers addObject: [OFString stringWithFormat: - @"%u.%u.%u.%u", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, ip & 0xFF]]; - } - - if (nameServers.count > 0) { - [nameServers makeImmutable]; - _nameServers = [nameServers copy]; - } -} -#endif - -- (void)of_reloadSystemConfig -{ - /* - * TODO: Rather than reparsing every time, check what actually changed - * (mtime) and only reset those. - */ - - if (_lastConfigReload != nil && _configReloadInterval > 0 && - _lastConfigReload.timeIntervalSinceNow < _configReloadInterval) - return; - - [_staticHosts release]; - _staticHosts = nil; - - [_nameServers release]; - _nameServers = nil; - - [_localDomain release]; - _localDomain = nil; - - [_searchDomains release]; - _searchDomains = nil; - - [self of_setDefaults]; - - [_lastConfigReload release]; - _lastConfigReload = nil; - - [self of_obtainSystemConfig]; -} - -- (void)of_resolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - settings: (OFDNSResolverSettings *)settings - nameServersIndex: (size_t)nameServersIndex - searchDomainsIndex: (size_t)searchDomainsIndex - runLoopMode: (of_run_loop_mode_t)runLoopMode - target: (id)target - selector: (SEL)selector - context: (id)context -{ - void *pool = objc_autoreleasePoolPush(); - OFNumber *ID; - OFString *domainName; - OFDNSResolverQuery *query; - - [self of_reloadSystemConfig]; - - /* Random, unused ID */ - do { - ID = [OFNumber numberWithUInt16: (uint16_t)of_random()]; - } while ([_queries objectForKey: ID] != nil); - - if (isFQDN(host, settings)) { - domainName = host; - - if (![domainName hasSuffix: @"."]) - domainName = [domainName stringByAppendingString: @"."]; - } else { - OFString *searchDomain = [settings->_searchDomains - objectAtIndex: searchDomainsIndex]; - - domainName = [OFString stringWithFormat: @"%@.%@.", - host, searchDomain]; - } - - if (domainName.UTF8StringLength > 253) - @throw [OFOutOfRangeException exception]; - - query = [[[OFDNSResolverQuery alloc] - initWithHost: host - domainName: domainName - recordClass: recordClass - recordType: recordType - ID: ID - settings: settings - nameServersIndex: nameServersIndex - searchDomainsIndex: searchDomainsIndex - target: target - selector: selector - context: context] autorelease]; - [_queries setObject: query - forKey: ID]; - - [self of_sendQuery: query - runLoopMode: runLoopMode]; - - objc_autoreleasePoolPop(pool); -} - -- (void)of_resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - answerRecords: (of_dns_resolver_records_t)answerRecords - authorityRecords: (of_dns_resolver_records_t)authorityRecords - additionalRecords: (of_dns_resolver_records_t)additionalRecords - context: (id)delegate - exception: (id)exception -{ - if ([delegate respondsToSelector: @selector(resolver: - didResolveDomainName:answerRecords:authorityRecords: - additionalRecords:exception:)]) - [delegate resolver: resolver - didResolveDomainName: domainName - answerRecords: answerRecords - authorityRecords: authorityRecords - additionalRecords: additionalRecords - exception: exception]; -} - -- (void)asyncResolveHost: (OFString *)host - delegate: (id )delegate -{ - [self of_asyncResolveHost: host - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: OF_DNS_RESOURCE_RECORD_TYPE_ALL - runLoopMode: of_run_loop_mode_default - target: self - selector: @selector(of_resolver:didResolveDomainName: - answerRecords:authorityRecords: - additionalRecords:context:exception:) - context: delegate]; -} - -- (void)asyncResolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - delegate: (id )delegate -{ - [self of_asyncResolveHost: host - recordClass: recordClass - recordType: recordType - runLoopMode: of_run_loop_mode_default - target: self - selector: @selector(of_resolver:didResolveDomainName: - answerRecords:authorityRecords: - additionalRecords:context:exception:) - context: delegate]; -} - -- (void)asyncResolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - runLoopMode: (of_run_loop_mode_t)runLoopMode - delegate: (id )delegate -{ - [self of_asyncResolveHost: host - recordClass: recordClass - recordType: recordType - runLoopMode: runLoopMode - target: self - selector: @selector(of_resolver:didResolveDomainName: - answerRecords:authorityRecords: - additionalRecords:context:exception:) - context: delegate]; -} - -- (void)of_asyncResolveHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - runLoopMode: (of_run_loop_mode_t)runLoopMode - target: (id)target - selector: (SEL)selector - context: (id)context -{ - void *pool = objc_autoreleasePoolPush(); - OFDNSResolverSettings *settings = [[[OFDNSResolverSettings alloc] - initWithNameServers: _nameServers - searchDomains: _searchDomains - timeout: _timeout - maxAttempts: _maxAttempts - minNumberOfDotsInAbsoluteName: _minNumberOfDotsInAbsoluteName] - autorelease]; - - [self of_resolveHost: host - recordClass: recordClass - recordType: recordType - settings: settings - nameServersIndex: 0 - searchDomainsIndex: 0 - runLoopMode: runLoopMode - target: target - selector: selector - context: context]; - - objc_autoreleasePoolPop(pool); -} - -- (void)of_sendQuery: (OFDNSResolverQuery *)query - runLoopMode: (of_run_loop_mode_t)runLoopMode +- (OFDictionary *)staticHosts +{ + return _settings->_staticHosts; +} + +- (void)setStaticHosts: (OFDictionary *)staticHosts +{ + OFDictionary *old = _settings->_staticHosts; + _settings->_staticHosts = [staticHosts copy]; + [old release]; +} + +- (OFArray *)nameServers +{ + return _settings->_nameServers; +} + +- (void)setNameServers: (OFArray *)nameServers +{ + OFArray *old = _settings->_nameServers; + _settings->_nameServers = [nameServers copy]; + [old release]; +} + +- (OFString *)localDomain +{ + return _settings->_localDomain; +} + +- (OFArray *)searchDomains +{ + return _settings->_searchDomains; +} + +- (void)setSearchDomains: (OFArray *)searchDomains +{ + OFArray *old = _settings->_searchDomains; + _settings->_searchDomains = [searchDomains copy]; + [old release]; +} + +- (of_time_interval_t)timeout +{ + return _settings->_timeout; +} + +- (void)setTimeout: (of_time_interval_t)timeout +{ + _settings->_timeout = timeout; +} + +- (unsigned int)maxAttempts +{ + return _settings->_maxAttempts; +} + +- (void)setMaxAttempts: (unsigned int)maxAttempts +{ + _settings->_maxAttempts = maxAttempts; +} + +- (unsigned int)minNumberOfDotsInAbsoluteName +{ + return _settings->_minNumberOfDotsInAbsoluteName; +} + +- (void)setMinNumberOfDotsInAbsoluteName: + (unsigned int)minNumberOfDotsInAbsoluteName +{ + _settings->_minNumberOfDotsInAbsoluteName = + minNumberOfDotsInAbsoluteName; +} + +- (bool)usesTCP +{ + return _settings->_usesTCP; +} + +- (void)setUsesTCP: (bool)usesTCP +{ + _settings->_usesTCP = usesTCP; +} + +- (of_time_interval_t)configReloadInterval +{ + return _settings->_configReloadInterval; +} + +- (void)setConfigReloadInterval: (of_time_interval_t)configReloadInterval +{ + _settings->_configReloadInterval = configReloadInterval; +} + +- (void)of_sendQueryForContext: (OFDNSResolverContext *)context + runLoopMode: (of_run_loop_mode_t)runLoopMode { OFUDPSocket *sock; OFString *nameServer; - [query->_cancelTimer invalidate]; - [query->_cancelTimer release]; - query->_cancelTimer = nil; - query->_cancelTimer = [[OFTimer alloc] + [context->_cancelTimer invalidate]; + [context->_cancelTimer release]; + context->_cancelTimer = nil; + context->_cancelTimer = [[OFTimer alloc] initWithFireDate: [OFDate dateWithTimeIntervalSinceNow: - query->_settings->_timeout] - interval: query->_settings->_timeout + context->_settings->_timeout] + interval: context->_settings->_timeout target: self - selector: @selector(of_queryWithIDTimedOut:) - object: query + selector: @selector(of_contextTimedOut:) + object: context repeats: false]; - [[OFRunLoop currentRunLoop] addTimer: query->_cancelTimer + [[OFRunLoop currentRunLoop] addTimer: context->_cancelTimer forMode: runLoopMode]; - nameServer = [query->_settings->_nameServers - objectAtIndex: query->_nameServersIndex]; - query->_usedNameServer = of_socket_address_parse_ip(nameServer, 53); + nameServer = [context->_settings->_nameServers + objectAtIndex: context->_nameServersIndex]; + context->_usedNameServer = of_socket_address_parse_ip(nameServer, 53); - switch (query->_usedNameServer.family) { + switch (context->_usedNameServer.family) { #ifdef OF_HAVE_IPV6 case OF_SOCKET_ADDRESS_FAMILY_IPV6: if (_IPv6Socket == nil) { of_socket_address_t address = of_socket_address_parse_ip(@"::", 0); @@ -1783,12 +723,10 @@ _IPv6Socket = [[OFUDPSocket alloc] init]; [_IPv6Socket of_bindToAddress: &address extraType: SOCK_DNS]; _IPv6Socket.blocking = false; _IPv6Socket.delegate = self; - [_IPv6Socket asyncReceiveIntoBuffer: _buffer - length: BUFFER_LENGTH]; } sock = _IPv6Socket; break; #endif @@ -1800,53 +738,90 @@ _IPv4Socket = [[OFUDPSocket alloc] init]; [_IPv4Socket of_bindToAddress: &address extraType: SOCK_DNS]; _IPv4Socket.blocking = false; _IPv4Socket.delegate = self; - [_IPv4Socket asyncReceiveIntoBuffer: _buffer - length: BUFFER_LENGTH]; } sock = _IPv4Socket; break; default: @throw [OFInvalidArgumentException exception]; } - [sock asyncSendData: query->_queryData - receiver: &query->_usedNameServer - runLoopMode: runLoopMode]; -} - -- (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query -{ - OFResolveHostFailedException *exception; - - if (query == nil) - return; - - if (query->_nameServersIndex + 1 < - query->_settings->_nameServers.count) { - query->_nameServersIndex++; - [self of_sendQuery: query - runLoopMode: [OFRunLoop currentRunLoop].currentMode]; - return; - } - - if (query->_attempt < query->_settings->_maxAttempts) { - query->_attempt++; - query->_nameServersIndex = 0; - [self of_sendQuery: query - runLoopMode: [OFRunLoop currentRunLoop].currentMode]; - return; - } - - query = [[query retain] autorelease]; - [_queries removeObjectForKey: query->_ID]; - - /* - * Cancel any pending requests, to avoid a send being still pending and + [sock asyncSendData: context->_queryData + receiver: &context->_usedNameServer + runLoopMode: runLoopMode]; + [sock asyncReceiveIntoBuffer: _buffer + length: BUFFER_LENGTH + runLoopMode: runLoopMode]; +} + +- (void)asyncPerformQuery: (OFDNSQuery *)query + delegate: (id )delegate +{ + [self asyncPerformQuery: query + runLoopMode: of_run_loop_mode_default + delegate: delegate]; +} + +- (void)asyncPerformQuery: (OFDNSQuery *)query + runLoopMode: (of_run_loop_mode_t)runLoopMode + delegate: (id )delegate +{ + void *pool = objc_autoreleasePoolPush(); + OFNumber *ID; + OFDNSResolverContext *context; + + /* Random, unused ID */ + do { + ID = [OFNumber numberWithUInt16: (uint16_t)of_random()]; + } while ([_queries objectForKey: ID] != nil); + + if (query.domainName.UTF8StringLength > 253) + @throw [OFOutOfRangeException exception]; + + context = [[[OFDNSResolverContext alloc] + initWithQuery: query + ID: ID + settings: _settings + delegate: delegate] autorelease]; + [_queries setObject: context + forKey: ID]; + + [self of_sendQueryForContext: context + runLoopMode: runLoopMode]; + + objc_autoreleasePoolPop(pool); +} + +- (void)of_contextTimedOut: (OFDNSResolverContext *)context +{ + of_run_loop_mode_t runLoopMode = [OFRunLoop currentRunLoop].currentMode; + OFDNSQueryFailedException *exception; + + if (context->_nameServersIndex + 1 < + context->_settings->_nameServers.count) { + context->_nameServersIndex++; + [self of_sendQueryForContext: context + runLoopMode: runLoopMode]; + return; + } + + if (context->_attempt < context->_settings->_maxAttempts) { + context->_attempt++; + context->_nameServersIndex = 0; + [self of_sendQueryForContext: context + runLoopMode: runLoopMode]; + return; + } + + context = [[context retain] autorelease]; + [_queries removeObjectForKey: context->_ID]; + + /* + * Cancel any pending queries, to avoid a send being still pending and * trying to access the query once it no longer exists. */ [_IPv4Socket cancelAsyncRequests]; [_IPv4Socket asyncReceiveIntoBuffer: _buffer length: BUFFER_LENGTH]; @@ -1854,18 +829,20 @@ [_IPv6Socket cancelAsyncRequests]; [_IPv6Socket asyncReceiveIntoBuffer: _buffer length: BUFFER_LENGTH]; #endif - exception = [OFResolveHostFailedException - exceptionWithHost: query->_host - recordClass: query->_recordClass - recordType: query->_recordType - error: OF_DNS_RESOLVER_ERROR_TIMEOUT]; - - callback(query->_target, query->_selector, self, query->_domainName, - nil, nil, nil, query->_context, exception); + exception = [OFDNSQueryFailedException + exceptionWithQuery: context->_query + error: OF_DNS_RESOLVER_ERROR_TIMEOUT]; + + if ([context->_delegate respondsToSelector: + @selector(resolver:didPerformQuery:response:exception:)]) + [context->_delegate resolver: self + didPerformQuery: context->_query + response: nil + exception: exception]; } - (bool)socket: (OFUDPSocket *)sock didReceiveIntoBuffer: (void *)buffer_ length: (size_t)length @@ -1873,49 +850,51 @@ exception: (id)exception { unsigned char *buffer = buffer_; OFDictionary *answerRecords = nil, *authorityRecords = nil; OFDictionary *additionalRecords = nil; + OFDNSResponse *response = nil; OFNumber *ID; - OFDNSResolverQuery *query; + OFDNSResolverContext *context; if (exception != nil) return true; if (length < 2) - /* We can't get the ID to get the query. Ignore packet. */ + /* We can't get the ID to get the context. Ignore packet. */ return true; ID = [OFNumber numberWithUInt16: (buffer[0] << 8) | buffer[1]]; - query = [[[_queries objectForKey: ID] retain] autorelease]; + context = [[[_queries objectForKey: ID] retain] autorelease]; - if (query == nil) + if (context == nil) return true; - if (!of_socket_address_equal(sender, &query->_usedNameServer)) + if (!of_socket_address_equal(sender, &context->_usedNameServer)) return true; - [query->_cancelTimer invalidate]; - [query->_cancelTimer release]; - query->_cancelTimer = nil; + [context->_cancelTimer invalidate]; + [context->_cancelTimer release]; + context->_cancelTimer = nil; [_queries removeObjectForKey: ID]; @try { + of_dns_resolver_error_t error = 0; + bool tryNextNameServer = false; const unsigned char *queryDataBuffer; size_t i; - of_dns_resolver_error_t error; uint16_t numQuestions, numAnswers, numAuthorityRecords; uint16_t numAdditionalRecords; if (length < 12) @throw [OFTruncatedDataException exception]; - if (query->_queryData.itemSize != 1 || - query->_queryData.count < 12) + if (context->_queryData.itemSize != 1 || + context->_queryData.count < 12) @throw [OFInvalidArgumentException exception]; - queryDataBuffer = query->_queryData.items; + queryDataBuffer = context->_queryData.items; /* QR */ if ((buffer[2] & 0x80) == 0) @throw [OFInvalidServerReplyException exception]; @@ -1934,52 +913,47 @@ case 1: error = OF_DNS_RESOLVER_ERROR_SERVER_INVALID_FORMAT; break; case 2: error = OF_DNS_RESOLVER_ERROR_SERVER_FAILURE; + tryNextNameServer = true; break; case 3: - if (query->_searchDomainsIndex + 1 < - query->_settings->_searchDomains.count) { - of_run_loop_mode_t runLoopMode = - [OFRunLoop currentRunLoop].currentMode; - - query->_searchDomainsIndex++; - - [self of_resolveHost: query->_host - recordClass: query->_recordClass - recordType: query->_recordType - settings: query->_settings - nameServersIndex: query->_nameServersIndex - searchDomainsIndex: query->_searchDomainsIndex - runLoopMode: runLoopMode - target: query->_target - selector: query->_selector - context: query->_context]; - - return true; - } - error = OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR; break; case 4: error = OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED; + tryNextNameServer = true; break; case 5: error = OF_DNS_RESOLVER_ERROR_SERVER_REFUSED; + tryNextNameServer = true; break; default: error = OF_DNS_RESOLVER_ERROR_UNKNOWN; + tryNextNameServer = true; break; } + + if (tryNextNameServer) { + if (context->_nameServersIndex + 1 < + context->_settings->_nameServers.count) { + of_run_loop_mode_t runLoopMode = + [OFRunLoop currentRunLoop].currentMode; + + context->_nameServersIndex++; + + [self of_sendQueryForContext: context + runLoopMode: runLoopMode]; + return false; + } + } if (buffer[3] & 0x0F) - @throw [OFResolveHostFailedException - exceptionWithHost: query->_host - recordClass: query->_recordClass - recordType: query->_recordType - error: error]; + @throw [OFDNSQueryFailedException + exceptionWithQuery: context->_query + error: error]; numQuestions = (buffer[4] << 8) | buffer[5]; numAnswers = (buffer[6] << 8) | buffer[7]; numAuthorityRecords = (buffer[8] << 8) | buffer[9]; numAdditionalRecords = (buffer[10] << 8) | buffer[11]; @@ -2000,270 +974,95 @@ answerRecords = parseSection(buffer, length, &i, numAnswers); authorityRecords = parseSection(buffer, length, &i, numAuthorityRecords); additionalRecords = parseSection(buffer, length, &i, numAdditionalRecords); - } @catch (id e) { - callback(query->_target, query->_selector, self, - query->_domainName, nil, nil, nil, query->_context, e); - return true; - } - - callback(query->_target, query->_selector, self, query->_domainName, - answerRecords, authorityRecords, additionalRecords, - query->_context, nil); - - return true; -} - -- (void)asyncResolveSocketAddressesForHost: (OFString *)host - delegate: (id )delegate -{ - [self asyncResolveSocketAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY - runLoopMode: of_run_loop_mode_default - delegate: delegate]; -} - -- (void)asyncResolveSocketAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t) - addressFamily - delegate: (id )delegate -{ - [self asyncResolveSocketAddressesForHost: host - addressFamily: addressFamily - runLoopMode: of_run_loop_mode_default - delegate: delegate]; -} - -- (void)asyncResolveSocketAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t) - addressFamily - runLoopMode: (of_run_loop_mode_t)runLoopMode - delegate: (id )delegate -{ - OFArray OF_GENERIC(OFString *) *aliases; - void *pool; - OFDNSResolverAsyncResolveSocketAddressesContext *context; - - @try { - of_socket_address_t address = - of_socket_address_parse_ip(host, 0); - OFData *addresses = nil; - id exception = nil; - - if (addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY || - addressFamily == address.family) - addresses = [OFData dataWithItems: &address - itemSize: sizeof(address) - count: 1]; - else - exception = [OFInvalidArgumentException exception]; - - if ([delegate respondsToSelector: @selector(resolver: - didResolveDomainName:socketAddresses:exception:)]) { - OFTimer *timer = [OFTimer - timerWithTimeInterval: 0 - target: delegate - selector: @selector(resolver: - didResolveDomainName: - socketAddresses: - exception:) - object: self - object: host - object: addresses - object: exception - repeats: false]; - [[OFRunLoop currentRunLoop] addTimer: timer - forMode: runLoopMode]; - } - - return; - } @catch (OFInvalidFormatException *e) { - } - - if ((aliases = [_staticHosts objectForKey: host]) != nil) { - OFMutableData *addresses = [OFMutableData - dataWithItemSize: sizeof(of_socket_address_t)]; - id exception = nil; - - for (OFString *alias in aliases) { - of_socket_address_t address; - - @try { - address = of_socket_address_parse_ip(alias, 0); - } @catch (OFInvalidFormatException *e) { - continue; - } - - if (addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY && - address.family != addressFamily) - continue; - - [addresses addItem: &address]; - } - - [addresses makeImmutable]; - - if (addresses.count == 0) { - of_dns_resource_record_type_t recordType = 0; - - addresses = nil; - - switch (addressFamily) { - case OF_SOCKET_ADDRESS_FAMILY_ANY: - recordType = OF_DNS_RESOURCE_RECORD_TYPE_ALL; - break; - case OF_SOCKET_ADDRESS_FAMILY_IPV4: - recordType = OF_DNS_RESOURCE_RECORD_TYPE_A; - break; - case OF_SOCKET_ADDRESS_FAMILY_IPV6: - recordType = OF_DNS_RESOURCE_RECORD_TYPE_AAAA; - break; - default: - exception = - [OFInvalidArgumentException exception]; - break; - } - - if (exception == nil) { - of_dns_resource_record_class_t recordClass = - OF_DNS_RESOURCE_RECORD_CLASS_IN; - of_dns_resolver_error_t error = - OF_DNS_RESOLVER_ERROR_NO_RESULT; - - exception = [OFResolveHostFailedException - exceptionWithHost: host - recordClass: recordClass - recordType: recordType - error: error]; - } - } - - if ([delegate respondsToSelector: @selector(resolver: - didResolveDomainName:socketAddresses:exception:)]) { - OFTimer *timer = [OFTimer - timerWithTimeInterval: 0 - target: delegate - selector: @selector(resolver: - didResolveDomainName: - socketAddresses: - exception:) - object: self - object: host - object: addresses - object: exception - repeats: false]; - [[OFRunLoop currentRunLoop] addTimer: timer - forMode: runLoopMode]; - } - - return; - } - - pool = objc_autoreleasePoolPush(); - - context = [[[OFDNSResolverAsyncResolveSocketAddressesContext alloc] - initWithHost: host - delegate: delegate] autorelease]; - - switch (addressFamily) { - case OF_SOCKET_ADDRESS_FAMILY_IPV4: -#ifdef OF_HAVE_IPV6 - case OF_SOCKET_ADDRESS_FAMILY_IPV6: -#endif - context->_expectedResponses = 1; - break; - case OF_SOCKET_ADDRESS_FAMILY_ANY: -#ifdef OF_HAVE_IPV6 - context->_expectedResponses = 2; -#else - context->_expectedResponses = 1; -#endif - break; - default: - @throw [OFInvalidArgumentException exception]; - } - -#ifdef OF_HAVE_IPV6 - if (addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV6 || - addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) { - OFNumber *recordTypeNumber = - [OFNumber numberWithInt: OF_DNS_RESOURCE_RECORD_TYPE_AAAA]; - - [self of_asyncResolveHost: host - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: OF_DNS_RESOURCE_RECORD_TYPE_AAAA - runLoopMode: runLoopMode - target: context - selector: @selector(resolver: - didResolveDomainName: - answerRecords:authorityRecords: - additionalRecords:context: - exception:) - context: recordTypeNumber]; - } -#endif - - if (addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV4 || - addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) - [self of_asyncResolveHost: host - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: OF_DNS_RESOURCE_RECORD_TYPE_A - runLoopMode: runLoopMode - target: context - selector: @selector(resolver: - didResolveDomainName: - answerRecords:authorityRecords: - additionalRecords:context: - exception:) - context: [OFNumber numberWithInt: - OF_DNS_RESOURCE_RECORD_TYPE_A]]; - - objc_autoreleasePoolPop(pool); -} - -- (OFData *)resolveSocketAddressesForHost: (OFString *)host - addressFamily: (of_socket_address_family_t) - addressFamily -{ - void *pool = objc_autoreleasePoolPush(); - OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; - OFDNSResolverResolveSocketAddressesDelegate *delegate; - OFData *ret; - - delegate = [[[OFDNSResolverResolveSocketAddressesDelegate - alloc] init] autorelease]; - - [self asyncResolveSocketAddressesForHost: host - addressFamily: addressFamily - runLoopMode: resolveRunLoopMode - delegate: delegate]; - - while (!delegate->_done) - [runLoop runMode: resolveRunLoopMode - beforeDate: nil]; - - /* Cleanup */ - [runLoop runMode: resolveRunLoopMode - beforeDate: [OFDate date]]; - - if (delegate->_exception != nil) - @throw delegate->_exception; - - ret = [delegate->_socketAddresses retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; + response = [OFDNSResponse + responseWithDomainName: context->_query.domainName + answerRecords: answerRecords + authorityRecords: authorityRecords + additionalRecords: additionalRecords]; + } @catch (id e) { + exception = e; + } + + if (exception != nil) + response = nil; + + if ([context->_delegate respondsToSelector: + @selector(resolver:didPerformQuery:response:exception:)]) + [context->_delegate resolver: self + didPerformQuery: context->_query + response: response + exception: exception]; + + return false; +} + +- (void)asyncResolveAddressesForHost: (OFString *)host + delegate: (id )delegate +{ + [self asyncResolveAddressesForHost: host + addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY + runLoopMode: of_run_loop_mode_default + delegate: delegate]; +} + +- (void)asyncResolveAddressesForHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily + delegate: (id )delegate +{ + [self asyncResolveAddressesForHost: host + addressFamily: addressFamily + runLoopMode: of_run_loop_mode_default + delegate: delegate]; +} + +- (void)asyncResolveAddressesForHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily + runLoopMode: (of_run_loop_mode_t)runLoopMode + delegate: (id )delegate +{ + void *pool = objc_autoreleasePoolPush(); + OFHostAddressResolver *resolver = [[[OFHostAddressResolver alloc] + initWithHost: host + addressFamily: addressFamily + resolver: self + settings: _settings + runLoopMode: runLoopMode + delegate: delegate] autorelease]; + + [resolver asyncResolve]; + + objc_autoreleasePoolPop(pool); +} + +- (OFData *)resolveAddressesForHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily +{ + void *pool = objc_autoreleasePoolPush(); + OFHostAddressResolver *resolver = [[[OFHostAddressResolver alloc] + initWithHost: host + addressFamily: addressFamily + resolver: self + settings: _settings + runLoopMode: nil + delegate: nil] autorelease]; + OFData *addresses = [resolver resolve]; + + [addresses retain]; + + objc_autoreleasePoolPop(pool); + + return [addresses autorelease]; } - (void)close { void *pool = objc_autoreleasePoolPush(); - OFEnumerator OF_GENERIC(OFDNSResolverQuery *) *enumerator; - OFDNSResolverQuery *query; + OFEnumerator OF_GENERIC(OFDNSResolverContext *) *enumerator; + OFDNSResolverContext *context; [_IPv4Socket cancelAsyncRequests]; [_IPv4Socket release]; _IPv4Socket = nil; @@ -2272,24 +1071,25 @@ [_IPv6Socket release]; _IPv6Socket = nil; #endif enumerator = [_queries objectEnumerator]; - while ((query = [enumerator nextObject]) != nil) { - OFResolveHostFailedException *exception; - - exception = [OFResolveHostFailedException - exceptionWithHost: query->_host - recordClass: query->_recordClass - recordType: query->_recordType - error: OF_DNS_RESOLVER_ERROR_CANCELED]; - - callback(query->_target, query->_selector, self, - query->_domainName, nil, nil, nil, query->_context, - exception); + while ((context = [enumerator nextObject]) != nil) { + OFDNSQueryFailedException *exception; + + exception = [OFDNSQueryFailedException + exceptionWithQuery: context->_query + error: OF_DNS_RESOLVER_ERROR_CANCELED]; + + if ([context->_delegate respondsToSelector: + @selector(resolver:didPerformQuery:response:exception:)]) + [context->_delegate resolver: self + didPerformQuery: context->_query + response: nil + exception: exception]; } [_queries removeAllObjects]; objc_autoreleasePoolPop(pool); } @end ADDED src/OFDNSResolverSettings.h Index: src/OFDNSResolverSettings.h ================================================================== --- src/OFDNSResolverSettings.h +++ src/OFDNSResolverSettings.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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. + */ + +#import "OFObject.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFArray OF_GENERIC(ObjectType); +@class OFDate; +@class OFDictionary OF_GENERIC(KeyType, ObjectType); + +@interface OFDNSResolverSettings: OFObject +{ +@public + OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC(OFString *) *) + *_staticHosts; + OFArray OF_GENERIC(OFString *) *_nameServers; + OFString *_Nullable _localDomain; + OFArray OF_GENERIC(OFString *) *_searchDomains; + of_time_interval_t _timeout; + unsigned int _maxAttempts, _minNumberOfDotsInAbsoluteName; + bool _usesTCP; + of_time_interval_t _configReloadInterval; +@protected + OFDate *_lastConfigReload; +} + +- (void)reload; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFDNSResolverSettings.m Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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" + +#include "unistd_wrapper.h" + +#import "OFDNSResolverSettings.h" +#import "OFArray.h" +#import "OFCharacterSet.h" +#import "OFDate.h" +#import "OFDictionary.h" +#import "OFFile.h" +#import "OFLocale.h" +#import "OFString.h" +#ifdef OF_WINDOWS +# import "OFWindowsRegistryKey.h" +#endif + +#import "OFInvalidFormatException.h" +#import "OFOpenItemFailedException.h" +#import "OFOutOfMemoryException.h" + +#ifdef OF_WINDOWS +# define interface struct +# include +# undef interface +#endif + +#ifdef OF_NINTENDO_3DS +# include <3ds.h> +#endif + +#import "socket_helpers.h" + +#if defined(OF_HAIKU) +# define HOSTS_PATH @"/system/settings/network/hosts" +# define RESOLV_CONF_PATH @"/system/settings/network/resolv.conf" +#elif defined(OF_MORPHOS) +# define HOSTS_PATH @"ENV:sys/net/hosts" +# define RESOLV_CONF_PATH @"ENV:sys/net/resolv.conf" +#elif defined(OF_AMIGAOS4) +# define HOSTS_PATH @"DEVS:Internet/hosts" +#elif defined(OF_AMIGAOS) +# define HOSTS_PATH @"AmiTCP:db/hosts" +# define RESOLV_CONF_PATH @"AmiTCP:db/resolv.conf" +#else +# define HOSTS_PATH @"/etc/hosts" +# define RESOLV_CONF_PATH @"/etc/resolv.conf" +#endif + +#ifndef OF_WII +static OFString * +domainFromHostname(void) +{ + char hostname[256]; + OFString *domain; + + if (gethostname(hostname, 256) != 0) + return nil; + + domain = [OFString stringWithCString: hostname + encoding: [OFLocale encoding]]; + + @try { + of_socket_address_parse_ip(domain, 0); + + /* + * If we are still here, the host name is a valid IP address. + * We can't use that as local domain. + */ + return nil; + } @catch (OFInvalidFormatException *e) { + /* Not an IP address -> we can use it if it contains a dot. */ + size_t pos = [domain rangeOfString: @"."].location; + + if (pos == OF_NOT_FOUND) + return nil; + + return [domain substringWithRange: + of_range(pos + 1, domain.length - pos - 1)]; + } +} +#endif + +@implementation OFDNSResolverSettings +- (void)dealloc +{ + [_staticHosts release]; + [_nameServers release]; + [_localDomain release]; + [_searchDomains release]; + [_lastConfigReload release]; + + [super dealloc]; +} + +- (id)copy +{ + OFDNSResolverSettings *copy = [[OFDNSResolverSettings alloc] init]; + + @try { + copy->_staticHosts = [_staticHosts copy]; + copy->_nameServers = [_nameServers copy]; + copy->_localDomain = [_localDomain copy]; + copy->_searchDomains = [_searchDomains copy]; + copy->_timeout = _timeout; + copy->_maxAttempts = _maxAttempts; + copy->_minNumberOfDotsInAbsoluteName = + _minNumberOfDotsInAbsoluteName; + copy->_usesTCP = _usesTCP; + copy->_configReloadInterval = _configReloadInterval; + copy->_lastConfigReload = [_lastConfigReload copy]; + } @catch (id e) { + [copy release]; + @throw e; + } + + return copy; +} + +- (void)setDefaults +{ + [_staticHosts release]; + _staticHosts = nil; + + [_nameServers release]; + _nameServers = nil; + + [_localDomain release]; + _localDomain = nil; + + [_searchDomains release]; + _searchDomains = nil; + + _timeout = 2; + _maxAttempts = 3; + _minNumberOfDotsInAbsoluteName = 1; + _usesTCP = false; +#ifndef OF_NINTENDO_3DS + _configReloadInterval = 2; +#else + _configReloadInterval = 0; +#endif +} + +#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_3DS) +- (void)parseHosts: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFCharacterSet *whitespaceCharacterSet = + [OFCharacterSet whitespaceCharacterSet]; + OFMutableDictionary *staticHosts; + OFFile *file; + OFString *line; + OFEnumerator *enumerator; + OFMutableArray *addresses; + + @try { + file = [OFFile fileWithPath: path + mode: @"r"]; + } @catch (OFOpenItemFailedException *e) { + objc_autoreleasePoolPop(pool); + return; + } + + staticHosts = [OFMutableDictionary dictionary]; + + while ((line = [file readLine]) != nil) { + void *pool2 = objc_autoreleasePoolPush(); + OFArray *components, *hosts; + size_t pos; + OFString *address; + + pos = [line rangeOfString: @"#"].location; + if (pos != OF_NOT_FOUND) + line = [line substringWithRange: of_range(0, pos)]; + + components = [line + componentsSeparatedByCharactersInSet: whitespaceCharacterSet + options: OF_STRING_SKIP_EMPTY]; + + if (components.count < 2) { + objc_autoreleasePoolPop(pool2); + continue; + } + + address = components.firstObject; + hosts = [components objectsInRange: + of_range(1, components.count - 1)]; + + for (OFString *host in hosts) { + addresses = [staticHosts objectForKey: host]; + + if (addresses == nil) { + addresses = [OFMutableArray array]; + [staticHosts setObject: addresses + forKey: host]; + } + + [addresses addObject: address]; + } + + objc_autoreleasePoolPop(pool2); + } + + enumerator = [staticHosts objectEnumerator]; + while ((addresses = [enumerator nextObject]) != nil) + [addresses makeImmutable]; + + [staticHosts makeImmutable]; + + [_staticHosts release]; + _staticHosts = [staticHosts copy]; + + objc_autoreleasePoolPop(pool); +} + +# if !defined(OF_WINDOWS) && !defined(OF_AMIGAOS4) +- (void)parseResolvConfOption: (OFString *)option +{ + @try { + if ([option hasPrefix: @"ndots:"]) { + option = [option substringWithRange: + of_range(6, option.length - 6)]; + + _minNumberOfDotsInAbsoluteName = + (unsigned int)option.decimalValue; + } else if ([option hasPrefix: @"timeout:"]) { + option = [option substringWithRange: + of_range(8, option.length - 8)]; + + _timeout = option.decimalValue; + } else if ([option hasPrefix: @"attempts:"]) { + option = [option substringWithRange: + of_range(9, option.length - 9)]; + + _maxAttempts = (unsigned int)option.decimalValue; + } else if ([option hasPrefix: @"reload-period:"]) { + option = [option substringWithRange: + of_range(14, option.length - 14)]; + + _configReloadInterval = option.decimalValue; + } else if ([option isEqual: @"tcp"]) + _usesTCP = true; + } @catch (OFInvalidFormatException *e) { + } +} + +- (void)parseResolvConf: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFCharacterSet *whitespaceCharacterSet = + [OFCharacterSet whitespaceCharacterSet]; + OFCharacterSet *commentCharacters = [OFCharacterSet + characterSetWithCharactersInString: @"#;"]; + OFMutableArray *nameServers = [[_nameServers mutableCopy] autorelease]; + OFFile *file; + OFString *line; + + @try { + file = [OFFile fileWithPath: path + mode: @"r"]; + } @catch (OFOpenItemFailedException *e) { + objc_autoreleasePoolPop(pool); + return; + } + + if (nameServers == nil) + nameServers = [OFMutableArray array]; + + while ((line = [file readLine]) != nil) { + void *pool2 = objc_autoreleasePoolPush(); + size_t pos; + OFArray *components, *arguments; + OFString *option; + + pos = [line indexOfCharacterFromSet: commentCharacters]; + if (pos != OF_NOT_FOUND) + line = [line substringWithRange: of_range(0, pos)]; + + components = [line + componentsSeparatedByCharactersInSet: whitespaceCharacterSet + options: OF_STRING_SKIP_EMPTY]; + + if (components.count < 2) { + objc_autoreleasePoolPop(pool2); + continue; + } + + option = components.firstObject; + arguments = [components objectsInRange: + of_range(1, components.count - 1)]; + + if ([option isEqual: @"nameserver"]) { + if (arguments.count != 1) { + objc_autoreleasePoolPop(pool2); + continue; + } + + [nameServers addObject: [arguments firstObject]]; + } else if ([option isEqual: @"domain"]) { + if (arguments.count != 1) { + objc_autoreleasePoolPop(pool2); + continue; + } + + [_localDomain release]; + _localDomain = [arguments.firstObject copy]; + } else if ([option isEqual: @"search"]) { + [_searchDomains release]; + _searchDomains = [arguments copy]; + } else if ([option isEqual: @"options"]) + for (OFString *argument in arguments) + [self parseResolvConfOption: argument]; + + objc_autoreleasePoolPop(pool2); + } + + [nameServers makeImmutable]; + + [_nameServers release]; + _nameServers = [nameServers copy]; + + objc_autoreleasePoolPop(pool); +} +# endif +#endif + +#ifdef OF_WINDOWS +- (void)obtainWindowsSystemConfig +{ + of_string_encoding_t encoding = [OFLocale encoding]; + OFMutableArray *nameServers; + /* + * We need more space than FIXED_INFO in case we have more than one + * name server, but we also want it to be properly aligned, meaning we + * can't just get a buffer of bytes. Thus, we just get space for 8. + */ + FIXED_INFO fixedInfo[8]; + ULONG length = sizeof(fixedInfo); + PIP_ADDR_STRING iter; + + if (GetNetworkParams(fixedInfo, &length) != ERROR_SUCCESS) + return; + + nameServers = [OFMutableArray array]; + + for (iter = &fixedInfo->DnsServerList; iter != NULL; iter = iter->Next) + [nameServers addObject: + [OFString stringWithCString: iter->IpAddress.String + encoding: encoding]]; + + if (nameServers.count > 0) { + [nameServers makeImmutable]; + _nameServers = [nameServers copy]; + } + + if (fixedInfo->DomainName[0] != '\0') + _localDomain = [[OFString alloc] + initWithCString: fixedInfo->DomainName + encoding: encoding]; +} +#endif + +#ifdef OF_AMIGAOS4 +- (void)obtainAmigaOS4SystemConfig +{ + OFMutableArray *nameServers = [OFMutableArray array]; + of_string_encoding_t encoding = [OFLocale encoding]; + struct List *nameServerList = ObtainDomainNameServerList(); + char buffer[MAXHOSTNAMELEN]; + + if (nameServerList == NULL) + @throw [OFOutOfMemoryException exception]; + + @try { + struct DomainNameServerNode *iter = + (struct DomainNameServerNode *)&nameServerList->lh_Head; + + while (iter->dnsn_MinNode.mln_Succ != NULL) { + if (iter->dnsn_UseCount != 0 && + iter->dnsn_Address != NULL) { + OFString *address = [OFString + stringWithCString: iter->dnsn_Address + encoding: encoding]; + + [nameServers addObject: address]; + } + + iter = (struct DomainNameServerNode *) + iter->dnsn_MinNode.mln_Succ; + } + } @finally { + ReleaseDomainNameServerList(nameServerList); + } + + if (nameServers.count > 0) { + [nameServers makeImmutable]; + _nameServers = [nameServers copy]; + } + + if (GetDefaultDomainName(buffer, sizeof(buffer))) + _localDomain = [[OFString alloc] initWithCString: buffer + encoding: encoding]; +} +#endif + +#ifdef OF_NINTENDO_3DS +- (void)obtainNintendo3DSSytemConfig +{ + OFMutableArray *nameServers = [OFMutableArray array]; + union { + /* + * For some unknown reason, this needs a 336 bytes buffer and + * always returns 336 bytes. + */ + char bytes[336]; + SOCU_DNSTableEntry entries[2]; + } buffer; + socklen_t optLen = sizeof(buffer); + + if (SOCU_GetNetworkOpt(SOL_CONFIG, NETOPT_DNS_TABLE, + &buffer, &optLen) != 0) + return; + + /* + * We're fine if this gets smaller in a future release (unlikely), as + * long as two entries still fit. + */ + if (optLen < sizeof(buffer.entries)) + return; + + for (uint_fast8_t i = 0; i < 2; i++) { + uint32_t ip = OF_BSWAP32_IF_LE(buffer.entries[i].ip.s_addr); + + if (ip == 0) + continue; + + [nameServers addObject: [OFString stringWithFormat: + @"%u.%u.%u.%u", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, ip & 0xFF]]; + } + + if (nameServers.count > 0) { + [nameServers makeImmutable]; + _nameServers = [nameServers copy]; + } +} +#endif + +- (void)reload +{ + void *pool; +#ifdef OF_WINDOWS + OFString *path; +#endif + + /* + * TODO: Rather than reparsing every time, check what actually changed + * (mtime) and only reset those. + */ + + if (_lastConfigReload != nil && _configReloadInterval > 0 && + _lastConfigReload.timeIntervalSinceNow < _configReloadInterval) + return; + + pool = objc_autoreleasePoolPush(); + + [self setDefaults]; + +#if defined(OF_WINDOWS) +# ifdef OF_HAVE_FILES + path = [[OFWindowsRegistryKey localMachineKey] + stringForValue: @"DataBasePath" + subkeyPath: @"SYSTEM\\CurrentControlSet\\Services\\" + @"Tcpip\\Parameters"]; + path = [path stringByAppendingPathComponent: @"hosts"]; + + if (path != nil) + [self parseHosts: path]; +# endif + + [self obtainWindowsSystemConfig]; +#elif defined(OF_AMIGAOS4) + [self parseHosts: HOSTS_PATH]; + [self obtainAmigaOS4SystemConfig]; +#elif defined(OF_NINTENDO_3DS) + [self obtainNintendo3DSSytemConfig]; +#elif defined(OF_HAVE_FILES) + [self parseHosts: HOSTS_PATH]; + [self parseResolvConf: RESOLV_CONF_PATH]; +#endif + + if (_staticHosts == nil) { + OFArray *localhost = +#ifdef OF_HAVE_IPV6 + [OFArray arrayWithObjects: @"::1", @"127.0.0.1", nil]; +#else + [OFArray arrayWithObject: @"127.0.0.1"]; +#endif + + _staticHosts = [[OFDictionary alloc] + initWithObject: localhost + forKey: @"localhost"]; + } + + if (_nameServers == nil) +#ifdef OF_HAVE_IPV6 + _nameServers = [[OFArray alloc] + initWithObjects: @"127.0.0.1", @"::1", nil]; +#else + _nameServers = [[OFArray alloc] initWithObject: @"127.0.0.1"]; +#endif + +#ifndef OF_WII + if (_localDomain == nil) + _localDomain = [domainFromHostname() copy]; +#endif + + if (_searchDomains == nil) { + if (_localDomain != nil) + _searchDomains = [[OFArray alloc] + initWithObject: _localDomain]; + else + _searchDomains = [[OFArray alloc] init]; + } + + objc_autoreleasePoolPop(pool); +} +@end Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -25,59 +25,59 @@ /*! @file */ @class OFData; /*! - * @brief The class of a DNS resource record. + * @brief The DNS class. */ typedef enum { /*! IN */ - OF_DNS_RESOURCE_RECORD_CLASS_IN = 1, + OF_DNS_CLASS_IN = 1, /*! Any class. Only for queries. */ - OF_DNS_RESOURCE_RECORD_CLASS_ANY = 255, -} of_dns_resource_record_class_t; + OF_DNS_CLASS_ANY = 255, +} of_dns_class_t; /*! * @brief The type of a DNS resource record. */ typedef enum { /*! A */ - OF_DNS_RESOURCE_RECORD_TYPE_A = 1, + OF_DNS_RECORD_TYPE_A = 1, /*! NS */ - OF_DNS_RESOURCE_RECORD_TYPE_NS = 2, + OF_DNS_RECORD_TYPE_NS = 2, /*! CNAME */ - OF_DNS_RESOURCE_RECORD_TYPE_CNAME = 5, + OF_DNS_RECORD_TYPE_CNAME = 5, /*! SOA */ - OF_DNS_RESOURCE_RECORD_TYPE_SOA = 6, + OF_DNS_RECORD_TYPE_SOA = 6, /*! PTR */ - OF_DNS_RESOURCE_RECORD_TYPE_PTR = 12, + OF_DNS_RECORD_TYPE_PTR = 12, /*! HINFO */ - OF_DNS_RESOURCE_RECORD_TYPE_HINFO = 13, + OF_DNS_RECORD_TYPE_HINFO = 13, /*! MX */ - OF_DNS_RESOURCE_RECORD_TYPE_MX = 15, + OF_DNS_RECORD_TYPE_MX = 15, /*! TXT */ - OF_DNS_RESOURCE_RECORD_TYPE_TXT = 16, + OF_DNS_RECORD_TYPE_TXT = 16, /*! RP */ - OF_DNS_RESOURCE_RECORD_TYPE_RP = 17, + OF_DNS_RECORD_TYPE_RP = 17, /*! AAAA */ - OF_DNS_RESOURCE_RECORD_TYPE_AAAA = 28, + OF_DNS_RECORD_TYPE_AAAA = 28, /*! SRV */ - OF_DNS_RESOURCE_RECORD_TYPE_SRV = 33, + OF_DNS_RECORD_TYPE_SRV = 33, /*! All types. Only for queries. */ - OF_DNS_RESOURCE_RECORD_TYPE_ALL = 255, -} of_dns_resource_record_type_t; + OF_DNS_RECORD_TYPE_ALL = 255, +} of_dns_record_type_t; /*! * @class OFDNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h * * @brief A class representing a DNS resource record. */ @interface OFDNSResourceRecord: OFObject { OFString *_name; - of_dns_resource_record_class_t _recordClass; - of_dns_resource_record_type_t _recordType; + of_dns_class_t _DNSClass; + of_dns_record_type_t _recordType; uint32_t _TTL; OF_RESERVE_IVARS(4) } /** @@ -84,18 +84,18 @@ * @brief The domain name to which the resource record belongs. */ @property (readonly, nonatomic) OFString *name; /*! - * @brief The resource record class code. + * @brief The DNS class. */ -@property (readonly, nonatomic) of_dns_resource_record_class_t recordClass; +@property (readonly, nonatomic) of_dns_class_t DNSClass; /*! * @brief The resource record type code. */ -@property (readonly, nonatomic) of_dns_resource_record_type_t recordType; +@property (readonly, nonatomic) of_dns_record_type_t recordType; /*! * @brief The number of seconds after which the resource record should be * discarded from the cache. */ @@ -104,18 +104,18 @@ /*! * @brief Initializes an already allocated OFDNSResourceRecord with the * specified name, class, type, data and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param recordType The type code for the resource record * @param TTL The time to live for the resource record * @return An initialized OFDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /*! * @class OFADNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h @@ -132,12 +132,12 @@ * @brief The IPv4 address of the resource record. */ @property (readonly, nonatomic) const of_socket_address_t *address; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFADNSResourceRecord with the * specified name, class, address and time to live. @@ -168,12 +168,12 @@ * @brief The IPv6 address of the resource record. */ @property (readonly, nonatomic) const of_socket_address_t *address; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFAAAADNSResourceRecord with the * specified name, class, address and time to live. @@ -204,26 +204,26 @@ * @brief The alias of the resource record. */ @property (readonly, nonatomic) OFString *alias; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFCNAMEDNSResourceRecord with the * specified name, class, alias and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param alias The alias for the resource record * @param TTL The time to live for the resource record * @return An initialized OFCNAMEDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass alias: (OFString *)alias TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /*! @@ -247,27 +247,27 @@ * @brief The OS of the host info of the resource record. */ @property (readonly, nonatomic) OFString *OS; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFHINFODNSResourceRecord with the * specified name, class, domain name and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param CPU The CPU of the host info for the resource record * @param OS The OS of the host info for the resource record * @param TTL The time to live for the resource record * @return An initialized OFHINFODNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass CPU: (OFString *)CPU OS: (OFString *)OS TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end @@ -293,27 +293,27 @@ * @brief The mail exchange of the resource record. */ @property (readonly, nonatomic) OFString *mailExchange; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFMXDNSResourceRecord with the * specified name, class, preference, mail exchange and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param preference The preference for the resource record * @param mailExchange The mail exchange for the resource record * @param TTL The time to live for the resource record * @return An initialized OFMXDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass preference: (uint16_t)preference mailExchange: (OFString *)mailExchange TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end @@ -333,26 +333,26 @@ * @brief The authoritative host of the resource record. */ @property (readonly, nonatomic) OFString *authoritativeHost; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFNSDNSResourceRecord with the * specified name, class, authoritative host and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param authoritativeHost The authoritative host for the resource record * @param TTL The time to live for the resource record * @return An initialized OFNSDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass authoritativeHost: (OFString *)authoritativeHost TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /*! @@ -371,26 +371,26 @@ * @brief The domain name of the resource record. */ @property (readonly, nonatomic) OFString *domainName; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFPTRDNSResourceRecord with the * specified name, class, domain name and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param domainName The domain name for the resource record * @param TTL The time to live for the resource record * @return An initialized OFPTRDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass domainName: (OFString *)domainName TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end /*! @@ -415,28 +415,28 @@ * person of the resource record. */ @property (readonly, nonatomic) OFString *TXTDomainName; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFRPDNSResourceRecord with the * specified name, class, alias and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param mailbox The mailbox of the responsible person of the resource record * @param TXTDomainName A domain name that contains a TXT resource record for * the responsible person of the resource record * @param TTL The time to live for the resource record * @return An initialized OFRPDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass mailbox: (OFString *)mailbox TXTDomainName: (OFString *)TXTDomainName TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end @@ -488,20 +488,20 @@ * @brief The minimum TTL of the zone. */ @property (readonly, nonatomic) uint32_t minTTL; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFSOADNSResourceRecord with the * specified name, class, text data and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param primaryNameServer The the primary name server for the zone * @param responsiblePerson The mailbox of the person responsible for the zone * @param serialNumber The serial number of the original copy of the zone * @param refreshInterval The refresh interval of the zone * @param retryInterval The retry interval of the zone @@ -509,11 +509,11 @@ * @param minTTL The minimum TTL of the zone * @param TTL The time to live for the resource record * @return An initialized OFSOADNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass primaryNameServer: (OFString *)primaryNameServer responsiblePerson: (OFString *)responsiblePerson serialNumber: (uint32_t)serialNumber refreshInterval: (uint32_t)refreshInterval retryInterval: (uint32_t)retryInterval @@ -555,12 +555,12 @@ * @brief The port on the target of the resource record. */ @property (readonly, nonatomic) uint16_t port; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFSRVDNSResourceRecord with the * specified name, class, preference, mail exchange and time to live. @@ -597,41 +597,38 @@ * @brief The text of the resource record. */ @property (readonly, nonatomic) OFData *textData; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFTXTDNSResourceRecord with the * specified name, class, text data and time to live. * * @param name The name for the resource record - * @param recordClass The class code for the resource record + * @param DNSClass The class code for the resource record * @param textData The data for the resource record * @param TTL The time to live for the resource record * @return An initialized OFTXTDNSResourceRecord */ - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass textData: (OFData *)textData TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end #ifdef __cplusplus extern "C" { #endif -extern OFString *_Nonnull of_dns_resource_record_class_to_string( - of_dns_resource_record_class_t recordClass); -extern OFString *_Nonnull of_dns_resource_record_type_to_string( - of_dns_resource_record_type_t recordType); -extern of_dns_resource_record_class_t of_dns_resource_record_class_parse( - OFString *_Nonnull string); -extern of_dns_resource_record_type_t of_dns_resource_record_type_parse( - OFString *_Nonnull string); +extern OFString *_Nonnull of_dns_class_to_string(of_dns_class_t DNSClass); +extern OFString *_Nonnull of_dns_record_type_to_string( + of_dns_record_type_t recordType); +extern of_dns_class_t of_dns_class_parse(OFString *_Nonnull string); +extern of_dns_record_type_t of_dns_record_type_parse(OFString *_Nonnull string); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -22,126 +22,134 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" OFString * -of_dns_resource_record_class_to_string( - of_dns_resource_record_class_t recordClass) +of_dns_class_to_string(of_dns_class_t DNSClass) { - switch (recordClass) { - case OF_DNS_RESOURCE_RECORD_CLASS_IN: + switch (DNSClass) { + case OF_DNS_CLASS_IN: return @"IN"; - case OF_DNS_RESOURCE_RECORD_CLASS_ANY: + case OF_DNS_CLASS_ANY: return @"any"; default: - return [OFString stringWithFormat: @"%u", recordClass]; + return [OFString stringWithFormat: @"%u", DNSClass]; } } OFString * -of_dns_resource_record_type_to_string(of_dns_resource_record_type_t recordType) +of_dns_record_type_to_string(of_dns_record_type_t recordType) { switch (recordType) { - case OF_DNS_RESOURCE_RECORD_TYPE_A: + case OF_DNS_RECORD_TYPE_A: return @"A"; - case OF_DNS_RESOURCE_RECORD_TYPE_NS: + case OF_DNS_RECORD_TYPE_NS: return @"NS"; - case OF_DNS_RESOURCE_RECORD_TYPE_CNAME: + case OF_DNS_RECORD_TYPE_CNAME: return @"CNAME"; - case OF_DNS_RESOURCE_RECORD_TYPE_SOA: + case OF_DNS_RECORD_TYPE_SOA: return @"SOA"; - case OF_DNS_RESOURCE_RECORD_TYPE_PTR: + case OF_DNS_RECORD_TYPE_PTR: return @"PTR"; - case OF_DNS_RESOURCE_RECORD_TYPE_HINFO: + case OF_DNS_RECORD_TYPE_HINFO: return @"HINFO"; - case OF_DNS_RESOURCE_RECORD_TYPE_MX: + case OF_DNS_RECORD_TYPE_MX: return @"MX"; - case OF_DNS_RESOURCE_RECORD_TYPE_TXT: + case OF_DNS_RECORD_TYPE_TXT: return @"TXT"; - case OF_DNS_RESOURCE_RECORD_TYPE_RP: + case OF_DNS_RECORD_TYPE_RP: return @"RP"; - case OF_DNS_RESOURCE_RECORD_TYPE_AAAA: + case OF_DNS_RECORD_TYPE_AAAA: return @"AAAA"; - case OF_DNS_RESOURCE_RECORD_TYPE_SRV: + case OF_DNS_RECORD_TYPE_SRV: return @"SRV"; - case OF_DNS_RESOURCE_RECORD_TYPE_ALL: + case OF_DNS_RECORD_TYPE_ALL: return @"all"; default: return [OFString stringWithFormat: @"%u", recordType]; } } -of_dns_resource_record_class_t of_dns_resource_record_class_parse( - OFString *string) +of_dns_class_t of_dns_class_parse(OFString *string) { void *pool = objc_autoreleasePoolPush(); - of_dns_resource_record_class_t recordClass; + of_dns_class_t DNSClass; string = string.uppercaseString; if ([string isEqual: @"IN"]) - recordClass = OF_DNS_RESOURCE_RECORD_CLASS_IN; - else - @throw [OFInvalidArgumentException exception]; + DNSClass = OF_DNS_CLASS_IN; + else { + @try { + DNSClass = (of_dns_class_t)[string decimalValue]; + } @catch (OFInvalidFormatException *e) { + @throw [OFInvalidArgumentException exception]; + } + } objc_autoreleasePoolPop(pool); - return recordClass; + return DNSClass; } -of_dns_resource_record_type_t of_dns_resource_record_type_parse( - OFString *string) +of_dns_record_type_t of_dns_record_type_parse(OFString *string) { void *pool = objc_autoreleasePoolPush(); - of_dns_resource_record_type_t recordType; + of_dns_record_type_t recordType; string = string.uppercaseString; if ([string isEqual: @"A"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_A; + recordType = OF_DNS_RECORD_TYPE_A; else if ([string isEqual: @"NS"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_NS; + recordType = OF_DNS_RECORD_TYPE_NS; else if ([string isEqual: @"CNAME"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_CNAME; + recordType = OF_DNS_RECORD_TYPE_CNAME; else if ([string isEqual: @"SOA"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_SOA; + recordType = OF_DNS_RECORD_TYPE_SOA; else if ([string isEqual: @"PTR"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_PTR; + recordType = OF_DNS_RECORD_TYPE_PTR; else if ([string isEqual: @"HINFO"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_HINFO; + recordType = OF_DNS_RECORD_TYPE_HINFO; else if ([string isEqual: @"MX"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_MX; + recordType = OF_DNS_RECORD_TYPE_MX; else if ([string isEqual: @"TXT"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_TXT; + recordType = OF_DNS_RECORD_TYPE_TXT; else if ([string isEqual: @"RP"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_RP; + recordType = OF_DNS_RECORD_TYPE_RP; else if ([string isEqual: @"AAAA"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_AAAA; + recordType = OF_DNS_RECORD_TYPE_AAAA; else if ([string isEqual: @"SRV"]) - recordType = OF_DNS_RESOURCE_RECORD_TYPE_SRV; - else - @throw [OFInvalidArgumentException exception]; + recordType = OF_DNS_RECORD_TYPE_SRV; + else { + @try { + recordType = + (of_dns_record_type_t)[string decimalValue]; + } @catch (OFInvalidFormatException *e) { + @throw [OFInvalidArgumentException exception]; + } + } objc_autoreleasePoolPop(pool); return recordType; } @implementation OFDNSResourceRecord -@synthesize name = _name, recordClass = _recordClass, recordType = _recordType; +@synthesize name = _name, DNSClass = _DNSClass, recordType = _recordType; @synthesize TTL = _TTL; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { self = [super init]; @try { _name = [name copy]; - _recordClass = recordClass; + _DNSClass = DNSClass; _recordType = recordType; _TTL = TTL; } @catch (id e) { [self release]; @throw e; @@ -169,20 +177,19 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tType = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), - of_dns_resource_record_type_to_string(_recordType), _TTL]; + self.className, _name, of_dns_class_to_string(_DNSClass), + of_dns_record_type_to_string(_recordType), _TTL]; } @end @implementation OFADNSResourceRecord - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } @@ -189,12 +196,12 @@ - (instancetype)initWithName: (OFString *)name address: (const of_socket_address_t *)address TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: OF_DNS_RESOURCE_RECORD_TYPE_A + DNSClass: OF_DNS_CLASS_IN + recordType: OF_DNS_RECORD_TYPE_A TTL: TTL]; _address = *address; return self; @@ -203,29 +210,32 @@ - (const of_socket_address_t *)address { return &_address; } -- (bool)isEqual: (id)otherObject -{ - OFADNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFADNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (!of_socket_address_equal(&otherRecord->_address, &_address)) +- (bool)isEqual: (id)object +{ + OFADNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFADNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (!of_socket_address_equal(&record->_address, &_address)) return false; return true; } @@ -234,12 +244,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address)); OF_HASH_FINALIZE(hash); @@ -260,12 +270,12 @@ } @end @implementation OFAAAADNSResourceRecord - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } @@ -272,12 +282,12 @@ - (instancetype)initWithName: (OFString *)name address: (const of_socket_address_t *)address TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: OF_DNS_RESOURCE_RECORD_TYPE_AAAA + DNSClass: OF_DNS_CLASS_IN + recordType: OF_DNS_RECORD_TYPE_AAAA TTL: TTL]; _address = *address; return self; @@ -286,29 +296,32 @@ - (const of_socket_address_t *)address { return &_address; } -- (bool)isEqual: (id)otherObject -{ - OFAAAADNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFAAAADNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (!of_socket_address_equal(&otherRecord->_address, &_address)) +- (bool)isEqual: (id)object +{ + OFAAAADNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFAAAADNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (!of_socket_address_equal(&record->_address, &_address)) return false; return true; } @@ -317,12 +330,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, of_socket_address_hash(&_address)); OF_HASH_FINALIZE(hash); @@ -345,25 +358,25 @@ @implementation OFCNAMEDNSResourceRecord @synthesize alias = _alias; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass alias: (OFString *)alias TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_CNAME + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_CNAME TTL: TTL]; @try { _alias = [alias copy]; } @catch (id e) { @@ -379,30 +392,32 @@ [_alias release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFCNAMEDNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFCNAMEDNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_alias != _alias && - ![otherRecord->_alias isEqual: _alias]) +- (bool)isEqual: (id)object +{ + OFCNAMEDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFCNAMEDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_alias != _alias && ![record->_alias isEqual: _alias]) return false; return true; } @@ -411,12 +426,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, _alias.hash); OF_HASH_FINALIZE(hash); @@ -431,35 +446,35 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tAlias = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), _alias, _TTL]; + self.className, _name, of_dns_class_to_string(_DNSClass), _alias, + _TTL]; } @end @implementation OFHINFODNSResourceRecord @synthesize CPU = _CPU, OS = _OS; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass CPU: (OFString *)CPU OS: (OFString *)OS TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_HINFO + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_HINFO TTL: TTL]; @try { _CPU = [CPU copy]; _OS = [OS copy]; @@ -477,32 +492,35 @@ [_OS release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFHINFODNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFHINFODNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_CPU != _CPU && ![otherRecord->_CPU isEqual: _CPU]) - return false; - - if (otherRecord->_OS != _OS && ![otherRecord->_OS isEqual: _OS]) +- (bool)isEqual: (id)object +{ + OFHINFODNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFHINFODNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_CPU != _CPU && ![record->_CPU isEqual: _CPU]) + return false; + + if (record->_OS != _OS && ![record->_OS isEqual: _OS]) return false; return true; } @@ -511,12 +529,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, _CPU.hash); OF_HASH_ADD_HASH(hash, _OS.hash); @@ -533,36 +551,35 @@ @"\tClass = %@\n" @"\tCPU = %@\n" @"\tOS = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), _CPU, _OS, + self.className, _name, of_dns_class_to_string(_DNSClass), _CPU, _OS, _TTL]; } @end @implementation OFMXDNSResourceRecord @synthesize preference = _preference, mailExchange = _mailExchange; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass preference: (uint16_t)preference mailExchange: (OFString *)mailExchange TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_MX + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_MX TTL: TTL]; @try { _preference = preference; _mailExchange = [mailExchange copy]; @@ -579,33 +596,36 @@ [_mailExchange release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFMXDNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFMXDNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_preference != _preference) - return false; - - if (otherRecord->_mailExchange != _mailExchange && - ![otherRecord->_mailExchange isEqual: _mailExchange]) +- (bool)isEqual: (id)object +{ + OFMXDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFMXDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_preference != _preference) + return false; + + if (record->_mailExchange != _mailExchange && + ![record->_mailExchange isEqual: _mailExchange]) return false; return true; } @@ -614,12 +634,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD(hash, _preference >> 8); OF_HASH_ADD(hash, _preference); OF_HASH_ADD_HASH(hash, _mailExchange.hash); @@ -637,35 +657,34 @@ @"\tClass = %@\n" @"\tPreference = %" PRIu16 "\n" @"\tMail Exchange = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), _preference, - _mailExchange, _TTL]; + self.className, _name, of_dns_class_to_string(_DNSClass), + _preference, _mailExchange, _TTL]; } @end @implementation OFNSDNSResourceRecord @synthesize authoritativeHost = _authoritativeHost; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass authoritativeHost: (OFString *)authoritativeHost TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_NS + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_NS TTL: TTL]; @try { _authoritativeHost = [authoritativeHost copy]; } @catch (id e) { @@ -681,30 +700,33 @@ [_authoritativeHost release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFNSDNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFNSDNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_authoritativeHost != _authoritativeHost && - ![otherRecord->_authoritativeHost isEqual: _authoritativeHost]) +- (bool)isEqual: (id)object +{ + OFNSDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFNSDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_authoritativeHost != _authoritativeHost && + ![record->_authoritativeHost isEqual: _authoritativeHost]) return false; return true; } @@ -713,12 +735,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, _authoritativeHost.hash); OF_HASH_FINALIZE(hash); @@ -733,35 +755,34 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tAuthoritative Host = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), + self.className, _name, of_dns_class_to_string(_DNSClass), _authoritativeHost, _TTL]; } @end @implementation OFPTRDNSResourceRecord @synthesize domainName = _domainName; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass domainName: (OFString *)domainName TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_PTR + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_PTR TTL: TTL]; @try { _domainName = [domainName copy]; } @catch (id e) { @@ -777,30 +798,33 @@ [_domainName release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFPTRDNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFPTRDNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_domainName != _domainName && - ![otherRecord->_domainName isEqual: _domainName]) +- (bool)isEqual: (id)object +{ + OFPTRDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFPTRDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_domainName != _domainName && + ![record->_domainName isEqual: _domainName]) return false; return true; } @@ -809,12 +833,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, _domainName.hash); OF_HASH_FINALIZE(hash); @@ -829,36 +853,35 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tDomain Name = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), _domainName, - _TTL]; + self.className, _name, of_dns_class_to_string(_DNSClass), + _domainName, _TTL]; } @end @implementation OFRPDNSResourceRecord @synthesize mailbox = _mailbox, TXTDomainName = _TXTDomainName; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass mailbox: (OFString *)mailbox TXTDomainName: (OFString *)TXTDomainName TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_RP + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_RP TTL: TTL]; @try { _mailbox = [mailbox copy]; _TXTDomainName = [TXTDomainName copy]; @@ -876,34 +899,37 @@ [_TXTDomainName release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFRPDNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFRPDNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_mailbox != _mailbox && - ![otherRecord->_mailbox isEqual: _mailbox]) - return false; - - if (otherRecord->_TXTDomainName != _TXTDomainName && - ![otherRecord->_TXTDomainName isEqual: _TXTDomainName]) +- (bool)isEqual: (id)object +{ + OFRPDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFRPDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_mailbox != _mailbox && + ![record->_mailbox isEqual: _mailbox]) + return false; + + if (record->_TXTDomainName != _TXTDomainName && + ![record->_TXTDomainName isEqual: _TXTDomainName]) return false; return true; } @@ -912,12 +938,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, _mailbox.hash); OF_HASH_ADD_HASH(hash, _TXTDomainName.hash); @@ -934,12 +960,11 @@ @"\tClass = %@\n" @"\tMailbox = %@\n" @"\tTXT Domain Name = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), _mailbox, + self.className, _name, of_dns_class_to_string(_DNSClass), _mailbox, _TXTDomainName, _TTL]; } @end @implementation OFSOADNSResourceRecord @@ -948,19 +973,19 @@ @synthesize serialNumber = _serialNumber, refreshInterval = _refreshInterval; @synthesize retryInterval = _retryInterval; @synthesize expirationInterval = _expirationInterval, minTTL = _minTTL; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass primaryNameServer: (OFString *)primaryNameServer responsiblePerson: (OFString *)responsiblePerson serialNumber: (uint32_t)serialNumber refreshInterval: (uint32_t)refreshInterval retryInterval: (uint32_t)retryInterval @@ -967,12 +992,12 @@ expirationInterval: (uint32_t)expirationInterval minTTL: (uint32_t)minTTL TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_SOA + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_SOA TTL: TTL]; @try { _primaryNameServer = [primaryNameServer copy]; _responsiblePerson = [responsiblePerson copy]; @@ -995,49 +1020,52 @@ [_responsiblePerson release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFSOADNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFSOADNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_primaryNameServer != _primaryNameServer && - ![otherRecord->_primaryNameServer isEqual: _primaryNameServer]) - return false; - - if (otherRecord->_responsiblePerson != _responsiblePerson && - ![otherRecord->_responsiblePerson isEqual: _responsiblePerson]) - return false; - - if (otherRecord->_serialNumber != _serialNumber) - return false; - - if (otherRecord->_refreshInterval != _refreshInterval) - return false; - - if (otherRecord->_retryInterval != _retryInterval) - return false; - - if (otherRecord->_expirationInterval != _expirationInterval) - return false; - - if (otherRecord->_minTTL != _minTTL) +- (bool)isEqual: (id)object +{ + OFSOADNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFSOADNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_primaryNameServer != _primaryNameServer && + ![record->_primaryNameServer isEqual: _primaryNameServer]) + return false; + + if (record->_responsiblePerson != _responsiblePerson && + ![record->_responsiblePerson isEqual: _responsiblePerson]) + return false; + + if (record->_serialNumber != _serialNumber) + return false; + + if (record->_refreshInterval != _refreshInterval) + return false; + + if (record->_retryInterval != _retryInterval) + return false; + + if (record->_expirationInterval != _expirationInterval) + return false; + + if (record->_minTTL != _minTTL) return false; return true; } @@ -1046,12 +1074,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, _primaryNameServer.hash); OF_HASH_ADD_HASH(hash, _responsiblePerson.hash); OF_HASH_ADD(hash, _serialNumber >> 24); @@ -1093,12 +1121,11 @@ @"\tRetry Interval = %" PRIu32 "\n" @"\tExpiration Interval = %" PRIu32 "\n" @"\tMinimum TTL = %" PRIu32 "\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), + self.className, _name, of_dns_class_to_string(_DNSClass), _primaryNameServer, _responsiblePerson, _serialNumber, _refreshInterval, _retryInterval, _expirationInterval, _minTTL, _TTL]; } @end @@ -1106,12 +1133,12 @@ @implementation OFSRVDNSResourceRecord @synthesize priority = _priority, weight = _weight, target = _target; @synthesize port = _port; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } @@ -1121,12 +1148,12 @@ target: (OFString *)target port: (uint16_t)port TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN - recordType: OF_DNS_RESOURCE_RECORD_TYPE_SRV + DNSClass: OF_DNS_CLASS_IN + recordType: OF_DNS_RECORD_TYPE_SRV TTL: TTL]; @try { _priority = priority; _weight = weight; @@ -1145,39 +1172,41 @@ [_target release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFSRVDNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFSRVDNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_priority != _priority) - return false; - - if (otherRecord->_weight != _weight) - return false; - - if (otherRecord->_target != _target && - ![otherRecord->_target isEqual: _target]) - return false; - - if (otherRecord->_port != _port) +- (bool)isEqual: (id)object +{ + OFSRVDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFSRVDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_priority != _priority) + return false; + + if (record->_weight != _weight) + return false; + + if (record->_target != _target && ![record->_target isEqual: _target]) + return false; + + if (record->_port != _port) return false; return true; } @@ -1186,12 +1215,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD(hash, _priority >> 8); OF_HASH_ADD(hash, _priority); OF_HASH_ADD(hash, _weight >> 8); @@ -1222,25 +1251,25 @@ @implementation OFTXTDNSResourceRecord @synthesize textData = _textData; - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + DNSClass: (of_dns_class_t)DNSClass + recordType: (of_dns_record_type_t)recordType TTL: (uint32_t)TTL { OF_INVALID_INIT_METHOD } - (instancetype)initWithName: (OFString *)name - recordClass: (of_dns_resource_record_class_t)recordClass + DNSClass: (of_dns_class_t)DNSClass textData: (OFData *)textData TTL: (uint32_t)TTL { self = [super initWithName: name - recordClass: recordClass - recordType: OF_DNS_RESOURCE_RECORD_TYPE_TXT + DNSClass: DNSClass + recordType: OF_DNS_RECORD_TYPE_TXT TTL: TTL]; @try { _textData = [textData copy]; } @catch (id e) { @@ -1256,30 +1285,33 @@ [_textData release]; [super dealloc]; } -- (bool)isEqual: (id)otherObject -{ - OFTXTDNSResourceRecord *otherRecord; - - if (![otherObject isKindOfClass: [OFTXTDNSResourceRecord class]]) - return false; - - otherRecord = otherObject; - - if (otherRecord->_name != _name && ![otherRecord->_name isEqual: _name]) - return false; - - if (otherRecord->_recordClass != _recordClass) - return false; - - if (otherRecord->_recordType != _recordType) - return false; - - if (otherRecord->_textData != _textData && - ![otherRecord->_textData isEqual: _textData]) +- (bool)isEqual: (id)object +{ + OFTXTDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFTXTDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_textData != _textData && + ![record->_textData isEqual: _textData]) return false; return true; } @@ -1288,12 +1320,12 @@ uint32_t hash; OF_HASH_INIT(hash); OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, _recordClass >> 8); - OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _DNSClass >> 8); + OF_HASH_ADD(hash, _DNSClass); OF_HASH_ADD(hash, _recordType >> 8); OF_HASH_ADD(hash, _recordType); OF_HASH_ADD_HASH(hash, _textData.hash); OF_HASH_FINALIZE(hash); @@ -1308,10 +1340,9 @@ @"\tName = %@\n" @"\tClass = %@\n" @"\tText Data = %@\n" @"\tTTL = %" PRIu32 "\n" @">", - self.className, _name, - of_dns_resource_record_class_to_string(_recordClass), _textData, + self.className, _name, of_dns_class_to_string(_DNSClass), _textData, _TTL]; } @end ADDED src/OFDNSResponse.h Index: src/OFDNSResponse.h ================================================================== --- src/OFDNSResponse.h +++ src/OFDNSResponse.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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. + */ + +#import "OFObject.h" +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFArray OF_GENERIC(ObjectType); +@class OFDictionary OF_GENERIC(KeyType, ObjectType); + +typedef OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC( + OF_KINDOF(OFDNSResourceRecord *)) *) *of_dns_response_records_t; + +/*! + * @class OFDNSResponse OFDNSResponse.h ObjFW/OFDNSResponse.h + * + * @brief A class storing a response from @ref OFDNSResolver. + */ +@interface OFDNSResponse: OFObject +{ + OFString *_domainName; + of_dns_response_records_t _answerRecords; + of_dns_response_records_t _authorityRecords; + of_dns_response_records_t _additionalRecords; + OF_RESERVE_IVARS(4) +} + +/*! + * @brief The domain name of the response. + */ +@property (readonly, nonatomic) OFString *domainName; + +/*! + * @brief The answer records of the response. + * + * This is a dictionary with the key being the domain name and the value being + * an array of @ref OFDNSResourceRecord. + */ +@property (readonly, nonatomic) of_dns_response_records_t answerRecords; + +/*! + * @brief The authority records of the response. + * + * This is a dictionary with the key being the domain name and the value being + * an array of @ref OFDNSResourceRecord. + */ +@property (readonly, nonatomic) of_dns_response_records_t authorityRecords; + +/*! + * @brief The additional records of the response. + * + * This is a dictionary with the key being the domain name and the value being + * an array of @ref OFDNSResourceRecord. + */ +@property (readonly, nonatomic) of_dns_response_records_t additionalRecords; + +/*! + * @brief Creates a new, autoreleased OFDNSResponse. + * + * @param answerRecords The answer records of the response + * @param authorityRecords The authority records of the response + * @param additionalRecords The additional records of the response + * @return A new, autoreleased OFDNSResponse + */ ++ (instancetype) + responseWithDomainName: (OFString *)domainName + answerRecords: (of_dns_response_records_t)answerRecords + authorityRecords: (of_dns_response_records_t)authorityRecords + additionalRecords: (of_dns_response_records_t)additionalRecords; + +/*! + * @brief Initializes an already allocated OFDNSResponse. + * + * @param answerRecords The answer records of the response + * @param authorityRecords The authority records of the response + * @param additionalRecords The additional records of the response + * @return An initialized OFDNSResponse + */ +- (instancetype) + initWithDomainName: (OFString *)domainName + answerRecords: (of_dns_response_records_t)answerRecords + authorityRecords: (of_dns_response_records_t)authorityRecords + additionalRecords: (of_dns_response_records_t)additionalRecords + OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFDNSResponse.m Index: src/OFDNSResponse.m ================================================================== --- src/OFDNSResponse.m +++ src/OFDNSResponse.m @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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 "OFDNSResponse.h" +#import "OFDictionary.h" +#import "OFString.h" + +@implementation OFDNSResponse +@synthesize domainName = _domainName, answerRecords = _answerRecords; +@synthesize authorityRecords = _authorityRecords; +@synthesize additionalRecords = _additionalRecords; + ++ (instancetype) + responseWithDomainName: (OFString *)domainName + answerRecords: (of_dns_response_records_t)answerRecords + authorityRecords: (of_dns_response_records_t)authorityRecords + additionalRecords: (of_dns_response_records_t)additionalRecords +{ + return [[[self alloc] + initWithDomainName: domainName + answerRecords: answerRecords + authorityRecords: authorityRecords + additionalRecords: additionalRecords] autorelease]; +} + +- (instancetype)initWithDomainName: (OFString *)domainName + answerRecords: (of_dns_response_records_t)answerRecords + authorityRecords: (of_dns_response_records_t)authorityRecords + additionalRecords: (of_dns_response_records_t)additionalRecords +{ + self = [super init]; + + @try { + _domainName = [domainName copy]; + _answerRecords = [answerRecords copy]; + _authorityRecords = [authorityRecords copy]; + _additionalRecords = [additionalRecords copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init OF_UNAVAILABLE +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_domainName release]; + [_answerRecords release]; + [_authorityRecords release]; + [_additionalRecords release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFDNSResponse *response; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFDNSResponse class]]) + return false; + + response = object; + + if (response->_domainName != _domainName && + ![response->_domainName isEqual: _domainName]) + return false; + if (response->_answerRecords != _answerRecords && + ![response->_answerRecords isEqual: _answerRecords]) + return false; + if (response->_authorityRecords != _authorityRecords && + ![response->_authorityRecords isEqual: _authorityRecords]) + return false; + if (response->_additionalRecords != _additionalRecords && + ![response->_additionalRecords isEqual: _additionalRecords]) + return false; + + return true; +} + +- (uint32_t)hash +{ + uint32_t hash; + + OF_HASH_INIT(hash); + OF_HASH_ADD_HASH(hash, _domainName.hash); + OF_HASH_ADD_HASH(hash, [_answerRecords hash]); + OF_HASH_ADD_HASH(hash, [_authorityRecords hash]); + OF_HASH_ADD_HASH(hash, [_additionalRecords hash]); + OF_HASH_FINALIZE(hash); + + return hash; +} + +- (OFString *)description +{ + OFString *answerRecords = [_answerRecords.description + stringByReplacingOccurrencesOfString: @"\n" + withString: @"\n\t"]; + OFString *authorityRecords = [_authorityRecords.description + stringByReplacingOccurrencesOfString: @"\n" + withString: @"\n\t"]; + OFString *additionalRecords = [_additionalRecords.description + stringByReplacingOccurrencesOfString: @"\n" + withString: @"\n\t"]; + + return [OFString stringWithFormat: + @"<%@:\n" + @"\tDomain name = %@\n" + @"\tAnswer records = %@\n" + @"\tAuthority records = %@\n" + @"\tAdditional records = %@\n" + @">", + self.className, _domainName, answerRecords, authorityRecords, + additionalRecords]; +} +@end Index: src/OFData.h ================================================================== --- src/OFData.h +++ src/OFData.h @@ -40,10 +40,11 @@ OFSerialization, OFMessagePackRepresentation> { unsigned char *_items; size_t _count, _itemSize; bool _freeWhenDone; +@private OFData *_parentData; OF_RESERVE_IVARS(4) } /*! Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -60,14 +60,10 @@ OFMessagePackRepresentation> #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define KeyType id # define ObjectType id #endif -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief An array of all keys. */ @property (readonly, nonatomic) OFArray OF_GENERIC(KeyType) *allKeys; Index: src/OFDimensionValue.h ================================================================== --- src/OFDimensionValue.h +++ src/OFDimensionValue.h @@ -17,13 +17,12 @@ #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFDimensionValue: OFValue { of_dimension_t _dimension; } @end OF_ASSUME_NONNULL_END Index: src/OFEpollKernelEventObserver.h ================================================================== --- src/OFEpollKernelEventObserver.h +++ src/OFEpollKernelEventObserver.h @@ -19,14 +19,13 @@ OF_ASSUME_NONNULL_BEGIN @class OFMapTable; -OF_SUBCLASSING_RESTRICTED @interface OFEpollKernelEventObserver: OFKernelEventObserver { int _epfd; OFMapTable *_FDToEvents; } @end OF_ASSUME_NONNULL_END Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -221,11 +221,11 @@ flags |= O_BINARY | O_CLOEXEC; # if defined(OF_WINDOWS) if ((handle = _wopen(path.UTF16String, flags, _S_IREAD | _S_IWRITE)) == -1) -# elif defined(OF_HAVE_OFF64_T) +# elif defined(HAVE_OPEN64) if ((handle = open64([path cStringWithEncoding: [OFLocale encoding]], flags, 0666)) == -1) # else if ((handle = open([path cStringWithEncoding: [OFLocale encoding]], flags, 0666)) == -1) @@ -464,11 +464,11 @@ @throw [OFNotOpenException exceptionWithObject: self]; #ifndef OF_AMIGAOS # if defined(OF_WINDOWS) ret = _lseeki64(_handle, offset, whence); -# elif defined(OF_HAVE_OFF64_T) +# elif defined(HAVE_LSEEK64) ret = lseek64(_handle, offset, whence); # else ret = lseek(_handle, offset, whence); # endif Index: src/OFFileURLHandler.h ================================================================== --- src/OFFileURLHandler.h +++ src/OFFileURLHandler.h @@ -17,11 +17,10 @@ #import "OFURLHandler.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFFileURLHandler: OFURLHandler + (bool)of_directoryExistsAtPath: (OFString *)path; @end OF_ASSUME_NONNULL_END Index: src/OFFileURLHandler.m ================================================================== --- src/OFFileURLHandler.m +++ src/OFFileURLHandler.m @@ -87,11 +87,11 @@ # define HAVE_STRUCT_STAT_ST_BIRTHTIME of_time_interval_t st_birthtime; DWORD fileAttributes; # endif } of_stat_t; -#elif defined(OF_HAVE_OFF64_T) +#elif defined(HAVE_STAT64) typedef struct stat64 of_stat_t; #else typedef struct stat of_stat_t; #endif @@ -272,11 +272,11 @@ # ifdef OF_AMIGAOS4 FreeDosObject(DOS_EXAMINEDATA, ed); # endif return 0; -#elif defined(OF_HAVE_OFF64_T) +#elif defined(HAVE_STAT64) return stat64([path cStringWithEncoding: [OFLocale encoding]], buffer); #else return stat([path cStringWithEncoding: [OFLocale encoding]], buffer); #endif } @@ -284,11 +284,11 @@ static int of_lstat(OFString *path, of_stat_t *buffer) { #if defined(HAVE_LSTAT) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) && \ !defined(OF_NINTENDO_3DS) && !defined(OF_WII) -# ifdef OF_HAVE_OFF64_T +# ifdef HAVE_LSTAT64 return lstat64([path cStringWithEncoding: [OFLocale encoding]], buffer); # else return lstat([path cStringWithEncoding: [OFLocale encoding]], buffer); # endif #else Index: src/OFHTTPURLHandler.h ================================================================== --- src/OFHTTPURLHandler.h +++ src/OFHTTPURLHandler.h @@ -17,10 +17,9 @@ #import "OFURLHandler.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFHTTPURLHandler: OFURLHandler @end OF_ASSUME_NONNULL_END ADDED src/OFHostAddressResolver.h Index: src/OFHostAddressResolver.h ================================================================== --- src/OFHostAddressResolver.h +++ src/OFHostAddressResolver.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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. + */ + +#import "OFObject.h" +#import "OFDNSResolver.h" +#import "OFRunLoop.h" + +#import "socket.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFDNSResolverSettings; +@class OFDNSResourceRecord; +@class OFMutableArray OF_GENERIC(ObjectType); +@class OFMutableData; +@class OFString; + +@interface OFHostAddressResolver: OFObject +{ + OFString *_host; + of_socket_address_family_t _addressFamily; + OFDNSResolver *_resolver; + OFDNSResolverSettings *_settings; + of_run_loop_mode_t _Nullable _runLoopMode; + id _Nullable _delegate; + bool _isFQDN; + size_t _searchDomainIndex; + unsigned int _numExpectedResponses; + OFMutableData *_addresses; +} + +- (instancetype)initWithHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily + resolver: (OFDNSResolver *)resolver + settings: (OFDNSResolverSettings *)settings + runLoopMode: (nullable of_run_loop_mode_t)runLoopMode + delegate: (nullable id )delegate; +- (void)asyncResolve; +- (OFData *)resolve; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFHostAddressResolver.m Index: src/OFHostAddressResolver.m ================================================================== --- src/OFHostAddressResolver.m +++ src/OFHostAddressResolver.m @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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 "OFHostAddressResolver.h" +#import "OFArray.h" +#import "OFDNSResolver.h" +#import "OFDNSResolverSettings.h" +#import "OFData.h" +#import "OFDate.h" +#import "OFDictionary.h" +#import "OFRunLoop.h" +#import "OFString.h" +#import "OFTimer.h" + +#import "OFDNSQueryFailedException.h" +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFResolveHostFailedException.h" + +@interface OFHostAddressResolverDelegate: OFObject +{ +@public + bool _done; + OFData *_addresses; + id _exception; +} +@end + +static const of_run_loop_mode_t resolveRunLoopMode = + @"of_host_address_resolver_resolve_mode"; + +static bool +isFQDN(OFString *host, unsigned int minNumberOfDotsInAbsoluteName) +{ + const char *UTF8String; + size_t length; + unsigned int dots; + + if ([host hasSuffix: @"."]) + return true; + + UTF8String = host.UTF8String; + length = host.UTF8StringLength; + dots = 0; + + for (size_t i = 0; i < length; i++) + if (UTF8String[i] == '.') + dots++; + + return (dots >= minNumberOfDotsInAbsoluteName); +} + +static bool +addressForRecord(OF_KINDOF(OFDNSResourceRecord *) record, + const of_socket_address_t **address, + of_socket_address_family_t addressFamily) +{ + switch ([record recordType]) { +#ifdef OF_HAVE_IPV6 + case OF_DNS_RECORD_TYPE_AAAA: + if (addressFamily != OF_SOCKET_ADDRESS_FAMILY_IPV6 && + addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY) + return false; + break; +#endif + case OF_DNS_RECORD_TYPE_A: + if (addressFamily != OF_SOCKET_ADDRESS_FAMILY_IPV4 && + addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY) + return false; + break; + default: + return false; + } + + *address = [record address]; + return true; +} + +static void +callDelegateInMode(of_run_loop_mode_t runLoopMode, + id delegate, OFDNSResolver *resolver, + OFString *host, OFData *addresses, id exception) +{ + SEL selector = @selector(resolver:didResolveHost:addresses:exception:); + + if ([delegate respondsToSelector: selector]) { + OFTimer *timer = [OFTimer + timerWithTimeInterval: 0 + target: delegate + selector: selector + object: resolver + object: host + object: addresses + object: exception + repeats: false]; + [[OFRunLoop currentRunLoop] addTimer: timer + forMode: runLoopMode]; + } +} + +@implementation OFHostAddressResolver: OFObject +- (instancetype)initWithHost: (OFString *)host + addressFamily: (of_socket_address_family_t)addressFamily + resolver: (OFDNSResolver *)resolver + settings: (OFDNSResolverSettings *)settings + runLoopMode: (of_run_loop_mode_t)runLoopMode + delegate: (id )delegate +{ + self = [super init]; + + @try { + _host = [host copy]; + _addressFamily = addressFamily; + _resolver = [resolver retain]; + _settings = [settings copy]; + _runLoopMode = [runLoopMode copy]; + _delegate = [delegate retain]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_host release]; + [_resolver release]; + [_settings release]; + [_runLoopMode release]; + [_delegate release]; + [_addresses release]; + + [super dealloc]; +} + +- (void)sendQueries +{ + OFString *domainName; + + if (!_isFQDN) { + OFString *searchDomain = [_settings->_searchDomains + objectAtIndex: _searchDomainIndex]; + + domainName = [OFString stringWithFormat: @"%@.%@", + _host, searchDomain]; + } else + domainName = _host; + +#ifdef OF_HAVE_IPV6 + if (_addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV6 || + _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) { + OFDNSQuery *query = [OFDNSQuery + queryWithDomainName: domainName + DNSClass: OF_DNS_CLASS_IN + recordType: OF_DNS_RECORD_TYPE_AAAA]; + _numExpectedResponses++; + [_resolver asyncPerformQuery: query + runLoopMode: _runLoopMode + delegate: self]; + } +#endif + + if (_addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV4 || + _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) { + OFDNSQuery *query = [OFDNSQuery + queryWithDomainName: domainName + DNSClass: OF_DNS_CLASS_IN + recordType: OF_DNS_RECORD_TYPE_A]; + _numExpectedResponses++; + [_resolver asyncPerformQuery: query + runLoopMode: _runLoopMode + delegate: self]; + } +} + +- (void)resolver: (OFDNSResolver *)resolver + didPerformQuery: (OFDNSQuery *)query + response: (OFDNSResponse *)response + exception: (id)exception +{ + _numExpectedResponses--; + + if ([exception isKindOfClass: [OFDNSQueryFailedException class]] && + [exception error] == OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR && + !_isFQDN && _numExpectedResponses == 0 && _addresses.count == 0 && + _searchDomainIndex + 1 < _settings->_searchDomains.count) { + _searchDomainIndex++; + [self sendQueries]; + return; + } + + for (OF_KINDOF(OFDNSResourceRecord *) record in + [response.answerRecords objectForKey: query.domainName]) { + const of_socket_address_t *address; + OFDNSQuery *CNAMEQuery; + + if ([record DNSClass] != OF_DNS_CLASS_IN) + continue; + + if (addressForRecord(record, &address, _addressFamily)) { + [_addresses addItem: address]; + continue; + } + + if ([record recordType] != OF_DNS_RECORD_TYPE_CNAME) + continue; + + /* FIXME: Check if it's already in answers */ + CNAMEQuery = [OFDNSQuery queryWithDomainName: [record alias] + DNSClass: OF_DNS_CLASS_IN + recordType: query.recordType]; + _numExpectedResponses++; + [_resolver asyncPerformQuery: CNAMEQuery + runLoopMode: _runLoopMode + delegate: self]; + } + + if (_numExpectedResponses > 0) + return; + + [_addresses makeImmutable]; + + if ([_delegate respondsToSelector: + @selector(resolver:didResolveHost:addresses:exception:)]) + [_delegate resolver: _resolver + didResolveHost: _host + addresses: (_addresses.count > 0 ? _addresses : nil) + exception: (_addresses.count == 0 ? exception : nil)]; +} + +- (void)asyncResolve +{ + void *pool = objc_autoreleasePoolPush(); + OFArray OF_GENERIC(OFString *) *aliases; + + @try { + of_socket_address_t address = + of_socket_address_parse_ip(_host, 0); + OFData *addresses = nil; + id exception = nil; + + if (_addressFamily == address.family || + _addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) + addresses = [OFData dataWithItems: &address + itemSize: sizeof(address) + count: 1]; + else + exception = [OFInvalidArgumentException exception]; + + callDelegateInMode(_runLoopMode, _delegate, _resolver, _host, + addresses, exception); + + objc_autoreleasePoolPop(pool); + return; + } @catch (OFInvalidFormatException *e) { + } + + if ((aliases = [_settings->_staticHosts objectForKey: _host]) != nil) { + OFMutableData *addresses = [OFMutableData + dataWithItemSize: sizeof(of_socket_address_t)]; + id exception = nil; + + for (OFString *alias in aliases) { + of_socket_address_t address; + + @try { + address = of_socket_address_parse_ip(alias, 0); + } @catch (OFInvalidFormatException *e) { + continue; + } + + if (_addressFamily != address.family && + _addressFamily != OF_SOCKET_ADDRESS_FAMILY_ANY) + continue; + + [addresses addItem: &address]; + } + + [addresses makeImmutable]; + + if (addresses.count == 0) { + addresses = nil; + exception = [OFResolveHostFailedException + exceptionWithHost: _host + addressFamily: _addressFamily + error: OF_DNS_RESOLVER_ERROR_NO_RESULT]; + } + + callDelegateInMode(_runLoopMode, _delegate, _resolver, _host, + addresses, exception); + + objc_autoreleasePoolPop(pool); + return; + } + + _isFQDN = isFQDN(_host, _settings->_minNumberOfDotsInAbsoluteName); + _addresses = [[OFMutableData alloc] + initWithItemSize: sizeof(of_socket_address_t)]; + + [self sendQueries]; + + objc_autoreleasePoolPop(pool); +} + +- (OFData *)resolve +{ + void *pool = objc_autoreleasePoolPush(); + OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; + OFHostAddressResolverDelegate *delegate; + OFData *ret; + + delegate = [[[OFHostAddressResolverDelegate alloc] init] autorelease]; + _runLoopMode = [resolveRunLoopMode copy]; + _delegate = [delegate retain]; + + [self asyncResolve]; + + while (!delegate->_done) + [runLoop runMode: resolveRunLoopMode + beforeDate: nil]; + + /* Cleanup */ + [runLoop runMode: resolveRunLoopMode + beforeDate: [OFDate date]]; + + if (delegate->_exception != nil) + @throw delegate->_exception; + + ret = [delegate->_addresses copy]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} +@end + +@implementation OFHostAddressResolverDelegate +- (void)dealloc +{ + [_addresses release]; + [_exception release]; + + [super dealloc]; +} + +- (void)resolver: (OFDNSResolver *)resolver + didResolveHost: (OFString *)host + addresses: (OFData *)addresses + exception: (id)exception +{ + _addresses = [addresses copy]; + _exception = [exception retain]; + _done = true; +} +@end Index: src/OFINIFileSettings.h ================================================================== --- src/OFINIFileSettings.h +++ src/OFINIFileSettings.h @@ -20,14 +20,13 @@ OF_ASSUME_NONNULL_BEGIN @class OFString; @class OFINIFile; -OF_SUBCLASSING_RESTRICTED @interface OFINIFileSettings: OFSettings { OFString *_filePath; OFINIFile *_INIFile; } @end OF_ASSUME_NONNULL_END Index: src/OFInflate64Stream.h ================================================================== --- src/OFInflate64Stream.h +++ src/OFInflate64Stream.h @@ -32,13 +32,10 @@ * underlying stream. */ OF_SUBCLASSING_RESTRICTED @interface OFInflate64Stream: OFStream { -#ifdef OF_INFLATE64_STREAM_M -@public -#endif OFStream *_stream; unsigned char _buffer[OF_INFLATE64_STREAM_BUFFER_SIZE]; uint16_t _bufferIndex, _bufferLength; uint8_t _byte; uint8_t _bitIndex, _savedBitsLength; Index: src/OFInflateStream.h ================================================================== --- src/OFInflateStream.h +++ src/OFInflateStream.h @@ -32,13 +32,10 @@ * underlying stream. */ OF_SUBCLASSING_RESTRICTED @interface OFInflateStream: OFStream { -#ifdef OF_INFLATE_STREAM_M -@public -#endif OFStream *_stream; unsigned char _buffer[OF_INFLATE_STREAM_BUFFER_SIZE]; uint16_t _bufferIndex, _bufferLength; uint8_t _byte; uint8_t _bitIndex, _savedBitsLength; Index: src/OFInflateStream.m ================================================================== --- src/OFInflateStream.m +++ src/OFInflateStream.m @@ -13,12 +13,10 @@ * 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. */ -#define OF_INFLATE_STREAM_M - #include "config.h" #include #include @@ -104,10 +102,11 @@ static const uint8_t codeLengthsOrder[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static struct of_huffman_tree *fixedLitLenTree, *fixedDistTree; +@implementation OFInflateStream static OF_INLINE bool tryReadBits(OFInflateStream *stream, uint16_t *bits, uint8_t count) { uint16_t ret = stream->_savedBits; @@ -146,11 +145,10 @@ *bits = ret; return true; } -@implementation OFInflateStream + (void)initialize { uint8_t lengths[288]; if (self != [OFInflateStream class]) DELETED src/OFIntrospection.h Index: src/OFIntrospection.h ================================================================== --- src/OFIntrospection.h +++ src/OFIntrospection.h @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019 - * 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. - */ - -#import "OFObject.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFArray OF_GENERIC(ObjectType); -@class OFMutableArray OF_GENERIC(ObjectType); -@class OFString; - -enum { - OF_PROPERTY_READONLY = 0x01, - OF_PROPERTY_ASSIGN = 0x04, - OF_PROPERTY_READWRITE = 0x08, - OF_PROPERTY_RETAIN = 0x10, - OF_PROPERTY_COPY = 0x20, - OF_PROPERTY_NONATOMIC = 0x40, - OF_PROPERTY_SYNTHESIZED = 0x100, - OF_PROPERTY_DYNAMIC = 0x200, - OF_PROPERTY_ATOMIC = 0x400, - OF_PROPERTY_WEAK = 0x800 -}; - -/*! - * @class OFMethod OFIntrospection.h ObjFW/OFIntrospection.h - * - * @brief A class for describing a method. - */ -@interface OFMethod: OFObject -{ - SEL _selector; - OFString *_name; - const char *_typeEncoding; - OF_RESERVE_IVARS(4) -} - -/*! - * @brief The selector of the method. - */ -@property (readonly, nonatomic) SEL selector; - -/*! - * @brief The name of the method. - */ -@property (readonly, nonatomic) OFString *name; - -/*! - * @brief The type encoding for the method. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) const char *typeEncoding; - -- (instancetype)init OF_UNAVAILABLE; -@end - -/*! - * @class OFProperty OFIntrospection.h ObjFW/OFIntrospection.h - * - * @brief A class for describing a property. - */ -@interface OFProperty: OFObject -{ - OFString *_name; - unsigned int _attributes; - OFString *_Nullable _getter, *_Nullable _setter, *_Nullable _iVar; - OF_RESERVE_IVARS(4) -} - -/*! - * @brief The name of the property. - */ -@property (readonly, nonatomic) OFString *name; - -/*! - * @brief The attributes of the property. - * - * The attributes are a bitmask with the following possible flags:@n - * Flag | Description - * ------------------------------|------------------------------------- - * OF_PROPERTY_READONLY | The property is declared `readonly` - * OF_PROPERTY_READWRITE | The property is declared `readwrite` - * OF_PROPERTY_ASSIGN | The property is declared `assign` - * OF_PROPERTY_RETAIN | The property is declared `retain` - * OF_PROPERTY_COPY | The property is declared `copy` - * OF_PROPERTY_NONATOMIC | The property is declared `nonatomic` - * OF_PROPERTY_ATOMIC | The property is declared `atomic` - * OF_PROPERTY_WEAK | The property is declared `weak` - * OF_PROPERTY_SYNTHESIZED | The property is synthesized - * OF_PROPERTY_DYNAMIC | The property is dynamic - */ -@property (readonly, nonatomic) unsigned int attributes; - -/*! - * @brief The name of the getter. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *getter; - -/*! - * @brief The name of the setter. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *setter; - -/*! - * @brief The name of the backing iVar. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *iVar; - -- (instancetype)init OF_UNAVAILABLE; -@end - -/*! - * @class OFInstanceVariable OFIntrospection.h ObjFW/OFIntrospection.h - * - * @brief A class for describing an instance variable. - */ -@interface OFInstanceVariable: OFObject -{ - OFString *_name; - const char *_typeEncoding; - ptrdiff_t _offset; - OF_RESERVE_IVARS(4) -} - -/*! - * @brief The name of the instance variable. - */ -@property (readonly, nonatomic) OFString *name; - -/*! - * @brief The offset of the instance variable. - */ -@property (readonly, nonatomic) ptrdiff_t offset; - -/*! - * @brief The type encoding for the instance variable. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) const char *typeEncoding; - -- (instancetype)init OF_UNAVAILABLE; -@end - -/*! - * @class OFIntrospection OFIntrospection.h ObjFW/OFIntrospection.h - * - * @brief A class for introspecting classes. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFIntrospection: OFObject -{ - OFMutableArray OF_GENERIC(OFMethod *) *_classMethods; - OFMutableArray OF_GENERIC(OFMethod *) *_instanceMethods; - OFMutableArray OF_GENERIC(OFProperty *) *_properties; - OFMutableArray OF_GENERIC(OFInstanceVariable *) *_instanceVariables; -} - -/*! - * @brief The class methods of the class. - */ -@property (readonly, nonatomic) OFArray OF_GENERIC(OFMethod *) *classMethods; - -/*! - * @brief The instance methods of the class. - */ -@property (readonly, nonatomic) OFArray OF_GENERIC(OFMethod *) *instanceMethods; - -/*! - * @brief The properties of the class. - * - * @warning **Do not rely on this, as this behaves differently depending on the - * compiler and ABI used!** - * - * @warning For the ObjFW ABI, Clang only emits data for property introspection - * if `@``synthesize` or `@``dynamic` has been used on the property, - * not if the property has only been implemented by methods. Using - * `@``synthesize` and manually implementing the methods works, - * though. - * - * @warning For the Apple ABI, Clang and GCC both emit data for property - * introspection for every property that has been declared using - * `@``property`, even if no `@``synchronize` or `@``dynamic` has been - * used. - * - * @warning GCC does not emit any data for property introspection for the GNU - * ABI. - */ -@property (readonly, nonatomic) OFArray OF_GENERIC(OFProperty *) *properties; - -/*! - * @brief The instance variables of the class. - */ -@property (readonly, nonatomic) - OFArray OF_GENERIC(OFInstanceVariable *) *instanceVariables; - -/* TODO: protocols */ - -/*! - * @brief Creates a new introspection for the specified class. - * - * @return A new, autoreleased introspection for the specified class - */ -+ (instancetype)introspectionWithClass: (Class)class_; - -- (instancetype)init OF_UNAVAILABLE; - -/*! - * @brief Initializes an already allocated OFIntrospection with the specified - * class. - * - * @return An initialized OFIntrospection - */ -- (instancetype)initWithClass: (Class)class_ OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFIntrospection.m Index: src/OFIntrospection.m ================================================================== --- src/OFIntrospection.m +++ src/OFIntrospection.m @@ -1,613 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, - * 2018, 2019 - * 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" - -#include - -#import "OFIntrospection.h" -#import "OFString.h" -#import "OFArray.h" - -#import "OFInitializationFailedException.h" - -@implementation OFMethod -@synthesize selector = _selector, name = _name, typeEncoding = _typeEncoding; - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -#if defined(OF_OBJFW_RUNTIME) -- (instancetype)of_initWithMethod: (struct objc_method *)method -{ - self = [super init]; - - @try { - _selector = (SEL)&method->selector; - _name = [[OFString alloc] - initWithUTF8String: sel_getName(_selector)]; - _typeEncoding = method->selector.typeEncoding; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#elif defined(OF_APPLE_RUNTIME) -- (instancetype)of_initWithMethod: (Method)method -{ - self = [super init]; - - @try { - _selector = method_getName(method); - _name = [[OFString alloc] - initWithUTF8String: sel_getName(_selector)]; - _typeEncoding = method_getTypeEncoding(method); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#else -# error Invalid ObjC runtime! -#endif - -- (void)dealloc -{ - [_name release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"<%@: %@ [%s]>", - self.class, _name, _typeEncoding]; -} - -- (bool)isEqual: (id)object -{ - OFMethod *method; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFMethod class]]) - return false; - - method = object; - - if (!sel_isEqual(method->_selector, _selector)) - return false; - - if (![method->_name isEqual: _name]) - return false; - - if ((method->_typeEncoding == NULL && _typeEncoding != NULL) || - (method->_typeEncoding != NULL && _typeEncoding == NULL)) - return false; - - if (method->_typeEncoding != NULL && _typeEncoding != NULL && - strcmp(method->_typeEncoding, _typeEncoding) != 0) - return false; - - return true; -} - -- (uint32_t)hash -{ - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - - if (_typeEncoding != NULL) { - size_t length = strlen(_typeEncoding); - - for (size_t i = 0; i < length; i++) - OF_HASH_ADD(hash, _typeEncoding[i]); - } - - OF_HASH_FINALIZE(hash); - - return hash; -} -@end - -@implementation OFProperty -@synthesize name = _name, attributes = _attributes; -@synthesize getter = _getter, setter = _setter, iVar = _iVar; - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -#if defined(OF_OBJFW_RUNTIME) -- (instancetype)of_initWithProperty: (struct objc_property *)property -{ - self = [super init]; - - @try { - _name = [[OFString alloc] initWithUTF8String: property->name]; - _attributes = - property->attributes | (property->extendedAttributes << 8); - - if (property->getter.name != NULL) - _getter = [[OFString alloc] - initWithUTF8String: property->getter.name]; - if (property->setter.name != NULL) - _setter = [[OFString alloc] - initWithUTF8String: property->setter.name]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#elif defined(OF_APPLE_RUNTIME) -- (instancetype)of_initWithProperty: (objc_property_t)property -{ - self = [super init]; - - @try { - const char *attributes; - - _name = [[OFString alloc] - initWithUTF8String: property_getName(property)]; - - if ((attributes = property_getAttributes(property)) == NULL) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - while (*attributes != '\0') { - const char *start; - - switch (*attributes) { - case 'T': - while (*attributes != ',' && - *attributes != '\0') - attributes++; - break; - case 'R': - _attributes |= OF_PROPERTY_READONLY; - attributes++; - break; - case 'C': - _attributes |= OF_PROPERTY_COPY; - attributes++; - break; - case '&': - _attributes |= OF_PROPERTY_RETAIN; - attributes++; - break; - case 'N': - _attributes |= OF_PROPERTY_NONATOMIC; - attributes++; - break; - case 'G': - start = ++attributes; - - if (_getter != nil) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - while (*attributes != ',' && - *attributes != '\0') - attributes++; - - _getter = [[OFString alloc] - initWithUTF8String: start - length: attributes - start]; - - break; - case 'S': - start = ++attributes; - - if (_setter != nil) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - while (*attributes != ',' && - *attributes != '\0') - attributes++; - - _setter = [[OFString alloc] - initWithUTF8String: start - length: attributes - start]; - - break; - case 'D': - _attributes |= OF_PROPERTY_DYNAMIC; - attributes++; - break; - case 'W': - _attributes |= OF_PROPERTY_WEAK; - attributes++; - break; - case 'P': - attributes++; - break; - case 'V': - start = ++attributes; - - if (_iVar != nil) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - while (*attributes != ',' && - *attributes != '\0') - attributes++; - - _iVar = [[OFString alloc] - initWithUTF8String: start - length: attributes - start]; - - break; - default: - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - } - - if (*attributes != ',' && *attributes != '\0') - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - - if (*attributes != '\0') - attributes++; - } - - if (!(_attributes & OF_PROPERTY_READONLY)) - _attributes |= OF_PROPERTY_READWRITE; - - if (!(_attributes & OF_PROPERTY_COPY) && - !(_attributes & OF_PROPERTY_RETAIN)) - _attributes |= OF_PROPERTY_ASSIGN; - - if (!(_attributes & OF_PROPERTY_NONATOMIC)) - _attributes |= OF_PROPERTY_ATOMIC; - - if (!(_attributes & OF_PROPERTY_DYNAMIC)) - _attributes |= OF_PROPERTY_SYNTHESIZED; - - if (_getter == nil) - _getter = [_name copy]; - - if ((_attributes & OF_PROPERTY_READWRITE) && _setter == nil) { - of_unichar_t first = [_name characterAtIndex: 0]; - OFMutableString *tmp = [_name mutableCopy]; - _setter = tmp; - - [tmp setCharacter: of_ascii_toupper(first) - atIndex: 0]; - [tmp prependString: @"set"]; - - [tmp makeImmutable]; - } - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#else -# error Invalid ObjC runtime! -#endif - -- (void)dealloc -{ - [_name release]; - [_getter release]; - [_setter release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString - stringWithFormat: @"<%@: %@\n" - @"\tAttributes = 0x%03X\n" - @"\tGetter = %@\n" - @"\tSetter = %@\n" - @"\tiVar = %@\n" - @">", - self.class, _name, _attributes, _getter, _setter, - _iVar]; -} - -- (bool)isEqual: (id)object -{ - OFProperty *otherProperty; - - if (object == self) - return true; - - if ([object isKindOfClass: [OFProperty class]]) - return false; - - otherProperty = object; - - if (![otherProperty->_name isEqual: _name]) - return false; - if (otherProperty->_attributes != _attributes) - return false; - if (![otherProperty->_getter isEqual: _getter]) - return false; - if (![otherProperty->_setter isEqual: _setter]) - return false; - - return true; -} - -- (uint32_t)hash -{ - uint32_t hash; - - OF_HASH_INIT(hash); - - OF_HASH_ADD_HASH(hash, _name.hash); - OF_HASH_ADD(hash, (_attributes & 0xFF00) >> 8); - OF_HASH_ADD(hash, _attributes & 0xFF); - OF_HASH_ADD_HASH(hash, _getter.hash); - OF_HASH_ADD_HASH(hash, _setter.hash); - - OF_HASH_FINALIZE(hash); - - return hash; -} -@end - -@implementation OFInstanceVariable -@synthesize name = _name, offset = _offset, typeEncoding = _typeEncoding; - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -#if defined(OF_OBJFW_RUNTIME) -- (instancetype)of_initWithIVar: (struct objc_ivar *)iVar -{ - self = [super init]; - - @try { - if (iVar->name != NULL) - _name = [[OFString alloc] - initWithUTF8String: iVar->name]; - - _typeEncoding = iVar->typeEncoding; - _offset = iVar->offset; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#elif defined(OF_APPLE_RUNTIME) -- (instancetype)of_initWithIVar: (Ivar)iVar -{ - self = [super init]; - - @try { - const char *name = ivar_getName(iVar); - - if (name != NULL) - _name = [[OFString alloc] initWithUTF8String: name]; - - _typeEncoding = ivar_getTypeEncoding(iVar); - _offset = ivar_getOffset(iVar); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#else -# error Invalid ObjC runtime! -#endif - -- (void)dealloc -{ - [_name release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"", - _name, _typeEncoding, _offset]; -} -@end - -@implementation OFIntrospection -@synthesize classMethods = _classMethods, instanceMethods = _instanceMethods; -@synthesize properties = _properties, instanceVariables = _instanceVariables; - -+ (instancetype)introspectionWithClass: (Class)class -{ - return [[[self alloc] initWithClass: class] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithClass: (Class)class -{ - self = [super init]; - - @try { -#if defined(OF_OBJFW_RUNTIME) - struct objc_method_list *methodList; - struct objc_property_list *propertyList; -#elif defined(OF_APPLE_RUNTIME) - Method *methodList; - objc_property_t *propertyList; - Ivar *iVarList; - unsigned count; -#endif - void *pool; - - _classMethods = [[OFMutableArray alloc] init]; - _instanceMethods = [[OFMutableArray alloc] init]; - _properties = [[OFMutableArray alloc] init]; - _instanceVariables = [[OFMutableArray alloc] init]; - -#if defined(OF_OBJFW_RUNTIME) - for (methodList = object_getClass(class)->methodList; - methodList != NULL; methodList = methodList->next) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < methodList->count; i++) - [_classMethods addObject: [[[OFMethod alloc] - of_initWithMethod: - &methodList->methods[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } - - for (methodList = class->methodList; methodList != NULL; - methodList = methodList->next) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < methodList->count; i++) - [_instanceMethods addObject: [[[OFMethod alloc] - of_initWithMethod: - &methodList->methods[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } - - for (propertyList = class->properties; propertyList != NULL; - propertyList = propertyList->next) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < propertyList->count; i++) - [_properties addObject: [[[OFProperty alloc] - of_initWithProperty: - &propertyList->properties[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } - - if (class->iVars != NULL) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < class->iVars->count; i++) - [_instanceVariables addObject: - [[[OFInstanceVariable alloc] - of_initWithIVar: - &class->iVars->iVars[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } -#elif defined(OF_APPLE_RUNTIME) - methodList = class_copyMethodList(object_getClass(class), - &count); - @try { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < count; i++) - [_classMethods addObject: [[[OFMethod alloc] - of_initWithMethod: methodList[i]] - autorelease]]; - - objc_autoreleasePoolPop(pool); - } @finally { - free(methodList); - } - - methodList = class_copyMethodList(class, &count); - @try { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < count; i++) - [_instanceMethods addObject: [[[OFMethod alloc] - of_initWithMethod: methodList[i]] - autorelease]]; - - objc_autoreleasePoolPop(pool); - } @finally { - free(methodList); - } - - propertyList = class_copyPropertyList(class, &count); - @try { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < count; i++) - [_properties addObject: [[[OFProperty alloc] - of_initWithProperty: propertyList[i]] - autorelease]]; - - objc_autoreleasePoolPop(pool); - } @finally { - free(propertyList); - } - - iVarList = class_copyIvarList(class, &count); - @try { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < count; i++) - [_instanceVariables addObject: - [[[OFInstanceVariable alloc] - of_initWithIVar: iVarList[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } @finally { - free(iVarList); - } -#else -# error Invalid ObjC runtime! -#endif - - [_classMethods makeImmutable]; - [_instanceMethods makeImmutable]; - [_properties makeImmutable]; - [_instanceVariables makeImmutable]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_classMethods release]; - [_instanceMethods release]; - [_instanceVariables release]; - - [super dealloc]; -} -@end Index: src/OFInvertedCharacterSet.h ================================================================== --- src/OFInvertedCharacterSet.h +++ src/OFInvertedCharacterSet.h @@ -17,11 +17,10 @@ #import "OFCharacterSet.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFInvertedCharacterSet: OFCharacterSet { OFCharacterSet *_characterSet; bool (*_characterIsMember)(id, SEL, of_unichar_t); } Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -131,17 +131,18 @@ ULONG _cancelSignal; #else of_socket_t _cancelFD[2]; struct sockaddr_in _cancelAddr; #endif -#ifdef OF_HAVE_THREADS - OFMutex *_mutex; +#ifdef OF_AMIGAOS + ULONG _execSignalMask; #endif +@private OFMutableData *_queueActions; OFMutableArray *_queueObjects; -#ifdef OF_AMIGAOS - ULONG _execSignalMask; +#ifdef OF_HAVE_THREADS + OFMutex *_mutex; #endif OF_RESERVE_IVARS(4) } /*! Index: src/OFKqueueKernelEventObserver.h ================================================================== --- src/OFKqueueKernelEventObserver.h +++ src/OFKqueueKernelEventObserver.h @@ -19,13 +19,12 @@ OF_ASSUME_NONNULL_BEGIN @class OFMutableArray OF_GENERIC(ObjectType); -OF_SUBCLASSING_RESTRICTED @interface OFKqueueKernelEventObserver: OFKernelEventObserver { int _kernelQueue; } @end OF_ASSUME_NONNULL_END Index: src/OFLHAArchive.m ================================================================== --- src/OFLHAArchive.m +++ src/OFLHAArchive.m @@ -387,11 +387,11 @@ OFLHADecompressingStream *decompressingStream = (OFLHADecompressingStream *)_decompressedStream; [decompressingStream close]; toRead = - _entry.compressedSize - decompressingStream->_bytesConsumed; + _entry.compressedSize - decompressingStream.bytesConsumed; stream = _stream; } if ([stream isKindOfClass: [OFSeekableStream class]] && Index: src/OFLHAArchiveEntry.h ================================================================== --- src/OFLHAArchiveEntry.h +++ src/OFLHAArchiveEntry.h @@ -31,13 +31,10 @@ * * @brief A class which represents an entry in an LHA archive. */ @interface OFLHAArchiveEntry: OFObject { -#ifdef OF_LHA_ARCHIVE_ENTRY_M -@public -#endif OFString *_fileName, *_Nullable _directoryName, *_compressionMethod; uint32_t _compressedSize, _uncompressedSize; OFDate *_date; uint8_t _headerLevel; uint16_t _CRC16; Index: src/OFLHAArchiveEntry.m ================================================================== --- src/OFLHAArchiveEntry.m +++ src/OFLHAArchiveEntry.m @@ -15,12 +15,10 @@ * file. */ #include "config.h" -#define OF_LHA_ARCHIVE_ENTRY_M - #include #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" #import "OFArray.h" @@ -35,10 +33,11 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #import "OFUnsupportedVersionException.h" +@implementation OFLHAArchiveEntry static OFDate * parseMSDOSDate(uint32_t MSDOSDate) { uint16_t year = ((MSDOSDate & 0xFE000000) >> 25) + 1980; uint8_t month = (MSDOSDate & 0x1E00000) >> 21; @@ -306,11 +305,10 @@ *fileNameLength = length - pos; *directoryName = cString; *directoryNameLength = pos; } -@implementation OFLHAArchiveEntry + (instancetype)entryWithFileName: (OFString *)fileName { return [[[self alloc] initWithFileName: fileName] autorelease]; } Index: src/OFLHADecompressingStream.h ================================================================== --- src/OFLHADecompressingStream.h +++ src/OFLHADecompressingStream.h @@ -19,14 +19,12 @@ OF_ASSUME_NONNULL_BEGIN #define OF_LHA_DECOMPRESSING_STREAM_BUFFER_SIZE 4096 -OF_SUBCLASSING_RESTRICTED @interface OFLHADecompressingStream: OFStream { -@public OFStream *_stream; uint8_t _distanceBits, _dictionaryBits; unsigned char _buffer[OF_LHA_DECOMPRESSING_STREAM_BUFFER_SIZE]; uint32_t _bytesConsumed; uint16_t _bufferIndex, _bufferLength; @@ -43,12 +41,14 @@ bool _currentIsExtendedLength, _skip; uint8_t *_Nullable _codesLengths; uint16_t _length; uint32_t _distance; } + +@property (readonly, nonatomic) uint32_t bytesConsumed; - (instancetype)of_initWithStream: (OFStream *)stream distanceBits: (uint8_t)distanceBits dictionaryBits: (uint8_t)dictionaryBits; @end OF_ASSUME_NONNULL_END Index: src/OFLHADecompressingStream.m ================================================================== --- src/OFLHADecompressingStream.m +++ src/OFLHADecompressingStream.m @@ -42,10 +42,13 @@ STATE_BLOCK_DIST_LENGTH, STATE_BLOCK_DIST_LENGTH_EXTRA, STATE_BLOCK_LEN_DIST_PAIR }; +@implementation OFLHADecompressingStream +@synthesize bytesConsumed = _bytesConsumed; + static OF_INLINE bool tryReadBits(OFLHADecompressingStream *stream, uint16_t *bits, uint8_t count) { uint16_t ret = stream->_savedBits; @@ -89,11 +92,10 @@ *bits = ret; return true; } -@implementation OFLHADecompressingStream - (instancetype)of_initWithStream: (OFStream *)stream distanceBits: (uint8_t)distanceBits dictionaryBits: (uint8_t)dictionaryBits { self = [super init]; Index: src/OFList.h ================================================================== --- src/OFList.h +++ src/OFList.h @@ -171,18 +171,6 @@ #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # undef ObjectType #endif @end -@interface OFListEnumerator: OFEnumerator -{ - OFList *_list; - of_list_object_t *_Nullable _current; - unsigned long _mutations; - unsigned long *_Nullable _mutationsPtr; -} - -- (instancetype)initWithList: (OFList *)list - mutationsPointer: (unsigned long *)mutationsPtr; -@end - OF_ASSUME_NONNULL_END Index: src/OFList.m ================================================================== --- src/OFList.m +++ src/OFList.m @@ -25,10 +25,22 @@ #import "OFXMLElement.h" #import "OFArray.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" + +@interface OFListEnumerator: OFEnumerator +{ + OFList *_list; + of_list_object_t *_Nullable _current; + unsigned long _mutations; + unsigned long *_Nullable _mutationsPtr; +} + +- (instancetype)initWithList: (OFList *)list + mutationsPointer: (unsigned long *)mutationsPtr; +@end @implementation OFList @synthesize firstListObject = _firstListObject; @synthesize lastListObject = _lastListObject; Index: src/OFMapTableDictionary.h ================================================================== --- src/OFMapTableDictionary.h +++ src/OFMapTableDictionary.h @@ -20,15 +20,14 @@ OF_ASSUME_NONNULL_BEGIN @class OFMapTable; @class OFMapTableEnumerator; -OF_SUBCLASSING_RESTRICTED @interface OFMapTableDictionary: OFDictionary { OFMapTable *_mapTable; } - (instancetype)initWithCapacity: (size_t)capacity; @end OF_ASSUME_NONNULL_END Index: src/OFMapTableSet.h ================================================================== --- src/OFMapTableSet.h +++ src/OFMapTableSet.h @@ -19,15 +19,14 @@ OF_ASSUME_NONNULL_BEGIN @class OFMapTable; -OF_SUBCLASSING_RESTRICTED @interface OFMapTableSet: OFSet { OFMapTable *_mapTable; } - (instancetype)initWithCapacity: (size_t)capacity; @end OF_ASSUME_NONNULL_END Index: src/OFMutableAdjacentArray.h ================================================================== --- src/OFMutableAdjacentArray.h +++ src/OFMutableAdjacentArray.h @@ -19,14 +19,13 @@ OF_ASSUME_NONNULL_BEGIN @class OFMutableData; -OF_SUBCLASSING_RESTRICTED @interface OFMutableAdjacentArray: OFMutableArray { OFMutableData *_array; unsigned long _mutations; } @end OF_ASSUME_NONNULL_END Index: src/OFMutableAdjacentArray.m ================================================================== --- src/OFMutableAdjacentArray.m +++ src/OFMutableAdjacentArray.m @@ -19,10 +19,11 @@ #include #import "OFMutableAdjacentArray.h" #import "OFAdjacentArray.h" +#import "OFArray+Private.h" #import "OFData.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" Index: src/OFMutableArray.h ================================================================== --- src/OFMutableArray.h +++ src/OFMutableArray.h @@ -44,14 +44,10 @@ */ @interface OFMutableArray OF_GENERIC(ObjectType): OFArray OF_GENERIC(ObjectType) #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief Creates a new OFMutableArray with enough memory to hold the specified * number of objects. * * @param capacity The initial capacity for the OFMutableArray Index: src/OFMutableDictionary.h ================================================================== --- src/OFMutableDictionary.h +++ src/OFMutableDictionary.h @@ -45,14 +45,10 @@ OFDictionary OF_GENERIC(KeyType, ObjectType) #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define KeyType id # define ObjectType id #endif -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief Creates a new OFMutableDictionary with enough memory to hold the * specified number of objects. * * @param capacity The initial capacity for the OFMutableDictionary Index: src/OFMutableMapTableDictionary.h ================================================================== --- src/OFMutableMapTableDictionary.h +++ src/OFMutableMapTableDictionary.h @@ -19,13 +19,12 @@ OF_ASSUME_NONNULL_BEGIN @class OFMapTable; -OF_SUBCLASSING_RESTRICTED @interface OFMutableMapTableDictionary: OFMutableDictionary { OFMapTable *_mapTable; } @end OF_ASSUME_NONNULL_END Index: src/OFMutableMapTableSet.h ================================================================== --- src/OFMutableMapTableSet.h +++ src/OFMutableMapTableSet.h @@ -19,13 +19,12 @@ OF_ASSUME_NONNULL_BEGIN @class OFMapTable; -OF_SUBCLASSING_RESTRICTED @interface OFMutableMapTableSet: OFMutableSet { OFMapTable *_mapTable; } @end OF_ASSUME_NONNULL_END Index: src/OFMutableSet.h ================================================================== --- src/OFMutableSet.h +++ src/OFMutableSet.h @@ -29,14 +29,10 @@ */ @interface OFMutableSet OF_GENERIC(ObjectType): OFSet OF_GENERIC(ObjectType) #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief Creates a new OFMutableSet with enough memory to hold the specified * number of objects. * * @param capacity The initial capacity for the OFMutableSet Index: src/OFMutableString.h ================================================================== --- src/OFMutableString.h +++ src/OFMutableString.h @@ -23,14 +23,10 @@ * @class OFMutableString OFString.h ObjFW/OFString.h * * @brief A class for storing and modifying strings. */ @interface OFMutableString: OFString -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief Sets the character at the specified index. * * @param character The character to set * @param index The index where to set the character Index: src/OFMutableUTF8String.h ================================================================== --- src/OFMutableUTF8String.h +++ src/OFMutableUTF8String.h @@ -18,15 +18,13 @@ #import "OFMutableString.h" #import "OFUTF8String.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFMutableUTF8String: OFMutableString { -@public struct of_string_utf8_ivars *restrict _s; struct of_string_utf8_ivars _storage; } @end OF_ASSUME_NONNULL_END Index: src/OFMutableUTF8String.m ================================================================== --- src/OFMutableUTF8String.m +++ src/OFMutableUTF8String.m @@ -374,11 +374,11 @@ _s->cString[_s->cStringLength] = 0; if ([string isKindOfClass: [OFUTF8String class]] || [string isKindOfClass: [OFMutableUTF8String class]]) { - if (((OFUTF8String *)string)->_s->isUTF8) + if (((OFMutableUTF8String *)string)->_s->isUTF8) _s->isUTF8 = true; } else _s->isUTF8 = true; } @@ -549,11 +549,11 @@ _s->cStringLength = newCStringLength; _s->length += string.length; if ([string isKindOfClass: [OFUTF8String class]] || [string isKindOfClass: [OFMutableUTF8String class]]) { - if (((OFUTF8String *)string)->_s->isUTF8) + if (((OFMutableUTF8String *)string)->_s->isUTF8) _s->isUTF8 = true; } else _s->isUTF8 = true; } @@ -642,11 +642,11 @@ _s->cStringLength = newCStringLength; _s->length = newLength; if ([replacement isKindOfClass: [OFUTF8String class]] || [replacement isKindOfClass: [OFMutableUTF8String class]]) { - if (((OFUTF8String *)replacement)->_s->isUTF8) + if (((OFMutableUTF8String *)replacement)->_s->isUTF8) _s->isUTF8 = true; } else _s->isUTF8 = true; } @@ -729,11 +729,11 @@ _s->cStringLength = newCStringLength; _s->length = newLength; if ([replacement isKindOfClass: [OFUTF8String class]] || [replacement isKindOfClass: [OFMutableUTF8String class]]) { - if (((OFUTF8String *)replacement)->_s->isUTF8) + if (((OFMutableUTF8String *)replacement)->_s->isUTF8) _s->isUTF8 = true; } else _s->isUTF8 = true; } Index: src/OFNonretainedObjectValue.h ================================================================== --- src/OFNonretainedObjectValue.h +++ src/OFNonretainedObjectValue.h @@ -17,13 +17,12 @@ #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFNonretainedObjectValue: OFValue { id _object; } @end OF_ASSUME_NONNULL_END Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -296,10 +296,15 @@ /*! * @brief The OFNumber as a `double`. */ @property (readonly, nonatomic) double doubleValue; +/*! + * @brief The OFNumber as a string. + */ +@property (readonly, nonatomic) OFString *stringValue; + #ifdef OF_HAVE_UNAVAILABLE + (instancetype)valueWithBytes: (const void *)bytes objCType: (const char *)objCType OF_UNAVAILABLE; + (instancetype)valueWithPointer: (const void *)pointer OF_UNAVAILABLE; + (instancetype)valueWithNonretainedObject: (id)object OF_UNAVAILABLE; Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -1114,10 +1114,15 @@ { return [self retain]; } - (OFString *)description +{ + return [self stringValue]; +} + +- (OFString *)stringValue { OFMutableString *ret; switch (_type) { case OF_NUMBER_TYPE_BOOL: Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -103,20 +103,16 @@ uint32_t of_hash_seed; static const char * typeEncodingForSelector(Class class, SEL selector) { -#if defined(OF_OBJFW_RUNTIME) - return class_getMethodTypeEncoding(class, selector); -#elif defined(OF_APPLE_RUNTIME) - Method m; + Method method; - if ((m = class_getInstanceMethod(class, selector)) == NULL) + if ((method = class_getInstanceMethod(class, selector)) == NULL) return NULL; - return method_getTypeEncoding(m); -#endif + return method_getTypeEncoding(method); } #if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__) static void uncaughtExceptionHandler(id exception) @@ -362,55 +358,16 @@ } + (void)inheritMethodsFromClass: (Class)class { Class superclass = [self superclass]; + Method *methodList; + unsigned int count; if ([self isSubclassOfClass: class]) return; -#if defined(OF_OBJFW_RUNTIME) - for (struct objc_method_list *methodList = - object_getClass(class)->methodList; - methodList != NULL; methodList = methodList->next) { - for (unsigned int i = 0; i < methodList->count; i++) { - SEL selector = (SEL)&methodList->methods[i].selector; - - /* - * Don't replace methods implemented in the receiving - * class. - */ - if ([self methodForSelector: selector] != - [superclass methodForSelector: selector]) - continue; - - [self replaceClassMethod: selector - withMethodFromClass: class]; - } - } - - for (struct objc_method_list *methodList = class->methodList; - methodList != NULL; methodList = methodList->next) { - for (unsigned int i = 0; i < methodList->count; i++) { - SEL selector = (SEL)&methodList->methods[i].selector; - - /* - * Don't replace methods implemented in the receiving - * class. - */ - if ([self instanceMethodForSelector: selector] != - [superclass instanceMethodForSelector: selector]) - continue; - - [self replaceInstanceMethod: selector - withMethodFromClass: class]; - } - } -#elif defined(OF_APPLE_RUNTIME) - Method *methodList; - unsigned int count; - methodList = class_copyMethodList(object_getClass(class), &count); @try { for (unsigned int i = 0; i < count; i++) { SEL selector = method_getName(methodList[i]); @@ -446,11 +403,10 @@ withMethodFromClass: class]; } } @finally { free(methodList); } -#endif [self inheritMethodsFromClass: superclass]; } + (bool)resolveClassMethod: (SEL)selector Index: src/OFPlugin.h ================================================================== --- src/OFPlugin.h +++ src/OFPlugin.h @@ -38,11 +38,11 @@ * * @brief Provides a system for loading plugins at runtime. */ @interface OFPlugin: OFObject { - of_plugin_handle_t _handle; + of_plugin_handle_t _pluginHandle; OF_RESERVE_IVARS(4) } /*! * @brief Loads a plugin from a file. Index: src/OFPlugin.m ================================================================== --- src/OFPlugin.m +++ src/OFPlugin.m @@ -107,11 +107,11 @@ of_dlclose(handle); @throw [OFInitializationFailedException exceptionWithClass: self]; } - plugin->_handle = handle; + plugin->_pluginHandle = handle; return plugin; } - (instancetype)init { @@ -129,12 +129,12 @@ return [super init]; } - (void)dealloc { - of_plugin_handle_t h = _handle; + of_plugin_handle_t h = _pluginHandle; [super dealloc]; of_dlclose(h); } @end Index: src/OFPointValue.h ================================================================== --- src/OFPointValue.h +++ src/OFPointValue.h @@ -17,13 +17,12 @@ #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFPointValue: OFValue { of_point_t _point; } @end OF_ASSUME_NONNULL_END Index: src/OFPointerValue.h ================================================================== --- src/OFPointerValue.h +++ src/OFPointerValue.h @@ -17,13 +17,12 @@ #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFPointerValue: OFValue { void *_pointer; } @end OF_ASSUME_NONNULL_END Index: src/OFPollKernelEventObserver.h ================================================================== --- src/OFPollKernelEventObserver.h +++ src/OFPollKernelEventObserver.h @@ -19,15 +19,14 @@ OF_ASSUME_NONNULL_BEGIN @class OFMutableData; -OF_SUBCLASSING_RESTRICTED @interface OFPollKernelEventObserver: OFKernelEventObserver { OFMutableData *_FDs; int _maxFD; id __unsafe_unretained *_FDToObject; } @end OF_ASSUME_NONNULL_END Index: src/OFRangeCharacterSet.h ================================================================== --- src/OFRangeCharacterSet.h +++ src/OFRangeCharacterSet.h @@ -17,13 +17,12 @@ #import "OFCharacterSet.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFRangeCharacterSet: OFCharacterSet { of_range_t _range; } @end OF_ASSUME_NONNULL_END Index: src/OFRangeValue.h ================================================================== --- src/OFRangeValue.h +++ src/OFRangeValue.h @@ -17,13 +17,12 @@ #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFRangeValue: OFValue { of_range_t _range; } @end OF_ASSUME_NONNULL_END Index: src/OFRectangleValue.h ================================================================== --- src/OFRectangleValue.h +++ src/OFRectangleValue.h @@ -17,13 +17,12 @@ #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFRectangleValue: OFValue { of_rectangle_t _rectangle; } @end OF_ASSUME_NONNULL_END Index: src/OFSHA224Or256Hash.h ================================================================== --- src/OFSHA224Or256Hash.h +++ src/OFSHA224Or256Hash.h @@ -26,21 +26,24 @@ * * @brief A base class for SHA-224 and SHA-256. */ @interface OFSHA224Or256Hash: OFObject { +@private OFSecureData *_iVarsData; +@protected struct of_sha224_or_256_hash_ivars { uint32_t state[8]; uint64_t bits; union of_sha224_or_256_hash_buffer { uint8_t bytes[64]; uint32_t words[64]; } buffer; size_t bufferLength; } *_iVars; +@private bool _calculated; OF_RESERVE_IVARS(4) } @end OF_ASSUME_NONNULL_END Index: src/OFSHA384Or512Hash.h ================================================================== --- src/OFSHA384Or512Hash.h +++ src/OFSHA384Or512Hash.h @@ -26,21 +26,24 @@ * * @brief A base class for SHA-384 and SHA-512. */ @interface OFSHA384Or512Hash: OFObject { +@private OFSecureData *_iVarsData; +@protected struct of_sha384_or_512_hash_ivars { uint64_t state[8]; uint64_t bits[2]; union of_sha384_or_512_hash_buffer { uint8_t bytes[128]; uint64_t words[80]; } buffer; size_t bufferLength; } *_iVars; +@private bool _calculated; OF_RESERVE_IVARS(4) } @end OF_ASSUME_NONNULL_END Index: src/OFSecureData.h ================================================================== --- src/OFSecureData.h +++ src/OFSecureData.h @@ -20,40 +20,38 @@ OF_ASSUME_NONNULL_BEGIN /*! * @class OFSecureData OFSecureData.h ObjFW/OFSecureData.h * - * @brief A class for storing arbitrary data in secure memory, securely wiping - * it when it gets deallocated. + * @brief A class for storing arbitrary data in secure (non-swappable) memory, + * securely wiping it when it gets deallocated. * - * @note Secure memory might be unavailable on the platform, in which case this - * falls back to insecure (potentially swappable) memory. + * @warning Non-swappable memory might be unavailable, in which case this falls + * back to swappable memory, but still wipes the data when it gets + * deallocated. Check the @ref swappable property to see whether a + * particular OFSecureData was allocated in swappable memory. */ OF_SUBCLASSING_RESTRICTED @interface OFSecureData: OFData { struct page *_page; + bool _swappable; } -#ifdef OF_HAVE_CLASS_PROPERTIES -@property (class, readonly, nonatomic, getter=isSecure) bool secure; -#endif +/*! + * @brief Whether the OFSecureData is in swappable memory. + */ +@property (readonly, nonatomic, getter=isSwappable) bool swappable; /*! * @brief All items of the OFSecureData as a C array. * * Modifying the returned array directly is allowed and will change the contents * of the data. */ @property (readonly, nonatomic) void *mutableItems OF_RETURNS_INNER_POINTER; -/*! - * @brief Whether OFSecureData is secure, meaning preventing the data from - * being swapped out is supported. - */ -+ (bool)isSecure; - /*! * @brief Preallocates the specified number of bytes. * * This is useful to allocate secure memory before enabling a sandbox that does * not allow it anymore. Index: src/OFSecureData.m ================================================================== --- src/OFSecureData.m +++ src/OFSecureData.m @@ -40,10 +40,11 @@ #define CHUNK_SIZE 16 struct page { struct page *next, *previous; void *map; + bool swappable; unsigned char *page; }; #if defined(OF_HAVE_COMPILER_TLS) static thread_local struct page *firstPage = NULL; @@ -59,11 +60,11 @@ static struct page **preallocatedPages = NULL; static size_t numPreallocatedPages = 0; #endif static void * -mapPages(size_t numPages) +mapPages(size_t numPages, bool *swappable) { size_t pageSize = [OFSystemInfo pageSize]; void *pointer; if (numPages > SIZE_MAX / pageSize) @@ -73,32 +74,33 @@ if ((pointer = mmap(NULL, numPages * pageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) @throw [OFOutOfMemoryException exceptionWithRequestedSize: pageSize]; - if (mlock(pointer, numPages * pageSize) != 0 && errno != EPERM) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; + *swappable = (mlock(pointer, numPages * pageSize) != 0); #else if ((pointer = malloc(numPages * pageSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: pageSize]; + + *swappable = true; #endif return pointer; } static void -unmapPages(void *pointer, size_t numPages) +unmapPages(void *pointer, size_t numPages, bool swappable) { size_t pageSize = [OFSystemInfo pageSize]; if (numPages > SIZE_MAX / pageSize) @throw [OFOutOfRangeException exception]; #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) - munlock(pointer, numPages * pageSize); + if (!swappable) + munlock(pointer, numPages * pageSize); munmap(pointer, numPages * pageSize); #else free(pointer); #endif } @@ -152,11 +154,11 @@ if ((page->map = calloc(1, mapSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: mapSize]; - page->page = mapPages(1); + page->page = mapPages(1, &page->swappable); of_explicit_memset(page->page, 0, pageSize); #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) lastPage = of_tlskey_get(lastPageKey); #endif @@ -191,11 +193,11 @@ for (size_t i = 0; i < mapSize; i++) if (map[i] != 0) return; - unmapPages(page->page, 1); + unmapPages(page->page, 1, page->swappable); free(page->map); if (page->previous != NULL) page->previous->next = page->next; if (page->next != NULL) @@ -261,10 +263,12 @@ for (size_t i = 0; i < chunks; i++) of_bitset_clear(page->map, chunkIndex + i); } @implementation OFSecureData +@synthesize swappable = _swappable; + #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) + (void)initialize { if (self != [OFSecureData class]) return; @@ -275,42 +279,10 @@ @throw [OFInitializationFailedException exceptionWithClass: self]; } #endif -+ (bool)isSecure -{ -#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) - bool isSecure = true; - size_t pageSize = [OFSystemInfo pageSize]; - void *pointer; - - if ((pointer = mmap(NULL, pageSize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; - - if (mlock(pointer, pageSize) != 0) { - if (errno != EPERM) { - munmap(pointer, pageSize); - - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; - } - - isSecure = false; - } - - munlock(pointer, pageSize); - munmap(pointer, pageSize); - - return isSecure; -#else - return false; -#endif -} - + (void)preallocateMemoryWithSize: (size_t)size { size_t pageSize = [OFSystemInfo pageSize]; size_t numPages = OF_ROUND_UP_POW2(pageSize, size) / pageSize; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) @@ -396,11 +368,11 @@ if (count > SIZE_MAX / itemSize) @throw [OFOutOfRangeException exception]; if (count * itemSize >= pageSize) _items = mapPages(OF_ROUND_UP_POW2(pageSize, - count * itemSize) / pageSize); + count * itemSize) / pageSize, &_swappable); else { #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page *lastPage = of_tlskey_get(lastPageKey); #endif @@ -422,10 +394,12 @@ if (_items == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: count * itemSize]; } + + _swappable = _page->swappable; } _itemSize = itemSize; _count = count; } @catch (id e) { @@ -496,11 +470,12 @@ { size_t pageSize = [OFSystemInfo pageSize]; if (_count * _itemSize > pageSize) unmapPages(_items, - OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / pageSize); + OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / pageSize, + _swappable); else if (_page != NULL) { if (_items != NULL) freeMemory(_page, _items, _count * _itemSize); removePageIfEmpty(_page); @@ -543,10 +518,13 @@ - (bool)isEqual: (id)object { OFData *otherData; unsigned char diff; + + if (object == self) + return true; if (![object isKindOfClass: [OFData class]]) return false; otherData = object; Index: src/OFSelectKernelEventObserver.h ================================================================== --- src/OFSelectKernelEventObserver.h +++ src/OFSelectKernelEventObserver.h @@ -30,14 +30,13 @@ #import "OFKernelEventObserver.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFSelectKernelEventObserver: OFKernelEventObserver { fd_set _readFDs, _writeFDs; int _maxFD; } @end OF_ASSUME_NONNULL_END Index: src/OFSet.h ================================================================== --- src/OFSet.h +++ src/OFSet.h @@ -67,14 +67,10 @@ @interface OFSet OF_GENERIC(ObjectType): OFObject #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief An array of all objects in the set. */ @property (readonly, nonatomic) OFArray OF_GENERIC(ObjectType) *allObjects; Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -194,20 +194,19 @@ * override these methods without the `lowlevel` prefix, you *will* break * caching and get broken results! */ @interface OFStream: OFObject { + bool _blocking; + id _Nullable _delegate; #if !defined(OF_SEEKABLE_STREAM_M) && !defined(OF_TCP_SOCKET_M) @private #endif char *_Nullable _readBuffer, *_Nullable _readBufferMemory; char *_Nullable _writeBuffer; size_t _readBufferLength, _writeBufferLength; bool _writeBuffered, _waitingForDelimiter; -@protected - bool _blocking; - id _Nullable _delegate; OF_RESERVE_IVARS(4) } /*! * @brief Whether the end of the stream has been reached. Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -119,14 +119,10 @@ * * @brief A class for handling strings. */ @interface OFString: OFObject -{ - OF_RESERVE_IVARS(4) -} - /*! * @brief The length of the string in Unicode codepoints. */ @property (readonly, nonatomic) size_t length; Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -65,11 +65,11 @@ static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; @interface OFTCPSocketAsyncConnectDelegate: OFObject + OFTCPSocketDelegate_Private, OFDNSResolverHostDelegate> { OFTCPSocket *_socket; OFString *_host; uint16_t _port; OFString *_SOCKS5Host; @@ -319,22 +319,22 @@ #endif [self didConnect]; } -- (void)resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - socketAddresses: (OFData *)socketAddresses - exception: (id)exception +- (void)resolver: (OFDNSResolver *)resolver + didResolveHost: (OFString *)host + addresses: (OFData *)addresses + exception: (id)exception { if (exception != nil) { _exception = [exception retain]; [self didConnect]; return; } - _socketAddresses = [socketAddresses copy]; + _socketAddresses = [addresses copy]; [self tryNextAddressWithRunLoopMode: [OFRunLoop currentRunLoop].currentMode]; } @@ -367,14 +367,14 @@ return; } @catch (OFInvalidFormatException *e) { } [[OFThread DNSResolver] - asyncResolveSocketAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY - runLoopMode: runLoopMode - delegate: self]; + asyncResolveAddressesForHost: host + addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY + runLoopMode: runLoopMode + delegate: self]; } - (void)sendSOCKS5Request { OFData *data = [OFData dataWithItems: "\x05\x01\x00" @@ -810,12 +810,12 @@ if (_SOCKS5Host != nil) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; socketAddresses = [[OFThread DNSResolver] - resolveSocketAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY]; + resolveAddressesForHost: host + addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY]; address = *(of_socket_address_t *)[socketAddresses itemAtIndex: 0]; of_socket_address_set_port(&address, port); if ((_socket = socket(address.sockaddr.sockaddr.sa_family, Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -63,13 +63,11 @@ */ @interface OFThread: OFObject #ifdef OF_HAVE_THREADS { -# ifdef OF_THREAD_M -@public -# endif +@private of_thread_t _thread; of_thread_attr_t _attr; enum of_thread_running { OF_THREAD_NOT_RUNNING, OF_THREAD_RUNNING, @@ -79,15 +77,13 @@ # ifdef OF_HAVE_BLOCKS of_thread_block_t _Nullable _threadBlock; # endif jmp_buf _exitEnv; id _returnValue; -@protected bool _supportsSockets; OFRunLoop *_Nullable _runLoop; OFMutableDictionary *_threadDictionary; -@private OFString *_Nullable _name; # ifdef OF_HAVE_SOCKETS OFDNSResolver *_DNSResolver; # endif OF_RESERVE_IVARS(4) Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -13,16 +13,15 @@ * 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. */ -#define OF_THREAD_M +#include "config.h" + #define _POSIX_TIMERS #define __NO_EXT_QNX -#include "config.h" - #include #include #include #include @@ -90,11 +89,16 @@ # import "socket.h" # endif static of_tlskey_t threadSelfKey; static OFThread *mainThread; +#elif defined(OF_HAVE_SOCKETS) +static OFDNSResolver *DNSResolver; +#endif +@implementation OFThread +#ifdef OF_HAVE_THREADS static void callMain(id object) { OFThread *thread = (OFThread *)object; OFString *name; @@ -143,16 +147,11 @@ thread->_running = OF_THREAD_WAITING_FOR_JOIN; [thread release]; } -#elif defined(OF_HAVE_SOCKETS) -static OFDNSResolver *DNSResolver; -#endif -@implementation OFThread -#ifdef OF_HAVE_THREADS @synthesize name = _name; # ifdef OF_HAVE_BLOCKS @synthesize threadBlock = _threadBlock; # endif Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -264,12 +264,12 @@ if (_socket != INVALID_SOCKET) @throw [OFAlreadyConnectedException exceptionWithSocket: self]; socketAddresses = [[OFThread DNSResolver] - resolveSocketAddressesForHost: host - addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY]; + resolveAddressesForHost: host + addressFamily: OF_SOCKET_ADDRESS_FAMILY_ANY]; address = *(of_socket_address_t *)[socketAddresses itemAtIndex: 0]; of_socket_address_set_port(&address, port); port = [self of_bindToAddress: &address Index: src/OFUTF8String.h ================================================================== --- src/OFUTF8String.h +++ src/OFUTF8String.h @@ -19,11 +19,10 @@ OF_ASSUME_NONNULL_BEGIN @interface OFUTF8String: OFString { -@public /* * A pointer to the actual data. * * Since constant strings don't have `_storage`, they have to allocate * it on the first access. Strings created at runtime just set the Index: src/OFValue.m ================================================================== --- src/OFValue.m +++ src/OFValue.m @@ -166,10 +166,13 @@ - (bool)isEqual: (id)object { const char *objCType; size_t size; void *value, *otherValue; + + if (object == self) + return true; if (![object isKindOfClass: [OFValue class]]) return false; objCType = self.objCType; Index: src/OFWin32ConsoleStdIOStream.h ================================================================== --- src/OFWin32ConsoleStdIOStream.h +++ src/OFWin32ConsoleStdIOStream.h @@ -19,11 +19,10 @@ #import "OFStdIOStream.h" OF_ASSUME_NONNULL_BEGIN -OF_SUBCLASSING_RESTRICTED @interface OFWin32ConsoleStdIOStream: OFStdIOStream { HANDLE _handle; of_char16_t _incompleteUTF16Surrogate; char _incompleteUTF8Surrogate[4]; Index: src/OFXMLElementBuilder.h ================================================================== --- src/OFXMLElementBuilder.h +++ src/OFXMLElementBuilder.h @@ -102,15 +102,15 @@ * * It can also be used to build OFXMLElements from parts of the document by * first parsing stuff using the OFXMLParser with another delegate and then * setting the OFXMLElementBuilder as delegate for the parser. */ -OF_SUBCLASSING_RESTRICTED @interface OFXMLElementBuilder: OFObject { OFMutableArray OF_GENERIC(OFXMLElement *) *_stack; id _Nullable _delegate; + OF_RESERVE_IVARS(4) } /*! * @brief The delegate for the OFXMLElementBuilder. */ Index: src/OFXMLProcessingInstructions.m ================================================================== --- src/OFXMLProcessingInstructions.m +++ src/OFXMLProcessingInstructions.m @@ -85,12 +85,12 @@ if (![object isKindOfClass: [OFXMLProcessingInstructions class]]) return false; processingInstructions = object; - return ([processingInstructions->_processingInstructions - isEqual: _processingInstructions]); + return [processingInstructions->_processingInstructions + isEqual: _processingInstructions]; } - (uint32_t)hash { return _processingInstructions.hash; Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -42,11 +42,10 @@ #import "OFNull.h" #import "OFMethodSignature.h" #import "OFInvocation.h" -#import "OFIntrospection.h" #import "OFNumber.h" #import "OFDate.h" #import "OFURL.h" #import "OFURLHandler.h" @@ -73,12 +72,14 @@ # import "OFStreamSocket.h" # import "OFTCPSocket.h" # import "OFUDPSocket.h" # import "OFTLSSocket.h" # import "OFKernelEventObserver.h" -# import "OFDNSResolver.h" +# import "OFDNSQuery.h" # import "OFDNSResourceRecord.h" +# import "OFDNSResponse.h" +# import "OFDNSResolver.h" #endif #ifdef OF_HAVE_SOCKETS # ifdef OF_HAVE_THREADS # import "OFHTTPClient.h" # endif @@ -132,11 +133,10 @@ #import "OFException.h" #ifdef OF_HAVE_SOCKETS # import "OFAcceptFailedException.h" # import "OFAlreadyConnectedException.h" # import "OFBindFailedException.h" -# import "OFResolveHostFailedException.h" #endif #import "OFChangeCurrentDirectoryPathFailedException.h" #import "OFChecksumMismatchException.h" #ifdef OF_HAVE_THREADS # import "OFConditionBroadcastFailedException.h" @@ -150,10 +150,15 @@ #import "OFCopyItemFailedException.h" #import "OFCreateDirectoryFailedException.h" #import "OFCreateSymbolicLinkFailedException.h" #ifdef OF_WINDOWS # import "OFCreateWindowsRegistryKeyFailedException.h" +#endif +#ifdef OF_HAVE_SOCKETS +# import "OFDNSQueryFailedException.h" +#endif +#ifdef OF_WINDOWS # import "OFDeleteWindowsRegistryKeyFailedException.h" # import "OFDeleteWindowsRegistryValueFailedException.h" #endif #import "OFEnumerationMutationException.h" #ifdef OF_HAVE_FILES @@ -196,10 +201,13 @@ #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFReadOrWriteFailedException.h" #import "OFRemoveItemFailedException.h" +#ifdef OF_HAVE_SOCKETS +# import "OFResolveHostFailedException.h" +#endif #import "OFRetrieveItemAttributesFailedException.h" #import "OFSandboxActivationFailedException.h" #import "OFSeekFailedException.h" #import "OFSetItemAttributesFailedException.h" #import "OFSetOptionFailedException.h" Index: src/block.h ================================================================== --- src/block.h +++ src/block.h @@ -48,12 +48,12 @@ /* * Clang has implicit declarations for these, but they are dllimport. When * compiling ObjFW itself or using it as a static library, these need to be * dllexport. Interestingly, this still works when using it as a shared library. */ -extern __declspec(dllexport) struct objc_abi_class _NSConcreteStackBlock; -extern __declspec(dllexport) struct objc_abi_class _NSConcreteGlobalBlock; +extern __declspec(dllexport) struct objc_class _NSConcreteStackBlock; +extern __declspec(dllexport) struct objc_class _NSConcreteGlobalBlock; extern __declspec(dllexport) void _Block_object_assign(void *, const void *, const int); extern __declspec(dllexport) void _Block_object_dispose(const void *, const int); # endif Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -56,10 +56,11 @@ SRCS_PLUGINS = OFLoadPluginFailedException.m SRCS_SOCKETS = OFAcceptFailedException.m \ OFAlreadyConnectedException.m \ OFBindFailedException.m \ OFConnectionFailedException.m \ + OFDNSQueryFailedException.m \ OFHTTPRequestFailedException.m \ OFListenFailedException.m \ OFObserveFailedException.m \ OFResolveHostFailedException.m SRCS_THREADS = OFConditionBroadcastFailedException.m \ ADDED src/exceptions/OFDNSQueryFailedException.h Index: src/exceptions/OFDNSQueryFailedException.h ================================================================== --- src/exceptions/OFDNSQueryFailedException.h +++ src/exceptions/OFDNSQueryFailedException.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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. + */ + +#import "OFException.h" +#import "OFDNSQuery.h" +#import "OFDNSResolver.h" +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/*! + * @class OFDNSQueryFailedException \ + * OFDNSQueryFailedException.h ObjFW/OFDNSQueryFailedException.h + * + * @brief An exception indicating that a DNS query failed. + */ +@interface OFDNSQueryFailedException: OFException +{ + OFDNSQuery *_query; + of_dns_resolver_error_t _error; +} + +/*! + * @brief The query which could not be performed. + */ +@property (readonly, nonatomic) OFDNSQuery *query; + +/*! + * @brief The error from the resolver. + */ +@property (readonly, nonatomic) of_dns_resolver_error_t error; + +/*! + * @brief Creates a new, autoreleased DNS query failed exception. + * + * @param query The query which could not be performed + * @param error The error from the resolver + * @return A new, autoreleased address translation failed exception + */ ++ (instancetype)exceptionWithQuery: (OFDNSQuery *)query + error: (of_dns_resolver_error_t)error; + +/*! + * @brief Initializes an already allocated DNS query failed exception. + * + * @param query The query which could not be performed + * @param error The error from the resolver + * @return An initialized address translation failed exception + */ +- (instancetype)initWithQuery: (OFDNSQuery *)query + error: (of_dns_resolver_error_t)error; +@end + +#ifdef __cplusplus +extern "C" { +#endif +extern OFString *of_dns_resolver_error_to_string(of_dns_resolver_error_t error); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFDNSQueryFailedException.m Index: src/exceptions/OFDNSQueryFailedException.m ================================================================== --- src/exceptions/OFDNSQueryFailedException.m +++ src/exceptions/OFDNSQueryFailedException.m @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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 "OFDNSQueryFailedException.h" +#import "OFString.h" + +OFString * +of_dns_resolver_error_to_string(of_dns_resolver_error_t error) +{ + switch (error) { + case OF_DNS_RESOLVER_ERROR_TIMEOUT: + return @"The query timed out."; + case OF_DNS_RESOLVER_ERROR_CANCELED: + return @"The query was canceled."; + case OF_DNS_RESOLVER_ERROR_NO_RESULT: + return @"No result for the specified host with the specified " + @"type and class."; + case OF_DNS_RESOLVER_ERROR_SERVER_INVALID_FORMAT: + return @"The server considered the query to be malformed."; + case OF_DNS_RESOLVER_ERROR_SERVER_FAILURE: + return @"The server was unable to process due to an internal " + @"error."; + case OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR: + return @"The server returned an error that the domain does not " + @"exist."; + case OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED: + return @"The server does not have support for the requested " + @"query."; + case OF_DNS_RESOLVER_ERROR_SERVER_REFUSED: + return @"The server refused the query."; + default: + return @"Unknown error."; + } +} + +@implementation OFDNSQueryFailedException +@synthesize query = _query, error = _error; + ++ (instancetype)exceptionWithQuery: (OFDNSQuery *)query + error: (of_dns_resolver_error_t)error +{ + return [[[self alloc] initWithQuery: query + error: error] autorelease]; +} + +- (instancetype)initWithQuery: (OFDNSQuery *)query + error: (of_dns_resolver_error_t)error +{ + self = [super init]; + + @try { + _query = [query copy]; + _error = error; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_query release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"DNS query %@ could not be performed: %@", + _query, of_dns_resolver_error_to_string(_error)]; +} +@end Index: src/exceptions/OFResolveHostFailedException.h ================================================================== --- src/exceptions/OFResolveHostFailedException.h +++ src/exceptions/OFResolveHostFailedException.h @@ -15,42 +15,35 @@ * file. */ #import "OFException.h" #import "OFDNSResolver.h" -#import "OFDNSResourceRecord.h" OF_ASSUME_NONNULL_BEGIN /*! * @class OFResolveHostFailedException \ * OFResolveHostFailedException.h ObjFW/OFResolveHostFailedException.h * - * @brief An exception indicating the resolving a host failed. + * @brief An exception indicating that resolving a host failed. */ @interface OFResolveHostFailedException: OFException { OFString *_host; - of_dns_resource_record_class_t _recordClass; - of_dns_resource_record_type_t _recordType; + of_socket_address_family_t _addressFamily; of_dns_resolver_error_t _error; } /*! * @brief The host which could not be resolved. */ @property (readonly, nonatomic) OFString *host; /*! - * @brief The class code for the resource record to resolve to. - */ -@property (readonly, nonatomic) of_dns_resource_record_class_t recordClass; - -/*! - * @brief The type code for the resource record to resolve to. - */ -@property (readonly, nonatomic) of_dns_resource_record_type_t recordType; + * @brief The address family for which the host could not be resolved. + */ +@property (readonly, nonatomic) of_socket_address_family_t addressFamily; /*! * @brief The error from the resolver. */ @property (readonly, nonatomic) of_dns_resolver_error_t error; @@ -57,31 +50,29 @@ /*! * @brief Creates a new, autoreleased resolve host failed exception. * * @param host The host which could not be resolved - * @param recordClass The class code for the resource record to resolve to - * @param recordType The type code for the resource record to resolve to + * @param addressFamily The address family for which the host could not be + * resolved * @param error The error from the resolver * @return A new, autoreleased address translation failed exception */ + (instancetype)exceptionWithHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + addressFamily: (of_socket_address_family_t)addressFamily error: (of_dns_resolver_error_t)error; /*! - * @brief Initializes an already allocated address translation failed exception. + * @brief Initializes an already allocated resolve host failed exception. * - * @param host The host for which translation was requested - * @param recordClass The class code for the resource record to resolve to - * @param recordType The type code for the resource record to resolve to + * @param host The host which could not be resolved + * @param addressFamily The address family for which the host could not be + * resolved * @param error The error from the resolver * @return An initialized address translation failed exception */ - (instancetype)initWithHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + addressFamily: (of_socket_address_family_t)addressFamily error: (of_dns_resolver_error_t)error; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFResolveHostFailedException.m ================================================================== --- src/exceptions/OFResolveHostFailedException.m +++ src/exceptions/OFResolveHostFailedException.m @@ -16,38 +16,34 @@ */ #include "config.h" #import "OFResolveHostFailedException.h" +#import "OFDNSQueryFailedException.h" #import "OFString.h" @implementation OFResolveHostFailedException -@synthesize host = _host, recordClass = _recordClass, recordType = _recordType; -@synthesize error = _error; +@synthesize host = _host, addressFamily = _addressFamily, error = _error; + (instancetype)exceptionWithHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + addressFamily: (of_socket_address_family_t)addressFamily error: (of_dns_resolver_error_t)error { return [[[self alloc] initWithHost: host - recordClass: recordClass - recordType: recordType + addressFamily: addressFamily error: error] autorelease]; } - (instancetype)initWithHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType + addressFamily: (of_socket_address_family_t)addressFamily error: (of_dns_resolver_error_t)error { self = [super init]; @try { _host = [host copy]; - _recordClass = recordClass; - _recordType = recordType; + _addressFamily = addressFamily; _error = error; } @catch (id e) { [self release]; @throw e; } @@ -62,44 +58,10 @@ [super dealloc]; } - (OFString *)description { - OFString *error; - - switch (_error) { - case OF_DNS_RESOLVER_ERROR_TIMEOUT: - error = @"The query timed out."; - break; - case OF_DNS_RESOLVER_ERROR_CANCELED: - error = @"The query was canceled."; - break; - case OF_DNS_RESOLVER_ERROR_NO_RESULT: - error = @"No result for the specified host with the specified " - @"type and class."; - break; - case OF_DNS_RESOLVER_ERROR_SERVER_INVALID_FORMAT: - error = @"The server considered the query to be malformed."; - break; - case OF_DNS_RESOLVER_ERROR_SERVER_FAILURE: - error = @"The server was unable to process due to an internal " - @"error."; - break; - case OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR: - error = @"The server returned an error that the domain does " - @"not exist."; - break; - case OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED: - error = @"The server does not have support for the requested " - @"query."; - case OF_DNS_RESOLVER_ERROR_SERVER_REFUSED: - error = @"The server refused the query."; - break; - default: - error = @"Unknown error."; - break; - } - return [OFString stringWithFormat: - @"The host %@ could not be resolved: %@", _host, error]; + @"The host %@ could not be resolved: %@", + _host, of_dns_resolver_error_to_string(_error)]; } @end Index: src/forwarding/apple-forwarding-arm.S ================================================================== --- src/forwarding/apple-forwarding-arm.S +++ src/forwarding/apple-forwarding-arm.S @@ -34,11 +34,11 @@ .section __TEXT, __text, regular, pure_instructions .arm .align 2 _of_forward: stmfd sp!, {r0-r4, lr} - fstmfdd sp!, {d0-d7} + vstmdb sp!, {d0-d7} ldr r4, sel_forwardingTargetForSelector_$indirect_L0 L0: ldr r4, [pc, r4] @@ -59,18 +59,18 @@ beq 0f ldr r1, [sp, #64] cmp r0, r1 beq 0f - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} add sp, sp, #4 @ throw away r0 ldmfd sp!, {r1-r4, lr} b _objc_msgSend 0: - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} ldmfd sp!, {r0-r4, lr} b _of_method_not_found .data_region sel_forwardingTargetForSelector_$indirect_L0: @@ -78,11 +78,11 @@ .end_data_region .align 2 _of_forward_stret: stmfd sp!, {r0-r4, lr} - fstmfdd sp!, {d0-d7} + vstmdb sp!, {d0-d7} ldr r4, sel_forwardingTargetForSelector_$indirect_L1 L1: ldr r4, [pc, r4] @@ -106,21 +106,21 @@ cmp r0, r1 beq 0f mov r1, r0 - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} ldmfd sp!, {r0} add sp, sp, #4 @ throw away r1 ldmfd sp!, {r2-r4, lr} b _objc_msgSend_stret 0: - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} ldmfd sp!, {r0-r4, lr} b _of_method_not_found_stret .data_region sel_forwardingTargetForSelector_$indirect_L1: .long sel_forwardingTargetForSelector_-(L1+8) .end_data_region Index: src/forwarding/forwarding-arm-elf.S ================================================================== --- src/forwarding/forwarding-arm-elf.S +++ src/forwarding/forwarding-arm-elf.S @@ -27,11 +27,11 @@ .globl of_forward_stret .section .text of_forward: #ifdef HAVE_VFP2 - fstmfdd sp!, {d0-d7} + vstmdb sp!, {d0-d7} #endif stmfd sp!, {r0-r4, lr} ldr r4, sel_forwardingTargetForSelector_$indirect_.L0 .L0: @@ -66,27 +66,27 @@ bl objc_msg_lookup(PLT) mov r12, r0 ldmfd sp!, {r0-r4, lr} #ifdef HAVE_VFP2 - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} #endif bx r12 0: ldmfd sp!, {r0-r4, lr} #ifdef HAVE_VFP2 - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} #endif b of_method_not_found(PLT) .type of_forward, %function .size of_forward, .-of_forward of_forward_stret: #ifdef HAVE_VFP2 - fstmfdd sp!, {d0-d7} + vstmdb sp!, {d0-d7} #endif stmfd sp!, {r0-r4, lr} ldr r4, sel_forwardingTargetForSelector_$indirect_.L1 .L1: @@ -122,19 +122,19 @@ bl objc_msg_lookup_stret(PLT) mov r12, r0 ldmfd sp!, {r0-r4, lr} #ifdef HAVE_VFP2 - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} #endif bx r12 0: ldmfd sp!, {r0-r4, lr} #ifdef HAVE_VFP2 - fldmfdd sp!, {d0-d7} + vldmia sp!, {d0-d7} #endif b of_method_not_found_stret(PLT) .type of_forward_stret, %function .size of_forward_stret, .-of_forward_stret Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -16,11 +16,13 @@ class.m \ dtable.m \ exception.m \ hashtable.m \ init.m \ + ivar.m \ lookup.m \ + method.m \ misc.m \ property.m \ protocol.m \ selector.m \ sparsearray.m \ Index: src/runtime/ObjFWRT.h ================================================================== --- src/runtime/ObjFWRT.h +++ src/runtime/ObjFWRT.h @@ -59,168 +59,34 @@ #define NO false typedef struct objc_class *Class; typedef struct objc_object *id; typedef const struct objc_selector *SEL; +typedef const struct objc_method *Method; +#ifdef __OBJC__ +@class Protocol; +#else +typedef const struct objc_protocol *Protocol; +#endif +typedef const struct objc_ivar *Ivar; +typedef const struct objc_property *objc_property_t; #if !defined(__wii__) && !defined(__amigaos__) typedef bool BOOL; #endif typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); typedef void (*objc_uncaught_exception_handler_t)(id _Nullable); typedef void (*objc_enumeration_mutation_handler_t)(id _Nonnull); -struct objc_class { - Class _Nonnull isa; - Class _Nullable superclass; - const char *_Nonnull name; - unsigned long version; - unsigned long info; - long instanceSize; - struct objc_ivar_list *_Nullable iVars; - struct objc_method_list *_Nullable methodList; - struct objc_dtable *_Nonnull DTable; - Class _Nullable *_Nullable subclassList; - void *_Nullable siblingClass; - struct objc_protocol_list *_Nullable protocols; - void *_Nullable GCObjectType; - unsigned long ABIVersion; - int32_t *_Nonnull *_Nullable iVarOffsets; - struct objc_property_list *_Nullable properties; -}; - -enum objc_class_info { - OBJC_CLASS_INFO_CLASS = 0x001, - OBJC_CLASS_INFO_METACLASS = 0x002, - OBJC_CLASS_INFO_NEW_ABI = 0x010, - OBJC_CLASS_INFO_SETUP = 0x100, - OBJC_CLASS_INFO_LOADED = 0x200, - OBJC_CLASS_INFO_DTABLE = 0x400, - OBJC_CLASS_INFO_INITIALIZED = 0x800 -}; - -struct objc_object { - Class _Nonnull isa; -}; - -struct objc_selector { - uintptr_t UID; - const char *_Nullable typeEncoding; -}; - struct objc_super { id __unsafe_unretained _Nullable self; #ifdef __cplusplus Class _Nonnull class_; #else Class _Nonnull class; #endif }; -struct objc_method { - struct objc_selector selector; - IMP _Nonnull implementation; -}; - -struct objc_method_list { - struct objc_method_list *_Nullable next; - unsigned int count; - struct objc_method methods[1]; -}; - -struct objc_category { - const char *_Nonnull categoryName; - const char *_Nonnull className; - struct objc_method_list *_Nullable instanceMethods; - struct objc_method_list *_Nullable classMethods; - struct objc_protocol_list *_Nullable protocols; -}; - -struct objc_ivar { - const char *_Nonnull name; - const char *_Nonnull typeEncoding; - unsigned int offset; -}; - -struct objc_ivar_list { - unsigned int count; - struct objc_ivar iVars[1]; -}; - -enum objc_property_attributes { - OBJC_PROPERTY_READONLY = 0x01, - OBJC_PROPERTY_GETTER = 0x02, - OBJC_PROPERTY_ASSIGN = 0x04, - OBJC_PROPERTY_READWRITE = 0x08, - OBJC_PROPERTY_RETAIN = 0x10, - OBJC_PROPERTY_COPY = 0x20, - OBJC_PROPERTY_NONATOMIC = 0x40, - OBJC_PROPERTY_SETTER = 0x80 -}; - -enum objc_property_extended_attributes { - OBJC_PROPERTY_SYNTHESIZE = 0x1, - OBJC_PROPERTY_DYNAMIC = 0x2, - OBJC_PROPERTY_PROTOCOL = 0x3, - OBJC_PROPERTY_ATOMIC = 0x4, - OBJC_PROPERTY_WEAK = 0x8, - OBJC_PROPERTY_STRONG = 0x10, - OBJC_PROPERTY_UNSAFE_UNRETAINED = 0x20 -}; - -struct objc_property { - const char *_Nonnull name; - unsigned char attributes, extendedAttributes; - struct { - const char *_Nullable name; - const char *_Nullable typeEncoding; - } getter, setter; -}; - -struct objc_property_list { - unsigned int count; - struct objc_property_list *_Nullable next; - struct objc_property properties[1]; -}; - -struct objc_method_description { - const char *_Nonnull name; - const char *_Nonnull typeEncoding; -}; - -struct objc_method_description_list { - int count; - struct objc_method_description list[1]; -}; - -#ifdef __OBJC__ -# if __has_attribute(__objc_root_class__) -__attribute__((__objc_root_class__)) -# endif -@interface Protocol -{ -@public -#else -typedef struct { -#endif - Class _Nonnull isa; - const char *_Nonnull name; - struct objc_protocol_list *_Nullable protocolList; - struct objc_method_description_list *_Nullable instanceMethods; - struct objc_method_description_list *_Nullable classMethods; -#ifdef __OBJC__ -} -@end -#else -} Protocol; -#endif - -struct objc_protocol_list { - struct objc_protocol_list *_Nullable next; - long count; - Protocol *__unsafe_unretained _Nonnull list[1]; -}; - #ifdef __cplusplus extern "C" { #endif extern SEL _Nonnull sel_registerName(const char *_Nonnull name); extern const char *_Nonnull sel_getName(SEL _Nonnull selector); @@ -242,11 +108,11 @@ Protocol *_Nonnull protocol); extern IMP _Nullable class_getMethodImplementation(Class _Nullable class_, SEL _Nonnull selector); extern IMP _Nullable class_getMethodImplementation_stret(Class _Nullable class_, SEL _Nonnull selector); -extern const char *_Nullable class_getMethodTypeEncoding(Class _Nullable class_, +extern Method _Nullable class_getInstanceMethod(Class _Nullable class_, SEL _Nonnull selector); extern bool class_addMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding); extern IMP _Nullable class_replaceMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, @@ -258,10 +124,24 @@ extern const char *_Nonnull protocol_getName(Protocol *_Nonnull protocol); extern bool protocol_isEqual(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); extern bool protocol_conformsToProtocol(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); +extern Method _Nullable *_Nullable class_copyMethodList(Class _Nullable class_, + unsigned int *_Nullable outCount); +extern SEL _Nonnull method_getName(Method _Nonnull method); +extern const char *_Nullable method_getTypeEncoding(Method _Nonnull method); +extern Ivar _Nullable *_Nullable class_copyIvarList(Class _Nullable class_, + unsigned int *_Nullable outCount); +extern const char *_Nonnull ivar_getName(Ivar _Nonnull ivar); +extern const char *_Nonnull ivar_getTypeEncoding(Ivar _Nonnull ivar); +extern ptrdiff_t ivar_getOffset(Ivar _Nonnull ivar); +extern objc_property_t _Nullable *_Nullable class_copyPropertyList( + Class _Nullable class_, unsigned int *_Nullable outCount); +extern const char *_Nonnull property_getName(objc_property_t _Nonnull property); +extern char *_Nullable property_copyAttributeValue( + objc_property_t _Nonnull property, const char *_Nonnull name); extern void objc_exit(void); extern _Nullable objc_uncaught_exception_handler_t objc_setUncaughtExceptionHandler( objc_uncaught_exception_handler_t _Nullable handler); extern void objc_setForwardHandler(IMP _Nullable forward, @@ -274,11 +154,12 @@ * Used by the compiler, but can also be called manually. * * These declarations are also required to prevent Clang's implicit * declarations which include __declspec(dllimport) on Windows. */ -extern void __objc_exec_class(void *_Nonnull module); +struct objc_module; +extern void __objc_exec_class(struct objc_module *_Nonnull module); extern IMP _Nonnull objc_msg_lookup(id _Nullable object, SEL _Nonnull selector); extern IMP _Nonnull objc_msg_lookup_stret(id _Nullable object, SEL _Nonnull selector); extern IMP _Nonnull objc_msg_lookup_super(struct objc_super *_Nonnull super, SEL _Nonnull selector); Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -53,13 +53,13 @@ return objc_init(version, libc, stdout_, stderr_); } void __saveds -glue___objc_exec_class PPC_PARAMS(void *module) +glue___objc_exec_class PPC_PARAMS(struct objc_module *module) { - M68K_ARG(void *, module, a0) + M68K_ARG(struct objc_module *, module, a0) __objc_exec_class(module); } IMP __saveds @@ -505,17 +505,17 @@ M68K_ARG(SEL, selector, a1) return class_getMethodImplementation_stret(class, selector); } -const char *__saveds -glue_class_getMethodTypeEncoding PPC_PARAMS(Class class, SEL selector) +Method __saveds +glue_class_getInstanceMethod PPC_PARAMS(Class class, SEL selector) { M68K_ARG(Class, class, a0) M68K_ARG(SEL, selector, a1) - return class_getMethodTypeEncoding(class, selector); + return class_getInstanceMethod(class, selector); } bool __saveds glue_class_addMethod PPC_PARAMS(Class class, SEL selector, IMP implementation, const char *typeEncoding) @@ -631,5 +631,90 @@ void __saveds glue_objc_exit(void) { objc_exit(); } + +Ivar *__saveds +glue_class_copyIvarList PPC_PARAMS(Class class, unsigned int *outCount) +{ + M68K_ARG(Class, class, a0) + M68K_ARG(unsigned int *, outCount, a1) + + return class_copyIvarList(class, outCount); +} + +const char *__saveds +glue_ivar_getName PPC_PARAMS(Ivar ivar) +{ + M68K_ARG(Ivar, ivar, a0) + + return ivar_getName(ivar); +} + +const char *__saveds +glue_ivar_getTypeEncoding PPC_PARAMS(Ivar ivar) +{ + M68K_ARG(Ivar, ivar, a0) + + return ivar_getTypeEncoding(ivar); +} + +ptrdiff_t __saveds +glue_ivar_getOffset PPC_PARAMS(Ivar ivar) +{ + M68K_ARG(Ivar, ivar, a0) + + return ivar_getOffset(ivar); +} + +Method *__saveds +glue_class_copyMethodList PPC_PARAMS(Class class, unsigned int *outCount) +{ + M68K_ARG(Class, class, a0) + M68K_ARG(unsigned int *, outCount, a1) + + return class_copyMethodList(class, outCount); +} + +SEL __saveds +glue_method_getName PPC_PARAMS(Method method) +{ + M68K_ARG(Method, method, a0) + + return method_getName(method); +} + +const char *__saveds +glue_method_getTypeEncoding PPC_PARAMS(Method method) +{ + M68K_ARG(Method, method, a0) + + return method_getTypeEncoding(method); +} + +objc_property_t *__saveds +glue_class_copyPropertyList PPC_PARAMS(Class class, unsigned int *outCount) +{ + M68K_ARG(Class, class, a0) + M68K_ARG(unsigned int *, outCount, a1) + + return class_copyPropertyList(class, outCount); +} + +const char *__saveds +glue_property_getName PPC_PARAMS(objc_property_t property) +{ + M68K_ARG(objc_property_t, property, a0) + + return property_getName(property); +} + +char *__saveds +glue_property_copyAttributeValue PPC_PARAMS(objc_property_t property, + const char *name) +{ + M68K_ARG(objc_property_t, property, a0) + M68K_ARG(const char *, name, a1) + + return property_copyAttributeValue(property, name); +} Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -62,74 +62,84 @@ extern void *_EH_FRAME_OBJECTS__; #endif extern bool glue_objc_init(void); extern void glue___objc_exec_class(void); -extern IMP _Nonnull glue_objc_msg_lookup(void); -extern IMP _Nonnull glue_objc_msg_lookup_stret(void); -extern IMP _Nonnull glue_objc_msg_lookup_super(void); -extern IMP _Nonnull glue_objc_msg_lookup_super_stret(void); -extern Class _Nullable glue_objc_lookUpClass(void); -extern Class _Nullable glue_objc_getClass(void); -extern Class _Nonnull glue_objc_getRequiredClass(void); -extern Class _Nullable glue_objc_lookup_class(void); -extern Class _Nonnull glue_objc_get_class(void); +extern IMP glue_objc_msg_lookup(void); +extern IMP glue_objc_msg_lookup_stret(void); +extern IMP glue_objc_msg_lookup_super(void); +extern IMP glue_objc_msg_lookup_super_stret(void); +extern Class glue_objc_lookUpClass(void); +extern Class glue_objc_getClass(void); +extern Class glue_objc_getRequiredClass(void); +extern Class glue_objc_lookup_class(void); +extern Class glue_objc_get_class(void); extern void glue_objc_exception_throw(void); extern int glue_objc_sync_enter(void); extern int glue_objc_sync_exit(void); -extern id _Nullable glue_objc_getProperty(void); +extern id glue_objc_getProperty(void); extern void glue_objc_setProperty(void); extern void glue_objc_getPropertyStruct(void); extern void glue_objc_setPropertyStruct(void); extern void glue_objc_enumerationMutation(void); extern int glue___gnu_objc_personality(void); -extern id _Nullable glue_objc_retain(void); -extern id _Nullable glue_objc_retainBlock(void); -extern id _Nullable glue_objc_retainAutorelease(void); +extern id glue_objc_retain(void); +extern id glue_objc_retainBlock(void); +extern id glue_objc_retainAutorelease(void); extern void glue_objc_release(void); -extern id _Nullable glue_objc_autorelease(void); -extern id _Nullable glue_objc_autoreleaseReturnValue(void); -extern id _Nullable glue_objc_retainAutoreleaseReturnValue(void); -extern id _Nullable glue_objc_retainAutoreleasedReturnValue(void); -extern id _Nullable glue_objc_storeStrong(void); -extern id _Nullable glue_objc_storeWeak(void); -extern id _Nullable glue_objc_loadWeakRetained(void); -extern id _Nullable glue_objc_initWeak(void); +extern id glue_objc_autorelease(void); +extern id glue_objc_autoreleaseReturnValue(void); +extern id glue_objc_retainAutoreleaseReturnValue(void); +extern id glue_objc_retainAutoreleasedReturnValue(void); +extern id glue_objc_storeStrong(void); +extern id glue_objc_storeWeak(void); +extern id glue_objc_loadWeakRetained(void); +extern id glue_objc_initWeak(void); extern void glue_objc_destroyWeak(void); -extern id _Nullable glue_objc_loadWeak(void); +extern id glue_objc_loadWeak(void); extern void glue_objc_copyWeak(void); extern void glue_objc_moveWeak(void); -extern SEL _Nonnull glue_sel_registerName(void); -extern const char *_Nonnull glue_sel_getName(void); +extern SEL glue_sel_registerName(void); +extern const char *glue_sel_getName(void); extern bool glue_sel_isEqual(void); -extern Class _Nonnull glue_objc_allocateClassPair(void); +extern Class glue_objc_allocateClassPair(void); extern void glue_objc_registerClassPair(void); extern unsigned int glue_objc_getClassList(void); -extern Class _Nonnull *_Nonnull glue_objc_copyClassList(void); +extern Class *glue_objc_copyClassList(void); extern bool glue_class_isMetaClass(void); -extern const char *_Nullable glue_class_getName(void); -extern Class _Nullable glue_class_getSuperclass(void); +extern const char *glue_class_getName(void); +extern Class glue_class_getSuperclass(void); extern unsigned long glue_class_getInstanceSize(void); extern bool glue_class_respondsToSelector(void); extern bool glue_class_conformsToProtocol(void); -extern IMP _Nullable glue_class_getMethodImplementation(void); -extern IMP _Nullable glue_class_getMethodImplementation_stret(void); -extern const char *_Nullable glue_class_getMethodTypeEncoding(void); +extern IMP glue_class_getMethodImplementation(void); +extern IMP glue_class_getMethodImplementation_stret(void); +extern Method glue_class_getInstanceMethod(void); extern bool glue_class_addMethod(void); -extern IMP _Nullable glue_class_replaceMethod(void); -extern Class _Nullable glue_object_getClass(void); -extern Class _Nullable glue_object_setClass(void); -extern const char *_Nullable glue_object_getClassName(void); -extern const char *_Nonnull glue_protocol_getName(void); +extern IMP glue_class_replaceMethod(void); +extern Class glue_object_getClass(void); +extern Class glue_object_setClass(void); +extern const char *glue_object_getClassName(void); +extern const char *glue_protocol_getName(void); extern bool glue_protocol_isEqual(void); extern bool glue_protocol_conformsToProtocol(void); -extern _Nullable objc_uncaught_exception_handler_t +extern objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(void); extern void glue_objc_setForwardHandler(void); extern void glue_objc_setEnumerationMutationHandler(void); extern void glue_objc_zero_weak_references(void); extern void glue_objc_exit(void); +extern Ivar *glue_class_copyIvarList(void); +extern const char *glue_ivar_getName(void); +extern const char *glue_ivar_getTypeEncoding(void); +extern ptrdiff_t glue_ivar_getOffset(void); +extern Method *glue_class_copyMethodList(void); +extern SEL glue_method_getName(void); +extern const char *glue_method_getTypeEncoding(void); +extern objc_property_t *glue_class_copyPropertyList(void); +extern const char *glue_property_getName(void); +extern char *glue_property_copyAttributeValue(void); #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; @@ -619,11 +629,11 @@ (CONST_APTR)glue_class_getInstanceSize, (CONST_APTR)glue_class_respondsToSelector, (CONST_APTR)glue_class_conformsToProtocol, (CONST_APTR)glue_class_getMethodImplementation, (CONST_APTR)glue_class_getMethodImplementation_stret, - (CONST_APTR)glue_class_getMethodTypeEncoding, + (CONST_APTR)glue_class_getInstanceMethod, (CONST_APTR)glue_class_addMethod, (CONST_APTR)glue_class_replaceMethod, (CONST_APTR)glue_object_getClass, (CONST_APTR)glue_object_setClass, (CONST_APTR)glue_object_getClassName, @@ -633,10 +643,20 @@ (CONST_APTR)glue_objc_setUncaughtExceptionHandler, (CONST_APTR)glue_objc_setForwardHandler, (CONST_APTR)glue_objc_setEnumerationMutationHandler, (CONST_APTR)glue_objc_zero_weak_references, (CONST_APTR)glue_objc_exit, + (CONST_APTR)glue_class_copyIvarList, + (CONST_APTR)glue_ivar_getName, + (CONST_APTR)glue_ivar_getTypeEncoding, + (CONST_APTR)glue_ivar_getOffset, + (CONST_APTR)glue_class_copyMethodList, + (CONST_APTR)glue_method_getName, + (CONST_APTR)glue_method_getTypeEncoding, + (CONST_APTR)glue_class_copyPropertyList, + (CONST_APTR)glue_property_getName, + (CONST_APTR)glue_property_copyAttributeValue, (CONST_APTR)-1, #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_END #endif }; Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ src/runtime/amigaos3.sfd @@ -5,11 +5,11 @@ ==public * Functions that are only for the linklib. bool glue_objc_init(unsigned int version, struct objc_libc *libc, FILE *stdout, FILE *stderr)(d0,a0,a1,a2) * These have a built-in declaration in the compiler that does not use the * registers and thus always need glue. -void glue___objc_exec_class(void *_Nonnull module)(a0) +void glue___objc_exec_class(struct objc_module *_Nonnull module)(a0) IMP _Nonnull glue_objc_msg_lookup(id _Nullable object, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_stret(id _Nullable object, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_super(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_super_stret(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) Class _Nullable glue_objc_lookUpClass(const char *_Nonnull name)(a0) @@ -55,11 +55,11 @@ unsigned long glue_class_getInstanceSize(Class _Nullable class_)(a0) bool glue_class_respondsToSelector(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) bool glue_class_conformsToProtocol(Class _Nullable class_, Protocol *_Nonnull p)(a0,a1) IMP _Nullable glue_class_getMethodImplementation(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) IMP _Nullable glue_class_getMethodImplementation_stret(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) -const char *_Nullable glue_class_getMethodTypeEncoding(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) +Method _Nullable glue_class_getInstanceMethod(Class _Nullable class_, SEL _Nonnull selector)(a0,a1) bool glue_class_addMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3) IMP _Nullable glue_class_replaceMethod(Class _Nonnull class_, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding)(a0,a1,a2,a3) Class _Nullable glue_object_getClass(id _Nullable object)(a0) Class _Nullable glue_object_setClass(id _Nullable object, Class _Nonnull class_)(a0,a1) const char *_Nullable glue_object_getClassName(id _Nullable object)(a0) @@ -69,6 +69,16 @@ _Nullable objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t _Nullable handler)(a0) void glue_objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward)(a0,a1) void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t _Nullable handler)(a0) void glue_objc_zero_weak_references(id _Nonnull value)(a0) void glue_objc_exit(void)() +Ivar _Nullable *_Nullable glue_class_copyIvarList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) +const char *_Nonnull glue_ivar_getName(Ivar _Nonnull ivar)(a0) +const char *_Nonnull glue_ivar_getTypeEncoding(Ivar _Nonnull ivar)(a0) +ptrdiff_t glue_ivar_getOffset(Ivar _Nonnull ivar)(a0) +Method _Nullable *_Nullable glue_class_copyMethodList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) +SEL _Nonnull glue_method_getName(Method _Nonnull method)(a0) +const char *_Nullable glue_method_getTypeEncoding(Method _Nonnull method)(a0) +objc_property_t _Nullable *_Nullable glue_class_copyPropertyList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) +const char *_Nonnull glue_property_getName(objc_property_t _Nonnull property)(a0) +char *_Nullable glue_property_copyAttributeValue(objc_property_t _Nonnull property, const char *_Nonnull name)(a0,a1) ==end Index: src/runtime/category.m ================================================================== --- src/runtime/category.m +++ src/runtime/category.m @@ -25,47 +25,45 @@ #import "private.h" static struct objc_hashtable *categoriesMap = NULL; static void -registerSelectors(struct objc_abi_category *category) -{ - for (struct objc_abi_method_list *methodList = - category->instanceMethods; methodList != NULL; - methodList = methodList->next) - for (unsigned int i = 0; i < methodList->count; i++) - objc_register_selector((struct objc_abi_selector *) - &methodList->methods[i]); - - for (struct objc_abi_method_list *methodList = category->classMethods; - methodList != NULL; methodList = methodList->next) - for (unsigned int i = 0; i < methodList->count; i++) - objc_register_selector((struct objc_abi_selector *) - &methodList->methods[i]); +registerSelectors(struct objc_category *category) +{ + struct objc_method_list *iter; + unsigned int i; + + for (iter = category->instanceMethods; iter != NULL; iter = iter->next) + for (i = 0; i < iter->count; i++) + objc_register_selector(&iter->methods[i].selector); + + for (iter = category->classMethods; iter != NULL; iter = iter->next) + for (i = 0; i < iter->count; i++) + objc_register_selector(&iter->methods[i].selector); } static void -registerCategory(struct objc_abi_category *category) +registerCategory(struct objc_category *category) { - struct objc_abi_category **categories; + struct objc_category **categories; Class class = objc_classname_to_class(category->className, false); if (categoriesMap == NULL) categoriesMap = objc_hashtable_new( objc_hash_string, objc_equal_string, 2); - categories = (struct objc_abi_category **)objc_hashtable_get( + categories = (struct objc_category **)objc_hashtable_get( categoriesMap, category->className); if (categories != NULL) { - struct objc_abi_category **newCategories; + struct objc_category **newCategories; size_t i; for (i = 0; categories[i] != NULL; i++); if ((newCategories = realloc(categories, - (i + 2) * sizeof(struct objc_abi_category *))) == NULL) + (i + 2) * sizeof(*categories))) == NULL) OBJC_ERROR("Not enough memory for category %s of " "class %s!", category->categoryName, category->className); newCategories[i] = category; @@ -79,12 +77,11 @@ } return; } - if ((categories = malloc( - 2 * sizeof(struct objc_abi_category *))) == NULL) + if ((categories = malloc(2 * sizeof(*categories))) == NULL) OBJC_ERROR("Not enough memory for category %s of class %s!\n", category->categoryName, category->className); categories[0] = category; categories[1] = NULL; @@ -95,14 +92,14 @@ objc_update_dtable(class->isa); } } void -objc_register_all_categories(struct objc_abi_symtab *symtab) +objc_register_all_categories(struct objc_symtab *symtab) { - struct objc_abi_category **categories = - (struct objc_abi_category **)symtab->defs + symtab->classDefsCount; + struct objc_category **categories = + (struct objc_category **)symtab->defs + symtab->classDefsCount; for (size_t i = 0; i < symtab->categoryDefsCount; i++) { registerSelectors(categories[i]); registerCategory(categories[i]); } Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -32,25 +32,25 @@ static struct objc_dtable *emptyDTable = NULL; static unsigned lookupsUntilFastPath = 128; static struct objc_sparsearray *fastPath = NULL; static void -registerClass(struct objc_abi_class *rawClass) +registerClass(Class class) { if (classes == NULL) classes = objc_hashtable_new( objc_hash_string, objc_equal_string, 2); - objc_hashtable_set(classes, rawClass->name, rawClass); + objc_hashtable_set(classes, class->name, class); if (emptyDTable == NULL) emptyDTable = objc_dtable_new(); - rawClass->DTable = emptyDTable; - rawClass->metaclass->DTable = emptyDTable; + class->DTable = emptyDTable; + class->isa->DTable = emptyDTable; - if (strcmp(rawClass->name, "Protocol") != 0) + if (strcmp(class->name, "Protocol") != 0) classesCount++; } bool class_registerAlias_np(Class class, const char *name) @@ -69,19 +69,18 @@ return YES; } static void -registerSelectors(struct objc_abi_class *rawClass) -{ - struct objc_abi_method_list *methodList; - - for (methodList = rawClass->methodList; methodList != NULL; - methodList = methodList->next) - for (unsigned int i = 0; i < methodList->count; i++) - objc_register_selector((struct objc_abi_selector *) - &methodList->methods[i]); +registerSelectors(Class class) +{ + struct objc_method_list *iter; + unsigned int i; + + for (iter = class->methodList; iter != NULL; iter = iter->next) + for (i = 0; i < iter->count; i++) + objc_register_selector(&iter->methods[i].selector); } Class objc_classname_to_class(const char *name, bool cache) { @@ -255,13 +254,12 @@ class->superclass->subclassList[i] = class; class->superclass->subclassList[i + 1] = Nil; } - static void -updateIVarOffsets(Class class) +updateIvarOffsets(Class class) { if (!(class->info & OBJC_CLASS_INFO_NEW_ABI)) return; if (class->instanceSize > 0) @@ -270,21 +268,21 @@ class->instanceSize = -class->instanceSize; if (class->superclass != Nil) { class->instanceSize += class->superclass->instanceSize; - if (class->iVars != NULL) { - for (unsigned int i = 0; i < class->iVars->count; i++) { - class->iVars->iVars[i].offset += + if (class->ivars != NULL) { + for (unsigned int i = 0; i < class->ivars->count; i++) { + class->ivars->ivars[i].offset += class->superclass->instanceSize; - *class->iVarOffsets[i] = - class->iVars->iVars[i].offset; + *class->ivarOffsets[i] = + class->ivars->ivars[i].offset; } } } else - for (unsigned int i = 0; i < class->iVars->count; i++) - *class->iVarOffsets[i] = class->iVars->iVars[i].offset; + for (unsigned int i = 0; i < class->ivars->count; i++) + *class->ivarOffsets[i] = class->ivars->ivars[i].offset; } static void setupClass(Class class) { @@ -291,31 +289,43 @@ const char *superclassName; if (class->info & OBJC_CLASS_INFO_SETUP) return; - superclassName = ((struct objc_abi_class *)class)->superclass; + superclassName = (const char *)class->superclass; if (superclassName != NULL) { Class super = objc_classname_to_class(superclassName, false); + Class rootClass; if (super == Nil) return; setupClass(super); if (!(super->info & OBJC_CLASS_INFO_SETUP)) return; + /* + * GCC sets class->isa->isa to the name of the root class, + * while Clang just sets it to Nil. Therefore always calculate + * it. + */ + for (Class iter = super; iter != NULL; iter = iter->superclass) + rootClass = iter; + class->superclass = super; + class->isa->isa = rootClass->isa; class->isa->superclass = super->isa; addSubclass(class); addSubclass(class->isa); - } else + } else { + class->isa->isa = class->isa; class->isa->superclass = class; + } - updateIVarOffsets(class); + updateIvarOffsets(class); class->info |= OBJC_CLASS_INFO_SETUP; class->isa->info |= OBJC_CLASS_INFO_SETUP; } @@ -416,19 +426,18 @@ } } } void -objc_register_all_classes(struct objc_abi_symtab *symtab) +objc_register_all_classes(struct objc_symtab *symtab) { for (uint16_t i = 0; i < symtab->classDefsCount; i++) { - struct objc_abi_class *rawClass = - (struct objc_abi_class *)symtab->defs[i]; + Class class = (Class)symtab->defs[i]; - registerClass(rawClass); - registerSelectors(rawClass); - registerSelectors(rawClass->metaclass); + registerClass(class); + registerSelectors(class); + registerSelectors(class->isa); } for (uint16_t i = 0; i < symtab->classDefsCount; i++) { Class class = (Class)symtab->defs[i]; @@ -491,11 +500,11 @@ void objc_registerClassPair(Class class) { objc_global_mutex_lock(); - registerClass((struct objc_abi_class *)class); + registerClass(class); if (class->superclass != Nil) { addSubclass(class); addSubclass(class->isa); } @@ -759,30 +768,32 @@ class->methodList = methodList; objc_update_dtable(class); } -const char * -class_getMethodTypeEncoding(Class class, SEL selector) +Method +class_getInstanceMethod(Class class, SEL selector) { - struct objc_method *method; + Method method; + Class superclass; if (class == Nil) return NULL; objc_global_mutex_lock(); if ((method = getMethod(class, selector)) != NULL) { - const char *ret = method->selector.typeEncoding; objc_global_mutex_unlock(); - return ret; + return method; } + + superclass = class->superclass; objc_global_mutex_unlock(); - if (class->superclass != Nil) - return class_getMethodTypeEncoding(class->superclass, selector); + if (superclass != Nil) + return class_getInstanceMethod(superclass, selector); return NULL; } bool @@ -864,12 +875,10 @@ } static void unregisterClass(Class class) { - struct objc_abi_class *rawClass = (struct objc_abi_class *)class; - if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil && class->superclass->subclassList != NULL) { size_t i = SIZE_MAX, count = 0; Class *tmp; @@ -901,11 +910,11 @@ objc_dtable_free(class->DTable); class->DTable = NULL; if ((class->info & OBJC_CLASS_INFO_SETUP) && class->superclass != Nil) - rawClass->superclass = class->superclass->name; + class->superclass = (Class)class->superclass->name; class->info &= ~OBJC_CLASS_INFO_SETUP; } void Index: src/runtime/init.m ================================================================== --- src/runtime/init.m +++ src/runtime/init.m @@ -19,14 +19,12 @@ #import "ObjFWRT.h" #import "private.h" void -__objc_exec_class(void *module_) +__objc_exec_class(struct objc_module *module) { - struct objc_abi_module *module = module_; - objc_global_mutex_lock(); objc_register_all_selectors(module->symtab); objc_register_all_classes(module->symtab); objc_register_all_categories(module->symtab); ADDED src/runtime/ivar.m Index: src/runtime/ivar.m ================================================================== --- src/runtime/ivar.m +++ src/runtime/ivar.m @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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 "ObjFWRT.h" +#import "private.h" + +Ivar * +class_copyIvarList(Class class, unsigned int *outCount) +{ + unsigned int count; + Ivar *ivars; + + if (class == Nil) { + if (outCount != NULL) + *outCount = 0; + + return NULL; + } + + objc_global_mutex_lock(); + + count = (class->ivars != NULL ? class->ivars->count : 0); + + if (count == 0) { + if (outCount != NULL) + *outCount = 0; + + objc_global_mutex_unlock(); + return NULL; + } + + if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL) + OBJC_ERROR("Not enough memory to copy ivars"); + + for (unsigned int i = 0; i < count; i++) + ivars[i] = &class->ivars->ivars[i]; + ivars[count] = NULL; + + if (outCount != NULL) + *outCount = count; + + objc_global_mutex_unlock(); + + return ivars; +} + +const char * +ivar_getName(Ivar ivar) +{ + return ivar->name; +} + +const char * +ivar_getTypeEncoding(Ivar ivar) +{ + return ivar->typeEncoding; +} + +ptrdiff_t +ivar_getOffset(Ivar ivar) +{ + return ivar->offset; +} Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -138,11 +138,11 @@ dtor(); } #endif void -__objc_exec_class(void *module) +__objc_exec_class(struct objc_module *module) { /* * The compiler generates constructors that call into this, so it is * possible that we are not set up yet when we get called. */ @@ -502,14 +502,14 @@ class_getMethodImplementation_stret(Class class, SEL selector) { return glue_class_getMethodImplementation_stret(class, selector); } -const char * -class_getMethodTypeEncoding(Class class, SEL selector) +Method +class_getInstanceMethod(Class class, SEL selector) { - return glue_class_getMethodTypeEncoding(class, selector); + return glue_class_getInstanceMethod(class, selector); } bool class_addMethod(Class class, SEL selector, IMP implementation, const char *typeEncoding) @@ -589,5 +589,65 @@ void objc_exit(void) { glue_objc_exit(); } + +Ivar * +class_copyIvarList(Class class, unsigned int *outCount) +{ + return glue_class_copyIvarList(class, outCount); +} + +const char * +ivar_getName(Ivar ivar) +{ + return glue_ivar_getName(ivar); +} + +const char * +ivar_getTypeEncoding(Ivar ivar) +{ + return glue_ivar_getTypeEncoding(ivar); +} + +ptrdiff_t +ivar_getOffset(Ivar ivar) +{ + return glue_ivar_getOffset(ivar); +} + +Method * +class_copyMethodList(Class class, unsigned int *outCount) +{ + return glue_class_copyMethodList(class, outCount); +} + +SEL +method_getName(Method method) +{ + return glue_method_getName(method); +} + +const char * +method_getTypeEncoding(Method method) +{ + return glue_method_getTypeEncoding(method); +} + +objc_property_t * +class_copyPropertyList(Class class, unsigned int *outCount) +{ + return glue_class_copyPropertyList(class, outCount); +} + +const char * +property_getName(objc_property_t property) +{ + return glue_property_getName(property); +} + +char * +property_copyAttributeValue(objc_property_t property, const char *name) +{ + return glue_property_copyAttributeValue(property, name); +} ADDED src/runtime/method.m Index: src/runtime/method.m ================================================================== --- src/runtime/method.m +++ src/runtime/method.m @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * 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 "ObjFWRT.h" +#import "private.h" + +Method * +class_copyMethodList(Class class, unsigned int *outCount) +{ + unsigned int i, count; + struct objc_method_list *iter; + Method *methods; + + if (class == Nil) { + if (outCount != NULL) + *outCount = 0; + + return NULL; + } + + objc_global_mutex_lock(); + + count = 0; + for (iter = class->methodList; iter != NULL; iter = iter->next) + count += iter->count; + + if (count == 0) { + if (outCount != NULL) + *outCount = 0; + + objc_global_mutex_unlock(); + return NULL; + } + + if ((methods = malloc((count + 1) * sizeof(Method))) == NULL) + OBJC_ERROR("Not enough memory to copy methods"); + + i = 0; + for (iter = class->methodList; iter != NULL; iter = iter->next) + for (unsigned int j = 0; j < iter->count; j++) + methods[i++] = &iter->methods[j]; + OF_ENSURE(i == count); + methods[count] = NULL; + + if (outCount != NULL) + *outCount = count; + + objc_global_mutex_unlock(); + + return methods; +} + +SEL +method_getName(Method method) +{ + return (SEL)&method->selector; +} + +const char * +method_getTypeEncoding(Method method) +{ + return method->selector.typeEncoding; +} Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ src/runtime/morphos-clib.h @@ -1,9 +1,9 @@ /* Functions that are only for the linklib. */ bool glue_objc_init(unsigned int, struct objc_libc *, FILE *, FILE *); /* All other functions. */ -void glue___objc_exec_class(void *); +void glue___objc_exec_class(struct objc_module *); IMP glue_objc_msg_lookup(id, SEL); IMP glue_objc_msg_lookup_stret(id, SEL); IMP glue_objc_msg_lookup_super(struct objc_super *, SEL); IMP glue_objc_msg_lookup_super_stret(struct objc_super *, SEL); Class glue_objc_lookUpClass(const char *); @@ -49,11 +49,11 @@ unsigned long glue_class_getInstanceSize(Class); bool glue_class_respondsToSelector(Class, SEL); bool glue_class_conformsToProtocol(Class, Protocol *); IMP glue_class_getMethodImplementation(Class, SEL); IMP glue_class_getMethodImplementation_stret(Class, SEL); -const char *glue_class_getMethodTypeEncoding(Class, SEL); +Method glue_class_getInstanceMethod(Class, SEL); bool glue_class_addMethod(Class class_, SEL selector, IMP, const char *); IMP glue_class_replaceMethod(Class, SEL, IMP, const char *); Class glue_object_getClass(id); Class glue_object_setClass(id, Class); const char *glue_object_getClassName(id); @@ -63,5 +63,15 @@ objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t); void glue_objc_setForwardHandler(IMP, IMP); void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t); void glue_objc_zero_weak_references(id); void glue_objc_exit(void); +Ivar *glue_class_copyIvarList(Class class_, unsigned int *outCount); +const char *glue_ivar_getName(Ivar ivar); +const char *glue_ivar_getTypeEncoding(Ivar ivar); +ptrdiff_t glue_ivar_getOffset(Ivar ivar); +Method *glue_class_copyMethodList(Class class_, unsigned int *outCount); +SEL glue_method_getName(Method method); +const char *glue_method_getTypeEncoding(Method method); +objc_property_t *glue_class_copyPropertyList(Class class_, unsigned int *outCount); +const char *glue_property_getName(objc_property_t property); +char *glue_property_copyAttributeValue(objc_property_t property, const char *name); Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ src/runtime/morphos.fd @@ -51,11 +51,11 @@ glue_class_getInstanceSize(class_)(sysv,r12base) glue_class_respondsToSelector(class_,selector)(sysv,r12base) glue_class_conformsToProtocol(class_,p)(sysv,r12base) glue_class_getMethodImplementation(class_,selector)(sysv,r12base) glue_class_getMethodImplementation_stret(class_,selector)(sysv,r12base) -glue_class_getMethodTypeEncoding(class_,selector)(sysv,r12base) +glue_class_getInstanceMethod(class_,selector)(sysv,r12base) glue_class_addMethod(class_,selector,implementation,typeEncoding)(sysv,r12base) glue_class_replaceMethod(class_,selector,implementation,typeEncoding)(sysv,r12base) glue_object_getClass(object)(sysv,r12base) glue_object_setClass(object,class_)(sysv,r12base) glue_object_getClassName(object)(sysv,r12base) @@ -65,6 +65,16 @@ glue_objc_setUncaughtExceptionHandler(handler)(sysv,r12base) glue_objc_setForwardHandler(forward,stretForward)(sysv,r12base) glue_objc_setEnumerationMutationHandler(handler)(sysv,r12base) glue_objc_zero_weak_references(value)(sysv,r12base) glue_objc_exit()(sysv,r12base) +glue_class_copyIvarList(class_,outCount)(sysv,r12base) +glue_ivar_getName(ivar)(sysv,r12base) +glue_ivar_getTypeEncoding(ivar)(sysv,r12base) +glue_ivar_getOffset(ivar)(sysv,r12base) +glue_class_copyMethodList(class_,outCount)(sysv,r12base) +glue_method_getName(method)(sysv,r12base) +glue_method_getTypeEncoding(method)(sysv,r12base) +glue_class_copyPropertyList(class_,outCount)(sysv,r12base) +glue_property_getName(property)(sysv,r12base) +glue_property_copyAttributeValue(property,name)(sysv,r12base) ##end Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -27,71 +27,162 @@ # ifndef _Nullable # define _Nullable # endif #endif -struct objc_abi_class { - struct objc_abi_class *_Nonnull metaclass; - const char *_Nullable superclass; +struct objc_class { + Class _Nonnull isa; + Class _Nullable superclass; const char *_Nonnull name; unsigned long version; unsigned long info; long instanceSize; - void *_Nullable iVars; - struct objc_abi_method_list *_Nullable methodList; - void *_Nullable DTable; - void *_Nullable subclassList; + struct objc_ivar_list *_Nullable ivars; + struct objc_method_list *_Nullable methodList; + struct objc_dtable *_Nonnull DTable; + Class _Nullable *_Nullable subclassList; void *_Nullable siblingClass; - void *_Nullable protocols; + struct objc_protocol_list *_Nullable protocols; void *_Nullable GCObjectType; - long ABIVersion; - int32_t *_Nonnull *_Nullable iVarOffsets; - void *_Nullable properties; + unsigned long ABIVersion; + int32_t *_Nonnull *_Nullable ivarOffsets; + struct objc_property_list *_Nullable propertyList; +}; + +enum objc_class_info { + OBJC_CLASS_INFO_CLASS = 0x001, + OBJC_CLASS_INFO_METACLASS = 0x002, + OBJC_CLASS_INFO_NEW_ABI = 0x010, + OBJC_CLASS_INFO_SETUP = 0x100, + OBJC_CLASS_INFO_LOADED = 0x200, + OBJC_CLASS_INFO_DTABLE = 0x400, + OBJC_CLASS_INFO_INITIALIZED = 0x800 +}; + +struct objc_object { + Class _Nonnull isa; }; -struct objc_abi_selector { - const char *_Nonnull name; +struct objc_selector { + uintptr_t UID; const char *_Nullable typeEncoding; }; -struct objc_abi_method { - struct objc_abi_selector selector; +struct objc_method { + struct objc_selector selector; IMP _Nonnull implementation; }; -struct objc_abi_method_list { - struct objc_abi_method_list *_Nullable next; +struct objc_method_list { + struct objc_method_list *_Nullable next; unsigned int count; - struct objc_abi_method methods[1]; + struct objc_method methods[1]; }; -struct objc_abi_category { +struct objc_category { const char *_Nonnull categoryName; const char *_Nonnull className; - struct objc_abi_method_list *_Nullable instanceMethods; - struct objc_abi_method_list *_Nullable classMethods; + struct objc_method_list *_Nullable instanceMethods; + struct objc_method_list *_Nullable classMethods; struct objc_protocol_list *_Nullable protocols; }; -struct objc_abi_static_instances { +struct objc_ivar { + const char *_Nonnull name; + const char *_Nonnull typeEncoding; + unsigned int offset; +}; + +struct objc_ivar_list { + unsigned int count; + struct objc_ivar ivars[1]; +}; + +struct objc_method_description { + const char *_Nonnull name; + const char *_Nonnull typeEncoding; +}; + +struct objc_method_description_list { + int count; + struct objc_method_description list[1]; +}; + +struct objc_protocol_list { + struct objc_protocol_list *_Nullable next; + long count; + Protocol *__unsafe_unretained _Nonnull list[1]; +}; + +#if __has_attribute(__objc_root_class__) +__attribute__((__objc_root_class__)) +#endif +@interface Protocol +{ +@public + Class _Nonnull isa; + const char *_Nonnull name; + struct objc_protocol_list *_Nullable protocolList; + struct objc_method_description_list *_Nullable instanceMethods; + struct objc_method_description_list *_Nullable classMethods; +} +@end + +enum objc_property_attributes { + OBJC_PROPERTY_READONLY = 0x01, + OBJC_PROPERTY_GETTER = 0x02, + OBJC_PROPERTY_ASSIGN = 0x04, + OBJC_PROPERTY_READWRITE = 0x08, + OBJC_PROPERTY_RETAIN = 0x10, + OBJC_PROPERTY_COPY = 0x20, + OBJC_PROPERTY_NONATOMIC = 0x40, + OBJC_PROPERTY_SETTER = 0x80 +}; + +enum objc_property_extended_attributes { + OBJC_PROPERTY_SYNTHESIZED = 0x1, + OBJC_PROPERTY_DYNAMIC = 0x2, + OBJC_PROPERTY_PROTOCOL = 0x3, + OBJC_PROPERTY_ATOMIC = 0x4, + OBJC_PROPERTY_WEAK = 0x8, + OBJC_PROPERTY_STRONG = 0x10, + OBJC_PROPERTY_UNSAFE_UNRETAINED = 0x20 +}; + +struct objc_property { + const char *_Nonnull name; + unsigned char attributes, extendedAttributes; + struct { + const char *_Nullable name; + const char *_Nullable typeEncoding; + } getter, setter; +}; + +struct objc_property_list { + unsigned int count; + struct objc_property_list *_Nullable next; + struct objc_property properties[1]; +}; + +struct objc_static_instances { const char *_Nonnull className; id _Nullable instances[1]; }; -struct objc_abi_symtab { +struct objc_symtab { unsigned long unknown; - struct objc_abi_selector *_Nullable selectorRefs; + struct objc_selector *_Nullable selectorRefs; uint16_t classDefsCount; uint16_t categoryDefsCount; void *_Nonnull defs[1]; }; -struct objc_abi_module { +struct objc_module { unsigned long version; /* 9 = non-fragile */ unsigned long size; const char *_Nullable name; - struct objc_abi_symtab *_Nonnull symtab; + struct objc_symtab *_Nonnull symtab; }; struct objc_hashtable_bucket { const void *_Nonnull key, *_Nonnull object; uint32_t hash; @@ -172,17 +263,17 @@ # undef stdout # undef stderr extern FILE *stdout, *stderr; #endif -extern void objc_register_all_categories(struct objc_abi_symtab *_Nonnull); +extern void objc_register_all_categories(struct objc_symtab *_Nonnull); extern struct objc_category *_Nullable *_Nullable objc_categories_for_class(Class _Nonnull); extern void objc_unregister_all_categories(void); extern void objc_initialize_class(Class _Nonnull); extern void objc_update_dtable(Class _Nonnull); -extern void objc_register_all_classes(struct objc_abi_symtab *_Nonnull); +extern void objc_register_all_classes(struct objc_symtab *_Nonnull); extern Class _Nullable objc_classname_to_class(const char *_Nonnull, bool); extern void objc_unregister_class(Class _Nonnull); extern void objc_unregister_all_classes(void); extern uint32_t objc_hash_string(const void *_Nonnull); extern bool objc_equal_string(const void *_Nonnull, const void *_Nonnull); @@ -195,12 +286,12 @@ extern void *_Nullable objc_hashtable_get(struct objc_hashtable *_Nonnull, const void *_Nonnull); extern void objc_hashtable_delete(struct objc_hashtable *_Nonnull, const void *_Nonnull); extern void objc_hashtable_free(struct objc_hashtable *_Nonnull); -extern void objc_register_selector(struct objc_abi_selector *_Nonnull); -extern void objc_register_all_selectors(struct objc_abi_symtab *_Nonnull); +extern void objc_register_selector(struct objc_selector *_Nonnull); +extern void objc_register_all_selectors(struct objc_symtab *_Nonnull); extern void objc_unregister_all_selectors(void); extern struct objc_sparsearray *_Nonnull objc_sparsearray_new(uint8_t); extern void *_Nullable objc_sparsearray_get(struct objc_sparsearray *_Nonnull, uintptr_t); extern void objc_sparsearray_set(struct objc_sparsearray *_Nonnull, uintptr_t, @@ -211,11 +302,11 @@ struct objc_dtable *_Nonnull); extern void objc_dtable_set(struct objc_dtable *_Nonnull, uint32_t, IMP _Nullable); extern void objc_dtable_free(struct objc_dtable *_Nonnull); extern void objc_dtable_cleanup(void); -extern void objc_init_static_instances(struct objc_abi_symtab *_Nonnull); +extern void objc_init_static_instances(struct objc_symtab *_Nonnull); extern void objc_forget_pending_static_instances(void); #ifdef OF_HAVE_THREADS extern void objc_global_mutex_lock(void); extern void objc_global_mutex_unlock(void); extern void objc_global_mutex_free(void); Index: src/runtime/property.m ================================================================== --- src/runtime/property.m +++ src/runtime/property.m @@ -154,5 +154,110 @@ return; } memcpy(dest, src, size); } + +objc_property_t * +class_copyPropertyList(Class class, unsigned int *outCount) +{ + unsigned int i, count; + struct objc_property_list *iter; + objc_property_t *properties; + + if (class == Nil) { + if (outCount != NULL) + *outCount = 0; + + return NULL; + } + + objc_global_mutex_lock(); + + count = 0; + if (class->info & OBJC_CLASS_INFO_NEW_ABI) + for (iter = class->propertyList; iter != NULL; + iter = iter->next) + count += iter->count; + + if (count == 0) { + if (outCount != NULL) + *outCount = 0; + + objc_global_mutex_unlock(); + return NULL; + } + + properties = malloc((count + 1) * sizeof(objc_property_t)); + if (properties == NULL) + OBJC_ERROR("Not enough memory to copy properties"); + + i = 0; + for (iter = class->propertyList; iter != NULL; iter = iter->next) + for (unsigned int j = 0; j < iter->count; j++) + properties[i++] = &iter->properties[j]; + OF_ENSURE(i == count); + properties[count] = NULL; + + if (outCount != NULL) + *outCount = count; + + objc_global_mutex_unlock(); + + return properties; +} + +const char * +property_getName(objc_property_t property) +{ + return property->name; +} + +char * +property_copyAttributeValue(objc_property_t property, const char *name) +{ + char *ret = NULL; + bool nullIsError = false; + + if (strlen(name) != 1) + return NULL; + + switch (*name) { + case 'T': + ret = of_strdup(property->getter.typeEncoding); + nullIsError = true; + break; + case 'G': + if (property->attributes & OBJC_PROPERTY_GETTER) { + ret = of_strdup(property->getter.name); + nullIsError = true; + } + break; + case 'S': + if (property->attributes & OBJC_PROPERTY_SETTER) { + ret = of_strdup(property->setter.name); + nullIsError = true; + } + break; +#define BOOL_CASE(name, field, flag) \ + case name: \ + if (property->field & flag) { \ + ret = calloc(1, 1); \ + nullIsError = true; \ + } \ + break; + + BOOL_CASE('R', attributes, OBJC_PROPERTY_READONLY) + BOOL_CASE('C', attributes, OBJC_PROPERTY_COPY) + BOOL_CASE('&', attributes, OBJC_PROPERTY_RETAIN) + BOOL_CASE('N', attributes, OBJC_PROPERTY_NONATOMIC) + BOOL_CASE('D', extendedAttributes, OBJC_PROPERTY_DYNAMIC) + BOOL_CASE('W', extendedAttributes, OBJC_PROPERTY_WEAK) +#undef BOOL_CASE + } + + if (nullIsError && ret == NULL) + OBJC_ERROR("Not enough memory to copy property attribute " + "value"); + + return ret; +} Index: src/runtime/selector.m ================================================================== --- src/runtime/selector.m +++ src/runtime/selector.m @@ -39,32 +39,31 @@ static struct objc_sparsearray *selectorNames = NULL; static void **freeList = NULL; static size_t freeListCount = 0; void -objc_register_selector(struct objc_abi_selector *rawSelector) +objc_register_selector(struct objc_selector *selector) { - struct objc_selector *selector; + SEL existingSelector; const char *name; if (selectorsCount > SEL_MAX) OBJC_ERROR("Out of selector slots!"); if (selectors == NULL) selectors = objc_hashtable_new( objc_hash_string, objc_equal_string, 2); - else if ((selector = objc_hashtable_get(selectors, - rawSelector->name)) != NULL) { - ((struct objc_selector *)rawSelector)->UID = selector->UID; + else if ((existingSelector = objc_hashtable_get(selectors, + (const char *)selector->UID)) != NULL) { + selector->UID = existingSelector->UID; return; } if (selectorNames == NULL) selectorNames = objc_sparsearray_new(SEL_SIZE); - name = rawSelector->name; - selector = (struct objc_selector *)rawSelector; + name = (const char *)selector->UID; selector->UID = selectorsCount++; objc_hashtable_set(selectors, name, selector); objc_sparsearray_set(selectorNames, (uint32_t)selector->UID, (void *)name); @@ -71,52 +70,51 @@ } SEL sel_registerName(const char *name) { - struct objc_abi_selector *rawSelector; + struct objc_selector *selector; objc_global_mutex_lock(); if (selectors != NULL && - (rawSelector= objc_hashtable_get(selectors, name)) != NULL) { + (selector = objc_hashtable_get(selectors, name)) != NULL) { objc_global_mutex_unlock(); - return (SEL)rawSelector; + return (SEL)selector; } - if ((rawSelector = malloc(sizeof(*rawSelector))) == NULL) + if ((selector = malloc(sizeof(*selector))) == NULL) OBJC_ERROR("Not enough memory to allocate selector!"); - if ((rawSelector->name = of_strdup(name)) == NULL) + if ((selector->UID = (uintptr_t)of_strdup(name)) == 0) OBJC_ERROR("Not enough memory to allocate selector!"); - rawSelector->typeEncoding = NULL; + selector->typeEncoding = NULL; if ((freeList = realloc(freeList, sizeof(void *) * (freeListCount + 2))) == NULL) OBJC_ERROR("Not enough memory to allocate selector!"); - freeList[freeListCount++] = rawSelector; - freeList[freeListCount++] = (char *)rawSelector->name; + freeList[freeListCount++] = selector; + freeList[freeListCount++] = (char *)selector->UID; - objc_register_selector(rawSelector); + objc_register_selector(selector); objc_global_mutex_unlock(); - return (SEL)rawSelector; + return (SEL)selector; } void -objc_register_all_selectors(struct objc_abi_symtab *symtab) +objc_register_all_selectors(struct objc_symtab *symtab) { - struct objc_abi_selector *rawSelector; + struct objc_selector *selector; if (symtab->selectorRefs == NULL) return; - for (rawSelector = symtab->selectorRefs; rawSelector->name != NULL; - rawSelector++) - objc_register_selector(rawSelector); + for (selector = symtab->selectorRefs; selector->UID != 0; selector++) + objc_register_selector(selector); } const char * sel_getName(SEL selector) { Index: src/runtime/static-instances.m ================================================================== --- src/runtime/static-instances.m +++ src/runtime/static-instances.m @@ -21,17 +21,17 @@ #include #import "ObjFWRT.h" #import "private.h" -static struct objc_abi_static_instances **staticInstancesList = NULL; +static struct objc_static_instances **staticInstancesList = NULL; static size_t staticInstancesCount = 0; void -objc_init_static_instances(struct objc_abi_symtab *symtab) +objc_init_static_instances(struct objc_symtab *symtab) { - struct objc_abi_static_instances **staticInstances; + struct objc_static_instances **staticInstances; /* Check if the class for a static instance became available */ for (size_t i = 0; i < staticInstancesCount; i++) { Class class = objc_lookUpClass( staticInstancesList[i]->className); @@ -51,11 +51,11 @@ staticInstancesList[i] = staticInstancesList[staticInstancesCount]; staticInstancesList = realloc(staticInstancesList, - sizeof(struct objc_abi_static_instances *) * + sizeof(*staticInstancesList) * staticInstancesCount); if (staticInstancesList == NULL) OBJC_ERROR("Not enough memory for list of " "static instances!"); @@ -66,11 +66,11 @@ */ i--; } } - staticInstances = (struct objc_abi_static_instances **) + staticInstances = (struct objc_static_instances **) symtab->defs[symtab->classDefsCount + symtab->categoryDefsCount]; if (staticInstances == NULL) return; @@ -81,11 +81,11 @@ for (id *instances = (*staticInstances)->instances; *instances != nil; instances++) object_setClass(*instances, class); } else { staticInstancesList = realloc(staticInstancesList, - sizeof(struct objc_abi_static_instances *) * + sizeof(*staticInstancesList) * (staticInstancesCount + 1)); if (staticInstancesList == NULL) OBJC_ERROR("Not enough memory for list of " "static instances!"); Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -468,12 +468,12 @@ 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; + addrIn6->sin6_addr.s6_addr[--i] = number >> 8; } } else { OFArray OF_GENERIC(OFString *) *components = [IPv6 componentsSeparatedByString: @":"]; size_t i; Index: tests/OFBlockTests.m ================================================================== --- tests/OFBlockTests.m +++ tests/OFBlockTests.m @@ -19,22 +19,28 @@ #import "TestsAppDelegate.h" static OFString *module = @"OFBlock"; -extern struct objc_abi_class _NSConcreteStackBlock; -extern struct objc_abi_class _NSConcreteGlobalBlock; -extern struct objc_abi_class _NSConcreteMallocBlock; +#if defined(OF_OBJFW_RUNTIME) +extern struct objc_class _NSConcreteStackBlock; +extern struct objc_class _NSConcreteGlobalBlock; +extern struct objc_class _NSConcreteMallocBlock; +#elif defined(OF_APPLE_RUNTIME) +extern void *_NSConcreteStackBlock; +extern void *_NSConcreteGlobalBlock; +extern void *_NSConcreteMallocBlock; +#endif static void (^g)(void) = ^ {}; static int (^returnStackBlock(void))(void) { __block int i = 42; - return Block_copy(^ int { return ++i; }); + return [Block_copy(^ int { return ++i; }) autorelease]; } static double forwardTest(void) { Index: tests/OFInvocationTests.m ================================================================== --- tests/OFInvocationTests.m +++ tests/OFInvocationTests.m @@ -40,10 +40,11 @@ : (struct test_struct)st { return st; } +#ifdef OF_INVOCATION_CAN_INVOKE - (void)invocationTestMethod2: (id)obj { assert(obj == self); } @@ -129,11 +130,11 @@ { return (d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 + d10 + d11 + d12 + d13 + d14 + d15 + d16) / 16; } -#if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__) +# if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__) - (complex double)invocationTestMethod7: (complex float)c1 : (complex double)c2 : (complex float)c3 : (complex double)c4 : (complex float)c5 @@ -205,13 +206,13 @@ OF_ENSURE(creal(c16) == 16.0 && cimag(c16) == 8.0); return (c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11 + c12 + c13 + c14 + c15 + c16) / 16; } -#endif +# endif -#ifdef __SIZEOF_INT128__ +# ifdef __SIZEOF_INT128__ __extension__ - (__int128)invocationTestMethod9: (int)i1 : (__int128)i2 : (__int128)i3 : (__int128)i4 @@ -249,10 +250,11 @@ return ((i1 + (int)i2 + (int)i3 + (int)i4 + i5 + (int)i6 + (int)i7 + (int)i8 + (int)i9 + (int)i10 + (int)i11 + (int)i12 + (int)i13 + (int)i14 + (int)i15 + (int)i16) / 16) + mask; } +# endif #endif - (void)invocationTests { void *pool = objc_autoreleasePoolPush(); Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -21,45 +21,37 @@ #import "OFArray.h" #import "OFDNSResolver.h" #import "OFSandbox.h" #import "OFStdIOStream.h" -@interface OFDNS: OFObject +@interface OFDNS: OFObject @end OF_APPLICATION_DELEGATE(OFDNS) @implementation OFDNS -- (void)resolver: (OFDNSResolver *)resolver - didResolveDomainName: (OFString *)domainName - answerRecords: (of_dns_resolver_records_t)answerRecords - authorityRecords: (of_dns_resolver_records_t)authorityRecords - additionalRecords: (of_dns_resolver_records_t)additionalRecords - exception: (id)exception +- (void)resolver: (OFDNSResolver *)resolver + didPerformQuery: (OFDNSQuery *)query + response: (OFDNSResponse *)response + exception: (id)exception { if (exception != nil) { [of_stderr writeFormat: @"Failed to resolve: %@\n", exception]; [OFApplication terminateWithStatus: 1]; } - [of_stdout writeFormat: @"FQDN: %@\n" - @"Answer records: %@\n" - @"Authority records: %@\n" - @"Additional records: %@\n", - domainName, answerRecords, authorityRecords, - additionalRecords]; + [of_stdout writeFormat: @"%@\n", response]; [OFApplication terminate]; } - (void)applicationDidFinishLaunching { OFArray OF_GENERIC(OFString *) *arguments = [OFApplication arguments]; - of_dns_resource_record_class_t recordClass = - OF_DNS_RESOURCE_RECORD_CLASS_ANY; - of_dns_resource_record_type_t recordType = - OF_DNS_RESOURCE_RECORD_TYPE_ALL; + of_dns_class_t DNSClass = OF_DNS_CLASS_ANY; + of_dns_record_type_t recordType = OF_DNS_RECORD_TYPE_ALL; + OFDNSQuery *query; OFDNSResolver *resolver; #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [[OFSandbox alloc] init]; @try { @@ -80,24 +72,24 @@ } resolver = [OFDNSResolver resolver]; if (arguments.count >= 2) - recordType = of_dns_resource_record_type_parse( + recordType = of_dns_record_type_parse( [arguments objectAtIndex: 1]); if (arguments.count >= 3) - recordClass = of_dns_resource_record_class_parse( - [arguments objectAtIndex: 2]); + DNSClass = of_dns_class_parse([arguments objectAtIndex: 2]); if (arguments.count >= 4) { resolver.configReloadInterval = 0; resolver.nameServers = [arguments objectsInRange: of_range(3, 1)]; } - [resolver asyncResolveHost: [arguments objectAtIndex: 0] - recordClass: recordClass - recordType: recordType - delegate: self]; + query = [OFDNSQuery queryWithDomainName: [arguments objectAtIndex: 0] + DNSClass: DNSClass + recordType: recordType]; + [resolver asyncPerformQuery: query + delegate: self]; } @end Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -615,11 +615,11 @@ if ([e isKindOfClass: [OFResolveHostFailedException class]]) { if (!_quiet) [of_stdout writeString: @"\n"]; [of_stderr writeLine: - OF_LOCALIZED(@"download_failed_resolve_host_failed", + OF_LOCALIZED(@"download_resolve_host_failed", @"%[prog]: Failed to download <%[url]>!\n" @" Failed to resolve host: %[exception]", @"prog", [OFApplication programName], @"url", request.URL.string, @"exception", e)]; Index: utils/ofhttp/lang/de.json ================================================================== --- utils/ofhttp/lang/de.json +++ utils/ofhttp/lang/de.json @@ -36,13 +36,13 @@ ], "output_only_with_one_url": [ "%[prog]: -o / --output kann nicht mit mehr als einer URL benutzt ", "werden!" ], - "download_failed_resolve_host_failed": [ + "download_resolve_host_failed": [ "%[prog]: Fehler beim Download von <%[url]>!\n", - " Adressauflösung fehlgeschlagen: %[exception]" + " Host auflösen fehlgeschlagen: %[exception]" ], "download_failed_connection_failed": [ "%[prog]: Fehler beim Download von <%[url]>!\n", " Verbindung fehlgeschlagen: %[exception]" ],