announce.c announce.h \
subscribe.c subscribe.h \
strlst.c strlst.h \
- rrlist.c rrlist.h
+ rrlist.c rrlist.h \
+ alternative.c alternative.h
prioq_test_SOURCES = \
prioq-test.c \
alternative_test_SOURCES = \
alternative-test.c \
- util.c util.h
+ alternative.c alternative.h
alternative_test_CFLAGS = $(AM_CFLAGS)
alternative_test_LDADD = $(AM_LDADD)
#include <stdio.h>
-#include "util.h"
+#include "alternative.h"
int main(int argc, char *argv[]) {
gchar *r = NULL;
--- /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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "alternative.h"
+
+gchar * avahi_alternative_host_name(const gchar *s) {
+ const gchar *p, *e = NULL;
+ gchar *c, *r;
+ gint n;
+
+ g_assert(s);
+
+ for (p = s; *p; p++)
+ if (!isdigit(*p))
+ e = p+1;
+
+ if (e && *e)
+ n = atoi(e)+1;
+ else
+ n = 2;
+
+ c = e ? g_strndup(s, e-s) : g_strdup(s);
+ r = g_strdup_printf("%s%i", c, n);
+ g_free(c);
+
+ return r;
+
+}
+
+gchar *avahi_alternative_service_name(const gchar *s) {
+ const gchar *e;
+ g_assert(s);
+
+ if ((e = strstr(s, " #"))) {
+ const gchar *n, *p;
+ e += 2;
+
+ while ((n = strstr(e, " #")))
+ e = n + 2;
+
+ for (p = e; *p; p++)
+ if (!isdigit(*p)) {
+ e = NULL;
+ break;
+ }
+ }
+
+ if (e) {
+ gchar *r, *c = g_strndup(s, e-s);
+ r = g_strdup_printf("%s%i", c, atoi(e)+1);
+ g_free(c);
+ return r;
+ } else
+ return g_strdup_printf("%s #2", s);
+}
--- /dev/null
+#ifndef fooalternativehfoo
+#define fooalternativehfoo
+
+/* $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 <glib.h>
+
+/** Find an alternative for the specified host name. If called with an
+ * original host name, "2" is appended, Afterwards the number is
+ * increased on each call. (i.e. "foo" becomes "foo2" becomes "foo3"
+ * and so on.)*/
+gchar *avahi_alternative_host_name(const gchar *s);
+
+/** Find an alternative for the specified service name. If called with
+ an original service name, " #2" is appended. Afterwards the number
+ is increased on each call (i.e. "foo" becomes "foo #2" becomes
+ "foo #3" and so on.)*/
+gchar *avahi_alternative_service_name(const gchar *s);
+
+#endif
gchar *t;
- g_message("Enough probes for record [%s]", t = avahi_record_to_string(a->entry->record));
- g_free(t);
+/* g_message("Enough probes for record [%s]", t = avahi_record_to_string(a->entry->record)); */
+/* g_free(t); */
if (a->entry->group) {
g_assert(a->entry->group->n_probing);
avahi_server_generate_response(a->server, a->interface, NULL, NULL, 0, FALSE);
if (++a->n_iteration >= 4) {
- gchar *t;
+/* gchar *t; */
/* Announcing done */
- g_message("Enough announcements for record [%s]", t = avahi_record_to_string(a->entry->record));
- g_free(t);
+/* g_message("Enough announcements for record [%s]", t = avahi_record_to_string(a->entry->record)); */
+/* g_free(t); */
a->state = AVAHI_ESTABLISHED;
static void new_announcement(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) {
AvahiAnnouncement *a;
- gchar *t;
+/* gchar *t; */
g_assert(s);
g_assert(i);
/* We don't want duplicate announcements */
if (avahi_get_announcement(s, e, i))
- return;
+ return;
a = g_new(AvahiAnnouncement, 1);
a->server = s;
go_to_initial_state(a, FALSE);
- g_message("New announcement on interface %s.%i for entry [%s] state=%i", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record), a->state);
- g_free(t);
+/* g_message("New announcement on interface %s.%i for entry [%s] state=%i", i->hardware->name, i->protocol, t = avahi_record_to_string(e->record), a->state); */
+/* g_free(t); */
}
void avahi_announce_interface(AvahiServer *s, AvahiInterface *i) {
#include <stdlib.h>
#include "core.h"
+#include "alternative.h"
+
+static AvahiEntryGroup *group = NULL;
+static AvahiServer *server = NULL;
+static gchar *service_name = NULL;
static gboolean quit_timeout(gpointer data) {
g_main_loop_quit(data);
g_free(t);
}
+
+static void remove_entries(void);
+static void create_entries(gboolean new_name);
+
static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
- g_message("entry group state: %i", state);
+ g_message("=======> entry group state: %i", state);
+
+ if (state == AVAHI_ENTRY_GROUP_COLLISION) {
+ remove_entries();
+ create_entries(TRUE);
+ }
}
-int main(int argc, char *argv[]) {
- AvahiServer *avahi;
- GMainLoop *loop = NULL;
- AvahiSubscription *s;
- AvahiKey *k;
- AvahiEntryGroup *g;
-
- avahi = avahi_server_new(NULL, NULL);
+static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) {
+ g_message("=======> server state: %i", state);
+
+ if (state == AVAHI_SERVER_RUNNING)
+ create_entries(FALSE);
+ else if (state == AVAHI_SERVER_COLLISION) {
+ gchar *n;
+ remove_entries();
+
+ n = avahi_alternative_host_name(avahi_server_get_host_name(s));
+ avahi_server_set_host_name(s, n);
+ g_free(n);
+ }
+}
+
+static void remove_entries(void) {
+ if (group)
+ avahi_entry_group_free(group);
- g = avahi_entry_group_new(avahi, entry_group_callback, NULL);
+ group = NULL;
+}
+
+static void create_entries(gboolean new_name) {
+ remove_entries();
+
+ group = avahi_entry_group_new(server, entry_group_callback, NULL);
-/* avahi_server_add_text(avahi, g, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, "HALLO", avahi_server_get_hostname(avahi), NULL); */
-/* avahi_server_add_text(avahi, g, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, "hallo", "waldo", NULL); */
+ if (!service_name)
+ service_name = g_strdup("Test Service");
+ else if (new_name) {
+ gchar *n = avahi_alternative_service_name(avahi_server_get_host_name(server));
+ g_free(service_name);
+ service_name = n;
+ }
- avahi_server_add_service(avahi, g, 0, AF_UNSPEC, "_http._tcp", "gurke", NULL, NULL, 80, "foo", NULL);
+ avahi_server_add_service(server, group, 0, AF_UNSPEC, "_http._tcp", service_name, NULL, NULL, 80, "foo", NULL);
+ avahi_server_add_service(server, group, 0, AF_UNSPEC, "_ftp._tcp", service_name, NULL, NULL, 21, "foo", NULL);
+ avahi_server_add_service(server, group, 0, AF_UNSPEC, "_webdav._tcp", service_name, NULL, NULL, 80, "foo", NULL);
- avahi_entry_group_commit(g);
+ avahi_entry_group_commit(group);
- avahi_server_dump(avahi, stdout);
+}
+int main(int argc, char *argv[]) {
+ GMainLoop *loop = NULL;
+/* AvahiSubscription *s; */
+/* AvahiKey *k; */
+ server = avahi_server_new(NULL, NULL, server_callback, NULL);
+
/* k = avahi_key_new("HALLO", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT); */
/* s = avahi_subscription_new(avahi, k, 0, AF_UNSPEC, subscription, NULL); */
/* avahi_key_unref(k); */
loop = g_main_loop_new(NULL, FALSE);
- g_timeout_add(1000*5, dump_timeout, avahi);
+ g_timeout_add(1000*5, dump_timeout, server);
/* g_timeout_add(1000*30, quit_timeout, loop); */
g_main_loop_run(loop);
g_main_loop_unref(loop);
/* avahi_subscription_free(s); */
- avahi_entry_group_free(g);
- avahi_server_free(avahi);
+
+ if (group)
+ avahi_entry_group_free(group);
+
+ if (server)
+ avahi_server_free(server);
+
+ g_free(service_name);
return 0;
}
}
void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const AvahiAddress *a) {
- gchar *txt;
+/* gchar *txt; */
g_assert(c);
g_assert(r && r->ref >= 1);
- g_message("cache update: %s", (txt = avahi_record_to_string(r)));
- g_free(txt);
+/* g_message("cache update: %s", (txt = avahi_record_to_string(r))); */
+/* g_free(txt); */
if (r->ttl == 0) {
/* This is a goodbye request */
if (e) {
- g_message("found matching cache entry");
+/* g_message("found matching cache entry"); */
/* We need to update the hash table key if we replace the
* record */
} else {
/* No entry found, therefore we create a new one */
- g_message("couldn't find matching cache entry");
+/* g_message("couldn't find matching cache entry"); */
e = g_new(AvahiCacheEntry, 1);
e->cache = c;
#include "core.h"
#include "util.h"
+#include "alternative.h"
static gchar *name = NULL;
static AvahiEntryGroup *group = NULL;
static gboolean rename_timeout(gpointer data) {
-
if (access("flag", F_OK) == 0) {
create_service("New - Bonjour Service Name");
return FALSE;
return TRUE;
}
-
-
static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
if (state == AVAHI_ENTRY_GROUP_COLLISION)
create_service(NULL);
}
}
+static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) {
+ g_message("server state: %i", state);
+}
+
int main(int argc, char *argv[]) {
GMainLoop *loop = NULL;
- avahi = avahi_server_new(NULL, NULL);
+ avahi = avahi_server_new(NULL, NULL, server_callback, NULL);
create_service("gurke");
avahi_server_dump(avahi, stdout);
#include <stdio.h>
#include <glib.h>
+/** An mDNS responder object */
typedef struct AvahiServer AvahiServer;
+
+/** A locally registered DNS resource record */
typedef struct AvahiEntry AvahiEntry;
+
+/** A group of locally registered DNS RRs */
typedef struct AvahiEntryGroup AvahiEntryGroup;
#include <avahi-core/address.h>
#include <avahi-core/rr.h>
+/** States of a server object */
typedef enum {
- AVAHI_ENTRY_NULL = 0,
- AVAHI_ENTRY_UNIQUE = 1,
- AVAHI_ENTRY_NOPROBE = 2,
- AVAHI_ENTRY_NOANNOUNCE = 4
+ AVAHI_SERVER_INVALID = -1, /**< Invalid state (initial) */
+ AVAHI_SERVER_REGISTERING = 0, /**< Host RRs are being registered */
+ AVAHI_SERVER_RUNNING, /**< All host RRs have been established */
+ AVAHI_SERVER_COLLISION /**< There is a collision with a host RR. All host RRs have been withdrawn, the user should set a new host name via avahi_server_set_host_name() */
+} AvahiServerState;
+
+/** Flags for server entries */
+typedef enum {
+ AVAHI_ENTRY_NULL = 0, /**< No special flags */
+ AVAHI_ENTRY_UNIQUE = 1, /**< The RRset is intended to be unique */
+ AVAHI_ENTRY_NOPROBE = 2, /**< Though the RRset is intended to be unique no probes shall be sent */
+ AVAHI_ENTRY_NOANNOUNCE = 4 /**< Do not announce this RR to other hosts */
} AvahiEntryFlags;
+/** States of an entry group object */
typedef enum {
- AVAHI_ENTRY_GROUP_UNCOMMITED,
- AVAHI_ENTRY_GROUP_REGISTERING,
- AVAHI_ENTRY_GROUP_ESTABLISHED,
- AVAHI_ENTRY_GROUP_COLLISION
+ AVAHI_ENTRY_GROUP_UNCOMMITED = -1, /**< The group has not yet been commited, the user must still call avahi_entry_group_commit() */
+ AVAHI_ENTRY_GROUP_REGISTERING = 0, /**< The entries of the group are currently being registered */
+ AVAHI_ENTRY_GROUP_ESTABLISHED, /**< The entries have successfully been established */
+ AVAHI_ENTRY_GROUP_COLLISION /**< A name collision for one of the entries in the group has been detected, the entries have been withdrawn */
} AvahiEntryGroupState;
+/** Prototype for callback functions which are called whenever the state of an AvahiServer object changes */
+typedef void (*AvahiServerCallback) (AvahiServer *s, AvahiServerState state, gpointer userdata);
+
+/** Prototype for callback functions which are called whenever the state of an AvahiEntryGroup object changes */
typedef void (*AvahiEntryGroupCallback) (AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata);
+/** Stores configuration options for a server instance */
typedef struct AvahiServerConfig {
- gboolean register_hinfo;
- gboolean register_addresses;
- gboolean use_ipv4;
- gboolean use_ipv6;
- gchar *host_name;
- gchar *domain_name;
- gboolean check_response_ttl;
+ gchar *host_name; /**< Default host name. If left empty defaults to the result of gethostname(2) of the libc */
+ gchar *domain_name; /**< Default domain name. If left empty defaults to .local */
+ gboolean use_ipv4; /**< Enable IPv4 support */
+ gboolean use_ipv6; /**< Enable IPv6 support */
+ gboolean register_hinfo; /**< Register a HINFO record for the host containing the local OS and CPU type */
+ gboolean register_addresses; /**< Register A, AAAA and PTR records for all local IP addresses */
+ gboolean check_response_ttl; /**< If enabled the server ignores all incoming responses with IP TTL != 255 */
} AvahiServerConfig;
-AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc);
+/** Allocate a new mDNS responder object. */
+AvahiServer *avahi_server_new(
+ GMainContext *c, /**< The GLIB main loop context to attach to */
+ const AvahiServerConfig *sc, /**< If non-NULL a pointer to a configuration structure for the server */
+ AvahiServerCallback callback, /**< A callback which is called whenever the state of the server changes */
+ gpointer userdata /**< An opaque pointer which is passed to the callback function */);
+
+/** Free an mDNS responder object */
void avahi_server_free(AvahiServer* s);
AvahiServerConfig* avahi_server_config_init(AvahiServerConfig *c);
AvahiServerConfig* avahi_server_config_copy(AvahiServerConfig *ret, const AvahiServerConfig *c);
void avahi_server_config_free(AvahiServerConfig *c);
-const gchar* avahi_server_get_domain(AvahiServer *s);
+const gchar* avahi_server_get_domain_name(AvahiServer *s);
const gchar* avahi_server_get_host_name(AvahiServer *s);
+const gchar* avahi_server_get_host_name_fqdn(AvahiServer *s);
+
+void avahi_server_set_host_name(AvahiServer *s, const gchar *host_name);
+void avahi_server_set_domain_name(AvahiServer *s, const gchar *domain_name);
+
+gpointer avahi_server_get_data(AvahiServer *s);
+void avahi_server_set_data(AvahiServer *s, gpointer userdata);
+
+AvahiServerState avhai_server_get_state(AvahiServer *s);
const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiEntryGroup *g, void **state);
void avahi_server_dump(AvahiServer *s, FILE *f);
void avahi_entry_group_free(AvahiEntryGroup *g);
void avahi_entry_group_commit(AvahiEntryGroup *g);
AvahiEntryGroupState avahi_entry_group_get_state(AvahiEntryGroup *g);
+void avahi_entry_group_set_data(AvahiEntryGroup *g, gpointer userdata);
+gpointer avahi_entry_group_get_data(AvahiEntryGroup *g);
void avahi_server_add(
AvahiServer *s,
#include "socket.h"
#include "announce.h"
-static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a, int remove) {
+static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a, gboolean remove) {
g_assert(m);
g_assert(a);
- if (!avahi_interface_address_relevant(a) || remove) {
+
+ if (avahi_interface_address_relevant(a) &&
+ !remove &&
+ m->server->config.register_addresses &&
+ (m->server->state == AVAHI_SERVER_RUNNING ||
+ m->server->state == AVAHI_SERVER_REGISTERING)) {
+
+ if (!a->entry_group) {
+ a->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
+ avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, AF_UNSPEC, 0, NULL, &a->address);
+ avahi_entry_group_commit(a->entry_group);
+ }
+ } else {
+
if (a->entry_group) {
+
+ if (avahi_entry_group_get_state(a->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
+ avahi_server_decrease_host_rr_pending(m->server);
+
avahi_entry_group_free(a->entry_group);
a->entry_group = NULL;
}
- } else {
- if (!a->entry_group && m->server->config.register_addresses) {
- a->entry_group = avahi_entry_group_new(m->server, NULL, NULL);
- avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, AF_UNSPEC, 0, NULL, &a->address);
- avahi_entry_group_commit(a->entry_group);
- }
- }
+ }
}
-static void update_interface_rr(AvahiInterfaceMonitor *m, AvahiInterface *i, int remove) {
+static void update_interface_rr(AvahiInterfaceMonitor *m, AvahiInterface *i, gboolean remove) {
AvahiInterfaceAddress *a;
g_assert(m);
g_assert(i);
update_address_rr(m, a, remove);
}
-static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, int remove) {
+static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, gboolean remove) {
AvahiInterface *i;
g_assert(m);
void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port) {
g_assert(i);
g_assert(p);
- char t[64];
+/* char t[64]; */
if (!avahi_interface_relevant(i))
return;
g_assert(!a || a->family == i->protocol);
- if (a)
- g_message("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port);
- else
- g_message("multicast sending on '%s.%i'", i->hardware->name, i->protocol);
+/* if (a) */
+/* g_message("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port); */
+/* else */
+/* g_message("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */
if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port);
return TRUE;
}
-
void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, gint interface, guchar protocol, AvahiInterfaceMonitorWalkCallback callback, gpointer userdata) {
g_assert(m);
g_assert(callback);
callback(m, i, userdata);
}
}
+
+void avahi_update_host_rrs(AvahiInterfaceMonitor *m, gboolean remove) {
+ AvahiInterface *i;
+
+ g_assert(m);
+
+ for (i = m->interfaces; i; i = i->interface_next)
+ update_interface_rr(m, i, remove);
+}
void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, gint index, guchar protocol, AvahiInterfaceMonitorWalkCallback callback, gpointer userdata);
+void avahi_update_host_rrs(AvahiInterfaceMonitor *m, gboolean remove);
+
#endif
pj->delivery = tv;
pj->time_event = avahi_time_event_queue_add(s->time_event_queue, &pj->delivery, elapse_callback, pj);
- g_message("Accepted new probe job.");
+/* g_message("Accepted new probe job."); */
return TRUE;
}
g_assert(key);
if ((qj = find_history_job(s, key))) {
- g_message("Query suppressed by local duplicate suppression (history)");
+/* g_message("Query suppressed by local duplicate suppression (history)"); */
return FALSE;
}
if ((qj = find_scheduled_job(s, key))) {
/* Duplicate questions suppression */
- g_message("Query suppressed by local duplicate suppression (scheduled)");
+/* g_message("Query suppressed by local duplicate suppression (scheduled)"); */
if (avahi_timeval_compare(&tv, &qj->delivery) < 0) {
/* If the new entry should be scheduled earlier,
return TRUE;
} else {
- g_message("Accepted new query job.\n");
+/* g_message("Accepted new query job.\n"); */
qj = job_new(s, key, FALSE);
qj->delivery = tv;
* "DUPLICATE QUESTION SUPPRESION". */
if ((qj = find_scheduled_job(s, key))) {
- g_message("Query suppressed by distributed duplicate suppression");
+/* g_message("Query suppressed by distributed duplicate suppression"); */
job_mark_done(s, qj);
return;
}
avahi_record_is_goodbye(record) == avahi_record_is_goodbye(rj->record) &&
rj->record->ttl >= record->ttl/2) {
- g_message("Response suppressed by known answer suppression.");
+/* g_message("Response suppressed by known answer suppression."); */
return FALSE;
}
if (avahi_record_is_goodbye(record) == avahi_record_is_goodbye(rj->record) &&
rj->record->ttl >= record->ttl/2 &&
(rj->flush_cache || !flush_cache)) {
- g_message("Response suppressed by local duplicate suppression (history)");
+/* g_message("Response suppressed by local duplicate suppression (history)"); */
return FALSE;
}
avahi_elapse_time(&tv, immediately ? 0 : AVAHI_RESPONSE_DEFER_MSEC, immediately ? 0 : AVAHI_RESPONSE_JITTER_MSEC);
if ((rj = find_scheduled_job(s, record))) {
- g_message("Response suppressed by local duplicate suppression (scheduled)");
+/* g_message("Response suppressed by local duplicate suppression (scheduled)"); */
/* Update a little ... */
return TRUE;
} else {
- g_message("Accepted new response job.");
+/* g_message("Accepted new response job."); */
/* Create a new job and schedule it */
rj = job_new(s, record, AVAHI_SCHEDULED);
record->ttl >= rj->record->ttl/2) { /* sensible TTL */
/* A matching entry was found, so let's mark it done */
- g_message("Response suppressed by distributed duplicate suppression");
+/* g_message("Response suppressed by distributed duplicate suppression"); */
job_mark_done(s, rj);
}
record->ttl >= rj->record->ttl/2) { /* sensible TTL */
/* A matching entry was found, so let's drop it */
- g_message("Known answer suppression active!");
+/* g_message("Known answer suppression active!"); */
job_free(s, rj);
}
}
gint avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b) {
gint r;
- gchar *t1, *t2;
+/* gchar *t1, *t2; */
g_assert(a);
g_assert(b);
- t1 = avahi_record_to_string(a);
- t2 = avahi_record_to_string(b);
- g_message("lexicocmp: %s %s", t1, t2);
- g_free(t1);
- g_free(t2);
+/* t1 = avahi_record_to_string(a); */
+/* t2 = avahi_record_to_string(b); */
+/* g_message("lexicocmp: %s %s", t1, t2); */
+/* g_free(t1); */
+/* g_free(t2); */
if (a == b)
return 0;
(r = uint16_cmp(a->data.srv.weight, b->data.srv.weight)) == 0 &&
(r = uint16_cmp(a->data.srv.port, b->data.srv.port)) == 0)
r = avahi_binary_domain_cmp(a->data.srv.name, b->data.srv.name);
-
- g_message("SRV: %i", r);
return r;
}
void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, AvahiKey *k, gboolean unicast_response) {
AvahiEntry *e;
- gchar *txt;
+/* gchar *txt; */
g_assert(s);
g_assert(i);
g_assert(k);
- g_message("Posting responses matching [%s]", txt = avahi_key_to_string(k));
- g_free(txt);
+/* g_message("Posting responses matching [%s]", txt = avahi_key_to_string(k)); */
+/* g_free(txt); */
if (avahi_key_is_pattern(k)) {
t = avahi_record_to_string(record);
- g_message("CHECKING FOR CONFLICT: [%s]", t);
+/* g_message("CHECKING FOR CONFLICT: [%s]", t); */
for (e = g_hash_table_lookup(s->entries_by_key, record->key); e; e = n) {
n = e->by_key_next;
if (record->key->type != AVAHI_DNS_TYPE_ANY) {
- g_message("Handling response: %s", txt = avahi_record_to_string(record));
- g_free(txt);
+/* g_message("Handling response: %s", txt = avahi_record_to_string(record)); */
+/* g_free(txt); */
if (handle_conflict(s, i, record, cache_flush, a)) {
avahi_cache_update(i->cache, record, cache_flush, a);
return;
}
- g_message("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol);
+/* g_message("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol); */
if (sa->sa_family == AF_INET6) {
static const guint8 ipv4_in_ipv6[] = {
handle_query(s, p, i, &a, port, legacy_unicast);
- g_message("Handled query");
+/* g_message("Handled query"); */
} else {
if (port != AVAHI_MDNS_PORT) {
}
handle_response(s, p, i, &a);
- g_message("Handled response");
+/* g_message("Handled response"); */
}
}
return TRUE;
}
-static void add_default_entries(AvahiServer *s) {
- AvahiAddress a;
+static void server_set_state(AvahiServer *s, AvahiServerState state) {
+ g_assert(s);
+
+ if (s->state == state)
+ return;
+ s->state = state;
+
+ if (s->callback)
+ s->callback(s, state, s->userdata);
+}
+
+static void withdraw_host_rrs(AvahiServer *s) {
g_assert(s);
- if (s->config.register_hinfo) {
- struct utsname utsname;
- AvahiRecord *r;
-
- /* Fill in HINFO rr */
- r = avahi_record_new_full(s->host_name_fqdn, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_HINFO);
- uname(&utsname);
- r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine));
- r->data.hinfo.os = g_strdup(g_strup(utsname.sysname));
- avahi_server_add(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, r);
- avahi_record_unref(r);
+ if (s->hinfo_entry_group) {
+ avahi_entry_group_free(s->hinfo_entry_group);
+ s->hinfo_entry_group = NULL;
}
+ avahi_update_host_rrs(s->monitor, TRUE);
+ s->n_host_rr_pending = 0;
+}
+
+void avahi_server_decrease_host_rr_pending(AvahiServer *s) {
+ g_assert(s);
+
+ g_assert(s->n_host_rr_pending > 0);
+
+ if (--s->n_host_rr_pending == 0)
+ server_set_state(s, AVAHI_SERVER_RUNNING);
+}
+
+void avahi_server_increase_host_rr_pending(AvahiServer *s) {
+ g_assert(s);
+
+ s->n_host_rr_pending ++;
+}
+
+void avahi_host_rr_entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) {
+ g_assert(s);
+ g_assert(g);
+
+ if (state == AVAHI_ENTRY_GROUP_REGISTERING &&
+ s->state == AVAHI_SERVER_REGISTERING)
+ avahi_server_increase_host_rr_pending(s);
+ else if (state == AVAHI_ENTRY_GROUP_COLLISION) {
+ withdraw_host_rrs(s);
+ server_set_state(s, AVAHI_SERVER_COLLISION);
+ } else if (state == AVAHI_ENTRY_GROUP_ESTABLISHED &&
+ s->state == AVAHI_SERVER_REGISTERING)
+ avahi_server_decrease_host_rr_pending(s);
+}
+
+static void register_hinfo(AvahiServer *s) {
+ struct utsname utsname;
+ AvahiRecord *r;
+
+ g_assert(s);
+
+ if (!s->config.register_hinfo || s->hinfo_entry_group)
+ return;
+
+ s->hinfo_entry_group = avahi_entry_group_new(s, avahi_host_rr_entry_group_callback, NULL);
+
+ /* Fill in HINFO rr */
+ r = avahi_record_new_full(s->host_name_fqdn, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_HINFO);
+ uname(&utsname);
+ r->data.hinfo.cpu = g_strdup(g_strup(utsname.machine));
+ r->data.hinfo.os = g_strdup(g_strup(utsname.sysname));
+ avahi_server_add(s, s->hinfo_entry_group, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, r);
+ avahi_record_unref(r);
+
+ avahi_entry_group_commit(s->hinfo_entry_group);
+}
+
+static void register_localhost(AvahiServer *s) {
+ AvahiAddress a;
+ g_assert(s);
+
/* Add localhost entries */
avahi_address_parse("127.0.0.1", AF_INET, &a);
avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "localhost", &a);
avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "ip6-localhost", &a);
}
-AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc) {
+static void register_stuff(AvahiServer *s) {
+ g_assert(s);
+
+ server_set_state(s, AVAHI_SERVER_REGISTERING);
+ register_hinfo(s);
+ avahi_update_host_rrs(s->monitor, FALSE);
+
+ if (s->n_host_rr_pending == 0)
+ server_set_state(s, AVAHI_SERVER_RUNNING);
+}
+
+static void update_fqdn(AvahiServer *s) {
+ g_assert(s);
+
+ g_assert(s->host_name);
+ g_assert(s->domain_name);
+
+ g_free(s->host_name_fqdn);
+ s->host_name_fqdn = g_strdup_printf("%s.%s", s->host_name, s->domain_name);
+}
+
+void avahi_server_set_host_name(AvahiServer *s, const gchar *host_name) {
+ g_assert(s);
+ g_assert(host_name);
+
+ withdraw_host_rrs(s);
+
+ g_free(s->host_name);
+ s->host_name = host_name ? avahi_normalize_name(host_name) : avahi_get_host_name();
+ s->host_name[strcspn(s->host_name, ".")] = 0;
+ update_fqdn(s);
+
+ register_stuff(s);
+}
+
+void avahi_server_set_domain_name(AvahiServer *s, const gchar *domain_name) {
+ g_assert(s);
+ g_assert(domain_name);
+
+ withdraw_host_rrs(s);
+
+ g_free(s->domain_name);
+ s->domain_name = domain_name ? avahi_normalize_name(domain_name) : g_strdup("local.");
+ update_fqdn(s);
+
+ register_stuff(s);
+}
+
+AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, AvahiServerCallback callback, gpointer userdata) {
AvahiServer *s;
static GSourceFuncs source_funcs = {
};
s = g_new(AvahiServer, 1);
-
+ s->n_host_rr_pending = 0;
s->need_entry_cleanup = s->need_group_cleanup = FALSE;
if (sc)
g_main_context_ref(s->context = c);
else
s->context = g_main_context_default();
+
+ /* Prepare IO source registration */
+ s->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(AvahiServer*));
+ *((AvahiServer**) (((guint8*) s->source) + sizeof(GSource))) = s;
+
+ memset(&s->pollfd_ipv4, 0, sizeof(s->pollfd_ipv4));
+ s->pollfd_ipv4.fd = s->fd_ipv4;
+ s->pollfd_ipv4.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+ g_source_add_poll(s->source, &s->pollfd_ipv4);
+
+ memset(&s->pollfd_ipv6, 0, sizeof(s->pollfd_ipv6));
+ s->pollfd_ipv6.fd = s->fd_ipv6;
+ s->pollfd_ipv6.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+ g_source_add_poll(s->source, &s->pollfd_ipv6);
+
+ g_source_attach(s->source, s->context);
+
+ s->callback = callback;
+ s->userdata = userdata;
AVAHI_LLIST_HEAD_INIT(AvahiEntry, s->entries);
s->entries_by_key = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
s->subscription_hashtable = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
/* Get host name */
- s->host_name = avahi_get_host_name();
+ s->host_name = s->config.host_name ? avahi_normalize_name(s->config.host_name) : avahi_get_host_name();
s->host_name[strcspn(s->host_name, ".")] = 0;
-
- s->domain = avahi_normalize_name("local.");
-
- s->host_name_fqdn = g_strdup_printf("%s.%s", s->host_name, s->domain);
+ s->domain_name = s->config.domain_name ? avahi_normalize_name(s->config.domain_name) : g_strdup("local.");
+ s->host_name_fqdn = NULL;
+ update_fqdn(s);
s->record_list = avahi_record_list_new();
s->time_event_queue = avahi_time_event_queue_new(s->context, G_PRIORITY_DEFAULT+10); /* Slightly less priority than the FDs */
+
+ s->state = AVAHI_SERVER_INVALID;
+
s->monitor = avahi_interface_monitor_new(s);
avahi_interface_monitor_sync(s->monitor);
-
- add_default_entries(s);
-
- /* Prepare IO source registration */
- s->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(AvahiServer*));
- *((AvahiServer**) (((guint8*) s->source) + sizeof(GSource))) = s;
- memset(&s->pollfd_ipv4, 0, sizeof(s->pollfd_ipv4));
- s->pollfd_ipv4.fd = s->fd_ipv4;
- s->pollfd_ipv4.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
- g_source_add_poll(s->source, &s->pollfd_ipv4);
-
- memset(&s->pollfd_ipv6, 0, sizeof(s->pollfd_ipv6));
- s->pollfd_ipv6.fd = s->fd_ipv6;
- s->pollfd_ipv6.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
- g_source_add_poll(s->source, &s->pollfd_ipv6);
-
- g_source_attach(s->source, s->context);
+ register_localhost(s);
+ s->hinfo_entry_group = NULL;
+ register_stuff(s);
+
return s;
}
close(s->fd_ipv6);
g_free(s->host_name);
- g_free(s->domain);
+ g_free(s->domain_name);
g_free(s->host_name_fqdn);
g_source_destroy(s->source);
if (g->state == state)
return;
-
+
g->state = state;
if (g->callback) {
return g->state;
}
-const gchar* avahi_server_get_domain(AvahiServer *s) {
+void avahi_entry_group_set_data(AvahiEntryGroup *g, gpointer userdata) {
+ g_assert(g);
+
+ g->userdata = userdata;
+}
+
+gpointer avahi_entry_group_get_data(AvahiEntryGroup *g) {
+ g_assert(g);
+
+ return g->userdata;
+}
+
+const gchar* avahi_server_get_domain_name(AvahiServer *s) {
g_assert(s);
- return s->domain;
+ return s->domain_name;
}
const gchar* avahi_server_get_host_name(AvahiServer *s) {
g_assert(s);
+ return s->host_name;
+}
+
+const gchar* avahi_server_get_host_name_fqdn(AvahiServer *s) {
+ g_assert(s);
+
return s->host_name_fqdn;
}
+gpointer avahi_server_get_data(AvahiServer *s) {
+ g_assert(s);
+
+ return s->userdata;
+}
+
+void avahi_server_set_data(AvahiServer *s, gpointer userdata) {
+ g_assert(s);
+
+ s->userdata = userdata;
+}
+
+AvahiServerState avhai_server_get_state(AvahiServer *s) {
+ g_assert(s);
+
+ return s->state;
+}
+
AvahiServerConfig* avahi_server_config_init(AvahiServerConfig *c) {
g_assert(c);
AvahiTimeEventQueue *time_event_queue;
- gchar *host_name, *host_name_fqdn, *domain;
+ gchar *host_name, *host_name_fqdn, *domain_name;
gint fd_ipv4, fd_ipv6;
GPollFD pollfd_ipv4, pollfd_ipv6;
GSource *source;
+ AvahiServerState state;
+ AvahiServerCallback callback;
+ gpointer userdata;
+
+ AvahiEntryGroup *hinfo_entry_group;
+ guint n_host_rr_pending;
+
/* Used for assembling responses */
AvahiRecordList *record_list;
};
void avahi_server_enumerate_aux_records(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, void (*callback)(AvahiServer *s, AvahiRecord *r, gboolean flush_cache, gpointer userdata), gpointer userdata);
+void avahi_host_rr_entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata);
+
+void avahi_server_decrease_host_rr_pending(AvahiServer *s);
+void avahi_server_increase_host_rr_pending(AvahiServer *s);
+
#endif
}
}
-
-gchar * avahi_alternative_host_name(const gchar *s) {
- const gchar *p, *e = NULL;
- gchar *c, *r;
- gint n;
-
- g_assert(s);
-
- for (p = s; *p; p++)
- if (!isdigit(*p))
- e = p+1;
-
- if (e && *e)
- n = atoi(e)+1;
- else
- n = 2;
-
- c = e ? g_strndup(s, e-s) : g_strdup(s);
- r = g_strdup_printf("%s%i", c, n);
- g_free(c);
-
- return r;
-
-}
-
-gchar *avahi_alternative_service_name(const gchar *s) {
- const gchar *e;
- g_assert(s);
-
- if ((e = strstr(s, " #"))) {
- const gchar *n, *p;
- e += 2;
-
- while ((n = strstr(e, " #")))
- e = n + 2;
-
- for (p = e; *p; p++)
- if (!isdigit(*p)) {
- e = NULL;
- break;
- }
- }
-
- if (e) {
- gchar *r, *c = g_strndup(s, e-s);
- r = g_strdup_printf("%s%i", c, atoi(e)+1);
- g_free(c);
- return r;
- } else
- return g_strdup_printf("%s #2", s);
-}
gint avahi_domain_hash(const gchar *s);
-gchar *avahi_alternative_host_name(const gchar *s);
-gchar *avahi_alternative_service_name(const gchar *s);
-
-
#endif
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../avahi-core/core.h ../avahi-core/address.h ../avahi-core/rr.h ../avahi-core/strlst.h
+INPUT = ../avahi-core/core.h ../avahi-core/address.h ../avahi-core/rr.h ../avahi-core/strlst.h ../avahi-core/alternative.h
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp