X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-common%2Fdbus-watch-glue.c;h=46fcc90978f492993bf2fbf5eebff10e4df2672f;hb=80ffb739edcbcdc2a22bfed71b7913213392f6ff;hp=20f87969187dd63ad1cf1e03357a5c473ba15150;hpb=deb6bcac8d1e1ecec4aafaee2d27dbe467e4f461;p=catta diff --git a/avahi-common/dbus-watch-glue.c b/avahi-common/dbus-watch-glue.c index 20f8796..46fcc90 100644 --- a/avahi-common/dbus-watch-glue.c +++ b/avahi-common/dbus-watch-glue.c @@ -20,9 +20,10 @@ ***/ #include +#include -#include - +#include "malloc.h" +#include "timeval.h" #include "dbus-watch-glue.h" static AvahiWatchEvent translate_dbus_to_avahi(unsigned int f) { @@ -55,6 +56,56 @@ static unsigned int translate_avahi_to_dbus(AvahiWatchEvent e) { return f; } +typedef struct { + DBusConnection *connection; + const AvahiPoll *poll_api; + AvahiTimeout *dispatch_timeout; + int ref; +} ConnectionData; + +static ConnectionData *connection_data_ref(ConnectionData *d) { + assert(d); + assert(d->ref >= 1); + + d->ref++; + return d; +} + +static void connection_data_unref(ConnectionData *d) { + assert(d); + assert(d->ref >= 1); + + if (--d->ref <= 0) { + d->poll_api->timeout_free(d->dispatch_timeout); + avahi_free(d); + } +} + +static void request_dispatch(ConnectionData *d) { + static const struct timeval tv = { 0, 0 }; + assert(d); + + assert(dbus_connection_get_dispatch_status(d->connection) == DBUS_DISPATCH_DATA_REMAINS); + + d->poll_api->timeout_update(d->dispatch_timeout, &tv); +} + +static void dispatch_timeout_callback(AvahiTimeout *t, void *userdata) { + ConnectionData *d = userdata; + assert(t); + assert(d); + + connection_data_ref(d); + dbus_connection_ref(d->connection); + + if (dbus_connection_dispatch(d->connection) == DBUS_DISPATCH_DATA_REMAINS) + /* If there's still data, request that this handler is called again */ + request_dispatch(d); + + dbus_connection_unref(d->connection); + connection_data_unref(d); +} + static void watch_callback(AvahiWatch *avahi_watch, int fd, AvahiWatchEvent events, void *userdata) { DBusWatch *dbus_watch = userdata; assert(avahi_watch); @@ -101,44 +152,66 @@ static dbus_bool_t update_watch(const AvahiPoll *poll_api, DBusWatch *dbus_watch } static dbus_bool_t add_watch(DBusWatch *dbus_watch, void *userdata) { - const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + ConnectionData *d = userdata; assert(dbus_watch); - assert(poll_api); + assert(d); - return update_watch(poll_api, dbus_watch); + return update_watch(d->poll_api, dbus_watch); } static void remove_watch(DBusWatch *dbus_watch, void *userdata) { - const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + ConnectionData *d = userdata; AvahiWatch *avahi_watch; assert(dbus_watch); - assert(poll_api); + assert(d); if ((avahi_watch = dbus_watch_get_data(dbus_watch))) { - poll_api->watch_free(avahi_watch); + d->poll_api->watch_free(avahi_watch); dbus_watch_set_data(dbus_watch, NULL, NULL); } } static void watch_toggled(DBusWatch *dbus_watch, void *userdata) { - const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + ConnectionData *d = userdata; assert(dbus_watch); - assert(poll_api); + assert(d); - update_watch(poll_api, dbus_watch); + update_watch(d->poll_api, dbus_watch); } typedef struct TimeoutData { const AvahiPoll *poll_api; AvahiTimeout *avahi_timeout; DBusTimeout *dbus_timeout; + int ref; } TimeoutData; +static TimeoutData* timeout_data_ref(TimeoutData *t) { + assert(t); + assert(t->ref >= 1); + + t->ref++; + return t; +} + +static void timeout_data_unref(TimeoutData *t) { + assert(t); + assert(t->ref >= 1); + + if (--t->ref <= 0) { + if (t->avahi_timeout) + t->poll_api->timeout_free(t->avahi_timeout); + + avahi_free(t); + } +} + static void update_timeout(TimeoutData *timeout) { assert(timeout); + assert(timeout->ref >= 1); if (dbus_timeout_get_enabled(timeout->dbus_timeout)) { struct timeval tv; @@ -156,80 +229,118 @@ static void timeout_callback(AvahiTimeout *avahi_timeout, void *userdata) { assert(avahi_timeout); assert(timeout); + timeout_data_ref(timeout); + dbus_timeout_handle(timeout->dbus_timeout); /* Ignore the return value */ + + if (timeout->avahi_timeout) + update_timeout(timeout); - update_timeout(timeout); + timeout_data_unref(timeout); } static dbus_bool_t add_timeout(DBusTimeout *dbus_timeout, void *userdata) { TimeoutData *timeout; - const AvahiPoll *poll_api = (const AvahiPoll*) userdata; + ConnectionData *d = userdata; struct timeval tv; dbus_bool_t b; assert(dbus_timeout); - assert(poll_api); + assert(d); if (!(timeout = avahi_new(TimeoutData, 1))) return FALSE; timeout->dbus_timeout = dbus_timeout; - timeout->poll_api = poll_api; + timeout->poll_api = d->poll_api; + timeout->ref = 1; if ((b = dbus_timeout_get_enabled(dbus_timeout))) avahi_elapse_time(&tv, dbus_timeout_get_interval(dbus_timeout), 0); - if (!(timeout->avahi_timeout = poll_api->timeout_new( - poll_api, + if (!(timeout->avahi_timeout = d->poll_api->timeout_new( + d->poll_api, b ? &tv : NULL, timeout_callback, - dbus_timeout))) { + timeout))) { avahi_free(timeout); return FALSE; } - dbus_timeout_set_data(dbus_timeout, timeout, NULL); + dbus_timeout_set_data(dbus_timeout, timeout, (DBusFreeFunction) timeout_data_unref); return TRUE; } static void remove_timeout(DBusTimeout *dbus_timeout, void *userdata) { + ConnectionData *d = userdata; TimeoutData *timeout; - const AvahiPoll *poll_api = (const AvahiPoll*) userdata; assert(dbus_timeout); - assert(poll_api); + assert(d); timeout = dbus_timeout_get_data(dbus_timeout); assert(timeout); - poll_api->timeout_free(timeout->avahi_timeout); - avahi_free(timeout); - dbus_timeout_set_data(dbus_timeout, NULL, NULL); + d->poll_api->timeout_free(timeout->avahi_timeout); + timeout->avahi_timeout = NULL; } static void timeout_toggled(DBusTimeout *dbus_timeout, void *userdata) { TimeoutData *timeout; - const AvahiPoll *poll_api = (const AvahiPoll*) userdata; assert(dbus_timeout); - assert(poll_api); - timeout = dbus_timeout_get_data(dbus_timeout); assert(timeout); update_timeout(timeout); } +static void dispatch_status(DBusConnection *connection, DBusDispatchStatus new_status, void *userdata) { + ConnectionData *d = userdata; + + if (new_status == DBUS_DISPATCH_DATA_REMAINS) + request_dispatch(d); + } + int avahi_dbus_connection_glue(DBusConnection *c, const AvahiPoll *poll_api) { + ConnectionData *d = NULL; + assert(c); assert(poll_api); - if (!(dbus_connection_set_watch_functions(c, add_watch, remove_watch, watch_toggled, (void*) poll_api, NULL))) - return -1; + if (!(d = avahi_new(ConnectionData, 1))) + goto fail;; + + d->poll_api = poll_api; + d->connection = c; + d->ref = 1; + + if (!(d->dispatch_timeout = poll_api->timeout_new(poll_api, NULL, dispatch_timeout_callback, d))) + goto fail; + + if (!(dbus_connection_set_watch_functions(c, add_watch, remove_watch, watch_toggled, connection_data_ref(d), (DBusFreeFunction)connection_data_unref))) + goto fail; + + if (!(dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, timeout_toggled, connection_data_ref(d), (DBusFreeFunction)connection_data_unref))) + goto fail; + + dbus_connection_set_dispatch_status_function(c, dispatch_status, connection_data_ref(d), (DBusFreeFunction)connection_data_unref); - if (!(dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, timeout_toggled, (void*) poll_api, NULL))) - return -1; + if (dbus_connection_get_dispatch_status(c) == DBUS_DISPATCH_DATA_REMAINS) + request_dispatch(d); + connection_data_unref(d); + return 0; + +fail: + + if (d) { + d->poll_api->timeout_free(d->dispatch_timeout); + + avahi_free(d); + } + + return -1; }