noinst_HEADERS = \
internal.h
+ dbus-watch-glue.h
noinst_PROGRAMS = \
client-test
libavahi_client_la_SOURCES = \
client.c client.h \
entrygroup.c \
- browser.c
+ browser.c \
+ dbus-watch-glue.c
+
+libavahi_client_la_CFLAGS = $(AM_CFLAGS)
+libavahi_client_la_LIBADD = $(AM_LDADD)
client_test_SOURCES = \
client-test.c
client_test_CFLAGS = $(AM_CFLAGS)
-client_test_LDADD = $(AM_LDADD) libavahi-client.la ../avahi-common/libavahi-common.la
+client_test_LDADD = $(AM_LDADD) libavahi-client.la ../avahi-common/libavahi-common.la ../avahi-glib/libavahi-glib.la
endif
#include <config.h>
#endif
-#include <avahi-client/client.h>
-#include <avahi-common/dbus.h>
-#include <avahi-common/llist.h>
-#include <avahi-common/error.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>
-#include <stdlib.h>
+#include <avahi-client/client.h>
+#include <avahi-common/dbus.h>
+#include <avahi-common/llist.h>
+#include <avahi-common/error.h>
+#include <avahi-common/malloc.h>
#include "client.h"
#include "internal.h"
/* AvahiDomainBrowser */
-AvahiDomainBrowser* avahi_domain_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, char *domain, AvahiDomainBrowserType btype, AvahiDomainBrowserCallback callback, void *user_data)
+AvahiDomainBrowser* avahi_domain_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiDomainBrowserType btype, AvahiDomainBrowserCallback callback, void *user_data)
{
AvahiDomainBrowser *tmp = NULL;
DBusMessage *message = NULL, *reply;
if (dbus_error_is_set (&error) || path == NULL)
goto dbus_error;
- tmp = malloc (sizeof (AvahiDomainBrowser));
+ tmp = avahi_new (AvahiDomainBrowser, 1);
tmp->client = client;
tmp->callback = callback;
tmp->user_data = user_data;
AVAHI_LLIST_REMOVE(AvahiDomainBrowser, domain_browsers, client->domain_browsers, b);
- free (b);
+ avahi_free (b);
return avahi_client_set_errno (client, AVAHI_OK);
}
-char*
+const char*
avahi_domain_browser_path (AvahiDomainBrowser *b)
{
return b->path;
}
/* AvahiServiceTypeBrowser */
-AvahiServiceTypeBrowser* avahi_service_type_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, char *domain, AvahiServiceTypeBrowserCallback callback, void *user_data)
+AvahiServiceTypeBrowser* avahi_service_type_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *domain, AvahiServiceTypeBrowserCallback callback, void *user_data)
{
AvahiServiceTypeBrowser *tmp = NULL;
DBusMessage *message = NULL, *reply;
if (dbus_error_is_set (&error) || path == NULL)
goto dbus_error;
- tmp = malloc (sizeof (AvahiServiceTypeBrowser));
+ tmp = avahi_new(AvahiServiceTypeBrowser, 1);
tmp->client = client;
tmp->callback = callback;
tmp->user_data = user_data;
AVAHI_LLIST_REMOVE(AvahiServiceTypeBrowser, service_type_browsers, b->client->service_type_browsers, b);
- free (b);
+ avahi_free (b);
return avahi_client_set_errno (client, AVAHI_OK);
}
-char*
+const char*
avahi_service_type_browser_path (AvahiServiceTypeBrowser *b)
{
return b->path;
/* AvahiServiceBrowser */
-AvahiServiceBrowser* avahi_service_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, char *type, char *domain, AvahiServiceBrowserCallback callback, void *user_data)
+AvahiServiceBrowser* avahi_service_browser_new (AvahiClient *client, AvahiIfIndex interface, AvahiProtocol protocol, const char *type, const char *domain, AvahiServiceBrowserCallback callback, void *user_data)
{
AvahiServiceBrowser *tmp = NULL;
DBusMessage *message = NULL, *reply;
if (dbus_error_is_set (&error) || path == NULL)
goto dbus_error;
- tmp = malloc (sizeof (AvahiServiceBrowser));
+ tmp = avahi_new(AvahiServiceBrowser, 1);
tmp->client = client;
tmp->callback = callback;
tmp->user_data = user_data;
AVAHI_LLIST_REMOVE(AvahiServiceBrowser, service_browsers, b->client->service_browsers, b);
- free (b);
+ avahi_free (b);
return avahi_client_set_errno (client, AVAHI_OK);
}
-char*
+const char*
avahi_service_browser_path (AvahiServiceBrowser *b)
{
return b->path;
#include <avahi-client/client.h>
#include <avahi-common/error.h>
+#include <avahi-glib/glib-watch.h>
+#include <avahi-glib/glib-malloc.h>
#include <stdio.h>
#include <glib.h>
-void
+static void
avahi_client_callback (AvahiClient *c, AvahiClientState state, void *user_data)
{
printf ("XXX: Callback on client, state -> %d, data -> %s\n", state, (char*)user_data);
}
-void
+static void
avahi_entry_group_callback (AvahiEntryGroup *g, AvahiEntryGroupState state, void *user_data)
{
printf ("XXX: Callback on %s, state -> %d, data -> %s\n", avahi_entry_group_path (g), state, (char*)user_data);
}
-void
-avahi_domain_browser_callback (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *domain, void *user_data)
+static void
+avahi_domain_browser_callback (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, void *user_data)
{
printf ("XXX: Callback on %s, interface (%d), protocol (%d), event (%d), domain (%s), data (%s)\n", avahi_domain_browser_path (b), interface, protocol, event, domain, (char*)user_data);
}
-void
-avahi_service_browser_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *name, char *type, char *domain, void *user_data)
+static void
+avahi_service_browser_callback (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, void *user_data)
{
printf ("XXX: Callback on %s, interface (%d), protocol (%d), event (%d), name (%s), type (%s), domain (%s), data (%s)\n", avahi_service_browser_path (b), interface, protocol, event, name, type, domain, (char*)user_data);
}
-void
-avahi_service_type_browser_callback (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *type, char *domain, void *user_data)
+static void
+avahi_service_type_browser_callback (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, void *user_data)
{
printf ("XXX: Callback on %s, interface (%d), protocol (%d), event (%d), type (%s), domain (%s), data (%s)\n", avahi_service_type_browser_path (b), interface, protocol, event, type, domain, (char*)user_data);
}
-gboolean
+static gboolean
test_free_domain_browser (gpointer data)
{
- printf ("XXX: freeing domain browser\n");
AvahiServiceBrowser *b = data;
+ printf ("XXX: freeing domain browser\n");
avahi_service_browser_free (b);
return FALSE;
}
-gboolean
+static gboolean
test_free_entry_group (gpointer data)
{
- printf ("XXX: freeing entry group\n");
AvahiEntryGroup *g = data;
+ printf ("XXX: freeing entry group\n");
avahi_entry_group_free (g);
return FALSE;
}
AvahiDomainBrowser *domain;
AvahiServiceBrowser *sb;
AvahiServiceTypeBrowser *st;
+ AvahiGLibPoll *glib_poll;
char *ret;
+ avahi_set_allocator(avahi_glib_allocator());
+
+ glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
loop = g_main_loop_new (NULL, FALSE);
- avahi = avahi_client_new (avahi_client_callback, "omghai2u");
+ avahi = avahi_client_new (avahi_glib_poll_get(glib_poll), avahi_client_callback, "omghai2u");
g_assert (avahi != NULL);
#include <avahi-common/dbus.h>
#include <avahi-common/llist.h>
#include <avahi-common/error.h>
+#include <avahi-common/malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
#include <stdlib.h>
+#include "dbus-watch-glue.h"
#include "client.h"
#include "internal.h"
client->callback (client, state, client->user_data);
}
-void
+static void
avahi_client_state_request_callback (DBusPendingCall *call, void *data)
{
AvahiClient *client = data;
dbus_pending_call_unref (call);
}
-void
+static void
avahi_client_schedule_state_request (AvahiClient *client)
{
DBusMessage *message;
dbus_error_init (&error);
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
- gchar *name, *old, *new;
+ char *name, *old, *new;
dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID);
if (dbus_error_is_set (&error)) {
}
AvahiClient *
-avahi_client_new (AvahiClientCallback callback, void *user_data)
+avahi_client_new (const AvahiPoll *poll_api, AvahiClientCallback callback, void *user_data)
{
AvahiClient *tmp = NULL;
DBusError error;
dbus_error_init (&error);
- if (!(tmp = malloc(sizeof(AvahiClient))))
+ if (!(tmp = avahi_new(AvahiClient, 1)))
goto fail;
AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, tmp->groups);
AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, tmp->service_browsers);
AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, tmp->service_type_browsers);
+ tmp->poll_api = poll_api;
tmp->bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
if (dbus_error_is_set (&error)) {
goto fail;
}
- dbus_connection_setup_with_g_main (tmp->bus, NULL);
- dbus_connection_set_exit_on_disconnect (tmp->bus, FALSE);
+/* dbus_connection_setup_with_g_main (tmp->bus, NULL); */
+/* dbus_connection_set_exit_on_disconnect (tmp->bus, FALSE); */
+
+ if (avahi_dbus_connection_glue(tmp->bus, poll_api) < 0)
+ goto fail;
if (!dbus_connection_add_filter (tmp->bus, filter_func, tmp, NULL))
{
return tmp;
fail:
- free (tmp);
+ avahi_free (tmp);
if (dbus_error_is_set(&error))
dbus_error_free(&error);
}
static char*
-avahi_client_get_string_reply_and_block (AvahiClient *client, char *method, char *param)
+avahi_client_get_string_reply_and_block (AvahiClient *client, const char *method, const char *param)
{
DBusMessage *message;
DBusMessage *reply;
return NULL;
}
- new = strdup (ret);
+ new = avahi_strdup (ret);
avahi_client_set_errno (client, AVAHI_OK);
return new;
#include <avahi-common/address.h>
#include <avahi-common/strlst.h>
#include <avahi-common/defs.h>
+#include <avahi-common/watch.h>
/** \file client.h Definitions and functions for the client API over D-Bus */
typedef void (*AvahiEntryGroupCallback) (AvahiEntryGroup *g, AvahiEntryGroupState state, void* userdata);
/** The function prototype for the callback of an AvahiDomainBrowser */
-typedef void (*AvahiDomainBrowserCallback) (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *domain, void *user_data);
+typedef void (*AvahiDomainBrowserCallback) (AvahiDomainBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *domain, void *user_data);
/** The function prototype for the callback of an AvahiServiceBrowser */
-typedef void (*AvahiServiceBrowserCallback) (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *name, char *type, char *domain, void *user_data);
+typedef void (*AvahiServiceBrowserCallback) (AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, void *user_data);
/** The function prototype for the callback of an AvahiServiceTypeBrowser */
-typedef void (*AvahiServiceTypeBrowserCallback) (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, char *type, char *domain, void *user_data);
+typedef void (*AvahiServiceTypeBrowserCallback) (AvahiServiceTypeBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *type, const char *domain, void *user_data);
/** Creates a new client instance */
-AvahiClient* avahi_client_new (AvahiClientCallback callback, void *user_data);
+AvahiClient* avahi_client_new (const AvahiPoll *poll_api, AvahiClientCallback callback, void *user_data);
/** Get the version of the server */
char* avahi_client_get_version_string (AvahiClient*);
AvahiStringList *txt);
/** Get the D-Bus path of an AvahiEntryGroup object, for debugging purposes only. */
-char* avahi_entry_group_path (AvahiEntryGroup *);
+const char* avahi_entry_group_path (AvahiEntryGroup *);
/** Browse for domains on the local network */
AvahiDomainBrowser* avahi_domain_browser_new (AvahiClient *client,
AvahiIfIndex interface,
AvahiProtocol protocol,
- char *domain,
+ const char *domain,
AvahiDomainBrowserType btype,
AvahiDomainBrowserCallback callback,
void *user_data);
/** Get the D-Bus path of an AvahiDomainBrowser object, for debugging purposes only. */
-char* avahi_domain_browser_path (AvahiDomainBrowser *);
+const char* avahi_domain_browser_path (AvahiDomainBrowser *);
/** Cleans up and frees an AvahiDomainBrowser object */
int avahi_domain_browser_free (AvahiDomainBrowser *);
AvahiClient *client,
AvahiIfIndex interface,
AvahiProtocol protocol,
- char *domain,
+ const char *domain,
AvahiServiceTypeBrowserCallback callback,
void *user_data);
/** Get the D-Bus path of an AvahiServiceTypeBrowser object, for debugging purposes only. */
-char* avahi_service_type_browser_path (AvahiServiceTypeBrowser *);
+const char* avahi_service_type_browser_path (AvahiServiceTypeBrowser *);
/** Cleans up and frees an AvahiServiceTypeBrowser object */
int avahi_service_type_browser_free (AvahiServiceTypeBrowser *);
AvahiClient *client,
AvahiIfIndex interface,
AvahiProtocol protocol,
- char *type,
- char *domain,
+ const char *type,
+ const char *domain,
AvahiServiceBrowserCallback callback,
void *user_data);
/** Get the D-Bus path of an AvahiServiceBrowser object, for debugging purposes only. */
-char* avahi_service_browser_path (AvahiServiceBrowser *);
+const char* avahi_service_browser_path (AvahiServiceBrowser *);
/* Cleans up and frees an AvahiServiceBrowser object */
int avahi_service_browser_free (AvahiServiceBrowser *);
--- /dev/null
+/* $Id$ */
+
+/***
+ This file is part of avahi.
+
+ avahi is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ avahi 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 Lesser General
+ Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with avahi; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include <assert.h>
+
+#include <avahi-common/malloc.h>
+
+#include "dbus-watch-glue.h"
+
+static AvahiWatchEvent translate_dbus_to_avahi(unsigned int f) {
+ AvahiWatchEvent e = 0;
+
+ if (f & DBUS_WATCH_READABLE)
+ e |= AVAHI_WATCH_IN;
+ if (f & DBUS_WATCH_WRITABLE)
+ e |= AVAHI_WATCH_OUT;
+ if (f & DBUS_WATCH_ERROR)
+ e |= AVAHI_WATCH_ERR;
+ if (f & DBUS_WATCH_HANGUP)
+ e |= AVAHI_WATCH_HUP;
+
+ return e;
+}
+
+static unsigned int translate_avahi_to_dbus(AvahiWatchEvent e) {
+ unsigned int f = 0;
+
+ if (e & AVAHI_WATCH_IN)
+ f |= DBUS_WATCH_READABLE;
+ if (e & AVAHI_WATCH_OUT)
+ f |= DBUS_WATCH_WRITABLE;
+ if (e & AVAHI_WATCH_ERR)
+ f |= DBUS_WATCH_ERROR;
+ if (e & AVAHI_WATCH_HUP)
+ f |= DBUS_WATCH_HANGUP;
+
+ return f;
+}
+
+static void watch_callback(AvahiWatch *avahi_watch, int fd, AvahiWatchEvent events, void *userdata) {
+ DBusWatch *dbus_watch = userdata;
+ assert(avahi_watch);
+ assert(dbus_watch);
+
+ dbus_watch_handle(dbus_watch, translate_avahi_to_dbus(events));
+ /* Ignore the return value */
+}
+
+static dbus_bool_t update_watch(const AvahiPoll *poll_api, DBusWatch *dbus_watch) {
+ AvahiWatch *avahi_watch;
+ dbus_bool_t b;
+
+ assert(dbus_watch);
+
+ avahi_watch = dbus_watch_get_data(dbus_watch);
+
+ b = dbus_watch_get_enabled(dbus_watch);
+
+ if (b && !avahi_watch) {
+
+ if (!(avahi_watch = poll_api->watch_new(
+ poll_api,
+ dbus_watch_get_fd(dbus_watch),
+ translate_dbus_to_avahi(dbus_watch_get_flags(dbus_watch)),
+ watch_callback,
+ dbus_watch)))
+ return FALSE;
+
+ dbus_watch_set_data(dbus_watch, avahi_watch, (DBusFreeFunction) poll_api->watch_free);
+
+ } else if (!b && avahi_watch) {
+
+ poll_api->watch_free(avahi_watch);
+ dbus_watch_set_data(dbus_watch, NULL, NULL);
+
+ } else if (avahi_watch) {
+
+ /* Update flags */
+ poll_api->watch_update(avahi_watch, dbus_watch_get_flags(dbus_watch));
+ }
+
+ return TRUE;
+}
+
+static dbus_bool_t add_watch(DBusWatch *dbus_watch, void *userdata) {
+ const AvahiPoll *poll_api = (const AvahiPoll*) userdata;
+
+ assert(dbus_watch);
+ assert(poll_api);
+
+ return update_watch(poll_api, dbus_watch);
+}
+
+static void remove_watch(DBusWatch *dbus_watch, void *userdata) {
+ const AvahiPoll *poll_api = (const AvahiPoll*) userdata;
+ AvahiWatch *avahi_watch;
+
+ assert(dbus_watch);
+ assert(poll_api);
+
+ avahi_watch = dbus_watch_get_data(dbus_watch);
+ 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;
+
+ assert(dbus_watch);
+ assert(poll_api);
+
+ update_watch(poll_api, dbus_watch);
+}
+
+typedef struct TimeoutData {
+ const AvahiPoll *poll_api;
+ AvahiTimeout *avahi_timeout;
+ DBusTimeout *dbus_timeout;
+} TimeoutData;
+
+static void update_timeout(TimeoutData *timeout) {
+ assert(timeout);
+
+ if (dbus_timeout_get_enabled(timeout->dbus_timeout)) {
+ struct timeval tv;
+ avahi_elapse_time(&tv, dbus_timeout_get_interval(timeout->dbus_timeout), 0);
+ timeout->poll_api->timeout_update(timeout->
+ avahi_timeout, &tv);
+ } else
+ timeout->poll_api->timeout_update(timeout->avahi_timeout, NULL);
+
+}
+
+static void timeout_callback(AvahiTimeout *avahi_timeout, void *userdata) {
+ TimeoutData *timeout = userdata;
+
+ assert(avahi_timeout);
+ assert(timeout);
+
+ dbus_timeout_handle(timeout->dbus_timeout);
+ /* Ignore the return value */
+
+ update_timeout(timeout);
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *dbus_timeout, void *userdata) {
+ TimeoutData *timeout;
+ const AvahiPoll *poll_api = (const AvahiPoll*) userdata;
+ struct timeval tv;
+ dbus_bool_t b;
+
+ assert(dbus_timeout);
+ assert(poll_api);
+
+ if (!(timeout = avahi_new(TimeoutData, 1)))
+ return FALSE;
+
+ timeout->dbus_timeout = dbus_timeout;
+ timeout->poll_api = poll_api;
+
+ 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,
+ b ? &tv : NULL,
+ timeout_callback,
+ dbus_timeout))) {
+ avahi_free(timeout);
+ return FALSE;
+ }
+
+ dbus_timeout_set_data(dbus_timeout, timeout, NULL);
+ return TRUE;
+}
+
+static void remove_timeout(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);
+
+ poll_api->timeout_free(timeout->avahi_timeout);
+ avahi_free(timeout);
+ dbus_timeout_set_data(dbus_timeout, NULL, 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);
+}
+
+int avahi_dbus_connection_glue(DBusConnection *c, const AvahiPoll *poll_api) {
+ 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 (!(dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, timeout_toggled, (void*) poll_api, NULL)))
+ return -1;
+
+ return 0;
+}
--- /dev/null
+#ifndef foodbuswatchgluehfoo
+#define foodbuswatchgluehfoo
+
+/* $Id$ */
+
+/***
+ This file is part of avahi.
+
+ avahi is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ avahi 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 Lesser General
+ Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with avahi; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include <dbus/dbus.h>
+
+#include <avahi-common/watch.h>
+
+int avahi_dbus_connection_glue(DBusConnection *c, const AvahiPoll *poll_api);
+
+#endif
#include <config.h>
#endif
-#include <avahi-client/client.h>
-#include <avahi-common/dbus.h>
-#include <avahi-common/llist.h>
-#include <avahi-common/error.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
-#include <stdlib.h>
+#include <avahi-client/client.h>
+#include <avahi-common/dbus.h>
+#include <avahi-common/llist.h>
+#include <avahi-common/error.h>
+#include <avahi-common/malloc.h>
#include "client.h"
#include "internal.h"
goto fail;
}
- tmp = malloc (sizeof (AvahiEntryGroup));
+ tmp = avahi_new(AvahiEntryGroup, 1);
tmp->client = client;
- tmp->path = strdup (path);
+ tmp->path = avahi_strdup (path);
tmp->callback = callback;
tmp->user_data = user_data;
return tmp;
fail:
- if (tmp) free (tmp);
+ if (tmp) avahi_free (tmp);
if (message) dbus_message_unref (message);
return NULL;
}
AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, client->groups, group);
- free (group);
+ avahi_free (group);
return avahi_client_set_errno (client, AVAHI_OK);
}
/* Assemble the AvahiStringList into an Array of Array of Bytes to send over dbus */
for (p = txt; p != NULL; p = p->next) {
DBusMessageIter sub2;
- const guint8 *data = p->text;
+ const uint8_t *data = p->text;
dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "y", &sub2);
dbus_message_iter_append_fixed_array(&sub2, DBUS_TYPE_BYTE, &data, p->size);
}
/* XXX: debug function */
-char* avahi_entry_group_path (AvahiEntryGroup *group)
+const char* avahi_entry_group_path (AvahiEntryGroup *group)
{
if (group != NULL) return group->path;
else return NULL;
struct _AvahiClient
{
+ const AvahiPoll *poll_api;
DBusConnection *bus;
int error;
AvahiClientCallback callback;
struct AvahiWatch {
AvahiSimplePoll *simple_poll;
int dead;
+
int idx;
struct pollfd pollfd;
+
AvahiWatchCallback callback;
void *userdata;
AVAHI_LLIST_FIELDS(AvahiWatch, watches);
};
+struct AvahiTimeout {
+ AvahiSimplePoll *simple_poll;
+ int dead;
+
+ int enabled;
+ struct timeval expiry;
+
+ AvahiTimeoutCallback callback;
+ void *userdata;
+
+ AVAHI_LLIST_FIELDS(AvahiTimeout, timeouts);
+};
+
struct AvahiSimplePoll {
AvahiPoll api;
AvahiPollFunc poll_func;
struct pollfd* pollfds;
int n_pollfds, max_pollfds, rebuild_pollfds;
- struct timeval wakeup;
- AvahiWakeupCallback wakeup_callback;
- void *wakeup_userdata;
-
- int req_cleanup;
-
+ int watch_req_cleanup, timeout_req_cleanup;
int quit;
+ int events_valid;
int n_watches;
AVAHI_LLIST_HEAD(AvahiWatch, watches);
+ AVAHI_LLIST_HEAD(AvahiTimeout, timeouts);
};
static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) {
return NULL;
w->simple_poll = s;
+ w->dead = 0;
+
w->pollfd.fd = fd;
w->pollfd.events = event;
+
w->callback = callback;
w->userdata = userdata;
- w->dead = 0;
if (s->n_pollfds < s->max_pollfds) {
/* If there's space for this pollfd, go on and allocate it */
w->simple_poll->rebuild_pollfds = 1;
}
+static AvahiWatchEvent watch_get_events(AvahiWatch *w) {
+ assert(w);
+ assert(!w->dead);
+
+ if (w->idx != -1 && w->simple_poll->events_valid)
+ return w->simple_poll->pollfds[w->idx].revents;
+
+ return 0;
+}
+
static void remove_pollfd(AvahiWatch *w) {
assert(w);
w->dead = 1;
w->simple_poll->n_watches --;
- w->simple_poll->req_cleanup = 1;
-}
-
-static void set_wakeup(const AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata) {
- AvahiSimplePoll *s;
-
- assert(api);
- s = api->userdata;
-
- if (callback) {
- if (tv)
- s->wakeup = *tv;
- else {
- s->wakeup.tv_sec = 0;
- s->wakeup.tv_usec = 0;
- }
-
- s->wakeup_callback = callback;
- s->wakeup_userdata = userdata;
- } else
- s->wakeup_callback = NULL;
+ w->simple_poll->watch_req_cleanup = 1;
}
static void destroy_watch(AvahiWatch *w) {
avahi_free(w);
}
-static void cleanup(AvahiSimplePoll *s, int all) {
+static void cleanup_watches(AvahiSimplePoll *s, int all) {
AvahiWatch *w, *next;
assert(s);
destroy_watch(w);
}
- s->req_cleanup = 0;
+ s->timeout_req_cleanup = 0;
+}
+
+static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) {
+ AvahiTimeout *t;
+ AvahiSimplePoll *s;
+
+ assert(api);
+ assert(callback);
+
+ s = api->userdata;
+ assert(s);
+
+ if (!(t = avahi_new(AvahiTimeout, 1)))
+ return NULL;
+
+ t->simple_poll = s;
+ t->dead = 0;
+
+ if ((t->enabled = !!tv))
+ t->expiry = *tv;
+
+ t->callback = callback;
+ t->userdata = userdata;
+
+ AVAHI_LLIST_PREPEND(AvahiTimeout, timeouts, s->timeouts, t);
+
+ return t;
+}
+
+static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
+ assert(t);
+ assert(!t->dead);
+
+ if ((t->enabled = !!tv))
+ t->expiry = *tv;
+}
+
+static void timeout_free(AvahiTimeout *t) {
+ assert(t);
+ assert(!t->dead);
+
+ t->dead = 1;
+ t->simple_poll->timeout_req_cleanup = 1;
+}
+
+
+static void destroy_timeout(AvahiTimeout *t) {
+ assert(t);
+
+ AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->simple_poll->timeouts, t);
+
+ avahi_free(t);
+}
+
+static void cleanup_timeouts(AvahiSimplePoll *s, int all) {
+ AvahiTimeout *t, *next;
+ assert(s);
+
+ for (t = s->timeouts; t; t = next) {
+ next = t->timeouts_next;
+
+ if (all || t->dead)
+ destroy_timeout(t);
+ }
+
+ s->timeout_req_cleanup = 0;
}
AvahiSimplePoll *avahi_simple_poll_new(void) {
return NULL;
s->api.userdata = s;
+
s->api.watch_new = watch_new;
s->api.watch_free = watch_free;
s->api.watch_update = watch_update;
- s->api.set_wakeup = set_wakeup;
+ s->api.watch_get_events = watch_get_events;
+
+ s->api.timeout_new = timeout_new;
+ s->api.timeout_free = timeout_free;
+ s->api.timeout_update = timeout_update;
+
s->pollfds = NULL;
s->max_pollfds = s->n_pollfds = 0;
- s->wakeup_callback = NULL;
s->rebuild_pollfds = 0;
s->quit = 0;
s->n_watches = 0;
- s->req_cleanup = 0;
+ s->events_valid = 0;
+
+ s->watch_req_cleanup = 0;
+ s->timeout_req_cleanup = 0;
avahi_simple_poll_set_func(s, NULL);
AVAHI_LLIST_HEAD_INIT(AvahiWatch, s->watches);
+ AVAHI_LLIST_HEAD_INIT(AvahiTimeout, s->timeouts);
return s;
}
void avahi_simple_poll_free(AvahiSimplePoll *s) {
assert(s);
- cleanup(s, 1);
-
+ cleanup_timeouts(s, 1);
+ cleanup_watches(s, 1);
assert(s->n_watches == 0);
avahi_free(s->pollfds);
}
s->n_pollfds = idx;
-
+ s->events_valid = 0;
s->rebuild_pollfds = 0;
return 0;
}
-static int start_wakeup_callback(AvahiSimplePoll *s) {
- AvahiWakeupCallback callback;
- void *userdata;
-
+static AvahiTimeout* find_next_timeout(AvahiSimplePoll *s) {
+ AvahiTimeout *t, *n = NULL;
assert(s);
- /* Reset the wakeup functions, but allow changing of the two
- values from the callback function */
+ for (t = s->timeouts; t; t = t->timeouts_next) {
+
+ if (t->dead || !t->enabled)
+ continue;
+
+ if (!n || avahi_timeval_compare(&t->expiry, &n->expiry) < 0)
+ n = t;
+ }
- callback = s->wakeup_callback;
- userdata = s->wakeup_userdata;
- s->wakeup_callback = NULL;
- s->wakeup_userdata = NULL;
+ return n;
+}
- assert(callback);
-
- callback(&s->api, userdata);
+static int start_timeout_callback(AvahiTimeout *t) {
+ assert(t);
+ assert(!t->dead);
+ assert(t->enabled);
+
+ t->enabled = 0;
+ t->callback(t, t->userdata);
return 0;
}
int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) {
int r;
+ AvahiTimeout *next_timeout;
assert(s);
/* Cleanup things first */
- if (s->req_cleanup)
- cleanup(s, 0);
+ if (s->watch_req_cleanup)
+ cleanup_watches(s, 0);
+
+ if (s->timeout_req_cleanup)
+ cleanup_timeouts(s, 0);
/* Check whether a quit was requested */
if (s->quit)
if (rebuild(s) < 0)
return -1;
+
/* Calculate the wakeup time */
- if (s->wakeup_callback) {
+ if ((next_timeout = find_next_timeout(s))) {
struct timeval now;
int t;
AvahiUsec usec;
gettimeofday(&now, NULL);
- usec = avahi_timeval_diff(&s->wakeup, &now);
+ usec = avahi_timeval_diff(&next_timeout->expiry, &now);
- if (usec <= 0)
+ if (usec <= 0) {
/* Timeout elapsed */
- return start_wakeup_callback(s);
+ /* The events poll() returned in the last call are now no longer valid */
+ s->events_valid = 0;
+ return start_timeout_callback(next_timeout);
+ }
/* Calculate sleep time. We add 1ms because otherwise we'd
* wake up too early most of the time */
if ((r = s->poll_func(s->pollfds, s->n_pollfds, timeout)) < 0)
return -1;
+ /* The pollf events are now valid again */
+ s->events_valid = 1;
+
/* Check whether the wakeup time has been reached now */
- if (s->wakeup_callback) {
+ if (next_timeout) {
struct timeval now;
gettimeofday(&now, NULL);
- if (avahi_timeval_compare(&s->wakeup, &now) <= 0)
+ if (avahi_timeval_compare(&next_timeout->expiry, &now) <= 0)
/* Time elapsed */
- return start_wakeup_callback(s);
+ return start_timeout_callback(next_timeout);
}
if (r > 0) {
}
}
-static void wakeup(AvahiPoll *_api, void *userdata) {
+static void wakeup(AvahiTimeout *t, void *userdata) {
static int i = 0;
struct timeval tv;
avahi_simple_poll_quit(simple_poll);
else {
avahi_elapse_time(&tv, 1000, 0);
- api->set_wakeup(api, &tv, wakeup, NULL);
+ api->timeout_update(t, &tv);
}
}
api->watch_new(api, 0, AVAHI_WATCH_IN, callback, NULL);
avahi_elapse_time(&tv, 1000, 0);
- api->set_wakeup(api, &tv, wakeup, NULL);
+ api->timeout_new(api, &tv, wakeup, NULL);
/* Our main loop */
for (;;)
/** An I/O watch object */
typedef struct AvahiWatch AvahiWatch;
+/** An I/O watch object */
+typedef struct AvahiTimeout AvahiTimeout;
+
/** An event polling abstraction object */
typedef struct AvahiPoll AvahiPoll;
/** Called whenever an I/O event happens on an I/O watch */
typedef void (*AvahiWatchCallback)(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata);
-/** Called when the wakeup time is reached */
-typedef void (*AvahiWakeupCallback)(AvahiPoll *api, void *userdata);
+/** Called when the timeout is reached */
+typedef void (*AvahiTimeoutCallback)(AvahiTimeout *t, void *userdata);
/** Defines an abstracted event polling API. This may be used to
connect Avahi to other main loops. This is losely based on Unix
to define a single wakeup time.*/
struct AvahiPoll {
- /** Some abstract user data usable by the implementor of the API */
+ /** Some abstract user data usable by the provider of the API */
void* userdata;
/** Create a new watch for the specified file descriptor and for
* whenever any of the events happens. */
AvahiWatch* (*watch_new)(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata);
- /** Update the events to wait for. */
+ /** Update the events to wait for. It is safe to call this function from an AvahiWatchCallback */
void (*watch_update)(AvahiWatch *w, AvahiWatchEvent event);
- /** Free a watch */
+ /** Return the events that happened. It is safe to call this function from an AvahiWatchCallback */
+ AvahiWatchEvent (*watch_get_events)(AvahiWatch *w);
+
+ /** Free a watch. It is safe to call this function from an AvahiWatchCallback */
void (*watch_free)(AvahiWatch *w);
/** Set a wakeup time for the polling loop. The API will call the
- callback function when the absolute time *tv is reached. If *tv is
- NULL, the callback will be called in the next main loop
- iteration. If callback is NULL the wakeup time is disabled. */
- void (*set_wakeup)(const AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata);
+ callback function when the absolute time *tv is reached. If tv is
+ NULL, the timeout is disabled. After the timeout expired the
+ callback function will be called and the timeout is disabled. You
+ can reenable it by calling timeout_update() */
+ AvahiTimeout* (*timeout_new)(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata);
+
+ /** Update the absolute expiration time for a timeout, If tv is
+ * null, the timeout is disabled. It is safe to call this function from an AvahiTimeoutCallback */
+ void (*timeout_update)(AvahiTimeout *, const struct timeval *tv);
+
+ /** Free a timeout. It is safe to call this function from an AvahiTimeoutCallback */
+ void (*timeout_free)(AvahiTimeout *t);
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
int error;
avahi_set_allocator(avahi_glib_allocator());
- glib_poll = avahi_glib_poll_new(NULL);
+ glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
avahi_server_config_init(&config);
/* config.host_name = g_strdup("test"); */
avahi_set_allocator(avahi_glib_allocator());
- glib_poll = avahi_glib_poll_new(NULL);
+ glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
avahi = avahi_server_new(avahi_glib_poll_get(glib_poll), NULL, server_callback, NULL, &error);
struct AvahiTimeEventQueue {
const AvahiPoll *poll_api;
AvahiPrioQueue *prioq;
+ AvahiTimeout *timeout;
};
static int compare(const void* _a, const void* _b) {
return avahi_timeval_compare(&a->last_run, &b->last_run);
}
-static void expiration_event(AvahiPoll *poll_api, void *userdata);
-
-static void update_wakeup(AvahiTimeEventQueue *q) {
+static void update_timeout(AvahiTimeEventQueue *q) {
+ AvahiTimeEvent *e;
assert(q);
- if (q->prioq->root) {
- AvahiTimeEvent *e = q->prioq->root->data;
- q->poll_api->set_wakeup(q->poll_api, &e->expiry, expiration_event, q);
- } else
- q->poll_api->set_wakeup(q->poll_api, NULL, NULL, NULL);
+ if ((e = avahi_time_event_queue_root(q)))
+ q->poll_api->timeout_update(q->timeout, &e->expiry);
+ else
+ q->poll_api->timeout_update(q->timeout, NULL);
}
-void expiration_event(AvahiPoll *poll_api, void *userdata) {
+static void expiration_event(AvahiTimeout *timeout, void *userdata) {
struct timeval now;
AvahiTimeEventQueue *q = userdata;
AvahiTimeEvent *e;
}
}
- update_wakeup(q);
+ update_timeout(q);
}
static void fix_expiry_time(AvahiTimeEvent *e) {
goto oom;
}
+ q->poll_api = poll_api;
+
if (!(q->prioq = avahi_prio_queue_new(compare)))
goto oom;
- q->poll_api = poll_api;
+ if (!(q->timeout = poll_api->timeout_new(poll_api, NULL, expiration_event, q)))
+ goto oom;
+
return q;
oom:
- if (q)
+ if (q) {
avahi_free(q);
+
+ if (q->prioq)
+ avahi_prio_queue_free(q->prioq);
+ }
return NULL;
}
void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
+ AvahiTimeEvent *e;
+
assert(q);
- while (q->prioq->root)
- avahi_time_event_free(q->prioq->root->data);
+ while ((e = avahi_time_event_queue_root(q)))
+ avahi_time_event_free(e);
avahi_prio_queue_free(q->prioq);
+ q->poll_api->timeout_free(q->timeout);
+
avahi_free(q);
}
return NULL;
}
- update_wakeup(q);
+ update_timeout(q);
return e;
}
avahi_prio_queue_remove(q->prioq, e->node);
avahi_free(e);
- update_wakeup(q);
+ update_timeout(q);
}
void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) {
fix_expiry_time(e);
avahi_prio_queue_shuffle(e->queue->prioq, e->node);
- update_wakeup(e->queue);
+ update_timeout(e->queue);
}
AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q) {
g_assert(c);
- poll_api = avahi_glib_poll_new(NULL);
+ poll_api = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
loop = g_main_loop_new(NULL, FALSE);
if (daemon_signal_init(SIGINT, SIGQUIT, SIGHUP, SIGTERM, SIGUSR1, 0) < 0) {
}
}
-static void wakeup(AvahiPoll *_api, void *userdata) {
+static void wakeup(AvahiTimeout *t, void *userdata) {
struct timeval tv;
static int i = 0;
g_main_loop_quit(loop);
avahi_elapse_time(&tv, 1000, 0);
- api->set_wakeup(api, &tv, wakeup, NULL);
+ api->timeout_update(t, &tv);
}
int main(int argc, char *argv[]) {
- AvahiGLibPoll *s;
+ AvahiGLibPoll *g;
struct timeval tv;
- s = avahi_glib_poll_new(NULL);
- assert(s);
+ g = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
+ assert(g);
- api = avahi_glib_poll_get(s);
+ api = avahi_glib_poll_get(g);
api->watch_new(api, 0, AVAHI_WATCH_IN, callback, NULL);
avahi_elapse_time(&tv, 1000, 0);
- api->set_wakeup(api, &tv, wakeup, NULL);
+ api->timeout_new(api, &tv, wakeup, NULL);
loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
g_main_loop_unref(loop);
+
+ avahi_glib_poll_free(g);
return 0;
}
struct AvahiWatch {
AvahiGLibPoll *glib_poll;
int dead;
+
GPollFD pollfd;
int pollfd_added;
+
AvahiWatchCallback callback;
void *userdata;
AVAHI_LLIST_FIELDS(AvahiWatch, watches);
};
+struct AvahiTimeout {
+ AvahiGLibPoll *glib_poll;
+ gboolean dead;
+
+ gboolean enabled;
+ struct timeval expiry;
+
+ AvahiTimeoutCallback callback;
+ void *userdata;
+
+ AVAHI_LLIST_FIELDS(AvahiTimeout, timeouts);
+};
+
struct AvahiGLibPoll {
GSource source;
AvahiPoll api;
GMainContext *context;
- struct timeval wakeup;
- AvahiWakeupCallback wakeup_callback;
- void *wakeup_userdata;
-
- int req_cleanup;
+ gboolean timeout_req_cleanup;
+ gboolean watch_req_cleanup;
- AVAHI_LLIST_HEAD(AvahiWatch, watches);
+ AVAHI_LLIST_HEAD(AvahiWatch, watches);
+ AVAHI_LLIST_HEAD(AvahiTimeout, timeouts);
};
static void destroy_watch(AvahiWatch *w) {
avahi_free(w);
}
-static void cleanup(AvahiGLibPoll *g, int all) {
+static void cleanup_watches(AvahiGLibPoll *g, int all) {
AvahiWatch *w, *next;
assert(g);
destroy_watch(w);
}
- g->req_cleanup = 0;
+ g->watch_req_cleanup = 0;
}
static AvahiWatch* watch_new(const AvahiPoll *api, int fd, AvahiWatchEvent event, AvahiWatchCallback callback, void *userdata) {
(event & AVAHI_WATCH_OUT ? G_IO_OUT : 0) |
(event & AVAHI_WATCH_ERR ? G_IO_ERR : 0) |
(event & AVAHI_WATCH_HUP ? G_IO_HUP : 0);
- ;
+ w->pollfd.revents = 0;
w->callback = callback;
w->userdata = userdata;
- w->dead = 0;
+ w->dead = FALSE;
g_source_add_poll(&g->source, &w->pollfd);
- w->pollfd_added = 1;
+ w->pollfd_added = TRUE;
AVAHI_LLIST_PREPEND(AvahiWatch, watches, g->watches, w);
w->pollfd.events = events;
}
+static AvahiWatchEvent watch_get_events(AvahiWatch *w) {
+ assert(w);
+ assert(!w->dead);
+
+ return w->pollfd.revents;
+}
+
static void watch_free(AvahiWatch *w) {
assert(w);
assert(!w->dead);
if (w->pollfd_added) {
g_source_remove_poll(&w->glib_poll->source, &w->pollfd);
- w->pollfd_added = 0;
+ w->pollfd_added = TRUE;
}
- w->dead = 1;
- w->glib_poll->req_cleanup = 1;
+ w->dead = TRUE;
+ w->glib_poll->timeout_req_cleanup = TRUE;
}
-static void set_wakeup(const AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata) {
+static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) {
+ AvahiTimeout *t;
AvahiGLibPoll *g;
-
+
assert(api);
+ assert(callback);
+
g = api->userdata;
+ assert(g);
- if (callback) {
- if (tv)
- g->wakeup = *tv;
- else {
- g->wakeup.tv_sec = 0;
- g->wakeup.tv_usec = 0;
- }
-
- g->wakeup_callback = callback;
- g->wakeup_userdata = userdata;
- } else
- g->wakeup_callback = NULL;
+ if (!(t = avahi_new(AvahiTimeout, 1)))
+ return NULL;
+
+ t->glib_poll = g;
+ t->dead = FALSE;
+
+ if ((t->enabled = !!tv))
+ t->expiry = *tv;
+
+ t->callback = callback;
+ t->userdata = userdata;
+
+ AVAHI_LLIST_PREPEND(AvahiTimeout, timeouts, g->timeouts, t);
+
+ return t;
}
-static void start_wakeup_callback(AvahiGLibPoll *g) {
- AvahiWakeupCallback callback;
- void *userdata;
+static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
+ assert(t);
+ assert(!t->dead);
+
+ if ((t->enabled = !!tv))
+ t->expiry = *tv;
+}
+
+static void timeout_free(AvahiTimeout *t) {
+ assert(t);
+ assert(!t->dead);
+
+ t->dead = TRUE;
+ t->glib_poll->timeout_req_cleanup = TRUE;
+}
+
+static void destroy_timeout(AvahiTimeout *t) {
+ assert(t);
+ AVAHI_LLIST_REMOVE(AvahiTimeout, timeouts, t->glib_poll->timeouts, t);
+ avahi_free(t);
+}
+
+static void cleanup_timeouts(AvahiGLibPoll *g, int all) {
+ AvahiTimeout *t, *next;
assert(g);
- /* Reset the wakeup functions, but allow changing of the two
- values from the callback function */
+ for (t = g->timeouts; t; t = next) {
+ next = t->timeouts_next;
- callback = g->wakeup_callback;
- userdata = g->wakeup_userdata;
- g->wakeup_callback = NULL;
- g->wakeup_userdata = NULL;
+ if (all || t->dead)
+ destroy_timeout(t);
+ }
- assert(callback);
-
- callback(&g->api, userdata);
+ g->timeout_req_cleanup = FALSE;
+}
+
+static AvahiTimeout* find_next_timeout(AvahiGLibPoll *g) {
+ AvahiTimeout *t, *n = NULL;
+ assert(g);
+
+ for (t = g->timeouts; t; t = t->timeouts_next) {
+
+ if (t->dead || !t->enabled)
+ continue;
+
+ if (!n || avahi_timeval_compare(&t->expiry, &n->expiry) < 0)
+ n = t;
+ }
+
+ return n;
+}
+
+static void start_timeout_callback(AvahiTimeout *t) {
+ assert(t);
+ assert(!t->dead);
+ assert(t->enabled);
+
+ t->enabled = 0;
+ t->callback(t, t->userdata);
}
static gboolean prepare_func(GSource *source, gint *timeout) {
AvahiGLibPoll *g = (AvahiGLibPoll*) source;
+ AvahiTimeout *next_timeout;
g_assert(g);
g_assert(timeout);
- if (g->req_cleanup)
- cleanup(g, 0);
+ if (g->watch_req_cleanup)
+ cleanup_watches(g, 0);
+
+ if (g->timeout_req_cleanup)
+ cleanup_timeouts(g, 0);
- if (g->wakeup_callback) {
+ if ((next_timeout = find_next_timeout(g))) {
GTimeVal now;
struct timeval tvnow;
AvahiUsec usec;
tvnow.tv_sec = now.tv_sec;
tvnow.tv_usec = now.tv_usec;
- usec = avahi_timeval_diff(&g->wakeup, &tvnow);
+ usec = avahi_timeval_diff(&next_timeout->expiry, &tvnow);
if (usec <= 0)
return TRUE;
static gboolean check_func(GSource *source) {
AvahiGLibPoll *g = (AvahiGLibPoll*) source;
AvahiWatch *w;
+ AvahiTimeout *next_timeout;
g_assert(g);
- if (g->wakeup_callback) {
+ if ((next_timeout = find_next_timeout(g))) {
GTimeVal now;
struct timeval tvnow;
g_source_get_current_time(source, &now);
tvnow.tv_sec = now.tv_sec;
tvnow.tv_usec = now.tv_usec;
- if (avahi_timeval_compare(&g->wakeup, &tvnow) < 0)
+ if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) < 0)
return TRUE;
}
static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) {
AvahiGLibPoll* g = (AvahiGLibPoll*) source;
AvahiWatch *w;
+ AvahiTimeout *next_timeout;
g_assert(g);
- if (g->wakeup_callback) {
+ if ((next_timeout = find_next_timeout(g))) {
GTimeVal now;
struct timeval tvnow;
g_source_get_current_time(source, &now);
tvnow.tv_sec = now.tv_sec;
tvnow.tv_usec = now.tv_usec;
- if (avahi_timeval_compare(&g->wakeup, &tvnow) < 0) {
- start_wakeup_callback(g);
+ if (avahi_timeval_compare(&next_timeout->expiry, &tvnow) < 0) {
+ start_timeout_callback(next_timeout);
return TRUE;
}
}
return TRUE;
}
-AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context) {
+AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, gint priority) {
AvahiGLibPoll *g;
static GSourceFuncs source_funcs = {
g_main_context_ref(g->context = context ? context : g_main_context_default());
g->api.userdata = g;
+
g->api.watch_new = watch_new;
g->api.watch_free = watch_free;
g->api.watch_update = watch_update;
- g->api.set_wakeup = set_wakeup;
+ g->api.watch_get_events = watch_get_events;
+
+ g->api.timeout_new = timeout_new;
+ g->api.timeout_free = timeout_free;
+ g->api.timeout_update = timeout_update;
- g->wakeup_callback = NULL;
- g->req_cleanup = 0;
+ g->watch_req_cleanup = FALSE;
+ g->timeout_req_cleanup = FALSE;
AVAHI_LLIST_HEAD_INIT(AvahiWatch, g->watches);
+ AVAHI_LLIST_HEAD_INIT(AvahiTimeout, g->timeouts);
g_source_attach(&g->source, g->context);
+ g_source_set_priority(&g->source, priority);
return g;
}
GSource *s = &g->source;
assert(g);
-/* g_message("BEFORE"); */
- cleanup(g, 1);
+ cleanup_watches(g, 1);
+ cleanup_timeouts(g, 1);
-/* g_message("MIDDLE"); */
g_main_context_unref(g->context);
g_source_destroy(s);
g_source_unref(s);
-/* g_message("AFTER"); */
}
const AvahiPoll* avahi_glib_poll_get(AvahiGLibPoll *g) {
AVAHI_C_DECL_BEGIN
#endif
-/** GLib main loop adapter */
+/** GLib main loop adapter. You can safely cast this into a GSource */
typedef struct AvahiGLibPoll AvahiGLibPoll;
/** Create a new GLib main loop adapter attached to the specified
context. If context is NULL, the default main loop context is
used. You can attach as many AvahiGLibPoll objects to the same context
- as you want. */
-AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context);
+ as you want. priority takes on of GLib's G_PRIORITY constants. */
+AvahiGLibPoll *avahi_glib_poll_new(GMainContext *context, gint priority);
/** Free GLib main loop adapter */
void avahi_glib_poll_free(AvahiGLibPoll *g);