X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-compat-libdns_sd%2Fcompat.c;h=70ccd4b1ef3141b08508a6ad027851e01956fab4;hb=270ea0a81dacf6a2073019d232b6f106e33eeb14;hp=3e2eb9db187bc66ae1e9577f5bb2111d3061f400;hpb=c26e445b409215cd2fa380c8ba8e6c8f6115aec5;p=catta diff --git a/avahi-compat-libdns_sd/compat.c b/avahi-compat-libdns_sd/compat.c index 3e2eb9d..70ccd4b 100644 --- a/avahi-compat-libdns_sd/compat.c +++ b/avahi-compat-libdns_sd/compat.c @@ -31,21 +31,29 @@ #include #include #include +#include + +#include +#include #include #include #include #include #include + #include +#include +#include #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 +67,7 @@ struct _DNSServiceRef_t { int thread_running; pthread_mutex_t mutex; - + void *context; DNSServiceBrowseReply service_browser_callback; DNSServiceResolveReply service_resolver_callback; @@ -99,10 +107,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: @@ -145,6 +154,20 @@ static DNSServiceErrorType map_error(int error) { return kDNSServiceErr_Unknown; } +static const char *add_trailing_dot(const char *s, char *buf, size_t buf_len) { + if (!s) + return NULL; + + if (*s == 0) + return s; + + if (s[strlen(s)-1] == '.') + return s; + + snprintf(buf, buf_len, "%s.", s); + return buf; +} + static int read_command(int fd) { ssize_t r; char command; @@ -207,25 +230,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; @@ -262,7 +292,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; @@ -275,7 +305,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; @@ -298,24 +328,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); @@ -360,12 +390,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) @@ -387,39 +417,40 @@ 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( AvahiServiceBrowser *b, AvahiIfIndex interface, - AvahiProtocol protocol, + AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, - AvahiLookupResultFlags flags, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void *userdata) { DNSServiceRef sdref = userdata; - + char type_fixed[AVAHI_DOMAIN_NAME_MAX], domain_fixed[AVAHI_DOMAIN_NAME_MAX]; assert(b); assert(sdref); assert(sdref->n_ref >= 1); + type = add_trailing_dot(type, type_fixed, sizeof(type_fixed)); + domain = add_trailing_dot(domain, domain_fixed, sizeof(domain_fixed)); + switch (event) { case AVAHI_BROWSER_NEW: sdref->service_browser_callback(sdref, kDNSServiceFlagsAdd, interface, kDNSServiceErr_NoError, name, type, domain, sdref->context); @@ -430,11 +461,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: @@ -445,27 +472,27 @@ 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_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: - case AVAHI_CLIENT_S_INVALID: case AVAHI_CLIENT_S_REGISTERING: break; } @@ -492,8 +519,10 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse( assert(domain); assert(callback); - if (interface == kDNSServiceInterfaceIndexLocalOnly || flags != 0) + if (interface == kDNSServiceInterfaceIndexLocalOnly || flags != 0) { + AVAHI_WARN_UNSUPPORTED; return kDNSServiceErr_Unsupported; + } if (!(sdref = sdref_new())) return kDNSServiceErr_Unknown; @@ -531,16 +560,16 @@ finish: static void service_resolver_callback( AvahiServiceResolver *r, AvahiIfIndex interface, - AvahiProtocol protocol, + AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, - const AvahiAddress *a, + AVAHI_GCC_UNUSED const AvahiAddress *a, uint16_t port, AvahiStringList *txt, - AvahiLookupResultFlags flags, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void *userdata) { DNSServiceRef sdref = userdata; @@ -552,16 +581,21 @@ static void service_resolver_callback( switch (event) { case AVAHI_RESOLVER_FOUND: { - char full_name[kDNSServiceMaxDomainName]; + 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); - ret = avahi_service_name_snprint(full_name, sizeof(full_name), name, type, domain); + ret = avahi_service_name_join(full_name, sizeof(full_name), name, type, domain); assert(ret == AVAHI_OK); + + strcat(full_name, "."); sdref->service_resolver_callback(sdref, 0, interface, kDNSServiceErr_NoError, full_name, host_name, htons(port), l, p, sdref->context); @@ -569,14 +603,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; } } @@ -603,8 +632,10 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve( assert(domain); assert(callback); - if (interface == kDNSServiceInterfaceIndexLocalOnly || flags != 0) + if (interface == kDNSServiceInterfaceIndexLocalOnly || flags != 0) { + AVAHI_WARN_UNSUPPORTED; return kDNSServiceErr_Unsupported; + } if (!(sdref = sdref_new())) return kDNSServiceErr_Unknown; @@ -652,7 +683,7 @@ int DNSSD_API DNSServiceConstructFullName ( assert(regtype); assert(domain); - if (avahi_service_name_snprint(fullName, kDNSServiceMaxDomainName, service, regtype, domain) < 0) + if (avahi_service_name_join(fullName, kDNSServiceMaxDomainName, service, regtype, domain) < 0) return -1; return 0; @@ -661,18 +692,21 @@ int DNSSD_API DNSServiceConstructFullName ( static void domain_browser_callback( AvahiDomainBrowser *b, AvahiIfIndex interface, - AvahiProtocol protocol, + AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, - AvahiLookupResultFlags flags, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void *userdata) { DNSServiceRef sdref = userdata; + static char domain_fixed[AVAHI_DOMAIN_NAME_MAX]; assert(b); assert(sdref); assert(sdref->n_ref >= 1); + domain = add_trailing_dot(domain, domain_fixed, sizeof(domain_fixed)); + switch (event) { case AVAHI_BROWSER_NEW: sdref->domain_browser_callback(sdref, kDNSServiceFlagsAdd, interface, kDNSServiceErr_NoError, domain, sdref->context); @@ -683,11 +717,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: @@ -714,8 +744,10 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains( assert(callback); if (interface == kDNSServiceInterfaceIndexLocalOnly || - (flags != kDNSServiceFlagsBrowseDomains && flags != kDNSServiceFlagsRegistrationDomains)) + (flags != kDNSServiceFlagsBrowseDomains && flags != kDNSServiceFlagsRegistrationDomains)) { + AVAHI_WARN_UNSUPPORTED; return kDNSServiceErr_Unsupported; + } if (!(sdref = sdref_new())) return kDNSServiceErr_Unknown; @@ -732,7 +764,7 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains( ifindex = interface == kDNSServiceInterfaceIndexAny ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface; - if (!(sdref->domain_browser = avahi_domain_browser_new(sdref->client, ifindex, AVAHI_PROTO_UNSPEC, NULL, + if (!(sdref->domain_browser = avahi_domain_browser_new(sdref->client, ifindex, AVAHI_PROTO_UNSPEC, "local", flags == kDNSServiceFlagsRegistrationDomains ? AVAHI_DOMAIN_BROWSER_REGISTER : AVAHI_DOMAIN_BROWSER_BROWSE, 0, domain_browser_callback, sdref))) { ret = map_error(avahi_client_errno(sdref->client)); @@ -753,37 +785,63 @@ finish: } static void reg_report_error(DNSServiceRef sdref, DNSServiceErrorType error) { + char regtype_fixed[AVAHI_DOMAIN_NAME_MAX], domain_fixed[AVAHI_DOMAIN_NAME_MAX]; + const char *regtype, *domain; assert(sdref); assert(sdref->n_ref >= 1); assert(sdref->service_register_callback); + regtype = add_trailing_dot(sdref->service_regtype, regtype_fixed, sizeof(regtype_fixed)); + domain = add_trailing_dot(sdref->service_domain, domain_fixed, sizeof(domain_fixed)); + sdref->service_register_callback( sdref, 0, error, sdref->service_name_chosen ? sdref->service_name_chosen : sdref->service_name, - sdref->service_regtype, - sdref->service_domain, + regtype, + domain, sdref->context); } 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; @@ -802,12 +860,10 @@ static void reg_client_callback(AvahiClient *s, AvahiClientState state, void* us return; switch (state) { - case AVAHI_CLIENT_DISCONNECTED: { - - reg_report_error(sdref, kDNSServiceErr_NoError); + case AVAHI_CLIENT_DISCONNECTED: + reg_report_error(sdref, kDNSServiceErr_Unknown); break; - } - + case AVAHI_CLIENT_S_RUNNING: { int ret; @@ -816,6 +872,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))); @@ -845,7 +902,6 @@ static void reg_client_callback(AvahiClient *s, AvahiClientState state, void* us break; - case AVAHI_CLIENT_S_INVALID: case AVAHI_CLIENT_S_REGISTERING: /* Ignore */ break; @@ -895,6 +951,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; + } } @@ -915,6 +977,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister ( DNSServiceErrorType ret = kDNSServiceErr_Unknown; int error; DNSServiceRef sdref = NULL; + AvahiStringList *txt = NULL; AVAHI_WARN_LINKAGE; @@ -922,22 +985,32 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister ( assert(callback); assert(regtype); - if (interface == kDNSServiceInterfaceIndexLocalOnly || flags) + if (interface == kDNSServiceInterfaceIndexLocalOnly || flags) { + AVAHI_WARN_UNSUPPORTED; return kDNSServiceErr_Unsupported; + } - if (!(sdref = sdref_new())) + if (txtRecord && txtLen > 0) + if (avahi_string_list_parse(txtRecord, txtLen, &txt) < 0) + return kDNSServiceErr_Invalid; + + if (!(sdref = sdref_new())) { + avahi_string_list_free(txt); return kDNSServiceErr_Unknown; + } sdref->context = context; sdref->service_register_callback = callback; sdref->service_name = avahi_strdup(name); - sdref->service_regtype = avahi_strdup(regtype); - sdref->service_domain = avahi_strdup(domain); - sdref->service_host = avahi_strdup(host); + sdref->service_regtype = regtype ? avahi_normalize_name_strdup(regtype) : NULL; + sdref->service_domain = domain ? avahi_normalize_name_strdup(domain) : NULL; + 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 = txt; + + /* Some OOM checking would be cool here */ ASSERT_SUCCESS(pthread_mutex_lock(&sdref->mutex));