]> git.meshlink.io Git - catta/commitdiff
add client part of known answer suppresion
authorLennart Poettering <lennart@poettering.net>
Thu, 31 Mar 2005 23:31:11 +0000 (23:31 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 31 Mar 2005 23:31:11 +0000 (23:31 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@20 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

13 files changed:
cache.c
cache.h
dns.c
dns.h
main.c
psched.c
psched.h
rr.c
rr.h
server.c
subscribe.c
subscribe.h
todo

diff --git a/cache.c b/cache.c
index 99d79fb15cd4488cd4a72d9d095c0bfd7561110f..bbf667b43c5264b66940080634a2d660a02c8372 100644 (file)
--- a/cache.c
+++ b/cache.c
@@ -1,22 +1,26 @@
 #include <string.h>
 
+#include "util.h"
 #include "cache.h"
 
-static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_hash_table) {
+static void remove_entry(flxCache *c, flxCacheEntry *e) {
+    flxCacheEntry *t;
+
     g_assert(c);
     g_assert(e);
 
-    g_message("removing from cache: %p %p", c, e);
-    
-    if (remove_from_hash_table) {
-        flxCacheEntry *t;
-        t = g_hash_table_lookup(c->hash_table, e->record->key);
-        FLX_LLIST_REMOVE(flxCacheEntry, by_name, t, e);
-        if (t)
-            g_hash_table_replace(c->hash_table, t->record->key, t);
-        else
-            g_hash_table_remove(c->hash_table, e->record->key);
-    }
+/*     g_message("removing from cache: %p %p", c, e); */
+
+    /* Remove from hash table */
+    t = g_hash_table_lookup(c->hash_table, e->record->key);
+    FLX_LLIST_REMOVE(flxCacheEntry, by_key, t, e);
+    if (t)
+        g_hash_table_replace(c->hash_table, t->record->key, t);
+    else
+        g_hash_table_remove(c->hash_table, e->record->key);
+
+    /* Remove from linked list */
+    FLX_LLIST_REMOVE(flxCacheEntry, entry, c->entries, e);
         
     if (e->time_event)
         flx_time_event_queue_remove(c->server->time_event_queue, e->time_event);
@@ -37,24 +41,17 @@ flxCache *flx_cache_new(flxServer *server, flxInterface *iface) {
     c->interface = iface;
     c->hash_table = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
 
-    return c;
-}
-
-gboolean remove_func(gpointer key, gpointer value, gpointer user_data) {
-    flxCacheEntry *e, *next;
-
-    for (e = value; e; e = next) {
-        next = e->by_name_next;
-        remove_entry(user_data, e, FALSE);
-    }
+    FLX_LLIST_HEAD_INIT(flxCacheEntry, c->entries);
     
-    return TRUE;
+    return c;
 }
 
 void flx_cache_free(flxCache *c) {
     g_assert(c);
 
-    g_hash_table_foreach_remove(c->hash_table, remove_func, c);
+    while (c->entries)
+        remove_entry(c, c->entries);
+    
     g_hash_table_destroy(c->hash_table);
     
     g_free(c);
@@ -64,19 +61,61 @@ flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k) {
     g_assert(c);
     g_assert(k);
 
+    g_assert(!flx_key_is_pattern(k));
+    
     return g_hash_table_lookup(c->hash_table, k);
 }
 
+gpointer flx_cache_walk(flxCache *c, flxKey *pattern, flxCacheWalkCallback cb, gpointer userdata) {
+    gpointer ret;
+    
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(cb);
+    
+    if (flx_key_is_pattern(pattern)) {
+        flxCacheEntry *e, *n;
+        
+        for (e = c->entries; e; e = n) {
+            n = e->entry_next;
+            
+            if (flx_key_pattern_match(pattern, e->record->key))
+                if ((ret = cb(c, pattern, e, userdata)))
+                    return ret;
+        }
+        
+    } else {
+        flxCacheEntry *e, *n;
+
+        for (e = flx_cache_lookup_key(c, pattern); e; e = n) {
+            n = e->by_key_next;
+                
+            if ((ret = cb(c, pattern, e, userdata)))
+                return ret;
+        }
+    }
+
+    return NULL;
+}
+
+static gpointer lookup_record_callback(flxCache *c, flxKey *pattern, flxCacheEntry *e, void *userdata) {
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+
+    if (flx_record_equal_no_ttl(e->record, userdata))
+        return e;
+
+    return NULL;
+}
+
 flxCacheEntry *flx_cache_lookup_record(flxCache *c, flxRecord *r) {
     flxCacheEntry *e;
+    
     g_assert(c);
     g_assert(r);
 
-    for (e = flx_cache_lookup_key(c, r->key); e; e = e->by_name_next)
-        if (flx_record_equal_no_ttl(e->record, r))
-            return e;
-
-    return NULL;
+    return flx_cache_walk(c, r->key, lookup_record_callback, r);
 }
 
 static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent);
@@ -88,7 +127,7 @@ static void elapse_func(flxTimeEvent *t, void *userdata) {
     g_assert(e);
 
     if (e->state == FLX_CACHE_FINAL) {
-        remove_entry(e->cache, e, TRUE);
+        remove_entry(e->cache, e);
         g_message("Removing entry from cache due to expiration");
     } else {
         guint percent = 0;
@@ -121,8 +160,9 @@ static void elapse_func(flxTimeEvent *t, void *userdata) {
 
         g_message("Requesting cache entry update at %i%%.", percent);
 
-        /* Request a cache update */
-        flx_interface_post_query(e->cache->interface, e->record->key, TRUE);
+        /* Request a cache update, if we are subscribed to this entry */
+        if (flx_is_subscribed(e->cache->server, e->record->key))
+            flx_interface_post_query(e->cache->interface, e->record->key, TRUE);
 
         /* Check again later */
         next_expiry(e->cache, e, percent);
@@ -189,13 +229,13 @@ void flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddre
             if (unique) {
                 
                 /* For unique records, remove all entries but one */
-                while (e->by_name_next)
-                    remove_entry(c, e->by_name_next, TRUE);
+                while (e->by_key_next)
+                    remove_entry(c, e->by_key_next);
                 
             } else {
                 
                 /* For non-unique record, look for exactly the same entry */
-                for (; e; e = e->by_name_next)
+                for (; e; e = e->by_key_next)
                     if (flx_record_equal_no_ttl(e->record, r))
                         break;
             }
@@ -206,7 +246,7 @@ void flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddre
 /*         g_message("found matching cache entry"); */
             
             /* We are the first in the linked list so let's replace the hash table key with the new one */
-            if (e->by_name_prev == NULL)
+            if (e->by_key_prev == NULL)
                 g_hash_table_replace(c->hash_table, r->key, e);
             
             /* Notify subscribers */
@@ -226,9 +266,14 @@ void flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddre
             e->cache = c;
             e->time_event = NULL;
             e->record = flx_record_ref(r);
-            FLX_LLIST_PREPEND(flxCacheEntry, by_name, t, e);
+
+            /* Append to hash table */
+            FLX_LLIST_PREPEND(flxCacheEntry, by_key, t, e);
             g_hash_table_replace(c->hash_table, e->record->key, t);
-            
+
+            /* Append to linked list */
+            FLX_LLIST_PREPEND(flxCacheEntry, entry, c->entries, e);
+
             /* Notify subscribers */
             flx_subscription_notify(c->server, c->interface, e->record, FLX_SUBSCRIPTION_NEW);
         } 
@@ -240,14 +285,20 @@ void flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddre
     }
 }
 
+static gpointer drop_key_callback(flxCache *c, flxKey *pattern, flxCacheEntry *e, gpointer userdata) {
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+
+    remove_entry(c, e);
+    return NULL;
+}
+
 void flx_cache_drop_key(flxCache *c, flxKey *k) {
-    flxCacheEntry *e;
-    
     g_assert(c);
     g_assert(k);
 
-    while ((e = flx_cache_lookup_key(c, k)))
-        remove_entry(c, e, TRUE);
+    flx_cache_walk(c, k, drop_key_callback, NULL);
 }
 
 void flx_cache_drop_record(flxCache *c, flxRecord *r) {
@@ -257,7 +308,7 @@ void flx_cache_drop_record(flxCache *c, flxRecord *r) {
     g_assert(r);
 
     if ((e = flx_cache_lookup_record(c, r))) 
-        remove_entry(c, e, TRUE);
+        remove_entry(c, e);
 }
 
 static void func(gpointer key, gpointer data, gpointer userdata) {
@@ -277,3 +328,19 @@ void flx_cache_dump(flxCache *c, FILE *f) {
     fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
     g_hash_table_foreach(c->hash_table, func, f);
 }
+
+gboolean flx_cache_entry_half_ttl(flxCache *c, flxCacheEntry *e) {
+    GTimeVal now;
+    guint age;
+    
+    g_assert(c);
+    g_assert(e);
+
+    g_get_current_time(&now);
+
+    age = flx_timeval_diff(&now, &e->timestamp)/1000000;
+
+    g_message("age: %u, ttl/2: %u", age, e->record->ttl);
+    
+    return age >= e->record->ttl/2;
+}
diff --git a/cache.h b/cache.h
index e7c8e7eab65a6e7ec4ad62d5077f06f5282205ad..3b4eef656a11129b82a25c88b8f39dab9444400e 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -32,7 +32,8 @@ struct flxCacheEntry {
     flxCacheEntryState state;
     flxTimeEvent *time_event;
 
-    FLX_LLIST_FIELDS(flxCacheEntry, by_name);
+    FLX_LLIST_FIELDS(flxCacheEntry, by_key);
+    FLX_LLIST_FIELDS(flxCacheEntry, entry);
 };
 
 struct _flxCache {
@@ -41,6 +42,8 @@ struct _flxCache {
     flxInterface *interface;
     
     GHashTable *hash_table;
+
+    FLX_LLIST_HEAD(flxCacheEntry, entries);
 };
 
 flxCache *flx_cache_new(flxServer *server, flxInterface *interface);
@@ -51,9 +54,13 @@ flxCacheEntry *flx_cache_lookup_record(flxCache *c, flxRecord *r);
 
 void flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddress *a);
 
-void flx_cache_drop_key(flxCache *c, flxKey *k);
 void flx_cache_drop_record(flxCache *c,  flxRecord *r);
 
 void flx_cache_dump(flxCache *c, FILE *f);
 
+typedef gpointer flxCacheWalkCallback(flxCache *c, flxKey *pattern, flxCacheEntry *e, gpointer userdata);
+gpointer flx_cache_walk(flxCache *c, flxKey *pattern, flxCacheWalkCallback cb, gpointer userdata);
+
+gboolean flx_cache_entry_half_ttl(flxCache *c, flxCacheEntry *e);
+
 #endif
diff --git a/dns.c b/dns.c
index 243c5a33c1703f2973664b92ac32fdba2a6fd275..bed7344d81d4fe5341d84567d63f2052eb299825 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -409,29 +409,37 @@ flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) {
 
 guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k) {
     guint8 *t;
+    guint size;
     
     g_assert(p);
     g_assert(k);
 
+    size = p->size;
+    
     if (!(t = flx_dns_packet_append_name(p, k->name)) ||
         !flx_dns_packet_append_uint16(p, k->type) ||
-        !flx_dns_packet_append_uint16(p, k->class))
+        !flx_dns_packet_append_uint16(p, k->class)) {
+        p->size = size;
         return NULL;
+    }
 
     return t;
 }
 
 guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush) {
     guint8 *t;
+    guint size;
 
     g_assert(p);
     g_assert(r);
 
+    size = p->size;
+
     if (!(t = flx_dns_packet_append_name(p, r->key->name)) ||
         !flx_dns_packet_append_uint16(p, r->key->type) ||
         !flx_dns_packet_append_uint16(p, cache_flush ? (r->key->class | MDNS_CACHE_FLUSH) : (r->key->class &~ MDNS_CACHE_FLUSH)) ||
         !flx_dns_packet_append_uint32(p, r->ttl))
-        return NULL;
+        goto fail;
 
     switch (r->key->type) {
         
@@ -445,7 +453,7 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac
             
             if (!flx_dns_packet_append_uint16(p, strlen(ptr_name)+1) ||
                 !flx_dns_packet_append_name(p, ptr_name))
-                return NULL;
+                goto fail;
 
             break;
         }
@@ -460,7 +468,7 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac
             if (!flx_dns_packet_append_uint16(p, strlen(name+6)+1+6) ||
                 !flx_dns_packet_append_bytes(p, r->data, 6) ||
                 !flx_dns_packet_append_name(p, name))
-                return NULL;
+                goto fail;
 
             break;
         }
@@ -468,8 +476,19 @@ guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cac
         default:
             if (!flx_dns_packet_append_uint16(p, r->size) ||
                 (r->size != 0 && !flx_dns_packet_append_bytes(p, r->data, r->size)))
-                return NULL;
+                goto fail;
     }
 
     return t;
