]> git.meshlink.io Git - catta/commitdiff
* add auxiliary records to packet
authorLennart Poettering <lennart@poettering.net>
Wed, 11 May 2005 23:01:38 +0000 (23:01 +0000)
committerLennart Poettering <lennart@poettering.net>
Wed, 11 May 2005 23:01:38 +0000 (23:01 +0000)
* reeimplement known answer suppression and add it for unicast packets
* fix a valist bug when adding services to a server

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

14 files changed:
avahi-core/Makefile.am
avahi-core/announce.c
avahi-core/avahi-test.c
avahi-core/dns.c
avahi-core/dns.h
avahi-core/iface.c
avahi-core/iface.h
avahi-core/psched.c
avahi-core/psched.h
avahi-core/rrlist.c [new file with mode: 0644]
avahi-core/rrlist.h [new file with mode: 0644]
avahi-core/server.c
avahi-core/server.h
avahi-core/strlst-test.c

index 512b7e3bf4f234f432d63c68243f17d1be62b180..e6708b6c99ddbfd24a4963d79a6ac91427a521be 100644 (file)
@@ -51,7 +51,8 @@ libavahi_core_la_SOURCES = \
        psched.c psched.h \
        announce.c announce.h \
        subscribe.c subscribe.h \
-       strlst.c strlst.h
+       strlst.c strlst.h \
+       rrlist.c rrlist.h
 
 prioq_test_SOURCES = \
        prioq-test.c  \
@@ -85,7 +86,6 @@ avahi_test_SOURCES = \
 avahi_test_CFLAGS = $(AM_CFLAGS)
 avahi_test_LDADD = $(AM_LDADD) libavahi-core.la
 
-
 valgrind: avahi-test
        libtool --mode=execute valgrind ./avahi-test
 
index dbad6c71f52174f2ef73d566c2bd349758a9105b..5ee0f48f2e7240d58e857b061617588a8b33b7dc 100644 (file)
@@ -152,7 +152,7 @@ static void next_state(AvahiAnnouncement *a) {
 
     } else if (a->state == AVAHI_ANNOUNCING) {
 
-        avahi_interface_post_response(a->interface, NULL, a->entry->record, a->entry->flags & AVAHI_ENTRY_UNIQUE, FALSE);
+        avahi_interface_post_response(a->interface, a->entry->record, a->entry->flags & AVAHI_ENTRY_UNIQUE, FALSE);
 
         if (++a->n_iteration >= 4) {
             gchar *t;
@@ -364,7 +364,7 @@ static void send_goodbye_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, g
         return;
     
     g = make_goodbye_record(e->record);
-    avahi_interface_post_response(i, NULL, g, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
+    avahi_interface_post_response(i, g, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
     avahi_record_unref(g);
 }
     
index 474f14101307d7d2de3f7bb62ef41162cc1609ef..ba9d7cdd00501b5352de58dc1c43707641c6b314 100644 (file)
@@ -69,12 +69,12 @@ 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, NULL, "hallo", NULL); */
-/*      avahi_server_add_service(avahi, g, 0, AF_UNSPEC, "_http._tcp", "gurke", NULL, NULL, 80, "foo", NULL);  */
+    avahi_server_add_text(avahi, g, 0, AF_UNSPEC, AVAHI_ENTRY_UNIQUE, NULL, "hallo", 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);
     
@@ -86,13 +86,13 @@ int main(int argc, char *argv[]) {
     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*30, quit_timeout, loop);  */
     
     g_main_loop_run(loop);
     g_main_loop_unref(loop);
 
 /*     avahi_subscription_free(s); */
-    /* avahi_entry_group_free(g);  */
+    avahi_entry_group_free(g);  
     avahi_server_free(avahi);
     
     return 0;
index 7a99192b0e56b667e697e87f7c8a9cd1c537106c..531e3cfea5a907507904d606a1036d4b75603fb7 100644 (file)
@@ -131,6 +131,14 @@ guint16 avahi_dns_packet_get_field(AvahiDnsPacket *p, guint index) {
     return g_ntohs(((guint16*) AVAHI_DNS_PACKET_DATA(p))[index]);
 }
 
+void avahi_dns_packet_inc_field(AvahiDnsPacket *p, guint index) {
+    g_assert(p);
+
+    avahi_dns_packet_set_field(p, index, avahi_dns_packet_get_field(p, index) + 1);
+}   
+
+
+
 /* Read the first label from string *name, unescape "\" and write it to dest */
 gchar *avahi_unescape_label(gchar *dest, guint size, const gchar **name) {
     guint i = 0;
index 373b9a6723b249fab801801ceec302ed5d0211ca..f1ecfe00ecfdfcb1f066278506907b8bdbd5fdd1 100644 (file)
@@ -46,6 +46,7 @@ AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, guint mtu, gboolea
 void avahi_dns_packet_free(AvahiDnsPacket *p);
 void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v);
 guint16 avahi_dns_packet_get_field(AvahiDnsPacket *p, guint index);
+void avahi_dns_packet_inc_field(AvahiDnsPacket *p, guint index);
 
 guint8 *avahi_dns_packet_extend(AvahiDnsPacket *p, guint l);
 
index 9ac4493052e725d07e1ba485f113f2fe4197c720..23507f222379b2d5094a86c86cb4ca46e11dca6b 100644 (file)
@@ -510,12 +510,12 @@ gboolean avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean i
     return FALSE;
 }
 
-gboolean avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+gboolean avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
     g_assert(i);
     g_assert(record);
 
     if (avahi_interface_relevant(i))
-        return avahi_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately);
+        return avahi_packet_scheduler_post_response(i->scheduler, record, flush_cache, immediately);
 
     return FALSE;
 }
