I was trying to implement FQDN to Address resolution using DNSServiceGetAddrInfo API of DNS_SD. Learning from this thread I wanted to use DNSServiceSetDispatchQueue to get results back asynchronously. Here is how I have implemented it.
var result = DNSServiceGetAddrInfo(&dnsServiceRef, kDNSServiceFlagsTimeout, 0, DNSServiceFlags(kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6), hostName.cString(using: .utf8), dnssd_callback, pointer)
if result != kDNSServiceErr_NoError || dnsServiceRef == nil {
delegate?.didFinishDNSResolution(.failed(.error(from: result)))
stopResolution()
} else {
result = DNSServiceSetDispatchQueue(dnsServiceRef, DispatchQueue.main)
if result != kDNSServiceErr_NoError {
delegate?.didFinishDNSResolution(.failed(.error(from: result)))
stopResolution()
}
}However, using this implementation I do not get callbacks. If I use DNSServiceProcessResult, I am getting responses successfully. If I call DNSServiceProcessResult after DNSServiceSetDispatchQueue, then also I receive callbacks successfully. But, that is discouraged in the documentation of DNSServiceSetDispatchQueue.
> * After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult
* on the same DNSServiceRef will result in undefined behavior and should be avoided.
I tried DNSSDObjects and SRVResolver (with a bit change DNSServiceSetDispatchQueue) samples and they both work pretty fine. But when I use the same in my code, it does not work. So, is it possible that DNSServiceSetDispatchQueue can be used with every DNS_SD API except for DNSServiceGetAddrInfo? Or is there a missing piece?
Any help would be greatly appreciated.
We have a server issue where we need to resolve FQDN and connect with IP address due to session details not being synced.
Be warned, connecting by IP address is likely to cause problems in certain situations (DNS64/NAT64, VPN On Demand, and so on).
Also, what platform are you targeting?
Can we use
API instead ofDNSServiceGetAddrInfoAPI for address resolution?CFHost
Yes.
Which one should be preferred and why?
Both should work equally well. I prefer
CFHost because its API fits in with the platform better (it works just like any of the other bazillion run loop based APIs out there).
Why
does not work withDNSServiceGetAddrInfo?DNSServiceSetDispatchQueue
I’m not sure what you’re doing wrong here. Pasted in at the end of this response is some code that I wrote to do this. When I put that in a test tool project and run it on a Mac here in my office, it prints the following:
will start resolve
did start resolve
did resolve example.com. to 2606:2800:220:1:248:1893:25c8:1946
did resolve example.com. to 93.184.216.34Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"import Foundation
import dnssd
func main() {
print("will start resolve")
var sdRefQ: DNSServiceRef? = nil
let err = DNSServiceGetAddrInfo(&sdRefQ, 0, 0, DNSServiceProtocol(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6), "example.com", { (_, _, _, err, hostnameQ, saQ, _, _) in
guard err == kDNSServiceErr_NoError else {
print("did not resolve, resolve failed, err: \(err)")
return
}
let hostStr = String(cString: hostnameQ!)
let sa = saQ!
var addr = [CChar](repeating: 0, count: Int(NI_MAXHOST))
let err2 = getnameinfo(sa, socklen_t(sa.pointee.sa_len), &addr, socklen_t(addr.count), nil, 0, NI_NUMERICHOST | NI_NUMERICSERV)
guard err2 == 0 else {
print("did not resolve, address-to-string failed, err: \(err)")
return
}
let addrStr = String(cString: addr)
print("did resolve \(hostStr) to \(addrStr)")
}, nil)
guard err == kDNSServiceErr_NoError else {
print(err)
return
}
let sdRef = sdRefQ!
let junk = DNSServiceSetDispatchQueue(sdRef, .main)
assert(junk == kDNSServiceErr_NoError)
print("did start resolve")
dispatchMain()
}
main()
exit(EXIT_SUCCESS)