]> git.meshlink.io Git - catta/blobdiff - avahi-compat-libdns_sd/compat.c
* add new entry group state AVAHI_ENTRY_GROUP_FAILURE
[catta] / avahi-compat-libdns_sd / compat.c
index 9bb2ce8c00d7179bbbdc211dbf1d55be0afee51c..a06ca6826c627da13d9fdba991366e97076aee7d 100644 (file)
 #include <string.h>
 #include <signal.h>
 #include <netinet/in.h>
+#include <fcntl.h>
 
 #include <avahi-common/simple-watch.h>
 #include <avahi-common/malloc.h>
 #include <avahi-common/error.h>
 #include <avahi-common/domain.h>
 #include <avahi-common/alternative.h>
+
 #include <avahi-client/client.h>
+#include <avahi-client/publish.h>
+#include <avahi-client/lookup.h>
 
 #include "warn.h"
 #include "dns_sd.h"
 
 enum {
-    COMMAND_POLL = 'P',
-    COMMAND_QUIT = 'Q',
-    COMMAND_POLLED = 'D'
+    COMMAND_POLL = 'p',
+    COMMAND_QUIT = 'q',
+    COMMAND_POLL_DONE = 'P',
+    COMMAND_POLL_FAILED = 'F'
 };
 
 struct _DNSServiceRef_t {
@@ -59,7 +64,7 @@ struct _DNSServiceRef_t {
     int thread_running;
 
     pthread_mutex_t mutex;
-
+    
     void *context;
     DNSServiceBrowseReply service_browser_callback;
     DNSServiceResolveReply service_resolver_callback;
@@ -99,10 +104,11 @@ static DNSServiceErrorType map_error(int error) {
         case AVAHI_ERR_INVALID_PORT:
         case AVAHI_ERR_INVALID_KEY:
         case AVAHI_ERR_INVALID_ADDRESS:
+        case AVAHI_ERR_INVALID_SERVICE_SUBTYPE:
             return kDNSServiceErr_BadParam;
 
 
-        case AVAHI_ERR_LOCAL_COLLISION:
+        case AVAHI_ERR_COLLISION:
             return kDNSServiceErr_NameConflict;
 
         case AVAHI_ERR_TOO_MANY_CLIENTS:
@@ -221,25 +227,32 @@ static void * thread_func(void *data) {
         
         switch (command) {
 
-            case COMMAND_POLL:
+            case COMMAND_POLL: {
+                int ret;
 
                 ASSERT_SUCCESS(pthread_mutex_lock(&sdref->mutex));
+
+                for (;;) {
+                    errno = 0;
                     
-                
-                if (avahi_simple_poll_run(sdref->simple_poll) < 0) {
-                    fprintf(stderr, __FILE__": avahi_simple_poll_run() failed.\n");
-                    ASSERT_SUCCESS(pthread_mutex_unlock(&sdref->mutex));
-                    break;
-                }
+                    if ((ret = avahi_simple_poll_run(sdref->simple_poll)) < 0) {
+
+                        if (errno == EINTR)
+                            continue;
+                        
+                        fprintf(stderr, __FILE__": avahi_simple_poll_run() failed: %s\n", strerror(errno));
+                    }
 
-                if (write_command(sdref->thread_fd, COMMAND_POLLED) < 0) {
-                    ASSERT_SUCCESS(pthread_mutex_unlock(&sdref->mutex));
                     break;
                 }
 
                 ASSERT_SUCCESS(pthread_mutex_unlock(&sdref->mutex));
+
+                if (write_command(sdref->thread_fd, ret < 0 ? COMMAND_POLL_FAILED : COMMAND_POLL_DONE) < 0)
+                    break;
                 
                 break;
+            }
 
             case COMMAND_QUIT:
                 return NULL;
@@ -276,7 +289,7 @@ static DNSServiceRef sdref_new(void) {
 
     ASSERT_SUCCESS(pthread_mutexattr_init(&mutex_attr));
     pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
-    ASSERT_SUCCESS(pthread_mutex_init(&sdref->mutex, NULL));
+    ASSERT_SUCCESS(pthread_mutex_init(&sdref->mutex, &mutex_attr));
 
     sdref->thread_running = 0;
 
@@ -289,7 +302,7 @@ static DNSServiceRef sdref_new(void) {
     if (avahi_simple_poll_prepare(sdref->simple_poll, -1) < 0)
         goto fail;
 
-    /* Queue a initiall POLL command for the thread */
+    /* Queue an initial POLL command for the thread */
     if (write_command(sdref->main_fd, COMMAND_POLL) < 0)
         goto fail;
     
@@ -312,24 +325,24 @@ static void sdref_free(DNSServiceRef sdref) {
     assert(sdref);
     
     if (sdref->thread_running) {
-        write_command(sdref->main_fd, COMMAND_QUIT);
+        ASSERT_SUCCESS(write_command(sdref->main_fd, COMMAND_QUIT));
         avahi_simple_poll_wakeup(sdref->simple_poll);
-        pthread_join(sdref->thread, NULL);
+        ASSERT_SUCCESS(pthread_join(sdref->thread, NULL));
     }
 
     if (sdref->client)
         avahi_client_free(sdref->client);
 
+    if (sdref->simple_poll)
+        avahi_simple_poll_free(sdref->simple_poll);
+
     if (sdref->thread_fd >= 0)
         close(sdref->thread_fd);
 
     if (sdref->main_fd >= 0)
         close(sdref->main_fd);
 
-    if (sdref->simple_poll)
-        avahi_simple_poll_free(sdref->simple_poll);
-
-    pthread_mutex_destroy(&sdref->mutex);
+    ASSERT_SUCCESS(pthread_mutex_destroy(&sdref->mutex));
 
     avahi_free(sdref->service_name);
     avahi_free(sdref->service_name_chosen);
@@ -374,12 +387,12 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdref) {
     
     AVAHI_WARN_LINKAGE;
 
-    sdref_ref(sdref);
-
     ASSERT_SUCCESS(pthread_mutex_lock(&sdref->mutex));
+
+    sdref_ref(sdref);
     
     /* Cleanup notification socket */
-    if (read_command(sdref->main_fd) != COMMAND_POLLED)
+    if (read_command(sdref->main_fd) != COMMAND_POLL_DONE)
         goto finish;
     
     if (avahi_simple_poll_dispatch(sdref->simple_poll) < 0)
@@ -401,20 +414,18 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdref) {
     
 finish:
 
-    ASSERT_SUCCESS(pthread_mutex_unlock(&sdref->mutex));
-
     sdref_unref(sdref);
+
+    ASSERT_SUCCESS(pthread_mutex_unlock(&sdref->mutex));
     
     return ret;
 }
 
 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdref) {
-    assert(sdref);
-    assert(sdref->n_ref >= 1);
-
     AVAHI_WARN_LINKAGE;
 
-    sdref_unref(sdref);
+    if (sdref)
+        sdref_unref(sdref);
 }
 
 static void service_browser_callback(
@@ -447,11 +458,7 @@ static void service_browser_callback(
             break;
 
         case AVAHI_BROWSER_FAILURE:
-            sdref->service_browser_callback(sdref, 0, interface, kDNSServiceErr_Unknown, NULL, NULL, NULL, sdref->context);
-            break;
-            
-        case AVAHI_BROWSER_NOT_FOUND:
-            sdref->service_browser_callback(sdref, 0, interface, kDNSServiceErr_NoSuchName, NULL, NULL, NULL, sdref->context);
+            sdref->service_browser_callback(sdref, 0, interface, map_error(avahi_client_errno(sdref->client)), NULL, NULL, NULL, sdref->context);
             break;
             
         case AVAHI_BROWSER_CACHE_EXHAUSTED:
@@ -462,23 +469,29 @@ static void service_browser_callback(
 
 static void generic_client_callback(AvahiClient *s, AvahiClientState state, void* userdata) {
     DNSServiceRef sdref = userdata;
-
+    int error = kDNSServiceErr_Unknown;
+        
     assert(s);
     assert(sdref);
     assert(sdref->n_ref >= 1);
 
     switch (state) {
-        case AVAHI_CLIENT_DISCONNECTED: {
+        case AVAHI_CLIENT_S_FAILURE:
+
+            error = map_error(avahi_client_errno(s));
+
+            /* Fall through */
+            
+        case AVAHI_CLIENT_DISCONNECTED:
 
             if (sdref->service_browser_callback)
-                sdref->service_browser_callback(sdref, 0, 0, kDNSServiceErr_Unknown, NULL, NULL, NULL, sdref->context);
+                sdref->service_browser_callback(sdref, 0, 0, error, NULL, NULL, NULL, sdref->context);
             else if (sdref->service_resolver_callback)
-                sdref->service_resolver_callback(sdref, 0, 0, kDNSServiceErr_Unknown, NULL, NULL, 0, 0, NULL, sdref->context);
+                sdref->service_resolver_callback(sdref, 0, 0, error, NULL, NULL, 0, 0, NULL, sdref->context);
             else if (sdref->domain_browser_callback)
-                sdref->domain_browser_callback(sdref, 0, 0, kDNSServiceErr_Unknown, NULL, sdref->context);
+                sdref->domain_browser_callback(sdref, 0, 0, error, NULL, sdref->context);
 
             break;
-        }
 
         case AVAHI_CLIENT_S_RUNNING:
         case AVAHI_CLIENT_S_COLLISION:
@@ -563,22 +576,22 @@ static void service_resolver_callback(
     void *userdata) {
 
     DNSServiceRef sdref = userdata;
-    char host_name_fixed[AVAHI_DOMAIN_NAME_MAX];
 
     assert(r);
     assert(sdref);
     assert(sdref->n_ref >= 1);
 
-    host_name = add_trailing_dot(host_name, host_name_fixed, sizeof(host_name_fixed));
-
     switch (event) {
         case AVAHI_RESOLVER_FOUND: {
 
+            char host_name_fixed[AVAHI_DOMAIN_NAME_MAX];
             char full_name[AVAHI_DOMAIN_NAME_MAX];
             int ret;
             char *p = NULL;
             size_t l = 0;
 
+            host_name = add_trailing_dot(host_name, host_name_fixed, sizeof(host_name_fixed));
+
             if ((p = avahi_new0(char, (l = avahi_string_list_serialize(txt, NULL, 0))+1)))
                 avahi_string_list_serialize(txt, p, l);
 
@@ -593,14 +606,9 @@ static void service_resolver_callback(
             break;
         }
 
-        case AVAHI_RESOLVER_TIMEOUT:
-        case AVAHI_RESOLVER_NOT_FOUND:
-            sdref->service_resolver_callback(sdref, 0, interface, kDNSServiceErr_NoSuchName, NULL, NULL, 0, 0, NULL, sdref->context);
-            break;
-            
         case AVAHI_RESOLVER_FAILURE:
-            sdref->service_resolver_callback(sdref, 0, interface, kDNSServiceErr_Unknown, NULL, NULL, 0, 0, NULL, sdref->context);
-            
+            sdref->service_resolver_callback(sdref, 0, interface, map_error(avahi_client_errno(sdref->client)), NULL, NULL, 0, 0, NULL, sdref->context);
+            break;
     }
 }
 
@@ -712,11 +720,7 @@ static void domain_browser_callback(
             break;
 
         case AVAHI_BROWSER_FAILURE:
-            sdref->domain_browser_callback(sdref, 0, interface, kDNSServiceErr_Unknown, domain, sdref->context);
-            break;
-            
-        case AVAHI_BROWSER_NOT_FOUND:
-            sdref->domain_browser_callback(sdref, 0, interface, kDNSServiceErr_NoSuchName, domain, sdref->context);
+            sdref->domain_browser_callback(sdref, 0, interface, map_error(avahi_client_errno(sdref->client)), domain, sdref->context);
             break;
             
         case AVAHI_BROWSER_CACHE_EXHAUSTED:
@@ -804,22 +808,43 @@ static void reg_report_error(DNSServiceRef sdref, DNSServiceErrorType error) {
 
 static int reg_create_service(DNSServiceRef sdref) {
     int ret;
+    const char *real_type;
+    
     assert(sdref);
     assert(sdref->n_ref >= 1);
 
+    real_type = avahi_get_type_from_subtype(sdref->service_regtype);
+    
     if ((ret = avahi_entry_group_add_service_strlst(
         sdref->entry_group,
         sdref->service_interface,
         AVAHI_PROTO_UNSPEC,
         0,
         sdref->service_name_chosen,
-        sdref->service_regtype,
+        real_type ? real_type : sdref->service_regtype,
         sdref->service_domain,
         sdref->service_host,
         sdref->service_port,
         sdref->service_txt)) < 0)
         return ret;
 
+    
+    if (real_type) {
+        /* Create a subtype entry */
+
+        if (avahi_entry_group_add_service_subtype(
+                sdref->entry_group,
+                sdref->service_interface,
+                AVAHI_PROTO_UNSPEC,
+                0,
+                sdref->service_name_chosen,
+                real_type,
+                sdref->service_domain,
+                sdref->service_regtype) < 0)
+            return ret;
+
+    }
+
     if ((ret = avahi_entry_group_commit(sdref->entry_group)) < 0)
         return ret;
 
@@ -838,11 +863,13 @@ static void reg_client_callback(AvahiClient *s, AvahiClientState state, void* us
         return;
     
     switch (state) {
-        case AVAHI_CLIENT_DISCONNECTED: {
+        case AVAHI_CLIENT_DISCONNECTED:
+            reg_report_error(sdref, kDNSServiceErr_Unknown);
+            break;
 
-            reg_report_error(sdref, kDNSServiceErr_NoError);
+        case AVAHI_CLIENT_S_FAILURE:
+            reg_report_error(sdref, map_error(avahi_client_errno(s)));
             break;
-        }
         
         case AVAHI_CLIENT_S_RUNNING: {
             int ret;
@@ -852,6 +879,7 @@ static void reg_client_callback(AvahiClient *s, AvahiClientState state, void* us
                 /* If the service name is taken from the host name, copy that */
 
                 avahi_free(sdref->service_name_chosen);
+                sdref->service_name_chosen = NULL;
 
                 if (!(n = avahi_client_get_host_name(sdref->client))) {
                     reg_report_error(sdref, map_error(avahi_client_errno(sdref->client)));
@@ -931,6 +959,12 @@ static void reg_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState st
         case AVAHI_ENTRY_GROUP_UNCOMMITED:
             /* Ignore */
             break;
+
+        case AVAHI_ENTRY_GROUP_FAILURE:
+            /* Inform the user */
+            reg_report_error(sdref, map_error(avahi_client_errno(sdref->client)));
+            break;
+            
     }
 }
 
@@ -975,7 +1009,9 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister (
     sdref->service_host = host ? avahi_normalize_name_strdup(host) : NULL;
     sdref->service_interface = interface == kDNSServiceInterfaceIndexAny ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface;
     sdref->service_port = ntohs(port);
-    sdref->service_txt = txtRecord ? avahi_string_list_parse(txtRecord, txtLen) : NULL;
+    sdref->service_txt = txtRecord && txtLen > 0 ? avahi_string_list_parse(txtRecord, txtLen) : NULL;
+
+    /* Some OOM checking would be cool here */
     
     ASSERT_SUCCESS(pthread_mutex_lock(&sdref->mutex));