Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -133,11 +133,12 @@ OFINICategory.m \ OFINIFile.m \ OFSettings.m \ OFString+PathAdditions.m SRCS_PLUGINS = OFPlugin.m -SRCS_SOCKETS = OFDNSResolver.m \ +SRCS_SOCKETS = OFDNSRequest.m \ + OFDNSResolver.m \ OFDNSResourceRecord.m \ OFDNSResponse.m \ OFHTTPClient.m \ OFHTTPCookie.m \ OFHTTPCookieManager.m \ ADDED src/OFDNSRequest.h Index: src/OFDNSRequest.h ================================================================== --- src/OFDNSRequest.h +++ src/OFDNSRequest.h @@ -0,0 +1,96 @@ +/* + * 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 OFDNSRequest OFDNSRequest.h ObjFW/OFDNSRequest.h + * + * @brief A class representing a DNS request. + */ +@interface OFDNSRequest: OFObject +{ + OFString *_host; + of_dns_resource_record_class_t _recordClass; + of_dns_resource_record_type_t _recordType; + OF_RESERVE_IVARS(4) +} + +/*! + * @brief The host to resolve. + */ +@property (readonly, nonatomic) OFString *host; + +/*! + * @brief The requested record class. + */ +@property (readonly, nonatomic) of_dns_resource_record_class_t recordClass; + +/*! + * @brief The requested record type. + */ +@property (readonly, nonatomic) of_dns_resource_record_type_t recordType; + +/*! + * @brief Creates a new, autoreleased OFDNSRequest with IN class and type ALL. + * + * @param host The host to resolve + * @return A new, autoreleased OFDNSRequest. + */ ++ (instancetype)requestWithHost: (OFString *)host; + +/*! + * @brief Creates a new, autoreleased OFDNSRequest. + * + * @param host The host to resolve + * @param recordClass The requested record class + * @param recordType The requested record type + * @return A new, autoreleased OFDNSRequest. + */ ++ (instancetype)requestWithHost: (OFString *)host + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType; + +/*! + * @brief Initializes an already allocated OFDNSRequest with IN class and type + * ALL. + * + * @param host The host to resolve + * @return An initialized OFDNSRequest + */ +- (instancetype)initWithHost: (OFString *)host; + +/*! + * @brief Initializes an already allocated OFDNSRequest. + * + * @param host The host to resolve + * @param recordClass The requested record class + * @param recordType The requested record type + * @return An initialized OFDNSRequest + */ +- (instancetype)initWithHost: (OFString *)host + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType + OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFDNSRequest.m Index: src/OFDNSRequest.m ================================================================== --- src/OFDNSRequest.m +++ src/OFDNSRequest.m @@ -0,0 +1,121 @@ +/* + * 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 "OFDNSRequest.h" +#import "OFString.h" + +@implementation OFDNSRequest +@synthesize host = _host, recordClass = _recordClass, recordType = _recordType; + ++ (instancetype)requestWithHost: (OFString *)host +{ + return [[[self alloc] initWithHost: host] autorelease]; +} + ++ (instancetype)requestWithHost: (OFString *)host + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType +{ + return [[[self alloc] initWithHost: host + recordClass: recordClass + recordType: recordType] autorelease]; +} + +- (instancetype)initWithHost: (OFString *)host +{ + return [self initWithHost: host + recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN + recordType: OF_DNS_RESOURCE_RECORD_TYPE_ALL]; +} + +- (instancetype)initWithHost: (OFString *)host + recordClass: (of_dns_resource_record_class_t)recordClass + recordType: (of_dns_resource_record_type_t)recordType +{ + self = [super init]; + + @try { + _host = [host copy]; + _recordClass = recordClass; + _recordType = recordType; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_host release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFDNSRequest *request; + + if (![object isKindOfClass: [OFDNSRequest class]]) + return false; + + request = object; + + if (request->_host != _host && ![request->_host isEqual: _host]) + return false; + if (request->_recordClass != _recordClass) + return false; + if (request->_recordType != _recordType) + return false; + + return true; +} + +- (uint32_t)hash +{ + uint32_t hash; + + OF_HASH_INIT(hash); + OF_HASH_ADD_HASH(hash, _host.hash); + OF_HASH_ADD(hash, _recordClass); + OF_HASH_ADD(hash, _recordType); + OF_HASH_FINALIZE(hash); + + return hash; +} + +- (id)copy +{ + return [self retain]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@ %@ %@ %@>", + self.className, _host, + of_dns_resource_record_class_to_string(_recordClass), + of_dns_resource_record_type_to_string(_recordType)]; +} +@end Index: src/OFDNSResolver.h ================================================================== --- src/OFDNSResolver.h +++ src/OFDNSResolver.h @@ -14,10 +14,11 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" +#import "OFDNSRequest.h" #import "OFDNSResourceRecord.h" #import "OFDNSResponse.h" #import "OFRunLoop.h" #import "OFString.h" @@ -198,45 +199,28 @@ * @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 request. + * + * @param request The request to perform + * @param delegate The delegate to use for callbacks + */ +- (void)asyncPerformRequest: (OFDNSRequest *)request + delegate: (id )delegate; + +/*! + * @brief Asynchronously performs the specified request. + * + * @param request The request 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)asyncPerformRequest: (OFDNSRequest *)request + 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 Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -22,10 +22,12 @@ #include "unistd_wrapper.h" #import "OFDNSResolver.h" #import "OFArray.h" #import "OFCharacterSet.h" +#import "OFDNSRequest.h" +#import "OFDNSResponse.h" #import "OFData.h" #import "OFDate.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFLocale.h" @@ -37,18 +39,18 @@ #import "OFUDPSocket+Private.h" #ifdef OF_WINDOWS # import "OFWindowsRegistryKey.h" #endif +#import "OFDNSRequestFailedException.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 @@ -119,13 +121,12 @@ @end @interface OFDNSResolverQuery: OFObject { @public - OFString *_host, *_domainName; - of_dns_resource_record_class_t _recordClass; - of_dns_resource_record_type_t _recordType; + OFDNSRequest *_request; + OFString *_domainName; OFNumber *_ID; OFDNSResolverSettings *_settings; size_t _nameServersIndex, _searchDomainsIndex; unsigned int _attempt; id _target; @@ -134,21 +135,19 @@ 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; +- (instancetype)initWithRequest: (OFDNSRequest *)request + domainName: (OFString *)domainName + 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; @@ -213,27 +212,23 @@ #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_asyncPerformRequest: (OFDNSRequest *)request + 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_asyncPerformRequest: (OFDNSRequest *)request + 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 @@ -696,33 +691,29 @@ [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 +- (instancetype)initWithRequest: (OFDNSRequest *)request + domainName: (OFString *)domainName + ID: (OFNumber *)ID + settings: (OFDNSResolverSettings *)settings + nameServersIndex: (size_t)nameServersIndex + searchDomainsIndex: (size_t)searchDomainsIndex + target: (id)target + selector: (SEL)selector + context: (id)context { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); OFMutableData *queryData; uint16_t tmp; - _host = [host copy]; + _request = [request copy]; _domainName = [domainName copy]; - _recordClass = recordClass; - _recordType = recordType; _ID = [ID retain]; _settings = [settings retain]; _nameServersIndex = nameServersIndex; _searchDomainsIndex = searchDomainsIndex; _target = [target retain]; @@ -731,11 +722,11 @@ 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); @@ -752,11 +743,11 @@ /* Question */ /* QNAME */ for (OFString *component in - [domainName componentsSeparatedByString: @"."]) { + [_domainName componentsSeparatedByString: @"."]) { size_t length = component.UTF8StringLength; uint8_t length8; if (length > 63 || queryData.count + length > 512) @throw [OFOutOfRangeException exception]; @@ -766,18 +757,18 @@ [queryData addItems: component.UTF8String count: length]; } /* QTYPE */ - tmp = OF_BSWAP16_IF_LE(recordType); + tmp = OF_BSWAP16_IF_LE(_request.recordType); [queryData addItems: &tmp count: 2]; /* QCLASS */ - tmp = OF_BSWAP16_IF_LE(recordClass); + tmp = OF_BSWAP16_IF_LE(_request.recordClass); [queryData addItems: &tmp - count: 2]; + count: 2]; [queryData makeImmutable]; _queryData = [queryData copy]; @@ -790,11 +781,11 @@ return self; } - (void)dealloc { - [_host release]; + [_request release]; [_domainName release]; [_ID release]; [_settings release]; [_target release]; [_context release]; @@ -893,26 +884,29 @@ if (!found) { of_run_loop_mode_t runLoopMode = [OFRunLoop currentRunLoop].currentMode; OFNumber *recordTypeNumber = [OFNumber numberWithInt: recordType]; + OFDNSRequest *request; _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:response: - context:exception:) - context: recordTypeNumber]; + request = [OFDNSRequest + requestWithHost: alias + recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN + recordType: recordType]; + [_resolver of_asyncPerformRequest: request + runLoopMode: runLoopMode + target: self + selector: @selector(resolver: + didResolveCNAME:response: + context:exception:) + context: recordTypeNumber]; } } - (void)resolver: (OFDNSResolver *)resolver didResolveCNAME: (OFString *)CNAME @@ -1007,16 +1001,20 @@ } } [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 (addresses.count == 0) { + OFDNSRequest *request = [OFDNSRequest + requestWithHost: _host + recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN + recordType: 0]; + + exception = [OFDNSRequestFailedException + exceptionWithRequest: request + error: OF_DNS_RESOLVER_ERROR_UNKNOWN]; + } if ([_delegate respondsToSelector: @selector( resolver:didResolveDomainName:socketAddresses:exception:)]) [_delegate resolver: _resolver didResolveDomainName: _domainName @@ -1567,33 +1565,32 @@ _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)of_asyncPerformRequest: (OFDNSRequest *)request + 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; + OFString *host, *domainName; OFDNSResolverQuery *query; [self of_reloadSystemConfig]; /* Random, unused ID */ do { ID = [OFNumber numberWithUInt16: (uint16_t)of_random()]; } while ([_queries objectForKey: ID] != nil); + host = request.host; if (isFQDN(host, settings)) { domainName = host; if (![domainName hasSuffix: @"."]) domainName = [domainName stringByAppendingString: @"."]; @@ -1607,21 +1604,19 @@ 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]; + initWithRequest: request + domainName: domainName + 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]; @@ -1641,61 +1636,40 @@ didResolveDomainName: domainName response: response 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: - response: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: - response: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: - response: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)asyncPerformRequest: (OFDNSRequest *)request + delegate: (id )delegate +{ + [self of_asyncPerformRequest: request + runLoopMode: of_run_loop_mode_default + target: self + selector: @selector(of_resolver: + didResolveDomainName:response:context: + exception:) + context: delegate]; +} + +- (void)asyncPerformRequest: (OFDNSRequest *)request + runLoopMode: (of_run_loop_mode_t)runLoopMode + delegate: (id )delegate +{ + [self of_asyncPerformRequest: request + runLoopMode: runLoopMode + target: self + selector: @selector(of_resolver: + didResolveDomainName:response:context: + exception:) + context: delegate]; +} + +- (void)of_asyncPerformRequest: (OFDNSRequest *)request + 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 @@ -1702,20 +1676,18 @@ 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]; + [self of_asyncPerformRequest: request + settings: settings + nameServersIndex: 0 + searchDomainsIndex: 0 + runLoopMode: runLoopMode + target: target + selector: selector + context: context]; objc_autoreleasePoolPop(pool); } - (void)of_sendQuery: (OFDNSResolverQuery *)query @@ -1786,11 +1758,11 @@ runLoopMode: runLoopMode]; } - (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query { - OFResolveHostFailedException *exception; + OFDNSRequestFailedException *exception; if (query == nil) return; if (query->_nameServersIndex + 1 < @@ -1823,15 +1795,13 @@ [_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]; + exception = [OFDNSRequestFailedException + exceptionWithRequest: query->_request + error: OF_DNS_RESOLVER_ERROR_TIMEOUT]; callback(query->_target, query->_selector, self, query->_domainName, nil, query->_context, exception); } @@ -1910,23 +1880,25 @@ case 3: if (query->_searchDomainsIndex + 1 < query->_settings->_searchDomains.count) { of_run_loop_mode_t runLoopMode = [OFRunLoop currentRunLoop].currentMode; + size_t nameServersIndex = + query->_nameServersIndex; + size_t searchDomainsIndex = + query->_searchDomainsIndex; 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]; + [self of_asyncPerformRequest: query->_request + settings: query->_settings + nameServersIndex: nameServersIndex + searchDomainsIndex: searchDomainsIndex + runLoopMode: runLoopMode + target: query->_target + selector: query->_selector + context: query->_context]; return true; } error = OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR; @@ -1941,15 +1913,13 @@ error = OF_DNS_RESOLVER_ERROR_UNKNOWN; break; } if (buffer[3] & 0x0F) - @throw [OFResolveHostFailedException - exceptionWithHost: query->_host - recordClass: query->_recordClass - recordType: query->_recordType - error: error]; + @throw [OFDNSRequestFailedException + exceptionWithRequest: query->_request + 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]; @@ -2101,16 +2071,18 @@ 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; + OFDNSRequest *request = [OFDNSRequest + requestWithHost: host + recordClass: recordClass + recordType: recordType]; - exception = [OFResolveHostFailedException - exceptionWithHost: host - recordClass: recordClass - recordType: recordType - error: error]; + exception = [OFDNSRequestFailedException + exceptionWithRequest: request + error: error]; } } if ([delegate respondsToSelector: @selector(resolver: didResolveDomainName:socketAddresses:exception:)]) { @@ -2158,37 +2130,44 @@ } #ifdef OF_HAVE_IPV6 if (addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV6 || addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) { + OFDNSRequest *request = [OFDNSRequest + requestWithHost: host + recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN + recordType: OF_DNS_RESOURCE_RECORD_TYPE_AAAA]; 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: - response:context:exception:) - context: recordTypeNumber]; + [self of_asyncPerformRequest: request + runLoopMode: runLoopMode + target: context + selector: @selector(resolver: + didResolveDomainName:response: + 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: - response:context:exception:) - context: [OFNumber numberWithInt: - OF_DNS_RESOURCE_RECORD_TYPE_A]]; + addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) { + OFDNSRequest *request = [OFDNSRequest + requestWithHost: host + recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN + recordType: OF_DNS_RESOURCE_RECORD_TYPE_A]; + OFNumber *recordTypeNumber = + [OFNumber numberWithInt: OF_DNS_RESOURCE_RECORD_TYPE_A]; + + [self of_asyncPerformRequest: request + runLoopMode: runLoopMode + target: context + selector: @selector(resolver: + didResolveDomainName:response: + context:exception:) + context: recordTypeNumber]; + } objc_autoreleasePoolPop(pool); } - (OFData *)resolveSocketAddressesForHost: (OFString *)host @@ -2242,17 +2221,15 @@ _IPv6Socket = nil; #endif enumerator = [_queries objectEnumerator]; while ((query = [enumerator nextObject]) != nil) { - OFResolveHostFailedException *exception; + OFDNSRequestFailedException *exception; - exception = [OFResolveHostFailedException - exceptionWithHost: query->_host - recordClass: query->_recordClass - recordType: query->_recordType - error: OF_DNS_RESOLVER_ERROR_CANCELED]; + exception = [OFDNSRequestFailedException + exceptionWithRequest: query->_request + error: OF_DNS_RESOLVER_ERROR_CANCELED]; callback(query->_target, query->_selector, self, query->_domainName, nil, query->_context, exception); } Index: src/OFDNSResponse.h ================================================================== --- src/OFDNSResponse.h +++ src/OFDNSResponse.h @@ -40,23 +40,23 @@ } /*! * @brief The answer records of the response. */ -@property OF_NULLABLE_PROPERTY (nonatomic, readonly) +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) of_dns_response_records_t answerRecords; /*! * @brief The authority records of the response. */ -@property OF_NULLABLE_PROPERTY (nonatomic, readonly) +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) of_dns_response_records_t authorityRecords; /*! * @brief The additional records of the response. */ -@property OF_NULLABLE_PROPERTY (nonatomic, readonly) +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) of_dns_response_records_t additionalRecords; /*! * @brief Creates a new, autoreleased OFDNSResponse. * Index: src/OFDNSResponse.m ================================================================== --- src/OFDNSResponse.m +++ src/OFDNSResponse.m @@ -80,15 +80,13 @@ other = object; if (other->_answerRecords != _answerRecords && ![other->_answerRecords isEqual: _answerRecords]) return false; - if (other->_authorityRecords != _authorityRecords && ![other->_authorityRecords isEqual: _authorityRecords]) return false; - if (other->_additionalRecords != _additionalRecords && ![other->_additionalRecords isEqual: _additionalRecords]) return false; return true; @@ -118,13 +116,13 @@ OFString *additionalRecords = [_additionalRecords.description stringByReplacingOccurrencesOfString: @"\n" withString: @"\n\t"]; return [OFString stringWithFormat: - @"", - answerRecords, authorityRecords, additionalRecords]; + self.className, answerRecords, authorityRecords, additionalRecords]; } @end Index: src/OFLHADecompressingStream.h ================================================================== --- src/OFLHADecompressingStream.h +++ src/OFLHADecompressingStream.h @@ -42,13 +42,13 @@ uint8_t *_Nullable _codesLengths; uint16_t _length; uint32_t _distance; } -@property (nonatomic, readonly) uint32_t bytesConsumed; +@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/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -145,11 +145,11 @@ #import "OFException.h" #ifdef OF_HAVE_SOCKETS # import "OFAcceptFailedException.h" # import "OFAlreadyConnectedException.h" # import "OFBindFailedException.h" -# import "OFResolveHostFailedException.h" +# import "OFDNSRequestFailedException.h" #endif #import "OFChangeCurrentDirectoryPathFailedException.h" #import "OFChecksumMismatchException.h" #ifdef OF_HAVE_THREADS # import "OFConditionBroadcastFailedException.h" Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -56,14 +56,14 @@ SRCS_PLUGINS = OFLoadPluginFailedException.m SRCS_SOCKETS = OFAcceptFailedException.m \ OFAlreadyConnectedException.m \ OFBindFailedException.m \ OFConnectionFailedException.m \ + OFDNSRequestFailedException.m \ OFHTTPRequestFailedException.m \ OFListenFailedException.m \ - OFObserveFailedException.m \ - OFResolveHostFailedException.m + OFObserveFailedException.m SRCS_THREADS = OFConditionBroadcastFailedException.m \ OFConditionSignalFailedException.m \ OFConditionStillWaitingException.m \ OFConditionWaitFailedException.m \ OFThreadJoinFailedException.m \ ADDED src/exceptions/OFDNSRequestFailedException.h Index: src/exceptions/OFDNSRequestFailedException.h ================================================================== --- src/exceptions/OFDNSRequestFailedException.h +++ src/exceptions/OFDNSRequestFailedException.h @@ -0,0 +1,68 @@ +/* + * 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 "OFDNSRequest.h" +#import "OFDNSResolver.h" +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/*! + * @class OFDNSRequestFailedException \ + * OFDNSRequestFailedException.h ObjFW/OFDNSRequestFailedException.h + * + * @brief An exception indicating the resolving a host failed. + */ +@interface OFDNSRequestFailedException: OFException +{ + OFDNSRequest *_request; + of_dns_resolver_error_t _error; +} + +/*! + * @brief The request which could not be performed. + */ +@property (readonly, nonatomic) OFDNSRequest *request; + +/*! + * @brief The error from the resolver. + */ +@property (readonly, nonatomic) of_dns_resolver_error_t error; + +/*! + * @brief Creates a new, autoreleased resolve host failed exception. + * + * @param request The request which could not be performed + * @param error The error from the resolver + * @return A new, autoreleased address translation failed exception + */ ++ (instancetype)exceptionWithRequest: (OFDNSRequest *)request + error: (of_dns_resolver_error_t)error; + +/*! + * @brief Initializes an already allocated address translation failed exception. + * + * @param request The request which could not be performed + * @param error The error from the resolver + * @return An initialized address translation failed exception + */ +- (instancetype)initWithRequest: (OFDNSRequest *)request + error: (of_dns_resolver_error_t)error; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFDNSRequestFailedException.m Index: src/exceptions/OFDNSRequestFailedException.m ================================================================== --- src/exceptions/OFDNSRequestFailedException.m +++ src/exceptions/OFDNSRequestFailedException.m @@ -0,0 +1,96 @@ +/* + * 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 "OFDNSRequestFailedException.h" +#import "OFString.h" + +@implementation OFDNSRequestFailedException +@synthesize request = _request, error = _error; + ++ (instancetype)exceptionWithRequest: (OFDNSRequest *)request + error: (of_dns_resolver_error_t)error +{ + return [[[self alloc] initWithRequest: request + error: error] autorelease]; +} + +- (instancetype)initWithRequest: (OFDNSRequest *)request + error: (of_dns_resolver_error_t)error +{ + self = [super init]; + + @try { + _request = [request copy]; + _error = error; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_request release]; + + [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: + @"Request %@ could not be performed: %@", _request, error]; +} +@end DELETED src/exceptions/OFResolveHostFailedException.h Index: src/exceptions/OFResolveHostFailedException.h ================================================================== --- src/exceptions/OFResolveHostFailedException.h +++ src/exceptions/OFResolveHostFailedException.h @@ -1,87 +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 "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. - */ -@interface OFResolveHostFailedException: OFException -{ - OFString *_host; - of_dns_resource_record_class_t _recordClass; - of_dns_resource_record_type_t _recordType; - 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 error from the resolver. - */ -@property (readonly, nonatomic) of_dns_resolver_error_t error; - -/*! - * @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 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 - error: (of_dns_resolver_error_t)error; - -/*! - * @brief Initializes an already allocated address translation 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 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 - error: (of_dns_resolver_error_t)error; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFResolveHostFailedException.m Index: src/exceptions/OFResolveHostFailedException.m ================================================================== --- src/exceptions/OFResolveHostFailedException.m +++ src/exceptions/OFResolveHostFailedException.m @@ -1,105 +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" - -#import "OFResolveHostFailedException.h" -#import "OFString.h" - -@implementation OFResolveHostFailedException -@synthesize host = _host, recordClass = _recordClass, recordType = _recordType; -@synthesize error = _error; - -+ (instancetype)exceptionWithHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - error: (of_dns_resolver_error_t)error -{ - return [[[self alloc] initWithHost: host - recordClass: recordClass - recordType: recordType - error: error] autorelease]; -} - -- (instancetype)initWithHost: (OFString *)host - recordClass: (of_dns_resource_record_class_t)recordClass - recordType: (of_dns_resource_record_type_t)recordType - error: (of_dns_resolver_error_t)error -{ - self = [super init]; - - @try { - _host = [host copy]; - _recordClass = recordClass; - _recordType = recordType; - _error = error; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_host release]; - - [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]; -} -@end Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -51,10 +51,11 @@ 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; + OFDNSRequest *request; OFDNSResolver *resolver; #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [[OFSandbox alloc] init]; @try { @@ -88,11 +89,12 @@ resolver.configReloadInterval = 0; resolver.nameServers = [arguments objectsInRange: of_range(3, 1)]; } - [resolver asyncResolveHost: [arguments objectAtIndex: 0] - recordClass: recordClass - recordType: recordType - delegate: self]; + request = [OFDNSRequest requestWithHost: [arguments objectAtIndex: 0] + recordClass: recordClass + recordType: recordType]; + [resolver asyncPerformRequest: request + delegate: self]; } @end Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -34,17 +34,17 @@ #import "OFTCPSocket.h" #import "OFTLSSocket.h" #import "OFURL.h" #import "OFConnectionFailedException.h" +#import "OFDNSRequestFailedException.h" #import "OFHTTPRequestFailedException.h" #import "OFInvalidFormatException.h" #import "OFInvalidServerReplyException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" -#import "OFResolveHostFailedException.h" #import "OFRetrieveItemAttributesFailedException.h" #import "OFUnsupportedProtocolException.h" #import "OFWriteFailedException.h" #import "ProgressBar.h" @@ -610,18 +610,18 @@ - (void)client: (OFHTTPClient *)client didFailWithException: (id)e request: (OFHTTPRequest *)request { - if ([e isKindOfClass: [OFResolveHostFailedException class]]) { + if ([e isKindOfClass: [OFDNSRequestFailedException class]]) { if (!_quiet) [of_stdout writeString: @"\n"]; [of_stderr writeLine: - OF_LOCALIZED(@"download_failed_resolve_host_failed", + OF_LOCALIZED(@"download_dns_request_failed", @"%[prog]: Failed to download <%[url]>!\n" - @" Failed to resolve host: %[exception]", + @" DNS request failed: %[exception]", @"prog", [OFApplication programName], @"url", request.URL.string, @"exception", e)]; } else if ([e isKindOfClass: [OFConnectionFailedException class]]) { if (!_quiet) 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_dns_request_failed": [ "%[prog]: Fehler beim Download von <%[url]>!\n", - " Adressauflösung fehlgeschlagen: %[exception]" + " DNS-Anfrage fehlgeschlagen: %[exception]" ], "download_failed_connection_failed": [ "%[prog]: Fehler beim Download von <%[url]>!\n", " Verbindung fehlgeschlagen: %[exception]" ],