index 431dae333ff97c90c1f6cda7f166743744d81318..00aea9aa9f4906342106432bd4130e4d0d45d76f 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, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+gboolean avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
 
 void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f);
 
index a1ab1bf9aba61521f197aad9f50951d59afd74c8..60bf40c88a57f7d9df5bc24018c296d575d6b5ed 100644 (file)
@@ -375,7 +375,6 @@ static AvahiResponseJob* response_job_new(AvahiPacketScheduler *s, AvahiRecord *
     rj->record = avahi_record_ref(record);
     rj->done = FALSE;
     rj->time_event = NULL;
-    rj->address_valid = FALSE;
     rj->flush_cache = FALSE;
     
     AVAHI_LLIST_PREPEND(AvahiResponseJob, jobs, s->response_jobs, rj);
@@ -383,7 +382,7 @@ static AvahiResponseJob* response_job_new(AvahiPacketScheduler *s, AvahiRecord *
     return rj;
 }
 
-gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
     AvahiResponseJob *rj;
     GTimeVal tv;
     
@@ -407,13 +406,6 @@ gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const Ava
             d >= 0 && d <= AVAHI_RESPONSE_HISTORY_MSEC*1000) {
             g_message("WARNING! DUPLICATE RESPONSE SUPPRESSION ACTIVE!");
 
-            /* This job is no longer specific to a single querier, so
-             * make sure it isn't suppressed by known answer
-             * suppresion */
-
-            if (rj->address_valid && (!a || avahi_address_cmp(a, &rj->address) != 0))
-                rj->address_valid = FALSE;
-
             rj->flush_cache = flush_cache;
             
             return FALSE;
@@ -433,13 +425,6 @@ gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const Ava
     rj->delivery = tv;
     rj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &rj->delivery, response_elapse, rj);
 
-    /* Store the address of the host this messages is intended to, so
-       that we can drop this job in case a truncated message with
-       known answer suppresion entries is recieved */
-
-    if ((rj->address_valid = !!a))
-        rj->address = *a;
-
     return TRUE;
 }
 
