]> git.meshlink.io Git - catta/commitdiff
* add C examples
authorLennart Poettering <lennart@poettering.net>
Wed, 3 Aug 2005 21:07:02 +0000 (21:07 +0000)
committerLennart Poettering <lennart@poettering.net>
Wed, 3 Aug 2005 21:07:02 +0000 (21:07 +0000)
* change doxygen to output stuff in "doxygen/" instead of "doxygen-doc/"
* implement avahi_entry_group_{reset,is_empty}() and make everyone use it
* move holdoff (SLEEPING) time checking from server to entry group
* add preliminary error codes

git-svn-id: file:///home/lennart/svn/public/avahi/trunk@216 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

20 files changed:
Makefile.am
avahi-core/avahi-test.c
avahi-core/conformance-test.c
avahi-core/core.h
avahi-core/iface.c
avahi-core/server.c
avahi-core/server.h
avahi-daemon/DBUS-API
avahi-daemon/EntryGroup.introspect
avahi-daemon/dbus-protocol.c
avahi-daemon/main.c
avahi-daemon/static-services.c
avahi-utils/avahi-publish-service.in
avahi-utils/avahi/__init__.py
configure.ac
doxygen.cfg
examples/Makefile.am [new file with mode: 0644]
examples/browse-services.c [new file with mode: 0644]
examples/publish-service.c [new file with mode: 0644]
todo

index e6f70561cd24a70c447bc041d6d2caa2ad58835e..9e826b3d8797b2aff4dbbb4d906120324fce0693 100644 (file)
@@ -20,7 +20,7 @@
 include aminclude.am
 
 EXTRA_DIST = bootstrap.sh LICENSE $(DX_CONFIG)
