diff options
Diffstat (limited to 'source3/lib/avahi.c')
-rw-r--r-- | source3/lib/avahi.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/source3/lib/avahi.c b/source3/lib/avahi.c new file mode 100644 index 0000000..269b329 --- /dev/null +++ b/source3/lib/avahi.c @@ -0,0 +1,275 @@ +/* + Unix SMB/CIFS implementation. + Connect avahi to lib/tevents + Copyright (C) Volker Lendecke 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" + +#include <avahi-common/watch.h> + +struct avahi_poll_context { + struct tevent_context *ev; + AvahiWatch **watches; + AvahiTimeout **timeouts; +}; + +struct AvahiWatch { + struct avahi_poll_context *ctx; + struct tevent_fd *fde; + int fd; + AvahiWatchEvent latest_event; + AvahiWatchCallback callback; + void *userdata; +}; + +struct AvahiTimeout { + struct avahi_poll_context *ctx; + struct tevent_timer *te; + AvahiTimeoutCallback callback; + void *userdata; +}; + +static uint16_t avahi_flags_map_to_tevent(AvahiWatchEvent event) +{ + return ((event & AVAHI_WATCH_IN) ? TEVENT_FD_READ : 0) + | ((event & AVAHI_WATCH_OUT) ? TEVENT_FD_WRITE : 0); +} + +static void avahi_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, uint16_t flags, + void *private_data); + +static AvahiWatch *avahi_watch_new(const AvahiPoll *api, int fd, + AvahiWatchEvent event, + AvahiWatchCallback callback, + void *userdata) +{ + struct avahi_poll_context *ctx = talloc_get_type_abort( + api->userdata, struct avahi_poll_context); + int num_watches = talloc_array_length(ctx->watches); + AvahiWatch **tmp, *watch_ctx; + + tmp = talloc_realloc(ctx, ctx->watches, AvahiWatch *, num_watches + 1); + if (tmp == NULL) { + return NULL; + } + ctx->watches = tmp; + + watch_ctx = talloc(tmp, AvahiWatch); + if (watch_ctx == NULL) { + goto fail; + } + ctx->watches[num_watches] = watch_ctx; + + watch_ctx->ctx = ctx; + watch_ctx->fde = tevent_add_fd(ctx->ev, watch_ctx, fd, + avahi_flags_map_to_tevent(event), + avahi_fd_handler, watch_ctx); + if (watch_ctx->fde == NULL) { + goto fail; + } + watch_ctx->callback = callback; + watch_ctx->userdata = userdata; + return watch_ctx; + + fail: + TALLOC_FREE(watch_ctx); + ctx->watches = talloc_realloc(ctx, ctx->watches, AvahiWatch *, + num_watches); + return NULL; +} + +static void avahi_fd_handler(struct tevent_context *ev, + struct tevent_fd *fde, uint16_t flags, + void *private_data) +{ + AvahiWatch *watch_ctx = talloc_get_type_abort(private_data, AvahiWatch); + + watch_ctx->latest_event = + ((flags & TEVENT_FD_READ) ? AVAHI_WATCH_IN : 0) + | ((flags & TEVENT_FD_WRITE) ? AVAHI_WATCH_OUT : 0); + + watch_ctx->callback(watch_ctx, watch_ctx->fd, watch_ctx->latest_event, + watch_ctx->userdata); +} + +static void avahi_watch_update(AvahiWatch *w, AvahiWatchEvent event) +{ + tevent_fd_set_flags(w->fde, avahi_flags_map_to_tevent(event)); +} + +static AvahiWatchEvent avahi_watch_get_events(AvahiWatch *w) +{ + return w->latest_event; +} + +static void avahi_watch_free(AvahiWatch *w) +{ + int i, num_watches; + AvahiWatch **watches = w->ctx->watches; + struct avahi_poll_context *ctx; + + num_watches = talloc_array_length(watches); + + for (i=0; i<num_watches; i++) { + if (w == watches[i]) { + break; + } + } + if (i == num_watches) { + return; + } + ctx = w->ctx; + TALLOC_FREE(w); + memmove(&watches[i], &watches[i+1], + sizeof(*watches) * (num_watches - i - 1)); + ctx->watches = talloc_realloc(ctx, watches, AvahiWatch *, + num_watches - 1); +} + +static void avahi_timeout_handler(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval current_time, + void *private_data); + +static AvahiTimeout *avahi_timeout_new(const AvahiPoll *api, + const struct timeval *tv, + AvahiTimeoutCallback callback, + void *userdata) +{ + struct avahi_poll_context *ctx = talloc_get_type_abort( + api->userdata, struct avahi_poll_context); + int num_timeouts = talloc_array_length(ctx->timeouts); + AvahiTimeout **tmp, *timeout_ctx; + + tmp = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *, + num_timeouts + 1); + if (tmp == NULL) { + return NULL; + } + ctx->timeouts = tmp; + + timeout_ctx = talloc(tmp, AvahiTimeout); + if (timeout_ctx == NULL) { + goto fail; + } + ctx->timeouts[num_timeouts] = timeout_ctx; + + timeout_ctx->ctx = ctx; + if (tv == NULL) { + timeout_ctx->te = NULL; + } else { + timeout_ctx->te = tevent_add_timer(ctx->ev, timeout_ctx, + *tv, avahi_timeout_handler, + timeout_ctx); + if (timeout_ctx->te == NULL) { + goto fail; + } + } + timeout_ctx->callback = callback; + timeout_ctx->userdata = userdata; + return timeout_ctx; + + fail: + TALLOC_FREE(timeout_ctx); + ctx->timeouts = talloc_realloc(ctx, ctx->timeouts, AvahiTimeout *, + num_timeouts); + return NULL; +} + +static void avahi_timeout_handler(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval current_time, + void *private_data) +{ + AvahiTimeout *timeout_ctx = talloc_get_type_abort( + private_data, AvahiTimeout); + + TALLOC_FREE(timeout_ctx->te); + timeout_ctx->callback(timeout_ctx, timeout_ctx->userdata); +} + +static void avahi_timeout_update(AvahiTimeout *t, const struct timeval *tv) +{ + TALLOC_FREE(t->te); + + if (tv == NULL) { + /* + * Disable this timer + */ + return; + } + + t->te = tevent_add_timer(t->ctx->ev, t, *tv, avahi_timeout_handler, t); + /* + * No failure mode defined here + */ + SMB_ASSERT(t->te != NULL); +} + +static void avahi_timeout_free(AvahiTimeout *t) +{ + int i, num_timeouts; + AvahiTimeout **timeouts = t->ctx->timeouts; + struct avahi_poll_context *ctx; + + num_timeouts = talloc_array_length(timeouts); + + for (i=0; i<num_timeouts; i++) { + if (t == timeouts[i]) { + break; + } + } + if (i == num_timeouts) { + return; + } + ctx = t->ctx; + TALLOC_FREE(t); + memmove(&timeouts[i], &timeouts[i+1], + sizeof(*timeouts) * (num_timeouts - i - 1)); + ctx->timeouts = talloc_realloc(ctx, timeouts, AvahiTimeout *, + num_timeouts - 1); +} + +struct AvahiPoll *tevent_avahi_poll(TALLOC_CTX *mem_ctx, + struct tevent_context *ev) +{ + struct AvahiPoll *result; + struct avahi_poll_context *ctx; + + result = talloc(mem_ctx, struct AvahiPoll); + if (result == NULL) { + return result; + } + ctx = talloc_zero(result, struct avahi_poll_context); + if (ctx == NULL) { + TALLOC_FREE(result); + return NULL; + } + ctx->ev = ev; + + result->watch_new = avahi_watch_new; + result->watch_update = avahi_watch_update; + result->watch_get_events = avahi_watch_get_events; + result->watch_free = avahi_watch_free; + result->timeout_new = avahi_timeout_new; + result->timeout_update = avahi_timeout_update; + result->timeout_free = avahi_timeout_free; + result->userdata = ctx; + + return result; +} |