From a8c7a377063ea45e85368399350121a3b8850995 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 4 Oct 2005 02:10:16 +0000 Subject: [PATCH] * Implement DNSServiceRegister() * All other Bonjour functions will only be implementedi on-demand git-svn-id: file:///home/lennart/svn/public/avahi/trunk@693 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- compat-bonjour/compat.c | 267 +++++++++++++++++++++++++++++++++++ compat-bonjour/funcs.txt | 36 +++-- compat-bonjour/unsupported.c | 19 --- 3 files changed, 284 insertions(+), 38 deletions(-) diff --git a/compat-bonjour/compat.c b/compat-bonjour/compat.c index f87a3bf..38397ff 100644 --- a/compat-bonjour/compat.c +++ b/compat-bonjour/compat.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "warn.h" @@ -61,11 +62,19 @@ struct _DNSServiceRef_t { DNSServiceBrowseReply service_browser_callback; DNSServiceResolveReply service_resolver_callback; DNSServiceDomainEnumReply domain_browser_callback; + DNSServiceRegisterReply service_register_callback; AvahiClient *client; AvahiServiceBrowser *service_browser; AvahiServiceResolver *service_resolver; AvahiDomainBrowser *domain_browser; + + char *service_name, *service_name_chosen, *service_regtype, *service_domain, *service_host; + uint16_t service_port; + AvahiIfIndex service_interface; + AvahiStringList *service_txt; + + AvahiEntryGroup *entry_group; }; #define ASSERT_SUCCESS(r) { int __ret = (r); assert(__ret == 0); } @@ -179,6 +188,10 @@ static DNSServiceRef sdref_new(void) { sdref->service_browser = NULL; sdref->service_resolver = NULL; sdref->domain_browser = NULL; + sdref->entry_group = NULL; + + sdref->service_name = sdref->service_name_chosen = sdref->service_regtype = sdref->service_domain = sdref->service_host = NULL; + sdref->service_txt = NULL; ASSERT_SUCCESS(pthread_mutexattr_init(&mutex_attr)); pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); @@ -276,6 +289,14 @@ void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdref) { avahi_simple_poll_free(sdref->simple_poll); pthread_mutex_destroy(&sdref->mutex); + + avahi_free(sdref->service_name); + avahi_free(sdref->service_name_chosen); + avahi_free(sdref->service_regtype); + avahi_free(sdref->service_domain); + avahi_free(sdref->service_host); + + avahi_string_list_free(sdref->service_txt); avahi_free(sdref); } @@ -663,3 +684,249 @@ finish: return ret; } +static void reg_report_error(DNSServiceRef sdref, DNSServiceErrorType error) { + assert(sdref); + + assert(sdref->service_register_callback); + + sdref->service_register_callback( + sdref, 0, error, + sdref->service_name_chosen ? sdref->service_name_chosen : sdref->service_name, + sdref->service_regtype, + sdref->service_domain, + sdref->context); +} + +static int reg_create_service(DNSServiceRef sdref) { + int ret; + assert(sdref); + + 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, + sdref->service_domain, + sdref->service_host, + sdref->service_port, + sdref->service_txt)) < 0) + return ret; + + if ((ret = avahi_entry_group_commit(sdref->entry_group)) < 0) + return ret; + + return 0; +} + +static void reg_client_callback(AvahiClient *s, AvahiClientState state, void* userdata) { + DNSServiceRef sdref = userdata; + + assert(s); + + /* We've not been setup completely */ + if (!sdref->entry_group) + return; + + switch (state) { + case AVAHI_CLIENT_DISCONNECTED: { + + reg_report_error(sdref, kDNSServiceErr_NoError); + break; + } + + case AVAHI_CLIENT_S_RUNNING: { + int ret; + + if (!sdref->service_name) { + const char *n; + /* If the service name is taken from the host name, copy that */ + + avahi_free(sdref->service_name_chosen); + + if (!(n = avahi_client_get_host_name(sdref->client))) { + reg_report_error(sdref, map_error(avahi_client_errno(sdref->client))); + return; + } + + if (!(sdref->service_name_chosen = avahi_strdup(n))) { + reg_report_error(sdref, kDNSServiceErr_NoMemory); + return; + } + } + + /* Register the service */ + + if ((ret = reg_create_service(sdref)) < 0) { + reg_report_error(sdref, map_error(ret)); + return; + } + + break; + } + + case AVAHI_CLIENT_S_COLLISION: + + /* Remove our entry */ + avahi_entry_group_reset(sdref->entry_group); + + break; + + case AVAHI_CLIENT_S_INVALID: + case AVAHI_CLIENT_S_REGISTERING: + /* Ignore */ + break; + } + +} + +static void reg_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { + DNSServiceRef sdref = userdata; + + assert(g); + + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED: + /* Inform the user */ + reg_report_error(sdref, kDNSServiceErr_NoError); + + break; + + case AVAHI_ENTRY_GROUP_COLLISION: { + char *n; + int ret; + + /* Remove our entry */ + avahi_entry_group_reset(sdref->entry_group); + + assert(sdref->service_name_chosen); + + /* Pick a new name */ + if (!(n = avahi_alternative_service_name(sdref->service_name_chosen))) { + reg_report_error(sdref, kDNSServiceErr_NoMemory); + return; + } + avahi_free(sdref->service_name_chosen); + sdref->service_name_chosen = n; + + /* Register the service with that new name */ + if ((ret = reg_create_service(sdref)) < 0) { + reg_report_error(sdref, map_error(ret)); + return; + } + + break; + } + + case AVAHI_ENTRY_GROUP_REGISTERING: + case AVAHI_ENTRY_GROUP_UNCOMMITED: + /* Ignore */ + break; + } +} + +DNSServiceErrorType DNSSD_API DNSServiceRegister ( + DNSServiceRef *ret_sdref, + DNSServiceFlags flags, + uint32_t interface, + const char *name, + const char *regtype, + const char *domain, + const char *host, + uint16_t port, + uint16_t txtLen, + const void *txtRecord, + DNSServiceRegisterReply callback, + void *context) { + + DNSServiceErrorType ret = kDNSServiceErr_Unknown; + int error; + DNSServiceRef sdref = NULL; + + AVAHI_WARN_LINKAGE; + + assert(ret_sdref); + assert(callback); + assert(regtype); + + if (interface == kDNSServiceInterfaceIndexLocalOnly || flags) + return kDNSServiceErr_Unsupported; + + if (!(sdref = sdref_new())) + 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_interface = interface == kDNSServiceInterfaceIndexAny ? AVAHI_IF_UNSPEC : (AvahiIfIndex) interface; + sdref->service_port = ntohs(port); + sdref->service_txt = txtRecord ? avahi_string_list_parse(txtRecord, txtLen) : NULL; + + ASSERT_SUCCESS(pthread_mutex_lock(&sdref->mutex)); + + if (!(sdref->client = avahi_client_new(avahi_simple_poll_get(sdref->simple_poll), reg_client_callback, sdref, &error))) { + ret = map_error(error); + goto finish; + } + + if (!sdref->service_domain) { + const char *d; + + if (!(d = avahi_client_get_domain_name(sdref->client))) { + ret = map_error(avahi_client_errno(sdref->client)); + goto finish; + } + + if (!(sdref->service_domain = avahi_strdup(d))) { + ret = kDNSServiceErr_NoMemory; + goto finish; + } + } + + if (!(sdref->entry_group = avahi_entry_group_new(sdref->client, reg_entry_group_callback, sdref))) { + ret = map_error(avahi_client_errno(sdref->client)); + goto finish; + } + + if (avahi_client_get_state(sdref->client) == AVAHI_CLIENT_S_RUNNING) { + const char *n; + + if (sdref->service_name) + n = sdref->service_name; + else { + if (!(n = avahi_client_get_host_name(sdref->client))) { + ret = map_error(avahi_client_errno(sdref->client)); + goto finish; + } + } + + if (!(sdref->service_name_chosen = avahi_strdup(n))) { + ret = kDNSServiceErr_NoMemory; + goto finish; + } + + + if ((error = reg_create_service(sdref)) < 0) { + ret = map_error(error); + goto finish; + } + } + + ret = kDNSServiceErr_NoError; + *ret_sdref = sdref; + +finish: + + ASSERT_SUCCESS(pthread_mutex_unlock(&sdref->mutex)); + + if (ret != kDNSServiceErr_NoError) + DNSServiceRefDeallocate(sdref); + + return ret; +} + diff --git a/compat-bonjour/funcs.txt b/compat-bonjour/funcs.txt index de8bba4..8bafc1a 100644 --- a/compat-bonjour/funcs.txt +++ b/compat-bonjour/funcs.txt @@ -1,26 +1,24 @@ -Functions marked with "x" are implemented. - Supported: -x DNSServiceRefSockFD -x DNSServiceProcessResult -x DNSServiceRefDeallocate -x DNSServiceEnumerateDomains +DNSServiceRefSockFD +DNSServiceProcessResult +DNSServiceRefDeallocate +DNSServiceEnumerateDomains DNSServiceRegister -x DNSServiceBrowse -x DNSServiceResolve -x DNSServiceConstructFullName +DNSServiceBrowse +DNSServiceResolve +DNSServiceConstructFullName -x TXTRecordCreate -x TXTRecordDeallocate -x TXTRecordSetValue -x TXTRecordRemoveValue -x TXTRecordGetLength -x TXTRecordGetBytesPtr -x TXTRecordContainsKey -x TXTRecordGetValuePtr -x TXTRecordGetCount -x TXTRecordGetItemAtIndex +TXTRecordCreate +TXTRecordDeallocate +TXTRecordSetValue +TXTRecordRemoveValue +TXTRecordGetLength +TXTRecordGetBytesPtr +TXTRecordContainsKey +TXTRecordGetValuePtr +TXTRecordGetCount +TXTRecordGetItemAtIndex Unsupported: diff --git a/compat-bonjour/unsupported.c b/compat-bonjour/unsupported.c index f74691d..73e4697 100644 --- a/compat-bonjour/unsupported.c +++ b/compat-bonjour/unsupported.c @@ -26,25 +26,6 @@ #include "dns_sd.h" #include "warn.h" -DNSServiceErrorType DNSSD_API DNSServiceRegister ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *name, - const char *regtype, - const char *domain, - const char *host, - uint16_t port, - uint16_t txtLen, - const void *txtRecord, - DNSServiceRegisterReply callBack, - void *context) { - - AVAHI_WARN_UNSUPPORTED; - - return kDNSServiceErr_Unsupported; -} - DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord ( DNSServiceRef sdRef, DNSRecordRef *RecordRef, -- 2.39.5