@@ -489,7 +474,6 @@ void response_job_set_elapse_time(AvahiPacketScheduler *s, AvahiResponseJob *rj,
         avahi_time_event_queue_update(s->server->time_event_queue, rj->time_event, &tv);
     else
         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) {
@@ -553,31 +537,6 @@ mark_done:
     g_get_current_time(&rj->delivery);
 }
 
-void avahi_packet_scheduler_incoming_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *a) {
-    AvahiResponseJob *rj;
-    
-    g_assert(s);
-    g_assert(record);
-    g_assert(a);
-
-    for (rj = s->response_jobs; rj; rj = rj->jobs_next) {
-
-        g_assert(record->ttl > 0);
-        g_assert(rj->record->ttl/2);
-        
-        if (avahi_record_equal_no_ttl(rj->record, record))
-            if (rj->address_valid)
-                if (avahi_address_cmp(&rj->address, a))
-                    if (record->ttl >= rj->record->ttl/2) {
-
-            /* Let's suppress it */
-
-            response_job_free(s, rj);
-            break;
-        }
-    }
-}
-
 void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s) {
     AvahiResponseJob *rj;
     
index b31b45e9e5a2a9edf95a9a504e536dcc54948588..12ea8800ff33b1cea2be165710952430402b78d0 100644 (file)
@@ -46,8 +46,6 @@ struct AvahiResponseJob {
     AvahiPacketScheduler *scheduler;
     AvahiTimeEvent *time_event;
     AvahiRecord *record;
-    AvahiAddress address;
-    gboolean address_valid;
     gboolean done;
     GTimeVal delivery;
     gboolean flush_cache;
@@ -87,12 +85,11 @@ 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, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+gboolean avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
 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_known_answer(AvahiPacketScheduler *s, AvahiRecord *record, const AvahiAddress *a);
 
 void avahi_packet_scheduler_flush_responses(AvahiPacketScheduler *s);
 
diff --git a/avahi-core/rrlist.c b/avahi-core/rrlist.c
new file mode 100644 (file)
index 0000000..429f142
--- /dev/null
@@ -0,0 +1,117 @@
+/* $Id$ */
+
+/***
+  This file is part of avahi.
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+  avahi is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include "rrlist.h"
+#include "llist.h"
+
+typedef struct AvahiRecordListItem AvahiRecordListItem;
+
+struct AvahiRecordListItem {
+    AvahiRecord *record;
+    gboolean unicast_response;
+    gboolean flush_cache;
+    AVAHI_LLIST_FIELDS(AvahiRecordListItem, items);
+};
+
+
+struct AvahiRecordList {
+    AVAHI_LLIST_HEAD(AvahiRecordListItem, items);
+};
+
+AvahiRecordList *avahi_record_list_new(void) {
+    AvahiRecordList *l = g_new(AvahiRecordList, 1);
+    AVAHI_LLIST_HEAD_INIT(AvahiRecordListItem, l->items);
+    return l;
+}
+
+void avahi_record_list_free(AvahiRecordList *l) {
+    g_assert(l);
+
+    avahi_record_list_flush(l);
+    g_free(l);
+}
+
+static void item_free(AvahiRecordList *l, AvahiRecordListItem *i) {
+    g_assert(i);
+
+    AVAHI_LLIST_REMOVE(AvahiRecordListItem, items, l->items, i);
+    avahi_record_unref(i->record);
+    g_free(i);
+}
+
+void avahi_record_list_flush(AvahiRecordList *l) {
+    g_assert(l);
+    
+    while (l->items)
+        item_free(l, l->items);
+}
+
+AvahiRecord* avahi_record_list_pop(AvahiRecordList *l, gboolean *flush_cache, gboolean *unicast_response) {
+    AvahiRecord *r;
+
+    if (!l->items)
+        return NULL;
+    
+    r = avahi_record_ref(l->items->record);
+    if (unicast_response) *unicast_response = l->items->unicast_response;
+    if (flush_cache) *flush_cache = l->items->flush_cache;
+
+    item_free(l, l->items);
+    
+    return r;
+}
+
+void avahi_record_list_push(AvahiRecordList *l, AvahiRecord *r, gboolean flush_cache, gboolean unicast_response) {
+    AvahiRecordListItem *i;
+        
+    g_assert(l);
+    g_assert(r);
+    
+    for (i = l->items; i; i = i->items_next)
+        if (avahi_record_equal_no_ttl(i->record, r))
+            return;
+
+    i = g_new(AvahiRecordListItem, 1);
+    i->unicast_response = unicast_response;
+    i->flush_cache = flush_cache;
+    i->record = avahi_record_ref(r);
+    AVAHI_LLIST_PREPEND(AvahiRecordListItem, items, l->items, i);
+}
+
+void avahi_record_list_drop(AvahiRecordList *l, AvahiRecord *r) {
+    AvahiRecordListItem *i;
+
+    g_assert(l);
+    g_assert(r);
+
+    for (i = l->items; i; i = i->items_next)
+        if (avahi_record_equal_no_ttl(i->record, r)) {
+            item_free(l, i);
+            break;
+        }
+}
+
+
+gboolean avahi_record_list_empty(AvahiRecordList *l) {
+    g_assert(l);
+    
+    return !l->items;
+}
diff --git a/avahi-core/rrlist.h b/avahi-core/rrlist.h
new file mode 100644 (file)
index 0000000..0578417
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef foorrlisthfoo
+#define foorrlisthfoo
+
+/* $Id$ */
+
+/***
+  This file is part of avahi.
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+  avahi is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+
+#include "rr.h"
+
+typedef struct AvahiRecordList AvahiRecordList;
+
+AvahiRecordList *avahi_record_list_new(void);
+void avahi_record_list_free(AvahiRecordList *l);
+void avahi_record_list_flush(AvahiRecordList *l);
+
+AvahiRecord* avahi_record_list_pop(AvahiRecordList *l, gboolean *flush_cache, gboolean *unicast_response);
+void avahi_record_list_push(AvahiRecordList *l, AvahiRecord *r, gboolean flush_cache, gboolean unicast_response);
+void avahi_record_list_drop(AvahiRecordList *l, AvahiRecord *r);
+
+gboolean avahi_record_list_empty(AvahiRecordList *l);
+
+#endif
index e9289da0388e3c6d4c4336623e922adc6584b0c4..d66388acc78e1681dd72ee12320f8f92cdc1e760 100644 (file)
@@ -102,90 +102,51 @@ static void cleanup_dead(AvahiServer *s) {
     }
 }
 
-static void send_unicast_response_packet(AvahiServer *s, AvahiInterface *i, const AvahiAddress *a, guint16 port) {
+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(a);
-    g_assert(port > 0);
-    g_assert(s->unicast_packet);
+    g_assert(i);
+    g_assert(name);
 
-    if (avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT) != 0)
-        avahi_interface_send_packet_unicast(i, s->unicast_packet, a, port);
+    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_dns_packet_free(s->unicast_packet);
-    s->unicast_packet = NULL;
+    avahi_key_unref(k);
 }
 
-static void post_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, AvahiRecord *r, gboolean flush_cache, gboolean legacy_unicast, gboolean unicast_response) {
+static void post_response(AvahiServer *s, AvahiInterface *i, AvahiEntry *e, gboolean unicast_response) {
     g_assert(s);
-    g_assert(a);
-    g_assert(port > 0);
-    g_assert(r);
-
-    if (legacy_unicast) {
-
-        /* Respond with a legacy unicast packet */
-        
-        if (!(s->unicast_packet))
-            s->unicast_packet = avahi_dns_packet_new_reply(p, 512 /* unicast DNS maximum packet size is 512 */ , TRUE, TRUE);
-
-        if (avahi_dns_packet_append_record(s->unicast_packet, r, FALSE, 10))
-
-            /* Increment the ANCOUNT field */
-            
-            avahi_dns_packet_set_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT,
-                                       avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT)+1);
-
-        /* If there's no space left for this response we simply don't send it */
-        
-    } else {
-
-        if (!avahi_interface_post_response(i, a, r, flush_cache, FALSE) && unicast_response) {
-            
-            /* Due to some reasons the record has not been scheduled.
-             * The client requested an unicast response in that
-             * case. Therefore we prepare such a response */
-
-            for (;;) {
-                
-                if (!(s->unicast_packet))
-                    s->unicast_packet = avahi_dns_packet_new_reply(p, i->hardware->mtu, FALSE, FALSE);
-                
-                if (avahi_dns_packet_append_record(s->unicast_packet, r, flush_cache, 0)) {
-
-                    /* Appending this record succeeded, so incremeant
-                     * the specific header field, and return to the caller */
-                    
-                    avahi_dns_packet_set_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT,
-                                               avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT)+1);
-
-                    break;
-                }
-
-                if (avahi_dns_packet_get_field(s->unicast_packet, AVAHI_DNS_FIELD_ANCOUNT) == 0) {
-                    g_warning("Record too large, doesn't fit in any packet!");
-                    return;
-                }
+    g_assert(i);
+    g_assert(e);
 
-                /* Appending the record didn't succeeed, so let's send this packet, and create a new one */
+    /* Append a record to a packet and all the records referred by it */
 
-                send_unicast_response_packet(s, i, a, port);
-                
-                avahi_dns_packet_free(s->unicast_packet);
-                s->unicast_packet = NULL;
-            }
-            
+    avahi_record_list_push(s->record_list, e->record, e->flags & AVAHI_ENTRY_UNIQUE, unicast_response);
+    
+    if (e->record->key->class == AVAHI_DNS_CLASS_IN) {
+        if (e->record->key->type == AVAHI_DNS_TYPE_PTR) {
+            add_aux_records(s, i, e->record->data.ptr.name, AVAHI_DNS_TYPE_SRV, unicast_response);
+            add_aux_records(s, i, e->record->data.ptr.name, AVAHI_DNS_TYPE_TXT, unicast_response);
+        } else if (e->record->key->type == AVAHI_DNS_TYPE_SRV) {
+            add_aux_records(s, i, e->record->data.srv.name, AVAHI_DNS_TYPE_A, unicast_response);
+            add_aux_records(s, i, e->record->data.srv.name, AVAHI_DNS_TYPE_AAAA, unicast_response);
         }
     }
 }
