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
--- /dev/null
+#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);
+}
#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
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
} 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);
}
}
}
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);
}
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);
}
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);
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;
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;
}
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;
}
}
-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;
}
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);
+}
#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;
};
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 {
flxAddress address;
flxInterface *interface;
- flxInterfaceAddress *next, *prev;
+
+ FLX_LLIST_FIELDS(flxInterfaceAddress, address);
gint rr_id;
};
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
--- /dev/null
+#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
#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;
}
GSource *source;
void (*callback) (flxNetlink *nl, struct nlmsghdr *n, gpointer userdata);
gpointer userdata;
- GSourceFuncs source_funcs;
};
-
static gboolean work(flxNetlink *nl) {
g_assert(nl);
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);
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));
#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);
#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);
}
/* 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);
q->last = n;
q->n_nodes++;
- shuffle_node(q, n);
+ flx_prio_queue_shuffle(q, n);
return 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;
}
flxPrioQueueNode *root, *last;
guint n_nodes;
- gint (*compare) (gpointer a, gpointer b);
+ gint (*compare) (gconstpointer a, gconstpointer b);
};
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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
#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, '.')))
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;
}
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);
}
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) {
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) {
}
}
-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;
-}
-
#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;
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
--- /dev/null
+#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);
+}
--- /dev/null
+#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
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;
+}
#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