]> git.meshlink.io Git - catta/commitdiff
* case insensitive name comparisons
authorLennart Poettering <lennart@poettering.net>
Mon, 16 May 2005 01:01:43 +0000 (01:01 +0000)
committerLennart Poettering <lennart@poettering.net>
Mon, 16 May 2005 01:01:43 +0000 (01:01 +0000)
* corectly handle RRsets
* make addresses unique
* return to probe state on conflict
* a bunch of fixes detected while testing against the Apple Bonjour Conformance Test
* a fix in avahi_record_lexicographical_cmp() regarding TXT records
* API for choosing alternative host and service names
* remove a bunch of unused crap from cache.c and server.c
* flush cache when an interface becomes unavailable

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

18 files changed:
avahi-core/Makefile.am
avahi-core/alternative-test.c [new file with mode: 0644]
avahi-core/announce.c
avahi-core/announce.h
avahi-core/avahi-test.c
avahi-core/cache.c
avahi-core/cache.h
avahi-core/core.h
avahi-core/iface.c
avahi-core/iface.h
avahi-core/psched.c
avahi-core/psched.h
avahi-core/rr.c
avahi-core/server.c
avahi-core/server.h
avahi-core/util.c
avahi-core/util.h
todo

index e6708b6c99ddbfd24a4963d79a6ac91427a521be..cd22097e27ca417556fdef3b61adefbb7f4896eb 100644 (file)
@@ -27,14 +27,15 @@ AM_LDADD=$(GLIB20_LIBS)
 AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")'
 
 lib_LTLIBRARIES = \
-       libavahi-core.la
+       libavahi-core.la 
 
 noinst_PROGRAMS = \
        dns-test \
        domain-test \
        prioq-test \
        strlst-test \
-       avahi-test
+       avahi-test \
+       alternative-test
 
 libavahi_core_la_SOURCES = \
        timeeventq.c timeeventq.h\
@@ -82,9 +83,17 @@ dns_test_CFLAGS = $(AM_CFLAGS)
 dns_test_LDADD = $(AM_LDADD)
 
 avahi_test_SOURCES = \
-       avahi-test.c
+       avahi-test.c \
+       $(libavahi_core_la_SOURCES)
+
 avahi_test_CFLAGS = $(AM_CFLAGS)
-avahi_test_LDADD = $(AM_LDADD) libavahi-core.la
+avahi_test_LDADD = $(AM_LDADD)
+
+alternative_test_SOURCES = \
+       alternative-test.c \
+       util.c util.h
+alternative_test_CFLAGS = $(AM_CFLAGS)
+alternative_test_LDADD = $(AM_LDADD)
 
 valgrind: avahi-test
        libtool --mode=execute valgrind ./avahi-test
