From af1ce5fe2245fba0045d2c0d70b58b700938bd2f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 May 2005 23:01:38 +0000 Subject: [PATCH] * add auxiliary records to packet * 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 --- avahi-core/Makefile.am | 4 +- avahi-core/announce.c | 4 +- avahi-core/avahi-test.c | 12 +- avahi-core/dns.c | 8 ++ avahi-core/dns.h | 1 + avahi-core/iface.c | 4 +- avahi-core/iface.h | 2 +- avahi-core/psched.c | 43 +------- avahi-core/psched.h | 5 +- avahi-core/rrlist.c | 117 ++++++++++++++++++++ avahi-core/rrlist.h | 40 +++++++ avahi-core/server.c | 231 +++++++++++++++++++++++---------------- avahi-core/server.h | 3 +- avahi-core/strlst-test.c | 2 + 14 files changed, 320 insertions(+), 156 deletions(-) create mode 100644 avahi-core/rrlist.c create mode 100644 avahi-core/rrlist.h diff --git a/avahi-core/Makefile.am b/avahi-core/Makefile.am index 512b7e3..e6708b6 100644 --- a/avahi-core/Makefile.am +++ b/avahi-core/Makefile.am @@ -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 diff --git a/avahi-core/announce.c b/avahi-core/announce.c index dbad6c7..5ee0f48 100644 --- a/avahi-core/announce.c +++ b/avahi-core/announce.c @@ -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); } diff --git a/avahi-core/avahi-test.c b/avahi-core/avahi-test.c index 474f141..ba9d7cd 100644 --- a/avahi-core/avahi-test.c +++ b/avahi-core/avahi-test.c @@ -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; diff --git a/avahi-core/dns.c b/avahi-core/dns.c index 7a99192..531e3cf 100644 --- a/avahi-core/dns.c +++ b/avahi-core/dns.c @@ -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; diff --git a/avahi-core/dns.h b/avahi-core/dns.h index 373b9a6..f1ecfe0 100644 --- a/avahi-core/dns.h +++ b/avahi-core/dns.h @@ -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); diff --git a/avahi-core/iface.c b/avahi-core/iface.c index 9ac4493..23507f2 100644 --- a/avahi-core/iface.c +++ b/avahi-core/iface.c @@ -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; } diff --git a/avahi-core/iface.h b/avahi-core/iface.h index 431dae3..00aea9a 100644 --- a/avahi-core/iface.h +++ b/avahi-core/iface.h @@ -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); diff --git a/avahi-core/psched.c b/avahi-core/psched.c index a1ab1bf..60bf40c 100644 --- a/avahi-core/psched.c +++ b/avahi-core/psched.c @@ -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; diff --git a/avahi-core/psched.h b/avahi-core/psched.h index b31b45e..12ea880 100644 --- a/avahi-core/psched.h +++ b/avahi-core/psched.h @@ -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 index 0000000..429f142 --- /dev/null +++ b/avahi-core/rrlist.c @@ -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 index 0000000..0578417 --- /dev/null +++ b/avahi-core/rrlist.h @@ -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 diff --git a/avahi-core/server.c b/avahi-core/server.c index e9289da..d66388a 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -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) { diff --git a/avahi-core/server.h b/avahi-core/server.h index 226672f..df7857e 100644 --- a/avahi-core/server.h +++ b/avahi-core/server.h @@ -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); diff --git a/avahi-core/strlst-test.c b/avahi-core/strlst-test.c index ebbf194..afc13b1 100644 --- a/avahi-core/strlst-test.c +++ b/avahi-core/strlst-test.c @@ -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"); -- 2.39.2