/*
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 .
*/
#include "includes.h"
#include
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; ictx;
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; ictx;
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;
}