+
+
+fail:
+    p->size = size;
+    return NULL;
+}
+
+gboolean flx_dns_packet_is_empty(flxDnsPacket *p) {
+    g_assert(p);
+
+    return p->size <= FLX_DNS_PACKET_HEADER_SIZE;
 }
diff --git a/dns.h b/dns.h
index 0b6e750feb0d85adf19e94a18774307bf9f98bf6..c5d2fae3562f96fe230c73e1e57a6e06dd885535 100644 (file)
--- a/dns.h
+++ b/dns.h
@@ -45,10 +45,10 @@ flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_fl
 
 gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p);
 
-
-
 gint flx_dns_packet_skip(flxDnsPacket *p, guint length);
 
+gboolean flx_dns_packet_is_empty(flxDnsPacket *p);
+
 #define DNS_FIELD_ID 0
 #define DNS_FIELD_FLAGS 1
 #define DNS_FIELD_QDCOUNT 2
@@ -59,6 +59,7 @@ gint flx_dns_packet_skip(flxDnsPacket *p, guint length);
 #define DNS_FLAG_QR (1 << 15)
 #define DNS_FLAG_OPCODE (15 << 11)
 #define DNS_FLAG_RCODE (15)
+#define DNS_FLAG_TC (1 << 9)
 
 #define DNS_FLAGS(qr, opcode, aa, tc, rd, ra, z, ad, cd, rcode) \
         (((guint16) !!qr << 15) |  \
diff --git a/main.c b/main.c
index 6f82d25f99f070019699abc543f7829c0dc879ff..d5278c741e05ec7b9e5a03dce0009f14943aa888 100644 (file)
--- a/main.c
+++ b/main.c
@@ -15,13 +15,13 @@ static gboolean send_timeout(gpointer data) {
     flxServer *flx = data;
     flxKey *k;
 
-    /*     k = flx_key_new("cocaine.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); */
-/*     flx_server_post_query(flx, 0, AF_UNSPEC, k); */
-/*     flx_key_unref(k); */
+    k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT);
+    flx_server_post_query(flx, 0, AF_UNSPEC, k);
+    flx_key_unref(k);
 
-/*     k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A); */
-/*     flx_server_post_query(flx, 0, AF_INET, k); */
-/*     flx_key_unref(k); */
+    k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A);
+    flx_server_post_query(flx, 0, AF_INET, k);
+    flx_key_unref(k);
 
     return FALSE;
 }
