]> git.meshlink.io Git - catta/commitdiff
* abstract MTU stuff for packet generation
authorLennart Poettering <lennart@poettering.net>
Tue, 10 May 2005 20:11:18 +0000 (20:11 +0000)
committerLennart Poettering <lennart@poettering.net>
Tue, 10 May 2005 20:11:18 +0000 (20:11 +0000)
* unicast response support
* legacy unicast support

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

13 files changed:
avahi-core/Makefile.am
avahi-core/dns-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/server.c
avahi-core/server.h
avahi-core/socket.c
avahi-core/socket.h
todo

index 31268e8b96b6479dd0ed30551d54d62c3402e5d4..512b7e3bf4f234f432d63c68243f17d1be62b180 100644 (file)
@@ -86,3 +86,8 @@ avahi_test_CFLAGS = $(AM_CFLAGS)
 avahi_test_LDADD = $(AM_LDADD) libavahi-core.la
 
 
+valgrind: avahi-test
+       libtool --mode=execute valgrind ./avahi-test
+
+gdb: avahi-test
+       libtool --mode=execute gdb ./avahi-test
index e0680c2ba3d85ffb9ac9422a729f938b3f37f6ac..aa36f2ac50836dc5d55084e1efa5d1299eef08c0 100644 (file)
@@ -30,7 +30,7 @@ int main(int argc, char *argv[]) {
     gchar t[256], *a, *b, *c, *d;
     AvahiDnsPacket *p;
 
-    p = avahi_dns_packet_new(8000);
+    p = avahi_dns_packet_new(0);
 
     avahi_dns_packet_append_name(p, a = "hello.hello.hello.de.");
     avahi_dns_packet_append_name(p, b = "this is a test.hello.de."); 
index cc1463a729b15ea66702bedd2e1134ccfeb4ba9e..3435a0dc632191cd3d092d3af4ab10af4368b279 100644 (file)
 #include "dns.h"
 #include "util.h"
 
-AvahiDnsPacket* avahi_dns_packet_new(guint max_size) {
+AvahiDnsPacket* avahi_dns_packet_new(guint mtu) {
     AvahiDnsPacket *p;
+    guint max_size;
 
-    if (max_size <= 0)
+    if (mtu <= 0)
         max_size = AVAHI_DNS_PACKET_MAX_SIZE;
-    else if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
+    else if (mtu >= 48)
+        max_size = mtu - 48;
+    else
+        max_size = 0;
+
+    if (max_size < AVAHI_DNS_PACKET_HEADER_SIZE)
         max_size = AVAHI_DNS_PACKET_HEADER_SIZE;
     
     p = g_malloc(sizeof(AvahiDnsPacket) + max_size);
@@ -49,22 +55,60 @@ AvahiDnsPacket* avahi_dns_packet_new(guint max_size) {
     return p;
 }
 
-AvahiDnsPacket* avahi_dns_packet_new_query(guint max_size) {
+AvahiDnsPacket* avahi_dns_packet_new_query(guint mtu) {
     AvahiDnsPacket *p;
 
-    p = avahi_dns_packet_new(max_size);
+    p = avahi_dns_packet_new(mtu);
     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
     return p;
 }
 
-AvahiDnsPacket* avahi_dns_packet_new_response(guint max_size) {
+AvahiDnsPacket* avahi_dns_packet_new_response(guint mtu) {
     AvahiDnsPacket *p;
 
-    p = avahi_dns_packet_new(max_size);
+    p = avahi_dns_packet_new(mtu);
     avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_FLAGS, AVAHI_DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
     return p;
 }
 
+AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, guint mtu, gboolean copy_queries, gboolean aa) {
+    AvahiDnsPacket *r;
+    g_assert(p);
+
+    r = avahi_dns_packet_new_response(mtu);
+
+    if (copy_queries) {
+        guint n, saved_rindex;
+
+        saved_rindex = p->rindex;
+        p->rindex = AVAHI_DNS_PACKET_HEADER_SIZE;
+        
+        for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT); n > 0; n--) {
+            AvahiKey *k;
+            gboolean unicast_response;
+
+            if ((k = avahi_dns_packet_consume_key(p, &unicast_response))) {
+                avahi_dns_packet_append_key(r, k, unicast_response);
+                avahi_key_unref(k);
+            }
+        }
+
+        p->rindex = saved_rindex;
+
+        avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_QDCOUNT, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT));
+    }
+
+    avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_ID, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID));
+
+    avahi_dns_packet_set_field(r, AVAHI_DNS_FIELD_FLAGS,
+                               (avahi_dns_packet_get_field(r, AVAHI_DNS_FIELD_FLAGS) & ~AVAHI_DNS_FLAG_OPCODE) |
+                               (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_FLAGS) & AVAHI_DNS_FLAG_OPCODE) |
+                               (aa ? AVAHI_DNS_FLAG_AA : 0));
+
+    return r;
+} 
+
+
 void avahi_dns_packet_free(AvahiDnsPacket *p) {
     g_assert(p);
 
@@ -654,7 +698,7 @@ guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean uni
     return t;
 }
 
-guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush) {
+guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush, guint max_ttl) {
     guint8 *t, *l, *start;
     guint size;
 
@@ -666,7 +710,7 @@ guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboole
     if (!(t = avahi_dns_packet_append_name(p, r->key->name)) ||
         !avahi_dns_packet_append_uint16(p, r->key->type) ||
         !avahi_dns_packet_append_uint16(p, cache_flush ? (r->key->class | AVAHI_DNS_CACHE_FLUSH) : (r->key->class &~ AVAHI_DNS_CACHE_FLUSH)) ||
-        !avahi_dns_packet_append_uint32(p, r->ttl) ||
+        !avahi_dns_packet_append_uint32(p, (max_ttl && r->ttl > max_ttl) ? max_ttl : r->ttl) ||
         !(l = avahi_dns_packet_append_uint16(p, 0)))
         goto fail;
 
index 7936baedb03a593b205562f03bbb5872be8190af..c7d858f35788a3d246463b7b96097ea56e2880dc 100644 (file)
@@ -37,9 +37,11 @@ typedef struct AvahiDnsPacket {
 
 #define AVAHI_DNS_PACKET_DATA(p) (((guint8*) p) + sizeof(AvahiDnsPacket))
 
-AvahiDnsPacket* avahi_dns_packet_new(guint size);
-AvahiDnsPacket* avahi_dns_packet_new_query(guint size);
-AvahiDnsPacket* avahi_dns_packet_new_response(guint size);
+AvahiDnsPacket* avahi_dns_packet_new(guint mtu);
+AvahiDnsPacket* avahi_dns_packet_new_query(guint mtu);
+AvahiDnsPacket* avahi_dns_packet_new_response(guint mtu);
+
+AvahiDnsPacket* avahi_dns_packet_new_reply(AvahiDnsPacket* p, guint mtu, gboolean copy_queries, gboolean aa);
 
 void avahi_dns_packet_free(AvahiDnsPacket *p);
 void avahi_dns_packet_set_field(AvahiDnsPacket *p, guint index, guint16 v);
@@ -52,7 +54,7 @@ guint8 *avahi_dns_packet_append_uint32(AvahiDnsPacket *p, guint32 v);
 guint8 *avahi_dns_packet_append_name(AvahiDnsPacket *p, const gchar *name);
 guint8 *avahi_dns_packet_append_bytes(AvahiDnsPacket  *p, gconstpointer, guint l);
 guint8* avahi_dns_packet_append_key(AvahiDnsPacket *p, AvahiKey *k, gboolean unicast_response);
-guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush);
+guint8* avahi_dns_packet_append_record(AvahiDnsPacket *p, AvahiRecord *r, gboolean cache_flush, guint max_ttl);
 guint8* avahi_dns_packet_append_string(AvahiDnsPacket *p, const gchar *s);
 
 gint avahi_dns_packet_is_query(AvahiDnsPacket *p);
@@ -84,6 +86,7 @@ guint avahi_dns_packet_space(AvahiDnsPacket *p);
 #define AVAHI_DNS_FLAG_OPCODE (15 << 11)
 #define AVAHI_DNS_FLAG_RCODE (15)
 #define AVAHI_DNS_FLAG_TC (1 << 9)
+#define AVAHI_DNS_FLAG_AA (1 << 10)
 
 #define AVAHI_DNS_FLAGS(qr, opcode, aa, tc, rd, ra, z, ad, cd, rcode) \
         (((guint16) !!qr << 15) |  \
index 13ffcef973d284c399a6cc59e63dca9b4111a3ec..9ac4493052e725d07e1ba485f113f2fe4197c720 100644 (file)
@@ -472,43 +472,62 @@ AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor
 }
 
 
-void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
+void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port) {
     g_assert(i);
     g_assert(p);
+    char t[64];
 
-    if (avahi_interface_relevant(i)) {
-        g_message("sending on '%s.%i'", i->hardware->name, i->protocol);
+    if (!avahi_interface_relevant(i))
+        return;
+    
+    g_assert(!a || a->family == i->protocol);
 
-        if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
-            avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p);
-        else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0)
-            avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p);
-    }
+    if (a)
+        g_message("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port);
+    else
+        g_message("multicast sending on '%s.%i'", i->hardware->name, i->protocol);
+    
+    if (i->protocol == AF_INET && i->monitor->server->fd_ipv4 >= 0)
+        avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port);
+    else if (i->protocol == AF_INET6 && i->monitor->server->fd_ipv6 >= 0)
+        avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, a ? &a->data.ipv6 : NULL, port);
+}
+
+void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) {
+    g_assert(i);
+    g_assert(p);
+
+    avahi_interface_send_packet_unicast(i, p, NULL, 0);
 }
 