-
-static void handle_query_key(AvahiServer *s, AvahiDnsPacket *p, AvahiKey *k, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) {
+static void handle_query_key(AvahiServer *s, AvahiInterface *i, AvahiKey *k, gboolean unicast_response) {
     AvahiEntry *e;
     gchar *txt;
     
     g_assert(s);
-    g_assert(k);
     g_assert(i);
-    g_assert(a);
+    g_assert(k);
 
     g_message("Handling query: %s", txt = avahi_key_to_string(k));
     g_free(txt);
@@ -198,7 +159,7 @@ static void handle_query_key(AvahiServer *s, AvahiDnsPacket *p, AvahiKey *k, Ava
         
         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, p, i, a, port, e->record, e->flags & AVAHI_ENTRY_UNIQUE, legacy_unicast, unicast_response);
+                post_response(s, i, e, unicast_response);
 
     } else {
 
@@ -206,7 +167,7 @@ static void handle_query_key(AvahiServer *s, AvahiDnsPacket *p, AvahiKey *k, Ava
         
         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, p, i, a, port, e->record, e->flags & AVAHI_ENTRY_UNIQUE, legacy_unicast, unicast_response);
+                post_response(s, i, e, unicast_response);
     }
 }
 
@@ -302,14 +263,14 @@ static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *
                     g_message("Recieved conflicting record [%s]. Local host won. Refreshing.", t);
 
                     valid = FALSE;
