diff options
Diffstat (limited to 'avahi-core/server.c')
-rw-r--r-- | avahi-core/server.c | 95 |
1 files changed, 91 insertions, 4 deletions
diff --git a/avahi-core/server.c b/avahi-core/server.c index 033622d..3f37e1f 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -102,7 +102,83 @@ static void cleanup_dead(AvahiServer *s) { } } -static void handle_query_key(AvahiServer *s, AvahiKey *k, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) { +static void send_unicast_response_packet(AvahiServer *s, AvahiInterface *i, const AvahiAddress *a, guint16 port) { + g_assert(s); + g_assert(a); + g_assert(port > 0); + g_assert(s->unicast_packet); + + 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); + + avahi_dns_packet_free(s->unicast_packet); + s->unicast_packet = NULL; +} + +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) { + 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; + } + + /* Appending the record didn't succeeed, so let's send this packet, and create a new one */ + + send_unicast_response_packet(s, i, a, port); + + avahi_dns_packet_free(s->unicast_packet); + s->unicast_packet = NULL; + } + + } + } +} + +static void handle_query_key(AvahiServer *s, AvahiDnsPacket *p, AvahiKey *k, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast, gboolean unicast_response) { AvahiEntry *e; gchar *txt; @@ -122,14 +198,15 @@ static void handle_query_key(AvahiServer *s, AvahiKey *k, AvahiInterface *i, con 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)) - avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE); + post_response(s, p, i, a, port, e->record, e->flags & AVAHI_ENTRY_UNIQUE, legacy_unicast, unicast_response); + } else { /* Handle all other queries */ 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)) - avahi_interface_post_response(i, a, e->record, e->flags & AVAHI_ENTRY_UNIQUE, FALSE); + post_response(s, p, i, a, port, e->record, e->flags & AVAHI_ENTRY_UNIQUE, legacy_unicast, unicast_response); } } @@ -196,6 +273,8 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c g_assert(i); g_assert(a); + g_assert(!s->unicast_packet); + /* Handle the questions */ for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n --) { AvahiKey *key; @@ -206,7 +285,7 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c return; } - handle_query_key(s, key, i, a, port, legacy_unicast, unicast_response); + handle_query_key(s, p, key, i, a, port, legacy_unicast, unicast_response); avahi_key_unref(key); } @@ -239,6 +318,9 @@ 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); } static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord *record, gboolean unique, const AvahiAddress *a) { @@ -557,6 +639,8 @@ AvahiServer *avahi_server_new(GMainContext *c) { s->hostname = g_strdup_printf("%s.local.", hn); g_free(hn); + s->unicast_packet = NULL; + 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); avahi_interface_monitor_sync(s->monitor); @@ -611,6 +695,9 @@ void avahi_server_free(AvahiServer* s) { 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); } |