]> git.meshlink.io Git - catta/commitdiff
massive work
authorLennart Poettering <lennart@poettering.net>
Fri, 21 Jan 2005 00:16:08 +0000 (00:16 +0000)
committerLennart Poettering <lennart@poettering.net>
Fri, 21 Jan 2005 00:16:08 +0000 (00:16 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@8 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

20 files changed:
Makefile
cache.c [new file with mode: 0644]
cache.h
flx.h
iface.c
iface.h
llist.h [new file with mode: 0644]
main.c
netlink.c
prioq-test.c
prioq.c
prioq.h
rr.c [new file with mode: 0644]
rr.h [new file with mode: 0644]
server.c
server.h
timeeventq.c [new file with mode: 0644]
timeeventq.h [new file with mode: 0644]
util.c
util.h

index 7aaa056d3a55169460ebc7c6af8e8ba145a9b6f4..a6b97a789049e5656a433618ac1fc206524b33c8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ LIBS=$(shell pkg-config --libs glib-2.0)
 
 all: flexmdns prioq-test
 
-flexmdns: main.o iface.o netlink.o server.o address.o util.o prioq.o
+flexmdns: timeeventq.o main.o iface.o netlink.o server.o address.o util.o prioq.o cache.o rr.o
        $(CC) -o $@ $^ $(LIBS)
 
 #test-llist: test-llist.o
diff --git a/cache.c b/cache.c
new file mode 100644 (file)
index 0000000..6a0a874
--- /dev/null
+++ b/cache.c
@@ -0,0 +1,149 @@
+#include <string.h>
+
+#include "cache.h"
+
+static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_hash_table) {
+    g_assert(c);
+    g_assert(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);
+    }
+        
+    flx_record_unref(e->record);
+    g_free(e);
+}
+
+flxCache *flx_cache_new(flxServer *server, flxInterface *iface) {
+    flxCache *c;
+    g_assert(server);
+
+    c = g_new(flxCache, 1);
+    c->server = server;
+    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);
+    }
+    
+    return TRUE;
+}
+
+void flx_cache_free(flxCache *c) {
+    g_assert(c);
+
+    g_hash_table_foreach_remove(c->hash_table, remove_func, c);
+    g_hash_table_destroy(c->hash_table);
+    
+    g_free(c);
+}
+
+flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k) {
+    g_assert(c);
+    g_assert(k);
+
+    return g_hash_table_lookup(c->hash_table, k);
+}
+
+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 (e->record->size == r->size && !memcmp(e->record->data, r->data, r->size))
+            return e;
+
+    return NULL;
+}
+
+flxCacheEntry *flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddress *a) {
+    flxCacheEntry *e, *t;
+    
+    g_assert(c);
+    g_assert(r);
+
+    if ((t = e = flx_cache_lookup_key(c, r->key))) {
+
+        if (unique) {
+            flxCacheEntry *n;
+            /* Drop all entries but the first which we replace */
+
+            while (e->by_name_next)
+                remove_entry(c, e->by_name_next, TRUE);
+
+            g_free(e->record->data);
+            e->record->data = g_memdup(r->data, r->size);
+            e->record->size = r->size;
+            e->record->ttl = r->ttl;
+
+        } else {
+            /* Look for exactly the same entry */
+
+            for (; e; e = e->by_name_next) {
+                if (e->record->size == r->size &&
+                    !memcmp(e->record->data, r->data, r->size)) {
+
+                    /* We found it, so let's update the TTL */
+                    e->record->ttl = r->ttl;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!e) {
+        /* No entry found, therefore we create a new one */
+        
+        e = g_new(flxCacheEntry, 1);
+        e->node = NULL;
+
+        e->record = flx_record_ref(r);
+        FLX_LLIST_PREPEND(flxCacheEntry, by_name, t, e);
+        g_hash_table_replace(c->hash_table, e->record->key, e);
+    } 
+
+    e->origin = *a;
+    
+    g_get_current_time(&e->timestamp);
+    e->expiry = e->timestamp;
+    g_time_val_add(&e->expiry, e->record->ttl * 1000000);
+
+    e->state = FLX_CACHE_VALID;
+
+    return e;
+}
+
+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);
+}
+
+void flx_cache_drop_record(flxCache *c, flxRecord *r) {
+    flxCacheEntry *e;
+    
+    g_assert(c);
+    g_assert(r);
+
+    if ((e = flx_cache_lookup_record(c, r))) 
+        remove_entry(c, e, TRUE);
+}
diff --git a/cache.h b/cache.h
index f2014dfd8c6a1037f90ed2190bb0f68bd1bb6b1d..ec0e974ae3122c9908d94f801e12d941b45eae5c 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1,22 +1,56 @@
 #ifndef foocachehfoo
 #define foocachehfoo
 
+#include <glib.h>
+
+struct _flxCache;
+typedef struct _flxCache flxCache;
+
+#include "prioq.h"
+#include "server.h"
+#include "llist.h"
+
 typedef enum {
     FLX_CACHE_VALID,
     FLX_CACHE_EXPIRY1,
     FLX_CACHE_EXPIRY2,
     FLX_CACHE_EXPIRY3
         
-} flxCacheEntry;
+} flxCacheEntryState;
+
+typedef struct flxCacheEntry flxCacheEntry;
 
-typedef struct flxCacheEntry {
+struct flxCacheEntry {
+    flxRecord *record;
     GTimeVal timestamp;
-    flxRecord rr;
-    gint interface;
+    GTimeVal expiry;
+    
     flxAddress origin;
 
     flxCacheEntryState state;
+
+    FLX_LLIST_FIELDS(flxCacheEntry, by_name);
+
+    flxPrioQueueNode *node;
     
-} flxCacheEntry;
+};
+
+struct _flxCache {
+    flxServer *server;
+    flxInterface *interface;
+    
+    GHashTable *hash_table;
+};
+
+flxCache *flx_cache_new(flxServer *server, flxInterface *interface);
+void flx_cache_free(flxCache *c);
+
+flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k);
+flxCacheEntry *flx_cache_lookup_record(flxCache *c, flxRecord *r);
+
+flxCacheEntry *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);
 
 #endif
diff --git a/flx.h b/flx.h
index dad707e7bf1ea27d147ff893610f06f7d8b32e4b..331dd2623062e597d5aac6aa0bf4bbbd130452e5 100644 (file)
--- a/flx.h
+++ b/flx.h
@@ -8,59 +8,58 @@ struct _flxServer;
 typedef struct _flxServer flxServer;
 
 #include "address.h"
-
-typedef struct  {
-    gchar *name;
-    guint16 type;
-    guint16 class;
-    gpointer data;
-    guint16 size;
-    guint32 ttl;
-} flxRecord;
-
-typedef struct {
-    gchar *name;
-    guint16 type;
-    guint16 class;
-} flxQuery;
+#include "rr.h"
 
 flxServer *flx_server_new(GMainContext *c);
 void flx_server_free(flxServer* s);
 
 gint flx_server_get_next_id(flxServer *s);
 
-void flx_server_add_rr(flxServer *s, gint id, gint interface, guchar protocol, const flxRecord *rr);
-void flx_server_add(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, guint16 type, gconstpointer data, guint size);
-void flx_server_add_address(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, flxAddress *a);
-void flx_server_add_text(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, const gchar *text);
+void flx_server_add(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    flxRecord *r);
+
+void flx_server_add_full(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    guint16 class,
+    guint16 type,
+    gconstpointer data,
+    guint size,
+    guint32 ttl);
+
+void flx_server_add_address(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    flxAddress *a);
+
+void flx_server_add_text(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    const gchar *text);
 
 void flx_server_remove(flxServer *s, gint id);
 
-const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state);
+void flx_server_send_query(flxServer *s, gint interface, guchar protocol, flxKey *k);
 
-flxRecord *flx_record_copy_normalize(flxRecord *ret_dest, const flxRecord*src);
+const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state);
 
 void flx_server_dump(flxServer *s, FILE *f);
 