-SUBDIRS = avahi-common avahi-core avahi-discover avahi-client avahi-daemon initscript avahi-dnsconfd avahi-utils
+SUBDIRS = avahi-common avahi-core avahi-discover avahi-client avahi-daemon initscript avahi-dnsconfd avahi-utils examples
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = avahi-core.pc
index d91e6980cb62d04ce3c2942bbc7d8669365dca3b..cc950d46e441672d785b21b4e0d85786d14afeef 100644 (file)
@@ -101,16 +101,18 @@ static void server_callback(AvahiServer *s, AvahiServerState state, gpointer use
 
 static void remove_entries(void) {
     if (group)
-        avahi_entry_group_free(group);
-
-    group = NULL;
+        avahi_entry_group_reset(group);
 }
 
 static void create_entries(gboolean new_name) {
     AvahiAddress a;
+
     remove_entries();
-    
-    group = avahi_entry_group_new(server, entry_group_callback, NULL);   
+
+    if (!group) 
+        group = avahi_entry_group_new(server, entry_group_callback, NULL);
+
+    g_assert(avahi_entry_group_is_empty(group));
     
     if (!service_name)
         service_name = g_strdup("Test Service");
index f8e0c937b4c50390f29b86ec0fa784101693f1ea..ccc9a12219f426fbaa73d8720e6f6a701de3895c 100644 (file)
@@ -56,17 +56,15 @@ static void create_service(const gchar *t) {
 
     g_assert(t || name);
 
-    if (group)
-        avahi_entry_group_free(group);
-    
     n = t ? g_strdup(t) : avahi_alternative_service_name(name);
     g_free(name);
     name = n;
 
-    if (try > 10)
-        sleep(2); /* ugly ugly ugly hack */
+    if (group)
+        avahi_entry_group_reset(group);
+    else
+        group = avahi_entry_group_new(avahi, entry_group_callback, NULL);
     
-    group = avahi_entry_group_new(avahi, entry_group_callback, NULL);   
     avahi_server_add_service(avahi, group, 0, AF_UNSPEC, name, "_http._tcp", NULL, NULL, 80, "foo", NULL);   
     avahi_entry_group_commit(group);
 
@@ -94,14 +92,17 @@ static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryG
 
 static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) {
     avahi_log_debug("server state: %i", state);
+
+    if (state == AVAHI_SERVER_RUNNING) {
+        create_service("gurke");
+        avahi_server_dump(avahi, dump_line, NULL);
+    }
 }
 
 int main(int argc, char *argv[]) {
     GMainLoop *loop = NULL;
 
     avahi = avahi_server_new(NULL, NULL, server_callback, NULL);
-    create_service("gurke");
-    avahi_server_dump(avahi, dump_line, NULL);
     
     loop = g_main_loop_new(NULL, FALSE);
     g_timeout_add(1000*5, dump_timeout, avahi);
@@ -109,7 +110,8 @@ int main(int argc, char *argv[]) {
     g_main_loop_run(loop);
     g_main_loop_unref(loop);
 
-    avahi_entry_group_free(group);   
+    if (group)
+        avahi_entry_group_free(group);   
     avahi_server_free(avahi);
     
     return 0;
index bacb97e455eccd2a240a8f9387c0c556d4323b03..aa6b80944f7f15ea7c81d4b13397aac990fe2cd3 100644 (file)
 
 /** \file core.h The Avahi Multicast DNS and DNS Service Discovery implmentation. */
 
+/** \example publish-service.c Example how to register a DNS-SD
+ * service using an embedded mDNS stack. It behaves like a network
+ * printer registering both an IPP and a BSD LPR service. */
+
+/** \example browse-services.c Example how to browse for DNS-SD
+ * services using an embedded mDNS stack. */
+
 #include <avahi-common/cdecl.h>
 
 AVAHI_C_DECL_BEGIN
@@ -47,13 +54,19 @@ AVAHI_C_DECL_END
 
 AVAHI_C_DECL_BEGIN
 
+/** Error codes used by avahi */
+enum { 
+    AVAHI_OK = 0,                      /**< OK */
+    AVAHI_ERR_FAILURE = -1,            /**< Generic error code */
+    AVAHI_ERR_BAD_STATE = -2           /**< Object was in a bad state */
+};
+
 /** States of a server object */
 typedef enum {
     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() */
-    AVAHI_SERVER_SLEEPING          /**< The host or domain name has changed and the server waits for old entries to be expired */
+    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 */
@@ -70,7 +83,8 @@ typedef enum {
     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 */ 
+    AVAHI_ENTRY_GROUP_COLLISION,          /**< A name collision for one of the entries in the group has been detected, the entries have been withdrawn */ 
+    AVAHI_ENTRY_GROUP_SLEEPING           /**< Rate limiting of probe packets is active */
 } AvahiEntryGroupState;
 
 /** Prototype for callback functions which are called whenever the state of an AvahiServer object changes */
@@ -189,6 +203,12 @@ void avahi_entry_group_free(AvahiEntryGroup *g);
 /** Commit an entry group. This starts the probing and registration process for all RRs in the group */
 gint avahi_entry_group_commit(AvahiEntryGroup *g);
 
+/** Remove all entries from the entry group and reset the state to AVAHI_ENTRY_GROUP_UNCOMMITED. */
+void avahi_entry_group_reset(AvahiEntryGroup *g);
+
+/** Return TRUE if the entry group is empty, i.e. has no records attached. */
+gboolean avahi_entry_group_is_empty(AvahiEntryGroup *g);
+
 /** Return the current state of the specified entry group */
 AvahiEntryGroupState avahi_entry_group_get_state(AvahiEntryGroup *g);
 
index ad26ab01bc06095ab09f4533973fd96ce62f9c36..437600857b00c574ce09d4ddf7f1ce2ae1dad4cc 100644 (file)
@@ -50,24 +50,31 @@ static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a
         (m->server->state == AVAHI_SERVER_RUNNING ||
         m->server->state == AVAHI_SERVER_REGISTERING)) {
 
-        if (!a->entry_group) {
+        /* Fill the entry group */
+        if (!a->entry_group) 
             a->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
+
+        if (avahi_entry_group_is_empty(a->entry_group)) {
+
             if (avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, a->interface->protocol, 0, NULL, &a->address) < 0) {
                 avahi_log_warn(__FILE__": avahi_server_add_address() failed.");
                 avahi_entry_group_free(a->entry_group);
                 a->entry_group = NULL;
-            } else
-                avahi_entry_group_commit(a->entry_group);
+                return;
+            }
+
+            avahi_entry_group_commit(a->entry_group);
         }
     } else {
 
-        if (a->entry_group) {
+        /* Clear the entry group */
+
+        if (a->entry_group && !avahi_entry_group_is_empty(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;
+            avahi_entry_group_reset(a->entry_group);
         }
     } 
 }
@@ -96,13 +103,16 @@ static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *h
         (m->server->state == AVAHI_SERVER_RUNNING ||
         m->server->state == AVAHI_SERVER_REGISTERING)) {
 
-        if (!hw->entry_group) {
+        if (!hw->entry_group)
+            hw->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
+
+        if (avahi_entry_group_is_empty(hw->entry_group)) {
             gchar *name;
             gchar *t = avahi_format_mac_address(hw->mac_address, hw->mac_address_size);
+            
             name = g_strdup_printf("%s [%s]", m->server->host_name, t);
             g_free(t);
             
-            hw->entry_group = avahi_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL);
             if (avahi_server_add_service(m->server, hw->entry_group, hw->index, AVAHI_PROTO_UNSPEC, name, "_workstation._tcp", NULL, NULL, 9, NULL) < 0) { 
                 avahi_log_warn(__FILE__": avahi_server_add_service() failed.");
                 avahi_entry_group_free(hw->entry_group);
@@ -115,13 +125,12 @@ static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *h
         
     } else {
 
-        if (hw->entry_group) {
+        if (hw->entry_group && !avahi_entry_group_is_empty(hw->entry_group)) {
 
             if (avahi_entry_group_get_state(hw->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING)
                 avahi_server_decrease_host_rr_pending(m->server);
 
-            avahi_entry_group_free(hw->entry_group);
-            hw->entry_group = NULL;
+            avahi_entry_group_reset(hw->entry_group);
         }
     }
 }
@@ -133,6 +142,9 @@ static void free_address(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a) {
 
     update_address_rr(m, a, TRUE);
     AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a);
+
+    if (a->entry_group)
+        avahi_entry_group_free(a->entry_group);
     
     g_free(a);
 }
@@ -171,6 +183,9 @@ static void free_hw_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, gb
     while (hw->interfaces)
         free_interface(m, hw->interfaces, send_goodbye);
 
+    if (hw->entry_group)
+        avahi_entry_group_free(hw->entry_group);
+    
     AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, m->hw_interfaces, hw);
     g_hash_table_remove(m->hash_table, &hw->index);
 
@@ -305,7 +320,7 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, gpointer user
             hw->name = NULL;
             hw->flags = 0;
             hw->mtu = 1500;
-            hw->index = ifinfomsg->ifi_index;
+            hw->index = (AvahiIfIndex) ifinfomsg->ifi_index;
             hw->mac_address_size = 0;
             hw->entry_group = NULL;
 
@@ -363,7 +378,7 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, gpointer user
         if (ifinfomsg->ifi_family != AF_UNSPEC)
             return;
         
-        if (!(hw = avahi_interface_monitor_get_hw_interface(m, ifinfomsg->ifi_index)))
+        if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifinfomsg->ifi_index)))
             return;
 
         update_hw_interface_rr(m, hw, TRUE);
@@ -381,10 +396,10 @@ static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, gpointer user
         if (ifaddrmsg->ifa_family != AVAHI_PROTO_INET && ifaddrmsg->ifa_family != AVAHI_PROTO_INET6)
             return;
 
-        if (!(i = (AvahiInterface*) avahi_interface_monitor_get_interface(m, ifaddrmsg->ifa_index, ifaddrmsg->ifa_family)))
+        if (!(i = (AvahiInterface*) avahi_interface_monitor_get_interface(m, (AvahiIfIndex) ifaddrmsg->ifa_index, (AvahiProtocol) ifaddrmsg->ifa_family)))
             return;
 
-        raddr.family = ifaddrmsg->ifa_family;
+        raddr.family = (AvahiProtocol) ifaddrmsg->ifa_family;
 
         l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg));
         a = IFA_RTA(ifaddrmsg);
