]> arthur.barton.de Git - netatalk.git/commitdiff
Support for mdnsresponder, from Lee Essen
authorFrank Lahm <franklahm@googlemail.com>
Wed, 29 Feb 2012 12:03:59 +0000 (13:03 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 29 Feb 2012 12:03:59 +0000 (13:03 +0100)
NEWS
etc/afpd/Makefile.am
etc/afpd/afp_avahi.c
etc/afpd/afp_avahi.h
etc/afpd/afp_mdns.c [new file with mode: 0644]
etc/afpd/afp_mdns.h [new file with mode: 0644]
etc/afpd/afp_zeroconf.c
etc/afpd/afp_zeroconf.h
macros/zeroconf.m4

diff --git a/NEWS b/NEWS
index f427f4d719c53f382cde838634c97d4eaac5737e..a988243261116578b8cd616d9f11c4ac39682e09 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 Changes in 2.2.3
 ================
 
+* NEW: afpd: support for mdnsresponder
 * UPD: based on Unicode 6.1.0
 * UPD: experimental systemd service files: always run both afpd and cnid_metad
 * UPD: afpd: Ensure our umask is not altered by eg pam_umask
index 4e9c02155e90281691d48deca067c41656316263..7a6ed52d56140fd06e29c8a06aff4ccf1543768a 100644 (file)
@@ -10,6 +10,7 @@ afpd_SOURCES = \
        afp_avahi.c \
        afp_config.c \
        afp_dsi.c \
+       afp_mdns.c \
        afp_options.c \
        afp_util.c \
        afp_zeroconf.c \
@@ -73,7 +74,7 @@ endif
 noinst_HEADERS = auth.h afp_config.h desktop.h directory.h fce_api_internal.h file.h \
         filedir.h fork.h icon.h mangle.h misc.h status.h switch.h \
         uam_auth.h uid.h unix.h volume.h hash.h acls.h acl_mappings.h extattrs.h \
-        dircache.h afp_zeroconf.h afp_avahi.h
+        dircache.h afp_zeroconf.h afp_avahi.h afp_mdns.h
 
 hash_SOURCES = hash.c
 hash_CFLAGS = -DKAZLIB_TEST_MAIN -I$(top_srcdir)/include
index 351e00190c9912c118eb592a0a2c3a22578c338c..837fa87ef7221bf576cad6a2c1fb3c64ab61bed9 100644 (file)
@@ -21,6 +21,7 @@
 #include <atalk/dsi.h>
 #include <atalk/unicode.h>
 
+#include "afp_zeroconf.h"
 #include "afp_avahi.h"
 #include "afp_config.h"
 #include "volume.h"
index e516408c6a79e17cc27ad95e7230e3e70e1830bd..9a6563ba8f75d89782fe6d2ab589f8b5dc468f89 100644 (file)
 
 #include "afp_config.h"
 
-#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
-#define ADISK_SERVICE_TYPE "_adisk._tcp"
-#define DEV_INFO_SERVICE_TYPE "_device-info._tcp"
-
-#define MAXINSTANCENAMELEN 63
-
 struct context {
        /* Avahi stuff */
   int               thread_running;
diff --git a/etc/afpd/afp_mdns.c b/etc/afpd/afp_mdns.c
new file mode 100644 (file)
index 0000000..2088402
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Author:   Lee Essen <lee.essen@nowonline.co.uk>
+ * Based on: avahi support from Daniel S. Haischt <me@daniel.stefan.haischt.name>
+ * Purpose:  mdns based Zeroconf support
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MDNS
+
+#include <unistd.h>
+#include <time.h>
+#include <pthread.h>
+#include <poll.h>
+
+#include <atalk/logger.h>
+#include <atalk/util.h>
+#include <atalk/dsi.h>
+#include <atalk/unicode.h>
+
+#include "afp_zeroconf.h"
+#include "afp_mdns.h"
+#include "afp_config.h"
+#include "volume.h"
+
+/*
+ * We'll store all the DNSServiceRef's here so that we can
+ * deallocate them later
+ */
+static DNSServiceRef   *svc_refs = NULL;
+static int             svc_ref_count = 0;
+static pthread_t       poller;
+
+/*
+ * Its easier to use asprintf to set the TXT record values
+ */
+#define TXTRecordPrintf(rec, key, args...) {            \
+        char *str;                                      \
+        asprintf(&str, args);                           \
+        TXTRecordSetValue(rec, key, strlen(str), str);  \
+        free(str);                                      \
+    }
+#define TXTRecordKeyPrintf(rec, k, var, args...) {      \
+        char *key, *str;                                \
+        asprintf(&key, k, var);                         \
+        asprintf(&str, args);                           \
+        TXTRecordSetValue(rec, key, strlen(str), str);  \
+        free(str); free(key);                           \
+    }
+
+
+/*
+ * This is the thread that polls the filehandles
+ */
+void *polling_thread(void *arg) {
+    // First we loop through getting the filehandles and adding them to our poll, we
+    // need to allocate our pollfd's
+    DNSServiceErrorType error;
+    struct pollfd           *fds = calloc(svc_ref_count, sizeof(struct pollfd));
+    assert(fds);
+
+    for(int i=0; i < svc_ref_count; i++) {
+        int fd = DNSServiceRefSockFD(svc_refs[i]);
+        fds[i].fd = fd;
+        fds[i].events = POLLIN;
+    }
+
+    // Now we can poll and process the results...
+    while(poll(fds, svc_ref_count, -1) > 0) {
+        for(int i=0; i < svc_ref_count; i++) {
+            if(fds[i].revents & POLLIN) {
+                error = DNSServiceProcessResult(svc_refs[i]);
+            }
+        }
+    }
+    return(NULL);
+}
+
+
+/*
+ * This is the callback for the service register function ... actually there isn't a lot
+ * we can do if we get problems, so we don't really need to do anything other than report
+ * the issue.
+ */
+void RegisterReply(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
+                   const char *name, const char *regtype, const char *domain, void *context) {
+
+    if(errorCode != kDNSServiceErr_NoError) {
+        LOG(log_error, logtype_afpd, "Failed to register mDNS service: %s%s%s: code=%d",
+            name, regtype, domain, errorCode);
+    }
+}
+
+
+/*
+ * This function unregisters anything we have already
+ * registered and frees associated memory
+ */
+static void unregister_stuff() {
+    pthread_kill(poller, SIGKILL);
+    if(svc_refs) {
+        for(int i=0; i < svc_ref_count; i++) {
+            DNSServiceRefDeallocate(svc_refs[i]);
+        }
+        free(svc_refs);
+        svc_refs = NULL;
+        svc_ref_count = 0;
+    }
+}
+
+/*
+ * This function tries to register the AFP DNS
+ * SRV service type.
+ */
+static void register_stuff(const AFPConfig *configs) {
+    uint                                        port;
+    const AFPConfig                 *config;
+    const struct vol                *volume;
+    DSI                                         *dsi;
+    char                                        name[MAXINSTANCENAMELEN+1];
+    DNSServiceErrorType         error;
+    TXTRecordRef                        txt_adisk;
+    TXTRecordRef                        txt_devinfo;
+    char                                        tmpname[256];
+
+    // If we had already registered, then we will unregister and re-register
+    if(svc_refs) unregister_stuff();
+
+    /* Register our service, prepare the TXT record */
+    TXTRecordCreate(&txt_adisk, 0, NULL);
+    TXTRecordPrintf(&txt_adisk, "sys", "waMa=0,adVF=0x100");
+
+    /* Build AFP volumes list */
+    int i = 0;
+
+    for (volume = getvolumes(); volume; volume = volume->v_next) {
+
+        if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_name, -1, tmpname, 255) <= 0) {
+            LOG ( log_error, logtype_afpd, "Could not set Zeroconf volume name for TimeMachine");
+            goto fail;
+        }
+
+        if (volume->v_flags & AFPVOL_TM) {
+            if (volume->v_uuid) {
+                LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine",
+                    volume->v_localname, volume->v_uuid);
+                TXTRecordKeyPrintf(&txt_adisk, "dk%u", i++, "adVN=%s,adVF=0xa1,adVU=%s",
+                                   tmpname, volume->v_uuid);
+            } else {
+                LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.",
+                    volume->v_localname);
+                TXTRecordKeyPrintf(&txt_adisk, "dk%u", i++, "adVN=%s,adVF=0xa1", tmpname);
+            }
+        }
+    }
+
+    // Now we can count the configs so we know how many service
+    // records to allocate
+    for (config = configs; config; config = config->next) {
+        svc_ref_count++;                    // AFP_DNS_SERVICE_TYPE
+        if(i) svc_ref_count++;      // ADISK_SERVICE_TYPE
+        if (config->obj.options.mimicmodel) svc_ref_count++;        // DEV_INFO_SERVICE_TYPE
+    }
+
+    // Allocate the memory to store our service refs
+    svc_refs = calloc(svc_ref_count, sizeof(DNSServiceRef));
+    assert(svc_ref);
+    svc_ref_count = 0;
+
+    /* AFP server */
+    for (config = configs; config; config = config->next) {
+
+        dsi = (DSI *)config->obj.handle;
+        port = getip_port((struct sockaddr *)&dsi->server);
+
+        if (convert_string(config->obj.options.unixcharset,
+                           CH_UTF8,
+                           config->obj.options.server ?
+                           config->obj.options.server :
+                           config->obj.options.hostname,
+                           -1,
+                           name,
+                           MAXINSTANCENAMELEN) <= 0) {
+            LOG(log_error, logtype_afpd, "Could not set Zeroconf instance name");
+            goto fail;
+        }
+        if ((dsi->bonjourname = strdup(name)) == NULL) {
+            LOG(log_error, logtype_afpd, "Could not set Zeroconf instance name");
+            goto fail;
+
+        }
+        LOG(log_info, logtype_afpd, "Registering server '%s' with Bonjour",
+            dsi->bonjourname);
+
+        error = DNSServiceRegister(&svc_refs[svc_ref_count++],
+                                   0,               // no flags
+                                   0,               // all network interfaces
+                                   dsi->bonjourname,
+                                   AFP_DNS_SERVICE_TYPE,
+                                   "",            // default domains
+                                   NULL,            // default host name
+                                   htons(port),
+                                   0,               // length of TXT
+                                   NULL,            // no TXT
+                                   RegisterReply,           // callback
+                                   NULL);       // no context
+        if(error != kDNSServiceErr_NoError) {
+            LOG(log_error, logtype_afpd, "Failed to add service: %s, error=%d",
+                AFP_DNS_SERVICE_TYPE, error);
+            goto fail;
+        }
+
+        if(i) {
+            error = DNSServiceRegister(&svc_refs[svc_ref_count++],
+                                       0,               // no flags
+                                       0,               // all network interfaces
+                                       dsi->bonjourname,
+                                       ADISK_SERVICE_TYPE,
+                                       "",            // default domains
+                                       NULL,            // default host name
+                                       htons(port),
+                                       TXTRecordGetLength(&txt_adisk),
+                                       TXTRecordGetBytesPtr(&txt_adisk),
+                                       RegisterReply,           // callback
+                                       NULL);       // no context
+            if(error != kDNSServiceErr_NoError) {
+                LOG(log_error, logtype_afpd, "Failed to add service: %s, error=%d",
+                    ADISK_SERVICE_TYPE, error);
+                goto fail;
+            }
+        }
+
+        if (config->obj.options.mimicmodel) {
+            TXTRecordCreate(&txt_devinfo, 0, NULL);
+            TXTRecordPrintf(&txt_devinfo, "model", config->obj.options.mimicmodel);
+            error = DNSServiceRegister(&svc_refs[svc_ref_count++],
+                                       0,               // no flags
+                                       0,               // all network interfaces
+                                       dsi->bonjourname,
+                                       DEV_INFO_SERVICE_TYPE,
+                                       "",            // default domains
+                                       NULL,            // default host name
+                                       htons(port),
+                                       TXTRecordGetLength(&txt_devinfo),
+                                       TXTRecordGetBytesPtr(&txt_devinfo),
+                                       RegisterReply,           // callback
+                                       NULL);       // no context
+            TXTRecordDeallocate(&txt_devinfo);
+            if(error != kDNSServiceErr_NoError) {
+                LOG(log_error, logtype_afpd, "Failed to add service: %s, error=%d",
+                    DEV_INFO_SERVICE_TYPE, error);
+                goto fail;
+            }
+        } /* if (config->obj.options.mimicmodel) */
+    }   /* for config*/
+
+        /*
+         * Now we can create the thread that will poll for the results
+         * and handle the calling of the callbacks
+         */
+    if(pthread_create(&poller, NULL, polling_thread, NULL) != 0) {
+        LOG(log_error, logtype_afpd, "Unable to start mDNS polling thread");
+        goto fail;
+    }
+
+fail:
+    TXTRecordDeallocate(&txt_adisk);
+    return;
+}
+
+/************************************************************************
+ * Public funcions
+ ************************************************************************/
+
+/*
+ * Tries to setup the Zeroconf thread and any
+ * neccessary config setting.
+ */
+void md_zeroconf_register(const AFPConfig *configs) {
+    int error;
+
+    register_stuff(configs);
+    return;
+}
+
+/*
+ * Tries to shutdown this loop impl.
+ * Call this function from inside this thread.
+ */
+int md_zeroconf_unregister() {
+    unregister_stuff();
+    return 0;
+}
+
+#endif /* USE_MDNS */
+
diff --git a/etc/afpd/afp_mdns.h b/etc/afpd/afp_mdns.h
new file mode 100644 (file)
index 0000000..fee1b58
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Author:   Lee Essen <lee.essen@nowonline.co.uk>
+ * Based on: avahi support from Daniel S. Haischt <me@daniel.stefan.haischt.name>
+ * Purpose:  mdns based Zeroconf support
+ */
+
+#ifndef AFPD_MDNS_H
+#define AFPD_MDNS_H
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include <dns_sd.h>
+
+#include <atalk/logger.h>
+
+#include "afp_config.h"
+
+/* prototype definitions */
+void md_zeroconf_register(const AFPConfig *configs);
+int md_zeroconf_unregister(void);
+
+#endif   /* AFPD_MDNS_H */
index d6fa657728b568ee1fe5b9a547ab02fc3b10990b..f8bbcf6fb4ed19297f954a4591c6f6141f157537 100644 (file)
@@ -14,7 +14,9 @@
 #include "afp_zeroconf.h"
 #include "afp_config.h"
 
