VPN: Cache DNS resolutions while the app is in memory

This commit is contained in:
Roopesh Chander 2018-10-29 05:55:48 +05:30
parent 8d3b616fa8
commit 5b85d58b27

View File

@ -8,6 +8,7 @@ class DNSResolver {
let endpoints: [Endpoint?] let endpoints: [Endpoint?]
let dispatchGroup: DispatchGroup let dispatchGroup: DispatchGroup
var dispatchWorkItems: [DispatchWorkItem] var dispatchWorkItems: [DispatchWorkItem]
static var cache = NSCache<NSString, NSString>()
init(endpoints: [Endpoint?]) { init(endpoints: [Endpoint?]) {
self.endpoints = endpoints self.endpoints = endpoints
@ -20,16 +21,31 @@ class DNSResolver {
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)
let numberOfEndpointsToResolve = endpoints.compactMap { $0 }.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() {
guard let endpoint = endpoint else { return } guard let endpoint = endpoint else { continue }
let workItem = DispatchWorkItem { if let resolvedEndpointStringInCache = DNSResolver.cache.object(forKey: endpoint.stringRepresentation() as NSString),
resolvedEndpoints[i] = DNSResolver.resolveSync(endpoint: endpoint) let resolvedEndpointInCache = Endpoint(from: resolvedEndpointStringInCache as String) {
resolvedEndpoints[i] = resolvedEndpointInCache
} else {
let workItem = DispatchWorkItem {
resolvedEndpoints[i] = DNSResolver.resolveSync(endpoint: endpoint)
isResolvedByDNSRequest[i] = true
}
dispatchWorkItems.append(workItem)
DispatchQueue.global(qos: .userInitiated).async(group: dispatchGroup, execute: workItem)
} }
dispatchWorkItems.append(workItem)
DispatchQueue.global(qos: .userInitiated).async(group: dispatchGroup, execute: workItem)
} }
dispatchGroup.notify(queue: .main) { dispatchGroup.notify(queue: .main) {
assert(endpoints.count == resolvedEndpoints.count)
for (i, endpoint) in endpoints.enumerated() {
guard let endpoint = endpoint, let resolvedEndpoint = resolvedEndpoints[i] else { return }
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 let numberOfResolvedEndpoints = resolvedEndpoints.compactMap { $0 }.count
if (numberOfResolvedEndpoints < numberOfEndpointsToResolve) { if (numberOfResolvedEndpoints < numberOfEndpointsToResolve) {
completionHandler(nil) completionHandler(nil)