index 4507aeac14cbecd818b5df70c3d02c8388fc4cc8..e3929dbd45d10654347044f882df9afc2b0e15a4 100644 (file)
@@ -38,7 +38,9 @@
 #include "browse.h"
 #include "log.h"
 
-#define AVAHI_HOST_RR_HOLDOFF_MSEC 2000
+#define AVAHI_RR_HOLDOFF_MSEC 1000
+#define AVAHI_RR_HOLDOFF_MSEC_RATE_LIMIT 60000
+#define AVAHI_RR_RATE_LIMIT_COUNT 15
 
 static void free_entry(AvahiServer*s, AvahiEntry *e) {
     AvahiEntry *t;
@@ -74,6 +76,9 @@ static void free_group(AvahiServer *s, AvahiEntryGroup *g) {
     while (g->entries)
         free_entry(s, g->entries);
 
+    if (g->register_time_event)
+        avahi_time_event_queue_remove(s->time_event_queue, g->register_time_event);
+    
     AVAHI_LLIST_REMOVE(AvahiEntryGroup, groups, s->groups, g);
     g_free(g);
 }
@@ -192,10 +197,14 @@ static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
         AvahiEntry *k;
         
         for (k = e->group->entries; k; k = k->by_group_next) {
-            avahi_goodbye_entry(s, k, FALSE);
-            k->dead = TRUE;
+            if (!k->dead) {
+                avahi_goodbye_entry(s, k, FALSE);
+                k->dead = TRUE;
+            }
         }
-        
+
+        e->group->n_probing = 0;
+
         avahi_entry_group_change_state(e->group, AVAHI_ENTRY_GROUP_COLLISION);
     } else {
         avahi_goodbye_entry(s, e, FALSE);
@@ -763,7 +772,7 @@ static void reflect_legacy_unicast_query_packet(AvahiServer *s, AvahiDnsPacket *
     if (!s->config.enable_reflector)
         return;
 
-/*     avahi_log_debug("legacy unicast reflectr"); */
+/*     avahi_log_debug("legacy unicast reflector"); */
     
     /* Reflecting legacy unicast queries is a little more complicated
        than reflecting normal queries, since we must route the
@@ -1090,15 +1099,11 @@ static void server_set_state(AvahiServer *s, AvahiServerState state) {
 static void withdraw_host_rrs(AvahiServer *s) {
     g_assert(s);
 
-    if (s->hinfo_entry_group) {
-        avahi_entry_group_free(s->hinfo_entry_group);
-        s->hinfo_entry_group = NULL;
-    }
+    if (s->hinfo_entry_group)
+        avahi_entry_group_reset(s->hinfo_entry_group);
 
-    if (s->browse_domain_entry_group) {
-        avahi_entry_group_free(s->browse_domain_entry_group);
-        s->browse_domain_entry_group = NULL;
-    }
+    if (s->browse_domain_entry_group)
+        avahi_entry_group_reset(s->browse_domain_entry_group);
 
     avahi_update_host_rrs(s->monitor, TRUE);
     s->n_host_rr_pending = 0;
@@ -1141,10 +1146,13 @@ static void register_hinfo(AvahiServer *s) {
     
     g_assert(s);
     
-    if (!s->config.publish_hinfo || s->hinfo_entry_group)
+    if (!s->config.publish_hinfo)
         return;
-    
-    s->hinfo_entry_group = avahi_entry_group_new(s, avahi_host_rr_entry_group_callback, NULL);
+
+    if (s->hinfo_entry_group)
+        g_assert(avahi_entry_group_is_empty(s->hinfo_entry_group));
+    else
+        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, AVAHI_DEFAULT_TTL_HOST_NAME);
@@ -1172,10 +1180,14 @@ static void register_localhost(AvahiServer *s) {
 static void register_browse_domain(AvahiServer *s) {
     g_assert(s);
 
-    if (!s->config.publish_domain || s->browse_domain_entry_group)
+    if (!s->config.publish_domain)
         return;
 
-    s->browse_domain_entry_group = avahi_entry_group_new(s, NULL, NULL);
+    if (s->browse_domain_entry_group)
+        g_assert(avahi_entry_group_is_empty(s->browse_domain_entry_group));
+    else
+        s->browse_domain_entry_group = avahi_entry_group_new(s, NULL, NULL);
+    
     avahi_server_add_ptr(s, s->browse_domain_entry_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, AVAHI_DEFAULT_TTL, "b._dns-sd._udp.local", s->domain_name);
     avahi_entry_group_commit(s->browse_domain_entry_group);
 }
@@ -1202,38 +1214,10 @@ static void update_fqdn(AvahiServer *s) {
     s->host_name_fqdn = g_strdup_printf("%s.%s", s->host_name, s->domain_name);
 }
 
-static void register_time_event_callback(AvahiTimeEvent *e, gpointer userdata) {
-    AvahiServer *s = userdata;
-    
-    g_assert(e);
-    g_assert(s);
-
-    g_assert(e == s->register_time_event);
-    avahi_time_event_queue_remove(s->time_event_queue, s->register_time_event);
-    s->register_time_event = NULL;
-
-    if (s->state == AVAHI_SERVER_SLEEPING)
-        register_stuff(s);
-}
-
-static void delayed_register_stuff(AvahiServer *s) {
-    GTimeVal tv;
-    
-    g_assert(s);
-
-    avahi_elapse_time(&tv, AVAHI_HOST_RR_HOLDOFF_MSEC, 0);
-
-    if (s->register_time_event)
-        avahi_time_event_queue_update(s->time_event_queue, s->register_time_event, &tv);
-    else
-        s->register_time_event = avahi_time_event_queue_add(s->time_event_queue, &tv, register_time_event_callback, s);
-}
-
 gint avahi_server_set_host_name(AvahiServer *s, const gchar *host_name) {
     g_assert(s);
     g_assert(host_name);
 
-    server_set_state(s, AVAHI_SERVER_SLEEPING);
     withdraw_host_rrs(s);
 
     g_free(s->host_name);
@@ -1241,26 +1225,24 @@ gint avahi_server_set_host_name(AvahiServer *s, const gchar *host_name) {
     s->host_name[strcspn(s->host_name, ".")] = 0;
     update_fqdn(s);
 
-    delayed_register_stuff(s);
-    return 0;
+    register_stuff(s);
+    return AVAHI_OK;
 }
 
 gint avahi_server_set_domain_name(AvahiServer *s, const gchar *domain_name) {
     g_assert(s);
     g_assert(domain_name);
 
-    server_set_state(s, AVAHI_SERVER_SLEEPING);
     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);
 
-    delayed_register_stuff(s);
-    return 0;
+    register_stuff(s);
+    return AVAHI_OK;
 }
 
-
 static void prepare_pollfd(AvahiServer *s, GPollFD *pollfd, gint fd) {
     g_assert(s);
     g_assert(pollfd);
@@ -1358,7 +1340,6 @@ AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, Avah
     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->register_time_event = NULL;
     
     s->state = AVAHI_SERVER_INVALID;
 
@@ -1407,8 +1388,6 @@ void avahi_server_free(AvahiServer* s) {
 
     g_hash_table_destroy(s->entries_by_key);
 
-    if (s->register_time_event)
-        avahi_time_event_queue_remove(s->time_event_queue, s->register_time_event);
     avahi_time_event_queue_free(s->time_event_queue);
 
     avahi_record_list_free(s->record_list);
@@ -1984,6 +1963,10 @@ AvahiEntryGroup *avahi_entry_group_new(AvahiServer *s, AvahiEntryGroupCallback c
     g->dead = FALSE;
     g->state = AVAHI_ENTRY_GROUP_UNCOMMITED;
     g->n_probing = 0;
+    g->n_register_try = 0;
+    g->register_time_event = NULL;
+    g->register_time.tv_sec = 0;
+    g->register_time.tv_usec = 0;
     AVAHI_LLIST_HEAD_INIT(AvahiEntry, g->entries);
 
     AVAHI_LLIST_PREPEND(AvahiEntryGroup, groups, s->groups, g);
@@ -1997,8 +1980,15 @@ void avahi_entry_group_free(AvahiEntryGroup *g) {
     g_assert(g->server);
 
     for (e = g->entries; e; e = e->by_group_next) {
-        avahi_goodbye_entry(g->server, e, TRUE);
-        e->dead = TRUE;
+        if (!e->dead) {
+            avahi_goodbye_entry(g->server, e, TRUE);
+            e->dead = TRUE;
+        }
+    }
+
+    if (g->register_time_event) {
+        avahi_time_event_queue_remove(g->server->time_event_queue, g->register_time_event);
+        g->register_time_event = NULL;
     }
 
     g->dead = TRUE;
@@ -2007,18 +1997,85 @@ void avahi_entry_group_free(AvahiEntryGroup *g) {
     g->server->need_entry_cleanup = TRUE;
 }
 
-gint avahi_entry_group_commit(AvahiEntryGroup *g) {
+static void entry_group_commit_real(AvahiEntryGroup *g) {
     g_assert(g);
-    g_assert(!g->dead);
-
-    if (g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)
-        return -1;
 
     avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING);
     avahi_announce_group(g->server, g);
     avahi_entry_group_check_probed(g, FALSE);
 
-    return 0;
+    g_get_current_time(&g->register_time);
+}
+
+static void entry_group_register_time_event_callback(AvahiTimeEvent *e, gpointer userdata) {
+    AvahiEntryGroup *g = userdata;
+    g_assert(g);
+
+    avahi_log_debug("Holdoff passed, waking up and going on.");
+
+    avahi_time_event_queue_remove(g->server->time_event_queue, g->register_time_event);
+    g->register_time_event = NULL;
+    
+    /* Holdoff time passed, so let's start probing */
+    entry_group_commit_real(g);
+}
+
+gint avahi_entry_group_commit(AvahiEntryGroup *g) {
+    GTimeVal now;
+    
+    g_assert(g);
+    g_assert(!g->dead);
+
+    if (g->state != AVAHI_ENTRY_GROUP_UNCOMMITED && g->state != AVAHI_ENTRY_GROUP_COLLISION)
+        return AVAHI_ERR_BAD_STATE;
+
+    g->n_register_try++;
+
+    avahi_timeval_add(&g->register_time,
+                      1000*(g->n_register_try >= AVAHI_RR_RATE_LIMIT_COUNT ?
+                            AVAHI_RR_HOLDOFF_MSEC_RATE_LIMIT :
+                            AVAHI_RR_HOLDOFF_MSEC));
+
+    g_get_current_time(&now);
+
+    if (avahi_timeval_compare(&g->register_time, &now) <= 0) {
+        /* Holdoff time passed, so let's start probing */
+        avahi_log_debug("Holdoff passed, directly going on.");
+
+        entry_group_commit_real(g);
+    } else {
+        avahi_log_debug("Holdoff not passed, sleeping.");
+
+        /* Holdoff time has not yet passed, so let's wait */
+        avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_SLEEPING);
+        
+        g_assert(!g->register_time_event);
+        g->register_time_event = avahi_time_event_queue_add(g->server->time_event_queue, &g->register_time, entry_group_register_time_event_callback, g);
+    }
+
+    return AVAHI_OK;
+}
+
+void avahi_entry_group_reset(AvahiEntryGroup *g) {
+    AvahiEntry *e;
+    g_assert(g);
+    
+    if (g->register_time_event) {
+        avahi_time_event_queue_remove(g->server->time_event_queue, g->register_time_event);
+        g->register_time_event = NULL;
+    }
+    
+    for (e = g->entries; e; e = e->by_group_next) {
+        if (!e->dead) {
+            avahi_goodbye_entry(g->server, e, TRUE);
+            e->dead = TRUE;
+        }
+    }
+    
+    g->server->need_entry_cleanup = TRUE;
+    g->n_probing = 0;
+
+    avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_UNCOMMITED);
 }
 
 gboolean avahi_entry_commited(AvahiEntry *e) {
@@ -2049,6 +2106,18 @@ gpointer avahi_entry_group_get_data(AvahiEntryGroup *g) {
     return g->userdata;
 }
 
+gboolean avahi_entry_group_is_empty(AvahiEntryGroup *g) {
+    AvahiEntry *e;
+    g_assert(g);
+
+    /* Look for an entry that is not dead */
+    for (e = g->entries; e; e = e->by_group_next)
+        if (!e->dead)
+            return FALSE;
+
+    return TRUE;
+}
+
 const gchar* avahi_server_get_domain_name(AvahiServer *s) {
     g_assert(s);
 
index 97febc5d736a518a2a0e3746ebfba9de3ce1eae6..7049f58970077097e3ab74fe07eb075a4e39a789 100644 (file)
@@ -75,6 +75,10 @@ struct AvahiEntryGroup {
 
     guint n_probing;
     
+    guint n_register_try;
+    GTimeVal register_time;
+    AvahiTimeEvent *register_time_event;
+    
     AVAHI_LLIST_FIELDS(AvahiEntryGroup, groups);
     AVAHI_LLIST_HEAD(AvahiEntry, entries);
 };
@@ -121,8 +125,6 @@ struct AvahiServer {
     AvahiEntryGroup *browse_domain_entry_group;
     guint n_host_rr_pending;
 
-    AvahiTimeEvent *register_time_event;
-    
     /* Used for assembling responses */
     AvahiRecordList *record_list;
 
index eb62ae399b16f021417da03db5c5aeddbd2d02f3..9b46ac05b4ab2264e4b375b1b29b254bff600efd 100644 (file)
@@ -20,7 +20,9 @@ org.freedesktop.Avahi.Server
 org.freedesktop.Avahi.EntryGroup
         void Free()
         void Commit()
+        void Reset()
         int32 GetState()
+       boolean IsEmpty()
         void AddService(int32 interface, int32 protocol, string name, string type, string domain, string host, uint16 port, string txt[])
         void AddAddress(int32 interface, int32 protocol, string name, string address)
         SIGNAL StateChanged(int32 state)
index 6da69731fe0fff0b3431af4deb7f03c20bf4ecb5..fa21b04869253e941a16e3435ed63a85222c9575 100644 (file)
@@ -13,6 +13,7 @@
   <interface name="org.freedesktop.Avahi.EntryGroup">
     <method name="Free"/>
     <method name="Commit"/>
+    <method name="Reset"/>
 
     <method name="GetState">
       <arg name="state" type="i" direction="out"/>
       <arg name="state" type="i"/>
     </signal>
 
+    <method name="IsEmpty">
+      <arg name="empty" type="b" direction="out"/>
+    </method>
+
     <method name="AddService">
       <arg name="interface" type="i" direction="in"/>
       <arg name="protocol" type="i" direction="in"/>
index 0813617b0adcadc62a07804376b1b2085196f05e..c6a60df22d80c14826090b8dcfeef7f08525f939 100644 (file)
@@ -513,6 +513,35 @@ static DBusHandlerResult msg_entry_group_impl(DBusConnection *c, DBusMessage *m,
         avahi_entry_group_commit(i->entry_group);
         return respond_ok(c, m);
         
+        
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "Reset")) {
+        
+        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
+            avahi_log_warn("Error parsing EntryGroup::Reset message");
+            goto fail;
+        }
+
+        avahi_entry_group_reset(i->entry_group);
+        return respond_ok(c, m);
+        
+    } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "IsEmpty")) {
+        DBusMessage *reply;
+        gboolean b;
+        
+        if (!dbus_message_get_args(m, &error, DBUS_TYPE_INVALID)) {
+            avahi_log_warn("Error parsing EntryGroup::IsEmpty message");
+            goto fail;
+        }
+
+        b = avahi_entry_group_is_empty(i->entry_group);
+        
+        reply = dbus_message_new_method_return(m);
+        dbus_message_append_args(m, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
+        dbus_connection_send(c, reply, NULL);
+        dbus_message_unref(reply);
+        
+        return DBUS_HANDLER_RESULT_HANDLED;
+        
     } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "GetState")) {
         DBusMessage *reply;
         gint32 t;
index 7d83c46858830eac293dbc5e782510e47087feec..1083416811bcb5625799852bb0f544e058461d0c 100644 (file)
@@ -131,14 +131,16 @@ finish:
     return ret;
 }
 
