X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fafp_avahi.c;h=89ff95fdca66bf01ee8bc2dfa360bd9fb643623c;hb=df7560dfdb12b06090dc4b2c6e88d0858930b591;hp=de4126ecb770c2feef64c4fcaf4ed1139cf4cba8;hpb=156269e3a96be9b7b199017331fef52f76779931;p=netatalk.git diff --git a/etc/afpd/afp_avahi.c b/etc/afpd/afp_avahi.c index de4126ec..89ff95fd 100644 --- a/etc/afpd/afp_avahi.c +++ b/etc/afpd/afp_avahi.c @@ -1,4 +1,3 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ /* * Author: Daniel S. Haischt * Purpose: Avahi based Zeroconf support @@ -13,6 +12,7 @@ #ifdef HAVE_AVAHI #include +#include #include @@ -43,96 +43,142 @@ static void publish_reply(AvahiEntryGroup *g, * SRV service type. */ static void register_stuff(void) { - uint port; - const AFPConfig *config; - const struct vol *volume; - DSI *dsi; - const char *name; - AvahiStringList *strlist = NULL; - char tmpname[256]; - - 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", - avahi_strerror(avahi_client_errno(ctx->client))); - goto fail; + uint port; + const AFPConfig *config; + const struct vol *volume; + DSI *dsi; + char name[MAXINSTANCENAMELEN+1]; + AvahiStringList *strlist = NULL; + AvahiStringList *strlist2 = NULL; + char tmpname[256]; + + 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", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } } - } - if (avahi_entry_group_is_empty(ctx->group)) { - /* Register our service */ + if (avahi_entry_group_is_empty(ctx->group)) { + /* Register our service */ - /* Build AFP volumes list */ - int i = 0; - strlist = avahi_string_list_add_printf(strlist, "sys=waMa=0,adVF=0x100"); + /* Build AFP volumes list */ + int i = 0; + strlist = avahi_string_list_add_printf(strlist, "sys=waMa=0,adVF=0x100"); - for (volume = getvolumes(); volume; volume = volume->v_next) { - - if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_name, -1, tmpname, 255) <= 0) - goto fail; - - if ((volume->v_flags & AFPVOL_TM) && volume->v_uuid) { - LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine", - volume->v_localname, volume->v_uuid); - strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1,adVU=%s", - i++, tmpname, volume->v_uuid); - } - } - - /* AFP server */ - for (config = ctx->configs; config; config = config->next) { - - dsi = (DSI *)config->obj.handle; - name = config->obj.options.server ? - config->obj.options.server : config->obj.options.hostname; - port = getip_port((struct sockaddr *)&dsi->server); - - if (avahi_entry_group_add_service(ctx->group, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - 0, - name, - AFP_DNS_SERVICE_TYPE, - NULL, - NULL, - port, - NULL) < 0) { - LOG(log_error, logtype_afpd, "Failed to add service: %s", - avahi_strerror(avahi_client_errno(ctx->client))); - goto fail; - } - - if (avahi_entry_group_add_service_strlst(ctx->group, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - 0, - name, - "_adisk._tcp", - NULL, - NULL, - 311, /* serveradmin, peaked from os x 10.6 server */ - strlist) < 0) { - LOG(log_error, logtype_afpd, "Failed to add service: %s", - avahi_strerror(avahi_client_errno(ctx->client))); - goto fail; - } /* if */ - } /* for config*/ - - 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; + 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); + strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1,adVU=%s", + i++, tmpname, volume->v_uuid); + } else { + LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.", + volume->v_localname); + strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1", + i++, tmpname); + } + } + } + + /* AFP server */ + for (config = ctx->configs; config; config = config->next) { + + dsi = (DSI *)config->obj.dsi; + 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); + + if (avahi_entry_group_add_service(ctx->group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + 0, + dsi->bonjourname, + AFP_DNS_SERVICE_TYPE, + NULL, + NULL, + port, + NULL) < 0) { + LOG(log_error, logtype_afpd, "Failed to add service: %s", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } + + if (i && avahi_entry_group_add_service_strlst(ctx->group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + 0, + dsi->bonjourname, + ADISK_SERVICE_TYPE, + NULL, + NULL, + 9, /* discard */ + strlist) < 0) { + LOG(log_error, logtype_afpd, "Failed to add service: %s", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } /* if */ + + if (config->obj.options.mimicmodel) { + strlist2 = avahi_string_list_add_printf(strlist2, "model=%s", config->obj.options.mimicmodel); + if (avahi_entry_group_add_service_strlst(ctx->group, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + 0, + dsi->bonjourname, + DEV_INFO_SERVICE_TYPE, + NULL, + NULL, + 0, + strlist2) < 0) { + LOG(log_error, logtype_afpd, "Failed to add service: %s", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } + } /* if (config->obj.options.mimicmodel) */ + + } /* for config*/ + + 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; fail: - avahi_client_free (ctx->client); - avahi_threaded_poll_quit(ctx->threaded_poll); + time(NULL); +// avahi_threaded_poll_quit(ctx->threaded_poll); } /* Called when publishing of service data completes */ @@ -140,92 +186,88 @@ static void publish_reply(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) { - 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: - /* 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; + 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: + /* 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_threaded_poll_quit(ctx->threaded_poll); + break; - case AVAHI_ENTRY_GROUP_FAILURE: - LOG(log_error, logtype_afpd, "Failed to register service: %s", - 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_UNCOMMITED: - break; - case AVAHI_ENTRY_GROUP_REGISTERING: - break; - } + case AVAHI_ENTRY_GROUP_FAILURE: + LOG(log_error, logtype_afpd, "Failed to register service: %s", + avahi_strerror(avahi_client_errno(ctx->client))); + avahi_threaded_poll_quit(ctx->threaded_poll); + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + break; + case AVAHI_ENTRY_GROUP_REGISTERING: + break; + } } static void client_callback(AvahiClient *client, AvahiClientState state, void *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(); - 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 */ - 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 contact server: %s", - avahi_strerror(error)); + 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(); + 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 */ + 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 contact server: %s", + avahi_strerror(error)); + + avahi_threaded_poll_quit(ctx->threaded_poll); + } + + } else { + LOG(log_error, logtype_afpd, "Client failure: %s", + avahi_strerror(avahi_client_errno(client))); + avahi_threaded_poll_quit(ctx->threaded_poll); + } + break; + } - avahi_client_free (ctx->client); - avahi_threaded_poll_quit(ctx->threaded_poll); - } - - } else { - 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); - } - break; - } - - case AVAHI_CLIENT_S_REGISTERING: - break; - case AVAHI_CLIENT_CONNECTING: - break; - } + case AVAHI_CLIENT_S_REGISTERING: + break; + case AVAHI_CLIENT_CONNECTING: + break; + } } /************************************************************************ @@ -236,75 +278,50 @@ static void client_callback(AvahiClient *client, * Tries to setup the Zeroconf thread and any * neccessary config setting. */ -void av_zeroconf_setup(const AFPConfig *configs) { - int error, ret; - - /* initialize the struct that holds our config settings. */ - if (!ctx) { - ctx = calloc(1, sizeof(struct context)); - ctx->configs = configs; - } - assert(ctx); +void av_zeroconf_register(const AFPConfig *configs) { + int error; + + /* initialize the struct that holds our config settings. */ + if (ctx) { + LOG(log_debug, logtype_afpd, "Resetting zeroconf records"); + avahi_entry_group_reset(ctx->group); + } else { + ctx = calloc(1, sizeof(struct context)); + ctx->configs = configs; + assert(ctx); + } /* first of all we need to initialize our threading env */ - if (!(ctx->threaded_poll = avahi_threaded_poll_new())) { - goto fail; - } + if (!(ctx->threaded_poll = avahi_threaded_poll_new())) { + goto fail; + } /* now we need to acquire a client */ - if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll), - AVAHI_CLIENT_NO_FAIL, - client_callback, - NULL, - &error))) { - LOG(log_error, logtype_afpd, "Failed to create client object: %s", - avahi_strerror(avahi_client_errno(ctx->client))); - goto fail; - } - - return; - -fail: - if (ctx) - av_zeroconf_unregister(); - - return; -} - -/* - * This function finally runs the loop impl. - */ -int av_zeroconf_run(void) { - int ret; + if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll), + AVAHI_CLIENT_NO_FAIL, + client_callback, + NULL, + &error))) { + LOG(log_error, logtype_afpd, "Failed to create client object: %s", + avahi_strerror(error)); + goto fail; + } - /* 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", - avahi_strerror(avahi_client_errno(ctx->client))); - goto fail; - } else { - LOG(log_info, logtype_afpd, "Successfully started avahi loop."); - } + if (avahi_threaded_poll_start(ctx->threaded_poll) < 0) { + LOG(log_error, logtype_afpd, "Failed to create thread: %s", + avahi_strerror(avahi_client_errno(ctx->client))); + goto fail; + } else { + LOG(log_info, logtype_afpd, "Successfully started avahi loop."); + } - ctx->thread_running = 1; - return 0; + ctx->thread_running = 1; + return; fail: - if (ctx) av_zeroconf_unregister(); - return -1; -} - -/* - * Tries to shutdown this loop impl. - * Call this function from outside this thread. - */ -void av_zeroconf_shutdown() { - /* Call this when the app shuts down */ - avahi_threaded_poll_stop(ctx->threaded_poll); - avahi_client_free(ctx->client); - avahi_threaded_poll_free(ctx->threaded_poll); + return; } /* @@ -312,27 +329,23 @@ void av_zeroconf_shutdown() { * Call this function from inside this thread. */ int av_zeroconf_unregister() { - if (ctx->thread_running) { - /* 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); - ctx->thread_running = 0; - } - - if (ctx->client) - avahi_client_free(ctx->client); - - if (ctx->threaded_poll) - avahi_threaded_poll_free(ctx->threaded_poll); - - free(ctx); - - return 0; + LOG(log_error, logtype_afpd, "av_zeroconf_unregister"); + + if (ctx) { + LOG(log_error, logtype_afpd, "av_zeroconf_unregister: avahi_threaded_poll_stop"); + if (ctx->threaded_poll) + avahi_threaded_poll_stop(ctx->threaded_poll); + LOG(log_error, logtype_afpd, "av_zeroconf_unregister: avahi_client_free"); + if (ctx->client) + avahi_client_free(ctx->client); + LOG(log_error, logtype_afpd, "av_zeroconf_unregister: avahi_threaded_poll_free"); + if (ctx->threaded_poll) + avahi_threaded_poll_free(ctx->threaded_poll); + free(ctx); + ctx = NULL; + } + return 0; } #endif /* USE_AVAHI */ +