VPN: DNSResolver: Resolve multiple endpoints in parallel

Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
Roopesh Chander 2018-10-28 15:34:07 +05:30
parent dfbdcf3c28
commit 493166bd70
1 changed files with 32 additions and 21 deletions

View File

@ -6,40 +6,51 @@ import Foundation
class DNSResolver { class DNSResolver {
let endpoints: [Endpoint?] let endpoints: [Endpoint?]
let dispatchGroup: DispatchGroup
var dispatchWorkItems: [DispatchWorkItem]
init(endpoints: [Endpoint?]) { init(endpoints: [Endpoint?]) {
self.endpoints = endpoints self.endpoints = endpoints
self.dispatchWorkItems = []
self.dispatchGroup = DispatchGroup()
} }
func resolve(completionHandler: @escaping ([Endpoint?]?) -> Void) { func resolve(completionHandler: @escaping ([Endpoint?]?) -> Void) {
let endpoints = self.endpoints let endpoints = self.endpoints
DispatchQueue.global(qos: .userInitiated).async { let dispatchGroup = self.dispatchGroup
var resolvedEndpoints: [Endpoint?] = [] dispatchWorkItems = []
var isError = false var resolvedEndpoints: [Endpoint?] = Array<Endpoint?>(repeating: nil, count: endpoints.count)
for endpoint in endpoints { let numberOfEndpointsToResolve = endpoints.compactMap { $0 }.count
if let endpoint = endpoint { for (i, endpoint) in self.endpoints.enumerated() {
if let resolvedEndpoint = DNSResolver.resolveSync(endpoint: endpoint) { guard let endpoint = endpoint else { return }
resolvedEndpoints.append(resolvedEndpoint) let workItem = DispatchWorkItem {
} else { resolvedEndpoints[i] = DNSResolver.resolveSync(endpoint: endpoint)
isError = true
break
} }
} else { dispatchWorkItems.append(workItem)
resolvedEndpoints.append(nil) DispatchQueue.global(qos: .userInitiated).async(group: dispatchGroup, execute: workItem)
} }
} dispatchGroup.notify(queue: .main) {
if (isError) { let numberOfResolvedEndpoints = resolvedEndpoints.compactMap { $0 }.count
DispatchQueue.main.async { if (numberOfResolvedEndpoints < numberOfEndpointsToResolve) {
completionHandler(nil) completionHandler(nil)
} } else {
return
}
DispatchQueue.main.async {
completionHandler(resolvedEndpoints) completionHandler(resolvedEndpoints)
} }
} }
} }
func cancel() {
for workItem in dispatchWorkItems {
workItem.cancel()
}
}
deinit {
cancel()
}
}
extension DNSResolver {
// Based on DNS resolution code by Jason Donenfeld <jason@zx2c4.com> // Based on DNS resolution code by Jason Donenfeld <jason@zx2c4.com>
// in parse_endpoint() in src/tools/config.c in the WireGuard codebase // in parse_endpoint() in src/tools/config.c in the WireGuard codebase
private static func resolveSync(endpoint: Endpoint) -> Endpoint? { private static func resolveSync(endpoint: Endpoint) -> Endpoint? {