@@ -58,7 +58,7 @@ int main(int argc, char *argv[]) {
 
     flx_server_add_text(flx, 0, 0, AF_UNSPEC, FALSE, NULL, "hallo");
 
-/*     k = flx_key_new("_http._tcp.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR); */
+/*     k = flx_key_new("ecstasy.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_ANY); */
 /*     s = flx_subscription_new(flx, k, 0, AF_UNSPEC, subscription, NULL); */
 /*     flx_key_unref(k); */
 
index 162c1b2b098708aa4b8bc3fe92037ba55e984628..138dd50d39a533c5857273a4c137d34ef80dcb55 100644 (file)
--- a/psched.c
+++ b/psched.c
@@ -21,6 +21,7 @@ flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i)
 
     FLX_LLIST_HEAD_INIT(flxQueryJob, s->query_jobs);
     FLX_LLIST_HEAD_INIT(flxResponseJob, s->response_jobs);
+    FLX_LLIST_HEAD_INIT(flxKnownAnswer, s->known_answers);
     
     return s;
 }
@@ -53,9 +54,11 @@ void flx_packet_scheduler_free(flxPacketScheduler *s) {
     flxQueryJob *qj;
     flxResponseJob *rj;
     flxTimeEvent *e;
-    
+
     g_assert(s);
 
+    g_assert(!s->known_answers);
+    
     while ((qj = s->query_jobs))
         query_job_free(s, qj);
     while ((rj = s->response_jobs))
@@ -64,6 +67,26 @@ void flx_packet_scheduler_free(flxPacketScheduler *s) {
     g_free(s);
 }
 
+static gpointer known_answer_walk_callback(flxCache *c, flxKey *pattern, flxCacheEntry *e, gpointer userdata) {
+    flxPacketScheduler *s = userdata;
+    flxKnownAnswer *ka;
+    
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+    g_assert(s);
+
+    if (flx_cache_entry_half_ttl(c, e))
+        return NULL;
+    
+    ka = g_new0(flxKnownAnswer, 1);
+    ka->scheduler = s;
+    ka->record = flx_record_ref(e->record);
+
+    FLX_LLIST_PREPEND(flxKnownAnswer, known_answer, s->known_answers, ka);
+    return NULL;
+}
+
 static guint8* packet_add_query_job(flxPacketScheduler *s, flxDnsPacket *p, flxQueryJob *qj) {
     guint8 *d;
 
@@ -81,11 +104,49 @@ static guint8* packet_add_query_job(flxPacketScheduler *s, flxDnsPacket *p, flxQ
         flx_time_event_queue_update(s->server->time_event_queue, qj->time_event, &tv);
 
         g_get_current_time(&qj->delivery);
+
+        /* Add all matching known answers to the list */
+        flx_cache_walk(s->interface->cache, qj->key, known_answer_walk_callback, s);
     }
 
     return d;
 }
-                                 
+
+static void append_known_answers_and_send(flxPacketScheduler *s, flxDnsPacket *p) {
+    flxKnownAnswer *ka;
+    guint n;
+    g_assert(s);
+    g_assert(p);
+
+    n = 0;
+    
+    while ((ka = s->known_answers)) {
+
+        while (!flx_dns_packet_append_record(p, ka->record, FALSE)) {
+
+            g_assert(!flx_dns_packet_is_empty(p));
+
+            flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) | DNS_FLAG_TC);
+            flx_dns_packet_set_field(p, DNS_FIELD_ANCOUNT, n);
+            flx_interface_send_packet(s->interface, p);
+            flx_dns_packet_free(p);
+
+            p = flx_dns_packet_new_query(s->interface->hardware->mtu - 48);
+            n = 0;
+        }
+
+        FLX_LLIST_REMOVE(flxKnownAnswer, known_answer, s->known_answers, ka);
+        flx_record_unref(ka->record);
+        g_free(ka);
+        
+        n++;
+    }
+    
+    flx_dns_packet_set_field(p, DNS_FIELD_ANCOUNT, n);
+    flx_interface_send_packet(s->interface, p);
+    flx_dns_packet_free(p);
+}
+
 static void query_elapse(flxTimeEvent *e, gpointer data) {
     flxQueryJob *qj = data;
     flxPacketScheduler *s;
@@ -102,6 +163,8 @@ static void query_elapse(flxTimeEvent *e, gpointer data) {
         return;
     }
 
+    g_assert(!s->known_answers);
+    
     p = flx_dns_packet_new_query(s->interface->hardware->mtu - 48);
     d = packet_add_query_job(s, p, qj);
     g_assert(d);
@@ -120,21 +183,9 @@ static void query_elapse(flxTimeEvent *e, gpointer data) {
     }
 
     flx_dns_packet_set_field(p, DNS_FIELD_QDCOUNT, n);
-    flx_interface_send_packet(s->interface, p);
-    flx_dns_packet_free(p);
-}
-
-static flxQueryJob* look_for_query(flxPacketScheduler *s, flxKey *key) {
-    flxQueryJob *qj;
-    
-    g_assert(s);
-    g_assert(key);
-
-    for (qj = s->query_jobs; qj; qj = qj->jobs_next)
-        if (flx_key_equal(qj->key, key))
-            return qj;
 
-    return NULL;
+    /* Now add known answers */
+    append_known_answers_and_send(s, p);
 }
 
 flxQueryJob* query_job_new(flxPacketScheduler *s, flxKey *key) {
@@ -162,18 +213,22 @@ void flx_packet_scheduler_post_query(flxPacketScheduler *s, flxKey *key, gboolea
     g_assert(key);
 
     flx_elapse_time(&tv, immediately ? 0 : FLX_QUERY_DEFER_MSEC, 0);
-    
-    if ((qj = look_for_query(s, key))) {
-        glong d = flx_timeval_diff(&tv, &qj->delivery);
 
-        /* Duplicate questions suppression */
-        if (d >= 0 && d <= FLX_QUERY_HISTORY_MSEC*1000) {
-            g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
-            return;
-        }
+    for (qj = s->query_jobs; qj; qj = qj->jobs_next)
 
-        query_job_free(s, qj);
-    }
+        if (flx_key_equal(qj->key, key)) {
+
+            glong d = flx_timeval_diff(&tv, &qj->delivery);
+
+            /* Duplicate questions suppression */
+            if (d >= 0 && d <= FLX_QUERY_HISTORY_MSEC*1000) {
+                g_message("WARNING! DUPLICATE QUERY SUPPRESSION ACTIVE!");
+                return;
+            }
+            
+            query_job_free(s, qj);
+            break;
+        }
 
     qj = query_job_new(s, key);
     qj->delivery = tv;
@@ -290,6 +345,8 @@ void flx_packet_scheduler_post_response(flxPacketScheduler *s, flxRecord *record
     g_assert(s);
     g_assert(record);
 
+    g_assert(!flx_key_is_pattern(record->key));
+    
     flx_elapse_time(&tv, immediately ? 0 : FLX_RESPONSE_DEFER_MSEC, immediately ? 0 : FLX_RESPONSE_JITTER_MSEC);
     
     /* Don't send out duplicates */
index c312ce8b85ab1d1c64e3e8ca8fc0b2ff14e4ab73..3a99ed1dddf203d5d76cc800a3d73ad41164f78a 100644 (file)
--- a/psched.h
+++ b/psched.h
@@ -4,6 +4,7 @@
 typedef struct _flxQueryJob flxQueryJob;
 typedef struct _flxResponseJob flxResponseJob;
 typedef struct _flxPacketScheduler flxPacketScheduler;
+typedef struct _flxKnownAnswer flxKnownAnswer;
 
 #include "timeeventq.h"
 #include "rr.h"
@@ -28,6 +29,13 @@ struct _flxResponseJob {
     FLX_LLIST_FIELDS(flxResponseJob, jobs);
 };
 
+struct _flxKnownAnswer {
+    flxPacketScheduler *scheduler;
+    flxRecord *record;
+
+    FLX_LLIST_FIELDS(flxKnownAnswer, known_answer);
+};
+
 struct _flxPacketScheduler {
     flxServer *server;
     
@@ -35,6 +43,7 @@ struct _flxPacketScheduler {
 
     FLX_LLIST_HEAD(flxQueryJob, query_jobs);
     FLX_LLIST_HEAD(flxResponseJob, response_jobs);
+    FLX_LLIST_HEAD(flxKnownAnswer, known_answers);
 };
 
 flxPacketScheduler *flx_packet_scheduler_new(flxServer *server, flxInterface *i);
diff --git a/rr.c b/rr.c
index 294d409ea493e18cf86c51c2dc26c524a1c33205..600e7219bb7b58116f378f8b300b06ca05e4261a 100644 (file)
--- a/rr.c
+++ b/rr.c
@@ -224,9 +224,31 @@ gboolean flx_key_equal(const flxKey *a, const flxKey *b) {
 
 /*     g_message("equal: %p %p", a, b); */
     
-    return strcmp(a->name, b->name) == 0 && a->type == b->type && a->class == b->class;
+    return strcmp(a->name, b->name) == 0 &&
+        a->type == b->type &&
+        a->class == b->class;
 }
 
+gboolean flx_key_pattern_match(const flxKey *pattern, const flxKey *k) {
+    g_assert(pattern);
+    g_assert(k);
+
+/*     g_message("equal: %p %p", a, b); */
+
+    g_assert(!flx_key_is_pattern(k));
+    
+    return strcmp(pattern->name, k->name) == 0 &&
+        (pattern->type == k->type || pattern->type == FLX_DNS_TYPE_ANY) &&
+        pattern->class == k->class;
+}
+
+gboolean flx_key_is_pattern(const flxKey *k) {
+    g_assert(k);
+
+    return k->type == FLX_DNS_TYPE_ANY;
+}
+
+
 guint flx_key_hash(const flxKey *k) {
     g_assert(k);
 
diff --git a/rr.h b/rr.h
index f17c36f74edb05ecd09d69dc8b0afc9772eb3465..65abb1d1e609e081ffd36e011b04162c58b488b7 100644 (file)
--- a/rr.h
+++ b/rr.h
@@ -13,7 +13,8 @@ enum {
     FLX_DNS_TYPE_MX = 0x0F,
     FLX_DNS_TYPE_TXT = 0x10,
     FLX_DNS_TYPE_AAAA = 0x1C,
-    FLX_DNS_TYPE_SRV = 0x21
+    FLX_DNS_TYPE_SRV = 0x21,
+    FLX_DNS_TYPE_ANY = 0xFF
 };
 
 enum {
@@ -42,7 +43,11 @@ flxKey *flx_key_new(const gchar *name, guint16 class, guint16 type);
 flxKey *flx_key_ref(flxKey *k);
 void flx_key_unref(flxKey *k);
 
-gboolean flx_key_equal(const flxKey *a, const flxKey *b);
+gboolean flx_key_equal(const flxKey *a, const flxKey *b);  /* Treat FLX_DNS_CLASS_ANY like any other type */
+gboolean flx_key_pattern_match(const flxKey *pattern, const flxKey *k); /* If pattern.type is FLX_DNS_CLASS_ANY, k.type is ignored */
+
+gboolean flx_key_is_pattern(const flxKey *k);
+
 guint flx_key_hash(const flxKey *k);
 
 flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 ttl);
index 6b3c2dd61c3c899714bba2c154004d59b4b3eea0..ecf44577ce2b45861d1cdd2d68359c684b452618 100644 (file)
--- a/server.c
+++ b/server.c
@@ -24,9 +24,22 @@ static void handle_query_key(flxServer *s, flxKey *k, flxInterface *i, const flx
 
     flx_packet_scheduler_incoming_query(i->scheduler, k);
 
-    for (e = g_hash_table_lookup(s->rrset_by_key, k); e; e = e->by_key_next)
-        if (flx_interface_match(i, e->interface, e->protocol))
-            flx_interface_post_response(i, e->record, FALSE);
+    if (k->type == FLX_DNS_TYPE_ANY) {
+
+        /* Handle ANY query */
+        
+        for (e = s->entries; e; e = e->entry_next)
+            if (flx_key_pattern_match(k, e->record->key))
+                if (flx_interface_match(i, e->interface, e->protocol))
+                    flx_interface_post_response(i, e->record, FALSE);
+    } else {
+
+        /* Handle all other queries */
+        
+        for (e = g_hash_table_lookup(s->rrset_by_key, k); e; e = e->by_key_next)
+            if (flx_interface_match(i, e->interface, e->protocol))
+                flx_interface_post_response(i, e->record, FALSE);
+    }
 }
 
 static void handle_query(flxServer *s, flxDnsPacket *p, flxInterface *i, const flxAddress *a) {
@@ -69,13 +82,15 @@ static void handle_response(flxServer *s, flxDnsPacket *p, flxInterface *i, cons
             return;
         }
 
-        g_message("Handling response: %s", txt = flx_record_to_string(record));
-        g_free(txt);
-
-        flx_cache_update(i->cache, record, cache_flush, a);
-
-        flx_packet_scheduler_incoming_response(i->scheduler, record);
-        flx_record_unref(record);
+        if (record->key->type != FLX_DNS_TYPE_ANY) {
+            g_message("Handling response: %s", txt = flx_record_to_string(record));
+            g_free(txt);
+            
+            flx_cache_update(i->cache, record, cache_flush, a);
+            
+            flx_packet_scheduler_incoming_response(i->scheduler, record);
+            flx_record_unref(record);
+        }
     }
 }
 
@@ -348,6 +363,8 @@ void flx_server_add(
     g_assert(s);
     g_assert(r);
 
+    g_assert(r->key->type != FLX_DNS_TYPE_ANY);
+
     e = g_new(flxServerEntry, 1);
     e->record = flx_record_ref(r);
     e->id = id;
index 7fd264d96b21e4ef100ff352ede520d3bd30364c..abd16206ba086bbddff4f7ee6b60184a103b4a76 100644 (file)
@@ -20,16 +20,39 @@ static void elapse(flxTimeEvent *e, void *userdata) {
     flx_time_event_queue_update(s->server->time_event_queue, s->time_event, &tv);
 }
 
-static void scan_cache_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
+struct cbdata {
+    flxSubscription *subscription;
+    flxInterface *interface;
+};
+
+static gpointer scan_cache_callback(flxCache *c, flxKey *pattern, flxCacheEntry *e, gpointer userdata) {
+    struct cbdata *cbdata = userdata;
+
+    g_assert(c);
+    g_assert(pattern);
+    g_assert(e);
+    g_assert(cbdata);
+
+    cbdata->subscription->callback(
+        cbdata->subscription,
+        e->record,
+        cbdata->interface->hardware->index,
+        cbdata->interface->protocol,
+        FLX_SUBSCRIPTION_NEW,
+        cbdata->subscription->userdata);
+
+    return NULL;
+}
+
+static void scan_interface_callback(flxInterfaceMonitor *m, flxInterface *i, gpointer userdata) {
     flxSubscription *s = userdata;
-    flxCacheEntry *e;
+    struct cbdata cbdata = { s, i };
 
     g_assert(m);
     g_assert(i);
     g_assert(s);
 
-    for (e = flx_cache_lookup_key(i->cache, s->key); e; e = e->by_name_next)
-        s->callback(s, e->record, i->hardware->index, i->protocol, FLX_SUBSCRIPTION_NEW, s->userdata);
+    flx_cache_walk(i->cache, s->key, scan_cache_callback, &cbdata);
 }
 
 flxSubscription *flx_subscription_new(flxServer *server, flxKey *key, gint interface, guchar protocol, flxSubscriptionCallback callback, gpointer userdata) {
@@ -40,6 +63,8 @@ flxSubscription *flx_subscription_new(flxServer *server, flxKey *key, gint inter
     g_assert(key);
     g_assert(callback);
 
+    g_assert(!flx_key_is_pattern(key));
+    
     s = g_new(flxSubscription, 1);
     s->server = server;
     s->key = flx_key_ref(key);
@@ -63,7 +88,7 @@ flxSubscription *flx_subscription_new(flxServer *server, flxKey *key, gint inter
     g_hash_table_replace(server->subscription_hashtable, key, t);
 
     /* Scan the caches */
-    flx_interface_monitor_walk(s->server->monitor, s->interface, s->protocol, scan_cache_callback, s);
+    flx_interface_monitor_walk(s->server->monitor, s->interface, s->protocol, scan_interface_callback, s);
     
     return s;
 }
@@ -91,6 +116,7 @@ void flx_subscription_free(flxSubscription *s) {
 
 void flx_subscription_notify(flxServer *server, flxInterface *i, flxRecord *record, flxSubscriptionEvent event) {
     flxSubscription *s;
+    flxKey *pattern;
     
     g_assert(server);
     g_assert(record);
@@ -98,5 +124,11 @@ void flx_subscription_notify(flxServer *server, flxInterface *i, flxRecord *reco
     for (s = g_hash_table_lookup(server->subscription_hashtable, record->key); s; s = s->by_key_next)
         if (flx_interface_match(i, s->interface, s->protocol))
             s->callback(s, record, i->hardware->index, i->protocol, event, s->userdata);
-    
+}
+
+gboolean flx_is_subscribed(flxServer *server, flxKey *k) {
+    g_assert(server);
+    g_assert(k);
+
+    return !!g_hash_table_lookup(server->subscription_hashtable, k);
 }
index 75818c768cf2bdec961f70263072a310a8ab83ad..6520433c50b0c721a91775d7603369674e49ec24 100644 (file)
@@ -36,4 +36,6 @@ void flx_subscription_free(flxSubscription *s);
 
 void flx_subscription_notify(flxServer *s, flxInterface *i, flxRecord *record, flxSubscriptionEvent event);
 
+gboolean flx_is_subscribed(flxServer *s, flxKey *k);
+
 #endif
diff --git a/todo b/todo
index 5576c7e8973eed679398410581aaacdf637c84f2..ab2519ba2032a1884b66fab3700f23806bdfa19b 100644 (file)
--- a/todo
+++ b/todo
@@ -1,12 +1,17 @@
 todo:
-* Unicast responses/queries
-* Known-Answer suppression
-* Truncation
 * Probing/Conflict resolution
-* Legacy unicast
 * uniqueness
 * defend our entries on incoming goodbye
 
+* Unicast responses/queries
+* Legacy unicast
+
+* Known-Answer suppression server part
+* Truncation
+
 done:
 * really send goodbye packets
+* refresh subscribed records only
+* FLX_DNS_TYPE_ANY support
+* Known-Answer suppression client part