-struct _flxLocalAddrSource;
-typedef struct _flxLocalAddrSource flxLocalAddrSource;
-
-enum {
-    FLX_DNS_TYPE_A = 0x01,
-    FLX_DNS_TYPE_NS = 0x02,
-    FLX_DNS_TYPE_CNAME = 0x05,
-    FLX_DNS_TYPE_SOA = 0x06,
-    FLX_DNS_TYPE_PTR = 0x0C,
-    FLX_DNS_TYPE_HINFO = 0x0D,
-    FLX_DNS_TYPE_MX = 0x0F,
-    FLX_DNS_TYPE_TXT = 0x10,
-    FLX_DNS_TYPE_AAAA = 0x1C,
-};
-
-enum {
-    FLX_DNS_CLASS_IN = 0x01
-};
-
-#define FLX_DEFAULT_TTL (120*60)
-
 #endif
diff --git a/iface.c b/iface.c
index 4bcd2d9de3fb228138116d36c16cd3114ea855d1..6ea7054e38439ad4b2270e8f7b5a56635ec91983 100644 (file)
--- a/iface.c
+++ b/iface.c
@@ -21,7 +21,7 @@ static void update_address_rr(flxInterfaceMonitor *m, flxInterfaceAddress *a, in
     } else {
         if (a->rr_id < 0) {
             a->rr_id = flx_server_get_next_id(m->server);
-            flx_server_add_address(m->server, a->rr_id, a->interface->index, AF_UNSPEC, m->server->hostname, &a->address);
+            flx_server_add_address(m->server, a->rr_id, a->interface->index, AF_UNSPEC, FALSE, m->server->hostname, &a->address);
         }
     }
 }
@@ -31,7 +31,7 @@ static void update_interface_rr(flxInterfaceMonitor *m, flxInterface *i, int rem
     g_assert(m);
     g_assert(i);
 
-    for (a = i->addresses; a; a = a->next)
+    for (a = i->addresses; a; a = a->address_next)
         update_address_rr(m, a, remove);
 }
 
@@ -44,15 +44,11 @@ static void free_address(flxInterfaceMonitor *m, flxInterfaceAddress *a) {
         a->interface->n_ipv4_addrs --;
     else if (a->address.family == AF_INET6)
         a->interface->n_ipv6_addrs --;
-    if (a->prev)
-        a->prev->next = a->next;
-    else
-        a->interface->addresses = a->next;
 
-    if (a->next)
-        a->next->prev = a->prev;
+    FLX_LLIST_REMOVE(flxInterfaceAddress, address, a->interface->addresses, a);
 
+    flx_server_remove(m->server, a->rr_id);
+    
     g_free(a);
 }
 
