DNSResolver: DNS resolution can now happen synchronously

Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
Roopesh Chander 2018-11-08 16:25:05 +05:30
parent 4404bb2b7d
commit 651ffa0c51
1 changed files with 23 additions and 18 deletions

View File

@ -4,6 +4,10 @@
import Network import Network
import Foundation import Foundation
enum DNSResolverError: Error {
case dnsResolutionFailed(hostnames: [String])
}
class DNSResolver { class DNSResolver {
let endpoints: [Endpoint?] let endpoints: [Endpoint?]
let dispatchGroup: DispatchGroup let dispatchGroup: DispatchGroup
@ -32,10 +36,11 @@ class DNSResolver {
return resolvedEndpoints return resolvedEndpoints
} }
func resolve(completionHandler: @escaping ([Endpoint?]?) -> Void) { func resolveSync() throws -> [Endpoint?] {
let endpoints = self.endpoints let endpoints = self.endpoints
let dispatchGroup = self.dispatchGroup let dispatchGroup = self.dispatchGroup
dispatchWorkItems = [] dispatchWorkItems = []
var resolvedEndpoints: [Endpoint?] = Array<Endpoint?>(repeating: nil, count: endpoints.count) var resolvedEndpoints: [Endpoint?] = Array<Endpoint?>(repeating: nil, count: endpoints.count)
var isResolvedByDNSRequest: [Bool] = Array<Bool>(repeating: false, count: endpoints.count) var isResolvedByDNSRequest: [Bool] = Array<Bool>(repeating: false, count: endpoints.count)
for (i, endpoint) in self.endpoints.enumerated() { for (i, endpoint) in self.endpoints.enumerated() {
@ -54,26 +59,26 @@ class DNSResolver {
DispatchQueue.global(qos: .userInitiated).async(group: dispatchGroup, execute: workItem) DispatchQueue.global(qos: .userInitiated).async(group: dispatchGroup, execute: workItem)
} }
} }
dispatchGroup.notify(queue: .main) {
assert(endpoints.count == resolvedEndpoints.count) dispatchGroup.wait() // TODO: Timeout?
for (i, endpoint) in endpoints.enumerated() {
guard let endpoint = endpoint, let resolvedEndpoint = resolvedEndpoints[i] else { var hostnamesWithDnsResolutionFailure: [String] = []
completionHandler(nil) assert(endpoints.count == resolvedEndpoints.count)
return for tuple in zip(endpoints, resolvedEndpoints) {
let endpoint = tuple.0
let resolvedEndpoint = tuple.1
if let endpoint = endpoint {
if (resolvedEndpoint == nil) {
// DNS resolution failed
guard let hostname = endpoint.hostname() else { fatalError() }
hostnamesWithDnsResolutionFailure.append(hostname)
} }
if (isResolvedByDNSRequest[i]) {
DNSResolver.cache.setObject(resolvedEndpoint.stringRepresentation() as NSString,
forKey: endpoint.stringRepresentation() as NSString)
}
}
let numberOfEndpointsToResolve = endpoints.compactMap { $0 }.count
let numberOfResolvedEndpoints = resolvedEndpoints.compactMap { $0 }.count
if (numberOfResolvedEndpoints < numberOfEndpointsToResolve) {
completionHandler(nil)
} else {
completionHandler(resolvedEndpoints)
} }
} }
if (!hostnamesWithDnsResolutionFailure.isEmpty) {
throw DNSResolverError.dnsResolutionFailed(hostnames: hostnamesWithDnsResolutionFailure)
}
return resolvedEndpoints
} }
func cancel() { func cancel() {