diff --git a/avahi-core/alternative-test.c b/avahi-core/alternative-test.c
new file mode 100644 (file)
index 0000000..18bc698
--- /dev/null
@@ -0,0 +1,48 @@
+/* $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 <stdio.h>
+
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+    gchar *r = NULL;
+    gint i, k;
+
+    for (k = 0; k < 2; k++) {
+        
+        for (i = 0; i < 20; i++) {
+            gchar *n;
+            
+            n = i == 0 ? g_strdup("gurke") : (k ? avahi_alternative_service_name(r) : avahi_alternative_host_name(r));
+            g_free(r);
+            r = n;
+            
+            printf("%s\n", r);
+        }
+    }
+
+    g_free(r);
+}
index 5ee0f48f2e7240d58e857b061617588a8b33b7dc..8149b387a3464356a0e50cc32394df831bb4fe7c 100644 (file)
@@ -152,7 +152,13 @@ static void next_state(AvahiAnnouncement *a) {
 
     } else if (a->state == AVAHI_ANNOUNCING) {
 
-        avahi_interface_post_response(a->interface, a->entry->record, a->entry->flags & AVAHI_ENTRY_UNIQUE, FALSE);
+        if (a->entry->flags & AVAHI_ENTRY_UNIQUE)
+            /* Send the whole rrset at once */
+            avahi_server_prepare_matching_responses(a->server, a->interface, a->entry->record->key, FALSE);
+        else
+            avahi_server_prepare_response(a->server, a->interface, a->entry, FALSE);
+
+        avahi_server_generate_response(a->server, a->interface, NULL, NULL, 0, FALSE);
 
         if (++a->n_iteration >= 4) {
             gchar *t;
@@ -196,9 +202,43 @@ AvahiAnnouncement *avahi_get_announcement(AvahiServer *s, AvahiEntry *e, AvahiIn
     return NULL;
 }
 
+static void go_to_initial_state(AvahiAnnouncement *a, gboolean immediately) {
+    AvahiEntry *e;
+    GTimeVal tv;
+        
+    g_assert(a);
+    e = a->entry;
+    
+    if ((e->flags & AVAHI_ENTRY_UNIQUE) && !(e->flags & AVAHI_ENTRY_NOPROBE))
+        a->state = AVAHI_PROBING;
+    else if (!(e->flags & AVAHI_ENTRY_NOANNOUNCE)) {
+
+        if (!e->group || e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED)
+            a->state = AVAHI_ANNOUNCING;
+        else
+            a->state = AVAHI_WAITING;
+        
+    } else
+        a->state = AVAHI_ESTABLISHED;
+
+    a->n_iteration = 1;
+    a->sec_delay = 1;
+
+    if (a->state == AVAHI_PROBING && e->group)
+        e->group->n_probing++;
+
+    if (a->state == AVAHI_PROBING) {
+        avahi_elapse_time(&tv, 0, immediately ? 0 : AVAHI_PROBE_JITTER_MSEC);
+        set_timeout(a, &tv);
+    } else if (a->state == AVAHI_ANNOUNCING) {
+        avahi_elapse_time(&tv, 0, immediately ? 0 : AVAHI_ANNOUNCEMENT_JITTER_MSEC);
+        set_timeout(a, &tv);
+    } else
+        set_timeout(a, NULL);
+}
+
 static void new_announcement(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) {
     AvahiAnnouncement *a;
-    GTimeVal tv;
     gchar *t; 
 
     g_assert(s);
@@ -220,41 +260,15 @@ static void new_announcement(AvahiServer *s, AvahiInterface *i, AvahiEntry *e) {
     a->server = s;
     a->interface = i;
     a->entry = e;
-
-    if ((e->flags & AVAHI_ENTRY_UNIQUE) && !(e->flags & AVAHI_ENTRY_NOPROBE))
-        a->state = AVAHI_PROBING;
-    else if (!(e->flags & AVAHI_ENTRY_NOANNOUNCE)) {
-
-        if (!e->group || e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED)
-            a->state = AVAHI_ANNOUNCING;
-        else
-            a->state = AVAHI_WAITING;
-        
-    } else
-        a->state = AVAHI_ESTABLISHED;
-
-
-    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);
-
-    a->n_iteration = 1;
-    a->sec_delay = 1;
     a->time_event = NULL;
 
-    if (a->state == AVAHI_PROBING)
-        if (e->group)
-            e->group->n_probing++;
-    
     AVAHI_LLIST_PREPEND(AvahiAnnouncement, by_interface, i->announcements, a);
     AVAHI_LLIST_PREPEND(AvahiAnnouncement, by_entry, e->announcements, a);
 
-    if (a->state == AVAHI_PROBING) {
-        avahi_elapse_time(&tv, 0, AVAHI_PROBE_JITTER_MSEC);
-        set_timeout(a, &tv);
-    } else if (a->state == AVAHI_ANNOUNCING) {
-        avahi_elapse_time(&tv, 0, AVAHI_ANNOUNCEMENT_JITTER_MSEC);
-        set_timeout(a, &tv);
-    }
+    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);
 }
 
 void avahi_announce_interface(AvahiServer *s, AvahiInterface *i) {
@@ -312,10 +326,13 @@ gboolean avahi_entry_registered(AvahiServer *s, AvahiEntry *e, AvahiInterface *i
     if (!(a = avahi_get_announcement(s, e, i)))
         return FALSE;
     
-    return a->state == AVAHI_ANNOUNCING || a->state == AVAHI_ESTABLISHED;
+    return
+        a->state == AVAHI_ANNOUNCING ||
+        a->state == AVAHI_ESTABLISHED ||
+        (a->state == AVAHI_WAITING && !(e->flags & AVAHI_ENTRY_UNIQUE));
 }
 
-gboolean avahi_entry_registering(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
+gboolean avahi_entry_probing(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
     AvahiAnnouncement *a;
 
     g_assert(s);
@@ -326,7 +343,25 @@ gboolean avahi_entry_registering(AvahiServer *s, AvahiEntry *e, AvahiInterface *
     if (!(a = avahi_get_announcement(s, e, i)))
         return FALSE;
     
-    return a->state == AVAHI_PROBING || a->state == AVAHI_WAITING;
+    return
+        a->state == AVAHI_PROBING ||
+        (a->state == AVAHI_WAITING && (e->flags & AVAHI_ENTRY_UNIQUE));
+}
+
+void avahi_entry_return_to_initial_state(AvahiServer *s, AvahiEntry *e, AvahiInterface *i) {
+    AvahiAnnouncement *a;
+    
+    g_assert(s);
+    g_assert(e);
+    g_assert(i);
+
+    if (!(a = avahi_get_announcement(s, e, i)))
+        return;
+
+    if (a->state == AVAHI_PROBING && a->entry->group)
+        a->entry->group->n_probing--;
+
+    go_to_initial_state(a, TRUE);
 }
 
 static AvahiRecord *make_goodbye_record(AvahiRecord *r) {
@@ -364,7 +399,7 @@ static void send_goodbye_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, g
         return;
     
     g = make_goodbye_record(e->record);
-    avahi_interface_post_response(i, g, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
+    avahi_interface_post_response(i, g, e->flags & AVAHI_ENTRY_UNIQUE, TRUE, NULL);
     avahi_record_unref(g);
 }
     
index 389c7ca37c4d60505750ae630ebc84d91e2ba3a5..244a00f493443e3a4890a1ddbbc6e194a85e1905 100644 (file)
@@ -57,10 +57,12 @@ void avahi_announce_interface(AvahiServer *s, AvahiInterface *i);
 void avahi_announce_entry(AvahiServer *s, AvahiEntry *e);
 void avahi_announce_group(AvahiServer *s, AvahiEntryGroup *g);
 
+void avahi_entry_return_to_initial_state(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
+
 void avahi_entry_group_check_probed(AvahiEntryGroup *g, gboolean immediately);
 
 gboolean avahi_entry_registered(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
-gboolean avahi_entry_registering(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
+gboolean avahi_entry_probing(AvahiServer *s, AvahiEntry *e, AvahiInterface *i);
 
 void avahi_goodbye_interface(AvahiServer *s, AvahiInterface *i, gboolean send);
 void avahi_goodbye_entry(AvahiServer *s, AvahiEntry *e, gboolean send);
index 553a0219263fa2fc7e81e0f078289a4805b059ee..e275649053b7bf2fad23cce827c9df61dca57df9 100644 (file)
@@ -50,7 +50,7 @@ static void subscription(AvahiSubscription *s, AvahiRecord *r, gint interface, g
     g_assert(protocol != AF_UNSPEC);
 
     g_message("SUBSCRIPTION: record [%s] on %i.%i is %s", t = avahi_record_to_string(r), interface, protocol,
-              event == AVAHI_SUBSCRIPTION_NEW ? "new" : (event == AVAHI_SUBSCRIPTION_CHANGE ? "changed" : "removed"));
+              event == AVAHI_SUBSCRIPTION_NEW ? "new" : "removed");
 
     g_free(t);
 }
@@ -61,7 +61,6 @@ static void entry_group_callback(AvahiServer *s, AvahiEntryGroup *g, AvahiEntryG
 
 int main(int argc, char *argv[]) {
     AvahiServer *avahi;
-    gchar *r;
     GMainLoop *loop = NULL;
     AvahiSubscription *s;
     AvahiKey *k;
@@ -69,32 +68,31 @@ int main(int argc, char *argv[]) {
 
     avahi = avahi_server_new(NULL);
 
-     g = avahi_entry_group_new(avahi, entry_group_callback, NULL);  
+    g = avahi_entry_group_new(avahi, entry_group_callback, NULL);   
     
-    avahi_server_add_text(avahi, g, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, "HALLO", "hallo", NULL); 
-    avahi_server_add_text(avahi, g, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, "hallo", "waldo", 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); */
     
-    avahi_server_add_service(avahi, g, 0, AF_UNSPEC, "_http._tcp", "gurke", NULL, NULL, 80, "foo", NULL);  
+    avahi_server_add_service(avahi, g, 0, AF_UNSPEC, "_http._tcp", "gurke", NULL, NULL, 80, "foo", NULL);   
     
-    avahi_entry_group_commit(g);  
+    avahi_entry_group_commit(g);   
 
     avahi_server_dump(avahi, stdout);
     
-    
-/*     k = avahi_key_new("ecstasy.local.", AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_ANY); */
+/*     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*20, dump_timeout, Avahi); */
-/*     g_timeout_add(1000*30, quit_timeout, loop);  */
+    g_timeout_add(1000*5, dump_timeout, avahi); 
+/*     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_subscription_free(s);  */
+    avahi_entry_group_free(g);   
     avahi_server_free(avahi);
     
     return 0;
index 5b9c8818dd10faef20d28cb2076df271c1ffe99b..cba9c0b4382ae12576e0bd56ff425f9bdc6c9163 100644 (file)
@@ -220,8 +220,17 @@ static void next_expiry(AvahiCache *c, AvahiCacheEntry *e, guint percent) {
     update_time_event(c, e);
 }
 
+static void expire_in_one_second(AvahiCache *c, AvahiCacheEntry *e) {
+    g_assert(c);
+    g_assert(e);
+    
+    e->state = AVAHI_CACHE_FINAL;
+    g_get_current_time(&e->expiry);
+    g_time_val_add(&e->expiry, 1000000); /* 1s */
+    update_time_event(c, e);
+}
+
 void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const AvahiAddress *a) {
-    AvahiCacheEntry *e, *t;
     gchar *txt;
     
     g_assert(c);
@@ -231,51 +240,51 @@ void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const Av
     g_free(txt);
 
     if (r->ttl == 0) {
-
         /* This is a goodbye request */
 
-        if ((e = avahi_cache_lookup_record(c, r))) {
+        AvahiCacheEntry *e;
 
-            e->state = AVAHI_CACHE_FINAL;
-            g_get_current_time(&e->timestamp);
-            e->expiry = e->timestamp;
-            g_time_val_add(&e->expiry, 1000000); /* 1s */
-            update_time_event(c, e);
-        }
+        if ((e = avahi_cache_lookup_record(c, r)))
+            expire_in_one_second(c, e);
 
     } else {
+        AvahiCacheEntry *e = NULL, *first;
+        GTimeVal now;
+
+        g_get_current_time(&now);
 
         /* This is an update request */
 
-        if ((t = e = avahi_cache_lookup_key(c, r->key))) {
-        
+        if ((first = avahi_cache_lookup_key(c, r->key))) {
+            
             if (unique) {
-                
-                /* For unique records, remove all entries but one */
-                while (e->by_key_next)
-                    remove_entry(c, e->by_key_next);
-                
-            } else {
-                
-                /* For non-unique record, look for exactly the same entry */
-                for (; e; e = e->by_key_next)
-                    if (avahi_record_equal_no_ttl(e->record, r))
-                        break;
+
+                /* For unique entries drop all entries older than one second */
+                for (e = first; e; e = e->by_key_next) {
+                    glong t;
+
+                    t = avahi_timeval_diff(&now, &e->timestamp);
+
+                    if (t > 1000000)
+                        expire_in_one_second(c, e);
+                }
             }
+                
+            /* Look for exactly the same entry */
+            for (e = first; e; e = e->by_key_next)
+                if (avahi_record_equal_no_ttl(e->record, r))
+                    break;
         }
     
         if (e) {
             
-/*         g_message("found matching cache entry"); */
-            
-            /* We are the first in the linked list so let's replace the hash table key with the new one */
+            g_message("found matching cache entry"); 
+
+            /* We need to update the hash table key if we replace the
+             * record */
             if (e->by_key_prev == NULL)
                 g_hash_table_replace(c->hash_table, r->key, e);
             
-            /* Notify subscribers */
-            if (!avahi_record_equal_no_ttl(e->record, r))
-                avahi_subscription_notify(c->server, c->interface, r, AVAHI_SUBSCRIPTION_CHANGE);    
-            
             /* Update the record */
             avahi_record_unref(e->record);
             e->record = avahi_record_ref(r);
@@ -283,7 +292,7 @@ void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const Av
         } 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;
@@ -291,8 +300,8 @@ void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const Av
             e->record = avahi_record_ref(r);
 
             /* Append to hash table */
-            AVAHI_LLIST_PREPEND(AvahiCacheEntry, by_key, t, e);
-            g_hash_table_replace(c->hash_table, e->record->key, t);
+            AVAHI_LLIST_PREPEND(AvahiCacheEntry, by_key, first, e);
+            g_hash_table_replace(c->hash_table, e->record->key, first);
 
             /* Append to linked list */
             AVAHI_LLIST_PREPEND(AvahiCacheEntry, entry, c->entries, e);
@@ -302,49 +311,24 @@ void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const Av
         } 
         
         e->origin = *a;
-        g_get_current_time(&e->timestamp);
+        e->timestamp = now;
         next_expiry(c, e, 80);
         e->state = AVAHI_CACHE_VALID;
     }
 }
 
-static gpointer drop_key_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) {
-    g_assert(c);
-    g_assert(pattern);
-    g_assert(e);
-
-    remove_entry(c, e);
-    return NULL;
-}
-
-void avahi_cache_drop_key(AvahiCache *c, AvahiKey *k) {
-    g_assert(c);
-    g_assert(k);
-
-    avahi_cache_walk(c, k, drop_key_callback, NULL);
-}
-
-void avahi_cache_drop_record(AvahiCache *c, AvahiRecord *r) {
-    AvahiCacheEntry *e;
-    
-    g_assert(c);
-    g_assert(r);
-
-    if ((e = avahi_cache_lookup_record(c, r))) 
-        remove_entry(c, e);
-}
-
-static void func(gpointer key, gpointer data, gpointer userdata) {
+static void dump_callback(gpointer key, gpointer data, gpointer userdata) {
     AvahiCacheEntry *e = data;
     AvahiKey *k = key;
-    gchar *t;
 
     g_assert(k);
     g_assert(e);
-    
-    t = avahi_record_to_string(e->record);
-    fprintf((FILE*) userdata, "%s\n", t);
-    g_free(t);
+
+    for (; e; e = e->by_key_next) {
+        gchar *t = avahi_record_to_string(e->record);
+        fprintf((FILE*) userdata, "%s\n", t);
+        g_free(t);
+    }
 }
 
 void avahi_cache_dump(AvahiCache *c, FILE *f) {
@@ -352,7 +336,7 @@ void avahi_cache_dump(AvahiCache *c, FILE *f) {
     g_assert(f);
 
     fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
-    g_hash_table_foreach(c->hash_table, func, f);
+    g_hash_table_foreach(c->hash_table, dump_callback, f);
 }
 
 gboolean avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e) {
@@ -366,7 +350,14 @@ gboolean avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e) {
 
     age = avahi_timeval_diff(&now, &e->timestamp)/1000000;
 
-    g_message("age: %u, ttl/2: %u", age, e->record->ttl);
+/*     g_message("age: %u, ttl/2: %u", age, e->record->ttl); */
     
     return age >= e->record->ttl/2;
 }
+
+void avahi_cache_flush(AvahiCache *c) {
+    g_assert(c);
+
+    while (c->entries)
+        remove_entry(c, c->entries);
+}
index 3f05b8e11c335e28e9f013d893cf8ced3b314752..4415c3c72627e4a530896803c90a84c5eea689ab 100644 (file)
@@ -74,8 +74,6 @@ AvahiCacheEntry *avahi_cache_lookup_record(AvahiCache *c, AvahiRecord *r);
 
 void avahi_cache_update(AvahiCache *c, AvahiRecord *r, gboolean unique, const AvahiAddress *a);
 
-void avahi_cache_drop_record(AvahiCache *c,  AvahiRecord *r);
-
 void avahi_cache_dump(AvahiCache *c, FILE *f);
 
 typedef gpointer AvahiCacheWalkCallback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata);
@@ -83,4 +81,6 @@ gpointer avahi_cache_walk(AvahiCache *c, AvahiKey *pattern, AvahiCacheWalkCallba
 
 gboolean avahi_cache_entry_half_ttl(AvahiCache *c, AvahiCacheEntry *e);
 
+void avahi_cache_flush(AvahiCache *c);
+
 #endif
index 42e6ee09e2b233c9762ede05608265f3f5e41f33..98f36b2dcc0fd791d7ebedff95157e4405b5073b 100644 (file)
@@ -51,6 +51,9 @@ typedef void (*AvahiEntryGroupCallback) (AvahiServer *s, AvahiEntryGroup *g, Ava
 AvahiServer *avahi_server_new(GMainContext *c);
 void avahi_server_free(AvahiServer* s);
 
+const gchar* avahi_server_get_domain(AvahiServer *s);
+const gchar* avahi_server_get_host_name(AvahiServer *s);
+
 const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiEntryGroup *g, void **state);
 void avahi_server_dump(AvahiServer *s, FILE *f);
 
@@ -151,7 +154,6 @@ void avahi_server_add_service_strlst(
 typedef enum {
     AVAHI_SUBSCRIPTION_NEW,
     AVAHI_SUBSCRIPTION_REMOVE,
-    AVAHI_SUBSCRIPTION_CHANGE
 } AvahiSubscriptionEvent;
 
 typedef struct AvahiSubscription AvahiSubscription;
index 23507f222379b2d5094a86c86cb4ca46e11dca6b..7f51305b54a0de895ab5e4afaddfe5987df2ac82 100644 (file)
@@ -49,7 +49,7 @@ static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a
     } else {
         if (!a->entry_group) {
             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_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);
         }
     }
@@ -202,13 +202,14 @@ static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i
     } else if (!b && i->announcing) {
         g_message("Interface %s.%i no longer relevant", i->hardware->name, i->protocol);
 
-        avahi_goodbye_interface(m->server, i, FALSE);
-
         if (i->protocol == AF_INET)
             avahi_mdns_mcast_leave_ipv4 (i->hardware->index, m->server->fd_ipv4);
         if (i->protocol == AF_INET6)
             avahi_mdns_mcast_leave_ipv6 (i->hardware->index, m->server->fd_ipv6);
 
+        avahi_goodbye_interface(m->server, i, FALSE);
+        avahi_cache_flush(i->cache);
+
         i->announcing = FALSE;
     }
 }
@@ -510,12 +511,12 @@ gboolean avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean i
     return FALSE;
 }
 
-gboolean avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+gboolean avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, gboolean flush_cache, gboolean immediately, const AvahiAddress *querier) {
     g_assert(i);
     g_assert(record);
 
     if (avahi_interface_relevant(i))
-        return avahi_packet_scheduler_post_response(i->scheduler, record, flush_cache, immediately);
+        return avahi_packet_scheduler_post_response(i->scheduler, record, flush_cache, immediately, querier);
 
     return FALSE;
 }
index 00aea9aa9f4906342106432bd4130e4d0d45d76f..e229b2c0a16fc51f2e1f127af8f22144793aa067 100644 (file)
@@ -108,7 +108,7 @@ void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, c
 
 gboolean avahi_interface_post_query(AvahiInterface *i, AvahiKey *k, gboolean immediately);
 gboolean avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *p, gboolean immediately);
-gboolean avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+gboolean avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, gboolean flush_cache, gboolean immediately, const AvahiAddress *querier);
 
 void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f);
 
