Есть ли способ сделать отдельные запросы DNS для IPv4 и IPv6 в Swift или ObjC

То, что я до сих пор это:

void startQueryIPv4(const char *hostName){
printf("startQueryIPv4");
DNSServiceRef serviceRef;
DNSServiceGetAddrInfo(&serviceRef, kDNSServiceFlagsForceMulticast, 0, kDNSServiceProtocol_IPv4, hostName, queryIPv4Callback, NULL);
DNSServiceProcessResult(serviceRef);
DNSServiceRefDeallocate(serviceRef);
}


static void queryIPv4Callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context){
printf("queryIPv4Callback");

if (errorCode == kDNSServiceErr_NoError) {

    printf("no error");
    char *theAddress = NULL;

    switch(address->sa_family) {
        case AF_INET: {
            struct sockaddr_in *addr_in = (struct sockaddr_in *)address;
            theAddress = malloc(INET_ADDRSTRLEN);
            inet_ntop(AF_INET, &(addr_in->sin_addr), theAddress, INET_ADDRSTRLEN);
            break;
        }
        case AF_INET6: {
            struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)address;
            theAddress = malloc(INET6_ADDRSTRLEN);
            inet_ntop(AF_INET6, &(addr_in6->sin6_addr), theAddress, INET6_ADDRSTRLEN);
            break;
        }
        default:
            break;
    }
    printf("IP address: %s\n", theAddress);
    free(theAddress);

} else {
    printf("%d", errorCode);
}

}

Но обратный вызов никогда не вызывается. В консоли я получаю эту ошибку: TIC Read Status [9:0x0]: 1:57 ObjectiveC - не моя сила, но мне пришлось с ней связываться. Любая помощь будет оценена.

2 ответа

Решение

Поскольку Objective-C является истинным надмножеством C и Darwin сертифицирован как совместимый с SUS 3, ваша программа Objective-C для iOS должна иметь возможность использовать интерфейс C для распознавателя имен системы: getaddrinfo(), Вы можете использовать третий аргумент этой функции, чтобы указать, что вам нужны только результаты IPv4 (или только результаты IPv6).

Вещи, о которых вы должны знать:

  • это, конечно, синхронный интерфейс; если вы хотите асинхронный, вы должны сами это организовать.

  • getaddrinfo() выделяет и возвращает связанный список адресов, поэтому

    • в принципе вам может понадобиться проверить более одного

    • вам нужно освободить список после того, как вы закончите с ним через freeaddrinfo()

Причина, по которой вы не получаете обратный вызов, заключается в том, что вы не используете очередь отправки. API DNSServiceGetAddrInfo является асинхронным. Если вы делаете это на устройстве Apple, вам нужно что-то вроде этого:

      void startQueryIPv4(const char *hostName) {
  printf("startQueryIPv4");
  DNSServiceRef serviceRef;
  DNSServiceGetAddrInfo(&serviceRef, kDNSServiceFlagsForceMulticast, 0, kDNSServiceProtocol_IPv4, hostName, queryIPv4Callback, NULL);
  main_queue = dispatch_get_main_queue();
  DNSServiceSetDispatchQueue(sdref, main_queue);
  dispatch_main();
}

Обратите внимание, что dispatch_main() является основным циклом событий для libdispatch: если вы хотите сделать что-то другое, вам нужно запланировать его в цикле отправки, потому что dispatch_main() не вернется.

В исходном коде вы вызвали DNSServiceRefDeallocate(), но вы не можете сделать это, пока не захотите остановить запрос. Если вы вызовете его сразу после запуска запроса, он отменит запрос. Так, например, вы можете вызвать его из обратного вызова.

Однако лучше было бы выполнить долгоживущий запрос (kDNSServiceFlagsLongLivedQuery), чтобы вы получали обновление при изменении информации. Конечно, затем вам нужно будет изменить хост, к которому вы подключаетесь, поэтому делайте это только в том случае, если ваше приложение будет подключено в течение длительного периода.

Кроме того, вы можете получить более одного ответа. Если вы это сделаете, возможно, одни ответы работают, а другие нет. Так что вам, возможно, захочется собрать ответы и попробовать каждый из них, вместо того, чтобы сдаваться, если первый полученный ответ не сработает. Обратный вызов будет включать флаг kDNSServiceFlagsMoreComing, если немедленно поступят дополнительные данные. Каждый раз, когда вызывается обратный вызов, он получает один ответ (или указание на то, что запрос каким-то образом не удался).

Конечно, это довольно низкоуровневый API. Если вы хотите немного облегчить себе жизнь, вам следует использовать Network Framework. Network Framework делает за вас часть «счастливых глаз» - проверяет каждый ответ до тех пор, пока не получит соединение, и возвращает вам полученное соединение, отменяя остальные.

Но вы не спрашивали об этом, поэтому я не буду здесь вдаваться в подробности.

Другие вопросы по тегам