Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -130,10 +130,11 @@ OFHTTPCookie.m \ OFHTTPCookieManager.m \ OFHTTPRequest.m \ OFHTTPResponse.m \ OFHTTPServer.m \ + OFLOCDNSResourceRecord.m \ OFMXDNSResourceRecord.m \ OFNSDNSResourceRecord.m \ OFPTRDNSResourceRecord.m \ OFRPDNSResourceRecord.m \ OFSOADNSResourceRecord.m \ Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -377,10 +377,37 @@ return [[[OFAAAADNSResourceRecord alloc] initWithName: name address: &address TTL: TTL] autorelease]; + } else if (recordType == OFDNSRecordTypeLOC) { + uint8_t size, horizontalPrecision, verticalPrecision; + uint32_t latitude, longitude, altitude; + + if (dataLength < 16 || buffer[i] != 0) + @throw [OFInvalidServerResponseException exception]; + + size = buffer[i + 1]; + horizontalPrecision = buffer[i + 2]; + verticalPrecision = buffer[i + 3]; + latitude = (buffer[i + 4] << 24) | (buffer[i + 5] << 16) | + (buffer[i + 6] << 8) | buffer[i + 7]; + longitude = (buffer[i + 8] << 24) | (buffer[i + 9] << 16) | + (buffer[i + 10] << 8) | buffer[i + 11]; + altitude = (buffer[i + 12] << 24) | (buffer[i + 13] << 16) | + (buffer[i + 14] << 8) | buffer[i + 15]; + + return [[[OFLOCDNSResourceRecord alloc] + initWithName: name + DNSClass: DNSClass + size: size + horizontalPrecision: horizontalPrecision + verticalPrecision: verticalPrecision + latitude: latitude + longitude: longitude + altitude: altitude + TTL: TTL] autorelease]; } else if (recordType == OFDNSRecordTypeSRV && DNSClass == OFDNSClassIN) { uint16_t priority, weight, port; size_t j; OFString *target; Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -56,10 +56,12 @@ OFDNSRecordTypeTXT = 16, /** RP */ OFDNSRecordTypeRP = 17, /** AAAA */ OFDNSRecordTypeAAAA = 28, + /** LOC */ + OFDNSRecordTypeLOC = 29, /** SRV */ OFDNSRecordTypeSRV = 33, /** All types. Only for queries. */ OFDNSRecordTypeAll = 255, /** URI */ @@ -161,13 +163,14 @@ #import "OFAAAADNSResourceRecord.h" #import "OFADNSResourceRecord.h" #import "OFCNAMEDNSResourceRecord.h" #import "OFHINFODNSResourceRecord.h" +#import "OFLOCDNSResourceRecord.h" #import "OFMXDNSResourceRecord.h" #import "OFNSDNSResourceRecord.h" #import "OFPTRDNSResourceRecord.h" #import "OFRPDNSResourceRecord.h" #import "OFSOADNSResourceRecord.h" #import "OFSRVDNSResourceRecord.h" #import "OFTXTDNSResourceRecord.h" #import "OFURIDNSResourceRecord.h" Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -56,10 +56,12 @@ return @"TXT"; case OFDNSRecordTypeRP: return @"RP"; case OFDNSRecordTypeAAAA: return @"AAAA"; + case OFDNSRecordTypeLOC: + return @"LOC"; case OFDNSRecordTypeSRV: return @"SRV"; case OFDNSRecordTypeAll: return @"all"; case OFDNSRecordTypeURI: @@ -115,10 +117,12 @@ recordType = OFDNSRecordTypeTXT; else if ([string isEqual: @"RP"]) recordType = OFDNSRecordTypeRP; else if ([string isEqual: @"AAAA"]) recordType = OFDNSRecordTypeAAAA; + else if ([string isEqual: @"LOC"]) + recordType = OFDNSRecordTypeLOC; else if ([string isEqual: @"SRV"]) recordType = OFDNSRecordTypeSRV; else if ([string isEqual: @"ALL"]) recordType = OFDNSRecordTypeAll; else if ([string isEqual: @"URI"]) ADDED src/OFLOCDNSResourceRecord.h Index: src/OFLOCDNSResourceRecord.h ================================================================== --- src/OFLOCDNSResourceRecord.h +++ src/OFLOCDNSResourceRecord.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008-2024 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 "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFLOCDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an LOC DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFLOCDNSResourceRecord: OFDNSResourceRecord +{ + uint8_t _size, _horizontalPrecision, _verticalPrecision; + uint32_t _latitude, _longitude, _altitude; +} + +/** + * @brief The diameter in centimeters of a sphere enclosing the position, + * encoded as per RFCC 1876. + */ +@property (readonly, nonatomic) uint8_t size; + +/** + * @brief The horizontal precision in centimeters, encoded as per RFC 1876. + */ +@property (readonly, nonatomic) uint8_t horizontalPrecision; + +/** + * @brief The vertical precision in centimeters, encoded as per RFC 1876. + */ +@property (readonly, nonatomic) uint8_t verticalPrecision; + +/** + * @brief The latitude in thousands of a second of an arc. + */ +@property (readonly, nonatomic) uint32_t latitude; + +/** + * @brief The longitude in thousands of a second of an arc. + */ +@property (readonly, nonatomic) uint32_t longitude; + +/** + * @brief The altitude in centimeters from a base of 100000 meters below the + * GPS reference. + */ +@property (readonly, nonatomic) uint32_t altitude; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFLOCDNSResourceRecord with the + * specified name, class, domain name and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param size The diameter in centimeters of a sphere enclosing the position, + * encoded as per RFCC 1876 + * @param horizontalPrecision The horizontal precision in centimeters, encoded + * as per RFC 1876 + * @param verticalPrecision The vertical precision in centimeters, encoded as + * per RFC 1876 + * @param latitude The latitude in thousands of a second of an arc + * @param longitude The longitude in thousands of a second of an arc + * @param altitude The altitude in centimeters from a base of 100000 meters + * below the GPS reference + * @param TTL The time to live for the resource record + * @return An initialized OFLOCDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + size: (uint8_t)size + horizontalPrecision: (uint8_t)horizontalPrecision + verticalPrecision: (uint8_t)verticalPrecision + latitude: (uint32_t)latitude + longitude: (uint32_t)longitude + altitude: (uint32_t)altitude + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFLOCDNSResourceRecord.m Index: src/OFLOCDNSResourceRecord.m ================================================================== --- src/OFLOCDNSResourceRecord.m +++ src/OFLOCDNSResourceRecord.m @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2008-2024 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 "OFLOCDNSResourceRecord.h" + +@implementation OFLOCDNSResourceRecord +@synthesize size = _size, horizontalPrecision = _horizontalPrecision; +@synthesize verticalPrecision = _verticalPrecision, latitude = _latitude; +@synthesize longitude = _longitude, altitude = _altitude; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + size: (uint8_t)size + horizontalPrecision: (uint8_t)horizontalPrecision + verticalPrecision: (uint8_t)verticalPrecision + latitude: (uint32_t)latitude + longitude: (uint32_t)longitude + altitude: (uint32_t)altitude + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeLOC + TTL: TTL]; + + @try { + _size = size; + _horizontalPrecision = horizontalPrecision; + _verticalPrecision = verticalPrecision; + _latitude = latitude; + _longitude = longitude; + _altitude = altitude; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (bool)isEqual: (id)object +{ + OFLOCDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFLOCDNSResourceRecord 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->_size != _size) + return false; + + if (record->_horizontalPrecision != _horizontalPrecision) + return false; + + if (record->_verticalPrecision != _verticalPrecision) + return false; + + if (record->_latitude != _latitude) + return false; + + if (record->_longitude != _longitude) + return false; + + if (record->_altitude != _altitude) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddByte(&hash, _size); + OFHashAddByte(&hash, _horizontalPrecision); + OFHashAddByte(&hash, _verticalPrecision); + OFHashAddByte(&hash, _latitude >> 24); + OFHashAddByte(&hash, _latitude >> 16); + OFHashAddByte(&hash, _latitude >> 8); + OFHashAddByte(&hash, _latitude); + OFHashAddByte(&hash, _longitude >> 24); + OFHashAddByte(&hash, _longitude >> 16); + OFHashAddByte(&hash, _longitude >> 8); + OFHashAddByte(&hash, _longitude); + OFHashAddByte(&hash, _altitude >> 24); + OFHashAddByte(&hash, _altitude >> 16); + OFHashAddByte(&hash, _altitude >> 8); + OFHashAddByte(&hash, _altitude); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tSize = %ue%u\n" + @"\tHorizontal precision = %ue%u\n" + @"\tVertical precision = %ue%u\n" + @"\tLatitude = %f\n" + @"\tLongitude = %f\n" + @"\tAltitude = %f\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), + _size >> 4, _size & 0xF, + _horizontalPrecision >> 4, _horizontalPrecision & 0xF, + _verticalPrecision >> 4, _verticalPrecision & 0xF, + ((double)_latitude - 2147483648) / 3600000, + ((double)_longitude - 2147483648) / 3600000, + ((double)_altitude - 10000000) / 100, _TTL]; +} +@end