index 60bf40c88a57f7d9df5bc24018c296d575d6b5ed..51210547d565ce7b39ed0251e26674ad22495283 100644 (file)
@@ -229,7 +229,7 @@ static void query_elapse(AvahiTimeEvent *e, gpointer data) {
     append_known_answers_and_send(s, p);
 }
 
-AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) {
+static AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) {
     AvahiQueryJob *qj;
     
     g_assert(s);
@@ -246,6 +246,19 @@ AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) {
     return qj;
 }
 
+static AvahiQueryJob* look_for_query(AvahiPacketScheduler *s, AvahiKey *key) {
+    AvahiQueryJob *qj;
+
+    g_assert(s);
+    g_assert(key);
+
+    for (qj = s->query_jobs; qj; qj = qj->jobs_next)
+        if (avahi_key_equal(qj->key, key))
+            return qj;
+
+    return NULL;
+}
+
 gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) {
     GTimeVal tv;
     AvahiQueryJob *qj;
@@ -255,22 +268,23 @@ gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *ke
 
     avahi_elapse_time(&tv, immediately ? 0 : AVAHI_QUERY_DEFER_MSEC, 0);
 
-    for (qj = s->query_jobs; qj; qj = qj->jobs_next) {
-
-        if (avahi_key_equal(qj->key, key)) {
+    if ((qj = look_for_query(s, key))) {
+        glong d = avahi_timeval_diff(&tv, &qj->delivery);
 
-            glong d = avahi_timeval_diff(&tv, &qj->delivery);
-
-            /* Duplicate questions suppression */
-            if (d >= 0 && d <= AVAHI_QUERY_HISTORY_MSEC*1000) {
-                g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
-                return FALSE;
-            }
+        /* Duplicate questions suppression */
+        if (!qj->done || d <= AVAHI_QUERY_HISTORY_MSEC*1000) {
+            g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
             
+            if (!qj->done && d < 0) {
+                /* If the new entry should be scheduled earlier,
+                 * update the old entry */
+                qj->delivery = tv;
+                avahi_time_event_queue_update(s->server->time_event_queue, qj->time_event, &qj->delivery);
+            }
+                
+            return FALSE;
+        } else
             query_job_free(s, qj);
-            break;
-        }
-
     }
     
     qj = query_job_new(s, key);
@@ -279,6 +293,34 @@ gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *ke
     return TRUE;
 }
 
+
+void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) {
+    AvahiQueryJob *qj;
+    GTimeVal tv;
+    
+    g_assert(s);
+    g_assert(key);
+
+    /* This function is called whenever an incoming query was
+     * receieved. We mark all matching queries that match as done. The
+     * keyword is "DUPLICATE QUESTION SUPPRESION". */
+
+    if (!(qj = look_for_query(s, key)))
+        qj = query_job_new(s, key);
+
+    qj->done = TRUE;
+
+    /* Drop the query after some time */
+    avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0);
+    
+    if (qj->time_event)
+        avahi_time_event_queue_update(s->server->time_event_queue, qj->time_event, &tv);
+    else
+        qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, query_elapse, qj);
+
+    g_get_current_time(&qj->delivery);
+}
+
 static guint8* packet_add_response_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) {
     guint8 *d;
 
@@ -376,13 +418,14 @@ static AvahiResponseJob* response_job_new(AvahiPacketScheduler *s, AvahiRecord *
     rj->done = FALSE;
     rj->time_event = NULL;
     rj->flush_cache = FALSE;
+    rj->querier_valid = FALSE;
     
     AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->response_jobs, rj);
 
     return rj;
 }
 
-gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately, const AvahiAddress *querier) {
     AvahiResponseJob *rj;
     GTimeVal tv;
     
@@ -396,70 +439,48 @@ gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiReco
     /* Don't send out duplicates */
     
     if ((rj = look_for_response(s, record))) {
-        glong d;
-
-        d = avahi_timeval_diff(&tv, &rj->delivery);
         
+        glong d = avahi_timeval_diff(&tv, &rj->delivery);
+
         /* If there's already a matching packet in our history or in
          * the schedule, we do nothing. */
-        if (!!record->ttl == !!rj->record->ttl &&
-            d >= 0 && d <= AVAHI_RESPONSE_HISTORY_MSEC*1000) {
-            g_message("WARNING! DUPLICATE RESPONSE SUPPRESSION ACTIVE!");
-
-            rj->flush_cache = flush_cache;
+        
+        if ((!!record->ttl == !!rj->record->ttl) &&
+            (rj->flush_cache || !flush_cache) &&
+            ((!rj->done && d >= 0) || (rj->done && d <= AVAHI_RESPONSE_HISTORY_MSEC*1000))) {
             
+            g_message("Duplicate suppresion active.");
             return FALSE;
         }
 
-        /* Either one was a goodbye packet, but the other was not, so
-         * let's drop the older one. */
+        /* If the old job was not yet done but scheduled earlier than
+         * our new one, we chedule our new job at the same time. */ 
+        if (!rj->done && d > 0)
+            tv = rj->delivery;
+
+        /* If the old job had the flush_cache bit enabled, we must
+           enable it on our new one, too */
+        if (!rj->done && rj->flush_cache)
+            flush_cache = TRUE;
+
+        /* For known answer suppresion we have record for which host this data was intended */
+        if (querier && !rj->done && (!rj->querier_valid || avahi_address_cmp(&rj->querier, querier) != 0))
+            querier = NULL;
+        
+        /* The old job wasn't good enough, so let's drop it */
         response_job_free(s, rj);
     }
 
-/*     g_message("ACCEPTED NEW RESPONSE [%s]", t = avahi_record_to_string(record)); */
-/*     g_free(t); */
-
     /* Create a new job and schedule it */
     rj = response_job_new(s, record);
     rj->flush_cache = flush_cache;
     rj->delivery = tv;
     rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &rj->delivery, response_elapse, rj);
 
-    return TRUE;
-}
-
-void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) {
-    GTimeVal tv;
-    AvahiQueryJob *qj;
-    
-    g_assert(s);
-    g_assert(key);
+    if ((rj->querier_valid = !!querier))
+        rj->querier = *querier;
 
-    /* This function is called whenever an incoming query was
-     * receieved. We drop all scheduled queries which match here. The
-     * keyword is "DUPLICATE QUESTION SUPPRESION". */
-
-    for (qj = s->query_jobs; qj; qj = qj->jobs_next)
-        if (avahi_key_equal(qj->key, key)) {
-
-            if (qj->done)
-                return;
-
-            goto mark_done;
-        }
-
-
-    /* No matching job was found. Add the query to the history */
-    qj = query_job_new(s, key);
-
-mark_done:
-    qj->done = TRUE;
-
-    /* Drop the query after some time */
-    avahi_elapse_time(&tv, AVAHI_QUERY_HISTORY_MSEC, 0);
-    qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, query_elapse, qj);
-
-    g_get_current_time(&qj->delivery);
+    return TRUE;
 }
 
 void response_job_set_elapse_time(AvahiPacketScheduler *s, AvahiResponseJob *rj, guint msec, guint jitter) {
@@ -476,8 +497,8 @@ void response_job_set_elapse_time(AvahiPacketScheduler *s, AvahiResponseJob *rj,
         rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &tv, response_elapse, rj);
 }
 
