AvahiRecordBrowserCallback callback;
gpointer userdata;
+ guint scan_idle_source;
AVAHI_LLIST_FIELDS(AvahiRecordBrowser, browser);
AVAHI_LLIST_FIELDS(AvahiRecordBrowser, by_key);
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;
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;
}
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;
+ }
+
}
}
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);
}
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>
+#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)
{
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);
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;
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;
}
#include <avahi-core/llist.h>
#include "simple-protocol.h"
+#include "main.h"
#define BUFFER_SIZE (10*1024)
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);
};
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);
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;
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 <hostname>\n"
+ "+ RESOLVE-HOSTNAME-IPV6 <hostname>\n"
+ "+ RESOLVE-HOSTNAME-IPV4 <hostname>\n"
+ "+ RESOLVE-ADDRESS <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) {
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 =