La couche de compatibilité Avahi dns_sd ne parvient pas à exécuter le rappel de navigation

StackOverflow https://stackoverflow.com/questions/7391079

Question

Contexte

Je travaille sur une bibliothèque multiplateforme Zeroconf / Bonjour / DNS-SD pour Haskell, et j'ai pensé que mon meilleur pari serait de cibler dns_sd.h API. Sous Linux, l'implémentation de cette interface est fournie par Avahi , qui prétend prendre en charge un sous-ensemble de l'API Bonjour .

Problème

Pour vérifier la cohérence de ma bibliothèque, j'ai écrit un petit programme de test en C qui n'utilise que le strict minimum de l'API. Il recherche n'importe quel service du réseau de type _http._tcp, imprime un message dès qu'il en voit un, puis meurt:

#include <dns_sd.h>
#include <stdio.h>
#include <stdlib.h>

void cb(DNSServiceRef sdRef,
        DNSServiceFlags flags,
        uint32_t interfaceIndex,
        DNSServiceErrorType errorCode,
        const char *serviceName,
        const char *regtype,
        const char *replyDomain,
        void *context) {
  printf("called!\n");
}

int main() {
  DNSServiceRef sd = malloc(sizeof(DNSServiceRef));
  const char *regtype = "_http._tcp";
  DNSServiceErrorType err1 = DNSServiceBrowse(&sd, 0, 0, regtype, NULL, &cb, NULL);
  printf("err1=%d\n", err1);
  DNSServiceErrorType err2 = DNSServiceProcessResult(sd);
  printf("err2=%d\n", err2);
  return 0;
}

Sur mon Mac, ce programme de test fonctionne très bien en C et en Haskell équivalent (il trouve mon imprimante; excitant!):

$ gcc test.c -o test
$ ./test
err1=0
called!
err2=0

Mais sur ma machine Linux, le programme me réprimande avant de quitter sans appeler le callback:

$ gcc test.c -o test -ldns_sd
$ ./test
*** WARNING *** The program 'test' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=test>
err1=0
err2=0

Questions

  1. La couche de compatibilité du dns_sd Avahi est-elle toujours une cible appropriée pour une liaison multiplateforme? Ou est-ce que ce message d'avertissement est suffisamment sérieux concernant l'utilisation de l'API native Avahi pour que je puisse envisager de recibler?
  2. Quel est l'état de l'art de Zeroconf multiplateforme en C?
Était-ce utile?

La solution

Pour une raison inconnue de moi, cela ne fonctionne qu'avec les appels non bloquants.Voici le code amélioré.Le socket d'Avahi est réglé sur un mode non bloquant, puis select (3) est utilisé pour attendre les données disponibles.DNSServiceProcessResult(sd) doit être appelé chaque fois qu'il y a des données sur le socket, donc c'est peut-être par pur hasard que votre exemple a fonctionné sur d'autres plates-formes.

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dns_sd.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

static int set_nonblocking(int fd)
{
    int flags;
    /* If they have O_NONBLOCK, use the Posix way to do it */
#if defined(O_NONBLOCK)
    /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
    if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
        flags = 0;
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
    /* Otherwise, use the old way of doing it */
    flags = 1;
    return ioctl(fd, FIOBIO, &flags);
#endif
}     

void cb(DNSServiceRef sdRef,
        DNSServiceFlags flags,
        uint32_t interfaceIndex,
        DNSServiceErrorType errorCode,
        const char *serviceName,
        const char *regtype,
        const char *replyDomain,
        void *context) {
    printf("called %s %s!\n", serviceName, regtype);
}

int main() {
    DNSServiceRef sd = malloc(sizeof(DNSServiceRef));
    const char *regtype = "_http._tcp";
    DNSServiceErrorType err1 = DNSServiceBrowse(&sd, 0, 0, regtype, NULL, &cb, NULL);
    printf("err1=%d\n", err1);
    int socket = DNSServiceRefSockFD(sd);
    set_nonblocking(socket);

    fd_set read_fds;
    FD_ZERO(&read_fds);
    FD_SET(socket, &read_fds);

    while(1) {
        if(select(socket+1, &read_fds, NULL, NULL, NULL)  < 0) {
            perror("select");  
        }
        DNSServiceErrorType err2 = DNSServiceProcessResult(sd);
        printf("err2=%d\n", err2);
        if(err2 != 0)
            return 2;
    }
    return 0;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top