-void avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean immediately) {
+gboolean avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, gboolean immediately) {
     g_assert(i);
     g_assert(key);
 
     if (avahi_interface_relevant(i))
-        avahi_packet_scheduler_post_query(i->scheduler, key, immediately);
-}
+        return avahi_packet_scheduler_post_query(i->scheduler, key, immediately);
 
+    return FALSE;
+}
 
-void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
+gboolean avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
     g_assert(i);
     g_assert(record);
 
     if (avahi_interface_relevant(i))
-        avahi_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately);
+        return avahi_packet_scheduler_post_response(i->scheduler, a, record, flush_cache, immediately);
+
+    return FALSE;
 }
 
-void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, gboolean immediately) {
+gboolean avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, gboolean immediately) {
     g_assert(i);
     g_assert(record);
     
     if (avahi_interface_relevant(i))
-        avahi_packet_scheduler_post_probe(i->scheduler, record, immediately);
+        return avahi_packet_scheduler_post_probe(i->scheduler, record, immediately);
+
+    return FALSE;
 }
 
 void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f) {
index bedf33189bd8c4d7dec91c2b861aee31de4107fc..431dae333ff97c90c1f6cda7f166743744d81318 100644 (file)
@@ -104,10 +104,11 @@ AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m,
 AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, gint index);
 
 void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p);
+void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, guint16 port);
 
-void avahi_interface_post_query(AvahiInterface *i, AvahiKey *k, gboolean immediately);
-void avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *p, gboolean immediately);
-void avahi_interface_post_response(AvahiInterface *i, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
+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);
 
 void avahi_dump_caches(AvahiInterfaceMonitor *m, FILE *f);
 