-                    avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
+                    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, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
+                avahi_interface_post_response(i, e->record, e->flags & AVAHI_ENTRY_UNIQUE, TRUE);
                 g_message("Recieved record with bad TTL [%s]. Refreshing.", t);
             }
             
@@ -332,16 +293,88 @@ static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *
     return valid;
 }
 
-static void incoming_known_answer(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, gboolean legacy_unicast, gboolean unique, const AvahiAddress *a) {
+static void generate_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) {
+
     g_assert(s);
+    g_assert(p);
     g_assert(i);
-    g_assert(r);
-    
-    if (legacy_unicast)
-        return;
+    g_assert(a);
+
+    if (legacy_unicast) {
+        AvahiDnsPacket *reply;
+        AvahiRecord *r;
+
+        reply = avahi_dns_packet_new_reply(p, 512 /* unicast DNS maximum packet size is 512 */ , TRUE, TRUE);
+        
+        while ((r = avahi_record_list_pop(s->record_list, NULL, NULL))) {
+            
+            if (avahi_dns_packet_append_record(reply, r, FALSE, 10))
+                avahi_dns_packet_inc_field(reply, AVAHI_DNS_FIELD_ANCOUNT);
+            else {
+                gchar *t = avahi_record_to_string(r);
+                g_warning("Record [%s] not fitting in legacy unicast packet, dropping.", t);
+                g_free(t);
+            }
+
+            avahi_record_unref(r);
+        }
+
+        if (avahi_dns_packet_get_field(reply, AVAHI_DNS_FIELD_ANCOUNT) != 0)
+            avahi_interface_send_packet_unicast(i, reply, a, port);
+
+        avahi_dns_packet_free(reply);
+
+    } else {
+        gboolean unicast_response, flush_cache;
+        AvahiDnsPacket *reply = NULL;
+        AvahiRecord *r;
+        
+        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) {
+            
+                /* Due to some reasons the record has not been scheduled.
+                 * The client requested an unicast response in that
+                 * case. Therefore we prepare such a response */
+
+                for (;;) {
+                
+                    if (!reply)
+                        reply = avahi_dns_packet_new_reply(p, i->hardware->mtu, FALSE, FALSE);
+                
+                    if (avahi_dns_packet_append_record(reply, r, flush_cache, 0)) {
+
+                        /* Appending this record succeeded, so incremeant
+                         * the specific header field, and return to the caller */
+                        
+                        avahi_dns_packet_inc_field(reply, AVAHI_DNS_FIELD_ANCOUNT);
+
+                        break;
+                    }
+
+                    if (avahi_dns_packet_get_field(reply, AVAHI_DNS_FIELD_ANCOUNT) == 0) {
+                        gchar *t = avahi_record_to_string(r);
+                        g_warning("Record [%s] too large, doesn't fit in any packet!", t);
+                        g_free(t);
+                        break;
+                    }
+
+                    /* Appending the record didn't succeeed, so let's send this packet, and create a new one */
+                    avahi_interface_send_packet_unicast(i, reply, a, port);
+                    avahi_dns_packet_free(reply);
+                    reply = NULL;
+                }
+            }
+
+            avahi_record_unref(r);
+        }
 
