2014-03-19 2 views
6

iOS SDK를 사용하여 DNS SRV 레코드를 해결하고 싶습니다.iOS SDK를 사용하여 SRV 레코드 해결

저는 Apple이 제공하는 고급 Bonjour API를 이미 시도했지만, 필요한 것은 아닙니다. 이제 DNS SD를 사용하고 있습니다.

는 (예 : _xmpp-server._tcp.gmail.com)에만 올바른 SRV 레코드를수록이 한 일
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; 
} 

하지만 기록이 잘못 입력 된 경우는, DNSServiceProcessResult (SDREF)는 무한 루프로 간다 .

DNSServiceProcessResult를 중지 할 방법이 있습니까? 이어야합니다.이 스레드를 호출하는 스레드를 취소 하시겠습니까?

답변

5

good old select()을 사용하십시오. 이것은 내가 지금 무엇을 가지고 : 나는 RR 구문 분석을 가지고있는

- (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 the Apple SRVResolver sample.

이 Apple 샘플은 영원히 차단 될 수 있다고 언급했지만 이상한 점은 시간 제한을 직접 추가하려고 시도 할 때 NSTimer을 사용하는 것이 좋습니다. 하지만 select()을 사용하는 것이 훨씬 더 좋은 방법이라고 생각합니다.

해야 할 일이 있습니다. 구현 flushing cache with DNSServiceReconfirmRecord. 그러나 지금은 그렇게하지 않을 것입니다.

이 코드는 작동하지만 아직 테스트 중입니다.

libresolv.dylib을 Xcode 프로젝트의 '링크 된 프레임 워크 및 라이브러리'에 추가해야합니다.

+1

나를 위해 작동합니다. – ssk

+0

작동합니다. 유일한 것은 'dnsHost'가 아니라 해당 서비스의 전체 이름을 사용해야한다는 것입니다. 예를 들어, SIP SRV 레코드의 경우 '_sips._tcp'.yourdomain.com – malex

관련 문제