-#ifdef HAVE_AVAHI
+#ifdef HAVE_MDNS
+#include "afp_mdns.h"
+#elif defined (HAVE_AVAHI)
 #include "afp_avahi.h"
 #endif
 
  */
 void zeroconf_register(const AFPConfig *configs)
 {
-#if defined (HAVE_AVAHI)
+#if defined (HAVE_MDNS)
+  LOG(log_debug, logtype_afpd, "Attempting to register with mDNS using mDNSResponder");
+
+       md_zeroconf_register(configs);
+#elif defined (HAVE_AVAHI)
   LOG(log_debug, logtype_afpd, "Attempting to register with mDNS using Avahi");
 
        av_zeroconf_register(configs);
@@ -33,7 +39,10 @@ void zeroconf_register(const AFPConfig *configs)
 
 void zeroconf_deregister(void)
 {
-#if defined (HAVE_AVAHI)
+#if defined (HAVE_MDNS)
+  LOG(log_debug, logtype_afpd, "Attempting to de-register mDNS using mDNSResponder");
+       md_zeroconf_unregister();
+#elif defined (HAVE_AVAHI)
   LOG(log_debug, logtype_afpd, "Attempting to de-register mDNS using Avahi");
        av_zeroconf_unregister();
 #endif
index e2711afb3a4a680d7c1f8ad063a2922b616f409e..8c370fd226d3515096309d538d69ffaf762b5888 100644 (file)
 
 #include "afp_config.h"
 
+#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
+#define ADISK_SERVICE_TYPE "_adisk._tcp"
+#define DEV_INFO_SERVICE_TYPE "_device-info._tcp"
+
+#define MAXINSTANCENAMELEN 63
+
 /*
  * Prototype Definitions
  */
index 788a193038fb217369d203bf581febb6766c4d11..2adc84285d6a74a20edb0f553828a9c824e8ef72 100644 (file)
@@ -25,32 +25,48 @@ AC_DEFUN([NETATALK_ZEROCONF], [
                        zeroconf_dir="$zeroconf"
                fi
 
-    # mDNS support using Avahi
-    AC_CHECK_HEADER(
-        avahi-client/client.h,
-        AC_CHECK_LIB(
-           avahi-client,
-           avahi_client_new,
-           AC_DEFINE(USE_ZEROCONF, 1, [Use DNS-SD registration]))
-    )
+        # mDNS support using mDNSResponder
+        AC_CHECK_HEADER(
+            dns_sd.h,
+            AC_CHECK_LIB(
+                dns_sd,
+                DNSServiceRegister,
+                AC_DEFINE(USE_ZEROCONF, 1, [Use DNS-SD registration]))
+        )
 
-    case "$ac_cv_lib_avahi_client_avahi_client_new" in
-      yes)
-      PKG_CHECK_MODULES(AVAHI, [ avahi-client >= 0.6 ])
-      PKG_CHECK_MODULES(AVAHI_TPOLL, [ avahi-client >= 0.6.4 ],
-        [AC_DEFINE(HAVE_AVAHI_THREADED_POLL, 1, [Uses Avahis threaded poll implementation])],
-        [AC_MSG_WARN(This Avahi implementation is not supporting threaded poll objects. Maybe this is not what you want.)])
-      ZEROCONF_LIBS="$AVAHI_LIBS"
-      ZEROCONF_CFLAGS="$AVAHI_CFLAGS"
-      AC_DEFINE(HAVE_AVAHI, 1, [Use Avahi/DNS-SD registration])
-      found_zeroconf=yes
-      ;;
-    esac
+        if test "$ac_cv_lib_dns_sd_DNSServiceRegister" = yes; then
+            ZEROCONF_LIBS="-ldns_sd"
+            AC_DEFINE(HAVE_MDNS, 1, [Use mDNSRespnder/DNS-SD registration])
+            found_zeroconf=yes
+        fi
 
-               CPPFLAGS="$savedcppflags"
-               LDFLAGS="$savedldflags"
+        # mDNS support using Avahi
+        if test x"$found_zeroconf" != x"yes" ; then
+            AC_CHECK_HEADER(
+                avahi-client/client.h,
+                AC_CHECK_LIB(
+                    avahi-client,
+                    avahi_client_new,
+                    AC_DEFINE(USE_ZEROCONF, 1, [Use DNS-SD registration]))
+            )
+
+            case "$ac_cv_lib_avahi_client_avahi_client_new" in
+            yes)
+                PKG_CHECK_MODULES(AVAHI, [ avahi-client >= 0.6 ])
+                PKG_CHECK_MODULES(AVAHI_TPOLL, [ avahi-client >= 0.6.4 ],
+                    [AC_DEFINE(HAVE_AVAHI_THREADED_POLL, 1, [Uses Avahis threaded poll implementation])],
+                    [AC_MSG_WARN(This Avahi implementation is not supporting threaded poll objects. Maybe this is not what you want.)])
+                ZEROCONF_LIBS="$AVAHI_LIBS"
+                ZEROCONF_CFLAGS="$AVAHI_CFLAGS"
+                AC_DEFINE(HAVE_AVAHI, 1, [Use Avahi/DNS-SD registration])
+                found_zeroconf=yes
+                ;;
+            esac
+               CPPFLAGS="$savedcppflags"
+                   LDFLAGS="$savedldflags"
+       fi
        fi
-       
+
        netatalk_cv_zeroconf=no
        AC_MSG_CHECKING([whether to enable Zerconf support])
        if test "x$found_zeroconf" = "xyes"; then