feat: sync httpdns sdk/platform updates without large binaries

This commit is contained in:
robin
2026-03-04 17:59:14 +08:00
parent 853897a6f8
commit 532891fad0
700 changed files with 6096 additions and 2712 deletions

View File

@@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
#import "HttpdnsRequest.h"
@class HttpdnsHostRecord;
@class HttpdnsIPRecord;
@class HttpdnsServerIpObject;
@interface HttpdnsIpObject: NSObject<NSCoding, NSCopying>
@property (nonatomic, copy, getter=getIpString, setter=setIp:) NSString *ip;
@property (nonatomic, assign) NSInteger connectedRT;
@end
@interface HttpdnsHostObject : NSObject<NSCoding, NSCopying>
@property (nonatomic, copy, setter=setCacheKey:, getter=getCacheKey) NSString *cacheKey;
@property (nonatomic, copy, setter=setHostName:, getter=getHostName) NSString *hostName;
@property (nonatomic, copy, setter=setClientIp:, getter=getClientIp) NSString *clientIp;
@property (nonatomic, strong, setter=setV4Ips:, getter=getV4Ips) NSArray<HttpdnsIpObject *> *v4Ips;
@property (nonatomic, strong, setter=setV6Ips:, getter=getV6Ips) NSArray<HttpdnsIpObject *> *v6Ips;
// 虽然当前后端接口的设计里ttl并没有区分v4、v6但原则是应该要分开
// v4 ttl
@property (nonatomic, setter=setV4TTL:, getter=getV4TTL) int64_t v4ttl;
@property (nonatomic, assign) int64_t lastIPv4LookupTime;
// v6 ttl
@property (nonatomic, setter=setV6TTL:, getter=getV6TTL) int64_t v6ttl;
@property (nonatomic, assign) int64_t lastIPv6LookupTime;
// 用来标记该域名为配置v4记录或v6记录的情况避免如双栈网络下因为某个协议查不到record需要重复请<E5A48D><E8AFB7>?
// 这个信息不用持久化一次APP启动周期内使用是合适的
@property (nonatomic, assign) BOOL hasNoIpv4Record;
@property (nonatomic, assign) BOOL hasNoIpv6Record;
@property (nonatomic, strong, setter=setExtra:, getter=getExtra) NSString *extra;
// 标识是否从持久化缓存加载
@property (nonatomic, assign, setter=setIsLoadFromDB:, getter=isLoadFromDB) BOOL isLoadFromDB;
- (instancetype)init;
- (BOOL)isIpEmptyUnderQueryIpType:(HttpdnsQueryIPType)queryType;
- (BOOL)isExpiredUnderQueryIpType:(HttpdnsQueryIPType)queryIPType;
+ (instancetype)fromDBRecord:(HttpdnsHostRecord *)IPRecord;
/**
* 将当前对象转换为数据库记录对<E5BD95><E5AFB9>?
* @return 数据库记录对<E5BD95><E5AFB9>?
*/
- (HttpdnsHostRecord *)toDBRecord;
- (NSArray<NSString *> *)getV4IpStrings;
- (NSArray<NSString *> *)getV6IpStrings;
/**
* 更新指定IP的connectedRT值并重新排序IP列表
* @param ip 需要更新的IP地址
* @param connectedRT 检测到的RT值-1表示不可<E4B88D><E58FAF>?
*/
- (void)updateConnectedRT:(NSInteger)connectedRT forIP:(NSString *)ip;
@end

View File