-void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record) {
-    AvahiResponseJob *rj;
+void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache) {
+    AvahiResponseJob *rj = NULL;
     
     g_assert(s);
     g_assert(record);
@@ -485,51 +506,39 @@ void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiReco
     /* This function is called whenever an incoming response was
      * receieved. We drop all scheduled responses which match
      * here. The keyword is "DUPLICATE ANSWER SUPPRESION". */
-    
-    for (rj = s->response_jobs; rj; rj = rj->jobs_next)
-        if (avahi_record_equal_no_ttl(rj->record, record)) {
-
-            if (rj->done) {
-
-                if (!!record->ttl == !!rj->record->ttl) {
-                    /* An entry like this is already in our history,
-                     * so let's get out of here! */
-                    
-                    return;
-                    
-                } else {
-                    /* Either one was a goodbye packet but other was
-                     * none. We remove the history entry, and add a
-                     * new one */
-                    
-                    response_job_free(s, rj);
-                    break;
-                }
-        
-            } else {
-
-                if (!!record->ttl == !!rj->record->ttl) {
 
-                    /* The incoming packet matches our scheduled
-                     * record, so let's mark that one as done */
-
-                    goto mark_done;
-                    
-                } else {
+    if ((rj = look_for_response(s, record))) {
+    
+        if (!rj->done) {
 
-                    /* Either one was a goodbye packet but other was
-                     * none. We ignore the incoming packet. */
+            if (rj->flush_cache && !flush_cache)
+                /* The incoming response didn't have flush_cache
+                 * set, but our scheduled has => we still have to
+                 * send our response */
+                return;
 
-                    return;
-                }
+            
+            if (!!record->ttl != !!rj->record->ttl) {
+                /* Either one was a goodbye packet but other was
+                 * none => we still have to send our response */
+                return;
             }
         }
+        
+        /* The two responses match, so let's mark the history
+         * entry as done or update it */
+    }
 
     /* No matching job was found. Add the query to the history */
-    rj = response_job_new(s, record);
-
-mark_done:
+    if (!rj) 
+        rj = response_job_new(s, record);
+    else {
+        avahi_record_unref(rj->record);
+        rj->record = avahi_record_ref(record);
+    }
+    
     rj->done = TRUE;
+    rj->flush_cache = rj->flush_cache || flush_cache;
                     
     /* Drop response after 500ms from history */
     response_job_set_elapse_time(s, rj, AVAHI_RESPONSE_HISTORY_MSEC, 0);
@@ -537,6 +546,34 @@ mark_done:
     g_get_current_time(&rj->delivery);
 }
 
+
+void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *querier) {
+    AvahiResponseJob *rj;
+    
+    g_assert(s);
+    g_assert(record);
+    g_assert(querier);
+
+    /* Check whether a matching job has been scheduled */
+    if (!(rj = look_for_response(s, record)) || rj->done)
+        return;
+
+    /* Chech whether another querier demanded the original job */
+    if (!rj->querier_valid || avahi_address_cmp(&rj->querier, querier) != 0)
+        return;
+
+    /* Check whether one of them is a goodbye packet, while the other is not */
+    if (!!record->ttl != !!rj->record->ttl)
+        return;
+
+    /* Check whether the known answer has a good TTL */
+    if (record->ttl <= rj->record->ttl/2)
+        return;
+
+    g_message("Known answer suppression active!");
+    response_job_free(s, rj);
+}
+
 void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s) {
     AvahiResponseJob *rj;
     
@@ -660,7 +697,7 @@ static void probe_elapse(AvahiTimeEvent *e, gpointer data) {
         if (!pj->chosen)
             continue;
 
-        if (!avahi_dns_packet_append_record(p, pj->record, TRUE, 0)) {
+        if (!avahi_dns_packet_append_record(p, pj->record, FALSE, 0)) {
             g_warning("Bad probe size estimate!");
 
             /* Unmark all following jobs */
index 12ea8800ff33b1cea2be165710952430402b78d0..4b9e5b24e7923588d61c1a6dec70e3346aefa2d8 100644 (file)
@@ -49,6 +49,10 @@ struct AvahiResponseJob {
     gboolean done;
     GTimeVal delivery;
     gboolean flush_cache;
+
+    AvahiAddress querier;
+    gboolean querier_valid;
+    
     AVAHI_LLIST_FIELDS(AvahiResponseJob, jobs);
 };
 
@@ -85,11 +89,12 @@ AvahiPacketScheduler *avahi_packet_scheduler_new(AvahiServer *server, AvahiInter
 void avahi_packet_scheduler_free(AvahiPacketScheduler *s);
 
 gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately);
-gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately, const AvahiAddress *querier);
 gboolean avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately);
 
 void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key);
-void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record);
+void avahi_packet_scheduler_incoming_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache);
+void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *querier);
 
 void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s);
 
index a9f6361d819a8a596db00a277c9b2b83c4da7927..5b5ec7ec8d45d3836b34a2eaf35949c9683eb54e 100644 (file)
@@ -456,9 +456,17 @@ static gint uint16_cmp(guint16 a, guint16 b) {
 }
 
 gint avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b) {
+    gint r;
+/*     gchar *t1, *t2; */
+
     g_assert(a);
     g_assert(b);
-    gint r;
+
+/*     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;
@@ -500,7 +508,7 @@ gint avahi_record_lexicographical_compare(AvahiRecord *a, AvahiRecord *b) {
             ma = g_new(guint8, asize = avahi_string_list_serialize(a->data.txt.string_list, NULL, 0));
             mb = g_new(guint8, bsize = avahi_string_list_serialize(b->data.txt.string_list, NULL, 0));
             avahi_string_list_serialize(a->data.txt.string_list, ma, asize);
-            avahi_string_list_serialize(a->data.txt.string_list, mb, bsize);
+            avahi_string_list_serialize(b->data.txt.string_list, mb, bsize);
 
             r = lexicographical_memcmp(ma, asize, mb, bsize);
             g_free(ma);
index d66388acc78e1681dd72ee12320f8f92cdc1e760..e80b0c4da97dd9c025db67c7f41ba7fa572261ea 100644 (file)
@@ -102,26 +102,19 @@ static void cleanup_dead(AvahiServer *s) {
     }
 }
 
-static void post_response(AvahiServer *s, AvahiInterface *i, AvahiEntry *e, gboolean unicast_response);
-
 static void add_aux_records(AvahiServer *s, AvahiInterface *i, const gchar *name, guint16 type, gboolean unicast_response) {
     AvahiKey *k;
-    AvahiEntry *e;
-    
+
     g_assert(s);
     g_assert(i);
     g_assert(name);
 
     k = avahi_key_new(name, AVAHI_DNS_CLASS_IN, type);
-    
-    for (e = g_hash_table_lookup(s->entries_by_key, k); e; e = e->by_key_next)
-        if (!e->dead && avahi_entry_registered(s, e, i))
-            post_response(s, i, e, unicast_response);
-
+    avahi_server_prepare_matching_responses(s, i, k, unicast_response);
     avahi_key_unref(k);
 }
 
-static void post_response(AvahiServer *s, AvahiInterface *i, AvahiEntry *e, gboolean unicast_response) {
+void avahi_server_prepare_response(AvahiServer *s, AvahiInterface *i, AvahiEntry *e, gboolean unicast_response) {
     g_assert(s);
     g_assert(i);
     g_assert(e);
@@ -140,7 +133,8 @@ static void post_response(AvahiServer *s, AvahiInterface *i, AvahiEntry *e, gboo
         }
     }
 }
-static void handle_query_key(AvahiServer *s, AvahiInterface *i, AvahiKey *k, gboolean unicast_response) {
+
+void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, AvahiKey *k, gboolean unicast_response) {
     AvahiEntry *e;
     gchar *txt;
     
@@ -148,18 +142,16 @@ static void handle_query_key(AvahiServer *s, AvahiInterface *i, AvahiKey *k, gbo
     g_assert(i);
     g_assert(k);
 
-    g_message("Handling query: %s", txt = avahi_key_to_string(k));
+    g_message("Posting responses matching [%s]", txt = avahi_key_to_string(k));
     g_free(txt);
 
-    avahi_packet_scheduler_incoming_query(i->scheduler, k);
-
-    if (k->type == AVAHI_DNS_TYPE_ANY) {
+    if (avahi_key_is_pattern(k)) {
 
         /* Handle ANY query */
         
         for (e = s->entries; e; e = e->entries_next)
             if (!e->dead && avahi_key_pattern_match(k, e->record->key) && avahi_entry_registered(s, e, i))
-                post_response(s, i, e, unicast_response);
+                avahi_server_prepare_response(s, i, e, unicast_response);
 
     } else {
 
@@ -167,14 +159,13 @@ static void handle_query_key(AvahiServer *s, AvahiInterface *i, AvahiKey *k, gbo
         
         for (e = g_hash_table_lookup(s->entries_by_key, k); e; e = e->by_key_next)
             if (!e->dead && avahi_entry_registered(s, e, i))
-                post_response(s, i, e, unicast_response);
+                avahi_server_prepare_response(s, i, e, unicast_response);
     }
 }
 
 static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
     g_assert(s);
     g_assert(e);
