? etc/afpd/afp_avahi.c ? etc/afpd/afp_avahi.c.org ? etc/afpd/afp_avahi.h ? etc/afpd/afp_avahi.h.org ? etc/afpd/afp_bonjour.c ? etc/afpd/afp_bonjour.c.org ? etc/afpd/afp_bonjour.h ? etc/afpd/afp_bonjour.h.org ? etc/afpd/afp_howl.c ? etc/afpd/afp_howl.c.org ? etc/afpd/afp_howl.h ? etc/afpd/afp_howl.h.org ? etc/afpd/afp_zeroconf.c ? etc/afpd/afp_zeroconf.c.org ? etc/afpd/afp_zeroconf.h ? etc/afpd/afp_zeroconf.h.org ? macros/zeroconf.m4 ? macros/zeroconf.m4.org Index: configure.in =================================================================== RCS file: /cvsroot/netatalk/netatalk/configure.in,v retrieving revision 1.203 diff -u -r1.203 configure.in --- configure.in 28 Apr 2005 20:49:17 -0000 1.203 +++ configure.in 5 May 2006 10:46:30 -0000 @@ -398,6 +398,9 @@ dnl Check for optional server location protocol support (used by MacOS X) NETATALK_SRVLOC +dnl Check for optional Zeroconf support +NETATALK_ZEROCONF + dnl Check for PAM libs netatalk_cv_use_pam=no AC_PATH_PAM([ Index: config/afpd.conf.tmpl =================================================================== RCS file: /cvsroot/netatalk/netatalk/config/afpd.conf.tmpl,v retrieving revision 1.16 diff -u -r1.16 afpd.conf.tmpl --- config/afpd.conf.tmpl 28 Apr 2005 20:49:20 -0000 1.16 +++ config/afpd.conf.tmpl 5 May 2006 10:46:31 -0000 @@ -51,6 +51,8 @@ # empty string. # -noslp Don't register this server with the Service # Location Protocol. +# -nozeroconf Don't register this server with the Multicats +# DNS Protocol. # # # Authentication Methods: Index: contrib/a2boot/Makefile.am =================================================================== RCS file: /cvsroot/netatalk/netatalk/contrib/a2boot/Makefile.am,v retrieving revision 1.5 diff -u -r1.5 Makefile.am --- contrib/a2boot/Makefile.am 28 Apr 2005 20:49:21 -0000 1.5 +++ contrib/a2boot/Makefile.am 5 May 2006 10:46:32 -0000 @@ -10,7 +10,7 @@ EXTRA_DIST = COPYRIGHT VERSION CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \ - @CFLAGS@ @SLP_CFLAGS@ \ + @CFLAGS@ @SLP_CFLAGS@ @ZEROCONF_CFLAGS@ \ -D_PATH_A_GS_BLOCKS=\"$(PKGCONFDIR)/a2boot/ProDOS16\ Boot\ Blocks\" \ -D_PATH_A_2E_BLOCKS=\"$(PKGCONFDIR)/a2boot/Apple\ :2f:2fe\ Boot\ Blocks\" \ -D_PATH_P16_IMAGE=\"$(PKGCONFDIR)/a2boot/ProDOS16\ Image\" Index: etc/afpd/Makefile.am =================================================================== RCS file: /cvsroot/netatalk/netatalk/etc/afpd/Makefile.am,v retrieving revision 1.38 diff -u -r1.38 Makefile.am --- etc/afpd/Makefile.am 30 Apr 2005 21:33:41 -0000 1.38 +++ etc/afpd/Makefile.am 5 May 2006 10:46:33 -0000 @@ -8,19 +8,21 @@ file.c enumerate.c desktop.c filedir.c fork.c appl.c gettok.c \ mangle.c status.c afp_options.c afp_asp.c afp_dsi.c messages.c \ afp_config.c nfsquota.c quota.c uam.c afs.c uid.c afp_util.c \ - catsearch.c afprun.c + catsearch.c afprun.c \ + afp_zeroconf.c afp_avahi.c afp_bonjour.c afp_howl.c afpd_LDADD = $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la afpd_LDFLAGS = -export-dynamic noinst_HEADERS = auth.h afp_config.h desktop.h directory.h file.h \ filedir.h fork.h globals.h icon.h mangle.h misc.h status.h switch.h \ - uam_auth.h uid.h unix.h volume.h + uam_auth.h uid.h unix.h volume.h \ + afp_zeroconf.h afp_avahi.h afp_bonjour.h afp_howl.h -LIBS = @LIBS@ @PAM_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@ @WRAP_LIBS@ +LIBS = @LIBS@ @PAM_LIBS@ @QUOTA_LIBS@ @SLP_LIBS@ @ZEROCONF_LIBS@ @WRAP_LIBS@ CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \ - @CFLAGS@ @SLP_CFLAGS@ \ + @CFLAGS@ @SLP_CFLAGS@ @ZEROCONF_CFLAGS@ \ -D_PATH_AFPDDEFVOL=\"$(pkgconfdir)/AppleVolumes.default\" \ -D_PATH_AFPDSYSVOL=\"$(pkgconfdir)/AppleVolumes.system\" \ -D_PATH_AFPDPWFILE=\"$(pkgconfdir)/afppasswd\" \ Index: etc/afpd/afp_config.c =================================================================== RCS file: /cvsroot/netatalk/netatalk/etc/afpd/afp_config.c,v retrieving revision 1.23 diff -u -r1.23 afp_config.c --- etc/afpd/afp_config.c 28 Apr 2005 20:49:39 -0000 1.23 +++ etc/afpd/afp_config.c 5 May 2006 10:46:35 -0000 @@ -50,6 +50,9 @@ #ifdef USE_SRVLOC #include <slp.h> #endif /* USE_SRVLOC */ +#ifdef USE_ZEROCONF +#include "afp_zeroconf.h" +#endif /* USE_ZEROCONF */ #include "globals.h" #include "afp_config.h" @@ -154,9 +157,9 @@ } #endif /* USE_SRVLOC */ -#ifdef USE_SRVLOC static void dsi_cleanup(const AFPConfig *config) { +#ifdef USE_SRVLOC SLPError err; SLPError callbackerr; SLPHandle hslp; @@ -189,8 +192,16 @@ 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 */ +} #ifndef NO_DDP static void asp_cleanup(const AFPConfig *config) @@ -355,6 +366,10 @@ struct servent *afpovertcp; int afp_port = 548; char *srvloc_hostname, *hostname; +#elif defined (USE_ZEROCONF) + struct servent *afpovertcp; + int afp_port = 548; + char *hostname = NULL; #endif /* USE_SRVLOC */ if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) { @@ -449,6 +464,36 @@ } #endif /* USE_SRVLOC */ +#ifdef USE_ZEROCONF + dsi->zeroconf_registered = 0; /* Mark that we haven't registered. */ + + if (!(options->flags & OPTION_NOZEROCONF)) { + /* XXX We don't want to tack on the port number if we don't have to. + * Why? + * Well, this seems to break MacOS < 10. If the user _really_ wants to + * use a non-default port, they can, but be aware, this server might + * not show up int the Network Browser. + */ + afpovertcp = getservbyname("afpovertcp", "tcp"); + if (afpovertcp != NULL) { + afp_port = ntohs(afpovertcp->s_port); + } + + /* If specified use the FQDN to register with srvloc, otherwise use IP. */ + p = NULL; + if (options->fqdn) { + hostname = options->fqdn; + p = strchr(hostname, ':'); + } + else + hostname = inet_ntoa(dsi->server.sin_addr); + + if (!(options->flags & OPTION_NOSLP)) { + zeroconf_register(afp_port, hostname); + dsi->zeroconf_registered = 1; /* Mark that we have registered. */ + } + } +#endif /* USE_ZEROCONF */ config->fd = dsi->serversock; config->obj.handle = dsi; @@ -469,6 +514,9 @@ #ifdef USE_SRVLOC config->server_cleanup = dsi_cleanup; #endif +#ifdef USE_ZEROCONF + config->server_cleanup = dsi_cleanup; +#endif return config; } Index: etc/afpd/afp_options.c =================================================================== RCS file: /cvsroot/netatalk/netatalk/etc/afpd/afp_options.c,v retrieving revision 1.35 diff -u -r1.35 afp_options.c --- etc/afpd/afp_options.c 28 Apr 2005 20:49:39 -0000 1.35 +++ etc/afpd/afp_options.c 5 May 2006 10:46:39 -0000 @@ -202,10 +202,15 @@ /* parse toggles */ if (strstr(buf, " -nodebug")) options->flags &= ~OPTION_DEBUG; + #ifdef USE_SRVLOC if (strstr(buf, " -noslp")) options->flags |= OPTION_NOSLP; #endif /* USE_SRVLOC */ +#ifdef USE_ZEROCONF + if (strstr(buf, " -nozeroconf")) + options->flags |= OPTION_NOZEROCONF; +#endif if (strstr(buf, " -nouservolfirst")) options->flags &= ~OPTION_USERVOLFIRST; @@ -578,6 +583,12 @@ puts( "No" ); #endif +#ifdef USE_ZEROCONF + puts( "Yes" ); +#else + puts( "No" ); +#endif + printf( " TCP wrappers support:\t" ); #ifdef TCPWRAP puts( "Yes" ); Index: etc/afpd/globals.h =================================================================== RCS file: /cvsroot/netatalk/netatalk/etc/afpd/globals.h,v retrieving revision 1.21 diff -u -r1.21 globals.h --- etc/afpd/globals.h 28 Apr 2005 20:49:43 -0000 1.21 +++ etc/afpd/globals.h 5 May 2006 10:46:39 -0000 @@ -40,6 +40,7 @@ #define OPTION_CUSTOMICON (1 << 4) #define OPTION_NOSLP (1 << 5) #define OPTION_ANNOUNCESSH (1 << 6) +#define OPTION_NOZEROCONF (1 << 7) #ifdef FORCE_UIDGID /* set up a structure for this */ Index: include/atalk/dsi.h =================================================================== RCS file: /cvsroot/netatalk/netatalk/include/atalk/dsi.h,v retrieving revision 1.6 diff -u -r1.6 dsi.h --- include/atalk/dsi.h 3 May 2005 14:55:12 -0000 1.6 +++ include/atalk/dsi.h 5 May 2006 10:46:41 -0000 @@ -85,6 +85,10 @@ char srvloc_url[512]; #endif +#ifdef USE_ZEROCONF + int zeroconf_registered; +#endif + /* buffer for OSX deadlock */ int noblocking; char *buffer; Index: macros/summary.m4 =================================================================== RCS file: /cvsroot/netatalk/netatalk/macros/summary.m4,v retrieving revision 1.2 diff -u -r1.2 summary.m4 --- macros/summary.m4 28 Apr 2005 20:50:05 -0000 1.2 +++ macros/summary.m4 5 May 2006 10:46:46 -0000 @@ -44,6 +44,7 @@ AC_MSG_RESULT([ Options:]) AC_MSG_RESULT([ CUPS support: $netatalk_cv_use_cups]) AC_MSG_RESULT([ SLP support: $netatalk_cv_srvloc]) + AC_MSG_RESULT([ Zeroconf support: $netatalk_cv_zeroconf]) AC_MSG_RESULT([ tcp wrapper support: $netatalk_cv_tcpwrap]) dnl if test x"$netatalk_cv_linux_sendfile" != x; then dnl AC_MSG_RESULT([ Linux sendfile support: $netatalk_cv_linux_sendfile]) Index: man/man5/afpd.conf.5.tmpl =================================================================== RCS file: /cvsroot/netatalk/netatalk/man/man5/afpd.conf.5.tmpl,v retrieving revision 1.4 diff -u -r1.4 afpd.conf.5.tmpl --- man/man5/afpd.conf.5.tmpl 28 Apr 2005 20:50:06 -0000 1.4 +++ man/man5/afpd.conf.5.tmpl 5 May 2006 10:46:48 -0000 @@ -210,6 +210,9 @@ Protocol (if SLP support was compiled in). This is useful if you are running multiple servers and want one to be hidden, perhaps because it is advertised elsewhere, ie. by a SLP Directory Agent. +\-noslp +Do not register this server using the Multicast DNS +Protocol (if Zeroconf support was compiled in). .SH "MISCELLANEOUS OPTIONS" .TP \-admingroup \fI[group]\fR --- etc/afpd/afp_avahi.c.org 2006-04-21 10:29:22.000000000 +0200 +++ etc/afpd/afp_avahi.c 2006-04-22 08:34:34.000000000 +0200 @@ -0,0 +1,500 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Avahi based Zeroconf support + * Docs: http://avahi.org/download/doxygen/ + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_AVAHI + +#include "afp_avahi.h" + +static void publish_reply(AvahiEntryGroup *g, + AvahiEntryGroupState state, + void *userdata); + +/* + * This function tries to register the AFP DNS + * SRV service type. + */ +static void register_stuff(struct context *ctx) { + char r[128]; + int ret; + + assert(ctx->client); + + if (!ctx->group) { + + if (!(ctx->group = avahi_entry_group_new(ctx->client, + publish_reply, + ctx))) { + LOG(log_error, + logtype_afpd, + "Failed to create entry group: %s\n", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } + + } + + LOG(log_info, logtype_afpd, "Adding service '%s'\n", 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\n", + 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\n", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } + } + + return; + + fail: + avahi_client_free (ctx->client); +#ifndef HAVE_AVAHI_THREADED_POLL + avahi_simple_poll_quit(ctx->simple_poll); +#else + avahi_threaded_poll_quit(ctx->threaded_poll); +#endif +} + +/* Called when publishing of service data completes */ +static void publish_reply(AvahiEntryGroup *g, + AvahiEntryGroupState state, + AVAHI_GCC_UNUSED void *userdata) +{ + struct context *ctx = userdata; + + assert(g == ctx->group); + + switch (state) { + + case AVAHI_ENTRY_GROUP_ESTABLISHED : + /* The entry group has been established successfully */ + break; + + case AVAHI_ENTRY_GROUP_COLLISION: { + char *n; + + /* 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); + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE: { + LOG(log_error, + logtype_afpd, + "Failed to register service: %s\n", + avahi_strerror(avahi_client_errno(ctx->client))); + avahi_client_free (avahi_entry_group_get_client(g)); +#ifndef HAVE_AVAHI_THREADED_POLL + avahi_simple_poll_quit(ctx->simple_poll); +#else + avahi_threaded_poll_quit(ctx->threaded_poll); +#endif + break; + } + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + } +} + +static void client_callback(AvahiClient *client, + AvahiClientState state, + void *userdata) +{ + struct context *ctx = userdata; + + ctx->client = client; + + switch (state) { + + case AVAHI_CLIENT_S_RUNNING: + + /* 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); + break; + + case AVAHI_CLIENT_S_COLLISION: + + if (ctx->group) + avahi_entry_group_reset(ctx->group); + break; + + case AVAHI_CLIENT_FAILURE: { + + if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) { + int error; + + avahi_client_free(ctx->client); + ctx->client = NULL; + ctx->group = NULL; + + /* Reconnect to the server */ + +#ifndef HAVE_AVAHI_THREADED_POLL + if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll), +#else + if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll), +#endif + AVAHI_CLIENT_NO_FAIL, + client_callback, + ctx, + &error))) { + + LOG(log_error, + logtype_afpd, + "Failed to contact server: %s\n", + avahi_strerror(error)); + + avahi_client_free (ctx->client); +#ifndef HAVE_AVAHI_THREADED_POLL + avahi_simple_poll_quit(ctx->simple_poll); +#else + avahi_threaded_poll_quit(ctx->threaded_poll); +#endif + } + + } else { + LOG(log_error, + logtype_afpd, + "Client failure: %s\n", + avahi_strerror(avahi_client_errno(client))); + + avahi_client_free (ctx->client); +#ifndef HAVE_AVAHI_THREADED_POLL + avahi_simple_poll_quit(ctx->simple_poll); +#else + avahi_threaded_poll_quit(ctx->threaded_poll); +#endif + } + + break; + } + + case AVAHI_CLIENT_S_REGISTERING: + case AVAHI_CLIENT_CONNECTING: + ; + } +} + +static void* thread(void *userdata) { +#ifndef HAVE_AVAHI_THREADED_POLL + struct context *ctx = userdata; + sigset_t mask; + int r; + + /* Make sure that signals are delivered to the main thread */ + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + + pthread_mutex_lock(&ctx->mutex); + + /* Run the main loop */ + LOG(log_info, logtype_afpd, "Starting avahi loop..."); + r = avahi_simple_poll_loop(ctx->simple_poll); + + /* Cleanup some stuff */ + if (ctx->client) + avahi_client_free(ctx->client); + ctx->client = NULL; + ctx->group = NULL; + + pthread_mutex_unlock(&ctx->mutex); +#endif + return NULL; +} + +static int poll_func(struct pollfd *ufds, + unsigned int nfds, + int timeout, + void *userdata) { +#ifndef HAVE_AVAHI_THREADED_POLL + pthread_mutex_t *mutex = userdata; + int r; + + /* Before entering poll() we unlock the mutex, so that + * avahi_simple_poll_quit() can succeed from another thread. */ + + pthread_mutex_unlock(mutex); + r = poll(ufds, nfds, timeout); + pthread_mutex_lock(mutex); + + return r; +#else + return 0; +#endif +} + +/* + * 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 "; + int error, ret; + + /* initialize the struct that holds our + * config settings. + */ + ctx = malloc(sizeof(struct context)); + assert(ctx); + ctx->client = NULL; + ctx->group = NULL; +#ifndef HAVE_AVAHI_THREADED_POLL + ctx->simple_poll = NULL; + pthread_mutex_init(&ctx->mutex, NULL); +#else + ctx->threaded_poll = NULL; +#endif + ctx->thread_running = 0; + + LOG(log_info, + logtype_afpd, + "Setting port for Zeroconf service to: %i.\n", + port); + ctx->port = port; + + /* Prepare service name */ + if (!name) { + LOG(log_info, + logtype_afpd, + "Assigning default service name.\n"); + 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 */ +#ifdef HAVE_AVAHI_THREADED_POLL + if (!(ctx->threaded_poll = avahi_threaded_poll_new())) { + goto fail; + } +#else + if (!(ctx->simple_poll = avahi_simple_poll_new())) { + LOG(log_error, + logtype_afpd, + "Failed to create event loop object.\n"); + goto fail; + } + + avahi_simple_poll_set_func(ctx->simple_poll, poll_func, &ctx->mutex); +#endif + +/* now we need to acquire a client */ +#ifdef HAVE_AVAHI_THREADED_POLL + if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll), + AVAHI_CLIENT_NO_FAIL, + client_callback, + ctx, + &error))) { + LOG(log_error, + logtype_afpd, + "Failed to create client object: %s\n", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } +#else + if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll), + AVAHI_CLIENT_NO_FAIL, + client_callback, + ctx, + &error))) { + LOG(log_error, + logtype_afpd, + "Failed to create client object: %s\n", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } +#endif + + return ctx; + +fail: + + if (ctx) + av_zeroconf_unregister(ctx); + + return NULL; +} + +/* + * This function finally runs the loop impl. + */ +int av_zeroconf_run(void *u) { + struct context *ctx = u; + int ret; + +#ifdef HAVE_AVAHI_THREADED_POLL + /* 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\n", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } else { + LOG(log_info, logtype_afpd, "Successfully started avahi loop.\n"); + } +#else + /* Create the mDNS event handler */ + if ((ret = pthread_create(&ctx->thread_id, NULL, thread, ctx)) < 0) { + LOG(log_error, + logtype_afpd, + "Failed to create thread: %s\n", strerror(ret)); + goto fail; + } else { + LOG(log_info, logtype_afpd, "Successfully started avahi loop.\n"); + } +#endif + + ctx->thread_running = 1; + + return 0; + +fail: + + if (ctx) + av_zeroconf_unregister(ctx); + + return -1; +} + +/* + * Used to lock access to the loop. + * Currently unused. + */ +void av_zeroconf_lock(void *u) { +#ifdef HAVE_AVAHI_THREADED_POLL + struct context *ctx = u; + + avahi_threaded_poll_lock(ctx->threaded_poll); +#endif +} + +/* + * Used to unlock access to the loop. + * Currently unused. + */ +void av_zeroconf_unlock(void *u) { +#ifdef HAVE_AVAHI_THREADED_POLL + struct context *ctx = u; + + avahi_threaded_poll_unlock(ctx->threaded_poll); +#endif +} + +/* + * Tries to shutdown this loop impl. + * Call this function from outside this thread. + */ +void av_zeroconf_shutdown(void *u) { + struct context *ctx = u; + + /* Call this when the app shuts down */ +#ifdef HAVE_AVAHI_THREADED_POLL + avahi_threaded_poll_stop(ctx->threaded_poll); + avahi_free(ctx->name); + avahi_client_free(ctx->client); + avahi_threaded_poll_free(ctx->threaded_poll); +#else + av_zeroconf_unregister(ctx); +#endif +} + +/* + * Tries to shutdown this loop impl. + * Call this function from inside this thread. + */ +int av_zeroconf_unregister(void *u) { + struct context *ctx = u; + + if (ctx->thread_running) { +#ifndef HAVE_AVAHI_THREADED_POLL + pthread_mutex_lock(&ctx->mutex); + avahi_simple_poll_quit(ctx->simple_poll); + pthread_mutex_unlock(&ctx->mutex); + + pthread_join(ctx->thread_id, NULL); +#else + /* First, block the event loop */ + avahi_threaded_poll_lock(ctx->threaded_poll); + + /* Than, do your stuff */ + avahi_threaded_poll_quit(ctx->threaded_poll); + + /* Finally, unblock the event loop */ + avahi_threaded_poll_unlock(ctx->threaded_poll); +#endif + ctx->thread_running = 0; + } + + avahi_free(ctx->name); + + if (ctx->client) + avahi_client_free(ctx->client); + +#ifndef HAVE_AVAHI_THREADED_POLL + if (ctx->simple_poll) + avahi_simple_poll_free(ctx->simple_poll); + + pthread_mutex_destroy(&ctx->mutex); +#else + if (ctx->threaded_poll) + avahi_threaded_poll_free(ctx->threaded_poll); +#endif + + free(ctx); + + return 0; +} + +#endif /* USE_AVAHI */ --- etc/afpd/afp_avahi.h.org 2006-04-21 10:29:23.000000000 +0200 +++ etc/afpd/afp_avahi.h 2006-04-22 07:40:05.000000000 +0200 @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Avahi based Zeroconf support + * Docs: http://avahi.org/download/doxygen/ + * + */ + +#ifndef AFPD_AVAHI_H +#define AFPD_AVAHI_H + +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include <avahi-client/client.h> +#include <avahi-client/publish.h> + +#include <avahi-common/alternative.h> + +#ifndef HAVE_AVAHI_THREADED_POLL +#include <avahi-common/simple-watch.h> +#include <signal.h> /* SIG_BLOCK */ +#else +#include <avahi-common/thread-watch.h> +#endif + +#include <avahi-common/malloc.h> +#include <avahi-common/error.h> + +#include <atalk/logger.h> + +#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp" + +struct context { + int thread_running; + pthread_t thread_id; + pthread_mutex_t mutex; + char *name; +#ifndef HAVE_AVAHI_THREADED_POLL + AvahiSimplePoll *simple_poll; +#else + AvahiThreadedPoll *threaded_poll; +#endif + AvahiClient *client; + AvahiEntryGroup *group; + unsigned long port; +}; + +/* 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_lock(void *); +void av_zeroconf_unlock(void *); + +#endif /* AFPD_AVAHI_H */ --- etc/afpd/afp_bonjour.h.org 2006-04-21 10:29:30.000000000 +0200 +++ etc/afpd/afp_bonjour.h 2006-04-21 07:37:05.000000000 +0200 @@ -0,0 +1,27 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Bonjour based Zeroconf support + * Docs: http://developer.apple.com/documentation/Networking/Reference/DNSServiceDiscovery_CRef/dns_sd/ + * + */ + +#ifndef AFPD_BONJOUR_H +#define AFPD_BONJOUR_H + +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include <dns_sd.h> /* DNSServiceRegister(), DNSServiceDiscoveryDeallocate() */ + +#include <atalk/logger.h> + +#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp" + +/* prototype definitions */ +void* bo_zeroconf_setup(unsigned long, const char *); +int bo_zeroconf_unregister(void); +int bo_zeroconf_run(void); + +#endif /* AFPD_BONJOUR_H */ --- etc/afpd/afp_bonjour.c.org 2006-04-21 10:29:28.000000000 +0200 +++ etc/afpd/afp_bonjour.c 2006-04-21 09:45:13.000000000 +0200 @@ -0,0 +1,112 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Bonjour based Zeroconf support + * Docs: http://developer.apple.com/documentation/Networking/Reference/DNSServiceDiscovery_CRef/dns_sd/ + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_BONJOUR + +#include "afp_bonjour.h" + +DNSServiceRef publish_session = NULL; + +static void DNSSD_API +publish_reply(DNSServiceRef, + const DNSServiceFlags, + DNSServiceErrorType, + const char *, + const char *, + const char *, + void *); + +static void DNSSD_API +publish_reply (DNSServiceRef sdRef, + const DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, + const char *regtype, + const char *domain, + void *context) +{ +} + +void* bo_zeroconf_setup(unsigned long port, const char *name) { + DNSServiceErrorType err; + char service[256] = "AFP Server on "; + + /* Prepare service name */ + if (!name) { + LOG(log_info, logtype_afpd,, "Assigning default service name.\n"); + gethostname(service+14, sizeof(service)-15); + service[sizeof(service)-1] = 0; + + name = strdup(service); + } + + assert(name); + assert(port); + + err = DNSServiceRegister (&publish_session, + 0, /* flags */ + 0, /* interface; 0 for all */ + name, /* name */ + AFP_DNS_SERVICE_TYPE, /* type */ + NULL, /* domain */ + NULL, /* hostname */ + htons (port), /* port in network byte order */ + 0, /* text record length */ + NULL, /* text record */ + publish_reply, /* callback */ + NULL); /* context */ + + if (err == kDNSServiceErr_NoError) { + LOG(log_info, logtype_afpd, "Adding service '%s'\n", name); + } else { + LOG(log_error, logtype_afpd, "Adding service '%s' failed\n", name); + bo_zeroconf_unregister(); + } +} + +int bo_zeroconf_run(void) { + fd_set set; + int fd; + struct timeval timeout; + + /* Initialize the file descriptor set. */ + FD_ZERO (&set); + FD_SET (fd, &set); + + /* Initialize the timeout data structure. */ + /* TODO: Should the value for sec be configurable? */ + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + if (publish_session != NULL) { + fd = DNSServiceRefSockFD(publish_session); + + if (select(FD_SETSIZE, + &set, NULL, NULL, + &timeout) > 0) { + DNSServiceProcessResult(publish_session); + } + } + + return 0; +} + +int bo_zeroconf_unregister(void) { + if (publish_session != NULL) { + DNSServiceRefDeallocate(publish_session); + publish_session = NULL; + } + + return 0; +} + +#endif /* HAVE_BONJOUR */ --- etc/afpd/afp_howl.c.org 2006-04-21 10:29:34.000000000 +0200 +++ etc/afpd/afp_howl.c 2006-04-21 09:46:11.000000000 +0200 @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Howl based Zeroconf support + * Doc: http://www.porchdogsoft.com/products/howl/docs/ + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_HOWL + +#include "afp_howl.h" + +sw_discovery discovery = NULL; + +static sw_result HOWL_API publish_reply(sw_discovery, + sw_discovery_oid, + sw_discovery_publish_status, + sw_opaque); + +static sw_result HOWL_API publish_reply(sw_discovery discovery, + sw_discovery_oid oid, + sw_discovery_publish_status status, + sw_opaque extra) { + static sw_string + status_text[] = + { + "Started", + "Stopped", + "Name Collision", + "Invalid" + }; + + LOG(log_info, logtype_afpd, "publish reply: %s\n", status_text[status]); + return SW_OKAY; +} + +void* ho_zeroconf_setup(unsigned long port, const char *name) { + sw_result result; + sw_discovery_publish_id id; + char service[256] = "AFP Server on "; + + if (sw_discovery_init (&discovery) != SW_OKAY) { + LOG(log_error, + logtype_afpd, + "AFPD could not be started. \nTry running mDNSResponder."); + return; + } + + /* Prepare service name */ + if (!name) { + LOG(log_info, logtype_afpd, "Assigning default service name.\n"); + gethostname(service+14, sizeof(service)-15); + service[sizeof(service)-1] = 0; + + name = strdup(service); + } + + assert(name); + + if (!(result = sw_discovery_publish (discovery, + 0, + name, + AFP_DNS_SERVICE_TYPE, + NULL, + NULL, + port, + NULL, + 0, + publish_reply, + NULL, + &id)) != SW_OKAY) { + LOG(log_info, logtype_afpd, "Adding service '%s'\n", name); + } else { + LOG(log_error, logtype_afpd, "Adding service '%s' failed\n", name); + ho_zeroconf_unregister(); + } +} + +void* ho_zeroconf_run(void) { + sw_discovery_run(discovery); +} + +void* ho_zeroconf_unregister(void) { + sw_discovery_stop_run(discovery); + sw_discovery_fina(discovery); +} + +#endif /* USE_HOWL */ --- etc/afpd/afp_howl.h.org 2006-04-21 10:29:33.000000000 +0200 +++ etc/afpd/afp_howl.h 2006-04-21 07:37:11.000000000 +0200 @@ -0,0 +1,27 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Howl based Zeroconf support + * Doc: http://www.porchdogsoft.com/products/howl/docs/ + * + */ + +#ifndef AFPD_HOWL_H +#define AFPD_HOWL_H + +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include <howl.h> + +#include <atalk/logger.h> + +#define NTP_DNS_SERVICE_TYPE "_afpovertcp._tcp" + +/* prototype definitions */ +void* ho_zeroconf_setup(unsigned long, const char *); +void* ho_zeroconf_unregister(void); +void* ho_zeroconf_run(void); + +#endif /* AFPD_HOWL_H */ --- etc/afpd/afp_zeroconf.h.org 2006-04-21 10:29:39.000000000 +0200 +++ etc/afpd/afp_zeroconf.h 2006-04-21 11:39:20.000000000 +0200 @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Zeroconf facade, that abstracts access to a + * particular Zeroconf implementation + * Doc: http://www.dns-sd.org/ + * + */ + +#ifndef AFPD_ZEROCONF_H +#define AFPD_ZEROCONF_H + +#include <netinet/in.h> /* htons() */ +#include <atalk/logger.h> + +# ifdef HAVE_BONJOUR +# include "afp_bonjour.h" +# elif defined (HAVE_HOWL) +# include "afp_howl.h" +# elif defined (HAVE_AVAHI) +# include "afp_avahi.h" +# endif + +#define AFP_PORT 548 + +/* + * Prototype Definitions + */ + +/* + * registers the ntpd service with a particular Zerconf implemenation. + */ +void zeroconf_register(int port, char *hostname); + +/* + * de-registers the ntpd service with a particular Zerconf implemenation. + */ +void zeroconf_deregister(void); + +#endif AFPD_ZEROCONF_H --- etc/afpd/afp_zeroconf.c.org 2006-04-21 10:29:38.000000000 +0200 +++ etc/afpd/afp_zeroconf.c 2006-04-21 13:12:38.000000000 +0200 @@ -0,0 +1,97 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name> + * Purpose: Zeroconf facade, that abstracts access to a + * particular Zeroconf implementation + * Doc: http://www.dns-sd.org/ + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "afp_zeroconf.h" + +/* + * Global Definitions + */ +#ifdef HAVE_AVAHI +struct context *ctx = NULL; +#endif + +/* + * Functions (actually they are just facades) + */ +void zeroconf_register(int port, char *hostname) +{ +#ifdef HAVE_BONJOUR + LOG(log_info, + logtype_afpd, + "Attempting to register with mDNS using Apple's Bonjour\n"); + if (hostname && strlen(hostname) > 0 && port) + { + bo_zeroconf_setup(port, hostname); + } + else if (hostname && strlen(hostname) > 0) + { + bo_zeroconf_setup(AFP_PORT, hostname); + } + else + { + bo_zeroconf_setup(AFP_PORT, NULL); + } + bo_zeroconf_run(); +#elif defined (HAVE_HOWL) + LOG(log_info, + logtype_afpd, + "Attempting to register with mDNS using Porchdog's Howl\n"); + if (hostname && strlen(hostname) > 0 && port) + { + ho_zeroconf_setup(port, hostname); + } + else if (hostname && strlen(hostname) > 0) + { + ho_zeroconf_setup(AFP_PORT, hostname); + } + else + { + ho_zeroconf_setup(AFP_PORT, NULL); + } + bo_zeroconf_run(); +#elif defined (HAVE_AVAHI) + LOG(log_info, logtype_afpd, "Attempting to register with mDNS using Avahi\n"); + if (hostname && strlen(hostname) > 0 && port) + { + ctx = av_zeroconf_setup(port, hostname); + } + else if (hostname && strlen(hostname) > 0) + { + ctx = av_zeroconf_setup(AFP_PORT, hostname); + } + else + { + ctx = av_zeroconf_setup(AFP_PORT, NULL); + } + av_zeroconf_run(ctx); +#endif +} + +void zeroconf_deregister(void) +{ +#ifdef HAVE_BONJOUR + LOG(log_error, + logtype_afpd, + "Attempting to de-register mDNS using Apple's Bonjour\n"); + bo_zeroconf_unregister(); +#elif defined (HAVE_HOWL) + LOG(log_error, + logtype_afpd, + "Attempting to de-register mDNS using Porchdog's Howl\n"); + ho_zeroconf_unregister(); +#elif defined (HAVE_AVAHI) + LOG(log_error, logtype_afpd, "Attempting to de-register mDNS using Avahi\n"); + if (ctx) + av_zeroconf_shutdown(ctx); +#endif +} --- macros/zeroconf.m4.org 2006-04-21 10:29:51.000000000 +0200 +++ macros/zeroconf.m4 2006-04-22 07:26:56.000000000 +0200 @@ -0,0 +1,101 @@ +dnl Check for optional Zeroconf support + +dnl $Id$ + +AC_DEFUN([NETATALK_ZEROCONF], [ + + ZEROCONF_LIBS="" + ZEROCONF_CFLAGS="" + found_zeroconf=no + zeroconf_dir="" + + AC_ARG_ENABLE(zeroconf, + [ --enable-zeroconf[[=DIR]] enable Zeroconf support [[auto]]], + [zeroconf=$enableval], + [zeroconf=try] + ) + + dnl make sure atalk_libname is defined beforehand + [[ -n "$atalk_libname" ]] || AC_MSG_ERROR([internal error, atalk_libname undefined]) + + if test "x$zeroconf" != "xno"; then + + savedcppflags="$CPPFLAGS" + savedldflags="$LDFLAGS" + + if test "x$zeroconf" = "xyes" -o "x$zeroconf" = "xtry"; then + zeroconf_dir="/usr" + else + zeroconf_dir="$zeroconf" + fi + + # mDNS support using Apple's Bonjour + 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_dns_sd_DNSServiceRegister" in + yes) + ZEROCONF_LIBS="-L$zeroconf_dir/lib -ldns_sd" + ZEROCONF_LIBS="-I$zeroconf_dir/include" + AC_DEFINE(HAVE_BONJOUR, 1, [Use Bonjour/DNS-SD registration]) + found_zeroconf=yes + ;; + esac + # mDNS support using Porchdog's Howl + AC_CHECK_HEADER(howl.h, + [AC_CHECK_LIB(howl, + sw_discovery_publish, + [AC_DEFINE(USE_ZEROCONF, 1, + [Use DNS-SD registration])])]) + case "$ac_cv_lib_howl_sw_discovery_publish" in + yes) + PKG_CHECK_MODULES(HOWL, [ howl >= 1.0.0 ]) + ZEROCONF_LIBS="$HOWL_LIBS" + ZEROCONF_CFLAGS="$HOWL_CFLAGS" + AC_DEFINE(HAVE_HOWL, 1, [Use Howl/DNS-SD registration]) + found_zeroconf=yes + ;; + esac + # 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])])]) + 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 + + netatalk_cv_zeroconf=no + AC_MSG_CHECKING([whether to enable Zerconf support]) + if test "x$found_zeroconf" = "xyes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE(USE_ZEROCONF, 1, [Define to enable Zeroconf support]) + netatalk_cv_zeroconf=yes + else + AC_MSG_RESULT([no]) + if test "x$zeroconf" != "xno" -a "x$zeroconf" != "xtry"; then + AC_MSG_ERROR([Zeroconf installation not found]) + fi + fi + + LIB_REMOVE_USR_LIB(ZEROCONF_LIBS) + CFLAGS_REMOVE_USR_INCLUDE(ZEROCONF_CFLAGS) + AC_SUBST(ZEROCONF_LIBS) + AC_SUBST(ZEROCONF_CFLAGS) +])