-static AvahiEntryGroup* add_dns_servers(AvahiServer *s, gchar **l) {
+static AvahiEntryGroup* add_dns_servers(AvahiServer *s, AvahiEntryGroup* g, gchar **l) {
     gchar **p;
-    AvahiEntryGroup *g;
 
     g_assert(s);
     g_assert(l);
 
-    g = avahi_entry_group_new(s, NULL, NULL);
+    if (!g) 
+        g = avahi_entry_group_new(s, NULL, NULL);
+
+    g_assert(avahi_entry_group_is_empty(g));
 
     for (p = l; *p; p++) {
         AvahiAddress a;
@@ -155,19 +157,15 @@ static AvahiEntryGroup* add_dns_servers(AvahiServer *s, gchar **l) {
     avahi_entry_group_commit(g);
 
     return g;
-    
 }
 
 static void remove_dns_server_entry_groups(void) {
-    if (resolv_conf_entry_group) {
-        avahi_entry_group_free(resolv_conf_entry_group);
-        resolv_conf_entry_group = NULL;
-    }
+
+    if (resolv_conf_entry_group)
+        avahi_entry_group_reset(resolv_conf_entry_group);
     
-    if (dns_servers_entry_group) {
-        avahi_entry_group_free(dns_servers_entry_group);
-        dns_servers_entry_group = NULL;
-    }
+    if (dns_servers_entry_group) 
+        avahi_entry_group_reset(dns_servers_entry_group);
 }
 
 static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) {
@@ -188,10 +186,10 @@ static void server_callback(AvahiServer *s, AvahiServerState state, gpointer use
         remove_dns_server_entry_groups();
 
         if (resolv_conf && resolv_conf[0])
-            resolv_conf_entry_group = add_dns_servers(s, resolv_conf);
+            resolv_conf_entry_group = add_dns_servers(s, resolv_conf_entry_group, resolv_conf);
 
         if (c->publish_dns_servers && c->publish_dns_servers[0])
-            dns_servers_entry_group = add_dns_servers(s, c->publish_dns_servers);
+            dns_servers_entry_group = add_dns_servers(s, dns_servers_entry_group, c->publish_dns_servers);
 
         simple_protocol_restart_queries();
         
@@ -207,8 +205,6 @@ static void server_callback(AvahiServer *s, AvahiServerState state, gpointer use
         avahi_server_set_host_name(s, n);
         g_free(n);
     }
-
-    
 }
 
 static void help(FILE *f, const gchar *argv0) {
@@ -476,15 +472,13 @@ static gboolean signal_callback(GIOChannel *source, GIOCondition condition, gpoi
             static_service_load();
             static_service_add_to_server();
 
-            if (resolv_conf_entry_group) {
-                avahi_entry_group_free(resolv_conf_entry_group);
-                resolv_conf_entry_group = NULL;
-            }
+            if (resolv_conf_entry_group)
+                avahi_entry_group_reset(resolv_conf_entry_group);
 
             load_resolv_conf(&config);
             
             if (resolv_conf && resolv_conf[0])
-                resolv_conf_entry_group = add_dns_servers(avahi_server, resolv_conf);
+                resolv_conf_entry_group = add_dns_servers(avahi_server, resolv_conf_entry_group, resolv_conf);
 
             break;
 
index 1f9b765099f0dd34501bc35e0d680e57b9d67940..8c54eab6d11494bcef273736917ddd3f7dd509f3 100644 (file)
@@ -152,7 +152,8 @@ static void static_service_free(StaticService *s) {
 static void static_service_group_free(StaticServiceGroup *g) {
     g_assert(g);
 
-    remove_static_service_group_from_server(g);
+    if (g->entry_group)
+        avahi_entry_group_free(g->entry_group);
 
     while (g->services)
         static_service_free(g->services);
@@ -202,8 +203,11 @@ static void add_static_service_group_to_server(StaticServiceGroup *g) {
         g->chosen_name = replacestr(g->name, "%h", avahi_server_get_host_name(avahi_server));
     else
         g->chosen_name = g_strdup(g->name);
-    
-    g->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, g);
+
+    if (!g->entry_group)
+        g->entry_group = avahi_entry_group_new(avahi_server, entry_group_callback, g);
+
+    g_assert(avahi_entry_group_is_empty(g->entry_group));
     
     for (s = g->services; s; s = s->services_next) {
 
@@ -226,10 +230,8 @@ static void add_static_service_group_to_server(StaticServiceGroup *g) {
 static void remove_static_service_group_from_server(StaticServiceGroup *g) {
     g_assert(g);
 
-    if (g->entry_group) {
-        avahi_entry_group_free(g->entry_group);
-        g->entry_group = NULL;
-    }
+    if (g->entry_group)
+        avahi_entry_group_reset(g->entry_group);
 }
 
 typedef enum {
index dfb21ab121de323698cabde9a79fa63b957f805c..ee0be765096333c3b4c0ce1d4b5e0aa6a947d0a4 100755 (executable)
@@ -70,16 +70,18 @@ n_rename = 0
 def remove_service():
     global group
 
-    if not (group is None):
-        group.Free()
-        group = None
+    if not group is None:
+        group.Reset()
 
 def add_service():
     global server, group, name, stype, domain, host, port, txt
-    assert group is None
+
+    if group is None:
+        group = dbus.Interface(bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP)
+
+    assert group.IsEmpty()
 
     print "Adding service '%s' of type '%s' ..." % (name, stype)
-    group = dbus.Interface(bus.get_object(avahi.DBUS_NAME, server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP)
     group.connect_to_signal('StateChanged', entry_group_state_changed)
     group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, name, stype, domain, host, dbus.UInt16(port), txt)
     group.Commit()
@@ -120,4 +122,5 @@ try:
 except KeyboardInterrupt, k:
     pass
 
-remove_service()
+if not group is None:
+    group.Free()
index 539dabb1ac0c6b1ff5d09e0b5007086aa5339895..831c1735829cb395a86acac510e58bfd4ac2895a 100644 (file)
@@ -1,4 +1,3 @@
-#!/usr/bin/python2.4
 # $Id$
 
 # This file is part of avahi.
@@ -21,9 +20,9 @@
 # Some definitions matching those in core.h
 import socket
 
-SERVER_INVALID, SERVER_REGISTERING, SERVER_RUNNING, SERVER_COLLISION, SERVER_SLEEPING = range(-1, 4)
+SERVER_INVALID, SERVER_REGISTERING, SERVER_RUNNING, SERVER_COLLISION = range(-1, 3)
 
-ENTRY_GROUP_UNCOMMITED, ENTRY_GROUP_REGISTERING, ENTRY_GROUP_ESTABLISHED, ENTRY_GROUP_COLLISION = range(-1, 3)
+ENTRY_GROUP_UNCOMMITED, ENTRY_GROUP_REGISTERING, ENTRY_GROUP_ESTABLISHED, ENTRY_GROUP_COLLISION, ENTRY_GROUP_SLEEPING = range(-1, 4)
 
 DOMAIN_BROWSER_REGISTER, DOMAIN_BROWSER_REGISTER_DEFAULT, DOMAIN_BROWSER_BROWSE, DOMAIN_BROWSER_BROWSE_DEFAULT, DOMAIN_BROWSER_BROWSE_LEGACY = range(0, 5)
 
index 690da385e2d25d7180cef4639d128df4e01dc0bb..9fa67b176cc82217e4b7094be81a21e184f80ae2 100644 (file)
@@ -102,9 +102,9 @@ DX_CHI_FEATURE(OFF)
 DX_MAN_FEATURE(OFF)
 DX_RTF_FEATURE(OFF)
 DX_XML_FEATURE(OFF)
-DX_PDF_FEATURE(ON)
+DX_PDF_FEATURE(OFF)
 DX_PS_FEATURE(OFF)
-DX_INIT_DOXYGEN(avahi, doxygen.cfg, doxygen-doc)
+DX_INIT_DOXYGEN(avahi, doxygen.cfg, doxygen)
 
 AC_ARG_ENABLE(dbus,
         AC_HELP_STRING([--enable-dbus],[use DBus (default=yes)]),
@@ -238,6 +238,7 @@ avahi-utils/avahi-dump-all
 avahi-utils/avahi-publish-service
 avahi-utils/avahi-publish-address
 avahi-utils/avahi-discover
+examples/Makefile
 ])
 AC_OUTPUT
 
index a751c6a430d405393b5cc52c203a51571ccd998e..f081d415152f36bb12ee7064238464356c6694fe 100644 (file)
@@ -58,7 +58,7 @@ SHOW_USED_FILES        = YES
 #---------------------------------------------------------------------------
 # configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
-QUIET                  = YES
+QUIET                  = NO
 WARNINGS               = YES
 WARN_IF_UNDOCUMENTED   = YES
 WARN_IF_DOC_ERROR      = YES
@@ -73,8 +73,8 @@ RECURSIVE              = NO
 EXCLUDE                = 
 EXCLUDE_SYMLINKS       = NO
 EXCLUDE_PATTERNS       = 
-EXAMPLE_PATH           = $(SRCDIR)
-EXAMPLE_PATTERNS       = 
+EXAMPLE_PATH           = $(SRCDIR)/examples
+EXAMPLE_PATTERNS       = *.c
 EXAMPLE_RECURSIVE      = NO
 IMAGE_PATH             = 
 INPUT_FILTER           = 
@@ -82,7 +82,7 @@ FILTER_SOURCE_FILES    = NO
 #---------------------------------------------------------------------------
 # configuration options related to source browsing
 #---------------------------------------------------------------------------
-SOURCE_BROWSER         = NO
+SOURCE_BROWSER         = YES
 INLINE_SOURCES         = NO
 STRIP_CODE_COMMENTS    = YES
 REFERENCED_BY_RELATION = YES
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644 (file)
index 0000000..e7be1bf
--- /dev/null
@@ -0,0 +1,36 @@
+# $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 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 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.
+
+AM_CFLAGS=-I$(top_srcdir)
+
+# GLIB 2.0
+AM_CFLAGS+=$(GLIB20_CFLAGS)
+AM_LDADD=$(GLIB20_LIBS)
+
+noinst_PROGRAMS = \
+       publish-service \
+       browse-services
+
+publish_service_SOURCES = publish-service.c
+publish_service_CFLAGS = $(AM_CFLAGS)
+publish_service_LDADD = $(AM_LDADD) ../avahi-core/libavahi-core.la ../avahi-common/libavahi-common.la
+
+browse_services_SOURCES = browse-services.c
+browse_services_CFLAGS = $(AM_CFLAGS)
+browse_services_LDADD = $(AM_LDADD) ../avahi-core/libavahi-core.la ../avahi-common/libavahi-common.la
diff --git a/examples/browse-services.c b/examples/browse-services.c
new file mode 100644 (file)
index 0000000..bb8eed8
--- /dev/null
@@ -0,0 +1,112 @@
+/* $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 <avahi-core/core.h>
+
+static GMainLoop *main_loop = NULL;
+
+static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const gchar *name,const gchar *type,const gchar *domain, const gchar *host_name, const AvahiAddress *address, guint16 port, AvahiStringList *txt, gpointer userdata) {
+    g_assert(r);
+
+    /* Called whenever a service has been resolved successfully or timed out */
+
+    if (event == AVAHI_RESOLVER_TIMEOUT)
+        g_message("Failed to resolve service '%s' of type '%s' in domain '%s'.", name, type, domain);
+    else {
+        gchar a[128], *t;
+
+        g_assert(event == AVAHI_RESOLVER_FOUND);
+        
+        g_message("Service '%s' of type '%s' in domain '%s':", name, type, domain);
+
+        avahi_address_snprint(a, sizeof(a), address);
+        t = avahi_string_list_to_string(txt);
+        g_message("\t%s:%u (%s) TXT=%s", host_name, port, a, t);
+        g_free(t);
+    }
+
+    avahi_service_resolver_free(r);
+}
+
+static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const gchar *name, const gchar *type, const gchar *domain, gpointer userdata) {
+    g_assert(b);
+    
+    AvahiServer *s = userdata;
+
+    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
+
+    g_message("%s: service '%s' of type '%s' in domain '%s'",
+              event == AVAHI_BROWSER_NEW ? "NEW" : "REMOVED",
+              name,
+              type,
+              domain);
+
+    /* If it's new, let's resolve it */
+    if (event == AVAHI_BROWSER_NEW)
+        
+        /* We ignore the returned resolver object. In the callback function
+        we free it. If the server is terminated before the callback
+        function is called the server will free the resolver for us. */
+
+        avahi_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, resolve_callback, s);
+}
+
+int main(int argc, char*argv[]) {
+    AvahiServerConfig config;
+    AvahiServer *server = NULL;
+    AvahiServiceBrowser *sb;
+
+    /* Do not publish any local records */
+    avahi_server_config_init(&config);
+    config.publish_hinfo = FALSE;
+    config.publish_addresses = FALSE;
+    config.publish_workstation = FALSE;
+    config.publish_domain = FALSE;
+    
+    /* Allocate a new server */
+    server = avahi_server_new(NULL, &config, NULL, NULL);
+
+    /* Free the configuration data */
+    avahi_server_config_free(&config);
+
+    /* Create the service browser */
+    sb = avahi_service_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_http._tcp", NULL, browse_callback, server);
+    
+    /* Run the main loop */
+    main_loop = g_main_loop_new(NULL, FALSE);
+    g_main_loop_run(main_loop);
+
+    /* Cleanup things */
+    if (sb)
+        avahi_service_browser_free(sb);
+    
+    if (server)
+        avahi_server_free(server);
+
+    if (main_loop)
+        g_main_loop_unref(main_loop);
+
+    return 0;
+}
diff --git a/examples/publish-service.c b/examples/publish-service.c
new file mode 100644 (file)
index 0000000..c9d0141
--- /dev/null
@@ -0,0 +1,156 @@
+/* $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 <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <avahi-core/core.h>
+
+static AvahiEntryGroup *group = NULL;
+static GMainLoop *main_loop = NULL;
+static gchar *name = NULL;
+
+static void create_services(AvahiServer *s);
+
+static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryGroupState state, gpointer userdata) {
+    g_assert(s);
+    g_assert(g == group);
+
+    /* Called whenever the entry group state changes */
+
+    if (state == AVAHI_ENTRY_GROUP_ESTABLISHED)
+        /* The entry group has been established successfully */
+        g_message("Service '%s' successfully established.", name);
+    
+    else if (state == AVAHI_ENTRY_GROUP_COLLISION) {
+        gchar *n;
+
+        /* A service name collision happened. Let's pick a new name */
+        n = avahi_alternative_service_name(name);
+        g_free(name);
+        name = n;
+
+        g_message("Service name collision, renaming service to '%s'", name);
+
+        /* And recreate the services */
+        create_services(s);
+    }
+}
+
+static void create_services(AvahiServer *s) {
+    gchar r[128];
+    g_assert(s);
+
+    /* If this is the first time we're called, let's create a new entry group */
+    if (!group)
+        group = avahi_entry_group_new(s, entry_group_callback, NULL);
+
+    g_message("Adding service '%s'", name);
+
+    /* Create some random TXT data */
+    snprintf(r, sizeof(r), "random=%i", rand());
+
+    /* Add the service for IPP */
+    if (avahi_server_add_service(s, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, name, "_ipp._tcp", NULL, NULL, 651, "test=blah", r, NULL) < 0) {
+        g_message("Failed to add _ipp._tcp service.");
+        g_main_loop_quit(main_loop);
+        return;
+    }
+
+    /* Add the same service for BSD LPR */
+    if (avahi_server_add_service(s, group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, name, "_printer._tcp", NULL, NULL, 515, NULL) < 0) {
+        g_message("Failed to add _printer._tcp service.");
+        g_main_loop_quit(main_loop);
+        return;
+    }
+
+    /* Tell the server to register the service */
+    avahi_entry_group_commit(group);
+}
+
+static void server_callback(AvahiServer *s, AvahiServerState state, gpointer userdata) {
+    g_assert(s);
+
+    /* Called whenever the server state changes */
+
+    if (state == AVAHI_SERVER_RUNNING)
+        /* The serve has startup successfully and registered its host
+         * name on the network, so it's time to create our services */
+        create_services(s);
+    
+    else if (state == AVAHI_SERVER_COLLISION) {
+        gchar *n;
+        
+        /* A host name collision happened. Let's pick a new name for the server */
+        n = avahi_alternative_host_name(avahi_server_get_host_name(s));
+        g_message("Host name collision, retrying with '%s'", n);
+        avahi_server_set_host_name(s, n);
+        g_free(n);
+
+        /* Let's drop our registered services. When the server is back
+         * in AVAHI_SERVER_RUNNING state we will register them
+         * again with the new host name. */
+        if (group)
+            avahi_entry_group_reset(group);
+    }
+}
+
+int main(int argc, char*argv[]) {
+    AvahiServerConfig config;
+    AvahiServer *server = NULL;
+
+    srand(time(NULL));
+    
+    name = g_strdup("MegaPrinter");
+
+    /* Let's set the host name for this server. */
+    avahi_server_config_init(&config);
+    config.host_name = g_strdup("gurkiman");
+    
+    /* Allocate a new server */
+    server = avahi_server_new(NULL, &config, server_callback, NULL);
+
+    /* Free the configuration data */
+    avahi_server_config_free(&config);
+    
+    /* Run the main loop */
+    main_loop = g_main_loop_new(NULL, FALSE);
+    g_main_loop_run(main_loop);
+
+    /* Cleanup things */
+    if (group)
+        avahi_entry_group_free(group);
+
+    if (server)
+        avahi_server_free(server);
+
+    if (main_loop)
+        g_main_loop_unref(main_loop);
+
+    g_free(name);
+    
+    return 0;
+}
diff --git a/todo b/todo
index e32d12c203c07d72c5faebedd7543a0d8d576ec4..be044cbe93ef445a3ea37f93374b9cbaf470d4af 100644 (file)
--- a/todo
+++ b/todo
@@ -1,9 +1,8 @@
 todo:
 * finish DBUS stuff:
        - allow NUL bytes in TXT records
-* release!
 * add internal error codes
-* add entry_group::reset()
+* release!
 
 later:
 * support for special domain PTR records based on local IP subnet address
@@ -49,3 +48,4 @@ done:
 * sensible logging
 * c++ support
 * drop trailing dot on avahi_normalize_name()
+* add entry_group::reset()