]> arthur.barton.de Git - netatalk.git/commitdiff
Use only one avahi thread to register all services
authorFrank Lahm <franklahm@googlemail.com>
Mon, 21 Jun 2010 10:08:25 +0000 (12:08 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Mon, 21 Jun 2010 10:08:25 +0000 (12:08 +0200)
etc/afpd/afp_avahi.c
etc/afpd/afp_avahi.h
etc/afpd/afp_config.c
etc/afpd/afp_options.c
etc/afpd/afp_zeroconf.c
etc/afpd/afp_zeroconf.h
etc/afpd/globals.h
etc/afpd/main.c
etc/afpd/volume.c
etc/afpd/volume.h

index 31d0120a634483070c93d09a4be52d7e5ac4a4f3..8b6bb27c0f6a665c05d3dbcbbeb9caeabedc2499 100644 (file)
 #ifdef HAVE_AVAHI
 
 #include <unistd.h>
+
+#include <atalk/logger.h>
+#include <atalk/util.h>
+#include <atalk/dsi.h>
+
 #include "afp_avahi.h"
+#include "afp_config.h"
+
+/*****************************************************************
+ * Global variables
+ *****************************************************************/
+struct context *ctx = NULL;
+
+/*****************************************************************
+ * Private functions
+ *****************************************************************/
 
 static void publish_reply(AvahiEntryGroup *g,
                           AvahiEntryGroupState state,
@@ -23,49 +38,53 @@ static void publish_reply(AvahiEntryGroup *g,
  * This function tries to register the AFP DNS
  * SRV service type.
  */
-static void register_stuff(struct context *ctx) {
-  char r[128];
-  int ret;
-
+static void register_stuff(void) {
+       const AFPConfig *config;
+       DSI *dsi;
   assert(ctx->client);
 
   if (!ctx->group) {
-    if (!(ctx->group = avahi_entry_group_new(ctx->client,
-                                             publish_reply,
-                                             ctx))) {
+    if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
       LOG(log_error, logtype_afpd, "Failed to create entry group: %s",
           avahi_strerror(avahi_client_errno(ctx->client)));
       goto fail;
     }
-
   }
 
-  LOG(log_info, logtype_afpd, "Adding service '%s'", ctx->name);
-
   if (avahi_entry_group_is_empty(ctx->group)) {
     /* Register our service */
 
-    if (avahi_entry_group_add_service(ctx->group,
-                                      AVAHI_IF_UNSPEC,
-                                      AVAHI_PROTO_UNSPEC,
-                                      0,
-                                      ctx->name,
-                                      AFP_DNS_SERVICE_TYPE,
-                                      NULL,
-                                      NULL,
-                                      ctx->port,
-                                      NULL) < 0) {
-      LOG(log_error, logtype_afpd, "Failed to add service: %s",
-          avahi_strerror(avahi_client_errno(ctx->client)));
-      goto fail;
-    }
+               /* AFP server */
+               for (config = ctx->configs; config; config = config->next) {
+                       dsi = (DSI *)config->obj.handle;
+                       if (avahi_entry_group_add_service(ctx->group,
+                                                                                                                                                               AVAHI_IF_UNSPEC,
+                                                                                                                                                               AVAHI_PROTO_UNSPEC,
+                                                                                                                                                               0,
+                                                                                                                                                               config->obj.options.server ?
+                                                                                                                                                                   config->obj.options.server
+                                                                                                                                                                   : config->obj.options.hostname,
+                                                                                                                                                               AFP_DNS_SERVICE_TYPE,
+                                                                                                                                                               NULL,
+                                                                                                                                                               NULL,
+                                                                                                                                                               getip_port((struct sockaddr *)&dsi->server),
+                                                                                                                                                               NULL) < 0) {
+                               LOG(log_error, logtype_afpd, "Failed to add service: %s",
+                                               avahi_strerror(avahi_client_errno(ctx->client)));
+                               goto fail;
+                       }
+
+               }       /* for config*/
+
+               /* AFP volumes */
+
+               if (avahi_entry_group_commit(ctx->group) < 0) {
+                       LOG(log_error, logtype_afpd, "Failed to commit entry group: %s",
+                                       avahi_strerror(avahi_client_errno(ctx->client)));
+                       goto fail;
+               }
 
-    if (avahi_entry_group_commit(ctx->group) < 0) {
-      LOG(log_error, logtype_afpd, "Failed to commit entry group: %s",
-          avahi_strerror(avahi_client_errno(ctx->client)));
-      goto fail;
-    }
-  }
+       }       /* if avahi_entry_group_is_empty*/
 
   return;
 
@@ -79,24 +98,21 @@ static void publish_reply(AvahiEntryGroup *g,
                           AvahiEntryGroupState state,
                           AVAHI_GCC_UNUSED void *userdata)
 {
-  struct context *ctx = userdata;
-       char *n;
-
-  assert(g == ctx->group);
+  assert(ctx->group == NULL || g == ctx->group);
 
   switch (state) {
 
   case AVAHI_ENTRY_GROUP_ESTABLISHED :
     /* The entry group has been established successfully */
+               LOG(log_debug, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_ESTABLISHED");
     break;
 
   case AVAHI_ENTRY_GROUP_COLLISION:
-    /* Pick a new name for our service */
-    n = avahi_alternative_service_name(ctx->name);
-    assert(n);
-    avahi_free(ctx->name);
-    ctx->name = n;
-    register_stuff(ctx);
+               /* With multiple names there's no way to know which one collided */
+    LOG(log_error, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_COLLISION",
+                               avahi_strerror(avahi_client_errno(ctx->client)));
+               avahi_client_free(avahi_entry_group_get_client(g));
+               avahi_threaded_poll_quit(ctx->threaded_poll);
     break;
                
   case AVAHI_ENTRY_GROUP_FAILURE:
@@ -117,8 +133,6 @@ static void client_callback(AvahiClient *client,
                             AvahiClientState state,
                             void *userdata)
 {
-  struct context *ctx = userdata;
-
   ctx->client = client;
 
   switch (state) {
@@ -126,7 +140,7 @@ static void client_callback(AvahiClient *client,
     /* The server has startup successfully and registered its host
      * name on the network, so it's time to create our services */
     if (!ctx->group)
-      register_stuff(ctx);
+      register_stuff();
     break;
 
   case AVAHI_CLIENT_S_COLLISION:
@@ -149,7 +163,7 @@ static void client_callback(AvahiClient *client,
                                            ctx,
                                            &error))) {
 
-        LOG(log_error, logtype_afpd, "Failed to contact server: %s\n",
+        LOG(log_error, logtype_afpd, "Failed to contact server: %s",
             avahi_strerror(error));
 
         avahi_client_free (ctx->client);
@@ -157,7 +171,7 @@ static void client_callback(AvahiClient *client,
       }
 
                } else {
-                       LOG(log_error, logtype_afpd, "Client failure: %s\n",
+                       LOG(log_error, logtype_afpd, "Client failure: %s",
                                        avahi_strerror(avahi_client_errno(client)));
                        avahi_client_free (ctx->client);
                        avahi_threaded_poll_quit(ctx->threaded_poll);
@@ -172,43 +186,23 @@ static void client_callback(AvahiClient *client,
   }
 }
 
+/************************************************************************
+ * Public funcions
+ ************************************************************************/
+
 /*
  * Tries to setup the Zeroconf thread and any
  * neccessary config setting.
  */
-void* av_zeroconf_setup(unsigned long port, const char *name) {
-  struct context *ctx = NULL;
-
-  /* default service name, if there's none in
-   * the config file.
-   */
-  char service[256] = "AFP Server on ";
+void av_zeroconf_setup(const AFPConfig *configs) {
   int error, ret;
 
-  /* initialize the struct that holds our
-   * config settings.
-   */
-  ctx = malloc(sizeof(struct context));
+  /* initialize the struct that holds our config settings. */
+  if (!ctx) {
+               ctx = calloc(1, sizeof(struct context));
+               ctx->configs = configs;
+       }
   assert(ctx);
-  ctx->client = NULL;
-  ctx->group = NULL;
-  ctx->threaded_poll = NULL;
-  ctx->thread_running = 0;
-
-  LOG(log_debug, logtype_afpd, "Setting port for Zeroconf service to: %i.", port);  
-  ctx->port = port;
-
-  /* Prepare service name */
-  if (!name) {
-    LOG(log_debug, logtype_afpd, "Assigning default service name.");
-    gethostname(service+14, sizeof(service)-15);
-    service[sizeof(service)-1] = 0;
-    ctx->name = strdup(service);
-  } else {
-    ctx->name = strdup(name);
-  }
-
-  assert(ctx->name);
 
 /* first of all we need to initialize our threading env */
   if (!(ctx->threaded_poll = avahi_threaded_poll_new())) {
@@ -219,34 +213,31 @@ void* av_zeroconf_setup(unsigned long port, const char *name) {
   if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
                                        AVAHI_CLIENT_NO_FAIL,
                                        client_callback,
-                                       ctx,
+                                       NULL,
                                        &error))) {
     LOG(log_error, logtype_afpd, "Failed to create client object: %s",
         avahi_strerror(avahi_client_errno(ctx->client)));
     goto fail;
   }
 
-  return ctx;
+  return;
 
 fail:
   if (ctx)
-    av_zeroconf_unregister(ctx);
+    av_zeroconf_unregister();
 
-  return NULL;
+  return;
 }
 
 /*
  * This function finally runs the loop impl.
  */
-int av_zeroconf_run(void *u) {
-  struct context *ctx = u;
+int av_zeroconf_run(void) {
   int ret;
 
   /* Finally, start the event loop thread */
   if (avahi_threaded_poll_start(ctx->threaded_poll) < 0) {
-    LOG(log_error,
-        logtype_afpd,
-        "Failed to create thread: %s",
+    LOG(log_error, logtype_afpd, "Failed to create thread: %s",
         avahi_strerror(avahi_client_errno(ctx->client)));
     goto fail;
   } else {
@@ -258,7 +249,7 @@ int av_zeroconf_run(void *u) {
 
 fail:
        if (ctx)
-    av_zeroconf_unregister(ctx);
+    av_zeroconf_unregister();
 
   return -1;
 }
@@ -267,12 +258,9 @@ fail:
  * Tries to shutdown this loop impl.
  * Call this function from outside this thread.
  */
-void av_zeroconf_shutdown(void *u) {
-  struct context *ctx = u;
-
+void av_zeroconf_shutdown() {
   /* Call this when the app shuts down */
   avahi_threaded_poll_stop(ctx->threaded_poll);
-  avahi_free(ctx->name);
   avahi_client_free(ctx->client);
   avahi_threaded_poll_free(ctx->threaded_poll);
 }
@@ -281,9 +269,7 @@ void av_zeroconf_shutdown(void *u) {
  * Tries to shutdown this loop impl.
  * Call this function from inside this thread.
  */
-int av_zeroconf_unregister(void *u) {
-  struct context *ctx = u;
-
+int av_zeroconf_unregister() {
   if (ctx->thread_running) {
     /* First, block the event loop */
     avahi_threaded_poll_lock(ctx->threaded_poll);
@@ -296,8 +282,6 @@ int av_zeroconf_unregister(void *u) {
     ctx->thread_running = 0;
   }
 
-  avahi_free(ctx->name);
-
   if (ctx->client)
     avahi_client_free(ctx->client);
 
index 059bdc1128786a536fcb66e7da7b429872e3e6a5..ae3d37dafaec57efb8e24e5c48a2e6cdaccdc598 100644 (file)
 
 #include <atalk/logger.h>
 
+#include "afp_config.h"
+
 #define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
 
 struct context {
-  int thread_running;
-  pthread_t thread_id;
-  pthread_mutex_t mutex;
-  char *name;
+       /* Avahi stuff */
+  int               thread_running;
   AvahiThreadedPoll *threaded_poll;
   AvahiClient       *client;
   AvahiEntryGroup   *group;
-  unsigned long     port;
+       /* Netatalk stuff */
+       const AFPConfig   *configs;
 };
 
 /* prototype definitions */
-void* av_zeroconf_setup(unsigned long, const char *);
-int av_zeroconf_run(void*);
-int av_zeroconf_unregister(void*);
-void av_zeroconf_shutdown(void*);
+void av_zeroconf_setup(const AFPConfig *configs);
+int av_zeroconf_run(void);
+int av_zeroconf_unregister(void);
+void av_zeroconf_shutdown(void);
 
 #endif   /* AFPD_AVAHI_H */
index f69c74a854ba58dc81a76c75e7c55cc4fbb9706b..4b3870939a4b3cf90d50155fbb06f562b690643b 100644 (file)
@@ -56,6 +56,8 @@ char *strchr (), *strrchr ();
 #include "afp_config.h"
 #include "uam_auth.h"
 #include "status.h"
+#include "volume.h"
+#include "afp_zeroconf.h"
 
 #define LINESIZE 1024  
 
@@ -154,9 +156,6 @@ static char * srvloc_encode(const struct afp_options *options, const char *name)
        return buf;
 }
 #endif /* USE_SRVLOC */
-#ifdef USE_ZEROCONF
-#include "afp_zeroconf.h"
-#endif /* USE_ZEROCONF */
 
 static void dsi_cleanup(const AFPConfig *config)
 {
@@ -193,14 +192,6 @@ static void dsi_cleanup(const AFPConfig *config)
 srvloc_dereg_err:
     dsi->srvloc_url[0] = '\0';
     SLPClose(hslp);
-#elif defined (USE_ZEROCONF)
-    DSI *dsi = (DSI *)config->obj.handle;
-
-    /*  Do nothing if we didn't register.  */
-    if (!dsi || dsi->zeroconf_registered == 0)
-        return;
-
-    zeroconf_deregister();
 #endif /* USE_SRVLOC */
 }
 
@@ -464,16 +455,6 @@ srvloc_reg_err:
     }
 #endif /* USE_SRVLOC */
 
-#ifdef USE_ZEROCONF
-    dsi->zeroconf_registered = 0; /*  Mark that we haven't registered.  */
-    if (!(options->flags & OPTION_NOZEROCONF)) {
-        zeroconf_register(getip_port((struct sockaddr *)&dsi->server),
-                          options->server ? options->server : options->hostname);
-        dsi->zeroconf_registered = 1; /*  Mark that we have registered.  */
-        config->server_cleanup = dsi_cleanup;
-    }
-#endif /* USE_ZEROCONF */
-
     config->fd = dsi->serversock;
     config->obj.handle = dsi;
     config->obj.config = config;
@@ -496,7 +477,7 @@ srvloc_reg_err:
 /* allocate server configurations. this should really store the last
  * entry in config->last or something like that. that would make
  * supporting multiple dsi transports easier. */
-static AFPConfig *AFPConfigInit(const struct afp_options *options,
+static AFPConfig *AFPConfigInit(struct afp_options *options,
                                 const struct afp_options *defoptions)
 {
     AFPConfig *config = NULL, *next = NULL;
@@ -609,7 +590,7 @@ AFPConfig *configinit(struct afp_options *cmdline)
         }
 #endif /* HAVE_ACLS */
 
-        /* this should really get a head and a tail to simplify things. */
+        /* AFPConfigInit can return two linked configs due to DSI and ASP */
         if (!first) {
             if ((first = AFPConfigInit(&options, cmdline)))
                 config = first->next ? first->next : first;
@@ -624,5 +605,10 @@ AFPConfig *configinit(struct afp_options *cmdline)
     if (!have_option)
         first = AFPConfigInit(cmdline, cmdline);
 
+    /* Now register with zeroconf, we also need the volumes for that */
+    readvolfile(&first->obj, &first->obj.options.systemvol, NULL, 0, NULL);
+
+    zeroconf_register(first);
+
     return first;
 }
index 40955be7dcdbc5f43f57db7a41c3f380a23cd074..92b7454286c0995c7fd8db43e5b3a00928903e35 100644 (file)
@@ -534,6 +534,7 @@ static void show_version_extended(void )
        puts( "No" );
 #endif
 
+       printf( "      Zeroconf support:\t" );
 #ifdef USE_ZEROCONF
        puts( "Yes" );
 #else
index 4c41bc6f7f7b1aeae5d388864d1eb6fa6dd9a841..84f187126340dd1664274106f08dc4765c167688 100644 (file)
 #endif
 
 #include "afp_zeroconf.h"
+#include "afp_config.h"
 
-/*
- * Global Definitions
- */
 #ifdef HAVE_AVAHI
-struct context *ctx = NULL;
+#include "afp_avahi.h"
 #endif
 
+
 /*
  * Functions (actually they are just facades)
  */
-void zeroconf_register(int port, const char *hostname)
+void zeroconf_register(const AFPConfig *configs)
 {
 #if defined (HAVE_AVAHI)
   LOG(log_debug, logtype_afpd, "Attempting to register with mDNS using Avahi");
 
-       ctx = av_zeroconf_setup(port ? port : AFP_PORT, 
-                                                                                                       (hostname && strlen(hostname) > 0) ? hostname : NULL);
-  av_zeroconf_run(ctx);
+       av_zeroconf_setup(configs);
+  av_zeroconf_run();
 #endif
 }
 
-void zeroconf_register_volume(const char *volname)
-{
-#if defined (HAVE_AVAHI)
-  LOG(log_debug, logtype_afpd, "Attempting to register volume with mDNS using Avahi");
-
-       ctx = av_zeroconf_setup(-1, volname);
-
-  av_zeroconf_run(ctx);
-#endif
-}
-
-
 void zeroconf_deregister(void)
 {
 #if defined (HAVE_AVAHI)
   LOG(log_debug, logtype_afpd, "Attempting to de-register mDNS using Avahi");
-  if (ctx)
-    av_zeroconf_shutdown(ctx);
+       av_zeroconf_shutdown();
 #endif
 }
index fa72a96b6daf6562da113b3e4c6861678d3fff18..e2711afb3a4a680d7c1f8ad063a2922b616f409e 100644 (file)
 #ifndef AFPD_ZEROCONF_H
 #define AFPD_ZEROCONF_H
 
-#include <netinet/in.h> /* htons() */
-#include <atalk/logger.h>
-
-#ifdef HAVE_AVAHI
-#include "afp_avahi.h"
-#endif
-
-#define AFP_PORT 548
+#include "afp_config.h"
 
 /*
  * Prototype Definitions
 /*
  * registers service with a particular Zerconf implemenation.
  */
-void zeroconf_register(int port, const char *hostname);
-
-/*
- * registers volume name with a particular Zerconf implemenation.
- */
-void zeroconf_register_volume(const char *volname);
+void zeroconf_register(const AFPConfig *configs);
 
 /*
  * de-registers the ntpd service with a particular Zerconf implemenation.
index 40c9601be635ec38e07ea13b3489b5d4ef8fdb09..b604cf22c41eeba27099aa77eb11378a7e8ce3dd 100644 (file)
@@ -91,7 +91,8 @@ struct afp_options {
 typedef struct _AFPObj {
     int proto;
     unsigned long servernum;
-    void *handle, *config;
+    void *handle;               /* either (DSI *) or (ASP *) */
+    void *config; 
     struct afp_options options;
     char *Obj, *Type, *Zone;
     char username[MAXUSERLEN];
index ffe409e08e05b608fb55b23e5328e7cb47496161..12c7295ce350994e313853a4690bbcd3a77c539e 100644 (file)
@@ -188,11 +188,6 @@ int main(int ac, char **av)
         exit(0);
     }
 
-#if 0
-    /* Register CNID  */
-    cnid_init();
-#endif
-
     /* install child handler for asp and dsi. we do this before afp_goaway
      * as afp_goaway references stuff from here. 
      * XXX: this should really be setup after the initial connections. */
index 03bc2be29375ee6bc5b7ded62236848688144c3a..f05b1c9f01b18bdf60bd2e4c92c7b884c8fd5d59 100644 (file)
@@ -249,11 +249,11 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
             }
         } else if (is_var(p, "$d")) {
             q = path;
-        } else if (is_var(p, "$f")) {
+        } else if (pwd && is_var(p, "$f")) {
             if ((r = strchr(pwd->pw_gecos, ',')))
                 *r = '\0';
             q = pwd->pw_gecos;
-        } else if (is_var(p, "$g")) {
+        } else if (pwd && is_var(p, "$g")) {
             struct group *grp = getgrgid(pwd->pw_gid);
             if (grp)
                 q = grp->gr_name;
@@ -278,7 +278,7 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
                 q = obj->options.server;
             } else
                 q = obj->options.hostname;
-        } else if (is_var(p, "$u")) {
+        } else if (obj->username && is_var(p, "$u")) {
             char* sep = NULL;
             if ( obj->options.ntseparator && (sep = strchr(obj->username, obj->options.ntseparator[0])) != NULL)
                 q = sep+1;
@@ -1078,7 +1078,10 @@ static int volfile_changed(struct afp_volume_name *p)
 
 /* ----------------------
  * Read a volume configuration file and add the volumes contained within to
- * the global volume list.  If p2 is non-NULL, the file that is opened is
+ * the global volume list. This gets called from the forked afpd childs.
+ * The master now reads this too for Zeroconf announcements.
+ *
+ * If p2 is non-NULL, the file that is opened is
  * p1/p2
  *
  * Lines that begin with # and blank lines are ignored.
@@ -1086,8 +1089,9 @@ static int volfile_changed(struct afp_volume_name *p)
  *      <unix path> [<volume name>] [allow:<user>,<@group>,...] \
  *                           [codepage:<file>] [casefold:<num>]
  *      <extension> TYPE [CREATOR]
+ *
  */
-static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent)
+int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int user, struct passwd *pwent)
 {
     FILE        *fp;
     char        path[MAXPATHLEN + 1];
@@ -1178,7 +1182,7 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us
             /* send path through variable substitution */
             if (*path != '~') /* need to copy path to tmp */
                 strcpy(tmp, path);
-            if (!pwent)
+            if (!pwent && obj->username)
                 pwent = getpwnam(obj->username);
             volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL);
 
index 63d090036bf713f955df7eecac383c772d7cbc4d..551f9ad6e45d5e3582ff5c663c62b1aaf7310ded 100644 (file)
@@ -28,6 +28,11 @@ extern int              ustatfs_getvolspace (const struct vol *,
 extern void             setvoltime (AFPObj *, struct vol *);
 extern int              pollvoltime (AFPObj *);
 extern void             load_volumes (AFPObj *obj);
+extern int              readvolfile(AFPObj *obj,
+                                    struct afp_volume_name *p1,
+                                    char *p2,
+                                    int user,
+                                    struct passwd *pwent);
 
 /* FP functions */
 int afp_openvol      (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf,  size_t *rbuflen);