-
     
     if (e->group) {
         AvahiEntry *k;
@@ -193,33 +184,50 @@ static void withdraw_entry(AvahiServer *s, AvahiEntry *e) {
     s->need_entry_cleanup = TRUE;
 }
 
+static void withdraw_rrset(AvahiServer *s, AvahiKey *key) {
+    AvahiEntry *e;
+    
+    g_assert(s);
+    g_assert(key);
+
+   for (e = g_hash_table_lookup(s->entries_by_key, key); e; e = e->by_key_next)
+        withdraw_entry(s, e);
+}
+
 static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *i) {
     AvahiEntry *e, *n;
     gchar *t;
+    gboolean ours = FALSE, won = FALSE, lost = FALSE;
     
     g_assert(s);
     g_assert(record);
     g_assert(i);
 
-    t = avahi_record_to_string(record);
-
-/*     g_message("PROBE: [%s]", t); */
-    
     for (e = g_hash_table_lookup(s->entries_by_key, record->key); e; e = n) {
+        gint cmp;
         n = e->by_key_next;
 
-        if (e->dead || avahi_record_equal_no_ttl(record, e->record))
+        if (e->dead || !avahi_entry_probing(s, e, i))
             continue;
+        
+        if ((cmp = avahi_record_lexicographical_compare(e->record, record)) == 0) {
+            ours = TRUE;
+            break;
+        } else if (cmp > 0)
+            won = TRUE;
+        else /* cmp < 0 */
+            lost = TRUE;
+    }
 
-        if (avahi_entry_registering(s, e, i)) {
-            gint cmp;
+    t = avahi_record_to_string(record);
 
-            if ((cmp = avahi_record_lexicographical_compare(record, e->record)) > 0) {
-                withdraw_entry(s, e);
-                g_message("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t);
-            } else if (cmp < 0)
-                g_message("Recieved conflicting probe [%s]. Local host won.", t);
+    if (!ours) {
 
+        if (won)
+            g_message("Recieved conflicting probe [%s]. Local host won.", t);
+        else if (lost) {
+            g_message("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t);
+            withdraw_rrset(s, record->key);
         }
     }
 
@@ -227,8 +235,8 @@ static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface *
 }
 
 static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, gboolean unique, const AvahiAddress *a) {
-    gboolean valid = TRUE;
-    AvahiEntry *e, *n;
+    gboolean valid = TRUE, ours = FALSE, conflict = FALSE, withdraw_immediately = FALSE;
+    AvahiEntry *e, *n, *conflicting_entry = NULL;
     gchar *t;
     
     g_assert(s);
@@ -237,68 +245,78 @@ static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *
 
     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 (e->dead)
+        if (e->dead || (!(e->flags & AVAHI_ENTRY_UNIQUE) && !unique))
             continue;
+
+        /* Either our entry or the other is intended to be unique, so let's check */
         
         if (avahi_entry_registered(s, e, i)) {
 
-            gboolean equal = avahi_record_equal_no_ttl(record, e->record);
+            if (avahi_record_equal_no_ttl(e->record, record)) {
+                ours = TRUE; /* We have an identical record, so this is no conflict */
                 
-            /* Check whether there is a unique record conflict */
-            if (!equal && ((e->flags & AVAHI_ENTRY_UNIQUE) || unique)) {
-                gint cmp;
-                
-                /* The lexicographically later data wins. */
-                if ((cmp = avahi_record_lexicographical_compare(record, e->record)) > 0) {
-                    g_message("Recieved conflicting record [%s]. Local host lost. Withdrawing.", t);
-                    withdraw_entry(s, e);
-                } else if (cmp < 0) {
-                    /* Tell the other host that our entry is lexicographically later */
-
-                    g_message("Recieved conflicting record [%s]. Local host won. Refreshing.", t);
-
+                /* Check wheter there is a TTL conflict */
+                if (record->ttl <= e->record->ttl/2) {
+                    /* Refresh */
+                    g_message("Recieved record with bad TTL [%s]. Refreshing.", t);
+                    avahi_interface_post_response(i, e->record, FALSE, TRUE, NULL);
                     valid = FALSE;
-                    avahi_interface_post_response(i, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
                 }
                 
-                /* Check wheter there is a TTL conflict */
-            } else if (equal && record->ttl <= e->record->ttl/2) {
-                /* Correct the TTL */
-                valid = FALSE;
-                avahi_interface_post_response(i, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
-                g_message("Recieved record with bad TTL [%s]. Refreshing.", t);
+                /* There's no need to check the other entries of this RRset */
+                break;
+            } else {
+                /* A conflict => we have to return to probe mode */
+                conflict = TRUE;
+                conflicting_entry = e;
             }
-            
-        } else if (avahi_entry_registering(s, e, i)) {
 
-            if (!avahi_record_equal_no_ttl(record, e->record) && ((e->flags & AVAHI_ENTRY_UNIQUE) || unique)) {
+        } else if (avahi_entry_probing(s, e, i)) {
 
+            if (!avahi_record_equal_no_ttl(record, e->record)) {
+            
                 /* We are currently registering a matching record, but
                  * someone else already claimed it, so let's
                  * withdraw */
-                
-                g_message("Recieved conflicting record [%s] with local record to be. Withdrawing.", t);
-                withdraw_entry(s, e);
+                conflict = TRUE;
+                withdraw_immediately = TRUE;
             }
         }
     }
 
+/*     g_message("ours=%i conflict=%i", ours, conflict); */
+
+    if (!ours && conflict) {
+        valid = FALSE;
+
+        if (withdraw_immediately) {
+            g_message("Recieved conflicting record [%s] with local record to be. Withdrawing.", t);
+            withdraw_rrset(s, record->key);
+        } else {
+            g_assert(conflicting_entry);
+            g_message("Recieved conflicting record [%s]. Resetting our record.", t);
+            avahi_entry_return_to_initial_state(s, conflicting_entry, i);
+
+            /* Local unique records are returned to probin
+             * state. Local shared records are reannounced. */
+        }
+    }
+
     g_free(t);
 
     return valid;
 }
 
-static void generate_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) {
+void avahi_server_generate_response(AvahiServer *s, AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) {
 
     g_assert(s);
-    g_assert(p);
     g_assert(i);
-    g_assert(a);
+    g_assert(!legacy_unicast || (a && port > 0 && p));
 
     if (legacy_unicast) {
         AvahiDnsPacket *reply;
@@ -331,7 +349,7 @@ static void generate_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface
         
         while ((r = avahi_record_list_pop(s->record_list, &flush_cache, &unicast_response))) {
 
-            if (!avahi_interface_post_response(i, r, flush_cache, FALSE) && unicast_response) {
+            if (!avahi_interface_post_response(i, r, flush_cache, FALSE, a) && unicast_response) {
             
                 /* Due to some reasons the record has not been scheduled.
                  * The client requested an unicast response in that
@@ -339,8 +357,10 @@ static void generate_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface
 
                 for (;;) {
                 
-                    if (!reply)
+                    if (!reply) {
+                        g_assert(p);
                         reply = avahi_dns_packet_new_reply(p, i->hardware->mtu, FALSE, FALSE);
+                    }
                 
                     if (avahi_dns_packet_append_record(reply, r, flush_cache, 0)) {
 
@@ -385,6 +405,8 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c
     g_assert(i);
     g_assert(a);
 
+/*     g_message("query"); */
+
     g_assert(avahi_record_list_empty(s->record_list));
     
     /* Handle the questions */
@@ -394,13 +416,18 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c
 
         if (!(key = avahi_dns_packet_consume_key(p, &unicast_response))) {
             g_warning("Packet too short (1)");
-            goto fail;
-        }
+            avahi_record_list_flush(s->record_list);
+            return;
+       }
 
-        handle_query_key(s, i, key, unicast_response);
+        avahi_packet_scheduler_incoming_query(i->scheduler, key);
+        avahi_server_prepare_matching_responses(s, i, key, unicast_response);
         avahi_key_unref(key);
     }
 
+    if (!avahi_record_list_empty(s->record_list))
+        avahi_server_generate_response(s, i, p, a, port, legacy_unicast);
+    
     /* Known Answer Suppression */
     for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT); n > 0; n --) {
         AvahiRecord *record;
@@ -408,11 +435,11 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c
 
         if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
             g_warning("Packet too short (2)");
-            goto fail;
+            return;
         }
 
         if (handle_conflict(s, i, record, unique, a))
-            avahi_record_list_drop(s->record_list, record);
+            avahi_packet_scheduler_incoming_known_answer(i->scheduler, record, a);
         
         avahi_record_unref(record);
     }
@@ -424,7 +451,7 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c
 
         if (!(record = avahi_dns_packet_consume_record(p, &unique))) {
             g_warning("Packet too short (3)");
-            goto fail;
+            return;
         }
 
         if (record->key->type != AVAHI_DNS_TYPE_ANY)
@@ -432,14 +459,6 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c
         
         avahi_record_unref(record);
     }
-
-    if (!avahi_record_list_empty(s->record_list))
-        generate_response(s, p, i, a, port, legacy_unicast);
-    
-    return;
-    
-fail:
-    avahi_record_list_flush(s->record_list);
 }
 
 static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a) {
@@ -449,6 +468,8 @@ static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i
     g_assert(p);
     g_assert(i);
     g_assert(a);
+
+/*     g_message("response"); */
     
     for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) +
              avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT); n > 0; n--) {
@@ -468,7 +489,7 @@ static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i
             
             if (handle_conflict(s, i, record, cache_flush, a)) {
                 avahi_cache_update(i->cache, record, cache_flush, a);
-                avahi_packet_scheduler_incoming_response(i->scheduler, record);
+                avahi_packet_scheduler_incoming_response(i->scheduler, record, cache_flush);
             }
         }
             
@@ -486,7 +507,8 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr *
     g_assert(sa);
     g_assert(iface > 0);
 
-    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, sa->sa_family))) {
+    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, sa->sa_family)) ||
+        !avahi_interface_relevant(i)) {
         g_warning("Recieved packet from invalid interface.");
         return;
     }