-    if (handle_conflict(s, i, r, unique, a))
-        avahi_packet_scheduler_incoming_known_answer(i->scheduler, r, a);
+        if (reply) {
+            if (avahi_dns_packet_get_field(reply, AVAHI_DNS_FIELD_ANCOUNT) != 0) 
+                avahi_interface_send_packet_unicast(i, reply, a, port);
+            avahi_dns_packet_free(reply);
+        }
+    }
 }
 
 static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) {
@@ -352,8 +385,8 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c
     g_assert(i);
     g_assert(a);
 
-    g_assert(!s->unicast_packet);
-
+    g_assert(avahi_record_list_empty(s->record_list));
+    
     /* Handle the questions */
     for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n --) {
         AvahiKey *key;
@@ -361,10 +394,10 @@ 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)");
-            return;
+            goto fail;
         }
 
-        handle_query_key(s, p, key, i, a, port, legacy_unicast, unicast_response);
+        handle_query_key(s, i, key, unicast_response);
         avahi_key_unref(key);
     }
 
@@ -375,10 +408,12 @@ 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)");
-            return;
+            goto fail;
         }
 
-        incoming_known_answer(s, i, record, legacy_unicast, unique, a);
+        if (handle_conflict(s, i, record, unique, a))
+            avahi_record_list_drop(s->record_list, record);
+        
         avahi_record_unref(record);
     }
 
