From f334deaf9d630782be3f7f535265ff7488162f85 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Jun 2005 16:32:27 +0000 Subject: [PATCH] * update avahi_address_parse() to work with AF_UNSPEC address family * complete simple protocol * defer scanning already cached RRs when browsing into its own main loop job git-svn-id: file:///home/lennart/svn/public/avahi/trunk@114 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-common/address.c | 18 +++-- avahi-core/browse.c | 26 ++++++- avahi-core/resolve-host-name.c | 1 - avahi-daemon/main.c | 33 ++++++++- avahi-daemon/main.h | 29 ++++++++ avahi-daemon/simple-protocol.c | 119 ++++++++++++++++++++++++++++++++- 6 files changed, 213 insertions(+), 13 deletions(-) create mode 100644 avahi-daemon/main.h diff --git a/avahi-common/address.c b/avahi-common/address.c index 3484707..3e6fc97 100644 --- a/avahi-common/address.c +++ b/avahi-common/address.c @@ -115,10 +115,20 @@ AvahiAddress *avahi_address_parse(const char *s, guchar family, AvahiAddress *re g_assert(ret_addr); g_assert(s); - if (inet_pton(family, s, ret_addr->data.data) < 0) - return NULL; - - ret_addr->family = family; + if (family == AF_UNSPEC) { + if (inet_pton(AF_INET, s, ret_addr->data.data) <= 0) { + if (inet_pton(AF_INET6, s, ret_addr->data.data) <= 0) + return NULL; + else + ret_addr->family = AF_INET6; + } else + ret_addr->family = AF_INET; + } else { + if (inet_pton(family, s, ret_addr->data.data) <= 0) + return NULL; + + ret_addr->family = family; + } return ret_addr; } diff --git a/avahi-core/browse.c b/avahi-core/browse.c index deeb465..10d71cb 100644 --- a/avahi-core/browse.c +++ b/avahi-core/browse.c @@ -40,6 +40,7 @@ struct AvahiRecordBrowser { AvahiRecordBrowserCallback callback; gpointer userdata; + guint scan_idle_source; AVAHI_LLIST_FIELDS(AvahiRecordBrowser, browser); AVAHI_LLIST_FIELDS(AvahiRecordBrowser, by_key); @@ -102,6 +103,17 @@ static void scan_interface_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, avahi_cache_walk(i->cache, s->key, scan_cache_callback, &cbdata); } +gboolean scan_idle_callback(gpointer data) { + AvahiRecordBrowser *b = data; + g_assert(b); + + /* Scan the caches */ + avahi_interface_monitor_walk(b->server->monitor, b->interface, b->protocol, scan_interface_callback, b); + b->scan_idle_source = (guint) -1; + + return FALSE; +} + AvahiRecordBrowser *avahi_record_browser_new(AvahiServer *server, gint interface, guchar protocol, AvahiKey *key, AvahiRecordBrowserCallback callback, gpointer userdata) { AvahiRecordBrowser *b, *t; GTimeVal tv; @@ -135,9 +147,8 @@ AvahiRecordBrowser *avahi_record_browser_new(AvahiServer *server, gint interface AVAHI_LLIST_PREPEND(AvahiRecordBrowser, by_key, t, b); g_hash_table_replace(server->record_browser_hashtable, key, t); - /* Scan the caches */ - avahi_interface_monitor_walk(b->server->monitor, b->interface, b->protocol, scan_interface_callback, b); - + /* The currenlty cached entries are scanned a bit later */ + b->scan_idle_source = g_idle_add_full(G_PRIORITY_HIGH, scan_idle_callback, b, NULL); return b; } @@ -151,6 +162,12 @@ void avahi_record_browser_free(AvahiRecordBrowser *b) { if (b->time_event) { avahi_time_event_queue_remove(b->server->time_event_queue, b->time_event); b->time_event = NULL; + + if (b->scan_idle_source != (guint) -1) { + g_source_remove(b->scan_idle_source); + b->scan_idle_source = (guint) -1; + } + } } @@ -171,6 +188,9 @@ void avahi_record_browser_destroy(AvahiRecordBrowser *b) { if (b->time_event) avahi_time_event_queue_remove(b->server->time_event_queue, b->time_event); avahi_key_unref(b->key); + + if (b->scan_idle_source != (guint) -1) + g_source_remove(b->scan_idle_source); g_free(b); } diff --git a/avahi-core/resolve-host-name.c b/avahi-core/resolve-host-name.c index f29b575..2cfd435 100644 --- a/avahi-core/resolve-host-name.c +++ b/avahi-core/resolve-host-name.c @@ -125,7 +125,6 @@ AvahiHostNameResolver *avahi_host_name_resolver_new(AvahiServer *server, gint in r->time_event = avahi_time_event_queue_add(server->time_event_queue, &tv, time_event_callback, r); AVAHI_LLIST_PREPEND(AvahiHostNameResolver, resolver, server->host_name_resolvers, r); - if (aprotocol == AF_INET || aprotocol == AF_UNSPEC) { k = avahi_key_new(host_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A); diff --git a/avahi-daemon/main.c b/avahi-daemon/main.c index 3875865..7b3f209 100644 --- a/avahi-daemon/main.c +++ b/avahi-daemon/main.c @@ -29,10 +29,13 @@ #include #include +#include "main.h" #include "simple-protocol.h" #define DBUS_SERVICE_AVAHI "org.freedesktop.Avahi" +AvahiServer *avahi_server = NULL; + static DBusHandlerResult do_register (DBusConnection *conn, DBusMessage *message) { @@ -112,12 +115,30 @@ signal_filter (DBusConnection *conn, DBusMessage *message, void *user_data) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - + +static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) { + g_assert(s); + + if (state == AVAHI_SERVER_RUNNING) + g_message("Server startup complete. Host name is <%s>", avahi_server_get_host_name_fqdn(s)); + else if (state == AVAHI_SERVER_COLLISION) { + gchar *n; + n = avahi_alternative_host_name(avahi_server_get_host_name(s)); + g_message("Host name conflict, retrying with <%s>", n); + avahi_server_set_host_name(s, n); + g_free(n); + } +} + int main(int argc, char *argv[]) { GMainLoop *loop = NULL; DBusConnection *bus = NULL; DBusError error; - gint r = -1; + gint r = 255; + AvahiServer *server = NULL; + AvahiServerConfig config; + + avahi_server_config_init(&config); loop = g_main_loop_new(NULL, FALSE); @@ -162,6 +183,9 @@ int main(int argc, char *argv[]) { if (simple_protocol_setup(NULL) < 0) goto finish; + if (!(avahi_server = avahi_server_new(NULL, &config, server_callback, NULL))) + goto finish; + g_main_loop_run(loop); r = 0; @@ -175,8 +199,13 @@ finish: dbus_connection_unref(bus); } + if (avahi_server) + avahi_server_free(avahi_server); + if (loop) g_main_loop_unref(loop); + avahi_server_config_free(&config); + return r; } diff --git a/avahi-daemon/main.h b/avahi-daemon/main.h new file mode 100644 index 0000000..8db60e4 --- /dev/null +++ b/avahi-daemon/main.h @@ -0,0 +1,29 @@ +#ifndef foomainhfoo +#define foomainhfoo + +/* $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 + +extern AvahiServer *avahi_server; + +#endif diff --git a/avahi-daemon/simple-protocol.c b/avahi-daemon/simple-protocol.c index 71dd639..91a8287 100644 --- a/avahi-daemon/simple-protocol.c +++ b/avahi-daemon/simple-protocol.c @@ -36,6 +36,7 @@ #include #include "simple-protocol.h" +#include "main.h" #define BUFFER_SIZE (10*1024) @@ -47,14 +48,26 @@ typedef struct Client Client; typedef struct Server Server; +typedef enum { + CLIENT_IDLE, + CLIENT_RESOLVE_HOSTNAME, + CLIENT_RESOLVE_ADDRESS, + CLIENT_DEAD +} ClientState; + struct Client { Server *server; + + ClientState state; gint fd; GPollFD poll_fd; gchar inbuf[BUFFER_SIZE], outbuf[BUFFER_SIZE]; guint inbuf_length, outbuf_length; + + AvahiHostNameResolver *host_name_resolver; + AvahiAddressResolver *address_resolver; AVAHI_LLIST_FIELDS(Client, clients); }; @@ -76,6 +89,12 @@ static void client_free(Client *c) { g_assert(c->server->n_clients >= 1); c->server->n_clients--; + + if (c->host_name_resolver) + avahi_host_name_resolver_free(c->host_name_resolver); + + if (c->address_resolver) + avahi_address_resolver_free(c->address_resolver); g_source_remove_poll(&c->server->source, &c->poll_fd); close(c->fd); @@ -91,9 +110,13 @@ static void client_new(Server *s, int fd) { c = g_new(Client, 1); c->server = s; c->fd = fd; + c->state = CLIENT_IDLE; c->inbuf_length = c->outbuf_length = 0; + c->host_name_resolver = NULL; + c->address_resolver = NULL; + memset(&c->poll_fd, 0, sizeof(GPollFD)); c->poll_fd.fd = fd; c->poll_fd.events = G_IO_IN|G_IO_ERR|G_IO_HUP; @@ -117,16 +140,101 @@ static void client_output(Client *c, const guint8*data, guint size) { memcpy(c->outbuf + c->outbuf_length, data, m); c->outbuf_length += m; + + c->poll_fd.events |= G_IO_OUT; +} + +static void client_output_printf(Client *c, gchar *format, ...) { + gchar txt[256]; + va_list ap; + + va_start(ap, format); + vsnprintf(txt, sizeof(txt), format, ap); + va_end(ap); + + client_output(c, (guint8*) txt, strlen(txt)); +} + +static void host_name_resolver_callback(AvahiHostNameResolver *r, gint iface, guchar protocol, AvahiBrowserEvent event, const gchar *hostname, const AvahiAddress *a, gpointer userdata) { + Client *c = userdata; + + g_assert(c); + + + if (event == AVAHI_RESOLVER_TIMEOUT) + client_output_printf(c, "- Query timed out\n"); + else { + gchar t[64]; + avahi_address_snprint(t, sizeof(t), a); + client_output_printf(c, "+ %s\n", t); + } + + c->state = CLIENT_DEAD; +} + +static void address_resolver_callback(AvahiAddressResolver *r, gint iface, guchar protocol, AvahiBrowserEvent event, const AvahiAddress *a, const gchar *hostname, gpointer userdata) { + Client *c = userdata; + + g_assert(c); + + if (event == AVAHI_RESOLVER_TIMEOUT) + client_output_printf(c, "- Query timed out\n"); + else + client_output_printf(c, "+ %s\n", hostname); + + c->state = CLIENT_DEAD; } static void handle_line(Client *c, const gchar *s) { - gchar t[256]; + gchar cmd[64], arg[64]; + gint n_args; g_assert(c); g_assert(s); - snprintf(t, sizeof(t), "you said <%s>\n", s); - client_output(c, (guint8*) t, strlen(t)); + if (c->state != CLIENT_IDLE) + return; + + if ((n_args = sscanf(s, "%63s %63s", cmd, arg)) < 1 ) { + client_output_printf(c, "- Failed to parse command, try \"HELP\".\n"); + c->state = CLIENT_DEAD; + return; + } + + if (strcmp(cmd, "HELP") == 0) { + client_output_printf(c, + "+ Available commands are:\n" + "+ RESOLVE-HOSTNAME \n" + "+ RESOLVE-HOSTNAME-IPV6 \n" + "+ RESOLVE-HOSTNAME-IPV4 \n" + "+ RESOLVE-ADDRESS
\n"); + c->state = CLIENT_DEAD; } + else if (strcmp(cmd, "FUCK") == 0 && n_args == 1) { + client_output_printf(c, "FUCK: Go fuck yourself!\n"); + c->state = CLIENT_DEAD; + } else if (strcmp(cmd, "RESOLVE-HOSTNAME-IPV4") == 0 && n_args == 2) { + c->state = CLIENT_RESOLVE_HOSTNAME; + c->host_name_resolver = avahi_host_name_resolver_new(avahi_server, -1, AF_UNSPEC, arg, AF_INET, host_name_resolver_callback, c); + } else if (strcmp(cmd, "RESOLVE-HOSTNAME-IPV6") == 0 && n_args == 2) { + c->state = CLIENT_RESOLVE_HOSTNAME; + c->host_name_resolver = avahi_host_name_resolver_new(avahi_server, -1, AF_UNSPEC, arg, AF_INET6, host_name_resolver_callback, c); + } else if (strcmp(cmd, "RESOLVE-HOSTNAME") == 0 && n_args == 2) { + c->state = CLIENT_RESOLVE_HOSTNAME; + c->host_name_resolver = avahi_host_name_resolver_new(avahi_server, -1, AF_UNSPEC, arg, AF_UNSPEC, host_name_resolver_callback, c); + } else if (strcmp(cmd, "RESOLVE-ADDRESS") == 0 && n_args == 2) { + AvahiAddress addr; + + if (!(avahi_address_parse(arg, AF_UNSPEC, &addr))) { + client_output_printf(c, "- Failed to parse address \"%s\".\n", arg); + c->state = CLIENT_DEAD; + } else { + c->state = CLIENT_RESOLVE_ADDRESS; + c->address_resolver = avahi_address_resolver_new(avahi_server, -1, AF_UNSPEC, &addr, address_resolver_callback, c); + } + } else { + client_output_printf(c, "- Invalid command \"%s\", try \"HELP\".\n", cmd); + c->state = CLIENT_DEAD; + } } static void handle_input(Client *c) { @@ -181,6 +289,11 @@ static void client_work(Client *c) { if (c->outbuf_length) memmove(c->outbuf, c->outbuf + r, c->outbuf_length - r); + + if (c->outbuf_length == 0 && c->state == CLIENT_DEAD) { + client_free(c); + return; + } } c->poll_fd.events = -- 2.39.5