index 249e279f30795173bb4e25daaa5c88d6b562a8e1..5af4a07361a17f02655a94420e5b56d8905213f8 100644 (file)
@@ -163,7 +163,7 @@ static void append_known_answers_and_send(AvahiPacketScheduler *s, AvahiDnsPacke
     
     while ((ka = s->known_answers)) {
 
-        while (!avahi_dns_packet_append_record(p, ka->record, FALSE)) {
+        while (!avahi_dns_packet_append_record(p, ka->record, FALSE, 0)) {
 
             g_assert(!avahi_dns_packet_is_empty(p));
 
@@ -172,7 +172,7 @@ static void append_known_answers_and_send(AvahiPacketScheduler *s, AvahiDnsPacke
             avahi_interface_send_packet(s->interface, p);
             avahi_dns_packet_free(p);
 
-            p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+            p = avahi_dns_packet_new_query(s->interface->hardware->mtu);
             n = 0;
         }
 
@@ -206,7 +206,7 @@ static void query_elapse(AvahiTimeEvent *e, gpointer data) {
 
     g_assert(!s->known_answers);
     
-    p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+    p = avahi_dns_packet_new_query(s->interface->hardware->mtu);
     d = packet_add_query_job(s, p, qj);
     g_assert(d);
     n = 1;
@@ -246,7 +246,7 @@ AvahiQueryJob* query_job_new(AvahiPacketScheduler *s, AvahiKey *key) {
     return qj;
 }
 
-void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) {
+gboolean avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately) {
     GTimeVal tv;
     AvahiQueryJob *qj;
     
@@ -264,7 +264,7 @@ void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, g
             /* Duplicate questions suppression */
             if (d >= 0 && d <= AVAHI_QUERY_HISTORY_MSEC*1000) {
                 g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
-                return;
+                return FALSE;
             }
             
             query_job_free(s, qj);
@@ -276,6 +276,7 @@ void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, g
     qj = query_job_new(s, key);
     qj->delivery = tv;
     qj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &qj->delivery, query_elapse, qj);
+    return TRUE;
 }
 
 static guint8* packet_add_response_job(AvahiPacketScheduler *s, AvahiDnsPacket *p, AvahiResponseJob *rj) {
@@ -285,7 +286,7 @@ static guint8* packet_add_response_job(AvahiPacketScheduler *s, AvahiDnsPacket *
     g_assert(p);
     g_assert(rj);
 
-    if ((d = avahi_dns_packet_append_record(p, rj->record, rj->flush_cache))) {
+    if ((d = avahi_dns_packet_append_record(p, rj->record, rj->flush_cache, 0))) {
         GTimeVal tv;
 
         rj->done = 1;
@@ -306,7 +307,7 @@ static void send_response_packet(AvahiPacketScheduler *s, AvahiResponseJob *rj)
 
     g_assert(s);
 
-    p = avahi_dns_packet_new_response(s->interface->hardware->mtu - 200);
+    p = avahi_dns_packet_new_response(s->interface->hardware->mtu);
     n = 0;
 
     /* If a job was specified, put it in the packet. */
@@ -382,7 +383,7 @@ static AvahiResponseJob* response_job_new(AvahiPacketScheduler *s, AvahiRecord *
     return rj;
 }
 
-void 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, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately) {
     AvahiResponseJob *rj;
     GTimeVal tv;
     
@@ -415,7 +416,7 @@ void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAd
 
             rj->flush_cache = flush_cache;
             
-            return;
+            return FALSE;
         }
 
         /* Either one was a goodbye packet, but the other was not, so
@@ -438,6 +439,8 @@ void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAd
 
     if ((rj->address_valid = !!a))
         rj->address = *a;
+
+    return TRUE;
 }
 
 void avahi_packet_scheduler_incoming_query(AvahiPacketScheduler *s, AvahiKey *key) {
@@ -663,7 +666,7 @@ static void probe_elapse(AvahiTimeEvent *e, gpointer data) {
     g_assert(pj);
     s = pj->scheduler;
 
-    p = avahi_dns_packet_new_query(s->interface->hardware->mtu - 48);
+    p = avahi_dns_packet_new_query(s->interface->hardware->mtu);
 
     /* Add the import probe */
     if (!packet_add_probe_query(s, p, pj)) {
@@ -698,7 +701,7 @@ static void probe_elapse(AvahiTimeEvent *e, gpointer data) {
         if (!pj->chosen)
             continue;
 
-        if (!avahi_dns_packet_append_record(p, pj->record, TRUE)) {
+        if (!avahi_dns_packet_append_record(p, pj->record, TRUE, 0)) {
             g_warning("Bad probe size estimate!");
 
             /* Unmark all following jobs */
@@ -720,7 +723,7 @@ static void probe_elapse(AvahiTimeEvent *e, gpointer data) {
     avahi_dns_packet_free(p);
 }
 
-void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately) {
+gboolean avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately) {
     AvahiProbeJob *pj;
     GTimeVal tv;
     
@@ -734,4 +737,6 @@ void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *rec
     pj = probe_job_new(s, record);
     pj->delivery = tv;
     pj->time_event = avahi_time_event_queue_add(s->server->time_event_queue, &pj->delivery, probe_elapse, pj);
+
+    return TRUE;
 }
index fe621ca0227188ae759b69b10bdfdd05fca6e7eb..b31b45e9e5a2a9edf95a9a504e536dcc54948588 100644 (file)
@@ -86,9 +86,9 @@ struct AvahiPacketScheduler {
 AvahiPacketScheduler *avahi_packet_scheduler_new(AvahiServer *server, AvahiInterface *i);
 void avahi_packet_scheduler_free(AvahiPacketScheduler *s);
 
-void avahi_packet_scheduler_post_query(AvahiPacketScheduler *s, AvahiKey *key, gboolean immediately);
-void avahi_packet_scheduler_post_response(AvahiPacketScheduler *s, const AvahiAddress *a, AvahiRecord *record, gboolean flush_cache, gboolean immediately);
-void avahi_packet_scheduler_post_probe(AvahiPacketScheduler *s, AvahiRecord *record, gboolean immediately);
+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_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);
index 033622d3cdc771237e2be39ca077a3d90d837c7f..3f37e1f3d764b680fcee527119fcfea1a6c1f8f0 100644 (file)
@@ -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);
 }
 
index 676788489fc4d6f309609f1129db01c3e0fe9aec..226672f79f7ef16988150a3702b310fb2848f5d0 100644 (file)
@@ -29,6 +29,7 @@
 #include "timeeventq.h"
 #include "announce.h"
 #include "subscribe.h"
+#include "dns.h"
 
 struct AvahiEntry {
     AvahiServer *server;
@@ -86,6 +87,8 @@ struct AvahiServer {
     GSource *source;
 
     gboolean ignore_bad_ttl;
+
+    AvahiDnsPacket *unicast_packet;
 };
 
 gboolean avahi_server_entry_match_interface(AvahiEntry *e, AvahiInterface *i);
index e59c78a6fd4167ef17ff5319a5d323ccfe461161..86e2a6fc6df4b56b2c2ada280bec5b91c01f3505 100644 (file)
@@ -61,8 +61,29 @@ static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
     inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
 }
 
-int avahi_mdns_mcast_join_ipv4 (int index, int fd)
-{
+static void ipv4_address_to_sockaddr(struct sockaddr_in *ret_sa, const AvahiIPv4Address *a, guint16 port) {
+    g_assert(ret_sa);
+    g_assert(a);
+    g_assert(port > 0);
+
+    memset(ret_sa, 0, sizeof(struct sockaddr_in));
+    ret_sa->sin_family = AF_INET;
+    ret_sa->sin_port = htons(port);
+    memcpy(&ret_sa->sin_addr, a, sizeof(AvahiIPv4Address));
+}
+
+static void ipv6_address_to_sockaddr(struct sockaddr_in6 *ret_sa, const AvahiIPv6Address *a, guint16 port) {
+    g_assert(ret_sa);
+    g_assert(a);
+    g_assert(port > 0);
+
+    memset(ret_sa, 0, sizeof(struct sockaddr_in6));
+    ret_sa->sin6_family = AF_INET6;
+    ret_sa->sin6_port = htons(port);
+    memcpy(&ret_sa->sin6_addr, a, sizeof(AvahiIPv6Address));
+}
+
+int avahi_mdns_mcast_join_ipv4 (int index, int fd) {
     struct ip_mreqn mreq; 
     struct sockaddr_in sa;
 
@@ -80,8 +101,7 @@ int avahi_mdns_mcast_join_ipv4 (int index, int fd)
     return 0;
 }
 
-int avahi_mdns_mcast_join_ipv6 (int index, int fd)
-{
+int avahi_mdns_mcast_join_ipv6 (int index, int fd) {
     struct ipv6_mreq mreq6; 
     struct sockaddr_in6 sa6;
 
@@ -99,8 +119,7 @@ int avahi_mdns_mcast_join_ipv6 (int index, int fd)
     return 0;
 }
 
-int avahi_mdns_mcast_leave_ipv4 (int index, int fd)
-{
+int avahi_mdns_mcast_leave_ipv4 (int index, int fd) {
     struct ip_mreqn mreq; 
     struct sockaddr_in sa;
     
@@ -118,8 +137,7 @@ int avahi_mdns_mcast_leave_ipv4 (int index, int fd)
     return 0;
 }
 
-int avahi_mdns_mcast_leave_ipv6 (int index, int fd)
-{
+int avahi_mdns_mcast_leave_ipv6 (int index, int fd) {
     struct ipv6_mreq mreq6; 
     struct sockaddr_in6 sa6;
 
@@ -313,7 +331,7 @@ static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
     return 0;
 }
 
-gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p) {
+gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p, const AvahiIPv4Address *a, guint16 port) {
     struct sockaddr_in sa;
     struct msghdr msg;
     struct iovec io;
@@ -324,8 +342,12 @@ gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p) {
     g_assert(fd >= 0);
     g_assert(p);
     g_assert(avahi_dns_packet_check_valid(p) >= 0);
+    g_assert(!a || port > 0);
 
-    mdns_mcast_group_ipv4(&sa);
+    if (!a)
+        mdns_mcast_group_ipv4(&sa);
+    else
+        ipv4_address_to_sockaddr(&sa, a, port);
 
     memset(&io, 0, sizeof(io));
     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
@@ -352,7 +374,7 @@ gint avahi_send_dns_packet_ipv4(gint fd, gint interface, AvahiDnsPacket *p) {
     return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
 }
 
-gint avahi_send_dns_packet_ipv6(gint fd, gint interface, AvahiDnsPacket *p) {
+gint avahi_send_dns_packet_ipv6(gint fd, gint interface, AvahiDnsPacket *p, const AvahiIPv6Address *a, guint16 port) {
     struct sockaddr_in6 sa;
     struct msghdr msg;
     struct iovec io;
@@ -364,7 +386,10 @@ gint avahi_send_dns_packet_ipv6(gint fd, gint interface, AvahiDnsPacket *p) {
     g_assert(p);
     g_assert(avahi_dns_packet_check_valid(p) >= 0);
 
-    mdns_mcast_group_ipv6(&sa);
+    if (!a)
+        mdns_mcast_group_ipv6(&sa);
+    else
+        ipv6_address_to_sockaddr(&sa, a, port);
 
     memset(&io, 0, sizeof(io));
     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
index 4f6c5a3b0a153e2014b450ea2d339081e9bc4012..fe41254705b45ecd661f1286932220c710fe0ec2 100644 (file)
@@ -31,8 +31,8 @@
 gint avahi_open_socket_ipv4(void);
 gint avahi_open_socket_ipv6(void);
 
-gint avahi_send_dns_packet_ipv4(gint fd, gint iface, AvahiDnsPacket *p);
-gint avahi_send_dns_packet_ipv6(gint fd, gint iface, AvahiDnsPacket *p);
+gint avahi_send_dns_packet_ipv4(gint fd, gint iface, AvahiDnsPacket *p, const AvahiIPv4Address *a, guint16 port);
+gint avahi_send_dns_packet_ipv6(gint fd, gint iface, AvahiDnsPacket *p, const AvahiIPv6Address *a, guint16 port);
 
 AvahiDnsPacket *avahi_recv_dns_packet_ipv4(gint fd, struct sockaddr_in*ret_sa, gint *ret_iface, guint8 *ret_ttl);
 AvahiDnsPacket *avahi_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6*ret_sa, gint *ret_iface, guint8 *ret_ttl);
diff --git a/todo b/todo
index 80192111662acbe59cdba40e24a0d55d3202ebc7..b0a9fef84978989023602d7fde126d756a43853a 100644 (file)
--- a/todo
+++ b/todo
@@ -1,7 +1,4 @@
 todo:
-* Unicast responses/queries
-* Legacy unicast
-
 * add SRV and TXT records referenced from PTR records automatically to packet
 * add A and AAAA records referenced from SRV records automatically to packet
 
@@ -25,3 +22,5 @@ done:
 * allow NULL bytes in TXT records
 * add flx_server_add_service_strlst() and friends
 * change flx_* to avahi_*
+* Unicast responses/queries
+* Legacy unicast