diff options
| author | Lennart Poettering <lennart@poettering.net> | 2005-05-10 20:11:18 +0000 | 
|---|---|---|
| committer | Lennart Poettering <lennart@poettering.net> | 2005-05-10 20:11:18 +0000 | 
| commit | 602a2b6481587b7da2594db39151ec9380f276df (patch) | |
| tree | cf41933a1abc3dd0a79e1d18146ceaf9ec99f5b7 | |
| parent | c650dc3616bd6cd55c5ebbe84cf80d7e042aac45 (diff) | |
* abstract MTU stuff for packet generation
* unicast response support
* legacy unicast support
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@66 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe
| -rw-r--r-- | avahi-core/Makefile.am | 5 | ||||
| -rw-r--r-- | avahi-core/dns-test.c | 2 | ||||
| -rw-r--r-- | avahi-core/dns.c | 62 | ||||
| -rw-r--r-- | avahi-core/dns.h | 11 | ||||
| -rw-r--r-- | avahi-core/iface.c | 49 | ||||
| -rw-r--r-- | avahi-core/iface.h | 7 | ||||
| -rw-r--r-- | avahi-core/psched.c | 29 | ||||
| -rw-r--r-- | avahi-core/psched.h | 6 | ||||
| -rw-r--r-- | avahi-core/server.c | 95 | ||||
| -rw-r--r-- | avahi-core/server.h | 3 | ||||
| -rw-r--r-- | avahi-core/socket.c | 49 | ||||
| -rw-r--r-- | avahi-core/socket.h | 4 | ||||
| -rw-r--r-- | todo | 5 | 
13 files changed, 259 insertions, 68 deletions
| diff --git a/avahi-core/Makefile.am b/avahi-core/Makefile.am index 31268e8..512b7e3 100644 --- a/avahi-core/Makefile.am +++ b/avahi-core/Makefile.am @@ -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 diff --git a/avahi-core/dns-test.c b/avahi-core/dns-test.c index e0680c2..aa36f2a 100644 --- a/avahi-core/dns-test.c +++ b/avahi-core/dns-test.c @@ -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.");  diff --git a/avahi-core/dns.c b/avahi-core/dns.c index cc1463a..3435a0d 100644 --- a/avahi-core/dns.c +++ b/avahi-core/dns.c @@ -32,12 +32,18 @@  #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; diff --git a/avahi-core/dns.h b/avahi-core/dns.h index 7936bae..c7d858f 100644 --- a/avahi-core/dns.h +++ b/avahi-core/dns.h @@ -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) |  \ diff --git a/avahi-core/iface.c b/avahi-core/iface.c index 13ffcef..9ac4493 100644 --- a/avahi-core/iface.c +++ b/avahi-core/iface.c @@ -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) { diff --git a/avahi-core/iface.h b/avahi-core/iface.h index bedf331..431dae3 100644 --- a/avahi-core/iface.h +++ b/avahi-core/iface.h @@ -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); diff --git a/avahi-core/psched.c b/avahi-core/psched.c index 249e279..5af4a07 100644 --- a/avahi-core/psched.c +++ b/avahi-core/psched.c @@ -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;  } diff --git a/avahi-core/psched.h b/avahi-core/psched.h index fe621ca..b31b45e 100644 --- a/avahi-core/psched.h +++ b/avahi-core/psched.h @@ -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); 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);  } diff --git a/avahi-core/server.h b/avahi-core/server.h index 6767884..226672f 100644 --- a/avahi-core/server.h +++ b/avahi-core/server.h @@ -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); diff --git a/avahi-core/socket.c b/avahi-core/socket.c index e59c78a..86e2a6f 100644 --- a/avahi-core/socket.c +++ b/avahi-core/socket.c @@ -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); diff --git a/avahi-core/socket.h b/avahi-core/socket.h index 4f6c5a3..fe41254 100644 --- a/avahi-core/socket.h +++ b/avahi-core/socket.h @@ -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); @@ -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 | 
