1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
3 * Author: Daniel S. Haischt <me@daniel.stefan.haischt.name>
4 * Purpose: Avahi based Zeroconf support
5 * Docs: http://avahi.org/download/doxygen/
17 #include <atalk/logger.h>
18 #include <atalk/util.h>
19 #include <atalk/dsi.h>
21 #include "afp_avahi.h"
22 #include "afp_config.h"
24 /*****************************************************************
26 *****************************************************************/
27 struct context *ctx = NULL;
29 /*****************************************************************
31 *****************************************************************/
33 static void publish_reply(AvahiEntryGroup *g,
34 AvahiEntryGroupState state,
38 * This function tries to register the AFP DNS
41 static void register_stuff(void) {
42 const AFPConfig *config;
47 if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
48 LOG(log_error, logtype_afpd, "Failed to create entry group: %s",
49 avahi_strerror(avahi_client_errno(ctx->client)));
54 if (avahi_entry_group_is_empty(ctx->group)) {
55 /* Register our service */
58 for (config = ctx->configs; config; config = config->next) {
59 dsi = (DSI *)config->obj.handle;
60 if (avahi_entry_group_add_service(ctx->group,
64 config->obj.options.server ?
65 config->obj.options.server
66 : config->obj.options.hostname,
70 getip_port((struct sockaddr *)&dsi->server),
72 LOG(log_error, logtype_afpd, "Failed to add service: %s",
73 avahi_strerror(avahi_client_errno(ctx->client)));
81 if (avahi_entry_group_commit(ctx->group) < 0) {
82 LOG(log_error, logtype_afpd, "Failed to commit entry group: %s",
83 avahi_strerror(avahi_client_errno(ctx->client)));
87 } /* if avahi_entry_group_is_empty*/
92 avahi_client_free (ctx->client);
93 avahi_threaded_poll_quit(ctx->threaded_poll);
96 /* Called when publishing of service data completes */
97 static void publish_reply(AvahiEntryGroup *g,
98 AvahiEntryGroupState state,
99 AVAHI_GCC_UNUSED void *userdata)
101 assert(ctx->group == NULL || g == ctx->group);
105 case AVAHI_ENTRY_GROUP_ESTABLISHED :
106 /* The entry group has been established successfully */
107 LOG(log_debug, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_ESTABLISHED");
110 case AVAHI_ENTRY_GROUP_COLLISION:
111 /* With multiple names there's no way to know which one collided */
112 LOG(log_error, logtype_afpd, "publish_reply: AVAHI_ENTRY_GROUP_COLLISION",
113 avahi_strerror(avahi_client_errno(ctx->client)));
114 avahi_client_free(avahi_entry_group_get_client(g));
115 avahi_threaded_poll_quit(ctx->threaded_poll);
118 case AVAHI_ENTRY_GROUP_FAILURE:
119 LOG(log_error, logtype_afpd, "Failed to register service: %s",
120 avahi_strerror(avahi_client_errno(ctx->client)));
121 avahi_client_free(avahi_entry_group_get_client(g));
122 avahi_threaded_poll_quit(ctx->threaded_poll);
125 case AVAHI_ENTRY_GROUP_UNCOMMITED:
127 case AVAHI_ENTRY_GROUP_REGISTERING:
132 static void client_callback(AvahiClient *client,
133 AvahiClientState state,
136 ctx->client = client;
139 case AVAHI_CLIENT_S_RUNNING:
140 /* The server has startup successfully and registered its host
141 * name on the network, so it's time to create our services */
146 case AVAHI_CLIENT_S_COLLISION:
148 avahi_entry_group_reset(ctx->group);
151 case AVAHI_CLIENT_FAILURE: {
152 if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) {
155 avahi_client_free(ctx->client);
159 /* Reconnect to the server */
160 if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
161 AVAHI_CLIENT_NO_FAIL,
166 LOG(log_error, logtype_afpd, "Failed to contact server: %s",
167 avahi_strerror(error));
169 avahi_client_free (ctx->client);
170 avahi_threaded_poll_quit(ctx->threaded_poll);
174 LOG(log_error, logtype_afpd, "Client failure: %s",
175 avahi_strerror(avahi_client_errno(client)));
176 avahi_client_free (ctx->client);
177 avahi_threaded_poll_quit(ctx->threaded_poll);
182 case AVAHI_CLIENT_S_REGISTERING:
184 case AVAHI_CLIENT_CONNECTING:
189 /************************************************************************
191 ************************************************************************/
194 * Tries to setup the Zeroconf thread and any
195 * neccessary config setting.
197 void av_zeroconf_setup(const AFPConfig *configs) {
200 /* initialize the struct that holds our config settings. */
202 ctx = calloc(1, sizeof(struct context));
203 ctx->configs = configs;
207 /* first of all we need to initialize our threading env */
208 if (!(ctx->threaded_poll = avahi_threaded_poll_new())) {
212 /* now we need to acquire a client */
213 if (!(ctx->client = avahi_client_new(avahi_threaded_poll_get(ctx->threaded_poll),
214 AVAHI_CLIENT_NO_FAIL,
218 LOG(log_error, logtype_afpd, "Failed to create client object: %s",
219 avahi_strerror(avahi_client_errno(ctx->client)));
227 av_zeroconf_unregister();
233 * This function finally runs the loop impl.
235 int av_zeroconf_run(void) {
238 /* Finally, start the event loop thread */
239 if (avahi_threaded_poll_start(ctx->threaded_poll) < 0) {
240 LOG(log_error, logtype_afpd, "Failed to create thread: %s",
241 avahi_strerror(avahi_client_errno(ctx->client)));
244 LOG(log_info, logtype_afpd, "Successfully started avahi loop.");
247 ctx->thread_running = 1;
252 av_zeroconf_unregister();
258 * Tries to shutdown this loop impl.
259 * Call this function from outside this thread.
261 void av_zeroconf_shutdown() {
262 /* Call this when the app shuts down */
263 avahi_threaded_poll_stop(ctx->threaded_poll);
264 avahi_client_free(ctx->client);
265 avahi_threaded_poll_free(ctx->threaded_poll);
269 * Tries to shutdown this loop impl.
270 * Call this function from inside this thread.
272 int av_zeroconf_unregister() {
273 if (ctx->thread_running) {
274 /* First, block the event loop */
275 avahi_threaded_poll_lock(ctx->threaded_poll);
277 /* Than, do your stuff */
278 avahi_threaded_poll_quit(ctx->threaded_poll);
280 /* Finally, unblock the event loop */
281 avahi_threaded_poll_unlock(ctx->threaded_poll);
282 ctx->thread_running = 0;
286 avahi_client_free(ctx->client);
288 if (ctx->threaded_poll)
289 avahi_threaded_poll_free(ctx->threaded_poll);
296 #endif /* USE_AVAHI */