4
dnl Check for optional server location protocol support (used by MacOS X)
7
+dnl Check for optional Zeroconf support
10
dnl Check for PAM libs
11
netatalk_cv_use_pam=no
13
--- a/config/afpd.conf.tmpl
14
+++ b/config/afpd.conf.tmpl
17
# -noslp Don't register this server with the Service
19
+# -nozeroconf Don't register this server with the Multicast
23
# Authentication Methods:
24
--- a/contrib/a2boot/Makefile.am
25
+++ b/contrib/a2boot/Makefile.am
27
EXTRA_DIST = COPYRIGHT VERSION
29
CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
30
- @CFLAGS@ @SLP_CFLAGS@ \
31
+ @CFLAGS@ @SLP_CFLAGS@ @ZEROCONF_CFLAGS@ \
32
-D_PATH_A_GS_BLOCKS=\"$(PKGCONFDIR)/a2boot/ProDOS16\ Boot\ Blocks\" \
33
-D_PATH_A_2E_BLOCKS=\"$(PKGCONFDIR)/a2boot/Apple\ :2f:2fe\ Boot\ Blocks\" \
34
-D_PATH_P16_IMAGE=\"$(PKGCONFDIR)/a2boot/ProDOS16\ Image\"
35
--- a/etc/afpd/Makefile.am
36
+++ b/etc/afpd/Makefile.am
38
file.c enumerate.c desktop.c filedir.c fork.c appl.c gettok.c \
39
mangle.c status.c afp_options.c afp_asp.c afp_dsi.c messages.c \
40
afp_config.c nfsquota.c quota.c uam.c afs.c uid.c afp_util.c \
41
- catsearch.c afprun.c
42
+ catsearch.c afprun.c \
43
+ afp_zeroconf.c afp_avahi.c afp_bonjour.c afp_howl.c
45
afpd_LDADD = $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la
46
afpd_LDFLAGS = -export-dynamic
48
noinst_HEADERS = auth.h afp_config.h desktop.h directory.h file.h \
49
filedir.h fork.h globals.h icon.h mangle.h misc.h status.h switch.h \
50
- uam_auth.h uid.h unix.h volume.h
51
+ uam_auth.h uid.h unix.h volume.h \
52
+ afp_zeroconf.h afp_avahi.h afp_bonjour.h afp_howl.h
54
-LIBS = @LIBS@ @QUOTA_LIBS@ @SLP_LIBS@ @WRAP_LIBS@ @LIBADD_DL@
55
+LIBS = @LIBS@ @QUOTA_LIBS@ @SLP_LIBS@ @ZEROCONF_LIBS@ @WRAP_LIBS@ @LIBADD_DL@
57
CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \
58
- @CFLAGS@ @SLP_CFLAGS@ \
59
+ @CFLAGS@ @SLP_CFLAGS@ @ZEROCONF_CFLAGS@ \
60
-D_PATH_AFPDDEFVOL=\"$(pkgconfdir)/AppleVolumes.default\" \
61
-D_PATH_AFPDSYSVOL=\"$(pkgconfdir)/AppleVolumes.system\" \
62
-D_PATH_AFPDPWFILE=\"$(pkgconfdir)/afppasswd\" \
63
--- a/etc/afpd/afp_config.c
64
+++ b/etc/afpd/afp_config.c
68
#endif /* USE_SRVLOC */
70
+#include "afp_zeroconf.h"
71
+#endif /* USE_ZEROCONF */
74
#include "afp_config.h"
77
#endif /* USE_SRVLOC */
80
static void dsi_cleanup(const AFPConfig *config)
88
dsi->srvloc_url[0] = '\0';
91
+#elif defined (USE_ZEROCONF)
92
+ DSI *dsi = (DSI *)config->obj.handle;
94
+ /* Do nothing if we didn't register. */
95
+ if (!dsi || dsi->zeroconf_registered == 0)
98
+ zeroconf_deregister();
99
#endif /* USE_SRVLOC */
103
static void asp_cleanup(const AFPConfig *config)
105
struct servent *afpovertcp;
107
char *srvloc_hostname, *hostname;
108
+#elif defined (USE_ZEROCONF)
109
+ struct servent *afpovertcp;
110
+ int afp_port = 548;
111
+ char *hostname = NULL;
112
#endif /* USE_SRVLOC */
114
if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
117
#endif /* USE_SRVLOC */
120
+ dsi->zeroconf_registered = 0; /* Mark that we haven't registered. */
122
+ if (!(options->flags & OPTION_NOZEROCONF)) {
123
+ /* XXX We don't want to tack on the port number if we don't have to.
125
+ * Well, this seems to break MacOS < 10. If the user _really_ wants to
126
+ * use a non-default port, they can, but be aware, this server might
127
+ * not show up int the Network Browser.
129
+ afpovertcp = getservbyname("afpovertcp", "tcp");
130
+ if (afpovertcp != NULL) {
131
+ afp_port = ntohs(afpovertcp->s_port);
134
+ /* If specified use the FQDN to register with srvloc, otherwise use IP. */
136
+ if (options->fqdn) {
137
+ hostname = options->fqdn;
138
+ p = strchr(hostname, ':');
141
+ hostname = inet_ntoa(dsi->server.sin_addr);
143
+ if (!(options->flags & OPTION_NOSLP)) {
144
+ zeroconf_register(afp_port, hostname);
145
+ dsi->zeroconf_registered = 1; /* Mark that we have registered. */
148
+#endif /* USE_ZEROCONF */
150
config->fd = dsi->serversock;
151
config->obj.handle = dsi;
154
config->server_cleanup = dsi_cleanup;
157
+ config->server_cleanup = dsi_cleanup;
162
--- a/etc/afpd/afp_options.c
163
+++ b/etc/afpd/afp_options.c
164
@@ -202,10 +202,15 @@
166
if (strstr(buf, " -nodebug"))
167
options->flags &= ~OPTION_DEBUG;
170
if (strstr(buf, " -noslp"))
171
options->flags |= OPTION_NOSLP;
172
#endif /* USE_SRVLOC */
174
+ if (strstr(buf, " -nozeroconf"))
175
+ options->flags |= OPTION_NOZEROCONF;
178
if (strstr(buf, " -nouservolfirst"))
179
options->flags &= ~OPTION_USERVOLFIRST;
190
printf( " TCP wrappers support:\t" );
193
--- a/etc/afpd/globals.h
194
+++ b/etc/afpd/globals.h
196
#define OPTION_CUSTOMICON (1 << 4)
197
#define OPTION_NOSLP (1 << 5)
198
#define OPTION_ANNOUNCESSH (1 << 6)
199
+#define OPTION_NOZEROCONF (1 << 7)
202
/* set up a structure for this */
203
--- a/include/atalk/dsi.h
204
+++ b/include/atalk/dsi.h
206
char srvloc_url[512];
210
+ int zeroconf_registered;
213
/* buffer for OSX deadlock */
216
--- a/macros/summary.m4
217
+++ b/macros/summary.m4
219
AC_MSG_RESULT([ Options:])
220
AC_MSG_RESULT([ CUPS support: $netatalk_cv_use_cups])
221
AC_MSG_RESULT([ SLP support: $netatalk_cv_srvloc])
222
+ AC_MSG_RESULT([ Zeroconf support: $netatalk_cv_zeroconf])
223
AC_MSG_RESULT([ tcp wrapper support: $netatalk_cv_tcpwrap])
224
dnl if test x"$netatalk_cv_linux_sendfile" != x; then
225
dnl AC_MSG_RESULT([ Linux sendfile support: $netatalk_cv_linux_sendfile])
226
--- a/man/man5/afpd.conf.5.tmpl
227
+++ b/man/man5/afpd.conf.5.tmpl
229
Do not register this server using the Service Location Protocol (if SLP
230
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\&.
235
+Do not register this server using the Multicast DNS Protocol (if Zeroconf
236
+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\&.
238
.SH "MISCELLANEOUS OPTIONS"
240
\-admingroup \fI[group]\fR
241
--- a/etc/afpd/afp_avahi.c
242
+++ b/etc/afpd/afp_avahi.c
244
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
246
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
247
+ * Purpose: Avahi based Zeroconf support
248
+ * Docs: http://avahi.org/download/doxygen/
252
+#ifdef HAVE_CONFIG_H
258
+#include "afp_avahi.h"
260
+static void publish_reply(AvahiEntryGroup *g,
261
+ AvahiEntryGroupState state,
265
+ * This function tries to register the AFP DNS
266
+ * SRV service type.
268
+static void register_stuff(struct context *ctx) {
272
+ assert(ctx->client);
276
+ if (!(ctx->group = avahi_entry_group_new(ctx->client,
281
+ "Failed to create entry group: %s\n",
282
+ avahi_strerror(avahi_client_errno(ctx->client)));
288
+ LOG(log_info, logtype_afpd, "Adding service '%s'\n", ctx->name);
290
+ if (avahi_entry_group_is_empty(ctx->group)) {
291
+ /* Register our service */
293
+ if (avahi_entry_group_add_service(ctx->group,
295
+ AVAHI_PROTO_UNSPEC,
298
+ AFP_DNS_SERVICE_TYPE,
305
+ "Failed to add service: %s\n",
306
+ avahi_strerror(avahi_client_errno(ctx->client)));
310
+ if (avahi_entry_group_commit(ctx->group) < 0) {
313
+ "Failed to commit entry group: %s\n",
314
+ avahi_strerror(avahi_client_errno(ctx->client)));
322
+ avahi_client_free (ctx->client);
323
+#ifndef HAVE_AVAHI_THREADED_POLL
324
+ avahi_simple_poll_quit(ctx->simple_poll);
326
+ avahi_threaded_poll_quit(ctx->threaded_poll);
330
+/* Called when publishing of service data completes */
331
+static void publish_reply(AvahiEntryGroup *g,
332
+ AvahiEntryGroupState state,
333
+ AVAHI_GCC_UNUSED void *userdata)
335
+ struct context *ctx = userdata;
337
+ assert(g == ctx->group);
341
+ case AVAHI_ENTRY_GROUP_ESTABLISHED :
342
+ /* The entry group has been established successfully */
345
+ case AVAHI_ENTRY_GROUP_COLLISION: {
348
+ /* Pick a new name for our service */
350
+ n = avahi_alternative_service_name(ctx->name);
353
+ avahi_free(ctx->name);
356
+ register_stuff(ctx);
360
+ case AVAHI_ENTRY_GROUP_FAILURE: {
363
+ "Failed to register service: %s\n",
364
+ avahi_strerror(avahi_client_errno(ctx->client)));
365
+ avahi_client_free (avahi_entry_group_get_client(g));
366
+#ifndef HAVE_AVAHI_THREADED_POLL
367
+ avahi_simple_poll_quit(ctx->simple_poll);
369
+ avahi_threaded_poll_quit(ctx->threaded_poll);
374
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
375
+ case AVAHI_ENTRY_GROUP_REGISTERING:
380
+static void client_callback(AvahiClient *client,
381
+ AvahiClientState state,
384
+ struct context *ctx = userdata;
386
+ ctx->client = client;
390
+ case AVAHI_CLIENT_S_RUNNING:
392
+ /* The server has startup successfully and registered its host
393
+ * name on the network, so it's time to create our services */
395
+ register_stuff(ctx);
398
+ case AVAHI_CLIENT_S_COLLISION:
401
+ avahi_entry_group_reset(ctx->group);
404
+ case AVAHI_CLIENT_FAILURE: {
406
+ if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) {
409
+ avahi_client_free(ctx->client);
410
+ ctx->client = NULL;
413
+ /* Reconnect to the server */
415
+#ifndef HAVE_AVAHI_THREADED_POLL
416
+ if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll),
418
+ if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
420
+ AVAHI_CLIENT_NO_FAIL,
427
+ "Failed to contact server: %s\n",
428
+ avahi_strerror(error));
430
+ avahi_client_free (ctx->client);
431
+#ifndef HAVE_AVAHI_THREADED_POLL
432
+ avahi_simple_poll_quit(ctx->simple_poll);
434
+ avahi_threaded_poll_quit(ctx->threaded_poll);
441
+ "Client failure: %s\n",
442
+ avahi_strerror(avahi_client_errno(client)));
444
+ avahi_client_free (ctx->client);
445
+#ifndef HAVE_AVAHI_THREADED_POLL
446
+ avahi_simple_poll_quit(ctx->simple_poll);
448
+ avahi_threaded_poll_quit(ctx->threaded_poll);
455
+ case AVAHI_CLIENT_S_REGISTERING:
456
+ case AVAHI_CLIENT_CONNECTING:
461
+static void* thread(void *userdata) {
462
+#ifndef HAVE_AVAHI_THREADED_POLL
463
+ struct context *ctx = userdata;
467
+ /* Make sure that signals are delivered to the main thread */
469
+ pthread_sigmask(SIG_BLOCK, &mask, NULL);
471
+ pthread_mutex_lock(&ctx->mutex);
473
+ /* Run the main loop */
474
+ LOG(log_info, logtype_afpd, "Starting avahi loop...");
475
+ r = avahi_simple_poll_loop(ctx->simple_poll);
477
+ /* Cleanup some stuff */
479
+ avahi_client_free(ctx->client);
480
+ ctx->client = NULL;
483
+ pthread_mutex_unlock(&ctx->mutex);
488
+static int poll_func(struct pollfd *ufds,
492
+#ifndef HAVE_AVAHI_THREADED_POLL
493
+ pthread_mutex_t *mutex = userdata;
496
+ /* Before entering poll() we unlock the mutex, so that
497
+ * avahi_simple_poll_quit() can succeed from another thread. */
499
+ pthread_mutex_unlock(mutex);
500
+ r = poll(ufds, nfds, timeout);
501
+ pthread_mutex_lock(mutex);
510
+ * Tries to setup the Zeroconf thread and any
511
+ * neccessary config setting.
513
+void* av_zeroconf_setup(unsigned long port, const char *name) {
514
+ struct context *ctx = NULL;
516
+ /* default service name, if there's none in
519
+ char service[256] = "AFP Server on ";
522
+ /* initialize the struct that holds our
525
+ ctx = malloc(sizeof(struct context));
527
+ ctx->client = NULL;
529
+#ifndef HAVE_AVAHI_THREADED_POLL
530
+ ctx->simple_poll = NULL;
531
+ pthread_mutex_init(&ctx->mutex, NULL);
533
+ ctx->threaded_poll = NULL;
535
+ ctx->thread_running = 0;
539
+ "Setting port for Zeroconf service to: %i.\n",
543
+ /* Prepare service name */
547
+ "Assigning default service name.\n");
548
+ gethostname(service+14, sizeof(service)-15);
549
+ service[sizeof(service)-1] = 0;
551
+ ctx->name = strdup(service);
554
+ ctx->name = strdup(name);
559
+/* first of all we need to initialize our threading env */
560
+#ifdef HAVE_AVAHI_THREADED_POLL
561
+ if (!(ctx->threaded_poll = avahi_threaded_poll_new())) {
565
+ if (!(ctx->simple_poll = avahi_simple_poll_new())) {
568
+ "Failed to create event loop object.\n");
572
+ avahi_simple_poll_set_func(ctx->simple_poll, poll_func, &ctx->mutex);
575
+/* now we need to acquire a client */
576
+#ifdef HAVE_AVAHI_THREADED_POLL
577
+ if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
578
+ AVAHI_CLIENT_NO_FAIL,
584
+ "Failed to create client object: %s\n",
585
+ avahi_strerror(avahi_client_errno(ctx->client)));
589
+ if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll),
590
+ AVAHI_CLIENT_NO_FAIL,
596
+ "Failed to create client object: %s\n",
597
+ avahi_strerror(avahi_client_errno(ctx->client)));
607
+ av_zeroconf_unregister(ctx);
613
+ * This function finally runs the loop impl.
615
+int av_zeroconf_run(void *u) {
616
+ struct context *ctx = u;
619
+#ifdef HAVE_AVAHI_THREADED_POLL
620
+ /* Finally, start the event loop thread */
621
+ if (avahi_threaded_poll_start(ctx->threaded_poll) < 0) {
624
+ "Failed to create thread: %s\n",
625
+ avahi_strerror(avahi_client_errno(ctx->client)));
628
+ LOG(log_info, logtype_afpd, "Successfully started avahi loop.\n");
631
+ /* Create the mDNS event handler */
632
+ if ((ret = pthread_create(&ctx->thread_id, NULL, thread, ctx)) < 0) {
635
+ "Failed to create thread: %s\n", strerror(ret));
638
+ LOG(log_info, logtype_afpd, "Successfully started avahi loop.\n");
642
+ ctx->thread_running = 1;
649
+ av_zeroconf_unregister(ctx);
655
+ * Used to lock access to the loop.
656
+ * Currently unused.
658
+void av_zeroconf_lock(void *u) {
659
+#ifdef HAVE_AVAHI_THREADED_POLL
660
+ struct context *ctx = u;
662
+ avahi_threaded_poll_lock(ctx->threaded_poll);
667
+ * Used to unlock access to the loop.
668
+ * Currently unused.
670
+void av_zeroconf_unlock(void *u) {
671
+#ifdef HAVE_AVAHI_THREADED_POLL
672
+ struct context *ctx = u;
674
+ avahi_threaded_poll_unlock(ctx->threaded_poll);
679
+ * Tries to shutdown this loop impl.
680
+ * Call this function from outside this thread.
682
+void av_zeroconf_shutdown(void *u) {
683
+ struct context *ctx = u;
685
+ /* Call this when the app shuts down */
686
+#ifdef HAVE_AVAHI_THREADED_POLL
687
+ avahi_threaded_poll_stop(ctx->threaded_poll);
688
+ avahi_free(ctx->name);
689
+ avahi_client_free(ctx->client);
690
+ avahi_threaded_poll_free(ctx->threaded_poll);
692
+ av_zeroconf_unregister(ctx);
697
+ * Tries to shutdown this loop impl.
698
+ * Call this function from inside this thread.
700
+int av_zeroconf_unregister(void *u) {
701
+ struct context *ctx = u;
703
+ if (ctx->thread_running) {
704
+#ifndef HAVE_AVAHI_THREADED_POLL
705
+ pthread_mutex_lock(&ctx->mutex);
706
+ avahi_simple_poll_quit(ctx->simple_poll);
707
+ pthread_mutex_unlock(&ctx->mutex);
709
+ pthread_join(ctx->thread_id, NULL);
711
+ /* First, block the event loop */
712
+ avahi_threaded_poll_lock(ctx->threaded_poll);
714
+ /* Than, do your stuff */
715
+ avahi_threaded_poll_quit(ctx->threaded_poll);
717
+ /* Finally, unblock the event loop */
718
+ avahi_threaded_poll_unlock(ctx->threaded_poll);
720
+ ctx->thread_running = 0;
723
+ avahi_free(ctx->name);
726
+ avahi_client_free(ctx->client);
728
+#ifndef HAVE_AVAHI_THREADED_POLL
729
+ if (ctx->simple_poll)
730
+ avahi_simple_poll_free(ctx->simple_poll);
732
+ pthread_mutex_destroy(&ctx->mutex);
734
+ if (ctx->threaded_poll)
735
+ avahi_threaded_poll_free(ctx->threaded_poll);
743
+#endif /* USE_AVAHI */
744
--- a/etc/afpd/afp_avahi.h
745
+++ b/etc/afpd/afp_avahi.h
747
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
749
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
750
+ * Purpose: Avahi based Zeroconf support
751
+ * Docs: http://avahi.org/download/doxygen/
755
+#ifndef AFPD_AVAHI_H
756
+#define AFPD_AVAHI_H
762
+#include <avahi-client/client.h>
763
+#include <avahi-client/publish.h>
765
+#include <avahi-common/alternative.h>
767
+#ifndef HAVE_AVAHI_THREADED_POLL
768
+#include <avahi-common/simple-watch.h>
769
+#include <signal.h> /* SIG_BLOCK */
771
+#include <avahi-common/thread-watch.h>
774
+#include <avahi-common/malloc.h>
775
+#include <avahi-common/error.h>
777
+#include <atalk/logger.h>
779
+#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
782
+ int thread_running;
783
+ pthread_t thread_id;
784
+ pthread_mutex_t mutex;
786
+#ifndef HAVE_AVAHI_THREADED_POLL
787
+ AvahiSimplePoll *simple_poll;
789
+ AvahiThreadedPoll *threaded_poll;
791
+ AvahiClient *client;
792
+ AvahiEntryGroup *group;
793
+ unsigned long port;
796
+/* prototype definitions */
797
+void* av_zeroconf_setup(unsigned long, const char *);
798
+int av_zeroconf_run(void*);
799
+int av_zeroconf_unregister(void*);
800
+void av_zeroconf_shutdown(void*);
801
+void av_zeroconf_lock(void *);
802
+void av_zeroconf_unlock(void *);
804
+#endif /* AFPD_AVAHI_H */
805
--- a/etc/afpd/afp_bonjour.h
806
+++ b/etc/afpd/afp_bonjour.h
808
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
810
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
811
+ * Purpose: Bonjour based Zeroconf support
812
+ * Docs: http://developer.apple.com/documentation/Networking/Reference/DNSServiceDiscovery_CRef/dns_sd/
816
+#ifndef AFPD_BONJOUR_H
817
+#define AFPD_BONJOUR_H
823
+#include <dns_sd.h> /* DNSServiceRegister(), DNSServiceDiscoveryDeallocate() */
825
+#include <atalk/logger.h>
827
+#define AFP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
829
+/* prototype definitions */
830
+void* bo_zeroconf_setup(unsigned long, const char *);
831
+int bo_zeroconf_unregister(void);
832
+int bo_zeroconf_run(void);
834
+#endif /* AFPD_BONJOUR_H */
835
--- a/etc/afpd/afp_bonjour.c
836
+++ b/etc/afpd/afp_bonjour.c
838
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
840
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
841
+ * Purpose: Bonjour based Zeroconf support
842
+ * Docs: http://developer.apple.com/documentation/Networking/Reference/DNSServiceDiscovery_CRef/dns_sd/
846
+#ifdef HAVE_CONFIG_H
852
+#include "afp_bonjour.h"
854
+DNSServiceRef publish_session = NULL;
856
+static void DNSSD_API
857
+publish_reply(DNSServiceRef,
858
+ const DNSServiceFlags,
859
+ DNSServiceErrorType,
865
+static void DNSSD_API
866
+publish_reply (DNSServiceRef sdRef,
867
+ const DNSServiceFlags flags,
868
+ DNSServiceErrorType errorCode,
870
+ const char *regtype,
871
+ const char *domain,
876
+void* bo_zeroconf_setup(unsigned long port, const char *name) {
877
+ DNSServiceErrorType err;
878
+ char service[256] = "AFP Server on ";
880
+ /* Prepare service name */
882
+ LOG(log_info, logtype_afpd,, "Assigning default service name.\n");
883
+ gethostname(service+14, sizeof(service)-15);
884
+ service[sizeof(service)-1] = 0;
886
+ name = strdup(service);
892
+ err = DNSServiceRegister (&publish_session,
894
+ 0, /* interface; 0 for all */
896
+ AFP_DNS_SERVICE_TYPE, /* type */
898
+ NULL, /* hostname */
899
+ htons (port), /* port in network byte order */
900
+ 0, /* text record length */
901
+ NULL, /* text record */
902
+ publish_reply, /* callback */
903
+ NULL); /* context */
905
+ if (err == kDNSServiceErr_NoError) {
906
+ LOG(log_info, logtype_afpd, "Adding service '%s'\n", name);
908
+ LOG(log_error, logtype_afpd, "Adding service '%s' failed\n", name);
909
+ bo_zeroconf_unregister();
913
+int bo_zeroconf_run(void) {
916
+ struct timeval timeout;
918
+ /* Initialize the file descriptor set. */
922
+ /* Initialize the timeout data structure. */
923
+ /* TODO: Should the value for sec be configurable? */
924
+ timeout.tv_sec = 10;
925
+ timeout.tv_usec = 0;
927
+ if (publish_session != NULL) {
928
+ fd = DNSServiceRefSockFD(publish_session);
930
+ if (select(FD_SETSIZE,
933
+ DNSServiceProcessResult(publish_session);
940
+int bo_zeroconf_unregister(void) {
941
+ if (publish_session != NULL) {
942
+ DNSServiceRefDeallocate(publish_session);
943
+ publish_session = NULL;
949
+#endif /* HAVE_BONJOUR */
950
--- a/etc/afpd/afp_howl.c
951
+++ b/etc/afpd/afp_howl.c
953
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
955
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
956
+ * Purpose: Howl based Zeroconf support
957
+ * Doc: http://www.porchdogsoft.com/products/howl/docs/
961
+#ifdef HAVE_CONFIG_H
967
+#include "afp_howl.h"
969
+sw_discovery discovery = NULL;
971
+static sw_result HOWL_API publish_reply(sw_discovery,
973
+ sw_discovery_publish_status,
976
+static sw_result HOWL_API publish_reply(sw_discovery discovery,
977
+ sw_discovery_oid oid,
978
+ sw_discovery_publish_status status,
989
+ LOG(log_info, logtype_afpd, "publish reply: %s\n", status_text[status]);
993
+void* ho_zeroconf_setup(unsigned long port, const char *name) {
995
+ sw_discovery_publish_id id;
996
+ char service[256] = "AFP Server on ";
998
+ if (sw_discovery_init (&discovery) != SW_OKAY) {
1001
+ "AFPD could not be started. \nTry running mDNSResponder.");
1005
+ /* Prepare service name */
1007
+ LOG(log_info, logtype_afpd, "Assigning default service name.\n");
1008
+ gethostname(service+14, sizeof(service)-15);
1009
+ service[sizeof(service)-1] = 0;
1011
+ name = strdup(service);
1016
+ if (!(result = sw_discovery_publish (discovery,
1019
+ AFP_DNS_SERVICE_TYPE,
1027
+ &id)) != SW_OKAY) {
1028
+ LOG(log_info, logtype_afpd, "Adding service '%s'\n", name);
1030
+ LOG(log_error, logtype_afpd, "Adding service '%s' failed\n", name);
1031
+ ho_zeroconf_unregister();
1035
+void* ho_zeroconf_run(void) {
1036
+ sw_discovery_run(discovery);
1039
+void* ho_zeroconf_unregister(void) {
1040
+ sw_discovery_stop_run(discovery);
1041
+ sw_discovery_fina(discovery);
1044
+#endif /* USE_HOWL */
1045
--- a/etc/afpd/afp_howl.h
1046
+++ b/etc/afpd/afp_howl.h
1048
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
1050
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
1051
+ * Purpose: Howl based Zeroconf support
1052
+ * Doc: http://www.porchdogsoft.com/products/howl/docs/
1056
+#ifndef AFPD_HOWL_H
1057
+#define AFPD_HOWL_H
1059
+#include <stdlib.h>
1060
+#include <assert.h>
1061
+#include <string.h>
1065
+#include <atalk/logger.h>
1067
+#define NTP_DNS_SERVICE_TYPE "_afpovertcp._tcp"
1069
+/* prototype definitions */
1070
+void* ho_zeroconf_setup(unsigned long, const char *);
1071
+void* ho_zeroconf_unregister(void);
1072
+void* ho_zeroconf_run(void);
1074
+#endif /* AFPD_HOWL_H */
1075
--- a/etc/afpd/afp_zeroconf.h
1076
+++ b/etc/afpd/afp_zeroconf.h
1078
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
1080
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
1081
+ * Purpose: Zeroconf facade, that abstracts access to a
1082
+ * particular Zeroconf implementation
1083
+ * Doc: http://www.dns-sd.org/
1087
+#ifndef AFPD_ZEROCONF_H
1088
+#define AFPD_ZEROCONF_H
1090
+#include <netinet/in.h> /* htons() */
1091
+#include <atalk/logger.h>
1093
+# ifdef HAVE_BONJOUR
1094
+# include "afp_bonjour.h"
1095
+# elif defined (HAVE_HOWL)
1096
+# include "afp_howl.h"
1097
+# elif defined (HAVE_AVAHI)
1098
+# include "afp_avahi.h"
1101
+#define AFP_PORT 548
1104
+ * Prototype Definitions
1108
+ * registers the ntpd service with a particular Zerconf implemenation.
1110
+void zeroconf_register(int port, char *hostname);
1113
+ * de-registers the ntpd service with a particular Zerconf implemenation.
1115
+void zeroconf_deregister(void);
1117
+#endif AFPD_ZEROCONF_H
1118
--- a/etc/afpd/afp_zeroconf.c
1119
+++ b/etc/afpd/afp_zeroconf.c
1121
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
1123
+ * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
1124
+ * Purpose: Zeroconf facade, that abstracts access to a
1125
+ * particular Zeroconf implementation
1126
+ * Doc: http://www.dns-sd.org/
1130
+#ifdef HAVE_CONFIG_H
1131
+#include <config.h>
1134
+#include "afp_zeroconf.h"
1137
+ * Global Definitions
1140
+struct context *ctx = NULL;
1144
+ * Functions (actually they are just facades)
1146
+void zeroconf_register(int port, char *hostname)
1148
+#ifdef HAVE_BONJOUR
1151
+ "Attempting to register with mDNS using Apple's Bonjour\n");
1152
+ if (hostname && strlen(hostname) > 0 && port)
1154
+ bo_zeroconf_setup(port, hostname);
1156
+ else if (hostname && strlen(hostname) > 0)
1158
+ bo_zeroconf_setup(AFP_PORT, hostname);
1162
+ bo_zeroconf_setup(AFP_PORT, NULL);
1164
+ bo_zeroconf_run();
1165
+#elif defined (HAVE_HOWL)
1168
+ "Attempting to register with mDNS using Porchdog's Howl\n");
1169
+ if (hostname && strlen(hostname) > 0 && port)
1171
+ ho_zeroconf_setup(port, hostname);
1173
+ else if (hostname && strlen(hostname) > 0)
1175
+ ho_zeroconf_setup(AFP_PORT, hostname);
1179
+ ho_zeroconf_setup(AFP_PORT, NULL);
1181
+ bo_zeroconf_run();
1182
+#elif defined (HAVE_AVAHI)
1183
+ LOG(log_info, logtype_afpd, "Attempting to register with mDNS using Avahi\n");
1184
+ if (hostname && strlen(hostname) > 0 && port)
1186
+ ctx = av_zeroconf_setup(port, hostname);
1188
+ else if (hostname && strlen(hostname) > 0)
1190
+ ctx = av_zeroconf_setup(AFP_PORT, hostname);
1194
+ ctx = av_zeroconf_setup(AFP_PORT, NULL);
1196
+ av_zeroconf_run(ctx);
1200
+void zeroconf_deregister(void)
1202
+#ifdef HAVE_BONJOUR
1205
+ "Attempting to de-register mDNS using Apple's Bonjour\n");
1206
+ bo_zeroconf_unregister();
1207
+#elif defined (HAVE_HOWL)
1210
+ "Attempting to de-register mDNS using Porchdog's Howl\n");
1211
+ ho_zeroconf_unregister();
1212
+#elif defined (HAVE_AVAHI)
1213
+ LOG(log_error, logtype_afpd, "Attempting to de-register mDNS using Avahi\n");
1215
+ av_zeroconf_shutdown(ctx);
1218
--- a/macros/zeroconf.m4
1219
+++ b/macros/zeroconf.m4
1221
+dnl Check for optional Zeroconf support
1225
+AC_DEFUN([NETATALK_ZEROCONF], [
1228
+ ZEROCONF_CFLAGS=""
1232
+ AC_ARG_ENABLE(zeroconf,
1233
+ [ --enable-zeroconf[[=DIR]] enable Zeroconf support [[auto]]],
1234
+ [zeroconf=$enableval],
1238
+ dnl make sure atalk_libname is defined beforehand
1239
+ [[ -n "$atalk_libname" ]] || AC_MSG_ERROR([internal error, atalk_libname undefined])
1241
+ if test "x$zeroconf" != "xno"; then
1243
+ savedcppflags="$CPPFLAGS"
1244
+ savedldflags="$LDFLAGS"
1246
+ if test "x$zeroconf" = "xyes" -o "x$zeroconf" = "xtry"; then
1247
+ zeroconf_dir="/usr"
1249
+ zeroconf_dir="$zeroconf"
1252
+ # mDNS support using Apple's Bonjour
1253
+ AC_CHECK_HEADER(dns_sd.h,
1254
+ [AC_CHECK_LIB(dns_sd,
1255
+ DNSServiceRegister,
1256
+ [AC_DEFINE(USE_ZEROCONF, 1,
1257
+ [Use DNS-SD registration])])])
1258
+ case "$ac_cv_lib_dns_sd_DNSServiceRegister" in
1260
+ ZEROCONF_LIBS="-L$zeroconf_dir/lib -ldns_sd"
1261
+ ZEROCONF_LIBS="-I$zeroconf_dir/include"
1262
+ AC_DEFINE(HAVE_BONJOUR, 1, [Use Bonjour/DNS-SD registration])
1263
+ found_zeroconf=yes
1266
+ # mDNS support using Porchdog's Howl
1267
+ AC_CHECK_HEADER(howl.h,
1268
+ [AC_CHECK_LIB(howl,
1269
+ sw_discovery_publish,
1270
+ [AC_DEFINE(USE_ZEROCONF, 1,
1271
+ [Use DNS-SD registration])])])
1272
+ case "$ac_cv_lib_howl_sw_discovery_publish" in
1274
+ PKG_CHECK_MODULES(HOWL, [ howl >= 1.0.0 ])
1275
+ ZEROCONF_LIBS="$HOWL_LIBS"
1276
+ ZEROCONF_CFLAGS="$HOWL_CFLAGS"
1277
+ AC_DEFINE(HAVE_HOWL, 1, [Use Howl/DNS-SD registration])
1278
+ found_zeroconf=yes
1281
+ # mDNS support using Avahi
1282
+ AC_CHECK_HEADER(avahi-client/client.h,
1283
+ [AC_CHECK_LIB(avahi-client,
1285
+ [AC_DEFINE(USE_ZEROCONF, 1,
1286
+ [Use DNS-SD registration])])])
1287
+ case "$ac_cv_lib_avahi_client_avahi_client_new" in
1289
+ PKG_CHECK_MODULES(AVAHI, [ avahi-client >= 0.6 ])
1290
+ PKG_CHECK_MODULES(AVAHI_TPOLL, [ avahi-client >= 0.6.4 ],
1291
+ [AC_DEFINE(HAVE_AVAHI_THREADED_POLL, 1, [Uses Avahis threaded poll implementation])],
1292
+ [AC_MSG_WARN(This Avahi implementation is not supporting threaded poll objects. Maybe this is not what you want.)])
1293
+ ZEROCONF_LIBS="$AVAHI_LIBS"
1294
+ ZEROCONF_CFLAGS="$AVAHI_CFLAGS"
1295
+ AC_DEFINE(HAVE_AVAHI, 1, [Use Avahi/DNS-SD registration])
1296
+ found_zeroconf=yes
1300
+ CPPFLAGS="$savedcppflags"
1301
+ LDFLAGS="$savedldflags"
1304
+ netatalk_cv_zeroconf=no
1305
+ AC_MSG_CHECKING([whether to enable Zerconf support])
1306
+ if test "x$found_zeroconf" = "xyes"; then
1307
+ AC_MSG_RESULT([yes])
1308
+ AC_DEFINE(USE_ZEROCONF, 1, [Define to enable Zeroconf support])
1309
+ netatalk_cv_zeroconf=yes
1311
+ AC_MSG_RESULT([no])
1312
+ if test "x$zeroconf" != "xno" -a "x$zeroconf" != "xtry"; then
1313
+ AC_MSG_ERROR([Zeroconf installation not found])
1317
+ LIB_REMOVE_USR_LIB(ZEROCONF_LIBS)
1318
+ CFLAGS_REMOVE_USR_INCLUDE(ZEROCONF_CFLAGS)
1319
+ AC_SUBST(ZEROCONF_LIBS)
1320
+ AC_SUBST(ZEROCONF_CFLAGS)