title: multi-threaded avahi resolving causes segfault
body: <p>I'm attempting to port my zeronconf-enabled C/C++ app to Linux, however I'm getting D-BUS related segfaults. I'm not sure if this is a bug in Avahi, my misuse of Avahi, or a bug in my code.</p>
  
  <p>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.</p>
  
  <p>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 in the code below (may not produce a
  segfault right away, but in my use case it happens frequently).</p>
  
  <p>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.</p>
  
  <p>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 Avahi wiki
  mean to imply that the 'creation' of AvahiClient/AvahiPoll objects is
  also not thread safe?</p>
  
  <p>[1] <a href="http://avahi.org/wiki/RunningAvahiClientAsThread" rel="nofollow">http://avahi.org/wiki/RunningAvahiClientAsThread</a><br></p>
  
  <pre><code>#include &lt;dispatch/dispatch.h&gt;
  #include &lt;cstdio&gt;
  
  #include &lt;sys/types.h&gt;
  #include &lt;netinet/in.h&gt;
  
  #include &lt;avahi-client/lookup.h&gt;
  #include &lt;avahi-client/client.h&gt;
  #include &lt;avahi-client/publish.h&gt;
  #include &lt;avahi-common/alternative.h&gt;
  #include &lt;avahi-common/simple-watch.h&gt;
  #include &lt;avahi-common/malloc.h&gt;
  #include &lt;avahi-common/error.h&gt;
  #include &lt;avahi-common/timeval.h&gt;
  
  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)
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [=]{
        char name[] = "SomeHTTPServerToResolve";
        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, &amp;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;
  }
  </code></pre>