Resolution SRV Records with iOS SDK

I want to allow DNS SRV records using the iOS SDK.

I have already tried the high-level Bonjour APIs that Apple provides, but they are not what I need. Now I am using DNS SD.

void *processQueryForSRVRecord(void *record) { DNSServiceRef sdRef; int context; printf("Setting up query for record: %s\n", record); DNSServiceQueryRecord(&sdRef, 0, 0, record, kDNSServiceType_SRV, kDNSServiceClass_IN, callback, &context); printf("Processing query for record: %s\n", record); DNSServiceProcessResult(sdRef); printf("Deallocating query for record: %s\n", record); DNSServiceRefDeallocate(sdRef); return NULL; } 

This works as long as it receives only the correct SRV records (for example: _xmpp-server._tcp.gmail.com), but when the record is erroneous, DNSServiceProcessResult (sdRef) goes into an infinite loop.

Is there a way to stop DNSServiceProcessResult or must I cancel the thread calling it?

+6
source share
1 answer

Use the good old select() . This is what I have at the moment:

 - (void)updateDnsRecords { if (self.dnsUpdatePending == YES) { return; } else { self.dnsUpdatePending = YES; } NSLog(@"DNS update"); DNSServiceRef sdRef; DNSServiceErrorType err; const char* host = [self.dnsHost UTF8String]; if (host != NULL) { NSTimeInterval remainingTime = self.dnsUpdateTimeout; NSDate* startTime = [NSDate date]; err = DNSServiceQueryRecord(&sdRef, 0, 0, host, kDNSServiceType_SRV, kDNSServiceClass_IN, processDnsReply, &remainingTime); // This is necessary so we don't hang forever if there are no results int dns_sd_fd = DNSServiceRefSockFD(sdRef); int nfds = dns_sd_fd + 1; fd_set readfds; int result; while (remainingTime > 0) { FD_ZERO(&readfds); FD_SET(dns_sd_fd, &readfds); struct timeval tv; tv.tv_sec = (time_t)remainingTime; tv.tv_usec = (remainingTime - tv.tv_sec) * 1000000; result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv); if (result == 1) { if (FD_ISSET(dns_sd_fd, &readfds)) { err = DNSServiceProcessResult(sdRef); if (err != kDNSServiceErr_NoError) { NSLog(@"There was an error reading the DNS SRV records."); break; } } } else if (result == 0) { NBLog(@"DNS SRV select() timed out"); break; } else { if (errno == EINTR) { NBLog(@"DNS SRV select() interrupted, retry."); } else { NBLog(@"DNS SRV select() returned %d errno %d %s.", result, errno, strerror(errno)); break; } } NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:startTime]; remainingTime -= elapsed; } DNSServiceRefDeallocate(sdRef); } } static void processDnsReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char* fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void* rdata, uint32_t ttl, void* context) { NSTimeInterval* remainingTime = (NSTimeInterval*)context; // If a timeout occurs the value of the errorCode argument will be // kDNSServiceErr_Timeout. if (errorCode != kDNSServiceErr_NoError) { return; } // The flags argument will have the kDNSServiceFlagsAdd bit set if the // callback is being invoked when a record is received in response to // the query. // // If kDNSServiceFlagsAdd bit is clear then callback is being invoked // because the record has expired, in which case the ttl argument will // be 0. if ((flags & kDNSServiceFlagsMoreComing) == 0) { *remainingTime = 0; } // Record parsing code below was copied from Apple SRVResolver sample. NSMutableData * rrData = [NSMutableData data]; dns_resource_record_t * rr; uint8_t u8; uint16_t u16; uint32_t u32; u8 = 0; [rrData appendBytes:&u8 length:sizeof(u8)]; u16 = htons(kDNSServiceType_SRV); [rrData appendBytes:&u16 length:sizeof(u16)]; u16 = htons(kDNSServiceClass_IN); [rrData appendBytes:&u16 length:sizeof(u16)]; u32 = htonl(666); [rrData appendBytes:&u32 length:sizeof(u32)]; u16 = htons(rdlen); [rrData appendBytes:&u16 length:sizeof(u16)]; [rrData appendBytes:rdata length:rdlen]; rr = dns_parse_resource_record([rrData bytes], (uint32_t) [rrData length]); // If the parse is successful, add the results. if (rr != NULL) { NSString *target; target = [NSString stringWithCString:rr->data.SRV->target encoding:NSASCIIStringEncoding]; if (target != nil) { uint16_t priority = rr->data.SRV->priority; uint16_t weight = rr->data.SRV->weight; uint16_t port = rr->data.SRV->port; [[FailoverWebInterface sharedInterface] addDnsServer:target priority:priority weight:weight port:port ttl:ttl]; // You'll have to do this in with your own method. } } dns_free_resource_record(rr); } 

Here's an Apple SRVResolver sample from which I got RR parsing.

In this example, Apple mentions that it can block forever, but, oddly enough, we recommend using NSTimer when trying to add a timeout on your own. But I think using select() much better.

I have one task: Deploy the clearing cache using DNSServiceReconfirmRecord . But now this will not happen.

Know this code works, but I'm still testing it.

You need to add libresolv.dylib to the Xcode project “Related Structures and Libraries”.

+5
source

All Articles