From 4f0a5e7572a4257894b4bfede42c26d65152609e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 Aug 2005 21:25:09 +0000 Subject: * strip glib from avahi-core * implement glib memory allocator * add new documentation file MALLOC * initialize pseudo-RNG from /dev/urandom in avahi-daemon * remove some gcc 4.0 warnings * beef up watch system with real timeouts * move GCC __attribute__ macros into its own header avahi-common/gccmacro.h * make use of GCC's sentinel attribute where it make sense * add malloc() implementations that abort on OOM and enable them by default git-svn-id: file:///home/lennart/svn/public/avahi/trunk@308 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-common/Makefile.am | 3 +- avahi-common/domain-test.c | 2 +- avahi-common/domain.c | 17 +++++++ avahi-common/domain.h | 5 ++ avahi-common/error.c | 3 +- avahi-common/error.h | 3 +- avahi-common/gccmacro.h | 47 +++++++++++++++++ avahi-common/malloc.c | 71 ++++++++++++++++++++++++-- avahi-common/malloc.h | 7 +-- avahi-common/simple-watch.c | 120 ++++++++++++++++++++++++++++++-------------- avahi-common/simple-watch.h | 2 +- avahi-common/strlst.h | 5 +- avahi-common/watch-test.c | 41 ++++++++------- avahi-common/watch.h | 3 +- 14 files changed, 256 insertions(+), 73 deletions(-) create mode 100644 avahi-common/gccmacro.h (limited to 'avahi-common') diff --git a/avahi-common/Makefile.am b/avahi-common/Makefile.am index c78e054..8ac6365 100644 --- a/avahi-common/Makefile.am +++ b/avahi-common/Makefile.am @@ -34,7 +34,8 @@ avahi_commoninclude_HEADERS = \ malloc.h watch.h \ timeval.h \ - simple-watch.h + simple-watch.h \ + gccmacro.h noinst_HEADERS = llist.h diff --git a/avahi-common/domain-test.c b/avahi-common/domain-test.c index fc310c7..76f806a 100644 --- a/avahi-common/domain-test.c +++ b/avahi-common/domain-test.c @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) { printf("%i\n", avahi_domain_equal("a", "aaa")); -/* printf("%u = %u\n", avahi_domain_hash("\\Aaaab\\\\."), avahi_domain_hash("aaaa\\b\\\\")); */ + printf("%u = %u\n", avahi_domain_hash("\\Aaaab\\\\."), avahi_domain_hash("aaaa\\b\\\\")); return 0; } diff --git a/avahi-common/domain.c b/avahi-common/domain.c index 5a51a39..3703a04 100644 --- a/avahi-common/domain.c +++ b/avahi-common/domain.c @@ -320,3 +320,20 @@ int avahi_is_valid_host_name(const char *t) { return 1; } + +unsigned avahi_domain_hash(const char *s) { + unsigned hash = 0; + + for (;;) { + char c[65], *p; + + if (!avahi_unescape_label(&s, c, sizeof(c))) + return hash; + + if (!c[0]) + continue; + + for (p = c; *p; p++) + hash = 31 * hash + tolower(*p); + } +} diff --git a/avahi-common/domain.h b/avahi-common/domain.h index 83a9332..c9cc39e 100644 --- a/avahi-common/domain.h +++ b/avahi-common/domain.h @@ -65,6 +65,11 @@ int avahi_is_valid_service_name(const char *t); /** Return 1 when the specified string contains a valid non-FQDN host name (i.e. without dots), 0 otherwise */ int avahi_is_valid_host_name(const char *t); +/** Return some kind of hash value for the domain, useful for using domains as hash table keys. */ +unsigned avahi_domain_hash(const char *name); + + + AVAHI_C_DECL_END #endif diff --git a/avahi-common/error.c b/avahi-common/error.c index 3dca208..b845793 100644 --- a/avahi-common/error.c +++ b/avahi-common/error.c @@ -47,7 +47,8 @@ const char *avahi_strerror(int error) { "Access denied", "Invalid operation", "An unexpected DBUS error occured", - "Could not get a connection to the daemon" + "Could not get a connection to the daemon", + "Memory exhausted" }; if (-error < 0 || -error >= -AVAHI_ERR_MAX) diff --git a/avahi-common/error.h b/avahi-common/error.h index 223ba02..943b49c 100644 --- a/avahi-common/error.h +++ b/avahi-common/error.h @@ -54,7 +54,8 @@ enum { AVAHI_ERR_INVALID_OPERATION = -21, /**< Invalid operation */ AVAHI_ERR_DBUS_ERROR = -22, /**< An unexpected DBUS error occured */ AVAHI_ERR_NOT_CONNECTED = -23, /**< Could not get a connection to the daemon */ - AVAHI_ERR_MAX = -24 + AVAHI_ERR_NO_MEMORY = -24, /**< Memory exhausted */ + AVAHI_ERR_MAX = -25 }; /** Return a human readable error string for the specified error code */ diff --git a/avahi-common/gccmacro.h b/avahi-common/gccmacro.h new file mode 100644 index 0000000..42fb153 --- /dev/null +++ b/avahi-common/gccmacro.h @@ -0,0 +1,47 @@ +#ifndef foogccmacrohfoo +#define foogccmacrohfoo + +/* $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. +***/ + +#ifdef __GNUC__ +#define AVAHI_GCC_SENTINEL __attribute__ ((sentinel)) +#else +#define AVAHI_GCC_SENTINEL +#endif + +#ifdef __GNUC__ +#define AVAHI_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +/** Macro for usage of GCC's printf compilation warnings */ +#define AVAHI_GCC_PRINTF_ATTR(a,b) +#endif + +#define AVAHI_GCC_PRINTF_ATTR12 AVAHI_GCC_PRINTF_ATTR(1,2) +#define AVAHI_GCC_PRINTF_ATTR23 AVAHI_GCC_PRINTF_ATTR(2,3) + +#ifdef __GNUC__ +#define AVAHI_GCC_NORETURN __attribute__((noreturn)) +#else +#define AVAHI_GCC_NORETURN +#endif + +#endif diff --git a/avahi-common/malloc.c b/avahi-common/malloc.c index 1883849..018a0c0 100644 --- a/avahi-common/malloc.c +++ b/avahi-common/malloc.c @@ -27,18 +27,78 @@ #include #include #include +#include #include "malloc.h" static const AvahiAllocator *allocator = NULL; +static void oom(void) AVAHI_GCC_NORETURN; + +static void oom(void) { + + static const char msg[] = "Out of memory, aborting ...\n"; + const char *n = msg; + + while (strlen(n) > 0) { + ssize_t r; + + if ((r = write(2, n, strlen(n))) < 0) + break; + + n += r; + } + + abort(); +} + +/* Default implementation for avahi_malloc() */ +static void* xmalloc(size_t size) { + void *p; + + if (size == 0) + return NULL; + + if (!(p = malloc(size))) + oom(); + + return p; +} + +/* Default implementation for avahi_realloc() */ +static void *xrealloc(void *p, size_t size) { + + if (size == 0) { + free(p); + return NULL; + } + + if (!(p = realloc(p, size))) + oom(); + + return p; +} + +/* Default implementation for avahi_calloc() */ +static void *xcalloc(size_t nmemb, size_t size) { + void *p; + + if (size == 0 || nmemb == 0) + return NULL; + + if (!(p = calloc(nmemb, size))) + oom(); + + return p; +} + void *avahi_malloc(size_t size) { if (size <= 0) return NULL; if (!allocator) - return malloc(size); + return xmalloc(size); assert(allocator->malloc); return allocator->malloc(size); @@ -51,7 +111,7 @@ void *avahi_malloc0(size_t size) { return NULL; if (!allocator) - return calloc(1, size); + return xcalloc(1, size); if (allocator->calloc) return allocator->calloc(1, size); @@ -79,8 +139,13 @@ void avahi_free(void *p) { void *avahi_realloc(void *p, size_t size) { + if (size == 0) { + avahi_free(p); + return NULL; + } + if (!allocator) - return realloc(p, size); + return xrealloc(p, size); assert(allocator->realloc); return allocator->realloc(p, size); diff --git a/avahi-common/malloc.h b/avahi-common/malloc.h index b658357..6d10226 100644 --- a/avahi-common/malloc.h +++ b/avahi-common/malloc.h @@ -28,6 +28,7 @@ #include #include +#include AVAHI_C_DECL_BEGIN @@ -73,12 +74,8 @@ struct AvahiAllocator { * allocators. The structure is not copied! */ void avahi_set_allocator(const AvahiAllocator *a); -#ifdef __GNUC__ -char *avahi_strdup_printf(const char *fmt, ... ) __attribute__ ((format(printf, 1, 2))); -#else /** Like sprintf() but store the result in a freshly allocated buffer. Free this with avahi_free() */ -char *avahi_strdup_printf(const char *fmt, ... ); -#endif +char *avahi_strdup_printf(const char *fmt, ... ) AVAHI_GCC_PRINTF_ATTR12; /** Same as avahi_strdup_printf() but take a va_list instead of varargs */ char *avahi_strdup_vprintf(const char *fmt, va_list ap); diff --git a/avahi-common/simple-watch.c b/avahi-common/simple-watch.c index acc0923..3caf371 100644 --- a/avahi-common/simple-watch.c +++ b/avahi-common/simple-watch.c @@ -51,7 +51,8 @@ struct AvahiSimplePoll { int n_pollfds, max_pollfds, rebuild_pollfds; struct timeval wakeup; - int use_wakeup; + AvahiWakeupCallback wakeup_callback; + void *wakeup_userdata; int req_cleanup; @@ -141,17 +142,24 @@ static void watch_free(AvahiWatch *w) { w->simple_poll->req_cleanup = 1; } -static void set_wakeup_time(AvahiPoll *api, const struct timeval *tv) { +static void set_wakeup(AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata) { AvahiSimplePoll *s; assert(api); s = api->userdata; - if (tv) { - s->wakeup = *tv; - s->use_wakeup = 1; + 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->use_wakeup = 0; + s->wakeup_callback = NULL; } static void destroy_watch(AvahiWatch *w) { @@ -190,10 +198,10 @@ AvahiSimplePoll *avahi_simple_poll_new(void) { s->api.watch_new = watch_new; s->api.watch_free = watch_free; s->api.watch_update = watch_update; - s->api.set_wakeup_time = set_wakeup_time; + s->api.set_wakeup = set_wakeup; s->pollfds = NULL; s->max_pollfds = s->n_pollfds = 0; - s->use_wakeup = 0; + s->wakeup_callback = NULL; s->rebuild_pollfds = 0; s->quit = 0; s->n_watches = 0; @@ -248,41 +256,84 @@ static int rebuild(AvahiSimplePoll *s) { return 0; } -int avahi_simple_poll_iterate(AvahiSimplePoll *s, int block) { - int timeout, r, ret = 0; +static int start_wakeup_callback(AvahiSimplePoll *s) { + AvahiWakeupCallback callback; + void *userdata; + assert(s); - if (s->quit) - return 1; + /* Reset the wakeup functions, but allow changing of the two + values from the callback function */ + + callback = s->wakeup_callback; + userdata = s->wakeup_userdata; + s->wakeup_callback = NULL; + s->wakeup_userdata = NULL; + + assert(callback); + + callback(&s->api, userdata); + return 0; +} + +int avahi_simple_poll_iterate(AvahiSimplePoll *s, int timeout) { + int r; + assert(s); + /* Cleanup things first */ if (s->req_cleanup) cleanup(s, 0); - + + /* Check whether a quit was requested */ + if (s->quit) + return 1; + + /* Do we need to rebuild our array of pollfds? */ if (s->rebuild_pollfds) if (rebuild(s) < 0) return -1; - if (block) { - if (s->use_wakeup) { - struct timeval now; - AvahiUsec usec; + /* Calculate the wakeup time */ + if (s->wakeup_callback) { + struct timeval now; + int t; + AvahiUsec usec; - gettimeofday(&now, NULL); + gettimeofday(&now, NULL); + usec = avahi_timeval_diff(&s->wakeup, &now); - usec = avahi_timeval_diff(&s->wakeup, &now); - - timeout = usec <= 0 ? 0 : (int) (usec / 1000); - } else - timeout = -1; - } else - timeout = 0; + if (usec <= 0) + /* Timeout elapsed */ + + return start_wakeup_callback(s); + + /* Calculate sleep time. We add 1ms because otherwise we'd + * wake up too early most of the time */ + t = (int) (usec / 1000) + 1; + + if (timeout < 0 || timeout > t) + timeout = t; + } if ((r = poll(s->pollfds, s->n_pollfds, timeout)) < 0) return -1; - else if (r > 0) { + /* Check whether the wakeup time has been reached now */ + if (s->wakeup_callback) { + struct timeval now; + + gettimeofday(&now, NULL); + + if (avahi_timeval_compare(&s->wakeup, &now) <= 0) + /* Time elapsed */ + return start_wakeup_callback(s); + } + + if (r > 0) { AvahiWatch *w; + /* Look for some kind of I/O event */ + for (w = s->watches; w; w = w->watches_next) { if (w->dead) @@ -291,24 +342,15 @@ int avahi_simple_poll_iterate(AvahiSimplePoll *s, int block) { assert(w->idx >= 0); assert(w->idx < s->n_pollfds); - if (s->pollfds[w->idx].revents > 0) + if (s->pollfds[w->idx].revents > 0) { + /* We execute only on callback in every iteration */ w->callback(w, w->pollfd.fd, s->pollfds[w->idx].revents, w->userdata); - - if (s->quit) { - ret = 1; - goto finish; + return 0; } } } - ret = 0; - -finish: - - if (s->req_cleanup) - cleanup(s, 0); - - return ret; + return 0; } void avahi_simple_poll_quit(AvahiSimplePoll *w) { diff --git a/avahi-common/simple-watch.h b/avahi-common/simple-watch.h index 600e5ce..127ddc5 100644 --- a/avahi-common/simple-watch.h +++ b/avahi-common/simple-watch.h @@ -35,7 +35,7 @@ void avahi_simple_poll_free(AvahiSimplePoll *s); AvahiPoll* avahi_simple_poll_get(AvahiSimplePoll *s); -int avahi_simple_poll_iterate(AvahiSimplePoll *s, int block); +int avahi_simple_poll_iterate(AvahiSimplePoll *s, int sleep_time); void avahi_simple_poll_quit(AvahiSimplePoll *s); diff --git a/avahi-common/strlst.h b/avahi-common/strlst.h index 56bf525..10b7aa6 100644 --- a/avahi-common/strlst.h +++ b/avahi-common/strlst.h @@ -29,6 +29,7 @@ #include #include +#include AVAHI_C_DECL_BEGIN @@ -47,7 +48,7 @@ typedef struct AvahiStringList { /** Create a new string list by taking a variable list of NUL * terminated strings. The strings are copied using g_strdup(). The * argument list must be terminated by a NULL pointer. */ -AvahiStringList *avahi_string_list_new(const char *txt, ...); +AvahiStringList *avahi_string_list_new(const char *txt, ...) AVAHI_GCC_SENTINEL; /** Same as avahi_string_list_new() but pass a va_list structure */ AvahiStringList *avahi_string_list_new_va(va_list va); @@ -79,7 +80,7 @@ AvahiStringList*avahi_string_list_add_anonymous(AvahiStringList *l, size_t size) /** Same as avahi_string_list_add(), but takes a variable number of * NUL terminated strings. The argument list must be terminated by a * NULL pointer. Returns the new list start. */ -AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...); +AvahiStringList *avahi_string_list_add_many(AvahiStringList *r, ...) AVAHI_GCC_SENTINEL; /** Same as avahi_string_list_add_many(), but use a va_list * structure. Returns the new list start. */ diff --git a/avahi-common/watch-test.c b/avahi-common/watch-test.c index f87a303..af46805 100644 --- a/avahi-common/watch-test.c +++ b/avahi-common/watch-test.c @@ -34,6 +34,7 @@ #include "timeval.h" static AvahiPoll *api = NULL; +static AvahiSimplePoll *simple_poll = NULL; static void callback(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata) { @@ -51,31 +52,35 @@ static void callback(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdat } } +static void wakeup(AvahiPoll *_api, void *userdata) { + static int i = 0; + struct timeval tv; + + printf("Wakeup #%i\n", i++); + + if (i > 10) + avahi_simple_poll_quit(simple_poll); + else { + avahi_elapse_time(&tv, 1000, 0); + api->set_wakeup(api, &tv, wakeup, NULL); + } +} + int main(int argc, char *argv[]) { - int i = 0; - AvahiSimplePoll *s; + struct timeval tv; - s = avahi_simple_poll_new(); - assert(s); - - api = avahi_simple_poll_get(s); + simple_poll = avahi_simple_poll_new(); + api = avahi_simple_poll_get(simple_poll); api->watch_new(api, 0, AVAHI_WATCH_IN, callback, NULL); - for (;;) { - struct timeval tv; - printf("Iteration %i\n", i++); - - if (i > 100) - avahi_simple_poll_quit(s); + avahi_elapse_time(&tv, 1000, 0); + api->set_wakeup(api, &tv, wakeup, NULL); - avahi_elapse_time(&tv, 1000, 0); - - api->set_wakeup_time(api, &tv); - - if (avahi_simple_poll_iterate(s, 1) != 0) + /* Our main loop */ + for (;;) + if (avahi_simple_poll_iterate(simple_poll, -1) != 0) break; - } return 0; } diff --git a/avahi-common/watch.h b/avahi-common/watch.h index b26c2ba..70dedb7 100644 --- a/avahi-common/watch.h +++ b/avahi-common/watch.h @@ -40,6 +40,7 @@ typedef enum { } AvahiWatchEvent; typedef void (*AvahiWatchCallback)(AvahiWatch *w, int fd, AvahiWatchEvent event, void *userdata); +typedef void (*AvahiWakeupCallback)(AvahiPoll *api, void *userdata); struct AvahiPoll { void* userdata; @@ -48,7 +49,7 @@ struct AvahiPoll { void (*watch_update)(AvahiWatch *w, AvahiWatchEvent event); void (*watch_free)(AvahiWatch *w); - void (*set_wakeup_time)(AvahiPoll *api, const struct timeval *tv); + void (*set_wakeup)(AvahiPoll *api, const struct timeval *tv, AvahiWakeupCallback callback, void *userdata); }; AVAHI_C_DECL_END -- cgit