@@ -516,8 +538,7 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr *
     if (avahi_dns_packet_is_query(p)) {
         gboolean legacy_unicast = FALSE;
 
-        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT) == 0 ||
-            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT) != 0) {
+        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT) != 0) {
             g_warning("Invalid query packet.");
             return;
         }
@@ -623,9 +644,11 @@ static void add_default_entries(AvahiServer *s) {
     AvahiRecord *r;
     
     g_assert(s);
+
+    return ;
     
     /* Fill in HINFO rr */
-    r = avahi_record_new_full(s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_HINFO);
+    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));
@@ -634,14 +657,13 @@ static void add_default_entries(AvahiServer *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_UNIQUE|AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "localhost", &a);
+    avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "localhost", &a);
 
     avahi_address_parse("::1", AF_INET6, &a);
-    avahi_server_add_address(s, NULL, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE|AVAHI_ENTRY_NOPROBE|AVAHI_ENTRY_NOANNOUNCE, "ip6-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) {
-    gchar *hn;
     AvahiServer *s;
     
     static GSourceFuncs source_funcs = {
@@ -659,7 +681,7 @@ AvahiServer *avahi_server_new(GMainContext *c) {
     s->need_entry_cleanup = s->need_group_cleanup = FALSE;
     
     s->fd_ipv4 = avahi_open_socket_ipv4();
-    s->fd_ipv6 = avahi_open_socket_ipv6();
+    s->fd_ipv6 = -1 /* avahi_open_socket_ipv6() */ ;
     
     if (s->fd_ipv6 < 0 && s->fd_ipv4 < 0) {
         g_critical("Failed to create IP sockets.\n");
@@ -685,11 +707,12 @@ AvahiServer *avahi_server_new(GMainContext *c) {
     s->subscription_hashtable = g_hash_table_new((GHashFunc) avahi_key_hash, (GEqualFunc) avahi_key_equal);
 
     /* Get host name */
-    hn = avahi_get_host_name();
-    hn[strcspn(hn, ".")] = 0;
+    s->host_name = avahi_get_host_name();
+    s->host_name[strcspn(s->host_name, ".")] = 0;
 
-    s->hostname = g_strdup_printf("%s.local.", hn);
-    g_free(hn);
+    s->domain = avahi_normalize_name("local.");
+
+    s->host_name_fqdn = g_strdup_printf("%s.%s", s->host_name, s->domain);
 
     s->record_list = avahi_record_list_new();
 
@@ -743,7 +766,9 @@ void avahi_server_free(AvahiServer* s) {
     if (s->fd_ipv6 >= 0)
         close(s->fd_ipv6);
 
-    g_free(s->hostname);
+    g_free(s->host_name);
+    g_free(s->domain);
+    g_free(s->host_name_fqdn);
 
     g_source_destroy(s->source);
     g_source_unref(s->source);
@@ -841,7 +866,7 @@ void avahi_server_add_ptr(
 
     g_assert(dest);
 
-    r = avahi_record_new_full(name ? name : s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR);
+    r = avahi_record_new_full(name ? name : s->host_name_fqdn, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR);
     r->data.ptr.name = avahi_normalize_name(dest);
     avahi_server_add(s, g, interface, protocol, flags, r);
     avahi_record_unref(r);
@@ -860,7 +885,7 @@ void avahi_server_add_address(
     g_assert(s);
     g_assert(a);
 
-    name = name ? (n = avahi_normalize_name(name)) : s->hostname;
+    name = name ? (n = avahi_normalize_name(name)) : s->host_name_fqdn;
     
     if (a->family == AF_INET) {
         gchar *reverse;
@@ -868,12 +893,11 @@ void avahi_server_add_address(
 
         r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A);
         r->data.a.address = a->data.ipv4;
-        avahi_server_add(s, g, interface, protocol, flags, r);
+        avahi_server_add(s, g, interface, protocol, flags | AVAHI_ENTRY_UNIQUE, r);
         avahi_record_unref(r);
         
         reverse = avahi_reverse_lookup_name_ipv4(&a->data.ipv4);
-        g_assert(reverse);
-        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
+        avahi_server_add_ptr(s, g, interface, protocol, flags | AVAHI_ENTRY_UNIQUE, reverse, name);
         g_free(reverse);
         
     } else {
@@ -882,17 +906,15 @@ void avahi_server_add_address(
             
         r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA);
         r->data.aaaa.address = a->data.ipv6;
-        avahi_server_add(s, g, interface, protocol, flags, r);
+        avahi_server_add(s, g, interface, protocol, flags | AVAHI_ENTRY_UNIQUE, r);
         avahi_record_unref(r);
 
         reverse = avahi_reverse_lookup_name_ipv6_arpa(&a->data.ipv6);
-        g_assert(reverse);
-        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
+        avahi_server_add_ptr(s, g, interface, protocol, flags | AVAHI_ENTRY_UNIQUE, reverse, name);
         g_free(reverse);
     
         reverse = avahi_reverse_lookup_name_ipv6_int(&a->data.ipv6);
-        g_assert(reverse);
-        avahi_server_add_ptr(s, g, interface, protocol, flags, reverse, name);
+        avahi_server_add_ptr(s, g, interface, protocol, flags | AVAHI_ENTRY_UNIQUE, reverse, name);
         g_free(reverse);
     }
     
@@ -912,7 +934,7 @@ void avahi_server_add_text_strlst(
     
     g_assert(s);
     
-    r = avahi_record_new_full(name ? name : s->hostname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT);
+    r = avahi_record_new_full(name ? name : s->host_name_fqdn, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT);
     r->data.txt.string_list = strlst;
     avahi_server_add(s, g, interface, protocol, flags, r);
     avahi_record_unref(r);
@@ -1000,7 +1022,7 @@ void avahi_server_add_service_strlst(
         domain = "local";
 
     if (!host)
-        host = s->hostname;
+        host = s->host_name_fqdn;
 
     snprintf(ptr_name, sizeof(ptr_name), "%s.%s", type, domain);
     snprintf(svc_name, sizeof(svc_name), "%s.%s.%s", ename, type, domain);
@@ -1080,36 +1102,12 @@ void avahi_server_post_query(AvahiServer *s, gint interface, guchar protocol, Av
     avahi_interface_monitor_walk(s->monitor, interface, protocol, post_query_callback, key);
 }
 
-struct tmpdata {
-    AvahiRecord *record;
-    gboolean flush_cache;
-};
-
-static void post_response_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) {
-    struct tmpdata *tmpdata = userdata;
-
-    g_assert(m);
-    g_assert(i);
-    g_assert(tmpdata);
-
-    avahi_interface_post_response(i, tmpdata->record, tmpdata->flush_cache, FALSE);
-}
-
-void avahi_server_post_response(AvahiServer *s, gint interface, guchar protocol, AvahiRecord *record, gboolean flush_cache) {
-    struct tmpdata tmpdata;
-    
-    g_assert(s);
-    g_assert(record);
-
-    tmpdata.record = record;
-    tmpdata.flush_cache = flush_cache;
-
-    avahi_interface_monitor_walk(s->monitor, interface, protocol, post_response_callback, &tmpdata);
-}
-
 void avahi_entry_group_change_state(AvahiEntryGroup *g, AvahiEntryGroupState state) {
     g_assert(g);
 
+    if (g->state == state)
+        return;
+    
     g->state = state;
     
     if (g->callback) {
@@ -1171,3 +1169,15 @@ AvahiEntryGroupState avahi_entry_group_get_state(AvahiEntryGroup *g) {
 
     return g->state;
 }
+
+const gchar* avahi_server_get_domain(AvahiServer *s) {
+    g_assert(s);
+
+    return s->domain;
+}
+
+const gchar* avahi_server_get_host_name(AvahiServer *s) {
+    g_assert(s);
+
+    return s->host_name_fqdn;
+}
index df7857e56a5c530befa104eec4f41303ca326589..420c50158c115fbedf64f250f121adc44f740be8 100644 (file)
@@ -80,7 +80,7 @@ struct AvahiServer {
     
     AvahiTimeEventQueue *time_event_queue;
     
-    gchar *hostname;
+    gchar *host_name, *host_name_fqdn, *domain;
 
     gint fd_ipv4, fd_ipv6;
 
@@ -95,7 +95,10 @@ struct AvahiServer {
 gboolean avahi_server_entry_match_interface(AvahiEntry *e, AvahiInterface *i);
 
 void avahi_server_post_query(AvahiServer *s, gint interface, guchar protocol, AvahiKey *key);
-void avahi_server_post_response(AvahiServer *s, gint interface, guchar protocol, AvahiRecord *record, gboolean flush_cache);
+
+void avahi_server_prepare_response(AvahiServer *s, AvahiInterface *i, AvahiEntry *e, gboolean unicast_response);
+void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, AvahiKey *k, gboolean unicast_response);
+void avahi_server_generate_response(AvahiServer *s, AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port, gboolean legacy_unicast);
 
 void avahi_entry_group_change_state(AvahiEntryGroup *g, AvahiEntryGroupState state);
 
index 086c041a79ca9490b52590ac1b49310297a39ec5..9b84d12134d104f3d1730dcfd6bb3db7bb1631bc 100644 (file)
@@ -29,6 +29,8 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
 
 #include "util.h"
 
@@ -401,3 +403,55 @@ gint avahi_domain_hash(const gchar *s) {
         g_free(n);
     }
 }
+
+
+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);
+}
index 6dcecfd6bcf73c6eee3ff3d0bf45512da7a5802d..59a0be6573c0d7a074755549f48f766a515b2e92 100644 (file)
@@ -52,4 +52,8 @@ gchar *avahi_escape_label(const guint8* src, guint src_length, gchar **ret_name,
 
 gint avahi_domain_hash(const gchar *s);
 
+gchar *avahi_alternative_host_name(const gchar *s);
+gchar *avahi_alternative_service_name(const gchar *s);
+
+
 #endif
diff --git a/todo b/todo
index d3d2f0c11014139cde4d2b48c6830ff5869fd6e5..108c20aac947129b25bbb7b8b9aaeea0a209fda3 100644 (file)
--- a/todo
+++ b/todo
@@ -2,10 +2,10 @@ todo:
 * Add some APIs to get the clean service name from RR for browsing
 
 RFC MUSTs:
-       * Return to probing state on conflict
-       * fix flush bit when working on RRsets
        * one RR too large for single packet
 
+* response job dependencies
+
 * test against apple test suite
 
 * release!
@@ -36,5 +36,8 @@ done:
 * support known answer suppresion for incoming unicast queries
 * check wether RRsets are supported correctly (i.e. that all records of an
   RRset are really sent if it is requested) (rfc 2181)
-* case insensitve comparision
-
+* case insensitve comparison
+* drop records from cache only one second after flush cache bit entry was received
+* either send entire RRSET or don't set flush cache bit!
+* mantain flush cache bit correctly in psched
+* Return to probing state on conflict