@@ -0,0 +1,306 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#import "HttpdnsHostObject.h"
#import "HttpdnsInternalConstant.h"
#import "HttpdnsUtil.h"
#import "HttpdnsLog_Internal.h"
#import "HttpdnsHostRecord.h"
#import "HttpdnsIPQualityDetector.h"
@implementation HttpdnsIpObject
- (instancetype)init {
if (self = [super init]) {
// connectedRT<EFBFBD><EFBFBD>?
self.connectedRT = NSIntegerMax;
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
self.ip = [aDecoder decodeObjectForKey:@"ip"];
self.connectedRT = [aDecoder decodeIntegerForKey:@"connectedRT"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.ip forKey:@"ip"];
[aCoder encodeInteger:self.connectedRT forKey:@"connectedRT"];
}
- (id)copyWithZone:(NSZone *)zone {
HttpdnsIpObject *copy = [[[self class] allocWithZone:zone] init];
if (copy) {
copy.ip = [self.ip copyWithZone:zone];
copy.connectedRT = self.connectedRT;
}
return copy;
}
+ (NSArray<HttpdnsIpObject *> *)IPObjectsFromIPs:(NSArray<NSString *> *)IPs {
NSMutableArray *IPObjects = [NSMutableArray arrayWithCapacity:IPs.count];
for (NSString *IP in IPs) {
HttpdnsIpObject *IPObject = [HttpdnsIpObject new];
IPObject.ip = IP;
IPObject.connectedRT = NSIntegerMax;
[IPObjects addObject:IPObject];
}
return [IPObjects copy];
}
- (NSString *)description {
if (self.connectedRT == NSIntegerMax) {
return [NSString stringWithFormat:@"ip: %@", self.ip];
} else {
return [NSString stringWithFormat:@"ip: %@, connectedRT: %ld", self.ip, self.connectedRT];
}
}
@end
@implementation HttpdnsHostObject
- (instancetype)init {
_hostName = nil;
_cacheKey = nil;
_clientIp = nil;
_v4ttl = -1;
_lastIPv4LookupTime = 0;
_v6ttl = -1;
_lastIPv6LookupTime = 0;
_isLoadFromDB = NO;
_v4Ips = nil;
_v6Ips = nil;
_extra = nil;
_hasNoIpv4Record = NO;
_hasNoIpv6Record = NO;
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
_cacheKey = [aDecoder decodeObjectForKey:@"cacheKey"];
_hostName = [aDecoder decodeObjectForKey:@"hostName"];
_clientIp = [aDecoder decodeObjectForKey:@"clientIp"];
_v4Ips = [aDecoder decodeObjectForKey:@"v4ips"];
_v4ttl = [aDecoder decodeInt64ForKey:@"v4ttl"];
_lastIPv4LookupTime = [aDecoder decodeInt64ForKey:@"lastIPv4LookupTime"];
_v6Ips = [aDecoder decodeObjectForKey:@"v6ips"];
_v6ttl = [aDecoder decodeInt64ForKey:@"v6ttl"];
_lastIPv6LookupTime = [aDecoder decodeInt64ForKey:@"lastIPv6LookupTime"];
_extra = [aDecoder decodeObjectForKey:@"extra"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_cacheKey forKey:@"cacheKey"];
[aCoder encodeObject:_hostName forKey:@"hostName"];
[aCoder encodeObject:_clientIp forKey:@"clientIp"];
[aCoder encodeObject:_v4Ips forKey:@"v4ips"];
[aCoder encodeInt64:_v4ttl forKey:@"v4ttl"];
[aCoder encodeInt64:_lastIPv4LookupTime forKey:@"lastIPv4LookupTime"];
[aCoder encodeObject:_v6Ips forKey:@"v6ips"];
[aCoder encodeInt64:_v6ttl forKey:@"v6ttl"];
[aCoder encodeInt64:_lastIPv6LookupTime forKey:@"lastIPv6LookupTime"];
[aCoder encodeObject:_extra forKey:@"extra"];
}
- (BOOL)isIpEmptyUnderQueryIpType:(HttpdnsQueryIPType)queryType {
if (queryType & HttpdnsQueryIPTypeIpv4) {
// _hasNoIpv4Recordtrueipv4ip<EFBFBD><EFBFBD>?
if ([HttpdnsUtil isEmptyArray:[self getV4Ips]] && !_hasNoIpv4Record) {
return YES;
}
} else if (queryType & HttpdnsQueryIPTypeIpv6 && !_hasNoIpv6Record) {
// _hasNoIpv6Recordtrueipv6ip<EFBFBD><EFBFBD>?
if ([HttpdnsUtil isEmptyArray:[self getV6Ips]] && !_hasNoIpv6Record) {
return YES;
}
}
return NO;
}
- (id)copyWithZone:(NSZone *)zone {
HttpdnsHostObject *copy = [[[self class] allocWithZone:zone] init];
if (copy) {
copy.cacheKey = [self.cacheKey copyWithZone:zone];
copy.hostName = [self.hostName copyWithZone:zone];
copy.clientIp = [self.clientIp copyWithZone:zone];
copy.v4Ips = [[NSArray allocWithZone:zone] initWithArray:self.v4Ips copyItems:YES];
copy.v6Ips = [[NSArray allocWithZone:zone] initWithArray:self.v6Ips copyItems:YES];
copy.v4ttl = self.v4ttl;
copy.lastIPv4LookupTime = self.lastIPv4LookupTime;
copy.v6ttl = self.v6ttl;
copy.lastIPv6LookupTime = self.lastIPv6LookupTime;
copy.hasNoIpv4Record = self.hasNoIpv4Record;
copy.hasNoIpv6Record = self.hasNoIpv6Record;
copy.extra = [self.extra copyWithZone:zone];
copy.isLoadFromDB = self.isLoadFromDB;
}
return copy;
}
- (BOOL)isExpiredUnderQueryIpType:(HttpdnsQueryIPType)queryIPType {
int64_t currentEpoch = (int64_t)[[[NSDate alloc] init] timeIntervalSince1970];
if ((queryIPType & HttpdnsQueryIPTypeIpv4)
&& !_hasNoIpv4Record
&& _lastIPv4LookupTime + _v4ttl <= currentEpoch) {
return YES;
}
if ((queryIPType & HttpdnsQueryIPTypeIpv6)
&& !_hasNoIpv6Record
&& _lastIPv6LookupTime + _v6ttl <= currentEpoch) {
return YES;
}
return NO;
}
+ (instancetype)fromDBRecord:(HttpdnsHostRecord *)hostRecord {
HttpdnsHostObject *hostObject = [HttpdnsHostObject new];
[hostObject setCacheKey:hostRecord.cacheKey];
[hostObject setHostName:hostRecord.hostName];
[hostObject setClientIp:hostRecord.clientIp];
NSArray *v4ips = hostRecord.v4ips;
NSArray *v6ips = hostRecord.v6ips;
if ([HttpdnsUtil isNotEmptyArray:v4ips]) {
[hostObject setV4Ips:[HttpdnsIpObject IPObjectsFromIPs:v4ips]];
[hostObject setV4TTL:hostRecord.v4ttl];
[hostObject setLastIPv4LookupTime:hostRecord.v4LookupTime];
}
if ([HttpdnsUtil isNotEmptyArray:v6ips]) {
[hostObject setV6Ips:[HttpdnsIpObject IPObjectsFromIPs:v6ips]];
[hostObject setV6TTL:hostRecord.v6ttl];
[hostObject setLastIPv6LookupTime:hostRecord.v6LookupTime];
}
[hostObject setExtra:hostRecord.extra];
[hostObject setIsLoadFromDB:YES];
return hostObject;
}
- (HttpdnsHostRecord *)toDBRecord {
// IPIP<EFBFBD><EFBFBD>?
NSArray<NSString *> *v4IpStrings = [self getV4IpStrings];
NSArray<NSString *> *v6IpStrings = [self getV6IpStrings];
// modifyAt
NSDate *currentDate = [NSDate date];
// 使hostNamecacheKeyfromDBRecord<EFBFBD><EFBFBD>?
return [[HttpdnsHostRecord alloc] initWithId:0 // ID
cacheKey:self.cacheKey
hostName:self.hostName
createAt:currentDate
modifyAt:currentDate
clientIp:self.clientIp
v4ips:v4IpStrings
v4ttl:self.v4ttl
v4LookupTime:self.lastIPv4LookupTime
v6ips:v6IpStrings
v6ttl:self.v6ttl
v6LookupTime:self.lastIPv6LookupTime
extra:self.extra];
}
- (NSArray<NSString *> *)getV4IpStrings {
NSArray<HttpdnsIpObject *> *ipv4Records = [self getV4Ips];
NSMutableArray<NSString *> *ipv4Strings = [NSMutableArray arrayWithCapacity:ipv4Records.count];
for (HttpdnsIpObject *IPObject in ipv4Records) {
[ipv4Strings addObject:[IPObject getIpString]];
}
return [ipv4Strings copy];
}
- (NSArray<NSString *> *)getV6IpStrings {
NSArray<HttpdnsIpObject *> *ipv6Records = [self getV6Ips];
NSMutableArray<NSString *> *ipv6sString = [NSMutableArray arrayWithCapacity:ipv6Records.count];
for (HttpdnsIpObject *ipObject in ipv6Records) {
[ipv6sString addObject:[ipObject getIpString]];
}
return [ipv6sString copy];
}
- (void)updateConnectedRT:(NSInteger)connectedRT forIP:(NSString *)ip {
if ([HttpdnsUtil isEmptyString:ip]) {
return;
}
BOOL isIPv6 = [HttpdnsUtil isIPv6Address:ip];
NSArray<HttpdnsIpObject *> *ipObjects = isIPv6 ? [self getV6Ips] : [self getV4Ips];
if ([HttpdnsUtil isEmptyArray:ipObjects]) {
return;
}
// IPconnectedRT
BOOL found = NO;
NSMutableArray<HttpdnsIpObject *> *mutableIpObjects = [ipObjects mutableCopy];
for (HttpdnsIpObject *ipObject in ipObjects) {
if ([ipObject.ip isEqualToString:ip]) {
ipObject.connectedRT = connectedRT;
found = YES;
break;
}
}
if (!found) {
return;
}
// connectedRTIP<EFBFBD><EFBFBD>?1<EFBFBD><EFBFBD>?
[mutableIpObjects sortUsingComparator:^NSComparisonResult(HttpdnsIpObject *obj1, HttpdnsIpObject *obj2) {
// obj1connectedRT<EFBFBD><EFBFBD>?1<EFBFBD><EFBFBD>?
if (obj1.connectedRT == -1) {
return NSOrderedDescending;
}
// obj2connectedRT<EFBFBD><EFBFBD>?1<EFBFBD><EFBFBD>?
if (obj2.connectedRT == -1) {
return NSOrderedAscending;
}
// connectedRT<EFBFBD><EFBFBD>?
return obj1.connectedRT > obj2.connectedRT ? NSOrderedDescending : (obj1.connectedRT < obj2.connectedRT ? NSOrderedAscending : NSOrderedSame);
}];
// IP
if (isIPv6) {
[self setV6Ips:[mutableIpObjects copy]];
} else {
[self setV4Ips:[mutableIpObjects copy]];
}
}
- (NSString *)description {
if (![HttpdnsUtil isNotEmptyArray:_v6Ips]) {
return [NSString stringWithFormat:@"Host = %@ v4ips = %@ v4ttl = %lld v4LastLookup = %lld extra = %@",
_hostName, _v4Ips, _v4ttl, _lastIPv4LookupTime, _extra];
} else {
return [NSString stringWithFormat:@"Host = %@ v4ips = %@ v4ttl = %lld v4LastLookup = %lld v6ips = %@ v6ttl = %lld v6LastLookup = %lld extra = %@",
_hostName, _v4Ips, _v4ttl, _lastIPv4LookupTime, _v6Ips, _v6ttl, _lastIPv6LookupTime, _extra];
}
}
@end

View File

@@ -0,0 +1,53 @@
//
// HttpdnsHostRecord.h
// TrustHttpDNS
//
// Created by ElonChan地风 on 2017/5/3.
// Copyright © 2017<31><37>?trustapp.com. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface HttpdnsHostRecord : NSObject
@property (nonatomic, assign, readonly) NSUInteger id;
@property (nonatomic, copy, readonly) NSString *cacheKey;
@property (nonatomic, copy, readonly) NSString *hostName;
@property (nonatomic, strong, readonly) NSDate *createAt;
@property (nonatomic, strong, readonly) NSDate *modifyAt;
@property (nonatomic, copy, readonly) NSString *clientIp;
@property (nonatomic, copy, readonly) NSArray<NSString *> *v4ips;
@property (nonatomic, assign, readonly) int64_t v4ttl;
@property (nonatomic, assign, readonly) int64_t v4LookupTime;
@property (nonatomic, copy, readonly) NSArray<NSString *> *v6ips;
@property (nonatomic, assign, readonly) int64_t v6ttl;
@property (nonatomic, assign, readonly) int64_t v6LookupTime;
@property (nonatomic, copy, readonly) NSString *extra;
- (instancetype)initWithId:(NSUInteger)id
cacheKey:(NSString *)cacheKey
hostName:(NSString *)hostName
createAt:(NSDate *)createAt
modifyAt:(NSDate *)modifyAt
clientIp:(NSString *)clientIp
v4ips:(NSArray<NSString *> *)v4ips
v4ttl:(int64_t)v4ttl
v4LookupTime:(int64_t)v4LookupTime
v6ips:(NSArray<NSString *> *)v6ips
v6ttl:(int64_t)v6ttl
v6LookupTime:(int64_t)v6LookupTime
extra:(NSString *)extra;
@end

View File

@@ -0,0 +1,91 @@
//
// HttpdnsHostRecord.m
// TrustHttpDNS
//
// Created by ElonChan on 2017/5/3.
// Copyright © 2017<EFBFBD><EFBFBD>?trustapp.com. All rights reserved.
//
#import "HttpdnsHostRecord.h"
#import "HttpdnsUtil.h"
@interface HttpdnsHostRecord()
@property (nonatomic, assign) NSUInteger id;
@property (nonatomic, copy) NSString *cacheKey;
@property (nonatomic, copy) NSString *hostName;
@property (nonatomic, strong) NSDate *createAt;
@property (nonatomic, strong) NSDate *modifyAt;
@property (nonatomic, copy) NSString *clientIp;
@property (nonatomic, copy) NSArray<NSString *> *v4ips;
@property (nonatomic, assign) int64_t v4ttl;
@property (nonatomic, assign) int64_t v4LookupTime;
@property (nonatomic, copy) NSArray<NSString *> *v6ips;
@property (nonatomic, assign) int64_t v6ttl;
@property (nonatomic, assign) int64_t v6LookupTime;
@property (nonatomic, copy) NSString *extra;
@end
@implementation HttpdnsHostRecord
- (instancetype)initWithId:(NSUInteger)id
cacheKey:(NSString *)cacheKey
hostName:(NSString *)hostName
createAt:(NSDate *)createAt
modifyAt:(NSDate *)modifyAt
clientIp:(NSString *)clientIp
v4ips:(NSArray<NSString *> *)v4ips
v4ttl:(int64_t)v4ttl
v4LookupTime:(int64_t)v4LookupTime
v6ips:(NSArray<NSString *> *)v6ips
v6ttl:(int64_t)v6ttl
v6LookupTime:(int64_t)v6LookupTime
extra:(NSString *)extra {
self = [super init];
if (self) {
_id = id;
_cacheKey = [cacheKey copy];
_hostName = [hostName copy];
_createAt = createAt;
_modifyAt = modifyAt;
_clientIp = [clientIp copy];
_v4ips = [v4ips copy] ?: @[];
_v4ttl = v4ttl;
_v4LookupTime = v4LookupTime;
_v6ips = [v6ips copy] ?: @[];
_v6ttl = v6ttl;
_v6LookupTime = v6LookupTime;
_extra = [extra copy];
}
return self;
}
- (NSString *)description {
NSString *hostName = self.hostName;
if (self.cacheKey) {
hostName = [NSString stringWithFormat:@"%@(%@)", hostName, self.cacheKey];
}
if ([HttpdnsUtil isEmptyArray:_v6ips]) {
return [NSString stringWithFormat:@"hostName = %@, v4ips = %@, v4ttl = %lld v4LastLookup = %lld extra = %@",
hostName, _v4ips, _v4ttl, _v4LookupTime, _extra];
} else {
return [NSString stringWithFormat:@"hostName = %@, v4ips = %@, v4ttl = %lld v4LastLookup = %lld v6ips = %@ v6ttl = %lld v6LastLookup = %lld extra = %@",
hostName, _v4ips, _v4ttl, _v4LookupTime, _v6ips, _v6ttl, _v6LookupTime, _extra];
}
}
@end

View File

@@ -0,0 +1,64 @@
//
// HttpdnsRequest.h
// TrustHttpDNS
//
// Created by xuyecan on 2024/5/19.
// Copyright © 2024 trustapp.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#ifndef TrustHTTPDNSQUERYIPTYPE
#define TrustHTTPDNSQUERYIPTYPE
typedef enum {
TrustHttpDNS_IPTypeV4 = 0, //ipv4
TrustHttpDNS_IPTypeV6 = 1, //ipv6
TrustHttpDNS_IPTypeV64 = 2, //ipv4 + ipv6
} TrustHttpDNS_IPType;
typedef NS_OPTIONS(NSUInteger, HttpdnsQueryIPType) {
HttpdnsQueryIPTypeAuto NS_SWIFT_NAME(auto) = 0,
HttpdnsQueryIPTypeIpv4 = 1 << 0,
HttpdnsQueryIPTypeIpv6 = 1 << 1,
HttpdnsQueryIPTypeBoth = HttpdnsQueryIPTypeIpv4 | HttpdnsQueryIPTypeIpv6,
};
#endif
@interface HttpdnsRequest : NSObject
/// 需要解析的域名
@property (nonatomic, copy) NSString *host;
/// 解析超时时间对于同步接口即为最大等待时间对于异步接口即为最大等待回调时<E8B083><E697B6>?
/// 默认<E9BB98><E8AEA4>?秒取值必须在0.5<EFBFBD><EFBFBD>?- 5秒之<E7A792><E4B98B>?
@property (nonatomic, assign) double resolveTimeoutInSecond;
/// 查询IP类型
/// 默认为HttpdnsQueryIPTypeAuto此类型下SDK至少会请求解析ipv4地址若判断到当前网络环境支持ipv6则还会请求解析ipv6地址
/// HttpdnsQueryIPTypeIpv4只请求解析ipv4
/// HttpdnsQueryIPTypeIpv6只请求解析ipv6
/// HttpdnsQueryIPTypeBoth不管当前网络环境是什么会尝试同时请求解析ipv4地址和ipv6地址这种用法通常需要拿到结果之后自行判断网络环境决定使用哪个结<E4B8AA><E7BB93>?
@property (nonatomic, assign) HttpdnsQueryIPType queryIpType;
/// SDNS参数针对软件自定义解析场景使用
@property (nonatomic, copy, nullable) NSDictionary<NSString *, NSString *> *sdnsParams;
/// 缓存Key针对软件自定义解析场景使用
@property (nonatomic, copy, nullable) NSString *cacheKey;
/// 请求所属的账号ID用于在多账号场景下定位实例
@property (nonatomic, assign) NSInteger accountId;
- (instancetype)initWithHost:(NSString *)host queryIpType:(HttpdnsQueryIPType)queryIpType;
- (instancetype)initWithHost:(NSString *)host queryIpType:(HttpdnsQueryIPType)queryIpType sdnsParams:(nullable NSDictionary<NSString *, NSString *> *)sdnsParams cacheKey:(nullable NSString *)cacheKey;
- (instancetype)initWithHost:(NSString *)host queryIpType:(HttpdnsQueryIPType)queryIpType sdnsParams:(nullable NSDictionary<NSString *, NSString *> *)sdnsParams cacheKey:(nullable NSString *)cacheKey resolveTimeout:(double)timeoutInSecond;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,76 @@
//
// HttpdnsRequest.m
// TrustHttpDNS
//
// Created by xuyecan on 2024/5/19.
// Copyright © 2024 trustapp.com. All rights reserved.
//
#import "HttpdnsRequest.h"
#import "HttpdnsRequest_Internal.h"
static double const RESOLVE_HOST_DEFAULT_TIMEOUT_IN_SEC = 2;
static double const RESOLVE_HOST_MIN_TIMEOUT_IN_SEC = 0.5;
static double const RESOLVE_HOST_MAX_TIMEOUT_IN_SEC = 5;
@implementation HttpdnsRequest
- (instancetype)initWithHost:(NSString *)host queryIpType:(HttpdnsQueryIPType)queryIpType {
return [self initWithHost:host queryIpType:queryIpType sdnsParams:nil cacheKey:host];
}
- (instancetype)initWithHost:(NSString *)host queryIpType:(HttpdnsQueryIPType)queryIpType sdnsParams:(NSDictionary<NSString *, NSString *> *)sdnsParams cacheKey:(NSString *)cacheKey {
return [self initWithHost:host queryIpType:queryIpType sdnsParams:sdnsParams cacheKey:cacheKey resolveTimeout:RESOLVE_HOST_DEFAULT_TIMEOUT_IN_SEC];
}
- (instancetype)initWithHost:(NSString *)host queryIpType:(HttpdnsQueryIPType)queryIpType sdnsParams:(NSDictionary<NSString *,NSString *> *)sdnsParams cacheKey:(NSString *)cacheKey resolveTimeout:(double)timeoutInSecond {
if (self = [super init]) {
_host = host;
_queryIpType = queryIpType;
_sdnsParams = sdnsParams;
if (cacheKey) {
_cacheKey = cacheKey;
} else {
_cacheKey = host;
}
_resolveTimeoutInSecond = timeoutInSecond;
}
return self;
}
- (instancetype)init {
if (self = [super init]) {
_queryIpType = HttpdnsQueryIPTypeAuto;
_resolveTimeoutInSecond = RESOLVE_HOST_DEFAULT_TIMEOUT_IN_SEC;
}
return self;
}
- (void)becomeBlockingRequest {
_isBlockingRequest = YES;
}
- (void)becomeNonBlockingRequest {
_isBlockingRequest = NO;
}
- (void)ensureResolveTimeoutInReasonableRange {
if (_resolveTimeoutInSecond == 0) {
_resolveTimeoutInSecond = RESOLVE_HOST_DEFAULT_TIMEOUT_IN_SEC;
} else if (_resolveTimeoutInSecond < RESOLVE_HOST_MIN_TIMEOUT_IN_SEC) {
_resolveTimeoutInSecond = RESOLVE_HOST_MIN_TIMEOUT_IN_SEC;
} else if (_resolveTimeoutInSecond > RESOLVE_HOST_MAX_TIMEOUT_IN_SEC) {
_resolveTimeoutInSecond = RESOLVE_HOST_MAX_TIMEOUT_IN_SEC;
} else {
// <EFBFBD><EFBFBD>?
}
}
- (NSString *)description {
return [NSString stringWithFormat:@"Host: %@, isBlockingRequest: %d, queryIpType: %ld, sdnsParams: %@, cacheKey: %@", self.host, self.isBlockingRequest, self.queryIpType, self.sdnsParams, self.cacheKey];
}
@end

View File

@@ -0,0 +1,25 @@
//
// HttpdnsRequest_Internal.h
// TrustHttpDNS
//
// Created by xuyecan on 2024/6/19.
// Copyright © 2024 trustapp.com. All rights reserved.
//
#ifndef HttpdnsRequest_Internal_h
#define HttpdnsRequest_Internal_h
@interface HttpdnsRequest ()
@property (nonatomic, assign) BOOL isBlockingRequest;
- (void)becomeBlockingRequest;
- (void)becomeNonBlockingRequest;
- (void)ensureResolveTimeoutInReasonableRange;
@end
#endif /* HttpdnsRequest_Internal_h */

View File

@@ -0,0 +1,42 @@
//
// HttpdnsResult.h
// TrustHttpDNS
//
// Created by xuyecan on 2024/5/15.
// Copyright © 2024 trustapp.com. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface HttpdnsResult : NSObject
@property (nonatomic, copy) NSString *host;
@property (nonatomic, copy) NSArray<NSString *> *ips;
@property (nonatomic, copy) NSArray<NSString *> *ipv6s;
// 最后一次ipv4地址更新时间戳Unix时间单位秒
@property (nonatomic, assign) NSTimeInterval lastUpdatedTimeInterval;
// 最后一次ipv6地址更新时间戳Unix时间单位秒
@property (nonatomic, assign) NSTimeInterval v6LastUpdatedTimeInterval;
// 对应ipv4的ttl单位秒
@property (nonatomic, assign) NSTimeInterval ttl;
// 对应ipv6的ttl单位秒
@property (nonatomic, assign) NSTimeInterval v6ttl;
- (BOOL)hasIpv4Address;
- (BOOL)hasIpv6Address;
- (nullable NSString *)firstIpv4Address;
- (nullable NSString *)firstIpv6Address;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,53 @@
//
// HttpdnsResult.m
// TrustHttpDNS
//
// Created by xuyecan on 2024/5/15.
// Copyright © 2024 trustapp.com. All rights reserved.
//
#import "HttpdnsResult.h"
@implementation HttpdnsResult
- (BOOL)hasIpv4Address {
return self.ips.count > 0;
}
- (BOOL)hasIpv6Address {
return self.ipv6s.count > 0;
}
- (nullable NSString *)firstIpv4Address {
if (self.ips.count == 0) {
return nil;
}
return self.ips.firstObject;
}
- (nullable NSString *)firstIpv6Address {
if (self.ipv6s.count == 0) {
return nil;
}
return self.ipv6s.firstObject;
}
- (NSString *)description {
NSMutableString *result = [NSMutableString stringWithFormat:@"Host: %@", self.host];
if ([self hasIpv4Address]) {
[result appendFormat:@", ipv4 Addresses: %@", [self.ips componentsJoinedByString:@", "]];
} else {
[result appendString:@", ipv4 Addresses: None"];
}
if ([self hasIpv6Address]) {
[result appendFormat:@", ipv6 Addresses: %@", [self.ipv6s componentsJoinedByString:@", "]];
} else {
[result appendString:@", ipv6 Addresses: None"];
}
return [result copy];
}
@end