[avahi] asynchronous resolving causes segfault

Jared Albers jalbers at mymail.mines.edu
Mon Jun 11 19:45:37 PDT 2012


I am using a ZeroconfResolver object that encapsulates an AvahiClient,
AvahiSimplePoll, and AvahiServiceResolver. The ZeroconfResolver has a
Resolve function that first instantiates the AvahiSimplePoll, then
AvahiClient, and finally the AvahiServiceResolver. At each
instantiation I am checking for errors before continuing to the next.
After the AvahiServiceResolver has been successfully created it calls
avahi_simple_poll_loop with the AvahiSimplePoll.

This whole process works great when done synchronously but fails with
segfaults when multiple ZeroconfResolvers are being used at the same
time asynchronously (i.e I have multiple threads creating their own
ZeroconfResolver objects). A trivial adaptation of the object that
reproduces the segfaults can be seen at [2] (may not produce a
segfault right away, but in my use case it happens frequently).

I understand that "out of the box" Avahi is not thread safe, but
according to my interpretation of [1] it is safe to have multiple
AvahiClient/AvahiPoll objects in the same process as long as they are
not 'accessed' from more than one thread. Each ZeroconfResolver has
its own set of Avahi objects that do not interact with each other
across thread boundaries.

The segfaults occur in seemingly random functions within the Avahi
library. In general they happen within the avahi_client_new or
avahi_service_resolver_new functions referencing dbus. Does the wiki
mean to imply that the 'creation' of AvahiClient/AvahiPoll objects is
also not thread safe?

-Jared

[1] http://avahi.org/wiki/RunningAvahiClientAsThread
[2] See below:

#include <xdispatch/dispatch.h>
#include <cstdio>

#include <sys/types.h>
#include <netinet/in.h>

#include <avahi-client/lookup.h>
#include <avahi-client/client.h>
#include <avahi-client/publish.h>
#include <avahi-common/alternative.h>
#include <avahi-common/simple-watch.h>
#include <avahi-common/malloc.h>
#include <avahi-common/error.h>
#include <avahi-common/timeval.h>

void resolve_reply(
   AvahiServiceResolver *r,
   AVAHI_GCC_UNUSED AvahiIfIndex interface,
   AVAHI_GCC_UNUSED AvahiProtocol protocol,
   AvahiResolverEvent event,
   const char *name,
   const char *type,
   const char *domain,
   const char *host_name,
   const AvahiAddress *address,
   uint16_t port,
   AvahiStringList *txt,
   AvahiLookupResultFlags flags,
   void * context) {

   assert(r);

   if (event == AVAHI_RESOLVER_FOUND)
     printf("resolve_reply(%s, %s, %s, %s)[FOUND]\n", name, type,
domain, host_name);

   avahi_service_resolver_free(
r);
   avahi_simple_poll_quit((AvahiSimplePoll*)context);
}


int main() {

 // Run until segfault
 while (true) {
   // Adding block to conccurent GCD queue (managed thread pool)
   xdispatch::global_queue().async(${
     char name[] = "AnHTTPServer";
     char domain[] = "local.";
     char type[] = "_http._tcp.";

     AvahiSimplePoll * simple_poll = NULL;
     if ((simple_poll = avahi_simple_poll_new())) {
       int error;
       AvahiClient * client = NULL;
       if ((client =
avahi_client_new(avahi_simple_poll_get(simple_poll),
AVAHI_CLIENT_NO_FAIL, NULL, NULL, &error))) {
         AvahiServiceResolver * resolver = NULL;
         if ((resolver = avahi_service_resolver_new(client,
AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, name, type, domain,
AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_NO_ADDRESS,
(AvahiServiceResolverCallback)resolve_reply, simple_poll))) {
             avahi_simple_poll_loop(simple_poll);
             printf("Exit Loop(%p)\n", simple_poll);
         } else {
           printf("Resolve(%s, %s, %s)[%s]\n", name, type, domain,
avahi_strerror(avahi_client_errno(client)));
         }
         avahi_client_free(client);
       } else {
         printf("avahi_client_new()[%s]\n", avahi_strerror(error));
       }
       avahi_simple_poll_free(simple_poll);
     } else {
       printf("avahi_simple_poll_new()[Failed]\n");
     }
   });
 }

 // Never reached
 return 0;
}


More information about the avahi mailing list