@@ -389,7 +424,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)");
-            return;
+            goto fail;
         }
 
         if (record->key->type != AVAHI_DNS_TYPE_ANY)
@@ -398,8 +433,13 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c
         avahi_record_unref(record);
     }
 
-    if (s->unicast_packet)
-        send_unicast_response_packet(s, i, a, port);
+    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) {
@@ -418,7 +458,7 @@ static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i
         
         if (!(record = avahi_dns_packet_consume_record(p, &cache_flush))) {
             g_warning("Packet too short (4)");
-            return;
+            break;
         }
 
         if (record->key->type != AVAHI_DNS_TYPE_ANY) {
@@ -651,7 +691,7 @@ AvahiServer *avahi_server_new(GMainContext *c) {
     s->hostname = g_strdup_printf("%s.local.", hn);
     g_free(hn);
 
-    s->unicast_packet = NULL;
+    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->monitor = avahi_interface_monitor_new(s);
@@ -696,20 +736,19 @@ void avahi_server_free(AvahiServer* s) {
 
     avahi_time_event_queue_free(s->time_event_queue);
 
+    avahi_record_list_free(s->record_list);
+    
     if (s->fd_ipv4 >= 0)
         close(s->fd_ipv4);
     if (s->fd_ipv6 >= 0)
         close(s->fd_ipv6);
-    
+
     g_free(s->hostname);
 
     g_source_destroy(s->source);
     g_source_unref(s->source);
     g_main_context_unref(s->context);
 
-    if (s->unicast_packet)
-        avahi_dns_packet_free(s->unicast_packet);
-
     g_free(s);
 }
 
@@ -998,7 +1037,7 @@ void avahi_server_add_service_va(
     g_assert(type);
     g_assert(name);
 
-    avahi_server_add_service(s, g, interface, protocol, type, name, domain, host, port, avahi_string_list_new_va(va));
+    avahi_server_add_service_strlst(s, g, interface, protocol, type, name, domain, host, port, avahi_string_list_new_va(va));
 }
 
 void avahi_server_add_service(
@@ -1053,7 +1092,7 @@ static void post_response_callback(AvahiInterfaceMonitor *m, AvahiInterface *i,
     g_assert(i);
     g_assert(tmpdata);
 
-    avahi_interface_post_response(i, NULL, tmpdata->record, tmpdata->flush_cache, FALSE);
+    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) {
index 226672f79f7ef16988150a3702b310fb2848f5d0..df7857e56a5c530befa104eec4f41303ca326589 100644 (file)
@@ -30,6 +30,7 @@
 #include "announce.h"
 #include "subscribe.h"
 #include "dns.h"
+#include "rrlist.h"
 
 struct AvahiEntry {
     AvahiServer *server;
@@ -88,7 +89,7 @@ struct AvahiServer {
 
     gboolean ignore_bad_ttl;
 
-    AvahiDnsPacket *unicast_packet;
+    AvahiRecordList *record_list; /* Used for assembling responses */
 };
 
 gboolean avahi_server_entry_match_interface(AvahiEntry *e, AvahiInterface *i);
index ebbf194bc5431ee175f252535aa0155f6891864c..afc13b18e4bd47e36f22653975fb3868bfb5a307 100644 (file)
@@ -34,6 +34,8 @@ int main(int argc, char *argv[]) {
     AvahiStringList *a = NULL, *b;
     guint size, n;
 
+    a = avahi_string_list_new("prefix", "a", "b", NULL);
+    
     a = avahi_string_list_add(a, "start");
     a = avahi_string_list_add(a, "foo");
     a = avahi_string_list_add(a, "bar");