@@ -63,18 +59,19 @@ static void free_interface(flxInterfaceMonitor *m, flxInterface *i) {
     while (i->addresses)
         free_address(m, i->addresses);
 
+    if (i->ipv4_cache)
+        flx_cache_free(i->ipv4_cache);
+    if (i->ipv6_cache)
+        flx_cache_free(i->ipv6_cache);
+    
     g_assert(i->n_ipv6_addrs == 0);
     g_assert(i->n_ipv4_addrs == 0);
 
-    if (i->prev)
-        i->prev->next = i->next;
-    else
-        m->interfaces = i->next;
-
-    if (i->next)
-        i->next->prev = i->prev;
-
+    FLX_LLIST_REMOVE(flxInterface, interface, m->interfaces, i);
     g_hash_table_remove(m->hash_table, &i->index);
+
+    flx_cache_free(i->ipv4_cache);
+    flx_cache_free(i->ipv6_cache);
     
     g_free(i->name);
     g_free(i);
@@ -87,7 +84,7 @@ static flxInterfaceAddress* get_address(flxInterfaceMonitor *m, flxInterface *i,
     g_assert(i);
     g_assert(raddr);
 
-    for (ia = i->addresses; ia; ia = ia->next)
+    for (ia = i->addresses; ia; ia = ia->address_next)
         if (flx_address_cmp(&ia->address, raddr) == 0)
             return ia;
 
@@ -134,15 +131,16 @@ static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
             changed = 1;
         else {
             i = g_new(flxInterface, 1);
+            i->monitor = m;
             i->name = NULL;
             i->index = ifinfomsg->ifi_index;
             i->addresses = NULL;
             i->n_ipv4_addrs = i->n_ipv6_addrs = 0;
-            if ((i->next = m->interfaces))
-                i->next->prev = i;
-            m->interfaces = i;
-            i->prev = NULL;
+            FLX_LLIST_PREPEND(flxInterface, interface, m->interfaces, i);
             g_hash_table_insert(m->hash_table, &i->index, i);
+            i->ipv4_cache = flx_cache_new(m->server, i);
+            i->ipv6_cache = flx_cache_new(m->server, i);
+            
             changed = 0;
         }
         
@@ -231,18 +229,16 @@ static void callback(flxNetlink *nl, struct nlmsghdr *n, gpointer userdata) {
             else {
                 addr = g_new(flxInterfaceAddress, 1);
                 addr->address = raddr;
+                addr->interface = i;
 
                 if (raddr.family == AF_INET)
                     i->n_ipv4_addrs++;
                 else if (raddr.family == AF_INET6)
                     i->n_ipv6_addrs++;
-                
-                addr->interface = i;
-                if ((addr->next = i->addresses))
-                    addr->next->prev = addr;
-                i->addresses = addr;
-                addr->prev = NULL;
+
                 addr->rr_id = -1;
+
+                FLX_LLIST_PREPEND(flxInterfaceAddress, address, i->addresses, addr);
                 
                 changed = 0;
             }
@@ -317,14 +313,14 @@ void flx_interface_monitor_free(flxInterfaceMonitor *m) {
 }
 
 
-const flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) {
+flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index) {
     g_assert(m);
     g_assert(index > 0);
 
     return g_hash_table_lookup(m->hash_table, &index);
 }
 
-const flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) {
+flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m) {
     g_assert(m);
     return m->interfaces;
 }
@@ -345,3 +341,8 @@ int flx_address_is_relevant(flxInterfaceAddress *a) {
         a->scope == RT_SCOPE_UNIVERSE &&
         flx_interface_is_relevant(a->interface);
 }
+
+void flx_interface_send_query(flxInterface *i, guchar protocol, flxKey *k) {
+    g_assert(i);
+    g_assert(k);
+}
diff --git a/iface.h b/iface.h
index 90bfc05857623adf02012ac5d54ad5de46786914..f7547b8462f768026f91ce5c4718ccf6af5ea3a6 100644 (file)
--- a/iface.h
+++ b/iface.h
@@ -15,13 +15,15 @@ typedef struct _flxInterface flxInterface;
 #include "address.h"
 #include "server.h"
 #include "netlink.h"
+#include "cache.h"
+#include "llist.h"
 
 struct _flxInterfaceMonitor {
     flxServer *server;
     flxNetlink *netlink;
     GHashTable *hash_table;
 
-    flxInterface *interfaces;
+    FLX_LLIST_HEAD(flxInterface, interfaces);
     
     guint query_addr_seq, query_link_seq;
     
@@ -29,14 +31,16 @@ struct _flxInterfaceMonitor {
 };
 
 struct _flxInterface {
+    flxInterfaceMonitor *monitor;
     gchar *name;
     gint index;
     guint flags;
 
+    FLX_LLIST_HEAD(flxInterfaceAddress, addresses);
+    FLX_LLIST_FIELDS(flxInterface, interface);
+
     guint n_ipv6_addrs, n_ipv4_addrs;
-    
-    flxInterfaceAddress *addresses;
-    flxInterface *next, *prev;
+    flxCache *ipv4_cache, *ipv6_cache;
 };
 
 struct _flxInterfaceAddress {
@@ -45,7 +49,8 @@ struct _flxInterfaceAddress {
     flxAddress address;
     
     flxInterface *interface;
-    flxInterfaceAddress *next, *prev;
+
+    FLX_LLIST_FIELDS(flxInterfaceAddress, address);
 
     gint rr_id;
 };
@@ -53,10 +58,12 @@ struct _flxInterfaceAddress {
 flxInterfaceMonitor *flx_interface_monitor_new(flxServer *server);
 void flx_interface_monitor_free(flxInterfaceMonitor *m);
 
-const flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index);
-const flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m);
+flxInterface* flx_interface_monitor_get_interface(flxInterfaceMonitor *m, gint index);
+flxInterface* flx_interface_monitor_get_first(flxInterfaceMonitor *m);
 
 int flx_interface_is_relevant(flxInterface *i);
 int flx_address_is_relevant(flxInterfaceAddress *a);
+
+void flx_interface_send_query(flxInterface *i, guchar protocol, flxKey *k);
     
 #endif
diff --git a/llist.h b/llist.h
new file mode 100644 (file)
index 0000000..e5787cd
--- /dev/null
+++ b/llist.h
@@ -0,0 +1,50 @@
+#ifndef foollistfoo
+#define foollistfoo
+
+#include <glib.h>
+
+/* Some macros for maintaining doubly linked lists */
+
+/* The head of the linked list. Use this in the structure that shall
+ * contain the head of the linked list */
+#define FLX_LLIST_HEAD(t,name) t *name
+
+/* The pointers in the linked list's items. Use this in the item structure */
+#define FLX_LLIST_FIELDS(t,name) t *name##_next, *name##_prev
+
+/* Initialize the list's head */
+#define FLX_LLIST_HEAD_INIT(t,head) do { (head) = NULL; } while(0)
+
+/* Initialize a list item */
+#define FLX_LLIST_INIT(t,name,item) do { \
+                               t *_item = (item); \
+                               g_assert(_item); \
+                               _item->name##_prev = _item->name##_next = NULL; \
+                               } while(0)
+
+/* Prepend an item to the list */
+#define FLX_LLIST_PREPEND(t,name,head,item) do { \
+                                        t **_head = &(head), *_item = (item); \
+                                        g_assert(_item); \
+                                        if ((_item->name##_next = *_head)) \
+                                           _item->name##_next->name##_prev = _item; \
+                                        _item->name##_prev = NULL; \
+                                        *_head = _item; \
+                                        } while (0)
+
+/* Remove an item from the list */
+#define FLX_LLIST_REMOVE(t,name,head,item) do { \
+                                    t **_head = &(head), *_item = (item); \
+                                    g_assert(_item); \
+                                    if (_item->name##_next) \
+                                       _item->name##_next->name##_prev = _item->name##_prev; \
+                                    if (_item->name##_prev) \
+                                       _item->name##_prev->name##_next = _item->name##_next; \
+                                    else {\
+                                       g_assert(*_head == _item); \
+                                       *_head = _item->name##_next; \
+                                    } \
+                                    _item->name##_next = _item->name##_prev = NULL; \
+                                    } while(0)
+
+#endif
diff --git a/main.c b/main.c
index d7a0f2f080cf8e0ac731463c827da083bc97e947..d8c2065ab6e4e73db543045b60779c1371c9cbca 100644 (file)
--- a/main.c
+++ b/main.c
@@ -5,35 +5,35 @@
 #include "flx.h"
 #include "server.h"
 
-static GMainLoop *loop = NULL;
-
 static gboolean timeout(gpointer data) {
-    g_main_loop_quit(loop);
+    g_main_loop_quit(data);
     return FALSE;
 }
 
 int main(int argc, char *argv[]) {
     flxServer *flx;
     gchar *r;
-    flxQuery q;
+    flxKey *k;
+    GMainLoop *loop = NULL;
 
     flx = flx_server_new(NULL);
 
-    flx_server_add_text(flx, 0, 0, AF_UNSPEC, NULL, "hallo");
-    
-    q.name = "campari.local.";
-    q.class = FLX_DNS_CLASS_IN;
-    q.type = FLX_DNS_TYPE_A;
-    flx_server_post_query_job(flx, 0, AF_UNSPEC, NULL, &q);
+    flx_server_add_text(flx, 0, 0, AF_UNSPEC, FALSE, NULL, "hallo");
+
+    k = flx_key_new("cocaine.local.", FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A);
+    flx_server_send_query(flx, 0, AF_UNSPEC, k);
+    flx_key_unref(k);
+
+    loop = g_main_loop_new(NULL, FALSE);
     
-    g_timeout_add(5000, timeout, NULL);
+    g_timeout_add(5000, timeout, loop);
     
-    loop = g_main_loop_new(NULL, FALSE);
     g_main_loop_run(loop);
     g_main_loop_unref(loop);
 
     flx_server_dump(flx, stdout);
 
     flx_server_free(flx);
+    
     return 0;
 }
index a04e6c9a42d9235c8520899b5cd14974ed9b4816..3bc7d0160baf1341e959adaee4ed441b98ac0b68 100644 (file)
--- a/netlink.c
+++ b/netlink.c
@@ -12,9 +12,7 @@ struct _flxNetlink {
     GSource *source;
     void (*callback) (flxNetlink *nl, struct nlmsghdr *n, gpointer userdata);
     gpointer userdata;
-    GSourceFuncs source_funcs;
 };
-
 static gboolean work(flxNetlink *nl) {
     g_assert(nl);
 
@@ -80,6 +78,15 @@ flxNetlink *flx_netlink_new(GMainContext *context, guint32 groups, void (*cb) (f
     struct sockaddr_nl addr;
     flxNetlink *nl;
 
+    static GSourceFuncs source_funcs = {
+        prepare_func,
+        check_func,
+        dispatch_func,
+        NULL,
+        NULL,
+        NULL
+    };
+    
     g_assert(context);
     g_assert(cb);
 
@@ -107,12 +114,7 @@ flxNetlink *flx_netlink_new(GMainContext *context, guint32 groups, void (*cb) (f
     nl->callback = cb;
     nl->userdata = userdata;
 
-    memset(&nl->source_funcs, 0, sizeof(nl->source_funcs));
-    nl->source_funcs.prepare = prepare_func;
-    nl->source_funcs.check = check_func;
-    nl->source_funcs.dispatch = dispatch_func,
-
-    nl->source = g_source_new(&nl->source_funcs, sizeof(GSource) + sizeof(flxNetlink*));
+    nl->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(flxNetlink*));
     *((flxNetlink**) (((guint8*) nl->source) + sizeof(GSource))) = nl;
 
     memset(&nl->poll_fd, 0, sizeof(GPollFD));
index 56cfbc120f704f63e4ef18e939c361574fdf320f..a54c1ff5a5ca6a6b8a7939fdd3609cc0bff75349 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "prioq.h"
 
-static gint compare(gpointer a, gpointer b) {
+static gint compare(gconstpointer a, gconstpointer b) {
     gint i = GPOINTER_TO_INT(a), j = GPOINTER_TO_INT(b);
 
     return i < j ? -1 : (i > j ? 1 : 0);
diff --git a/prioq.c b/prioq.c
index 43604972fe153cc59d419689bf18bcfbd5a3e1d8..09d781f92389002916a688455e5d7bc385f9ed17 100644 (file)
--- a/prioq.c
+++ b/prioq.c
@@ -1,6 +1,6 @@
 #include "prioq.h"
 
-flxPrioQueue* flx_prio_queue_new(gint (*compare) (gpointer a, gpointer b)) {
+flxPrioQueue* flx_prio_queue_new(gint (*compare) (gconstpointer a, gconstpointer b)) {
     flxPrioQueue *q;
     g_assert(compare);
 
@@ -216,7 +216,7 @@ static void exchange_nodes(flxPrioQueue *q, flxPrioQueueNode *a, flxPrioQueueNod
 }
 
 /* Move a node to the correct position */
-static void shuffle_node(flxPrioQueue *q, flxPrioQueueNode *n) {
+void flx_prio_queue_shuffle(flxPrioQueue *q, flxPrioQueueNode *n) {
     g_assert(q);
     g_assert(n);
 
@@ -290,7 +290,7 @@ flxPrioQueueNode* flx_prio_queue_put(flxPrioQueue *q, gpointer data) {
     q->last = n;
     q->n_nodes++;
 
-    shuffle_node(q, n);
+    flx_prio_queue_shuffle(q, n);
 
     return n;
 }
@@ -303,7 +303,7 @@ void flx_prio_queue_remove(flxPrioQueue *q, flxPrioQueueNode *n) {
         flxPrioQueueNode *replacement = q->last;
         exchange_nodes(q, replacement, n);
         flx_prio_queue_remove(q, q->last);
-        shuffle_node(q, replacement);
+        flx_prio_queue_shuffle(q, replacement);
         return;
     }
 
diff --git a/prioq.h b/prioq.h
index e1b87966bfb303fb0046943378f07217dbf0293e..46c64827965f3d0f8931a704360e474d8adc13ac 100644 (file)
--- a/prioq.h
+++ b/prioq.h
@@ -13,7 +13,7 @@ struct _flxPrioQueue {
     flxPrioQueueNode *root, *last;
     
     guint n_nodes;
-    gint (*compare) (gpointer a, gpointer b);
+    gint (*compare) (gconstpointer a, gconstpointer b);
 };
 
 struct _flxPrioQueueNode {
@@ -24,10 +24,12 @@ struct _flxPrioQueueNode {
     flxPrioQueueNode *left, *right, *parent, *next, *prev;
 };
 
-flxPrioQueue* flx_prio_queue_new(gint (*compare) (gpointer a, gpointer b));
+flxPrioQueue* flx_prio_queue_new(gint (*compare) (gconstpointer a, gconstpointer b));
 void flx_prio_queue_free(flxPrioQueue *q);
 
 flxPrioQueueNode* flx_prio_queue_put(flxPrioQueue *q, gpointer data);
 void flx_prio_queue_remove(flxPrioQueue *q, flxPrioQueueNode *n);
 
+void flx_prio_queue_shuffle(flxPrioQueue *q, flxPrioQueueNode *n);
+
 #endif
diff --git a/rr.c b/rr.c
new file mode 100644 (file)
index 0000000..0153b28
--- /dev/null
+++ b/rr.c
@@ -0,0 +1,166 @@
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "util.h"
+#include "rr.h"
+
+flxKey *flx_key_new(const gchar *name, guint16 class, guint16 type) {
+    flxKey *k;
+    g_assert(name);
+
+    k = g_new(flxKey, 1);
+    k->ref = 1;
+    k->name = flx_normalize_name(name);    
+    k->class = class;
+    k->type = type;
+
+    return k;
+}
+
+flxKey *flx_key_ref(flxKey *k) {
+    g_assert(k);
+    g_assert(k->ref >= 1);
+
+    k->ref++;
+    return k;
+}
+
+void flx_key_unref(flxKey *k) {
+    g_assert(k);
+    g_assert(k->ref >= 1);
+
+    if ((--k->ref) <= 0) {
+        g_free(k->name);
+        g_free(k);
+    }
+}
+
+flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 ttl) {
+    flxRecord *r;
+    
+    g_assert(k);
+    g_assert(data);
+    g_assert(size > 0);
+    g_assert(ttl > 0);
+
+    r = g_new(flxRecord, 1);
+    r->ref = 1;
+    r->key = flx_key_ref(k);
+    r->data = g_memdup(data, size);
+    r->size = size;
+    r->ttl = ttl;
+
+    return r;
+}
+
+flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type, gconstpointer data, guint16 size, guint32 ttl) {
+    flxRecord *r;
+    flxKey *k;
+    
+    k = flx_key_new(name, class, type);
+    r = flx_record_new(k, data, size, ttl);
+    flx_key_unref(k);
+
+    return r;
+}
+
+flxRecord *flx_record_ref(flxRecord *r) {
+    g_assert(r);
+    g_assert(r->ref >= 1);
+
+    r->ref++;
+    return r;
+}
+
+void flx_record_unref(flxRecord *r) {
+    g_assert(r);
+    g_assert(r->ref >= 1);
+
+    if ((--r->ref) <= 0) {
+        flx_key_unref(r->key);
+        g_free(r->data);
+        g_free(r);
+    }
+}
+
+const gchar *flx_dns_class_to_string(guint16 class) {
+    if (class == FLX_DNS_CLASS_IN)
+        return "IN";
+
+    return NULL;
+}
+
+const gchar *flx_dns_type_to_string(guint16 type) {
+    switch (type) {
+        case FLX_DNS_TYPE_A:
+            return "A";
+        case FLX_DNS_TYPE_AAAA:
+            return "AAAA";
+        case FLX_DNS_TYPE_PTR:
+            return "PTR";
+        case FLX_DNS_TYPE_HINFO:
+            return "HINFO";
+        case FLX_DNS_TYPE_TXT:
+            return "TXT";
+        default:
+            return NULL;
+    }
+}
+
+
+gchar *flx_key_to_string(flxKey *k) {
+    return g_strdup_printf("%s\t%s\t%s",
+                           k->name,
+                           flx_dns_class_to_string(k->class),
+                           flx_dns_type_to_string(k->type));
+}
+
+gchar *flx_record_to_string(flxRecord *r) {
+    gchar *p, *s;
+    char t[256] = "<unparsable>";
+
+    if (r->key->type == FLX_DNS_TYPE_A)
+        inet_ntop(AF_INET, r->data, t, sizeof(t));
+    else if (r->key->type == FLX_DNS_TYPE_AAAA)
+        inet_ntop(AF_INET6, r->data, t, sizeof(t));
+    else if (r->key->type == FLX_DNS_TYPE_PTR || r->key->type == FLX_DNS_TYPE_TXT) {
+        size_t l;
+        
+        l = r->size;
+        if (l > sizeof(t)-1)
+            l = sizeof(t)-1;
+        
+        memcpy(t, r->data, l);
+        t[l] = 0;
+    } else if (r->key->type == FLX_DNS_TYPE_HINFO) {
+        char *s2;
+        
+        if ((s2 = memchr(r->data, 0, r->size))) {
+            s2++;
+            if (memchr(s2, 0, r->size - ((char*) s2 - (char*) r->data)))
+                snprintf(t, sizeof(t), "'%s' '%s'", (char*) r->data, s2);
+        }
+    }
+
+    p = flx_key_to_string(r->key);
+    s = g_strdup_printf("%s %s", p, t);
+    g_free(p);
+    
+    return s;
+}
+
+gboolean flx_key_equal(const flxKey *a, const flxKey *b) {
+    g_assert(a);
+    g_assert(b);
+    
+    return strcmp(a->name, b->name) == 0 && a->type == b->type && a->class == b->class;
+}
+
+guint flx_key_hash(const flxKey *k) {
+    g_assert(k);
+
+    return g_str_hash(k->name) + k->type + k->class;
+}
diff --git a/rr.h b/rr.h
new file mode 100644 (file)
index 0000000..bcd684e
--- /dev/null
+++ b/rr.h
@@ -0,0 +1,58 @@
+#ifndef foorrhfoo
+#define foorrhfoo
+
+#include <glib.h>
+
+enum {
+    FLX_DNS_TYPE_A = 0x01,
+    FLX_DNS_TYPE_NS = 0x02,
+    FLX_DNS_TYPE_CNAME = 0x05,
+    FLX_DNS_TYPE_SOA = 0x06,
+    FLX_DNS_TYPE_PTR = 0x0C,
+    FLX_DNS_TYPE_HINFO = 0x0D,
+    FLX_DNS_TYPE_MX = 0x0F,
+    FLX_DNS_TYPE_TXT = 0x10,
+    FLX_DNS_TYPE_AAAA = 0x1C,
+};
+
+enum {
+    FLX_DNS_CLASS_IN = 0x01
+};
+
+#define FLX_DEFAULT_TTL (120*60)
+
+typedef struct {
+    guint ref;
+    gchar *name;
+    guint16 class;
+    guint16 type;
+} flxKey;
+
+typedef struct  {
+    guint ref;
+    flxKey *key;
+    
+    gpointer data;
+    guint16 size;
+    guint32 ttl;
+} flxRecord;
+
+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);
+guint flx_key_hash(const flxKey *k);
+
+flxRecord *flx_record_new(flxKey *k, gconstpointer data, guint16 size, guint32 ttl);
+flxRecord *flx_record_new_full(const gchar *name, guint16 class, guint16 type, gconstpointer data, guint16 size, guint32 ttl);
+flxRecord *flx_record_ref(flxRecord *r);
+void flx_record_unref(flxRecord *r);
+
+const gchar *flxdns_class_to_string(guint16 class);
+const gchar *flx_dns_type_to_string(guint16 type);
+
+gchar *flx_key_to_string(flxKey *k); /* g_free() the result! */
+gchar *flx_record_to_string(flxRecord *r);  /* g_free() the result! */
+
+#endif
index c31ff8097439279a8101d39890d225b0121c2d76..79c017fe11cd57d280583e78ed60ae77611c0de6 100644 (file)
--- a/server.c
+++ b/server.c
@@ -7,64 +7,51 @@
 #include "util.h"
 #include "iface.h"
 
-static gint timeval_cmp(const GTimeVal *a, const GTimeVal *b) {
-    g_assert(a);
-    g_assert(b);
-
-    if (a->tv_sec < b->tv_sec)
-        return -1;
-
-    if (a->tv_sec > b->tv_sec)
-        return 1;
-
-    if (a->tv_usec < b->tv_usec)
-        return -1;
-
-    if (a->tv_usec > b->tv_usec)
-        return 1;
-
-    return 0;
-}
-
-static gint query_job_instance_compare(gpointer a, gpointer b) {
-    flxQueryJobInstance *j = a, *k = b;
-    g_assert(j);
-    g_assert(k);
+static void add_default_entries(flxServer *s) {
+    gint length = 0;
+    struct utsname utsname;
+    gchar *hinfo;
+    flxAddress a;
+    
+    g_assert(s);
+    
+    /* Fill in HINFO rr */
+    uname(&utsname);
+    hinfo = g_strdup_printf("%s%c%s%n", g_strup(utsname.machine), 0, g_strup(utsname.sysname), &length);
+    
+    flx_server_add_full(s, 0, 0, AF_UNSPEC, TRUE,
+                        s->hostname, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_HINFO, hinfo, length+1, FLX_DEFAULT_TTL);
 
-    return timeval_cmp(&j->job->time, &k->job->time);
-}
+    g_free(hinfo);
 
-static gint response_job_instance_compare(gpointer a, gpointer b) {
-    flxResponseJobInstance *j = a, *k = b;
-    g_assert(j);
-    g_assert(k);
+    /* Add localhost entries */
+    flx_address_parse("127.0.0.1", AF_INET, &a);
+    flx_server_add_address(s, 0, 0, AF_UNSPEC, TRUE, "localhost", &a);
 
-    return timeval_cmp(&j->job->time, &k->job->time);
+    flx_address_parse("::1", AF_INET6, &a);
+    flx_server_add_address(s, 0, 0, AF_UNSPEC, TRUE, "ip6-localhost", &a);
 }
 
 flxServer *flx_server_new(GMainContext *c) {
-    gchar *hn, *e, *hinfo;
-    struct utsname utsname;
-    gint length;
-    flxAddress a;
-    flxServer *s = g_new(flxServer, 1);
+    gchar *hn, *e;
+    flxServer *s;
 
-    if (c) {
-        g_main_context_ref(c);
-        s->context = c;
-    } else
+    s = g_new(flxServer, 1);
+
+    if (c)
+        g_main_context_ref(s->context = c);
+    else
         s->context = g_main_context_default();
     
     s->current_id = 1;
     s->rrset_by_id = g_hash_table_new(g_int_hash, g_int_equal);
-    s->rrset_by_name = g_hash_table_new(g_str_hash, g_str_equal);
-    s->entries = NULL;
+    s->rrset_by_name = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
 
-    s->query_job_queue = flx_prio_queue_new(query_job_instance_compare);
-    s->response_job_queue = flx_prio_queue_new(response_job_instance_compare);
-    
-    s->monitor = flx_interface_monitor_new(s);
+    FLX_LLIST_HEAD_INIT(flxEntry, s->entries);
 
+    s->monitor = flx_interface_monitor_new(s);
+    s->time_event_queue = flx_time_event_queue_new(s->context);
+    
     /* Get host name */
     hn = flx_get_host_name();
     if ((e = strchr(hn, '.')))
@@ -73,22 +60,7 @@ flxServer *flx_server_new(GMainContext *c) {
     s->hostname = g_strdup_printf("%s.local.", hn);
     g_free(hn);
 
-    /* Fill in HINFO rr */
-    s->hinfo_rr_id = flx_server_get_next_id(s);
-
-    uname(&utsname);
-    hinfo = g_strdup_printf("%s%c%s%n", g_strup(utsname.machine), 0, g_strup(utsname.sysname), &length);
-    
-    flx_server_add(s, s->hinfo_rr_id, 0, AF_UNSPEC,
-                   s->hostname, FLX_DNS_TYPE_HINFO, hinfo, length+1);
-
-
-    /* Add localhost entries */
-    flx_address_parse("127.0.0.1", AF_INET, &a);
-    flx_server_add_address(s, 0, 0, AF_UNSPEC, "localhost", &a);
-
-    flx_address_parse("::1", AF_INET6, &a);
-    flx_server_add_address(s, 0, 0, AF_UNSPEC, "ip6-localhost", &a);
+    add_default_entries(s);
 
     return s;
 }
@@ -96,20 +68,16 @@ flxServer *flx_server_new(GMainContext *c) {
 void flx_server_free(flxServer* s) {
     g_assert(s);
 
-    while (s->query_job_queue->last)
-        flx_server_remove_query_job_instance(s, s->query_job_queue->last->data);
-    
-    flx_prio_queue_free(s->query_job_queue);
-    flx_prio_queue_free(s->response_job_queue);
-
     flx_interface_monitor_free(s->monitor);
     
     flx_server_remove(s, 0);
     
     g_hash_table_destroy(s->rrset_by_id);
     g_hash_table_destroy(s->rrset_by_name);
-    g_main_context_unref(s->context);
 
+    flx_time_event_queue_free(s->time_event_queue);
+    g_main_context_unref(s->context);
+    
     g_free(s->hostname);
     g_free(s);
 }
@@ -120,53 +88,59 @@ gint flx_server_get_next_id(flxServer *s) {
     return s->current_id++;
 }
 
-void flx_server_add_rr(flxServer *s, gint id, gint interface, guchar protocol, const flxRecord *rr) {
-    flxEntry *e;
+void flx_server_add(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    flxRecord *r) {
+    
+    flxEntry *e, *t;
     g_assert(s);
-    g_assert(rr);
-    g_assert(rr->name);
-    g_assert(rr->data);
-    g_assert(rr->size);
+    g_assert(r);
 
     e = g_new(flxEntry, 1);
-    flx_record_copy_normalize(&e->rr, rr);
+    e->record = flx_record_ref(r);
     e->id = id;
     e->interface = interface;
     e->protocol = protocol;
+    e->unique = unique;
 
-    /* Insert into linked list */
-    e->prev = NULL;
-    if ((e->next = s->entries))
-        e->next->prev = e;
-    s->entries = e;
+    FLX_LLIST_PREPEND(flxEntry, entry, s->entries, e);
 
     /* Insert into hash table indexed by id */
-    e->prev_by_id = NULL;
-    if ((e->next_by_id = g_hash_table_lookup(s->rrset_by_id, &id)))
-        e->next_by_id->prev = e;
-    g_hash_table_replace(s->rrset_by_id, &e->id, e);
-
+    t = g_hash_table_lookup(s->rrset_by_id, &e->id);
+    FLX_LLIST_PREPEND(flxEntry, by_id, t, e);
+    g_hash_table_replace(s->rrset_by_id, &e->id, t);
+    
     /* Insert into hash table indexed by name */
-    e->prev_by_name = NULL;
-    if ((e->next_by_name = g_hash_table_lookup(s->rrset_by_name, e->rr.name)))
-        e->next_by_name->prev = e;
-    g_hash_table_replace(s->rrset_by_name, e->rr.name, e);
+    t = g_hash_table_lookup(s->rrset_by_name, e->record->key);
+    FLX_LLIST_PREPEND(flxEntry, by_name, t, e);
+    g_hash_table_replace(s->rrset_by_name, e->record->key, t);
 }
 
-void flx_server_add(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, guint16 type, gconstpointer data, guint size) {
-    flxRecord rr;
+void flx_server_add_full(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    guint16 class,
+    guint16 type,
+    gconstpointer data,
+    guint size,
+    guint32 ttl) {
+    
+    flxRecord *r;
     g_assert(s);
-    g_assert(name);
     g_assert(data);
     g_assert(size);
 
-    rr.name = (gchar*) name;
-    rr.type = type;
-    rr.class = FLX_DNS_CLASS_IN;
-    rr.data = (gpointer) data;
-    rr.size = size;
-    rr.ttl = FLX_DEFAULT_TTL;
-    flx_server_add_rr(s, id, interface, protocol, &rr);
+    r = flx_record_new_full(name ? name : s->hostname, class, type, data, size, ttl);
+    flx_server_add(s, id, interface, protocol, unique, r);
+    flx_record_unref(r);
 }
 
 const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) {
@@ -175,53 +149,42 @@ const flxRecord *flx_server_iterate(flxServer *s, gint id, void **state) {
     g_assert(e);
 
     if (e)
-        *e = id > 0 ? (*e)->next_by_id : (*e)->next;
+        *e = id > 0 ? (*e)->by_id_next : (*e)->entry_next;
     else
         *e = id > 0 ? g_hash_table_lookup(s->rrset_by_id, &id) : s->entries;
         
     if (!*e)
         return NULL;
 
-    return &(*e)->rr;
+    return flx_record_ref((*e)->record);
 }
 
 static void free_entry(flxServer*s, flxEntry *e) {
+    flxEntry *t;
+    
     g_assert(e);
 
     /* Remove from linked list */
-    if (e->prev)
-        e->prev->next = e->next;
-    else
-        s->entries = e->next;
-    
-    if (e->next)
-        e->next->prev = e->prev;
+    FLX_LLIST_REMOVE(flxEntry, entry, s->entries, e);
 
     /* Remove from hash table indexed by id */
-    if (e->prev_by_id)
-        e->prev_by_id = e->next_by_id;
-    else {
-        if (e->next_by_id)
-            g_hash_table_replace(s->rrset_by_id, &e->next_by_id->id, e->next_by_id);
-        else
-            g_hash_table_remove(s->rrset_by_id, &e->id);
-    }
-
-    if (e->next_by_id)
-        e->next_by_id->prev_by_id = e->prev_by_id;
-
-    /* Remove from hash table indexed by name */
-    if (e->prev_by_name)
-        e->prev_by_name = e->next_by_name;
-    else {
-        if (e->next_by_name)
-            g_hash_table_replace(s->rrset_by_name, &e->next_by_name->rr.name, e->next_by_name);
-        else
-            g_hash_table_remove(s->rrset_by_name, &e->rr.name);
-    }
+    t = g_hash_table_lookup(s->rrset_by_id, &e->id);
+    FLX_LLIST_REMOVE(flxEntry, by_id, t, e);
+    if (t)
+        g_hash_table_replace(s->rrset_by_id, &t->id, t);
+    else
+        g_hash_table_remove(s->rrset_by_id, &e->id);
     
-    if (e->next_by_name)
-        e->next_by_name->prev_by_name = e->prev_by_name;
+    /* Remove from hash table indexed by name */
+    t = g_hash_table_lookup(s->rrset_by_name, e->record->key);
+    FLX_LLIST_REMOVE(flxEntry, by_name, t, e);
+    if (t)
+        g_hash_table_replace(s->rrset_by_name, t->record->key, t);
+    else
+        g_hash_table_remove(s->rrset_by_name, e->record->key);
+
+    flx_record_unref(e->record);
+    g_free(e);
 }
 
 void flx_server_remove(flxServer *s, gint id) {
@@ -238,234 +201,95 @@ void flx_server_remove(flxServer *s, gint id) {
     }
 }
 
-flxRecord *flx_record_copy_normalize(flxRecord *ret_dest, const flxRecord*src) {
-    g_assert(ret_dest);
-    g_assert(src);
-
-    *ret_dest = *src;
-    ret_dest->name = flx_normalize_name(src->name);
-    ret_dest->data = g_memdup(src->data, src->size);
-
-    return ret_dest;    
-}
-
-static const gchar *dns_class_to_string(guint16 class) {
-    if (class == FLX_DNS_CLASS_IN)
-        return "IN";
-
-    return NULL;
-}
-
-static const gchar *dns_type_to_string(guint16 type) {
-    switch (type) {
-        case FLX_DNS_TYPE_A:
-            return "A";
-        case FLX_DNS_TYPE_AAAA:
-            return "AAAA";
-        case FLX_DNS_TYPE_PTR:
-            return "PTR";
-        case FLX_DNS_TYPE_HINFO:
-            return "HINFO";
-        case FLX_DNS_TYPE_TXT:
-            return "TXT";
-        default:
-            return NULL;
-    }
-}
-
 void flx_server_dump(flxServer *s, FILE *f) {
     flxEntry *e;
     g_assert(s);
     g_assert(f);
 
-    for (e = s->entries; e; e = e->next) {
-        char t[256];
-        fprintf(f, "%i.%u: %-40s %-8s %-8s ", e->interface, e->protocol, e->rr.name, dns_class_to_string(e->rr.class), dns_type_to_string(e->rr.type));
+    for (e = s->entries; e; e = e->entry_next) {
+        gchar *t;
 
-        t[0] = 0;
-        
-        if (e->rr.class == FLX_DNS_CLASS_IN) {
-            if (e->rr.type == FLX_DNS_TYPE_A)
-                inet_ntop(AF_INET, e->rr.data, t, sizeof(t));
-            else if (e->rr.type == FLX_DNS_TYPE_AAAA)
-                inet_ntop(AF_INET6, e->rr.data, t, sizeof(t));
-            else if (e->rr.type == FLX_DNS_TYPE_PTR)
-                g_strlcpy(t, e->rr.data, sizeof(t));
-            else if (e->rr.type == FLX_DNS_TYPE_HINFO) {
-                char *s2;
-
-                if ((s2 = memchr(e->rr.data, 0, e->rr.size))) {
-                    s2++;
-                    if (memchr(s2, 0, e->rr.size - ((char*) s2 - (char*) e->rr.data)))
-                        snprintf(t, sizeof(t), "'%s' '%s'", (char*) e->rr.data, s2);
-                }
-                
-            } else if (e->rr.type == FLX_DNS_TYPE_TXT) {
-                size_t l;
-
-                l = e->rr.size;
-                if (l > sizeof(t)-1)
-                    l = sizeof(t)-1;
-
-                memcpy(t, e->rr.data, l);
-                t[l] = 0;
-            }
-        }
-            
+        t = flx_record_to_string(e->record);
         fprintf(f, "%s\n", t);
+        g_free(t);
     }
 }
 
-void flx_server_add_address(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, flxAddress *a) {
+void flx_server_add_address(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    flxAddress *a) {
+
     gchar *n;
     g_assert(s);
     g_assert(a);
 
-    n = flx_normalize_name(name ? name : s->hostname);
+    n = name ? flx_normalize_name(name) : s->hostname;
     
     if (a->family == AF_INET) {
         gchar *r;
         
-        flx_server_add(s, id, interface, protocol, n, FLX_DNS_TYPE_A, &a->ipv4, sizeof(a->ipv4));
+        flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_A, &a->ipv4, sizeof(a->ipv4), FLX_DEFAULT_TTL);
 
         r = flx_reverse_lookup_name_ipv4(&a->ipv4);
         g_assert(r);
-        flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
+        flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
         g_free(r);
         
     } else {
         gchar *r;
             
-        flx_server_add(s, id, interface, protocol, n, FLX_DNS_TYPE_AAAA, &a->ipv6, sizeof(a->ipv6));
+        flx_server_add_full(s, id, interface, protocol, unique, n, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_AAAA, &a->ipv6, sizeof(a->ipv6), FLX_DEFAULT_TTL);
 
         r = flx_reverse_lookup_name_ipv6_arpa(&a->ipv6);
         g_assert(r);
-        flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
+        flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
         g_free(r);
     
         r = flx_reverse_lookup_name_ipv6_int(&a->ipv6);
         g_assert(r);
-        flx_server_add(s, id, interface, protocol, r, FLX_DNS_TYPE_PTR, n, strlen(n)+1);
+        flx_server_add_full(s, id, interface, protocol, unique, r, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_PTR, n, strlen(n)+1, FLX_DEFAULT_TTL);
         g_free(r);
     }
     
     g_free(n);
 }
 
-void flx_server_add_text(flxServer *s, gint id, gint interface, guchar protocol, const gchar *name, const gchar *text) {
-    gchar *n;
+void flx_server_add_text(
+    flxServer *s,
+    gint id,
+    gint interface,
+    guchar protocol,
+    gboolean unique,
+    const gchar *name,
+    const gchar *text) {
+    
     g_assert(s);
     g_assert(text);
 
-    n = flx_normalize_name(name ? name : s->hostname);
-    flx_server_add(s, id, interface, protocol, n, FLX_DNS_TYPE_TXT, text, strlen(text));
-    g_free(n);
-}
-
-
-flxQueryJob* flx_query_job_new(void) {
-    flxQueryJob *job = g_new(flxQueryJob, 1);
-    job->query.name = NULL;
-    job->query.class = 0;
-    job->query.type = 0;
-    job->ref = 1;
-    job->time.tv_sec = 0;
-    job->time.tv_usec = 0;
-    return job;
+    flx_server_add_full(s, id, interface, protocol, unique, name, FLX_DNS_CLASS_IN, FLX_DNS_TYPE_TXT, text, strlen(text), FLX_DEFAULT_TTL);
 }
 
-flxQueryJob* flx_query_job_ref(flxQueryJob *job) {
-    g_assert(job);
-    g_assert(job->ref >= 1);
-    job->ref++;
-    return job;
-}
-
-void flx_query_job_unref(flxQueryJob *job) {
-    g_assert(job);
-    g_assert(job->ref >= 1);
-    if (!(--job->ref))
-        g_free(job);
-}
-
-static gboolean query_job_exists(flxServer *s, gint interface, guchar protocol, flxQuery *q) {
-    flxPrioQueueNode *n;
-    g_assert(s);
-    g_assert(q);
-
-    for (n = s->query_job_queue->root; n; n = n->next)
-        if (flx_query_equal(&((flxQueryJobInstance*) n->data)->job->query, q))
-            return TRUE;
-
-    return FALSE;
-}
-
-static void post_query_job(flxServer *s, gint interface, guchar protocol, flxQueryJob *job) {
+void flx_server_send_query(flxServer *s, gint interface, guchar protocol, flxKey *k) {
     g_assert(s);
-    g_assert(job);
+    g_assert(k);
 
     if (interface <= 0) {
-        const flxInterface *i;
+        flxInterface *i;
+
+        for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next)
+            flx_interface_send_query(i, protocol, k);
         
-        for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->next)
-            post_query_job(s, i->index, protocol, job);
-    } else if (protocol == AF_UNSPEC) {
-        post_query_job(s, interface, AF_INET, job);
-        post_query_job(s, interface, AF_INET6, job);
     } else {
-        flxQueryJobInstance *i;
+        flxInterface *i;
 
-        if (query_job_exists(s, interface, protocol, &job->query))
+        if (!(i = flx_interface_monitor_get_interface(s->monitor, interface)))
             return;
-        
-        i = g_new(flxQueryJobInstance, 1);
-        i->job = flx_query_job_ref(job);
-        i->interface = interface;
-        i->protocol = protocol;
-        i->node = flx_prio_queue_put(s->query_job_queue, i);
-    }
-}
 
-void flx_server_post_query_job(flxServer *s, gint interface, guchar protocol, const GTimeVal *tv, const flxQuery *q) {
-    flxQueryJob *job;
-    g_assert(s);
-    g_assert(q);
-
-    job = flx_query_job_new();
-    job->query.name = g_strdup(q->name);
-    job->query.class = q->class;
-    job->query.type = q->type;
-    if (tv)
-        job->time = *tv;
-    post_query_job(s, interface, protocol, job);
-}
-
-void flx_server_drop_query_job(flxServer *s, gint interface, guchar protocol, const flxQuery *q) {
-    flxPrioQueueNode *n, *next;
-    g_assert(s);
-    g_assert(interface > 0);
-    g_assert(protocol != AF_UNSPEC);
-    g_assert(q);
-
-    for (n = s->query_job_queue->root; n; n = next) {
-        next = n->next;
-    
-        if (flx_query_equal(&((flxQueryJobInstance*) n->data)->job->query, q))
-            flx_server_remove_query_job_instance(s, n->data);
+        flx_interface_send_query(i, protocol, k);
     }
 }
-
-void flx_server_remove_query_job_instance(flxServer *s, flxQueryJobInstance *i) {
-    g_assert(s);
-    g_assert(i);
-    g_assert(i->node);
-
-    flx_prio_queue_remove(s->query_job_queue, i->node);
-    flx_query_job_unref(i->job);
-    g_free(i);
-}
-
-gboolean flx_query_equal(const flxQuery *a, const flxQuery *b) {
-    return strcmp(a->name, b->name) == 0 && a->type == b->type && a->class == b->class;
-}
-
index daaa815ebd967cc129f63b2f8a81494762ebb3b0..982143b038bf48d56222b76aa3a38efd5fb49c2d 100644 (file)
--- a/server.h
+++ b/server.h
@@ -1,51 +1,33 @@
 #ifndef fooflxserverhfoo
 #define fooflxserverhfoo
 
-struct _flxEntry;
 typedef struct _flxEntry flxEntry;
+typedef struct _flxResponseJob flxResponseJob;
 
 #include "flx.h"
 #include "iface.h"
 #include "prioq.h"
+#include "llist.h"
+#include "timeeventq.h"
 
 struct _flxEntry {
-    flxRecord rr;
+    flxRecord *record;
     gint id;
     gint interface;
     guchar protocol;
 
     gboolean unique;
 
-    flxEntry *next, *prev;
-    flxEntry *next_by_name, *prev_by_name;
-    flxEntry *next_by_id, *prev_by_id;
+    FLX_LLIST_FIELDS(flxEntry, entry);
+    FLX_LLIST_FIELDS(flxEntry, by_name);
+    FLX_LLIST_FIELDS(flxEntry, by_id);
 };
 
-typedef struct _flxQueryJob {
-    gint ref;
-    GTimeVal time;
-    flxQuery query;
-} flxQueryJob;
-
-typedef struct _flxQueryJobInstance {
-    flxPrioQueueNode *node;
-    flxQueryJob *job;
-    gint interface;
-    guchar protocol;
-} flxQueryJobInstance;
-
-typedef struct _flxResponseJob {
-    gint ref;
-    GTimeVal time;
-    flxRecord response;
-} flxResponseJob;
-
-typedef struct _flxResponseJobInstance {
-    flxPrioQueueNode *node;
-    flxResponseJob *job;
-    gint interface;
-    guchar protocol;
-} flxResponseJobInstance;
+struct _flxResponseJob {
+    flxTimeEvent *time_event;
+    flxRecord *record;
+    FLX_LLIST_FIELDS(flxResponseJob, response);
+};
 
 struct _flxServer {
     GMainContext *context;
@@ -56,25 +38,12 @@ struct _flxServer {
     GHashTable *rrset_by_id;
     GHashTable *rrset_by_name;
 
-    flxEntry *entries;
-
-    flxPrioQueue *query_job_queue;
-    flxPrioQueue *response_job_queue;
-
-    gint hinfo_rr_id;
+    FLX_LLIST_HEAD(flxEntry, entries);
 
+    flxTimeEventQueue *time_event_queue;
+    
     gchar *hostname;
 };
 
-flxQueryJob* flx_query_job_new(void);
-flxQueryJob* flx_query_job_ref(flxQueryJob *job);
-void flx_query_job_unref(flxQueryJob *job);
-
-void flx_server_post_query_job(flxServer *s, gint interface, guchar protocol, const GTimeVal *tv, const flxQuery *q);
-void flx_server_drop_query_job(flxServer *s, gint interface, guchar protocol, const flxQuery *q);
-
-void flx_server_remove_query_job_instance(flxServer *s, flxQueryJobInstance *i);
-
-gboolean flx_query_equal(const flxQuery *a, const flxQuery *b);
 
 #endif
diff --git a/timeeventq.c b/timeeventq.c
new file mode 100644 (file)
index 0000000..b3dd897
--- /dev/null
@@ -0,0 +1,144 @@
+#include "timeeventq.h"
+#include "util.h"
+
+static gint compare(gconstpointer _a, gconstpointer _b) {
+    const flxTimeEvent *a = _a,  *b = _b;
+
+    return flx_timeval_compare(&a->expiry, &b->expiry);
+}
+
+static gboolean prepare_func(GSource *source, gint *timeout) {
+    flxTimeEventQueue *q = (flxTimeEventQueue*) source;
+    flxTimeEvent *e;
+    GTimeVal now;
+
+    g_assert(source);
+    g_assert(timeout);
+
+    if (!q->prioq->root) {
+        *timeout = -1;
+        return FALSE;
+    }
+    
+    e = q->prioq->root->data;
+    g_assert(e);
+
+    g_source_get_current_time(source, &now);
+
+    if (flx_timeval_compare(&now, &e->expiry) >= 0) {
+        *timeout = -1;
+        return TRUE;
+    }
+
+    *timeout = (gint) (flx_timeval_diff(&e->expiry, &now)/1000);
+    
+    return FALSE;
+}
+
+static gboolean check_func(GSource *source) {
+    flxTimeEventQueue *q = (flxTimeEventQueue*) source;
+    flxTimeEvent *e;
+    GTimeVal now;
+
+    g_assert(source);
+
+    if (!q->prioq->root)
+        return FALSE;
+
+    e = q->prioq->root->data;
+    g_assert(e);
+
+    g_source_get_current_time(source, &now);
+    
+    return flx_timeval_compare(&now, &e->expiry) >= 0;
+}
+
+static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
+    flxTimeEventQueue *q = (flxTimeEventQueue*) source;
+    GTimeVal now;
+
+    g_assert(source);
+
+    g_source_get_current_time(source, &now);
+
+    while (q->prioq->root) {
+        flxTimeEvent *e = q->prioq->root->data;
+
+        if (flx_timeval_compare(&now, &e->expiry) < 0)
+            break;
+
+        g_assert(e->callback);
+        e->callback(e, e->userdata);
+    }
+
+    return TRUE;
+}
+
+flxTimeEventQueue* flx_time_event_queue_new(GMainContext *context) {
+    flxTimeEventQueue *q;
+
+    static GSourceFuncs source_funcs = {
+        prepare_func,
+        check_func,
+        dispatch_func,
+        NULL,
+        NULL,
+        NULL
+    };
+
+    q = (flxTimeEventQueue*) g_source_new(&source_funcs, sizeof(flxTimeEventQueue));
+    q->prioq = flx_prio_queue_new(compare);
+
+    g_source_attach(&q->source, context);
+    
+    return q;
+}
+
+void flx_time_event_queue_free(flxTimeEventQueue *q) {
+    g_assert(q);
+
+    while (q->prioq->root)
+        flx_time_event_queue_remove(q, q->prioq->root->data);
+    flx_prio_queue_free(q->prioq);
+
+    g_source_destroy(&q->source);
+    g_source_unref(&q->source);
+}
+
+flxTimeEvent* flx_time_event_queue_add(flxTimeEventQueue *q, const GTimeVal *timeval, void (*callback)(flxTimeEvent *e, void *userdata), void *userdata) {
+    flxTimeEvent *e;
+    
+    g_assert(q);
+    g_assert(timeval);
+    g_assert(callback);
+    g_assert(userdata);
+
+    e = g_new(flxTimeEvent, 1);
+    e->queue = q;
+    e->expiry = *timeval;
+    e->callback = callback;
+    e->userdata = userdata;
+
+    e->node = flx_prio_queue_put(q->prioq, e);
+    
+    return e;
+}
+
+void flx_time_event_queue_remove(flxTimeEventQueue *q, flxTimeEvent *e) {
+    g_assert(q);
+    g_assert(e);
+    g_assert(e->queue == q);
+
+    flx_prio_queue_remove(q->prioq, e->node);
+    g_free(e);
+}
+
+void flx_time_event_update(flxTimeEventQueue *q, flxTimeEvent *e, const GTimeVal *timeval) {
+    g_assert(q);
+    g_assert(e);
+    g_assert(e->queue == q);
+
+    e->expiry = *timeval;
+
+    flx_prio_queue_shuffle(q->prioq, e->node);
+}
diff --git a/timeeventq.h b/timeeventq.h
new file mode 100644 (file)
index 0000000..8fd5c02
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef footimeeventqhfoo
+#define footimeeventqhfoo
+
+typedef struct _flxTimeEventQueue flxTimeEventQueue;
+typedef struct _flxTimeEvent flxTimeEvent;
+
+#include "prioq.h"
+
+struct _flxTimeEvent {
+    flxTimeEventQueue *queue;
+    flxPrioQueueNode *node;
+    GTimeVal expiry;
+    void (*callback)(flxTimeEvent *e, void *userdata);
+    void *userdata;
+};
+
+struct _flxTimeEventQueue {
+    GSource source;
+    flxPrioQueue *prioq;
+};
+
+flxTimeEventQueue* flx_time_event_queue_new(GMainContext *context);
+void flx_time_event_queue_free(flxTimeEventQueue *q);
+
+flxTimeEvent* flx_time_event_queue_add(flxTimeEventQueue *q, const GTimeVal *timeval, void (*callback)(flxTimeEvent *e, void *userdata), void *userdata);
+void flx_time_event_queue_remove(flxTimeEventQueue *q, flxTimeEvent *e);
+
+void flx_time_event_update(flxTimeEventQueue *q, flxTimeEvent *e, const GTimeVal *timeval);
+
+#endif
diff --git a/util.c b/util.c
index 334a7990e4cbd1bc417f47fa7b9db5a5f4f808b6..62574ba524d83920bf9b8f448ef3f90deeae3987 100644 (file)
--- a/util.c
+++ b/util.c
@@ -24,3 +24,29 @@ gchar *flx_normalize_name(const gchar *s) {
     return g_strdup_printf("%s.", s);
 }
 
+gint flx_timeval_compare(const GTimeVal *a, const GTimeVal *b) {
+    g_assert(a);
+    g_assert(b);
+
+    if (a->tv_sec < b->tv_sec)
+        return -1;
+
+    if (a->tv_sec > b->tv_sec)
+        return 1;
+
+    if (a->tv_usec < b->tv_usec)
+        return -1;
+
+    if (a->tv_usec > b->tv_usec)
+        return 1;
+
+    return 0;
+}
+
+glong flx_timeval_diff(const GTimeVal *a, const GTimeVal *b) {
+    g_assert(a);
+    g_assert(b);
+    g_assert(flx_timeval_compare(a, b) >= 0);
+
+    return (a->tv_sec - b->tv_sec)*1000000 + a->tv_usec - b->tv_usec;
+}
diff --git a/util.h b/util.h
index a9d12e0b7a22f14adb0c8c5b86d019850ddfe543..9c3edd17a379930abf77f5be2666d78f153da10f 100644 (file)
--- a/util.h
+++ b/util.h
@@ -3,7 +3,10 @@
 
 #include <glib.h>
 
-gchar *flx_normalize_name(const gchar *s);
-gchar *flx_get_host_name(void);
+gchar *flx_normalize_name(const gchar *s); /* g_free() the result! */
+gchar *flx_get_host_name(void); /* g_free() the result! */
+
+gint flx_timeval_compare(const GTimeVal *a, const GTimeVal *b);
+glong flx_timeval_diff(const GTimeVal *a, const GTimeVal *b);
 
 #endif