123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- //
- // OSSHttpdns.m
- // AliyunOSSiOS
- //
- // Created by zhouzhuo on 5/1/16.
- // Copyright © 2016 zhouzhuo. All rights reserved.
- //
- #import "OSSLog.h"
- #import "OSSHttpdns.h"
- #import "OSSIPv6Adapter.h"
- NSString * const OSS_HTTPDNS_SERVER_IP = @"203.107.1.1";
- NSString * const OSS_HTTPDNS_SERVER_PORT = @"80";
- NSString * const ACCOUNT_ID = @"181345";
- NSTimeInterval const MAX_ENDURABLE_EXPIRED_TIME_IN_SECOND = 60; // The DNS entry's expiration time in seconds. After it expires, the entry is invalid.
- NSTimeInterval const PRERESOLVE_IN_ADVANCE_IN_SECOND = 10; // Once the remaining valid time of an DNS entry is less than this number, issue a DNS request to prefetch the data.
- @interface IpObject : NSObject
- @property (nonatomic, copy) NSString * ip;
- @property (nonatomic, assign) NSTimeInterval expiredTime;
- @end
- @implementation IpObject
- @end
- @implementation OSSHttpdns {
- NSMutableDictionary * gHostIpMap;
- NSMutableSet * penddingSet;
- }
- + (instancetype)sharedInstance {
- static OSSHttpdns * sharedInstance = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- sharedInstance = [OSSHttpdns new];
- });
- return sharedInstance;
- }
- - (instancetype)init {
- if (self = [super init]) {
- gHostIpMap = [NSMutableDictionary new];
- penddingSet = [NSMutableSet new];
- }
- return self;
- }
- /**
- * OSS SDK specific
- *
- * @param host it needs strictly follow the domain's format, such as oss-cn-hangzhou.aliyuncs.com
- *
- * @return an ip in the ip list of the resolved host.
- */
- - (NSString *)asynGetIpByHost:(NSString *)host {
- IpObject * ipObject = [gHostIpMap objectForKey:host];
- if (!ipObject) {
- // if the host is not resolved, asynchronously resolve it and return nil
- [self resolveHost:host];
- return nil;
- } else if ([[NSDate date] timeIntervalSince1970] - ipObject.expiredTime > MAX_ENDURABLE_EXPIRED_TIME_IN_SECOND) {
- // If the entry is expired, asynchronously resolve it and return nil.
- [self resolveHost:host];
- return nil;
- } else if (ipObject.expiredTime -[[NSDate date] timeIntervalSince1970] < PRERESOLVE_IN_ADVANCE_IN_SECOND) {
- // If the entry is about to expire, asynchronously resolve it and return the current value.
- [self resolveHost:host];
- return ipObject.ip;
- } else {
- // returns the current result.
- return ipObject.ip;
- }
- }
- /**
- * resolve the host asynchronously
- * If the host is being resolved, the call will be skipped.
- *
- * @param host the host to resolve
- */
- - (void)resolveHost:(NSString *)host {
- @synchronized (self) {
- if ([penddingSet containsObject:host]) {
- return;
- } else {
- [penddingSet addObject:host];
- }
- }
- NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/%@/d?host=%@", [[OSSIPv6Adapter getInstance] handleIpv4Address:OSS_HTTPDNS_SERVER_IP], ACCOUNT_ID, host]];
- NSURLSession * session = [NSURLSession sharedSession];
- NSURLSessionDataTask * dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
- IpObject * ipObject = nil;
- NSUInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
- if (statusCode != 200) {
- OSSLogError(@"Httpdns resolve host: %@ failed, responseCode: %lu", host, (unsigned long)statusCode);
- } else {
- NSError *error = nil;
- NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
- NSTimeInterval expiredTime = [[NSDate new] timeIntervalSince1970] + [[json objectForKey:@"ttl"] longLongValue];
- NSArray *ips = [json objectForKey:@"ips"];
- if (ips == nil || [ips count] == 0) {
- OSSLogError(@"Httpdns resolve host: %@ failed, ip list empty.", host);
- } else {
- NSString * ip = ips[0];
- ipObject = [IpObject new];
- ipObject.expiredTime = expiredTime;
- ipObject.ip = ip;
- OSSLogDebug(@"Httpdns resolve host: %@ success, ip: %@, expiredTime: %lf", host, ipObject.ip, ipObject.expiredTime);
- }
- }
- @synchronized (self) {
- if (ipObject) {
- gHostIpMap[host] = ipObject;
- }
- [penddingSet removeObject:host];
- }
- }];
- [dataTask resume];
- }
- @end
|