DNSServiceProcessResult(), GCD, and bogus DNS

DNSServiceProcessResult() is a synchronous call that blocks, so I thought "Hey, I'll use GCD to address that problem". What I came up after some experimentation was:


static void callBack(
  DNSServiceRef  sdRef,
  ...
{
  NSLog(@"Callback!");
  if(theErrorCode == kDNSServiceErr_NoError) {
  // if no error,stop updating
  DNSServiceRefDeallocate(sdRef);
  }
}
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
  DNSServiceRef sdRef;
  DNSServiceQueryRecord(&sdRef, 0, 0, [domain UTF8String], kDNSServiceType_MX, kDNSServiceClass_IN, callBack, NULL);
  DNSServiceErrorType theErrorCode = DNSServiceProcessResult(sdRef);
  if(theErrorCode != kDNSServiceErr_NoError) {
  // there was an error so the callback never did the dealloc
  DNSServiceRefDeallocate(sdRef);
  }
});


The above code appears to work fine for the "no-error" case. When I give it a made up name, like "foo.foobar", it hangs for a long time - like forever!


So then I thought "I'll just verify the domain first" - so I used gethostbyname2() to do it. But then I found that my ISP (and probably a lot of others) use this DNS hijacking service called "BAREFOOT" in the EU. When a DNS entry isn't found (for real) you get told that BAREFOOT is the address and you get routed there! Yikes!


So - how do I do this? Verify that a domain really exists, then see if it has a MX record, and on a background thread?

Accepted Reply

DNSServiceProcessResult
is a synchronous call that blocks …

That’s not how it’s meant to be used. Rather, you’re expected to call

DNSServiceRefSockFD
and then call
DNSServiceProcessResult
when there’s data waiting on the socket. Better yet, if you’re already in GCD land, use
DNSServiceSetDispatchQueue
. The DNSSDObjects sample code shows that approach.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

DNSServiceProcessResult
is a synchronous call that blocks …

That’s not how it’s meant to be used. Rather, you’re expected to call

DNSServiceRefSockFD
and then call
DNSServiceProcessResult
when there’s data waiting on the socket. Better yet, if you’re already in GCD land, use
DNSServiceSetDispatchQueue
. The DNSSDObjects sample code shows that approach.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Just a clarification on DNSServiceSetDispatchQueue. I'm initializing the sdRef with DNSServiceQueryRecord, then using DNSServiceSetDispatchQueue. Its working fine, and I just have one last question: is it save to call DNSServiceRefDeallocate(sdRef) on the main thread at any arbitrary time (for instance, my class is getting deallocated prior to gettting a response)?


Also, is there Swift code anywhere for DNSServiceQueryRecord, DNSServiceSetDispatchQueue, and the callback? Is it even possible?


Thanks!



Comments to anyone else reading this thread:


1) in the callback, if you get a no error, you can stop the callback using this code in the callback method:


  if(theErrorCode == kDNSServiceErr_NoError) {
    DNSServiceRefDeallocate(sdRef);
  }


2) Add this flag as the second argument to get a callback after 30 seconds or so (Simulator): kDNSServiceFlagsTimeout