Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -452,10 +452,36 @@ 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) { + uint16_t priority, weight, port; + size_t j; + OFString *target; + + if (dataLength < 6) + @throw [OFInvalidServerReplyException exception]; + + priority = (buffer[i] << 8) | buffer[i + 1]; + weight = (buffer[i + 2] << 8) | buffer[i + 3]; + port = (buffer[i + 4] << 8) | buffer[i + 5]; + + j = i + 6; + target = parseName(buffer, length, &j, MAX_ALLOWED_POINTERS); + + if (j != i + dataLength) + @throw [OFInvalidServerReplyException exception]; + + return [[[OFSRVDNSResourceRecord alloc] + initWithName: name + priority: priority + weight: weight + target: target + port: port + TTL: TTL] autorelease]; } else return [[[OFDNSResourceRecord alloc] initWithName: name recordClass: recordClass recordType: recordType Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -56,10 +56,12 @@ OF_DNS_RESOURCE_RECORD_TYPE_TXT = 16, /*! RP */ OF_DNS_RESOURCE_RECORD_TYPE_RP = 17, /*! AAAA */ OF_DNS_RESOURCE_RECORD_TYPE_AAAA = 28, + /*! SRV */ + OF_DNS_RESOURCE_RECORD_TYPE_SRV = 33, /*! All types. Only for queries. */ OF_DNS_RESOURCE_RECORD_TYPE_ALL = 255, } of_dns_resource_record_type_t; /*! @@ -506,10 +508,68 @@ expirationInterval: (uint32_t)expirationInterval minTTL: (uint32_t)minTTL TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end +/*! + * @class OFSRVDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an SRV DNS resource record. + */ +@interface OFSRVDNSResourceRecord: OFDNSResourceRecord +{ + uint16_t _priority, _weight; + OFString *_target; + uint16_t _port; +} + +/*! + * @brief The priority of the resource record. + */ +@property (readonly, nonatomic) uint16_t priority; + +/*! + * @brief The weight of the resource record. + */ +@property (readonly, nonatomic) uint16_t weight; + +/*! + * @brief The target of the resource record. + */ +@property (readonly, nonatomic) OFString *target; + +/*! + * @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 + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/*! + * @brief Initializes an already allocated OFSRVDNSResourceRecord with the + * specified name, class, preference, mail exchange and time to live. + * + * @param name The name for the resource record + * @param priority The priority for the resource record + * @param weight The weight for the resource record + * @param target The target for the resource record + * @param port The port on the target for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFSRVDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + priority: (uint16_t)priority + weight: (uint16_t)weight + target: (OFString *)target + port: (uint16_t)port + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + /*! * @class OFTXTDNSResourceRecord \ * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h * * @brief A class representing a TXT DNS resource record. Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -59,10 +59,12 @@ return @"TXT"; case OF_DNS_RESOURCE_RECORD_TYPE_RP: return @"RP"; case OF_DNS_RESOURCE_RECORD_TYPE_AAAA: return @"AAAA"; + case OF_DNS_RESOURCE_RECORD_TYPE_SRV: + return @"SRV"; case OF_DNS_RESOURCE_RECORD_TYPE_ALL: return @"all"; default: return [OFString stringWithFormat: @"%u", recordType]; } @@ -112,10 +114,12 @@ recordType = OF_DNS_RESOURCE_RECORD_TYPE_TXT; else if ([string isEqual: @"RP"]) recordType = OF_DNS_RESOURCE_RECORD_TYPE_RP; else if ([string isEqual: @"AAAA"]) recordType = OF_DNS_RESOURCE_RECORD_TYPE_AAAA; + else if ([string isEqual: @"SRV"]) + recordType = OF_DNS_RESOURCE_RECORD_TYPE_SRV; else @throw [OFInvalidArgumentException exception]; objc_autoreleasePoolPop(pool); @@ -1109,10 +1113,127 @@ _primaryNameServer, _responsiblePerson, _serialNumber, _refreshInterval, _retryInterval, _expirationInterval, _minTTL, _TTL]; } @end + +@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 + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + priority: (uint16_t)priority + weight: (uint16_t)weight + 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 + TTL: TTL]; + + @try { + _priority = priority; + _weight = weight; + _target = [target copy]; + _port = port; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_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) + 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, _recordClass >> 8); + OF_HASH_ADD(hash, _recordClass); + 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); + OF_HASH_ADD(hash, _weight); + OF_HASH_ADD_HASH(hash, [_target hash]); + OF_HASH_ADD(hash, _port >> 8); + OF_HASH_ADD(hash, _port); + + OF_HASH_FINALIZE(hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tPriority = %" PRIu16 "\n" + @"\tWeight = %" PRIu16 "\n" + @"\tTarget = %@\n" + @"\tPort = %" PRIu16 "\n" + @"\tTTL = %" PRIu32 "\n" + @">", + [self className], _name, _priority, _weight, _target, _port, _TTL]; +} +@end @implementation OFTXTDNSResourceRecord @synthesize textData = _textData; - (instancetype)initWithName: (OFString *)name