]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9775: First round of integration of DHT into libblade, requires ongoing changes...
authorShane Bryldt <astaelan@gmail.com>
Mon, 9 Jan 2017 13:19:14 +0000 (13:19 +0000)
committerMike Jerris <mike@jerris.com>
Wed, 25 Jan 2017 20:59:38 +0000 (14:59 -0600)
17 files changed:
libs/libblade/src/blade_peer.c
libs/libblade/src/blade_stack.c
libs/libblade/src/include/blade.h
libs/libblade/src/include/blade_peer.h
libs/libblade/src/include/blade_stack.h
libs/libblade/test/Makefile.am
libs/libblade/test/bladec.c [new file with mode: 0644]
libs/libblade/test/testbuild.c
libs/libks/src/dht/ks_dht.c
libs/libks/src/dht/ks_dht.h [deleted file]
libs/libks/src/dht/ks_dht_endpoint.c
libs/libks/src/include/ks_dht-int.h [moved from libs/libks/src/dht/ks_dht-int.h with 99% similarity]
libs/libks/src/include/ks_dht.h
libs/libks/src/ks_dht.c [deleted file]
libs/libks/test/Makefile.am
libs/libks/test/nodeidgen.c [new file with mode: 0644]
libs/libks/test/testdht2.c

index e67e733b6b3ca864edec13f00ffd4f96d5d3dfc8..8bb96ae676f991ca35910b327685b7424c6b7686 100644 (file)
 
 #include "blade.h"
 
+#define KS_DHT_TPOOL_MIN 2
+#define KS_DHT_TPOOL_MAX 8
+#define KS_DHT_TPOOL_STACK (1024 * 256)
+#define KS_DHT_TPOOL_IDLE 10
+
 typedef enum {
        BP_NONE = 0,
-       BP_MYPOOL = (1 << 0)
+       BP_MYPOOL = (1 << 0),
+       BP_MYTPOOL = (1 << 1)
 } bppvt_flag_t;
 
 struct blade_peer_s {
        bppvt_flag_t flags;
        ks_pool_t *pool;
+       ks_thread_pool_t *tpool;
+       ks_dht_t *dht;
 };
 
 
@@ -60,33 +68,75 @@ KS_DECLARE(ks_status_t) blade_peer_destroy(blade_peer_t **bpP)
        flags = bp->flags;
        pool = bp->pool;
 
+       if (bp->dht) ks_dht_destroy(&bp->dht);
+       if (bp->tpool && (flags & BP_MYTPOOL)) ks_thread_pool_destroy(&bp->tpool);
+       
        ks_pool_free(bp->pool, &bp);
 
-       if (pool && (flags & BP_MYPOOL)) {
-               ks_pool_close(&pool);
-       }
+       if (pool && (flags & BP_MYPOOL)) ks_pool_close(&pool);
 
        return KS_STATUS_SUCCESS;
 }
 
-KS_DECLARE(ks_status_t) blade_peer_create(blade_peer_t **bpP, ks_pool_t *pool)
+KS_DECLARE(ks_status_t) blade_peer_create(blade_peer_t **bpP, ks_pool_t *pool, ks_thread_pool_t *tpool, ks_dht_nodeid_t *nodeid)
 {
        bppvt_flag_t newflags = BP_NONE;
        blade_peer_t *bp = NULL;
+       ks_dht_t *dht = NULL;
 
        if (!pool) {
                newflags |= BP_MYPOOL;
                ks_pool_open(&pool);
+               ks_assert(pool);
+       }
+       if (!tpool) {
+               newflags |= BP_MYTPOOL;
+               ks_thread_pool_create(&tpool, BLADE_PEER_TPOOL_MIN, BLADE_PEER_TPOOL_MAX, BLADE_PEER_TPOOL_STACK, KS_PRI_NORMAL, BLADE_PEER_TPOOL_IDLE);
+               ks_assert(tpool);
        }
+       ks_dht_create(&dht, pool, tpool, nodeid);
+       ks_assert(dht);
 
        bp = ks_pool_alloc(pool, sizeof(*bp));
-       bp->pool = pool;
        bp->flags = newflags;
+       bp->pool = pool;
+       bp->tpool = tpool;
+       bp->dht = dht;
        *bpP = bp;
 
        return KS_STATUS_SUCCESS;
 }
 
+KS_DECLARE(ks_dht_nodeid_t *) blade_peer_myid(blade_peer_t *bp)
+{
+       ks_assert(bp);
+       ks_assert(bp->dht);
+
+       return &bp->dht->nodeid;
+}
+
+KS_DECLARE(void) blade_peer_autoroute(blade_peer_t *bp, ks_bool_t autoroute, ks_port_t port)
+{
+       ks_assert(bp);
+
+       ks_dht_autoroute(bp->dht, autoroute, port);
+}
+
+KS_DECLARE(ks_status_t) blade_peer_bind(blade_peer_t *bp, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint)
+{
+       ks_assert(bp);
+       ks_assert(addr);
+
+       return ks_dht_bind(bp->dht, addr, endpoint);
+}
+
+KS_DECLARE(void) blade_peer_pulse(blade_peer_t *bp, int32_t timeout)
+{
+       ks_assert(bp);
+       ks_assert(timeout >= 0);
+
+       ks_dht_pulse(bp->dht, timeout);
+}
 
 /* For Emacs:
  * Local Variables:
index 9dc4ba2f36407e5aca7d465cd5bb6c44288dfd13..7e4bcf01d9ce19f704912081add1e0bb5f33ddbb 100644 (file)
 
 typedef enum {
        BH_NONE = 0,
-       BH_MYPOOL = (1 << 0)
+       BH_MYPOOL = (1 << 0),
+       BH_MYTPOOL = (1 << 1)
 } bhpvt_flag_t;
 
 struct blade_handle_s {
-       ks_pool_t *pool;
        bhpvt_flag_t flags;
+       ks_pool_t *pool;
+       ks_thread_pool_t *tpool;
        blade_peer_t *peer;
 };
 
@@ -62,6 +64,7 @@ KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP)
        pool = bh->pool;
 
        blade_peer_destroy(&bh->peer);
+    if (bh->tpool && (flags & BH_MYTPOOL)) ks_thread_pool_destroy(&bh->tpool);
 
        ks_pool_free(bh->pool, &bh);
 
@@ -72,26 +75,78 @@ KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP)
        return KS_STATUS_SUCCESS;
 }
 
-KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *pool)
+KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *pool, ks_thread_pool_t *tpool, const char *nodeid)
 {
        bhpvt_flag_t newflags = BH_NONE;
        blade_handle_t *bh = NULL;
+       ks_dht_nodeid_t nid;
+
+       ks_assert(nodeid);
+       ks_assert(strlen(nodeid) == (KS_DHT_NODEID_SIZE * 2));
 
        if (!pool) {
                newflags |= BH_MYPOOL;
                ks_pool_open(&pool);
        }
-
+    if (!tpool) {
+               newflags |= BH_MYTPOOL;
+               ks_thread_pool_create(&tpool, BLADE_HANDLE_TPOOL_MIN, BLADE_HANDLE_TPOOL_MAX, BLADE_HANDLE_TPOOL_STACK, KS_PRI_NORMAL, BLADE_HANDLE_TPOOL_IDLE);
+               ks_assert(tpool);
+       }
+       
        bh = ks_pool_alloc(pool, sizeof(*bh));
-       bh->pool = pool;
        bh->flags = newflags;
-       blade_peer_create(&bh->peer, bh->pool);
+       bh->pool = pool;
+       bh->tpool = tpool;
+       ks_dht_dehex(nid.id, nodeid, KS_DHT_NODEID_SIZE);
+       blade_peer_create(&bh->peer, bh->pool, bh->tpool, &nid);
 
        *bhP = bh;
 
        return KS_STATUS_SUCCESS;
 }
 
+KS_DECLARE(void) blade_handle_myid(blade_handle_t *bh, char *buffer)
+{
+       ks_dht_nodeid_t *nodeid = NULL;
+
+       ks_assert(bh);
+       ks_assert(bh->peer);
+
+       nodeid = blade_peer_myid(bh->peer);
+       ks_dht_hex(nodeid->id, buffer, KS_DHT_NODEID_SIZE);
+}
+
+KS_DECLARE(void) blade_handle_autoroute(blade_handle_t *bh, ks_bool_t autoroute, ks_port_t port)
+{
+       ks_assert(bh);
+       ks_assert(bh->peer);
+
+       blade_peer_autoroute(bh->peer, autoroute, port);
+}
+
+KS_DECLARE(ks_status_t) blade_handle_bind(blade_handle_t *bh, const char *ip, ks_port_t port, ks_dht_endpoint_t **endpoint)
+{
+       ks_sockaddr_t addr;
+       int family = AF_INET;
+       
+       ks_assert(bh);
+       ks_assert(ip);
+       ks_assert(port);
+
+       if (ip[1] != '.' && ip[2] != '.' && ip[3] != '.') family = AF_INET6;
+       
+       ks_addr_set(&addr, ip, port, family);
+       return blade_peer_bind(bh->peer, &addr, endpoint);
+}
+
+KS_DECLARE(void) blade_handle_pulse(blade_handle_t *bh, int32_t timeout)
+{
+       ks_assert(bh);
+       ks_assert(timeout >= 0);
+
+       blade_peer_pulse(bh->peer, timeout);
+}
 
 
 /* For Emacs:
index 4fe1dac783573b5b143f5813ff83f0f5744cd0d7..8df818f7b9afd07aaaf0baa1d722a49b83f0b970 100644 (file)
@@ -34,6 +34,7 @@
 #ifndef _BLADE_H_
 #define _BLADE_H_
 #include <ks.h>
+#include <ks_dht.h>
 #include <sodium.h>
 #include "blade_types.h"
 #include "blade_stack.h"
index e7db60230b06cdf7832399a7c4a83660963c34e4..3c0bb5925dbf2139d082d63fdf9c822468bdb979 100644 (file)
 #define _BPCP_H_
 #include <blade.h>
 
+#define BLADE_PEER_TPOOL_MIN 2
+#define BLADE_PEER_TPOOL_MAX 8
+#define BLADE_PEER_TPOOL_STACK (1024 * 256)
+#define BLADE_PEER_TPOOL_IDLE 10
+
 KS_BEGIN_EXTERN_C
-KS_DECLARE(ks_status_t) blade_peer_create(blade_peer_t **bpP, ks_pool_t *pool);
+KS_DECLARE(ks_status_t) blade_peer_create(blade_peer_t **bpP, ks_pool_t *pool, ks_thread_pool_t *tpool, ks_dht_nodeid_t *nodeid);
 KS_DECLARE(ks_status_t) blade_peer_destroy(blade_peer_t **bpP);
+KS_DECLARE(ks_dht_nodeid_t *) blade_peer_myid(blade_peer_t *bp);
+KS_DECLARE(void) blade_peer_autoroute(blade_peer_t *bp, ks_bool_t autoroute, ks_port_t port);
+KS_DECLARE(ks_status_t) blade_peer_bind(blade_peer_t *bp, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint);
+KS_DECLARE(void) blade_peer_pulse(blade_peer_t *bp, int32_t timeout);
 KS_END_EXTERN_C
 
 #endif
index 8fdec5f0c21ad1d31126e41ce439fa205abef115..a5744e459ff758c00d4f7e412c153dd93a0602cd 100644 (file)
 #define _BLADE_STACK_H_
 #include <blade.h>
 
+#define BLADE_HANDLE_TPOOL_MIN 2
+#define BLADE_HANDLE_TPOOL_MAX 8
+#define BLADE_HANDLE_TPOOL_STACK (1024 * 256)
+#define BLADE_HANDLE_TPOOL_IDLE 10
+
 KS_BEGIN_EXTERN_C
 KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP);
-KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *pool);
+KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP, ks_pool_t *pool, ks_thread_pool_t *tpool, const char *nodeid);
+KS_DECLARE(void) blade_handle_myid(blade_handle_t *bh, char *buffer);
+KS_DECLARE(void) blade_handle_autoroute(blade_handle_t *bh, ks_bool_t autoroute, ks_port_t port);
+KS_DECLARE(ks_status_t) blade_handle_bind(blade_handle_t *bh, const char *ip, ks_port_t port, ks_dht_endpoint_t **endpoint);
+KS_DECLARE(void) blade_handle_pulse(blade_handle_t *bh, int32_t timeout);
 KS_END_EXTERN_C
 
 #endif
index 37e67e04607254bc1363937d8fbc095d5ddb227f..d577b955073e4feb8c588b2b7e5793b3a557300a 100644 (file)
@@ -7,6 +7,11 @@ testbuild_SOURCES = testbuild.c tap.c
 testbuild_CFLAGS = $(AM_CFLAGS)
 testbuild_LDADD = $(TEST_LDADD)
 
+check_PROGRAMS += bladec
+bladec_SOURCES = bladec.c tap.c
+bladec_CFLAGS = $(AM_CFLAGS)
+bladec_LDADD = $(TEST_LDADD)
+
 
 TESTS=$(check_PROGRAMS)
 
diff --git a/libs/libblade/test/bladec.c b/libs/libblade/test/bladec.c
new file mode 100644 (file)
index 0000000..f03fe52
--- /dev/null
@@ -0,0 +1,204 @@
+#include "blade.h"
+#include "tap.h"
+
+#ifdef _WIN32
+#define STDIO_FD(_fs) _fileno(_fs)
+#define READ(_fd, _buffer, _count) _read(_fd, _buffer, _count)
+#else
+#define STDIO_FD(_fs) fileno(_fs)
+#define READ(_fd, _buffer, _count) read(_fd, _buffer, _count)
+#endif
+
+#define CONSOLE_INPUT_MAX 512
+
+ks_bool_t g_shutdown = KS_FALSE;
+char g_console_input[CONSOLE_INPUT_MAX];
+size_t g_console_input_length = 0;
+size_t g_console_input_eol = 0;
+
+void loop(blade_handle_t *bh);
+void process_console_input(blade_handle_t *bh, char *line);
+
+typedef void (*command_callback)(blade_handle_t *bh, char *args);
+
+struct command_def_s {
+       const char *cmd;
+       command_callback callback;
+};
+
+void command_test(blade_handle_t *bh, char *args);
+void command_quit(blade_handle_t *bh, char *args);
+void command_myid(blade_handle_t *bh, char *args);
+void command_bind(blade_handle_t *bh, char *args);
+
+static const struct command_def_s command_defs[] = {
+       { "test", command_test },
+       { "quit", command_quit },
+       { "myid", command_myid },
+       { "bind", command_bind },
+       
+       { NULL, NULL }
+};
+
+
+int main(int argc, char **argv)
+{
+       blade_handle_t *bh = NULL;
+       const char *nodeid;
+
+       ks_assert(argc >= 2);
+
+       nodeid = argv[1];
+
+       ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG);
+       
+       blade_init();
+
+       blade_handle_create(&bh, NULL, NULL, nodeid);
+
+       blade_handle_autoroute(bh, KS_TRUE, KS_DHT_DEFAULT_PORT);
+
+       loop(bh);
+       
+       blade_handle_destroy(&bh);
+
+       blade_shutdown();
+
+       return 0;
+}
+
+void buffer_console_input(void)
+{
+       ssize_t bytes = 0;
+       struct pollfd poll[1];
+       poll[0].fd = STDIO_FD(stdin);
+       poll[0].events = POLLIN | POLLERR;
+
+       if (ks_poll(poll, 1, 1) > 0) {
+               if (poll[0].revents & POLLIN) {
+                       if ((bytes = READ(poll[0].fd, g_console_input + g_console_input_length, CONSOLE_INPUT_MAX - g_console_input_length)) <= 0) {
+                               // @todo error
+                               return;
+                       }
+                       g_console_input_length += bytes;
+               }
+       }
+}
+
+void loop(blade_handle_t *bh)
+{
+       while (!g_shutdown) {
+               ks_bool_t eol = KS_FALSE;
+               buffer_console_input();
+
+               for (; g_console_input_eol < g_console_input_length; ++g_console_input_eol) {
+                       char c = g_console_input[g_console_input_eol];
+                       if (c == '\r' || c == '\n') {
+                               eol = KS_TRUE;
+                               break;
+                       }
+               }
+               if (eol) {
+                       g_console_input[g_console_input_eol] = '\0';
+                       process_console_input(bh, g_console_input);
+                       g_console_input_eol++;
+                       for (; g_console_input_eol < g_console_input_length; ++g_console_input_eol) {
+                               char c = g_console_input[g_console_input_eol];
+                               if (c != '\r' && c != '\n') break;
+                       }
+                       if (g_console_input_eol == g_console_input_length) g_console_input_eol = g_console_input_length = 0;
+                       else {
+                               memcpy(g_console_input, g_console_input + g_console_input_eol, g_console_input_length - g_console_input_eol);
+                               g_console_input_length -= g_console_input_eol;
+                               g_console_input_eol = 0;
+                       }
+               }
+               if (g_console_input_length == CONSOLE_INPUT_MAX) {
+                       // @todo lines must not exceed 512 bytes, treat as error and ignore buffer until next new line?
+                       ks_assert(0);
+               }
+               blade_handle_pulse(bh, 1);
+       }
+}
+
+void parse_argument(char **input, char **arg, char terminator)
+{
+       char *tmp;
+       
+       ks_assert(input);
+       ks_assert(*input);
+       ks_assert(arg);
+
+       tmp = *input;
+       *arg = tmp;
+
+       while (*tmp && *tmp != terminator) ++tmp;
+       if (*tmp == terminator) {
+               *tmp = '\0';
+               ++tmp;
+       }
+       *input = tmp;
+}
+
+void process_console_input(blade_handle_t *bh, char *line)
+{
+       char *args = line;
+       char *cmd = NULL;
+       ks_bool_t found = KS_FALSE;
+       
+       ks_log(KS_LOG_DEBUG, "Output: %s\n", line);
+
+       parse_argument(&args, &cmd, ' ');
+       
+       ks_log(KS_LOG_DEBUG, "Command: %s, Args: %s\n", cmd, args);
+
+       for (int32_t index = 0; command_defs[index].cmd; ++index) {
+               if (!strcmp(command_defs[index].cmd, cmd)) {
+                       found = KS_TRUE;
+                       command_defs[index].callback(bh, args);
+               }
+       }
+       if (!found) ks_log(KS_LOG_INFO, "Command '%s' unknown.\n", cmd);
+}
+
+void command_test(blade_handle_t *bh, char *args)
+{
+       ks_log(KS_LOG_DEBUG, "Hello World!\n");
+}
+
+void command_quit(blade_handle_t *bh, char *args)
+{
+       ks_assert(bh);
+       ks_assert(args);
+       
+       ks_log(KS_LOG_DEBUG, "Shutting down\n");
+       g_shutdown = KS_TRUE;
+}
+
+void command_myid(blade_handle_t *bh, char *args)
+{
+       char buf[KS_DHT_NODEID_SIZE * 2 + 1];
+
+       ks_assert(bh);
+       ks_assert(args);
+
+       blade_handle_myid(bh, buf);
+
+       ks_log(KS_LOG_INFO, "%s\n", buf);
+}
+
+void command_bind(blade_handle_t *bh, char *args)
+{
+       char *ip = NULL;
+       char *port = NULL;
+       ks_port_t p;
+
+       ks_assert(args);
+
+       parse_argument(&args, &ip, ' ');
+       parse_argument(&args, &port, ' ');
+
+       p = atoi(port); // @todo use strtol for error handling
+
+       blade_handle_bind(bh, ip, p, NULL);
+}
index 4af08b1982ec0b1a791a8eea1476938b858f75b7..29998fa1a70e6068a1cfff4768a88683ced59c04 100644 (file)
@@ -11,7 +11,7 @@ int main(void)
 
        plan(1);
 
-       status = blade_handle_create(&bh, NULL);
+       status = blade_handle_create(&bh, NULL, NULL);
        status = blade_handle_destroy(&bh);
 
        ok(status == KS_STATUS_SUCCESS);
index 4cffb7cef73d7941a9a038d3d0b95830e8ffe28a..a70adef12ba3ea85241248f36543e1fc73a78bbe 100644 (file)
@@ -8,13 +8,14 @@ void ks_dht_transaction_destructor(void *ptr) { ks_dht_transaction_destroy((ks_d
 
 void ks_dht_storageitem_destructor(void *ptr) { ks_dht_storageitem_destroy((ks_dht_storageitem_t **)&ptr); }
 
-KS_DECLARE(ks_status_t) ks_dht_create(ks_dht_t **dht, ks_pool_t *pool, ks_thread_pool_t *tpool)
+KS_DECLARE(ks_status_t) ks_dht_create(ks_dht_t **dht, ks_pool_t *pool, ks_thread_pool_t *tpool, ks_dht_nodeid_t *nodeid)
 {
        ks_bool_t pool_alloc = !pool;
        ks_dht_t *d = NULL;
        ks_status_t ret = KS_STATUS_SUCCESS;
 
        ks_assert(dht);
+       ks_assert(nodeid);
 
        *dht = NULL;
 
@@ -49,6 +50,8 @@ KS_DECLARE(ks_status_t) ks_dht_create(ks_dht_t **dht, ks_pool_t *pool, ks_thread
                ks_assert(d->tpool);
        }
 
+       d->nodeid = *nodeid;
+
        /**
         * Default autorouting to disabled.
         */
@@ -366,7 +369,7 @@ KS_DECLARE(ks_status_t) ks_dht_autoroute_check(ks_dht_t *dht, const ks_sockaddr_
        if (!ep && dht->autoroute) {
                ks_sockaddr_t addr;
                if ((ret = ks_addr_set(&addr, ip, dht->autoroute_port, raddr->family)) != KS_STATUS_SUCCESS) return ret;
-               if ((ret = ks_dht_bind(dht, NULL, &addr, &ep)) != KS_STATUS_SUCCESS) return ret;
+               if ((ret = ks_dht_bind(dht, &addr, &ep)) != KS_STATUS_SUCCESS) return ret;
        }
 
        /**
@@ -419,7 +422,7 @@ KS_DECLARE(void) ks_dht_register_error(ks_dht_t *dht, const char *value, ks_dht_
 }
 
 
-KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_dht_nodeid_t *nodeid, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint)
+KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint)
 {
        ks_socket_t sock = KS_SOCK_INVALID;
        ks_dht_endpoint_t *ep = NULL;
@@ -466,7 +469,7 @@ KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_dht_nodeid_t *nodeid
        /**
         * Allocate the endpoint to track the local socket.
         */
-       ks_dht_endpoint_create(&ep, dht->pool, nodeid, addr, sock);
+       ks_dht_endpoint_create(&ep, dht->pool, addr, sock);
        ks_assert(ep);
 
        /**
@@ -506,24 +509,24 @@ KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_dht_nodeid_t *nodeid
        if (ep->addr.family == AF_INET) {
                if (!dht->rt_ipv4 && (ret = ks_dhtrt_initroute(&dht->rt_ipv4, dht, dht->pool)) != KS_STATUS_SUCCESS) goto done;
                if ((ret = ks_dhtrt_create_node(dht->rt_ipv4,
-                                                                               ep->nodeid,
+                                                                               dht->nodeid,
                                                                                KS_DHT_LOCAL,
                                                                                ep->addr.host,
                                                                                ep->addr.port,
                                                                                KS_DHTRT_CREATE_DEFAULT,
-                                                                               &ep->node)) != KS_STATUS_SUCCESS) goto done;
+                                                                               &dht->node)) != KS_STATUS_SUCCESS) goto done;
        } else {
                if (!dht->rt_ipv6 && (ret = ks_dhtrt_initroute(&dht->rt_ipv6, dht, dht->pool)) != KS_STATUS_SUCCESS) goto done;
                if ((ret = ks_dhtrt_create_node(dht->rt_ipv6,
-                                                                               ep->nodeid,
+                                                                               dht->nodeid,
                                                                                KS_DHT_LOCAL,
                                                                                ep->addr.host,
                                                                                ep->addr.port,
                                                                                KS_DHTRT_CREATE_DEFAULT,
-                                                                               &ep->node)) != KS_STATUS_SUCCESS) goto done;
+                                                                               &dht->node)) != KS_STATUS_SUCCESS) goto done;
        }
        /**
-        * Do not release the ep->node, keep it alive until cleanup
+        * Do not release the dht->node, keep it alive until cleanup
         */
 
        /**
@@ -788,6 +791,19 @@ KS_DECLARE(char *) ks_dht_hex(const uint8_t *data, char *buffer, ks_size_t len)
        return buffer;
 }
 
+KS_DECLARE(uint8_t *) ks_dht_dehex(uint8_t *data, const char *buffer, ks_size_t len)
+{
+       const char *t = buffer;
+       
+       ks_assert(data);
+       ks_assert(buffer);
+       ks_assert(!(len & 1));
+
+       for (int i = 0; i < len; ++i, t += 2) sscanf(t, "%2hhx", &data[i]);
+       
+       return data;
+}
+
 KS_DECLARE(void) ks_dht_utility_nodeid_xor(ks_dht_nodeid_t *dest, ks_dht_nodeid_t *src1, ks_dht_nodeid_t *src2)
 {
        ks_assert(dest);
@@ -1361,7 +1377,7 @@ KS_DECLARE(ks_status_t) ks_dht_query_setup(ks_dht_t *dht,
 
        if (args) *args = a;
 
-       ben_dict_set(a, ben_blob("id", 2), ben_blob(ep->nodeid.id, KS_DHT_NODEID_SIZE));
+       ben_dict_set(a, ben_blob("id", 2), ben_blob(dht->nodeid.id, KS_DHT_NODEID_SIZE));
 
        *message = msg;
 
@@ -1414,7 +1430,7 @@ KS_DECLARE(ks_status_t) ks_dht_response_setup(ks_dht_t *dht,
 
        if (args) *args = r;
 
-       ben_dict_set(r, ben_blob("id", 2), ben_blob(ep->nodeid.id, KS_DHT_NODEID_SIZE));
+       ben_dict_set(r, ben_blob("id", 2), ben_blob(dht->nodeid.id, KS_DHT_NODEID_SIZE));
 
        *message = msg;
 
@@ -1546,7 +1562,7 @@ KS_DECLARE(ks_status_t) ks_dht_process_query(ks_dht_t *dht, ks_dht_message_t *me
        message->args_id = *id;
 
        ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(id->id, id_buf, KS_DHT_NODEID_SIZE));
-       if ((ret = ks_dhtrt_create_node(message->endpoint->node->table,
+       if ((ret = ks_dhtrt_create_node(message->endpoint->addr.family == AF_INET ? dht->rt_ipv4 : dht->rt_ipv6,
                                                                        *id,
                                                                        KS_DHT_REMOTE,
                                                                        message->raddr.host,
@@ -1620,7 +1636,7 @@ KS_DECLARE(ks_status_t) ks_dht_process_response(ks_dht_t *dht, ks_dht_message_t
        message->args_id = *id;
 
        ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(id->id, id_buf, KS_DHT_NODEID_SIZE));
-       if ((ret = ks_dhtrt_create_node(message->endpoint->node->table,
+       if ((ret = ks_dhtrt_create_node(message->endpoint->addr.family == AF_INET ? dht->rt_ipv4 : dht->rt_ipv6,
                                                                        *id,
                                                                        KS_DHT_REMOTE,
                                                                        message->raddr.host,
@@ -1629,7 +1645,7 @@ KS_DECLARE(ks_status_t) ks_dht_process_response(ks_dht_t *dht, ks_dht_message_t
                                                                        &node)) != KS_STATUS_SUCCESS) goto done;
        
        ks_log(KS_LOG_DEBUG, "Touching node %s\n", ks_dht_hex(id->id, id_buf, KS_DHT_NODEID_SIZE));
-       if ((ret = ks_dhtrt_touch_node(message->endpoint->node->table, *id)) != KS_STATUS_SUCCESS) goto done;
+       if ((ret = ks_dhtrt_touch_node(message->endpoint->addr.family == AF_INET ? dht->rt_ipv4 : dht->rt_ipv6, *id)) != KS_STATUS_SUCCESS) goto done;
 
        
        tid = (uint32_t *)message->transactionid;
@@ -2292,7 +2308,7 @@ KS_DECLARE(ks_status_t) ks_dht_query_findnode(ks_dht_t *dht, ks_dht_job_t *job)
 
        ben_dict_set(a, ben_blob("target", 6), ben_blob(job->query_target.id, KS_DHT_NODEID_SIZE));
        // Only request both v4 and v6 if we have both interfaces bound and are looking for our own node id, aka bootstrapping
-       if (dht->rt_ipv4 && dht->rt_ipv6 && !memcmp(message->endpoint->nodeid.id, job->query_target.id, KS_DHT_NODEID_SIZE)) {
+       if (dht->rt_ipv4 && dht->rt_ipv6 && !memcmp(dht->nodeid.id, job->query_target.id, KS_DHT_NODEID_SIZE)) {
                struct bencode *want = ben_list();
                ben_list_append_str(want, "n4");
                ben_list_append_str(want, "n6");
diff --git a/libs/libks/src/dht/ks_dht.h b/libs/libks/src/dht/ks_dht.h
deleted file mode 100644 (file)
index 3652c47..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-#ifndef KS_DHT_H
-#define KS_DHT_H
-
-#include "ks.h"
-#include "ks_bencode.h"
-#include "sodium.h"
-
-KS_BEGIN_EXTERN_C
-
-
-#define KS_DHT_DEFAULT_PORT 5309
-
-#define KS_DHT_TPOOL_MIN 2
-#define KS_DHT_TPOOL_MAX 8
-#define KS_DHT_TPOOL_STACK (1024 * 256)
-#define KS_DHT_TPOOL_IDLE 10
-
-#define KS_DHT_DATAGRAM_BUFFER_SIZE 1000
-
-//#define KS_DHT_RECV_BUFFER_SIZE 0xFFFF
-
-#define KS_DHT_NODEID_SIZE 20
-
-#define KS_DHT_RESPONSE_NODES_MAX_SIZE 8
-
-#define KS_DHT_MESSAGE_TRANSACTIONID_MAX_SIZE 20
-#define KS_DHT_MESSAGE_TYPE_MAX_SIZE 20
-#define KS_DHT_MESSAGE_QUERY_MAX_SIZE 20
-#define KS_DHT_MESSAGE_ERROR_MAX_SIZE 256
-
-#define KS_DHT_TRANSACTION_EXPIRATION 10
-#define KS_DHT_TRANSACTIONS_PULSE 1
-
-#define KS_DHT_SEARCH_RESULTS_MAX_SIZE 8 // @todo replace with KS_DHTRT_BUCKET_SIZE
-
-#define KS_DHT_STORAGEITEM_PKEY_SIZE crypto_sign_PUBLICKEYBYTES
-#define KS_DHT_STORAGEITEM_SKEY_SIZE crypto_sign_SECRETKEYBYTES
-#define KS_DHT_STORAGEITEM_SALT_MAX_SIZE 64
-#define KS_DHT_STORAGEITEM_SIGNATURE_SIZE crypto_sign_BYTES
-#define KS_DHT_STORAGEITEM_EXPIRATION 7200
-#define KS_DHT_STORAGEITEM_KEEPALIVE 300
-#define KS_DHT_STORAGEITEMS_PULSE 10
-
-#define KS_DHT_TOKEN_SIZE SHA_DIGEST_LENGTH
-#define KS_DHT_TOKEN_EXPIRATION 300
-#define KS_DHT_TOKENS_PULSE 1
-
-#define  KS_DHTRT_MAXQUERYSIZE 20
-
-typedef struct ks_dht_s ks_dht_t;
-typedef struct ks_dht_datagram_s ks_dht_datagram_t;
-typedef struct ks_dht_job_s ks_dht_job_t;
-typedef struct ks_dht_nodeid_s ks_dht_nodeid_t;
-typedef struct ks_dht_token_s ks_dht_token_t;
-typedef struct ks_dht_storageitem_pkey_s ks_dht_storageitem_pkey_t;
-typedef struct ks_dht_storageitem_skey_s ks_dht_storageitem_skey_t;
-typedef struct ks_dht_storageitem_signature_s ks_dht_storageitem_signature_t;
-typedef struct ks_dht_message_s ks_dht_message_t;
-typedef struct ks_dht_endpoint_s ks_dht_endpoint_t;
-typedef struct ks_dht_transaction_s ks_dht_transaction_t;
-typedef struct ks_dht_search_s ks_dht_search_t;
-typedef struct ks_dht_publish_s ks_dht_publish_t;
-typedef struct ks_dht_distribute_s ks_dht_distribute_t;
-typedef struct ks_dht_node_s ks_dht_node_t;
-typedef struct ks_dhtrt_routetable_s ks_dhtrt_routetable_t;
-typedef struct ks_dhtrt_querynodes_s ks_dhtrt_querynodes_t;
-typedef struct ks_dht_storageitem_s ks_dht_storageitem_t;
-
-
-typedef ks_status_t (*ks_dht_job_callback_t)(ks_dht_t *dht, ks_dht_job_t *job);
-typedef ks_status_t (*ks_dht_message_callback_t)(ks_dht_t *dht, ks_dht_message_t *message);
-//typedef ks_status_t (*ks_dht_search_callback_t)(ks_dht_t *dht, ks_dht_search_t *search);
-typedef ks_status_t (*ks_dht_storageitem_callback_t)(ks_dht_t *dht, ks_dht_storageitem_t *item);
-
-
-struct ks_dht_datagram_s {
-       ks_pool_t *pool;
-       ks_dht_t *dht;
-       ks_dht_endpoint_t *endpoint;
-       ks_sockaddr_t raddr;
-       uint8_t buffer[KS_DHT_DATAGRAM_BUFFER_SIZE];
-       ks_size_t buffer_length;
-};
-
-/**
- * Note: This must remain a structure for casting from raw data
- */
-struct ks_dht_nodeid_s {
-       uint8_t id[KS_DHT_NODEID_SIZE];
-};
-
-enum ks_afflags_t { ifv4=AF_INET, ifv6=AF_INET6, ifboth=AF_INET+AF_INET6};
-enum ks_dht_nodetype_t { KS_DHT_REMOTE=0x01, 
-                                                KS_DHT_LOCAL=0x02, 
-                                                KS_DHT_BOTH=KS_DHT_REMOTE+KS_DHT_LOCAL };
-
-enum ks_create_node_flags_t { 
-                                                KS_DHTRT_CREATE_DEFAULT=0,
-                                                KS_DHTRT_CREATE_PING,
-                                                KS_DHTRT_CREATE_TOUCH 
-};             
-                               
-struct ks_dht_node_s {
-    ks_dht_nodeid_t  nodeid;
-    ks_sockaddr_t    addr;
-    enum ks_dht_nodetype_t type;               /* local or remote */
-    ks_dhtrt_routetable_t* table;
-    ks_rwl_t        *reflock;          
-};
-
-struct ks_dht_token_s {
-       uint8_t token[KS_DHT_TOKEN_SIZE];
-};
-
-enum ks_dht_job_state_t {
-       KS_DHT_JOB_STATE_QUERYING,
-       KS_DHT_JOB_STATE_RESPONDING,
-       KS_DHT_JOB_STATE_EXPIRING,
-       KS_DHT_JOB_STATE_COMPLETING,
-};
-
-enum ks_dht_job_result_t {
-       KS_DHT_JOB_RESULT_SUCCESS = 0,
-       KS_DHT_JOB_RESULT_EXPIRED,
-       KS_DHT_JOB_RESULT_ERROR,
-       KS_DHT_JOB_RESULT_FAILURE,
-};
-
-struct ks_dht_job_s {
-       ks_pool_t *pool;
-       ks_dht_t *dht;
-       ks_dht_job_t *next;
-
-       enum ks_dht_job_state_t state;
-       enum ks_dht_job_result_t result;
-
-       ks_sockaddr_t raddr; // will obtain local endpoint node id when creating message using raddr
-       int32_t attempts;
-
-       //enum ks_dht_job_type_t type;
-       ks_dht_job_callback_t query_callback;
-       ks_dht_job_callback_t finish_callback;
-
-       void *data;
-       ks_dht_message_t *response;
-
-       // job specific query parameters
-       ks_dht_nodeid_t query_target;
-       struct bencode *query_salt;
-       int64_t query_cas;
-       ks_dht_token_t query_token;
-       ks_dht_storageitem_t *query_storageitem;
-
-       // error response parameters
-       int64_t error_code;
-       struct bencode *error_description;
-       
-       // job specific response parameters
-       ks_dht_node_t *response_id;
-       ks_dht_node_t *response_nodes[KS_DHT_RESPONSE_NODES_MAX_SIZE];
-       ks_size_t response_nodes_count;
-       ks_dht_node_t *response_nodes6[KS_DHT_RESPONSE_NODES_MAX_SIZE];
-       ks_size_t response_nodes6_count;
-       
-       ks_dht_token_t response_token;
-       int64_t response_seq;
-       ks_bool_t response_hasitem;
-       ks_dht_storageitem_t *response_storageitem;
-};
-
-struct ks_dhtrt_routetable_s {
-    void*       internal;                       
-    ks_pool_t*  pool;                           
-    ks_logger_t logger;
-};
-
-struct ks_dhtrt_querynodes_s {
-    ks_dht_nodeid_t nodeid;                   /* in: id to query                   */
-    enum ks_afflags_t family;                 /* in: AF_INET or AF_INET6 or both   */
-    enum ks_dht_nodetype_t type;              /* remote, local, or  both           */
-    uint8_t        max;                       /* in: maximum to return             */
-    uint8_t        count;                     /* out: number returned              */
-    ks_dht_node_t* nodes[ KS_DHTRT_MAXQUERYSIZE ]; /* out: array of peers (ks_dht_node_t* nodes[incount]) */
-};
-
-struct ks_dht_storageitem_pkey_s {
-       uint8_t key[KS_DHT_STORAGEITEM_PKEY_SIZE];
-};
-
-struct ks_dht_storageitem_skey_s {
-       uint8_t key[KS_DHT_STORAGEITEM_SKEY_SIZE];
-};
-
-struct ks_dht_storageitem_signature_s {
-       uint8_t sig[KS_DHT_STORAGEITEM_SIGNATURE_SIZE];
-};
-
-struct ks_dht_message_s {
-       ks_pool_t *pool;
-       ks_dht_endpoint_t *endpoint;
-       ks_sockaddr_t raddr;
-       struct bencode *data;
-       uint8_t transactionid[KS_DHT_MESSAGE_TRANSACTIONID_MAX_SIZE];
-       ks_size_t transactionid_length;
-       ks_dht_transaction_t *transaction;
-       char type[KS_DHT_MESSAGE_TYPE_MAX_SIZE];
-       struct bencode *args;
-       ks_dht_nodeid_t args_id;
-};
-
-struct ks_dht_endpoint_s {
-       ks_pool_t *pool;
-       ks_dht_nodeid_t nodeid;
-       ks_sockaddr_t addr;
-       ks_socket_t sock;
-       // @todo make sure this node is unlocked, and never gets destroyed, should also never use local nodes in search results as they can be internal
-       // network addresses, not what others have contacted through
-       ks_dht_node_t *node;
-};
-
-struct ks_dht_transaction_s {
-       ks_pool_t *pool;
-       ks_dht_job_t *job;
-       uint32_t transactionid;
-       //ks_dht_nodeid_t target; // @todo look at moving this into job now
-       ks_dht_job_callback_t callback;
-       ks_time_t expiration;
-       ks_bool_t finished;
-};
-
-struct ks_dht_search_s {
-       ks_pool_t *pool;
-       ks_dhtrt_routetable_t *table;
-       ks_dht_nodeid_t target;
-       ks_dht_job_callback_t callback;
-       void *data;
-       ks_mutex_t *mutex;
-       ks_hash_t *searched;
-       int32_t searching;
-       ks_dht_node_t *results[KS_DHT_SEARCH_RESULTS_MAX_SIZE];
-       ks_dht_nodeid_t distances[KS_DHT_SEARCH_RESULTS_MAX_SIZE];
-       ks_size_t results_length;
-};
-
-struct ks_dht_publish_s {
-       ks_pool_t *pool;
-       ks_dht_job_callback_t callback;
-       void *data;
-       int64_t cas;
-       ks_dht_storageitem_t *item;
-};
-
-struct ks_dht_distribute_s {
-       ks_pool_t *pool;
-       ks_dht_storageitem_callback_t callback;
-       void *data;
-       ks_mutex_t *mutex;
-       int32_t publishing;
-       int64_t cas;
-       ks_dht_storageitem_t *item;
-};
-
-struct ks_dht_storageitem_s {
-       ks_pool_t *pool;
-       ks_dht_nodeid_t id;
-       ks_time_t expiration;
-       ks_time_t keepalive;
-       struct bencode *v;
-
-       ks_mutex_t *mutex;
-       volatile int32_t refc;
-       ks_dht_storageitem_callback_t callback;
-
-       ks_bool_t mutable;
-       ks_dht_storageitem_pkey_t pk;
-       ks_dht_storageitem_skey_t sk;
-       struct bencode *salt;
-       int64_t seq;
-       ks_dht_storageitem_signature_t sig;
-};
-
-struct ks_dht_s {
-       ks_pool_t *pool;
-       ks_bool_t pool_alloc;
-
-       ks_thread_pool_t *tpool;
-       ks_bool_t tpool_alloc;
-
-       ks_bool_t autoroute;
-       ks_port_t autoroute_port;
-       
-       ks_hash_t *registry_type;
-       ks_hash_t *registry_query;
-       ks_hash_t *registry_error;
-
-       ks_dht_endpoint_t **endpoints;
-       int32_t endpoints_length;
-       int32_t endpoints_size;
-       ks_hash_t *endpoints_hash;
-       struct pollfd *endpoints_poll;
-
-       ks_q_t *send_q;
-       ks_dht_message_t *send_q_unsent;
-       uint8_t recv_buffer[KS_DHT_DATAGRAM_BUFFER_SIZE + 1]; // Add 1, if we receive it then overflow error
-       ks_size_t recv_buffer_length;
-
-       ks_mutex_t *jobs_mutex;
-       ks_dht_job_t *jobs_first;
-       ks_dht_job_t *jobs_last;
-
-       ks_time_t transactions_pulse;
-       ks_mutex_t *transactionid_mutex;
-       volatile uint32_t transactionid_next;
-       ks_hash_t *transactions_hash;
-
-       ks_dhtrt_routetable_t *rt_ipv4;
-       ks_dhtrt_routetable_t *rt_ipv6;
-
-       ks_time_t tokens_pulse;
-       volatile uint32_t token_secret_current;
-       volatile uint32_t token_secret_previous;
-       ks_time_t token_secret_expiration;
-
-       ks_time_t storageitems_pulse;
-       ks_hash_t *storageitems_hash;
-};
-
-/**
- * Constructor function for ks_dht_t.
- * Will allocate and initialize internal state including registration of message handlers.
- * @param dht dereferenced out pointer to the allocated dht instance
- * @param pool pointer to the memory pool used by the dht instance, may be NULL to create a new memory pool internally
- * @param tpool pointer to a thread pool used by the dht instance, may be NULL to create a new thread pool internally
- * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_NO_MEM
- */
-KS_DECLARE(ks_status_t) ks_dht_create(ks_dht_t **dht, ks_pool_t *pool, ks_thread_pool_t *tpool);
-                                               
-/**
- * Destructor function for ks_dht_t.
- * Will deinitialize and deallocate internal state.
- * @param dht dereferenced in/out pointer to the dht instance, NULL upon return
- */
-KS_DECLARE(void) ks_dht_destroy(ks_dht_t **dht);
-
-/**
- * Enable or disable (default) autorouting support.
- * When enabled, autorouting will allow sending to remote addresses on interfaces which are not yet bound.
- * The address will be bound with the provided autoroute port when this occurs.
- * @param dht pointer to the dht instance
- * @param autoroute enable or disable autorouting
- * @param port when enabling autorouting this port will be used to bind new addresses, may be 0 to use the default DHT port
- */
-KS_DECLARE(void) ks_dht_autoroute(ks_dht_t *dht, ks_bool_t autoroute, ks_port_t port);
-
-/**
- * Register a callback for a specific message type.
- * Will overwrite any duplicate handlers.
- * @param dht pointer to the dht instance
- * @param value string of the type text under the 'y' key of a message
- * @param callback the callback to be called when a message matches
- */
-KS_DECLARE(void) ks_dht_register_type(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback);
-
-/**
- * Register a callback for a specific message query.
- * Will overwrite any duplicate handlers.
- * @param dht pointer to the dht instance
- * @param value string of the type text under the 'q' key of a message
- * @param callback the callback to be called when a message matches
- */
-KS_DECLARE(void) ks_dht_register_query(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback);
-
-/**
- * Register a callback for a specific message error.
- * Will overwrite any duplicate handlers.
- * @param dht pointer to the dht instance
- * @param value string of the errorcode under the first item of the 'e' key of a message
- * @param callback the callback to be called when a message matches
- */
-KS_DECLARE(void) ks_dht_register_error(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback);
-
-/**
- * Bind a local address and port for receiving UDP datagrams.
- * @param dht pointer to the dht instance
- * @param nodeid pointer to a nodeid for this endpoint, may be NULL to generate one randomly
- * @param addr pointer to the local address information
- * @param endpoint dereferenced out pointer to the allocated endpoint, may be NULL to ignore endpoint output
- * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_FAIL, ...
- * @see ks_socket_option
- * @see ks_addr_bind
- * @see ks_dht_endpoint_alloc
- * @see ks_dht_endpoint_init
- * @see ks_hash_insert
- * @see ks_dhtrt_initroute
- * @see ks_dhtrt_create_node
- */
-KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_dht_nodeid_t *nodeid, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint);
-
-/**
- * Pulse the internals of dht.
- * Handles receiving UDP datagrams, dispatching processing, handles expirations, throttled message sending, route table pulsing, etc.
- * @param dht pointer to the dht instance
- * @param timeout timeout value used when polling sockets for new UDP datagrams
- */
-KS_DECLARE(void) ks_dht_pulse(ks_dht_t *dht, int32_t timeout);
-
-
-KS_DECLARE(char *) ks_dht_hex(const uint8_t *data, char *buffer, ks_size_t len);
-/**
- *
- */
-KS_DECLARE(ks_status_t) ks_dht_storageitem_target_immutable(const uint8_t *value, ks_size_t value_length, ks_dht_nodeid_t *target);
-
-/**
- *
- */
-KS_DECLARE(ks_status_t) ks_dht_storageitem_target_mutable(ks_dht_storageitem_pkey_t *pk, const uint8_t *salt, ks_size_t salt_length, ks_dht_nodeid_t *target);
-
-/**
- *
- */
-KS_DECLARE(ks_status_t) ks_dht_storageitem_signature_generate(ks_dht_storageitem_signature_t *sig,
-                                                                                                                         ks_dht_storageitem_skey_t *sk,
-                                                                                                                         const uint8_t *salt,
-                                                                                                                         ks_size_t salt_length,
-                                                                                                                         int64_t sequence,
-                                                                                                                         const uint8_t *value,
-                                                                                                                         ks_size_t value_length);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_storageitem_reference(ks_dht_storageitem_t *item);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_storageitem_dereference(ks_dht_storageitem_t *item);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_storageitem_callback(ks_dht_storageitem_t *item, ks_dht_storageitem_callback_t callback);
-                                               
-/**
- *
- */
-KS_DECLARE(void) ks_dht_storageitems_read_lock(ks_dht_t *dht);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_storageitems_read_unlock(ks_dht_t *dht);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_storageitems_write_lock(ks_dht_t *dht);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_storageitems_write_unlock(ks_dht_t *dht);
-
-/**
- *
- */
-KS_DECLARE(ks_dht_storageitem_t *) ks_dht_storageitems_find(ks_dht_t *dht, ks_dht_nodeid_t *target);
-
-/**
- *
- */
-KS_DECLARE(ks_status_t) ks_dht_storageitems_insert(ks_dht_t *dht, ks_dht_storageitem_t *item);
-                                               
-/**
- *
- */
-KS_DECLARE(void) ks_dht_ping(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_job_callback_t callback, void *data);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_findnode(ks_dht_t *dht,
-                                                                const ks_sockaddr_t *raddr,
-                                                                ks_dht_job_callback_t callback,
-                                                                void *data,
-                                                                ks_dht_nodeid_t *target);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_get(ks_dht_t *dht,
-                                                       const ks_sockaddr_t *raddr,
-                                                       ks_dht_job_callback_t callback,
-                                                       void *data,
-                                                       ks_dht_nodeid_t *target,
-                                                       const uint8_t *salt,
-                                                       ks_size_t salt_length);
-
-/**
- *
- */
-KS_DECLARE(void) ks_dht_put(ks_dht_t *dht,
-                                                       const ks_sockaddr_t *raddr,
-                                                       ks_dht_job_callback_t callback,
-                                                       void *data,
-                                                       ks_dht_token_t *token,
-                                                       int64_t cas,
-                                                       ks_dht_storageitem_t *item);
-                                               
-/**
- * Create a network search of the closest nodes to a target.
- * @param dht pointer to the dht instance
- * @param family either AF_INET or AF_INET6 for the appropriate network to search
- * @param target pointer to the nodeid for the target to be searched
- * @param callback an optional callback to add to the search when it is finished
- * @param search dereferenced out pointer to the allocated search, may be NULL to ignore search output
- * @see ks_dht_search_create
- * @see ks_hash_insert
- * @see ks_dht_findnode
- */
-KS_DECLARE(void) ks_dht_search(ks_dht_t *dht,
-                                                          ks_dht_job_callback_t callback,
-                                                          void *data,
-                                                          ks_dhtrt_routetable_t *table,
-                                                          ks_dht_nodeid_t *target);
-
-KS_DECLARE(void) ks_dht_publish(ks_dht_t *dht,
-                                                               const ks_sockaddr_t *raddr,
-                                                               ks_dht_job_callback_t callback,
-                                                               void *data,
-                                                               int64_t cas,
-                                                               ks_dht_storageitem_t *item);
-
-KS_DECLARE(void) ks_dht_distribute(ks_dht_t *dht,
-                                                                  ks_dht_storageitem_callback_t callback,
-                                                                  void *data,
-                                                                  ks_dhtrt_routetable_t *table,
-                                                                  int64_t cas,
-                                                                  ks_dht_storageitem_t *item);
-
-/**
- * route table methods
- *
- */
-KS_DECLARE(ks_status_t) ks_dhtrt_initroute(ks_dhtrt_routetable_t **tableP, 
-                                                                                       ks_dht_t *dht, 
-                                                                                       ks_pool_t *pool); 
-KS_DECLARE(void) ks_dhtrt_deinitroute(ks_dhtrt_routetable_t **table);
-
-KS_DECLARE(ks_status_t)        ks_dhtrt_create_node(ks_dhtrt_routetable_t* table,
-                                                                                                       ks_dht_nodeid_t nodeid,
-                                                                                                       enum ks_dht_nodetype_t type,
-                                                                                                       char* ip, unsigned short port,
-                                                    enum ks_create_node_flags_t flags,
-                                                                                                       ks_dht_node_t** node);
-
-KS_DECLARE(ks_status_t)        ks_dhtrt_delete_node(ks_dhtrt_routetable_t* table, ks_dht_node_t* node);
-
-KS_DECLARE(ks_status_t)        ks_dhtrt_touch_node(ks_dhtrt_routetable_t* table,  ks_dht_nodeid_t nodeid);
-KS_DECLARE(ks_status_t)        ks_dhtrt_expire_node(ks_dhtrt_routetable_t* table,  ks_dht_nodeid_t nodeid);
-
-KS_DECLARE(uint8_t)            ks_dhtrt_findclosest_nodes(ks_dhtrt_routetable_t* table, ks_dhtrt_querynodes_t* query);
-KS_DECLARE(ks_dht_node_t*)     ks_dhtrt_find_node(ks_dhtrt_routetable_t* table, ks_dht_nodeid_t id);
-
-KS_DECLARE(ks_status_t)        ks_dhtrt_sharelock_node(ks_dht_node_t* node);
-KS_DECLARE(ks_status_t)        ks_dhtrt_release_node(ks_dht_node_t* node);
-KS_DECLARE(ks_status_t)        ks_dhtrt_release_querynodes(ks_dhtrt_querynodes_t* query);
-
-KS_DECLARE(void)               ks_dhtrt_process_table(ks_dhtrt_routetable_t* table);
-
-KS_DECLARE(uint32_t)          ks_dhtrt_serialize(ks_dhtrt_routetable_t* table, void** ptr);
-KS_DECLARE(ks_status_t)        ks_dhtrt_deserialize(ks_dhtrt_routetable_t* table, void* ptr);
-
-
-/* debugging aids */
-KS_DECLARE(void)               ks_dhtrt_dump(ks_dhtrt_routetable_t* table, int level);
-
-                                                                                                                                                                                                                                                                                               
-KS_END_EXTERN_C
-
-#endif /* KS_DHT_H */
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
index d8c2965fc420e226b70a6416ed89a4eaaaafdefa..3651bea39d3a654ed6740718f62c97806727de54 100644 (file)
@@ -7,7 +7,6 @@
  */
 KS_DECLARE(ks_status_t) ks_dht_endpoint_create(ks_dht_endpoint_t **endpoint,
                                                                                           ks_pool_t *pool,
-                                                                                          const ks_dht_nodeid_t *nodeid,
                                                                                           const ks_sockaddr_t *addr,
                                                                                           ks_socket_t sock)
 {
@@ -23,8 +22,6 @@ KS_DECLARE(ks_status_t) ks_dht_endpoint_create(ks_dht_endpoint_t **endpoint,
        ks_assert(ep);
 
        ep->pool = pool;
-    if (!nodeid) randombytes_buf(ep->nodeid.id, KS_DHT_NODEID_SIZE);
-       else memcpy(ep->nodeid.id, nodeid->id, KS_DHT_NODEID_SIZE);
        ep->addr = *addr;
        ep->sock = sock;
 
similarity index 99%
rename from libs/libks/src/dht/ks_dht-int.h
rename to libs/libks/src/include/ks_dht-int.h
index 6d06d4682bff9681344d41fbba8cbba7197ae30b..ad5d20bb9cff0319e00b6911c85c4c76e3b0383e 100644 (file)
@@ -319,7 +319,6 @@ KS_DECLARE(void) ks_dht_job_destroy(ks_dht_job_t **job);
  */
 KS_DECLARE(ks_status_t) ks_dht_endpoint_create(ks_dht_endpoint_t **endpoint,
                                                                                           ks_pool_t *pool,
-                                                                                          const ks_dht_nodeid_t *nodeid,
                                                                                           const ks_sockaddr_t *addr,
                                                                                           ks_socket_t sock);
 KS_DECLARE(void) ks_dht_endpoint_destroy(ks_dht_endpoint_t **endpoint);
index 2b5b9cb4677137db8fdb41cf5feb33ad99ea5c83..2c84921a8727d9ef2f5acd5bdccc31c746c67247 100644 (file)
-/*
-Copyright (c) 2009-2011 by Juliusz Chroboczek
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-#ifndef _KS_DHT_H
-#define _KS_DHT_H
+#ifndef KS_DHT_H
+#define KS_DHT_H
 
 #include "ks.h"
 #include "ks_bencode.h"
+#include "sodium.h"
 
 KS_BEGIN_EXTERN_C
 
-typedef enum {
-       KS_DHT_EVENT_NONE = 0,
-       KS_DHT_EVENT_VALUES = 1,
-       KS_DHT_EVENT_VALUES6 = 2,
-       KS_DHT_EVENT_SEARCH_DONE = 3,
-       KS_DHT_EVENT_SEARCH_DONE6 = 4
-} ks_dht_event_t;
-
-
-typedef enum {
-       DHT_PARAM_AUTOROUTE = 1
-} ks_dht_param_t;
-
-typedef enum {
-       KS_DHT_AF_INET4 = (1 << 0),
-       KS_DHT_AF_INET6 = (1 << 1)
-} ks_dht_af_flag_t;
-
-
-typedef void (*dht_callback_t)(void *closure, ks_dht_event_t event, const unsigned char *info_hash, const void *data, size_t data_len);
-
-typedef struct dht_handle_s dht_handle_t;
-
-KS_DECLARE(int) dht_periodic(dht_handle_t *h, const void *buf, size_t buflen, ks_sockaddr_t *from);
-KS_DECLARE(ks_status_t) ks_dht_init(dht_handle_t **handle, ks_dht_af_flag_t af_flags, const unsigned char *id, unsigned int port);
-KS_DECLARE(void) ks_dht_set_param(dht_handle_t *h, ks_dht_param_t param, ks_bool_t val);
-KS_DECLARE(ks_status_t) ks_dht_add_ip(dht_handle_t *h, char *ip, int port);
-KS_DECLARE(void) ks_dht_start(dht_handle_t *h);
-KS_DECLARE(int) dht_insert_node(dht_handle_t *h, const unsigned char *id, ks_sockaddr_t *sa);
-KS_DECLARE(int) dht_ping_node(dht_handle_t *h, ks_sockaddr_t *sa);
-KS_DECLARE(int) dht_search(dht_handle_t *h, const unsigned char *id, int port, int af, dht_callback_t callback, void *closure);
-KS_DECLARE(int) dht_nodes(dht_handle_t *h, int af, int *good_return, int *dubious_return, int *cached_return, int *incoming_return);
-KS_DECLARE(ks_status_t) ks_dht_one_loop(dht_handle_t *h, int timeout);
-KS_DECLARE(ks_status_t) ks_dht_get_bind_addrs(dht_handle_t *h, const ks_sockaddr_t ***addrs, ks_size_t *addrlen);
-KS_DECLARE(void) ks_dht_set_callback(dht_handle_t *h, dht_callback_t callback, void *closure);
-KS_DECLARE(void) ks_dht_set_port(dht_handle_t *h, unsigned int port);
-KS_DECLARE(void) dht_dump_tables(dht_handle_t *h, FILE *f);
-KS_DECLARE(int) dht_get_nodes(dht_handle_t *h, struct sockaddr_in *sin, int *num, struct sockaddr_in6 *sin6, int *num6);
-KS_DECLARE(int) dht_uninit(dht_handle_t **h);
-KS_DECLARE(void) ks_dht_set_v(dht_handle_t *h, const unsigned char *v);
-KS_DECLARE(int) ks_dht_calculate_mutable_storage_target(unsigned char *pk, unsigned char *salt, int salt_length, unsigned char *target, int target_length);
-KS_DECLARE(int) ks_dht_generate_mutable_storage_args(struct bencode *data, int64_t sequence, int cas,
-                                                                                                        unsigned char *id, int id_len, /* querying nodes id */
-                                                                                                        const unsigned char *sk, const unsigned char *pk,
-                                                                                                        unsigned char *salt, unsigned long long salt_length,
-                                                                                                        unsigned char *token, unsigned long long token_length,
-                                                                                                        unsigned char *signature, unsigned long long *signature_length,
-                                                                                                        struct bencode **arguments);
-
-/* This must be provided by the user. */
-KS_DECLARE(int) dht_blacklisted(const ks_sockaddr_t *sa);
-KS_DECLARE(void) dht_hash(void *hash_return, int hash_size, const void *v1, int len1, const void *v2, int len2, const void *v3, int len3);
-KS_DECLARE(int) dht_random_bytes(void *buf, size_t size);
-
-KS_DECLARE(int) ks_dht_send_message_mutable(dht_handle_t *h, unsigned char *sk, unsigned char *pk, char **node_id,
-                                                                                       char *message_id, int sequence, char *message, ks_time_t life);
-
-KS_DECLARE(int) ks_dht_send_message_mutable_cjson(dht_handle_t *h, unsigned char *sk, unsigned char *pk, char **node_id,
-                                                                                                 char *message_id, int sequence, cJSON *message, ks_time_t life);
-
-typedef void (ks_dht_store_entry_json_cb)(struct dht_handle_s *h, const cJSON *msg, void *obj);
-KS_DECLARE(void) ks_dht_store_entry_json_cb_set(struct dht_handle_s *h, ks_dht_store_entry_json_cb *store_json_cb, void *arg);
-
-KS_DECLARE(int) ks_dht_api_find_node(dht_handle_t *h, char *node_id_hex, char *target_hex, ks_bool_t ipv6);
 
+#define KS_DHT_DEFAULT_PORT 5309
+
+#define KS_DHT_TPOOL_MIN 2
+#define KS_DHT_TPOOL_MAX 8
+#define KS_DHT_TPOOL_STACK (1024 * 256)
+#define KS_DHT_TPOOL_IDLE 10
+
+#define KS_DHT_DATAGRAM_BUFFER_SIZE 1000
+
+//#define KS_DHT_RECV_BUFFER_SIZE 0xFFFF
+
+#define KS_DHT_NODEID_SIZE 20
+
+#define KS_DHT_RESPONSE_NODES_MAX_SIZE 8
+
+#define KS_DHT_MESSAGE_TRANSACTIONID_MAX_SIZE 20
+#define KS_DHT_MESSAGE_TYPE_MAX_SIZE 20
+#define KS_DHT_MESSAGE_QUERY_MAX_SIZE 20
+#define KS_DHT_MESSAGE_ERROR_MAX_SIZE 256
+
+#define KS_DHT_TRANSACTION_EXPIRATION 10
+#define KS_DHT_TRANSACTIONS_PULSE 1
+
+#define KS_DHT_SEARCH_RESULTS_MAX_SIZE 8 // @todo replace with KS_DHTRT_BUCKET_SIZE
+
+#define KS_DHT_STORAGEITEM_PKEY_SIZE crypto_sign_PUBLICKEYBYTES
+#define KS_DHT_STORAGEITEM_SKEY_SIZE crypto_sign_SECRETKEYBYTES
+#define KS_DHT_STORAGEITEM_SALT_MAX_SIZE 64
+#define KS_DHT_STORAGEITEM_SIGNATURE_SIZE crypto_sign_BYTES
+#define KS_DHT_STORAGEITEM_EXPIRATION 7200
+#define KS_DHT_STORAGEITEM_KEEPALIVE 300
+#define KS_DHT_STORAGEITEMS_PULSE 10
+
+#define KS_DHT_TOKEN_SIZE SHA_DIGEST_LENGTH
+#define KS_DHT_TOKEN_EXPIRATION 300
+#define KS_DHT_TOKENS_PULSE 1
+
+#define  KS_DHTRT_MAXQUERYSIZE 20
+
+typedef struct ks_dht_s ks_dht_t;
+typedef struct ks_dht_datagram_s ks_dht_datagram_t;
+typedef struct ks_dht_job_s ks_dht_job_t;
+typedef struct ks_dht_nodeid_s ks_dht_nodeid_t;
+typedef struct ks_dht_token_s ks_dht_token_t;
+typedef struct ks_dht_storageitem_pkey_s ks_dht_storageitem_pkey_t;
+typedef struct ks_dht_storageitem_skey_s ks_dht_storageitem_skey_t;
+typedef struct ks_dht_storageitem_signature_s ks_dht_storageitem_signature_t;
+typedef struct ks_dht_message_s ks_dht_message_t;
+typedef struct ks_dht_endpoint_s ks_dht_endpoint_t;
+typedef struct ks_dht_transaction_s ks_dht_transaction_t;
+typedef struct ks_dht_search_s ks_dht_search_t;
+typedef struct ks_dht_publish_s ks_dht_publish_t;
+typedef struct ks_dht_distribute_s ks_dht_distribute_t;
+typedef struct ks_dht_node_s ks_dht_node_t;
+typedef struct ks_dhtrt_routetable_s ks_dhtrt_routetable_t;
+typedef struct ks_dhtrt_querynodes_s ks_dhtrt_querynodes_t;
+typedef struct ks_dht_storageitem_s ks_dht_storageitem_t;
+
+
+typedef ks_status_t (*ks_dht_job_callback_t)(ks_dht_t *dht, ks_dht_job_t *job);
+typedef ks_status_t (*ks_dht_message_callback_t)(ks_dht_t *dht, ks_dht_message_t *message);
+//typedef ks_status_t (*ks_dht_search_callback_t)(ks_dht_t *dht, ks_dht_search_t *search);
+typedef ks_status_t (*ks_dht_storageitem_callback_t)(ks_dht_t *dht, ks_dht_storageitem_t *item);
+
+
+struct ks_dht_datagram_s {
+       ks_pool_t *pool;
+       ks_dht_t *dht;
+       ks_dht_endpoint_t *endpoint;
+       ks_sockaddr_t raddr;
+       uint8_t buffer[KS_DHT_DATAGRAM_BUFFER_SIZE];
+       ks_size_t buffer_length;
+};
+
+/**
+ * Note: This must remain a structure for casting from raw data
+ */
+struct ks_dht_nodeid_s {
+       uint8_t id[KS_DHT_NODEID_SIZE];
+};
+
+enum ks_afflags_t { ifv4=AF_INET, ifv6=AF_INET6, ifboth=AF_INET+AF_INET6};
+enum ks_dht_nodetype_t { KS_DHT_REMOTE=0x01, 
+                                                KS_DHT_LOCAL=0x02, 
+                                                KS_DHT_BOTH=KS_DHT_REMOTE+KS_DHT_LOCAL };
+
+enum ks_create_node_flags_t { 
+                                                KS_DHTRT_CREATE_DEFAULT=0,
+                                                KS_DHTRT_CREATE_PING,
+                                                KS_DHTRT_CREATE_TOUCH 
+};             
+                               
+struct ks_dht_node_s {
+    ks_dht_nodeid_t  nodeid;
+    ks_sockaddr_t    addr;
+    enum ks_dht_nodetype_t type;               /* local or remote */
+    ks_dhtrt_routetable_t* table;
+    ks_rwl_t        *reflock;          
+};
+
+struct ks_dht_token_s {
+       uint8_t token[KS_DHT_TOKEN_SIZE];
+};
+
+enum ks_dht_job_state_t {
+       KS_DHT_JOB_STATE_QUERYING,
+       KS_DHT_JOB_STATE_RESPONDING,
+       KS_DHT_JOB_STATE_EXPIRING,
+       KS_DHT_JOB_STATE_COMPLETING,
+};
+
+enum ks_dht_job_result_t {
+       KS_DHT_JOB_RESULT_SUCCESS = 0,
+       KS_DHT_JOB_RESULT_EXPIRED,
+       KS_DHT_JOB_RESULT_ERROR,
+       KS_DHT_JOB_RESULT_FAILURE,
+};
+
+struct ks_dht_job_s {
+       ks_pool_t *pool;
+       ks_dht_t *dht;
+       ks_dht_job_t *next;
+
+       enum ks_dht_job_state_t state;
+       enum ks_dht_job_result_t result;
+
+       ks_sockaddr_t raddr; // will obtain local endpoint node id when creating message using raddr
+       int32_t attempts;
+
+       //enum ks_dht_job_type_t type;
+       ks_dht_job_callback_t query_callback;
+       ks_dht_job_callback_t finish_callback;
+
+       void *data;
+       ks_dht_message_t *response;
+
+       // job specific query parameters
+       ks_dht_nodeid_t query_target;
+       struct bencode *query_salt;
+       int64_t query_cas;
+       ks_dht_token_t query_token;
+       ks_dht_storageitem_t *query_storageitem;
+
+       // error response parameters
+       int64_t error_code;
+       struct bencode *error_description;
+       
+       // job specific response parameters
+       ks_dht_node_t *response_id;
+       ks_dht_node_t *response_nodes[KS_DHT_RESPONSE_NODES_MAX_SIZE];
+       ks_size_t response_nodes_count;
+       ks_dht_node_t *response_nodes6[KS_DHT_RESPONSE_NODES_MAX_SIZE];
+       ks_size_t response_nodes6_count;
+       
+       ks_dht_token_t response_token;
+       int64_t response_seq;
+       ks_bool_t response_hasitem;
+       ks_dht_storageitem_t *response_storageitem;
+};
+
+struct ks_dhtrt_routetable_s {
+    void*       internal;                       
+    ks_pool_t*  pool;                           
+    ks_logger_t logger;
+};
+
+struct ks_dhtrt_querynodes_s {
+    ks_dht_nodeid_t nodeid;                   /* in: id to query                   */
+    enum ks_afflags_t family;                 /* in: AF_INET or AF_INET6 or both   */
+    enum ks_dht_nodetype_t type;              /* remote, local, or  both           */
+    uint8_t        max;                       /* in: maximum to return             */
+    uint8_t        count;                     /* out: number returned              */
+    ks_dht_node_t* nodes[ KS_DHTRT_MAXQUERYSIZE ]; /* out: array of peers (ks_dht_node_t* nodes[incount]) */
+};
+
+struct ks_dht_storageitem_pkey_s {
+       uint8_t key[KS_DHT_STORAGEITEM_PKEY_SIZE];
+};
+
+struct ks_dht_storageitem_skey_s {
+       uint8_t key[KS_DHT_STORAGEITEM_SKEY_SIZE];
+};
+
+struct ks_dht_storageitem_signature_s {
+       uint8_t sig[KS_DHT_STORAGEITEM_SIGNATURE_SIZE];
+};
+
+struct ks_dht_message_s {
+       ks_pool_t *pool;
+       ks_dht_endpoint_t *endpoint;
+       ks_sockaddr_t raddr;
+       struct bencode *data;
+       uint8_t transactionid[KS_DHT_MESSAGE_TRANSACTIONID_MAX_SIZE];
+       ks_size_t transactionid_length;
+       ks_dht_transaction_t *transaction;
+       char type[KS_DHT_MESSAGE_TYPE_MAX_SIZE];
+       struct bencode *args;
+       ks_dht_nodeid_t args_id;
+};
+
+struct ks_dht_endpoint_s {
+       ks_pool_t *pool;
+       ks_sockaddr_t addr;
+       ks_socket_t sock;
+};
+
+struct ks_dht_transaction_s {
+       ks_pool_t *pool;
+       ks_dht_job_t *job;
+       uint32_t transactionid;
+       //ks_dht_nodeid_t target; // @todo look at moving this into job now
+       ks_dht_job_callback_t callback;
+       ks_time_t expiration;
+       ks_bool_t finished;
+};
+
+struct ks_dht_search_s {
+       ks_pool_t *pool;
+       ks_dhtrt_routetable_t *table;
+       ks_dht_nodeid_t target;
+       ks_dht_job_callback_t callback;
+       void *data;
+       ks_mutex_t *mutex;
+       ks_hash_t *searched;
+       int32_t searching;
+       ks_dht_node_t *results[KS_DHT_SEARCH_RESULTS_MAX_SIZE];
+       ks_dht_nodeid_t distances[KS_DHT_SEARCH_RESULTS_MAX_SIZE];
+       ks_size_t results_length;
+};
+
+struct ks_dht_publish_s {
+       ks_pool_t *pool;
+       ks_dht_job_callback_t callback;
+       void *data;
+       int64_t cas;
+       ks_dht_storageitem_t *item;
+};
+
+struct ks_dht_distribute_s {
+       ks_pool_t *pool;
+       ks_dht_storageitem_callback_t callback;
+       void *data;
+       ks_mutex_t *mutex;
+       int32_t publishing;
+       int64_t cas;
+       ks_dht_storageitem_t *item;
+};
+
+struct ks_dht_storageitem_s {
+       ks_pool_t *pool;
+       ks_dht_nodeid_t id;
+       ks_time_t expiration;
+       ks_time_t keepalive;
+       struct bencode *v;
+
+       ks_mutex_t *mutex;
+       volatile int32_t refc;
+       ks_dht_storageitem_callback_t callback;
+
+       ks_bool_t mutable;
+       ks_dht_storageitem_pkey_t pk;
+       ks_dht_storageitem_skey_t sk;
+       struct bencode *salt;
+       int64_t seq;
+       ks_dht_storageitem_signature_t sig;
+};
+
+struct ks_dht_s {
+       ks_pool_t *pool;
+       ks_bool_t pool_alloc;
+
+       ks_thread_pool_t *tpool;
+       ks_bool_t tpool_alloc;
+
+       ks_dht_nodeid_t nodeid;
+       // @todo make sure this node is unlocked, and never gets destroyed, should also never use local nodes in search results as they can be internal
+       // network addresses, not what others have contacted through
+       ks_dht_node_t *node;
+       
+       ks_bool_t autoroute;
+       ks_port_t autoroute_port;
+       
+       ks_hash_t *registry_type;
+       ks_hash_t *registry_query;
+       ks_hash_t *registry_error;
+
+       ks_dht_endpoint_t **endpoints;
+       int32_t endpoints_length;
+       int32_t endpoints_size;
+       ks_hash_t *endpoints_hash;
+       struct pollfd *endpoints_poll;
+
+       ks_q_t *send_q;
+       ks_dht_message_t *send_q_unsent;
+       uint8_t recv_buffer[KS_DHT_DATAGRAM_BUFFER_SIZE + 1]; // Add 1, if we receive it then overflow error
+       ks_size_t recv_buffer_length;
+
+       ks_mutex_t *jobs_mutex;
+       ks_dht_job_t *jobs_first;
+       ks_dht_job_t *jobs_last;
+
+       ks_time_t transactions_pulse;
+       ks_mutex_t *transactionid_mutex;
+       volatile uint32_t transactionid_next;
+       ks_hash_t *transactions_hash;
+
+       ks_dhtrt_routetable_t *rt_ipv4;
+       ks_dhtrt_routetable_t *rt_ipv6;
+
+       ks_time_t tokens_pulse;
+       volatile uint32_t token_secret_current;
+       volatile uint32_t token_secret_previous;
+       ks_time_t token_secret_expiration;
+
+       ks_time_t storageitems_pulse;
+       ks_hash_t *storageitems_hash;
+};
+
+/**
+ * Constructor function for ks_dht_t.
+ * Will allocate and initialize internal state including registration of message handlers.
+ * @param dht dereferenced out pointer to the allocated dht instance
+ * @param pool pointer to the memory pool used by the dht instance, may be NULL to create a new memory pool internally
+ * @param tpool pointer to a thread pool used by the dht instance, may be NULL to create a new thread pool internally
+ * @param nodeid pointer to the nodeid for this dht instance
+ * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_NO_MEM
+ */
+KS_DECLARE(ks_status_t) ks_dht_create(ks_dht_t **dht, ks_pool_t *pool, ks_thread_pool_t *tpool, ks_dht_nodeid_t *nodeid);
+                                               
+/**
+ * Destructor function for ks_dht_t.
+ * Will deinitialize and deallocate internal state.
+ * @param dht dereferenced in/out pointer to the dht instance, NULL upon return
+ */
+KS_DECLARE(void) ks_dht_destroy(ks_dht_t **dht);
+
+/**
+ * Enable or disable (default) autorouting support.
+ * When enabled, autorouting will allow sending to remote addresses on interfaces which are not yet bound.
+ * The address will be bound with the provided autoroute port when this occurs.
+ * @param dht pointer to the dht instance
+ * @param autoroute enable or disable autorouting
+ * @param port when enabling autorouting this port will be used to bind new addresses, may be 0 to use the default DHT port
+ */
+KS_DECLARE(void) ks_dht_autoroute(ks_dht_t *dht, ks_bool_t autoroute, ks_port_t port);
+
+/**
+ * Register a callback for a specific message type.
+ * Will overwrite any duplicate handlers.
+ * @param dht pointer to the dht instance
+ * @param value string of the type text under the 'y' key of a message
+ * @param callback the callback to be called when a message matches
+ */
+KS_DECLARE(void) ks_dht_register_type(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback);
+
+/**
+ * Register a callback for a specific message query.
+ * Will overwrite any duplicate handlers.
+ * @param dht pointer to the dht instance
+ * @param value string of the type text under the 'q' key of a message
+ * @param callback the callback to be called when a message matches
+ */
+KS_DECLARE(void) ks_dht_register_query(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback);
+
+/**
+ * Register a callback for a specific message error.
+ * Will overwrite any duplicate handlers.
+ * @param dht pointer to the dht instance
+ * @param value string of the errorcode under the first item of the 'e' key of a message
+ * @param callback the callback to be called when a message matches
+ */
+KS_DECLARE(void) ks_dht_register_error(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback);
+
+/**
+ * Bind a local address and port for receiving UDP datagrams.
+ * @param dht pointer to the dht instance
+ * @param addr pointer to the local address information
+ * @param endpoint dereferenced out pointer to the allocated endpoint, may be NULL to ignore endpoint output
+ * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_FAIL, ...
+ * @see ks_socket_option
+ * @see ks_addr_bind
+ * @see ks_dht_endpoint_alloc
+ * @see ks_dht_endpoint_init
+ * @see ks_hash_insert
+ * @see ks_dhtrt_initroute
+ * @see ks_dhtrt_create_node
+ */
+KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint);
+
+/**
+ * Pulse the internals of dht.
+ * Handles receiving UDP datagrams, dispatching processing, handles expirations, throttled message sending, route table pulsing, etc.
+ * @param dht pointer to the dht instance
+ * @param timeout timeout value used when polling sockets for new UDP datagrams
+ */
+KS_DECLARE(void) ks_dht_pulse(ks_dht_t *dht, int32_t timeout);
+
+
+KS_DECLARE(char *) ks_dht_hex(const uint8_t *data, char *buffer, ks_size_t len);
+KS_DECLARE(uint8_t *) ks_dht_dehex(uint8_t *data, const char *buffer, ks_size_t len);
+                                               
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_target_immutable(const uint8_t *value, ks_size_t value_length, ks_dht_nodeid_t *target);
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_target_mutable(ks_dht_storageitem_pkey_t *pk, const uint8_t *salt, ks_size_t salt_length, ks_dht_nodeid_t *target);
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitem_signature_generate(ks_dht_storageitem_signature_t *sig,
+                                                                                                                         ks_dht_storageitem_skey_t *sk,
+                                                                                                                         const uint8_t *salt,
+                                                                                                                         ks_size_t salt_length,
+                                                                                                                         int64_t sequence,
+                                                                                                                         const uint8_t *value,
+                                                                                                                         ks_size_t value_length);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_storageitem_reference(ks_dht_storageitem_t *item);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_storageitem_dereference(ks_dht_storageitem_t *item);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_storageitem_callback(ks_dht_storageitem_t *item, ks_dht_storageitem_callback_t callback);
+                                               
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_storageitems_read_lock(ks_dht_t *dht);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_storageitems_read_unlock(ks_dht_t *dht);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_storageitems_write_lock(ks_dht_t *dht);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_storageitems_write_unlock(ks_dht_t *dht);
+
+/**
+ *
+ */
+KS_DECLARE(ks_dht_storageitem_t *) ks_dht_storageitems_find(ks_dht_t *dht, ks_dht_nodeid_t *target);
+
+/**
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dht_storageitems_insert(ks_dht_t *dht, ks_dht_storageitem_t *item);
+                                               
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_ping(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_job_callback_t callback, void *data);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_findnode(ks_dht_t *dht,
+                                                                const ks_sockaddr_t *raddr,
+                                                                ks_dht_job_callback_t callback,
+                                                                void *data,
+                                                                ks_dht_nodeid_t *target);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_get(ks_dht_t *dht,
+                                                       const ks_sockaddr_t *raddr,
+                                                       ks_dht_job_callback_t callback,
+                                                       void *data,
+                                                       ks_dht_nodeid_t *target,
+                                                       const uint8_t *salt,
+                                                       ks_size_t salt_length);
+
+/**
+ *
+ */
+KS_DECLARE(void) ks_dht_put(ks_dht_t *dht,
+                                                       const ks_sockaddr_t *raddr,
+                                                       ks_dht_job_callback_t callback,
+                                                       void *data,
+                                                       ks_dht_token_t *token,
+                                                       int64_t cas,
+                                                       ks_dht_storageitem_t *item);
+                                               
+/**
+ * Create a network search of the closest nodes to a target.
+ * @param dht pointer to the dht instance
+ * @param family either AF_INET or AF_INET6 for the appropriate network to search
+ * @param target pointer to the nodeid for the target to be searched
+ * @param callback an optional callback to add to the search when it is finished
+ * @param search dereferenced out pointer to the allocated search, may be NULL to ignore search output
+ * @see ks_dht_search_create
+ * @see ks_hash_insert
+ * @see ks_dht_findnode
+ */
+KS_DECLARE(void) ks_dht_search(ks_dht_t *dht,
+                                                          ks_dht_job_callback_t callback,
+                                                          void *data,
+                                                          ks_dhtrt_routetable_t *table,
+                                                          ks_dht_nodeid_t *target);
+
+KS_DECLARE(void) ks_dht_publish(ks_dht_t *dht,
+                                                               const ks_sockaddr_t *raddr,
+                                                               ks_dht_job_callback_t callback,
+                                                               void *data,
+                                                               int64_t cas,
+                                                               ks_dht_storageitem_t *item);
+
+KS_DECLARE(void) ks_dht_distribute(ks_dht_t *dht,
+                                                                  ks_dht_storageitem_callback_t callback,
+                                                                  void *data,
+                                                                  ks_dhtrt_routetable_t *table,
+                                                                  int64_t cas,
+                                                                  ks_dht_storageitem_t *item);
+
+/**
+ * route table methods
+ *
+ */
+KS_DECLARE(ks_status_t) ks_dhtrt_initroute(ks_dhtrt_routetable_t **tableP, 
+                                                                                       ks_dht_t *dht, 
+                                                                                       ks_pool_t *pool); 
+KS_DECLARE(void) ks_dhtrt_deinitroute(ks_dhtrt_routetable_t **table);
+
+KS_DECLARE(ks_status_t)        ks_dhtrt_create_node(ks_dhtrt_routetable_t* table,
+                                                                                                       ks_dht_nodeid_t nodeid,
+                                                                                                       enum ks_dht_nodetype_t type,
+                                                                                                       char* ip, unsigned short port,
+                                                    enum ks_create_node_flags_t flags,
+                                                                                                       ks_dht_node_t** node);
+
+KS_DECLARE(ks_status_t)        ks_dhtrt_delete_node(ks_dhtrt_routetable_t* table, ks_dht_node_t* node);
+
+KS_DECLARE(ks_status_t)        ks_dhtrt_touch_node(ks_dhtrt_routetable_t* table,  ks_dht_nodeid_t nodeid);
+KS_DECLARE(ks_status_t)        ks_dhtrt_expire_node(ks_dhtrt_routetable_t* table,  ks_dht_nodeid_t nodeid);
+
+KS_DECLARE(uint8_t)            ks_dhtrt_findclosest_nodes(ks_dhtrt_routetable_t* table, ks_dhtrt_querynodes_t* query);
+KS_DECLARE(ks_dht_node_t*)     ks_dhtrt_find_node(ks_dhtrt_routetable_t* table, ks_dht_nodeid_t id);
+
+KS_DECLARE(ks_status_t)        ks_dhtrt_sharelock_node(ks_dht_node_t* node);
+KS_DECLARE(ks_status_t)        ks_dhtrt_release_node(ks_dht_node_t* node);
+KS_DECLARE(ks_status_t)        ks_dhtrt_release_querynodes(ks_dhtrt_querynodes_t* query);
+
+KS_DECLARE(void)               ks_dhtrt_process_table(ks_dhtrt_routetable_t* table);
+
+KS_DECLARE(uint32_t)           ks_dhtrt_serialize(ks_dhtrt_routetable_t* table, void** ptr);
+KS_DECLARE(ks_status_t)        ks_dhtrt_deserialize(ks_dhtrt_routetable_t* table, void* ptr);
+                                                                                                                                                                                        
+/* debugging aids */
+KS_DECLARE(void)               ks_dhtrt_dump(ks_dhtrt_routetable_t* table, int level);
+
+                                                                                                                                                                                                                                                                                               
 KS_END_EXTERN_C
 
-#endif /* _KS_DHT_H */
+#endif /* KS_DHT_H */
 
 /* For Emacs:
  * Local Variables:
diff --git a/libs/libks/src/ks_dht.c b/libs/libks/src/ks_dht.c
deleted file mode 100644 (file)
index 5715a49..0000000
+++ /dev/null
@@ -1,4137 +0,0 @@
-/*
-Copyright (c) 2009-2011 by Juliusz Chroboczek
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-/* Please, please, please.
-
-   You are welcome to integrate this code in your favourite Bittorrent
-   client.  Please remember, however, that it is meant to be usable by
-   others, including myself.  This means no C++, no relicensing, and no
-   gratuitious changes to the coding style.  And please send back any
-   improvements to the author. */
-
-/* Sorry dude, we hacked up this code pretty good but its not C++ and the license is pure BSD.
-Like Meatloaf says, 2 out of 3 ain't bad! But we needed a good base for some additions we needed */
-
-
-#include "ks.h"
-#include "sodium.h"
-
-#ifndef MSG_CONFIRM
-#define MSG_CONFIRM 0
-#endif
-
-KS_DECLARE(int) dht_blacklisted(const ks_sockaddr_t *sa)
-{
-       return 0;
-}
-
-KS_DECLARE(void) dht_hash(void *hash_return, int hash_size, const void *v1, int len1, const void *v2, int len2, const void *v3, int len3)
-{
-       crypto_generichash_state state;
-
-       crypto_generichash_init(&state, NULL, 0, hash_size);
-       crypto_generichash_update(&state, v1, len1);
-       crypto_generichash_update(&state, v2, len2);
-       crypto_generichash_update(&state, v3, len3);
-       crypto_generichash_final(&state, (unsigned char *)hash_return, hash_size);
-
-       return;
-}
-
-/*
-KS_DECLARE(int) dht_random_bytes(void *buf, size_t size)
-{
-return 0;
-}
-*/
-
-#ifdef _WIN32
-
-#undef EAFNOSUPPORT
-#define EAFNOSUPPORT WSAEAFNOSUPPORT
-
-static int random(void)
-{
-    return rand();
-}
-
-/* Windows Vista and later already provide the implementation. */
-#if _WIN32_WINNT < 0x0600
-extern const char *inet_ntop(int, const void *, char *, socklen_t);
-#endif
-
-#else
-#endif
-
-/* We set sin_family to 0 to mark unused slots. */
-#if AF_INET == 0 || AF_INET6 == 0
-#error You lose
-#endif
-
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-/* nothing */
-#elif defined(__GNUC__)
-#define inline __inline
-#if  (__GNUC__ >= 3)
-#define restrict __restrict
-#else
-#define restrict /**/
-#endif
-#else
-#define inline /**/
-#define restrict /**/
-#endif
-
-#define MAX(x, y) ((x) >= (y) ? (x) : (y))
-#define MIN(x, y) ((x) <= (y) ? (x) : (y))
-
-struct node {
-    unsigned char id[20];
-    ks_sockaddr_t ss;
-    time_t time;                /* time of last message received */
-    time_t reply_time;          /* time of last correct reply received */
-    time_t pinged_time;         /* time of last request */
-    int pinged;                 /* how many requests we sent since last reply */
-    struct node *next;
-};
-
-struct bucket {
-    int af;
-    unsigned char first[20];
-    int count;                  /* number of nodes */
-    time_t time;                /* time of last reply in this bucket */
-    struct node *nodes;
-    ks_sockaddr_t cached;  /* the address of a likely candidate */
-    struct bucket *next;
-};
-
-struct search_node {
-    unsigned char id[20];
-    ks_sockaddr_t ss;
-    time_t request_time;        /* the time of the last unanswered request */
-    time_t reply_time;          /* the time of the last reply */
-    int pinged;
-    unsigned char token[40];
-    int token_len;
-    int replied;                /* whether we have received a reply */
-    int acked;                  /* whether they acked our announcement */
-};
-
-/* When performing a search, we search for up to SEARCH_NODES closest nodes
-   to the destination, and use the additional ones to backtrack if any of
-   the target 8 turn out to be dead. */
-#define SEARCH_NODES 14
-
-struct search {
-    unsigned short tid;
-    int af;
-    time_t step_time;           /* the time of the last search_step */
-    unsigned char id[20];
-    unsigned short port;        /* 0 for pure searches */
-    int done;
-    struct search_node nodes[SEARCH_NODES];
-    int numnodes;
-    struct search *next;
-};
-
-struct peer {
-    time_t time;
-       ks_sockaddr_t addr;
-};
-
-/* The maximum number of peers we store for a given hash. */
-#ifndef DHT_MAX_PEERS
-#define DHT_MAX_PEERS 2048
-#endif
-
-/* The maximum number of hashes we're willing to track. */
-#ifndef DHT_MAX_HASHES
-#define DHT_MAX_HASHES 16384
-#endif
-
-/* The maximum number of searches we keep data about. */
-#ifndef DHT_MAX_SEARCHES
-#define DHT_MAX_SEARCHES 1024
-#endif
-
-/* The time after which we consider a search to be expirable. */
-#ifndef DHT_SEARCH_EXPIRE_TIME
-#define DHT_SEARCH_EXPIRE_TIME (62 * 60)
-#endif
-
-struct storage {
-    unsigned char id[20];
-    int numpeers, maxpeers;
-    struct peer *peers;
-    struct storage *next;
-};
-
-static struct storage * find_storage(dht_handle_t *h, const unsigned char *id);
-static void flush_search_node(struct search_node *n, struct search *sr);
-
-typedef enum {
-       DHT_MSG_INVALID = 0,
-       DHT_MSG_ERROR = 1,
-       DHT_MSG_REPLY = 2,
-       DHT_MSG_PING = 3,
-       DHT_MSG_FIND_NODE = 4,
-       DHT_MSG_GET_PEERS = 5,
-       DHT_MSG_ANNOUNCE_PEER = 6,
-       DHT_MSG_STORE_PUT = 7
-} dht_msg_type_t;
-
-#define WANT4 1
-#define WANT6 2
-
-static dht_msg_type_t parse_message(struct bencode *bencode_p,
-                                                                       unsigned char *tid_return, int *tid_len,
-                                                                       unsigned char *id_return);
-
-static unsigned char *debug_printable(const unsigned char *buf, unsigned char *out, int buflen);
-static void print_hex(FILE *f, const unsigned char *buf, int buflen);
-static int is_martian(const ks_sockaddr_t *sa);
-static int id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2);
-static int lowbit(const unsigned char *id);
-static int common_bits(const unsigned char *id1, const unsigned char *id2);
-static int xorcmp(const unsigned char *id1, const unsigned char *id2, const unsigned char *ref);
-static int in_bucket(const unsigned char *id, struct bucket *b);
-static struct bucket *find_bucket(dht_handle_t *h, unsigned const char *id, int af);
-static struct bucket *previous_bucket(dht_handle_t *h, struct bucket *b);
-static struct node *find_node(dht_handle_t *h, const unsigned char *id, int af);
-static struct node *random_node(struct bucket *b);
-static int bucket_middle(struct bucket *b, unsigned char *id_return);
-static int bucket_random(struct bucket *b, unsigned char *id_return);
-static struct node *insert_node(dht_handle_t *h, struct node *node);
-static int node_good(dht_handle_t *h, struct node *node);
-static void make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno);
-static int tid_match(const unsigned char *tid, const char *prefix, unsigned short *seqno_return);
-static int send_cached_ping(dht_handle_t *h, struct bucket *b);
-static void pinged(dht_handle_t *h, struct node *n, struct bucket *b);
-static void blacklist_node(dht_handle_t *h, const unsigned char *id, const ks_sockaddr_t *sa);
-static int node_blacklisted(dht_handle_t *h, const ks_sockaddr_t *sa);
-static struct bucket *split_bucket(dht_handle_t *h, struct bucket *b);
-static struct node *new_node(dht_handle_t *h, const unsigned char *id, const ks_sockaddr_t *sa, int confirm);
-static int expire_buckets(dht_handle_t *h, struct bucket *b);
-static struct search *find_search(dht_handle_t *h, unsigned short tid, int af);
-static int insert_search_node(dht_handle_t *h, unsigned char *id,
-                                                         const ks_sockaddr_t *sa,
-                                                         struct search *sr, int replied,
-                                                         unsigned char *token, int token_len);
-static void flush_search_node(struct search_node *n, struct search *sr);
-static void expire_searches(dht_handle_t *h);
-static int search_send_get_peers(dht_handle_t *h, struct search *sr, struct search_node *n);
-static void search_step(dht_handle_t *h, struct search *sr);
-static struct search *new_search(dht_handle_t *h);
-static void insert_search_bucket(dht_handle_t *h, struct bucket *b, struct search *sr);
-static struct storage *find_storage(dht_handle_t *h, const unsigned char *id);
-static int storage_store(dht_handle_t *h, const unsigned char *id, const ks_sockaddr_t *sa, unsigned short port);
-static int expire_storage(dht_handle_t *h);
-static int rotate_secrets(dht_handle_t *h);
-static void make_token(dht_handle_t *h, const ks_sockaddr_t *sa, int old, unsigned char *token_return);
-static int token_match(dht_handle_t *h, const unsigned char *token, int token_len, const ks_sockaddr_t *sa);
-static void dump_bucket(dht_handle_t *h, FILE *f, struct bucket *b);
-
-static void reset_poll(dht_handle_t *h);
-static void clear_all_ip(dht_handle_t *h);
-static int token_bucket(dht_handle_t *h);
-static int neighbourhood_maintenance(dht_handle_t *h, int af);
-static int bucket_maintenance(dht_handle_t *h, int af);
-static int dht_send(dht_handle_t *h, const void *buf, size_t len, int flags, const ks_sockaddr_t *sa);
-
-static int send_ping(dht_handle_t *h, const ks_sockaddr_t *sa, const unsigned char *tid, int tid_len);
-static int send_pong(dht_handle_t *h, const ks_sockaddr_t *sa, const unsigned char *tid, int tid_len);
-static int send_find_node(dht_handle_t *h, const ks_sockaddr_t *sa, const unsigned char *tid, int tid_len, const unsigned char *target, int target_len,
-                                                 int want, int confirm);
-static int send_nodes_peers(dht_handle_t *h, const ks_sockaddr_t *sa, const unsigned char *tid, int tid_len, const unsigned char *nodes, int nodes_len,
-                            const unsigned char *nodes6, int nodes6_len, int af, struct storage *st, const unsigned char *token, int token_len);
-static int insert_closest_node(unsigned char *nodes, int numnodes, const unsigned char *id, struct node *n);
-static int buffer_closest_nodes(dht_handle_t *h, unsigned char *nodes, int numnodes, const unsigned char *id, struct bucket *b);
-static int send_closest_nodes(dht_handle_t *h, const ks_sockaddr_t *sa, const unsigned char *tid, int tid_len, const unsigned char *id, int want,
-                              int af, struct storage *st, const unsigned char *token, int token_len);
-static int send_get_peers(dht_handle_t *h, const ks_sockaddr_t *sa, unsigned char *tid, int tid_len, unsigned char *infohash, int want, int confirm);
-static int send_announce_peer(dht_handle_t *h, const ks_sockaddr_t *sa, unsigned char *tid, int tid_len, unsigned char *infohas, unsigned short port,
-                              unsigned char *token, int token_len, int confirm);
-static int send_peer_announced(dht_handle_t *h, const ks_sockaddr_t *sa, unsigned char *tid, int tid_len);
-static int send_error(dht_handle_t *h, const ks_sockaddr_t *sa, unsigned char *tid, int tid_len, int code, const char *message);
-
-static dht_msg_type_t parse_message(struct bencode *bencode_p, unsigned char *tid_return, int *tid_len, unsigned char *id_return);
-static int b64encode(unsigned char *in, ks_size_t ilen, unsigned char *out, ks_size_t olen);
-
-
-static const unsigned char zeroes[20] = {0};
-//static const unsigned char v4prefix[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
-
-#define MAX_TOKEN_BUCKET_TOKENS 400
-
-/* The maximum number of nodes that we snub.  There is probably little
-   reason to increase this value. */
-#ifndef DHT_MAX_BLACKLISTED
-#define DHT_MAX_BLACKLISTED 10
-#endif
-
-struct ks_dht_store_entry_s {
-    const char *key;
-
-       ks_time_t received; /* recieved timestamp */
-       ks_time_t last_announce;
-       ks_time_t expiration; /* When should 'my' message be automatically expired. If not set will be expired after 10 minutes */
-
-       /* Top level struct pointers. Will need to be freed */
-       struct bencode *bencode_message_raw;
-       struct bencode *payload_bencode;
-       cJSON *body;
-
-       /* Short cut accessor pointers. Do not free these. */
-       const char *content_type;
-       const char *payload_raw;
-
-       unsigned int serial;
-       ks_bool_t mine;
-       ks_pool_t *pool;
-};
-
-struct ks_dht_store_s {
-    ks_time_t next_expiring;
-       ks_hash_t *hash;
-       ks_pool_t *pool;
-};
-
-typedef struct {
-       char ip[80];
-       ks_sockaddr_t addr;
-       ks_socket_t sock;
-} ks_ip_t;
-
-struct dht_handle_s {
-       ks_pool_t *pool;
-
-       struct pollfd *pollsocks;
-       ks_ip_t **iptsocks;
-       ks_sockaddr_t **addrsocks;
-       uint32_t num_pollsocks;
-
-       //int dht_socket;
-       //int dht_socket6;
-
-       time_t search_time;
-       time_t confirm_nodes_time;
-       time_t rotate_secrets_time;
-
-       unsigned char myid[20];
-       int have_v;
-       unsigned char my_v[9];
-       unsigned char secret[8];
-       unsigned char oldsecret[8];
-       unsigned int port;
-
-       struct bucket *buckets;
-       struct bucket *buckets6;
-       struct storage *storage;
-       int numstorage;
-
-       struct search *searches;
-       int numsearches;
-       unsigned short search_id;
-
-       ks_sockaddr_t blacklist[DHT_MAX_BLACKLISTED];
-       int next_blacklisted;
-
-       ks_time_t now;
-       time_t mybucket_grow_time, mybucket6_grow_time;
-       time_t expire_stuff_time;
-
-       time_t token_bucket_time;
-       int token_bucket_tokens;
-
-       ks_dht_store_entry_json_cb *store_json_cb;
-       void *store_json_cb_arg;
-       
-       ks_hash_t *iphash;
-
-       struct ks_dht_store_s *store;
-
-       dht_callback_t callback;
-       void *closure;
-
-       uint32_t ip4s;
-       uint32_t ip6s;
-
-       int af_flags;
-
-       int tosleep;
-
-       int autoroute;
-
-       int started;
-};
-
-static ks_ip_t *add_ip(dht_handle_t *h, const char *ip, int port, int family);
-
-static void ks_dht_store_entry_destroy(struct ks_dht_store_entry_s **old_entry);
-static int ks_dht_store_entry_create(struct dht_handle_s *h, struct bencode *msg, struct ks_dht_store_entry_s **new_entry, ks_time_t life, ks_bool_t mine);
-static struct ks_dht_store_entry_s *ks_dht_store_fetch(struct ks_dht_store_s *store, char *key);
-static int ks_dht_store_insert(struct ks_dht_store_s *store, struct ks_dht_store_entry_s *entry, ks_time_t now);
-static int ks_dht_store_replace(struct ks_dht_store_s *store, struct ks_dht_store_entry_s *entry);
-static void ks_dht_store_prune(struct ks_dht_store_s *store, ks_time_t now);
-static int ks_dht_store_create(ks_pool_t *pool, struct ks_dht_store_s **new_store);
-static void ks_dht_store_destroy(struct ks_dht_store_s **old_store);
-
-
-KS_DECLARE(void) ks_dht_store_entry_json_cb_set(struct dht_handle_s *h, ks_dht_store_entry_json_cb *store_json_cb, void *arg)
-{
-       h->store_json_cb = store_json_cb;
-       h->store_json_cb_arg = arg;
-}
-
-static unsigned char *debug_printable(const unsigned char *buf, unsigned char *out, int buflen)
-{
-    int i;
-       for (i = 0; i < buflen; i++) {
-               out[i] = (buf[i] >= 32 && buf[i] <= 126) ? buf[i] : '.';
-       }
-       return out;
-}
-
-static void print_hex(FILE *f, const unsigned char *buf, int buflen)
-{
-    int i;
-    for (i = 0; i < buflen; i++) {
-        fprintf(f, "%02x", buf[i]);
-       }
-}
-
-static int is_martian(const ks_sockaddr_t *sa)
-{
-    switch(sa->family) {
-    case AF_INET: {
-               return (sa->port == 0);
-    }
-    case AF_INET6: {
-               return (sa->port == 0);
-    }
-
-    default:
-        return 1;
-    }
-}
-
-/* Forget about the ``XOR-metric''.  An id is just a path from the
-   root of the tree, so bits are numbered from the start. */
-
-static int id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2)
-{
-    /* Memcmp is guaranteed to perform an unsigned comparison. */
-    return memcmp(id1, id2, 20);
-}
-
-/* Find the lowest 1 bit in an id. */
-static int lowbit(const unsigned char *id)
-{
-    int i, j;
-
-    for (i = 19; i >= 0; i--) {
-        if (id[i] != 0) {
-                       break;
-               }
-       }
-
-    if (i < 0) return -1;
-
-    for (j = 7; j >= 0; j--) {
-        if ((id[i] & (0x80 >> j)) != 0) {
-                       break;
-               }
-       }
-
-    return 8 * i + j;
-}
-
-/* Find how many bits two ids have in common. */
-static int common_bits(const unsigned char *id1, const unsigned char *id2)
-{
-    int i, j;
-    unsigned char xor;
-    for (i = 0; i < 20; i++) {
-        if (id1[i] != id2[i]) {
-            break;
-               }
-    }
-
-    if (i == 20) {
-        return 160;
-       }
-
-    xor = id1[i] ^ id2[i];
-
-    j = 0;
-    while ((xor & 0x80) == 0) {
-        xor <<= 1;
-        j++;
-    }
-
-    return 8 * i + j;
-}
-
-/* Determine whether id1 or id2 is closer to ref */
-static int xorcmp(const unsigned char *id1, const unsigned char *id2, const unsigned char *ref)
-{
-    int i;
-    for (i = 0; i < 20; i++) {
-        unsigned char xor1, xor2;
-        if (id1[i] == id2[i]) {
-            continue;
-               }
-        xor1 = id1[i] ^ ref[i];
-        xor2 = id2[i] ^ ref[i];
-        if (xor1 < xor2) {
-            return -1;
-               }
-               return 1;
-    }
-    return 0;
-}
-
-/* We keep buckets in a sorted linked list.  A bucket b ranges from
-   b->first inclusive up to b->next->first exclusive. */
-static int in_bucket(const unsigned char *id, struct bucket *b)
-{
-    return id_cmp(b->first, id) <= 0 && (b->next == NULL || id_cmp(id, b->next->first) < 0);
-}
-
-static struct bucket *find_bucket(dht_handle_t *h, unsigned const char *id, int af)
-{
-    struct bucket *b = af == AF_INET ? h->buckets : h->buckets6;
-
-    if (b == NULL) {
-        return NULL;
-       }
-
-    while (1) {
-        if (b->next == NULL) {
-            return b;
-               }
-
-        if (id_cmp(id, b->next->first) < 0) {
-            return b;
-               }
-
-        b = b->next;
-    }
-}
-
-static struct bucket *previous_bucket(dht_handle_t *h, struct bucket *b)
-{
-    struct bucket *p = b->af == AF_INET ? h->buckets : h->buckets6;
-
-    if (b == p) {
-        return NULL;
-       }
-
-    while (1) {
-        if (p->next == NULL) {
-            return NULL;
-               }
-
-        if (p->next == b) {
-            return p;
-               }
-
-        p = p->next;
-    }
-}
-
-/* Every bucket contains an unordered list of nodes. */
-static struct node *find_node(dht_handle_t *h, const unsigned char *id, int af)
-{
-    struct bucket *b = find_bucket(h, id, af);
-    struct node *n;
-
-    if (b == NULL)
-        return NULL;
-
-    n = b->nodes;
-    while (n) {
-        if (id_cmp(n->id, id) == 0) {
-            return n;
-               }
-        n = n->next;
-    }
-    return NULL;
-}
-
-/* Return a random node in a bucket. */
-static struct node *random_node(struct bucket *b)
-{
-    struct node *n;
-    int nn;
-
-    if (b->count == 0) {
-        return NULL;
-       }
-
-    nn = random() % b->count;
-    n = b->nodes;
-    while (nn > 0 && n) {
-        n = n->next;
-        nn--;
-    }
-    return n;
-}
-
-/* Return the middle id of a bucket. */
-static int bucket_middle(struct bucket *b, unsigned char *id_return)
-{
-    int bit1 = lowbit(b->first);
-    int bit2 = b->next ? lowbit(b->next->first) : -1;
-    int bit = MAX(bit1, bit2) + 1;
-
-    if (bit >= 160) {
-        return -1;
-       }
-
-    memcpy(id_return, b->first, 20);
-    id_return[bit / 8] |= (0x80 >> (bit % 8));
-    return 1;
-}
-
-/* Return a random id within a bucket. */
-static int bucket_random(struct bucket *b, unsigned char *id_return)
-{
-    int bit1 = lowbit(b->first);
-    int bit2 = b->next ? lowbit(b->next->first) : -1;
-    int bit = MAX(bit1, bit2) + 1;
-    int i;
-
-    if (bit >= 160) {
-        memcpy(id_return, b->first, 20);
-        return 1;
-    }
-
-    memcpy(id_return, b->first, bit / 8);
-    id_return[bit / 8] = b->first[bit / 8] & (0xFF00 >> (bit % 8));
-    id_return[bit / 8] |= random() & 0xFF >> (bit % 8);
-    for (i = bit / 8 + 1; i < 20; i++) {
-        id_return[i] = random() & 0xFF;
-       }
-    return 1;
-}
-
-/* Insert a new node into a bucket. */
-static struct node *insert_node(dht_handle_t *h, struct node *node)
-{
-    struct bucket *b = find_bucket(h, node->id, node->ss.family);
-
-    if (b == NULL) {
-        return NULL;
-       }
-
-    node->next = b->nodes;
-    b->nodes = node;
-    b->count++;
-    return node;
-}
-
-/* This is our definition of a known-good node. */
-static int node_good(dht_handle_t *h, struct node *node)
-{
-    return node->pinged <= 2 && node->reply_time >= h->now - 7200 && node->time >= h->now - 900;
-}
-
-/* Our transaction-ids are 4-bytes long, with the first two bytes identi-
-   fying the kind of request, and the remaining two a sequence number in
-   host order. */
-
-static void make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno)
-{
-    tid_return[0] = prefix[0] & 0xFF;
-    tid_return[1] = prefix[1] & 0xFF;
-    memcpy(tid_return + 2, &seqno, 2);
-}
-
-static int tid_match(const unsigned char *tid, const char *prefix, unsigned short *seqno_return)
-{
-    if (tid[0] == (prefix[0] & 0xFF) && tid[1] == (prefix[1] & 0xFF)) {
-        if (seqno_return) {
-            memcpy(seqno_return, tid + 2, 2);
-               }
-        return 1;
-    }
-
-       return 0;
-}
-
-/* Every bucket caches the address of a likely node.  Ping it. */
-static int send_cached_ping(dht_handle_t *h, struct bucket *b)
-{
-    unsigned char tid[4];
-    int rc;
-    /* We set family to 0 when there's no cached node. */
-    if (b->cached.family == 0) {
-        return 0;
-       }
-
-    ks_log(KS_LOG_DEBUG, "Sending ping to cached node.\n");
-    make_tid(tid, "pn", 0);
-    rc = send_ping(h, &b->cached, tid, 4);
-    b->cached.family = 0;
-    return rc;
-}
-
-/* Called whenever we send a request to a node, increases the ping count
-   and, if that reaches 3, sends a ping to a new candidate. */
-static void pinged(dht_handle_t *h, struct node *n, struct bucket *b)
-{
-    n->pinged++;
-    n->pinged_time = h->now;
-    if (n->pinged >= 3) {
-        send_cached_ping(h, b ? b : find_bucket(h, n->id, n->ss.family));
-       }
-}
-
-/* The internal blacklist is an LRU cache of nodes that have sent
-   incorrect messages. */
-static void blacklist_node(dht_handle_t *h, const unsigned char *id, const ks_sockaddr_t *sa)
-{
-    int i;
-
-    ks_log(KS_LOG_DEBUG, "Blacklisting broken node.\n");
-
-    if (id) {
-        struct node *n;
-        struct search *sr;
-        /* Make the node easy to discard. */
-        n = find_node(h, id, sa->family);
-        if (n) {
-            n->pinged = 3;
-            pinged(h, n, NULL);
-        }
-        /* Discard it from any searches in progress. */
-        sr = h->searches;
-        while (sr) {
-            for (i = 0; i < sr->numnodes; i++) {
-                if (id_cmp(sr->nodes[i].id, id) == 0) {
-                    flush_search_node(&sr->nodes[i], sr);
-                               }
-                       }
-            sr = sr->next;
-        }
-    }
-    /* And make sure we don't hear from it again. */
-       ks_addr_copy(&h->blacklist[h->next_blacklisted], sa);
-    h->next_blacklisted = (h->next_blacklisted + 1) % DHT_MAX_BLACKLISTED;
-}
-
-static int node_blacklisted(dht_handle_t *h, const ks_sockaddr_t *sa)
-{
-    int i;
-
-    if (dht_blacklisted(sa)) {
-        return 1;
-       }
-
-    for(i = 0; i < DHT_MAX_BLACKLISTED; i++) {
-               if (ks_addr_cmp(&h->blacklist[i], sa)) {
-            return 1;
-               }
-    }
-
-    return 0;
-}
-
-/* Split a bucket into two equal parts. */
-static struct bucket *split_bucket(dht_handle_t *h, struct bucket *b)
-{
-    struct bucket *new;
-    struct node *nodes;
-    int rc;
-    unsigned char new_id[20];
-
-    if ((rc = bucket_middle(b, new_id)) < 0) {
-        return NULL;
-       }
-
-       new = ks_pool_alloc(h->pool, sizeof(struct bucket));
-
-    new->af = b->af;
-
-    send_cached_ping(h, b);
-
-    memcpy(new->first, new_id, 20);
-    new->time = b->time;
-
-    nodes = b->nodes;
-    b->nodes = NULL;
-    b->count = 0;
-    new->next = b->next;
-    b->next = new;
-    while (nodes) {
-        struct node *n;
-        n = nodes;
-        nodes = nodes->next;
-        insert_node(h, n);
-    }
-    return b;
-}
-
-/* We just learnt about a node, not necessarily a new one.  Confirm is 1 if
-   the node sent a message, 2 if it sent us a reply. */
-static struct node *new_node(dht_handle_t *h, const unsigned char *id, const ks_sockaddr_t *sa, int confirm)
-{
-    struct bucket *b = find_bucket(h, id, sa->family);
-    struct node *n;
-    int mybucket, split;
-
-    if (b == NULL) {
-        return NULL;
-       }
-
-    if (id_cmp(id, h->myid) == 0) {
-        return NULL;
-       }
-
-    if (is_martian(sa) || node_blacklisted(h, sa)) {
-        return NULL;
-       }
-
-    mybucket = in_bucket(h->myid, b);
-
-    if (confirm == 2) {
-        b->time = h->now;
-       }
-
-    n = b->nodes;
-    while (n) {
-        if (id_cmp(n->id, id) == 0) {
-            if (confirm || n->time < h->now - 15 * 60) {
-                /* Known node.  Update stuff. */
-                               ks_addr_copy(&n->ss, sa);
-
-                if (confirm) {
-                    n->time = h->now;
-                               }
-                if (confirm >= 2) {
-                    n->reply_time = h->now;
-                    n->pinged = 0;
-                    n->pinged_time = 0;
-                }
-            }
-            return n;
-        }
-        n = n->next;
-    }
-
-    /* New node. */
-
-    if (mybucket) {
-        if (sa->family == AF_INET) {
-            h->mybucket_grow_time = h->now;
-               } else {
-            h->mybucket6_grow_time = h->now;
-               }
-    }
-
-    /* First, try to get rid of a known-bad node. */
-    n = b->nodes;
-    while (n) {
-        if (n->pinged >= 3 && n->pinged_time < h->now - 15) {
-            memcpy(n->id, id, 20);
-                       ks_addr_copy(&n->ss, sa);
-            n->time = confirm ? h->now : 0;
-            n->reply_time = confirm >= 2 ? h->now : 0;
-            n->pinged_time = 0;
-            n->pinged = 0;
-            return n;
-        }
-        n = n->next;
-    }
-
-    if (b->count >= 8) {
-        /* Bucket full.  Ping a dubious node */
-        int dubious = 0;
-        n = b->nodes;
-        while (n) {
-            /* Pick the first dubious node that we haven't pinged in the
-               last 15 seconds.  This gives nodes the time to reply, but
-               tends to concentrate on the same nodes, so that we get rid
-               of bad nodes fast. */
-            if (!node_good(h, n)) {
-                dubious = 1;
-                if (n->pinged_time < h->now - 15) {
-                    unsigned char tid[4];
-                    ks_log(KS_LOG_DEBUG, "Sending ping to dubious node.\n");
-                    make_tid(tid, "pn", 0);
-                    send_ping(h, &n->ss, tid, 4);
-                    n->pinged++;
-                    n->pinged_time = h->now;
-                    break;
-                }
-            }
-            n = n->next;
-        }
-
-        split = 0;
-        if (mybucket) {
-            if (!dubious) {
-                split = 1;
-                       }
-            /* If there's only one bucket, split eagerly.  This is
-               incorrect unless there's more than 8 nodes in the DHT. */
-            else if (b->af == AF_INET && h->buckets->next == NULL) {
-                split = 1;
-                       } else if (b->af == AF_INET6 && h->buckets6->next == NULL) {
-                split = 1;
-                       }
-        }
-
-        if (split) {
-            ks_log(KS_LOG_DEBUG, "Splitting.\n");
-            b = split_bucket(h, b);
-            return new_node(h, id, sa, confirm);
-        }
-
-        /* No space for this node.  Cache it away for later. */
-        if (confirm || b->cached.family == 0) {
-                       ks_addr_copy(&b->cached, sa);
-        }
-
-        return NULL;
-    }
-       
-    /* Create a new node. */
-    n = ks_pool_alloc(h->pool, sizeof(struct node));
-
-    memcpy(n->id, id, 20);
-       ks_addr_copy(&n->ss, sa);
-    n->time = confirm ? h->now : 0;
-    n->reply_time = confirm >= 2 ? h->now : 0;
-    n->next = b->nodes;
-    b->nodes = n;
-    b->count++;
-    return n;
-}
-
-/* Called periodically to purge known-bad nodes.  Note that we're very
-   conservative here: broken nodes in the table don't do much harm, we'll
-   recover as soon as we find better ones. */
-static int expire_buckets(dht_handle_t *h, struct bucket *b)
-{
-    while (b) {
-        struct node *n, *p;
-        int changed = 0;
-
-        while (b->nodes && b->nodes->pinged >= 4) {
-            n = b->nodes;
-            b->nodes = n->next;
-            b->count--;
-            changed = 1;
-            ks_pool_free(h->pool, &n);
-        }
-
-        p = b->nodes;
-        while (p) {
-            while (p->next && p->next->pinged >= 4) {
-                n = p->next;
-                p->next = n->next;
-                b->count--;
-                changed = 1;
-                ks_pool_free(h->pool, &n);
-            }
-            p = p->next;
-        }
-
-        if (changed) {
-            send_cached_ping(h, b);
-               }
-
-        b = b->next;
-    }
-    h->expire_stuff_time = h->now + 120 + random() % 240;
-    return 1;
-}
-
-/* While a search is in progress, we don't necessarily keep the nodes being
-   walked in the main bucket table.  A search in progress is identified by
-   a unique transaction id, a short (and hence small enough to fit in the
-   transaction id of the protocol packets). */
-
-static struct search *find_search(dht_handle_t *h, unsigned short tid, int af)
-{
-    struct search *sr = h->searches;
-    while (sr) {
-        if (sr->tid == tid && sr->af == af) {
-            return sr;
-               }
-        sr = sr->next;
-    }
-    return NULL;
-}
-
-/* A search contains a list of nodes, sorted by decreasing distance to the
-   target.  We just got a new candidate, insert it at the right spot or
-   discard it. */
-
-static int insert_search_node(dht_handle_t *h, unsigned char *id,
-                   const ks_sockaddr_t *sa,
-                   struct search *sr, int replied,
-                   unsigned char *token, int token_len)
-{
-    struct search_node *n;
-    int i, j;
-
-    if (sa->family != sr->af) {
-        ks_log(KS_LOG_DEBUG, "Attempted to insert node in the wrong family.\n");
-        return 0;
-    }
-
-    for(i = 0; i < sr->numnodes; i++) {
-        if (id_cmp(id, sr->nodes[i].id) == 0) {
-            n = &sr->nodes[i];
-            goto found;
-        }
-        if (xorcmp(id, sr->nodes[i].id, sr->id) < 0) {
-            break;
-               }
-    }
-
-    if (i == SEARCH_NODES) {
-        return 0;
-       }
-
-    if (sr->numnodes < SEARCH_NODES) {
-        sr->numnodes++;
-       }
-
-    for (j = sr->numnodes - 1; j > i; j--) {
-        sr->nodes[j] = sr->nodes[j - 1];
-    }
-
-    n = &sr->nodes[i];
-
-    memset(n, 0, sizeof(struct search_node));
-    memcpy(n->id, id, 20);
-
-found:
-
-       ks_addr_copy(&n->ss, sa);
-
-    if (replied) {
-        n->replied = 1;
-        n->reply_time = h->now;
-        n->request_time = 0;
-        n->pinged = 0;
-    }
-    if (token) {
-        if (token_len >= 40) {
-            ks_log(KS_LOG_DEBUG, "Eek!  Overlong token.\n");
-                       assert(0);
-        } else {
-            memcpy(n->token, token, token_len);
-            n->token_len = token_len;
-        }
-    }
-
-    return 1;
-}
-
-static void flush_search_node(struct search_node *n, struct search *sr)
-{
-    int i = n - sr->nodes, j;
-    for (j = i; j < sr->numnodes - 1; j++) {
-        sr->nodes[j] = sr->nodes[j + 1];
-       }
-    sr->numnodes--;
-}
-
-static void expire_searches(dht_handle_t *h)
-{
-    struct search *sr = h->searches, *previous = NULL;
-
-    while (sr) {
-        struct search *next = sr->next;
-        if (sr->step_time < h->now - DHT_SEARCH_EXPIRE_TIME) {
-            if (previous) {
-                previous->next = next;
-            } else {
-                h->searches = next;
-                       }
-            ks_pool_free(h->pool, &sr);
-            h->numsearches--;
-        } else {
-            previous = sr;
-        }
-        sr = next;
-    }
-}
-
-/* This must always return 0 or 1, never -1, not even on failure (see below). */
-static int search_send_get_peers(dht_handle_t *h, struct search *sr, struct search_node *n)
-{
-    struct node *node;
-    unsigned char tid[4];
-
-    if (n == NULL) {
-        int i;
-        for (i = 0; i < sr->numnodes; i++) {
-            if (sr->nodes[i].pinged < 3 && !sr->nodes[i].replied && sr->nodes[i].request_time < h->now - 15) {
-                n = &sr->nodes[i];
-                       }
-        }
-    }
-
-    if (!n || n->pinged >= 3 || n->replied || n->request_time >= h->now - 15) {
-        return 0;
-       }
-
-    ks_log(KS_LOG_DEBUG, "Sending get_peers.\n");
-    make_tid(tid, "gp", sr->tid);
-    send_get_peers(h, &n->ss, tid, 4, sr->id, -1, n->reply_time >= h->now - 15);
-    n->pinged++;
-    n->request_time = h->now;
-    /* If the node happens to be in our main routing table, mark it as pinged. */
-    if ((node = find_node(h, n->id, n->ss.family))) {
-               pinged(h, node, NULL);
-       }
-    return 1;
-}
-
-/* When a search is in progress, we periodically call search_step to send
-   further requests. */
-static void search_step(dht_handle_t *h, struct search *sr)
-{
-    int i, j;
-    int all_done = 1;
-
-    /* Check if the first 8 live nodes have replied. */
-    j = 0;
-    for (i = 0; i < sr->numnodes && j < 8; i++) {
-        struct search_node *n = &sr->nodes[i];
-        if (n->pinged >= 3) {
-            continue;
-               }
-        if (!n->replied) {
-            all_done = 0;
-            break;
-        }
-        j++;
-    }
-
-    if (all_done) {
-               int all_acked = 1;
-        if (sr->port == 0) {
-            goto done;
-        }
-
-               j = 0;
-
-               for (i = 0; i < sr->numnodes && j < 8; i++) {
-                       struct search_node *n = &sr->nodes[i];
-                       struct node *node;
-                       unsigned char tid[4];
-                       if (n->pinged >= 3) {
-                               continue;
-                       }
-                       /* A proposed extension to the protocol consists in omitting the token when storage tables are full.  While
-                          I don't think this makes a lot of sense -- just sending a positive reply is just as good --, let's deal with it. */
-                       if (n->token_len == 0) {
-                               n->acked = 1;
-                       }
-                       if (!n->acked) {
-                               all_acked = 0;
-                               ks_log(KS_LOG_DEBUG, "Sending announce_peer.\n");
-                               make_tid(tid, "ap", sr->tid);
-                               send_announce_peer(h, &n->ss,
-                                                                  tid, 4, sr->id, sr->port,
-                                                                  n->token, n->token_len,
-                                                                  n->reply_time < h->now - 15);
-                               n->pinged++;
-                               n->request_time = h->now;
-                               node = find_node(h, n->id, n->ss.family);
-                               if (node) pinged(h, node, NULL);
-                       }
-                       j++;
-               }
-               if (all_acked) {
-                       goto done;
-               }
-
-        sr->step_time = h->now;
-        return;
-    }
-
-    if (sr->step_time + 15 >= h->now) {
-        return;
-       }
-
-    j = 0;
-    for (i = 0; i < sr->numnodes; i++) {
-        j += search_send_get_peers(h, sr, &sr->nodes[i]);
-        if (j >= 3) {
-            break;
-               }
-    }
-    sr->step_time = h->now;
-    return;
-
- done:
-    sr->done = 1;
-    if (h->callback) {
-        h->callback(h->closure, sr->af == AF_INET ? KS_DHT_EVENT_SEARCH_DONE : KS_DHT_EVENT_SEARCH_DONE6, sr->id, NULL, 0);
-       }
-    sr->step_time = h->now;
-}
-
-static struct search *new_search(dht_handle_t *h)
-{
-    struct search *sr, *oldest = NULL;
-
-    /* Find the oldest done search */
-    sr = h->searches;
-    while (sr) {
-        if (sr->done && (oldest == NULL || oldest->step_time > sr->step_time)) {
-            oldest = sr;
-               }
-        sr = sr->next;
-    }
-
-    /* The oldest slot is expired. */
-    if (oldest && oldest->step_time < h->now - DHT_SEARCH_EXPIRE_TIME) {
-        return oldest;
-       }
-
-    /* Allocate a new slot. */
-    if (h->numsearches < DHT_MAX_SEARCHES) {
-               sr = ks_pool_alloc(h->pool, sizeof(struct search));
-               sr->next = h->searches;
-               h->searches = sr;
-               h->numsearches++;
-               return sr;
-    }
-
-    /* Oh, well, never mind.  Reuse the oldest slot. */
-    return oldest;
-}
-
-/* Insert the contents of a bucket into a search structure. */
-static void insert_search_bucket(dht_handle_t *h, struct bucket *b, struct search *sr)
-{
-    struct node *n;
-    n = b->nodes;
-    while (n) {
-        insert_search_node(h, n->id, &n->ss, sr, 0, NULL, 0);
-        n = n->next;
-    }
-}
-
-/* Start a search.  If port is non-zero, perform an announce when the
-   search is complete. */
-KS_DECLARE(int) dht_search(dht_handle_t *h, const unsigned char *id, int port, int af, dht_callback_t callback, void *closure)
-{
-    struct search *sr;
-    struct storage *st;
-    struct bucket *b = find_bucket(h, id, af);
-
-    if (b == NULL) {
-        errno = EAFNOSUPPORT;
-        return -1;
-    }
-
-       if (!callback) callback = h->callback;
-       if (!closure) closure = h->closure;
-
-    /* Try to answer this search locally.  In a fully grown DHT this
-       is very unlikely, but people are running modified versions of
-       this code in private DHTs with very few nodes.  What's wrong
-       with flooding? */
-    if (callback) {
-        st = find_storage(h, id);
-        if (st) {
-            int i;
-
-            ks_log(KS_LOG_DEBUG, "Found local data (%d peers).\n", st->numpeers);
-
-            for (i = 0; i < st->numpeers; i++) {
-                               (*callback)(closure, st->peers[i].addr.family == AF_INET ? KS_DHT_EVENT_VALUES : KS_DHT_EVENT_VALUES6, id, (void *)&st->peers[i].addr, sizeof(st->peers[i].addr));
-            }
-        }
-    }
-
-    sr = h->searches;
-    while (sr) {
-        if (sr->af == af && id_cmp(sr->id, id) == 0) {
-            break;
-               }
-        sr = sr->next;
-    }
-
-    if (sr) {
-        /* We're reusing data from an old search.  Reusing the same tid
-           means that we can merge replies for both searches. */
-        int i;
-        sr->done = 0;
-    again:
-        for (i = 0; i < sr->numnodes; i++) {
-            struct search_node *n;
-            n = &sr->nodes[i];
-            /* Discard any doubtful nodes. */
-            if (n->pinged >= 3 || n->reply_time < h->now - 7200) {
-                flush_search_node(n, sr);
-                goto again;
-            }
-            n->pinged = 0;
-            n->token_len = 0;
-            n->replied = 0;
-            n->acked = 0;
-        }
-    } else {
-        sr = new_search(h);
-        if (sr == NULL) {
-            errno = ENOSPC;
-            return -1;
-        }
-        sr->af = af;
-        sr->tid = h->search_id++;
-        sr->step_time = 0;
-        memcpy(sr->id, id, 20);
-        sr->done = 0;
-        sr->numnodes = 0;
-    }
-
-    sr->port = port;
-
-    insert_search_bucket(h, b, sr);
-
-    if (sr->numnodes < SEARCH_NODES) {
-        struct bucket *p = previous_bucket(h, b);
-        if (b->next) {
-            insert_search_bucket(h, b->next, sr);
-               }
-        if (p) {
-            insert_search_bucket(h, p, sr);
-               }
-    }
-    if (sr->numnodes < SEARCH_NODES) {
-        insert_search_bucket(h, find_bucket(h, h->myid, af), sr);
-       }
-
-    search_step(h, sr);
-    h->search_time = h->now;
-    return 1;
-}
-
-/* A struct storage stores all the stored peer addresses for a given info hash. */
-static struct storage *find_storage(dht_handle_t *h, const unsigned char *id)
-{
-    struct storage *st = h->storage;
-
-    while(st) {
-        if (id_cmp(id, st->id) == 0) {
-            break;
-               }
-        st = st->next;
-    }
-    return st;
-}
-
-static int storage_store(dht_handle_t *h, const unsigned char *id, const ks_sockaddr_t *sa, unsigned short port)
-{
-    int i;
-    struct storage *st;
-
-    st = find_storage(h, id);
-
-    if (st == NULL) {
-        if (h->numstorage >= DHT_MAX_HASHES) {
-            return -1;
-               }
-
-               st = ks_pool_alloc(h->pool, sizeof(struct storage));
-        memcpy(st->id, id, 20);
-        st->next = h->storage;
-        h->storage = st;
-        h->numstorage++;
-    }
-
-    for(i = 0; i < st->numpeers; i++) {
-               if (ks_addr_cmp(&st->peers[i].addr, sa)) {
-            break;
-               }
-    }
-
-    if (i < st->numpeers) {
-        /* Already there, only need to refresh */
-        st->peers[i].time = h->now;
-        return 0;
-    } else {
-        struct peer *p;
-        if (i >= st->maxpeers) {
-            /* Need to expand the array. */
-            struct peer *new_peers;
-            int n;
-            if (st->maxpeers >= DHT_MAX_PEERS) {
-                return 0;
-                       }
-            n = st->maxpeers == 0 ? 2 : 2 * st->maxpeers;
-            n = MIN(n, DHT_MAX_PEERS);
-            
-            if (!(new_peers = realloc(st->peers, n * sizeof(struct peer)))) {
-                return -1;
-                       }
-            st->peers = new_peers;
-            st->maxpeers = n;
-        }
-        p = &st->peers[st->numpeers++];
-        p->time = h->now;
-               ks_addr_copy(&p->addr, sa);
-        return 1;
-    }
-}
-
-static int expire_storage(dht_handle_t *h)
-{
-    struct storage *st = h->storage, *previous = NULL;
-
-    while (st) {
-        int i = 0;
-        while (i < st->numpeers) {
-            if (st->peers[i].time < h->now - 32 * 60) {
-                if (i != st->numpeers - 1)
-                    st->peers[i] = st->peers[st->numpeers - 1];
-                st->numpeers--;
-            } else {
-                i++;
-            }
-        }
-
-        if (st->numpeers == 0) {
-            free(st->peers);
-            if (previous) {
-                previous->next = st->next;
-                               ks_pool_free(h->pool, &st);
-                st = previous->next;
-                       } else {
-                h->storage = st->next;
-                               ks_pool_free(h->pool, &st);
-                st = h->storage;
-                       }
-
-            h->numstorage--;
-            if (h->numstorage < 0) {
-                ks_log(KS_LOG_DEBUG, "Eek... numstorage became negative.\n");
-                h->numstorage = 0;
-            }
-        } else {
-            previous = st;
-            st = st->next;
-        }
-    }
-    return 1;
-}
-
-static int rotate_secrets(dht_handle_t *h)
-{
-    h->rotate_secrets_time = h->now + 900 + random() % 1800;
-
-    memcpy(h->oldsecret, h->secret, sizeof(h->secret));
-       randombytes_buf(h->secret, sizeof(h->secret));
-
-    return 1;
-}
-
-#ifndef TOKEN_SIZE
-#define TOKEN_SIZE 8
-#endif
-
-static void make_token(dht_handle_t *h, const ks_sockaddr_t *sa, int old, unsigned char *token_return)
-{
-    void *ip;
-    ks_size_t iplen;
-    unsigned short port;
-
-       ks_addr_raw_data(sa, &ip, &iplen);
-       port = htons(sa->port);
-
-    dht_hash(token_return, TOKEN_SIZE, old ? h->oldsecret : h->secret, sizeof(h->secret), ip, iplen, (unsigned char*)&port, 2);
-}
-
-static int token_match(dht_handle_t *h, const unsigned char *token, int token_len, const ks_sockaddr_t *sa)
-{
-    unsigned char t[TOKEN_SIZE];
-
-    if (token_len != TOKEN_SIZE) {
-        return 0;
-       }
-
-    make_token(h, sa, 0, t);
-    if (memcmp(t, token, TOKEN_SIZE) == 0) {
-        return 1;
-       }
-
-    make_token(h, sa, 1, t);
-    if (memcmp(t, token, TOKEN_SIZE) == 0) {
-        return 1;
-       }
-
-    return 0;
-}
-
-KS_DECLARE(int) dht_nodes(dht_handle_t *h, int af, int *good_return, int *dubious_return, int *cached_return, int *incoming_return)
-{
-    int good = 0, dubious = 0, cached = 0, incoming = 0;
-    struct bucket *b = af == AF_INET ? h->buckets : h->buckets6;
-
-    while (b) {
-        struct node *n = b->nodes;
-        while (n) {
-            if (node_good(h, n)) {
-                good++;
-                if (n->time > n->reply_time) {
-                    incoming++;
-                               }
-            } else {
-                dubious++;
-            }
-            n = n->next;
-        }
-        if (b->cached.family > 0) {
-            cached++;
-               }
-        b = b->next;
-    }
-
-    if (good_return) {
-        *good_return = good;
-       }
-
-    if (dubious_return) {
-        *dubious_return = dubious;
-       }
-
-    if (cached_return) {
-        *cached_return = cached;
-       }
-
-    if (incoming_return) {
-        *incoming_return = incoming;
-       }
-
-    return good + dubious;
-}
-
-static void dump_bucket(dht_handle_t *h, FILE *f, struct bucket *b)
-{
-    struct node *n = b->nodes;
-       int mine = in_bucket(h->myid, b);
-       int age = (int)(h->now - b->time);
-       int cached = b->cached.family;
-    fprintf(f, "Bucket ");
-    print_hex(f, b->first, 20);
-    fprintf(f, " count %d age %d%s%s:\n", b->count, age, mine ? " (mine)" : "", cached ? " (cached)" : "");
-
-    while (n) {
-        fprintf(f, "    Node ");
-        print_hex(f, n->id, 20);
-
-        if (n->ss.family == AF_INET6) {
-            fprintf(f, " [%s]:%d ", n->ss.host, n->ss.port);
-               } else {
-            fprintf(f, " %s:%d ", n->ss.host, n->ss.port);
-               }
-
-        if (n->time != n->reply_time) {
-            fprintf(f, "age %ld, %ld", (long)(h->now - n->time), (long)(h->now - n->reply_time));
-        } else {
-            fprintf(f, "age %ld", (long)(h->now - n->time));
-               }
-
-        if (n->pinged) {
-            fprintf(f, " (%d)", n->pinged);
-               }
-
-        if (node_good(h, n)) {
-            fprintf(f, " (good)");
-               }
-        fprintf(f, "\n");
-        n = n->next;
-    }
-
-}
-
-KS_DECLARE(void) dht_dump_tables(dht_handle_t *h, FILE *f)
-{
-    int i;
-    struct bucket *b;
-    struct storage *st = h->storage;
-    struct search *sr = h->searches;
-
-    fprintf(f, "My id ");
-    print_hex(f, h->myid, 20);
-    fprintf(f, "\n");
-
-    b = h->buckets;
-    while (b) {
-        dump_bucket(h, f, b);
-        b = b->next;
-    }
-
-    fprintf(f, "\n");
-
-    b = h->buckets6;
-    while (b) {
-        dump_bucket(h, f, b);
-        b = b->next;
-    }
-
-    while (sr) {
-        fprintf(f, "\nSearch%s id ", sr->af == AF_INET6 ? " (IPv6)" : "");
-        print_hex(f, sr->id, 20);
-        fprintf(f, " age %d%s\n", (int)(h->now - sr->step_time), sr->done ? " (done)" : "");
-        for (i = 0; i < sr->numnodes; i++) {
-            struct search_node *n = &sr->nodes[i];
-            fprintf(f, "Node %d id ", i);
-            print_hex(f, n->id, 20);
-            fprintf(f, " bits %d age ", common_bits(sr->id, n->id));
-            if (n->request_time) {
-                fprintf(f, "%d, ", (int)(h->now - n->request_time));
-                       }
-            fprintf(f, "%d", (int)(h->now - n->reply_time));
-            if (n->pinged) {
-                fprintf(f, " (%d)", n->pinged);
-                       }
-            fprintf(f, "%s%s.\n", find_node(h, n->id, AF_INET) ? " (known)" : "", n->replied ? " (replied)" : "");
-        }
-        sr = sr->next;
-    }
-
-    while (st) {
-        fprintf(f, "\nStorage ");
-        print_hex(f, st->id, 20);
-        fprintf(f, " %d/%d nodes:", st->numpeers, st->maxpeers);
-        for (i = 0; i < st->numpeers; i++) {
-            char buf[100];
-            if (st->peers[i].addr.family == AF_INET) {
-                               ks_snprintf(buf, sizeof(buf), "%s", st->peers[i].addr.host);
-            } else if (st->peers[i].addr.family == AF_INET6) {
-                               ks_snprintf(buf, sizeof(buf), "[%s]", st->peers[i].addr.host);
-            } else {
-                strcpy(buf, "???");
-            }
-            fprintf(f, " %s:%u (%ld)", buf, st->peers[i].addr.port, (long)(h->now - st->peers[i].time));
-        }
-        st = st->next;
-    }
-
-    fprintf(f, "\n\n");
-    fflush(f);
-}
-
-static void ks_dht_store_entry_destroy(struct ks_dht_store_entry_s **old_entry)
-{
-       struct ks_dht_store_entry_s *entry = *old_entry;
-       ks_pool_t *pool = entry->pool;
-       *old_entry = NULL;
-
-       /* While setting these members to NULL is not required, defaulting to including them for easier debugging */
-       entry->key = NULL;
-       entry->content_type = NULL;
-       entry->payload_raw = NULL;
-       entry->pool = NULL;
-       
-       if ( entry->bencode_message_raw ) {
-               ben_free(entry->bencode_message_raw);
-               entry->bencode_message_raw = NULL;
-       }
-
-       if ( entry->payload_bencode ) {
-               ben_free(entry->payload_bencode);
-               entry->payload_bencode = NULL;
-       }
-
-       if ( entry->body ) {
-               cJSON_Delete(entry->body);
-               entry->body = NULL;
-       }
-       
-       ks_pool_free(pool, &entry);     
-       return;
-}
-
-/* Entries can be created by a remote system 'pushing' a message to us, or the local system creating and sending the message. */
-
-static int ks_dht_store_entry_create(struct dht_handle_s *h, struct bencode *msg, struct ks_dht_store_entry_s **new_entry, ks_time_t life, ks_bool_t mine)
-{
-       struct ks_dht_store_entry_s *entry = NULL;
-       ks_time_t now = ks_time_now_sec();
-
-       entry = ks_pool_alloc(h->pool, sizeof(struct ks_dht_store_entry_s));
-       entry->pool = h->pool;
-       entry->received = now;
-       entry->expiration = now + life;
-       entry->last_announce = 0; /* TODO: Instead we should announce this one, and set to now */
-       entry->serial = 1;
-       entry->mine = mine;
-
-       entry->bencode_message_raw = msg;
-       entry->payload_raw = NULL;
-
-       entry->content_type = NULL;
-       entry->payload_bencode = NULL;
-       entry->body = NULL;
-       
-       if ( msg ) {
-               struct bencode *key_args = ben_dict_get_by_str(msg, "a");
-               struct bencode *key_token = NULL;
-               struct bencode *key_v = NULL;
-               struct bencode *key_ct = NULL;
-               struct bencode *tmp_v = NULL;
-
-               if ( !key_args ) {
-                       ks_log(KS_LOG_ERROR, "dht_store_entry requires an 'a' key in the message\n");
-                       goto err;
-               }
-
-               key_token = ben_dict_get_by_str(key_args, "token");
-               if ( !key_token ) {
-                       ks_log(KS_LOG_ERROR, "dht_store_entry requires an 'token' key in the message\n");
-                       goto err;
-               }
-               entry->key = ben_str_val(key_token);            
-               ks_log(KS_LOG_INFO, "dht_store_entry now with new key[%s]\n", entry->key);
-               
-               key_v = ben_dict_get_by_str(key_args, "v");
-               if ( !key_v ) {
-                       ks_log(KS_LOG_ERROR, "dht_store_entry requires an 'v' key in the message\n");
-                       goto err;
-               }
-
-               tmp_v = ben_decode(ben_str_val(key_v), ben_str_len(key_v));
-
-               entry->payload_raw = ben_str_val(tmp_v);
-               entry->payload_bencode = ben_decode(entry->payload_raw, ben_str_len(tmp_v));
-
-               if ( !entry->payload_bencode ) {
-                       ks_log(KS_LOG_WARNING, "dht_store_entry payload failed to parse as bencode object\n");
-                       goto err;
-               }
-
-               ks_log(KS_LOG_DEBUG, "Payload: %s\n", ben_print(entry->payload_bencode));
-
-               if ( ! ben_is_dict( entry->payload_bencode ) ) {
-                       ks_log(KS_LOG_DEBUG, "dht_store_entry is not a bencode dict. Legal, just not likely one of ours.\n");
-                       goto done;                      
-               }
-               
-               /* 
-                  This is a custom key that SWITCHBLADE is adding to give the protocol decoder a hint as to the payload type. 
-                  If this key is not set, then we need to assume that the payload is binary buffer of a known length, likely not from SWITCHBLADE.
-                */
-               key_ct = ben_dict_get_by_str(entry->payload_bencode, "ct");
-               if ( !key_ct ) {
-                       ks_log(KS_LOG_DEBUG, "dht_store_entry without a 'ct' key to hint at payload content type. Legal, just not likely one of ours.\n");
-                       goto done;
-               }
-
-               entry->content_type = ben_str_val(key_ct);
-               
-               if ( !ben_cmp_with_str(key_ct, "json") ) {
-                       struct bencode *key_b = ben_dict_get_by_str(entry->payload_bencode, "b");
-                       int buf_len = ben_str_len(key_b);
-                       char *buf = NULL;
-
-                       buf = calloc(1, buf_len);
-                       memcpy(buf, ben_str_val(key_b), buf_len);
-
-                       entry->body = cJSON_Parse(buf);
-                       free(buf);
-                       buf = NULL;
-
-                       if ( !entry->body ) {
-                               ks_log(KS_LOG_ERROR, "dht_store_entry with json payload failed to json parse. Someone sent and signed an invalid message.\n");
-                               goto err;
-                       }
-
-                       if ( h->store_json_cb ) {
-                               h->store_json_cb(h, entry->body, h->store_json_cb_arg);
-                       }
-               }               
-       }
-       
- done:
-       *new_entry = entry;
-       return 0;
- err:
-       ks_dht_store_entry_destroy(&entry);
-       return -1;      
-}
-
-static struct ks_dht_store_entry_s *ks_dht_store_fetch(struct ks_dht_store_s *store, char *key)
-{
-       assert(store != NULL);
-
-       return ks_hash_search(store->hash, (void *)key, 0);
-}
-
-static int ks_dht_store_insert(struct ks_dht_store_s *store, struct ks_dht_store_entry_s *entry, ks_time_t now)
-{
-       return ks_hash_insert(store->hash, (void *)entry->key, entry);
-}
-
-static int ks_dht_store_replace(struct ks_dht_store_s *store, struct ks_dht_store_entry_s *entry)
-{
-       struct ks_dht_store_entry_s *val = ks_hash_remove(store->hash, (void *) entry->key);
-
-       if ( val ) {
-               ks_dht_store_entry_destroy(&val);
-       }
-       
-       return ks_hash_insert(store->hash, (void *) entry->key, entry);
-}
-
-static void ks_dht_store_prune(struct ks_dht_store_s *store, ks_time_t now)
-{
-       (void) store;
-       (void) now;
-       return;
-}
-
-/* TODO: Look into using the ks_hash automatic destructor functionality. */
-static int ks_dht_store_create(ks_pool_t *pool, struct ks_dht_store_s **new_store)
-{
-       struct ks_dht_store_s *store = NULL;
-
-       store = ks_pool_alloc(pool, sizeof(struct ks_dht_store_s));
-       store->next_expiring = 0;
-       store->pool = pool;
-
-       ks_hash_create(&store->hash, KS_HASH_MODE_DEFAULT, KS_HASH_FLAG_RWLOCK, pool);
-
-       *new_store = store;
-       return 0;
-}
-
-static void ks_dht_store_destroy(struct ks_dht_store_s **old_store)
-{
-       struct ks_dht_store_s *store = *old_store;
-       ks_hash_iterator_t *itt = NULL;
-       ks_pool_t *pool = store->pool;
-       *old_store = NULL;
-
-       ks_hash_write_lock(store->hash);
-       for (itt = ks_hash_first(store->hash, KS_UNLOCKED); itt; itt = ks_hash_next(&itt)) {
-               const void *key = NULL;
-               struct ks_dht_store_entry_s *val = NULL;
-
-               ks_hash_this(itt, &key, NULL, (void **) &val);
-               ks_hash_remove(store->hash, (char *)key);
-
-               ks_dht_store_entry_destroy(&val);
-       }
-       ks_hash_write_unlock(store->hash);
-
-       ks_hash_destroy(&store->hash);
-
-       ks_pool_free(pool, &store);
-       
-       return;
-}
-
-static void reset_poll(dht_handle_t *h)
-{
-       int i = 0, socks = h->ip4s + h->ip6s;
-       ks_hash_iterator_t *itt;
-
-       if (!h->iphash) return;
-
-       if (h->num_pollsocks < socks) {
-               h->num_pollsocks = socks;
-               h->pollsocks = (struct pollfd *)ks_pool_resize(h->pool, (void *)h->pollsocks, sizeof(struct pollfd) * h->num_pollsocks);
-               h->iptsocks = (ks_ip_t **) ks_pool_resize(h->pool, (void *)h->iptsocks, sizeof(ks_ip_t *) * h->num_pollsocks);
-               h->addrsocks = (ks_sockaddr_t **) ks_pool_resize(h->pool, (void *)h->addrsocks, sizeof(ks_sockaddr_t *) * h->num_pollsocks);
-               ks_log(KS_LOG_DEBUG, "Resize poll array to %d\n", h->num_pollsocks);
-       }
-
-       for (itt = ks_hash_first(h->iphash, KS_UNLOCKED); itt; itt = ks_hash_next(&itt)) {
-               const void *key;
-               void *val;
-               ks_ip_t *ipt;
-               
-               ks_hash_this(itt, &key, NULL, &val);
-               
-               ipt = (ks_ip_t *) val;
-               
-               h->pollsocks[i].fd = ipt->sock;
-               h->pollsocks[i].events = POLLIN | POLLERR;
-               h->iptsocks[i] = ipt;
-               h->addrsocks[i] = &ipt->addr;
-               i++;
-       }
-}
-
-KS_DECLARE(ks_status_t) ks_dht_get_bind_addrs(dht_handle_t *h, const ks_sockaddr_t ***addrs, ks_size_t *addrlen)
-{
-       *addrs = (const ks_sockaddr_t **) h->addrsocks;
-       *addrlen = h->num_pollsocks;
-
-       return KS_STATUS_SUCCESS;
-}
-
-KS_DECLARE(ks_status_t) ks_dht_one_loop(dht_handle_t *h, int timeout)
-{
-       ks_status_t status;
-       int s, i;
-       unsigned char buf[65536] = {0};
-       ks_size_t bytes = sizeof(buf);
-
-       if (!h->started) {
-               return KS_STATUS_FAIL;
-       }
-
-
-       reset_poll(h);
-
-       if (!timeout) timeout = h->tosleep * 1000;
-
-
-       s = ks_poll(h->pollsocks, h->num_pollsocks, timeout);
-       
-       if (s < 0) {
-               return KS_STATUS_FAIL;
-       }
-
-       if (s == 0) {
-               dht_periodic(h, buf, 0, NULL);
-               return KS_STATUS_TIMEOUT;
-       }
-
-       for (i = 0; i < h->num_pollsocks; i++) {
-               if ((h->pollsocks[i].revents & POLLIN)) {
-                       ks_sockaddr_t remote_addr = KS_SA_INIT;
-                       
-                       remote_addr.family = h->iptsocks[i]->addr.family;
-                       if ((status = ks_socket_recvfrom(h->pollsocks[i].fd, buf, &bytes, &remote_addr)) == KS_STATUS_SUCCESS) {
-                               // git rid of tosleep and convert it to non-blocking counter so you can still call this in a loop and just return timeout till tosleep expired
-                               // beginning of rabbit hole to change references to addrs to ks_addrs instead and stop passing sockaddr and len all over the place.
-                               dht_periodic(h, buf, bytes, &remote_addr);
-                       }
-               }
-       }
-
-       return KS_STATUS_SUCCESS;
-}
-
-static void clear_all_ip(dht_handle_t *h)
-{
-       ks_hash_iterator_t *itt;
-
-       if (!h->iphash) return;
-
-       ks_hash_write_lock(h->iphash);
-       for (itt = ks_hash_first(h->iphash, KS_UNLOCKED); itt; itt = ks_hash_next(&itt)) {
-               const void *key;
-               void *val;
-               ks_ip_t *ipt;
-
-               ks_hash_this(itt, &key, NULL, &val);
-
-               ipt = (ks_ip_t *) val;
-
-               ks_socket_close(&ipt->sock);
-               ks_pool_free(h->pool, &ipt);
-
-               if (ipt->addr.family == AF_INET) {
-                       h->ip4s--;
-               } else {
-                       h->ip6s--;
-               }
-
-               ks_hash_remove(h->iphash, (char *)key);
-       }
-       ks_hash_write_unlock(h->iphash);
-
-       ks_hash_destroy(&h->iphash);
-
-}
-
-static ks_ip_t *add_ip(dht_handle_t *h, const char *ip, int port, int family)
-{
-       ks_ip_t *ipt;
-
-       ks_assert(h);
-       ks_assert(ip);
-
-       if (!port) port = h->port;
-
-       if (family == AF_INET) {
-               h->af_flags |= KS_DHT_AF_INET4;
-
-               if (!h->buckets) {
-                       h->buckets = ks_pool_alloc(h->pool, sizeof(*h->buckets));
-                       h->buckets->af = AF_INET;
-               }
-
-       } else if (family == AF_INET6) {
-               h->af_flags |= KS_DHT_AF_INET6;
-               
-               if (!h->buckets6) {
-                       h->buckets6 = ks_pool_alloc(h->pool, sizeof(*h->buckets6));
-                       h->buckets6->af = AF_INET6;
-               }
-       }
-
-
-       ks_log(KS_LOG_DEBUG, "Adding bind ip: %s port: %d family:%d\n", ip, port, family);
-
-       ipt = ks_pool_alloc(h->pool, sizeof(*ipt));
-       ipt->sock = KS_SOCK_INVALID;
-
-       ks_set_string(ipt->ip, ip);
-       
-       ks_addr_set(&ipt->addr, ip, port, family);
-
-       if ((ipt->sock = socket(family, SOCK_DGRAM, IPPROTO_UDP)) == KS_SOCK_INVALID) {
-               ks_log(KS_LOG_ERROR, "Socket Error\n");
-               ks_pool_free(h->pool, &ipt);
-               return NULL;
-       }
-
-       if (ks_addr_bind(ipt->sock, &ipt->addr) != KS_STATUS_SUCCESS) {
-               ks_log(KS_LOG_ERROR, "Error Adding bind ip: %s port: %d sock: %d (%s)\n", ip, port, ipt->sock, strerror(errno));
-               ks_socket_close(&ipt->sock);
-               ks_pool_free(h->pool, &ipt);
-               return NULL;
-       }
-
-       ks_socket_option(ipt->sock, SO_REUSEADDR, KS_TRUE);
-       ks_socket_option(ipt->sock, KS_SO_NONBLOCK, KS_TRUE);
-
-       ks_hash_insert(h->iphash, (void *)ipt->ip, ipt);
-
-       if (family == AF_INET) {
-               h->ip4s++;
-       } else {
-               h->ip6s++;
-       }
-
-       reset_poll(h);
-
-       return ipt;
-}
-
-KS_DECLARE(void) ks_dht_set_port(dht_handle_t *h, unsigned int port)
-{
-       h->port = port;
-}
-
-KS_DECLARE(void) ks_dht_set_v(dht_handle_t *h, const unsigned char *v)
-{
-    if (v) {
-        memcpy(h->my_v, "1:v4:", 5);
-        memcpy(h->my_v + 5, v, 4);
-        h->have_v = 1;
-    } else {
-        h->have_v = 0;
-    }
-}
-
-KS_DECLARE(ks_status_t) ks_dht_add_ip(dht_handle_t *h, char *ip, int port)
-{
-       int family = AF_INET;
-
-       if (strchr(ip, ':')) {
-               family = AF_INET6;
-       }
-
-       return add_ip(h, ip, port, family) ? KS_STATUS_SUCCESS : KS_STATUS_FAIL;
-}
-
-
-KS_DECLARE(void) ks_dht_set_callback(dht_handle_t *h, dht_callback_t callback, void *closure)
-{
-       h->callback = callback;
-       h->closure = closure;
-}
-
-
-KS_DECLARE(void) ks_dht_set_param(dht_handle_t *h, ks_dht_param_t param, ks_bool_t val)
-{
-       switch(param) {
-       case DHT_PARAM_AUTOROUTE:
-               h->autoroute = val;
-               break;
-       }
-}
-
-KS_DECLARE(void) ks_dht_start(dht_handle_t *h)
-{
-       char ip[48] = "";
-       int mask = 0;
-
-       if (h->started) return;
-
-    if ((h->af_flags & KS_DHT_AF_INET4) && !h->ip4s) {
-               ks_find_local_ip(ip, sizeof(ip), &mask, AF_INET, NULL);
-               add_ip(h, ip, 0, AF_INET);
-    }
-
-       if ((h->af_flags & KS_DHT_AF_INET6) && !h->ip6s) {
-               ks_find_local_ip(ip, sizeof(ip), &mask, AF_INET6, NULL);
-               add_ip(h, ip, 0, AF_INET6);
-    }
-       
-       h->started = 1;
-
-}
-
-//KS_DECLARE(int) dht_init(dht_handle_t **handle, int s, int s6, const unsigned char *id, const unsigned char *v, unsigned int port)
-KS_DECLARE(ks_status_t) ks_dht_init(dht_handle_t **handle, ks_dht_af_flag_t af_flags, const unsigned char *id, unsigned int port)
-{
-    int rc;
-       dht_handle_t *h;
-       ks_pool_t *pool;
-
-       ks_pool_open(&pool);
-       *handle = h = ks_pool_alloc(pool, sizeof(dht_handle_t));
-
-       h->pool = pool;
-    h->searches = NULL;
-    h->numsearches = 0;
-
-       if (port) {
-               h->port = port;
-       } else {
-               h->port = 5309;
-       }
-
-       h->af_flags = af_flags;
-
-
-       ks_hash_create(&h->iphash, KS_HASH_MODE_DEFAULT, KS_HASH_FLAG_RWLOCK, h->pool);
-
-       h->store_json_cb = NULL;
-       h->store_json_cb_arg = NULL;
-       
-    h->storage = NULL;
-    h->numstorage = 0;
-
-       if (!id) {
-               //ks_random_string((char *)h->myid, 20, NULL);
-               randombytes_buf(h->myid, 20);
-       } else {
-               memcpy(h->myid, id, 20);
-       }
-
-       h->have_v = 0;
-
-       h->now = ks_time_now_sec();
-
-    h->mybucket_grow_time = h->now;
-    h->mybucket6_grow_time = h->now;
-    h->confirm_nodes_time = h->now + random() % 3;
-
-    h->search_id = random() & 0xFFFF;
-    h->search_time = 0;
-
-    h->next_blacklisted = 0;
-
-    h->token_bucket_time = h->now;
-    h->token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
-
-    memset(h->secret, 0, sizeof(h->secret));
-    rc = rotate_secrets(h);
-    if (rc < 0)
-        goto fail;
-
-
-    expire_buckets(h, h->buckets);
-    expire_buckets(h, h->buckets6);
-
-       ks_dht_store_create(h->pool, &h->store);
-
-    return KS_STATUS_SUCCESS;
-
- fail:
-    ks_pool_free(h->pool, &h->buckets);
-    h->buckets = NULL;
-    ks_pool_free(h->pool, &h->buckets6);
-    h->buckets6 = NULL;
-    return KS_STATUS_FAIL;
-}
-
-KS_DECLARE(int) dht_uninit(dht_handle_t **handle)
-{
-       dht_handle_t *h;
-       ks_pool_t *pool;
-
-       ks_assert(handle && *handle);
-       
-       h = *handle;
-       *handle = NULL;
-
-       clear_all_ip(h);
-       
-    while (h->buckets) {
-        struct bucket *b = h->buckets;
-        h->buckets = b->next;
-        while (b->nodes) {
-            struct node *n = b->nodes;
-            b->nodes = n->next;
-            ks_pool_free(h->pool, &n);
-        }
-        ks_pool_free(h->pool, &b);
-    }
-
-    while (h->buckets6) {
-        struct bucket *b = h->buckets6;
-        h->buckets6 = b->next;
-        while (b->nodes) {
-            struct node *n = b->nodes;
-            b->nodes = n->next;
-            ks_pool_free(h->pool, &n);
-        }
-        ks_pool_free(h->pool, &b);
-    }
-
-    while (h->storage) {
-        struct storage *st = h->storage;
-        h->storage = h->storage->next;
-        ks_pool_free(h->pool, &st->peers);
-        ks_pool_free(h->pool, &st);
-    }
-
-    while (h->searches) {
-        struct search *sr = h->searches;
-        h->searches = h->searches->next;
-        ks_pool_free(h->pool, &sr);
-    }
-
-       ks_dht_store_destroy(&h->store);
-       pool = h->pool;
-       h->pool = NULL;
-       ks_pool_free(pool, &h);
-       ks_pool_close(&pool);
-
-    return 1;
-}
-
-/* Rate control for requests we receive. */
-
-static int token_bucket(dht_handle_t *h)
-{
-    if (h->token_bucket_tokens == 0) {
-        h->token_bucket_tokens = MIN(MAX_TOKEN_BUCKET_TOKENS, 100 * (h->now - h->token_bucket_time));
-        h->token_bucket_time = h->now;
-    }
-
-    if (h->token_bucket_tokens == 0) {
-        return 0;
-       }
-
-    h->token_bucket_tokens--;
-    return 1;
-}
-
-static int neighbourhood_maintenance(dht_handle_t *h, int af)
-{
-    unsigned char id[20];
-    struct bucket *b = find_bucket(h, h->myid, af);
-    struct bucket *q;
-    struct node *n;
-
-    if (b == NULL) {
-        return 0;
-       }
-
-    memcpy(id, h->myid, 20);
-    id[19] = random() & 0xFF;
-    q = b;
-
-    if (q->next && (q->count == 0 || (random() & 7) == 0)) {
-        q = b->next;
-       }
-
-    if (q->count == 0 || (random() & 7) == 0) {
-        struct bucket *r;
-        r = previous_bucket(h, b);
-        if (r && r->count > 0) {
-            q = r;
-               }
-    }
-
-    if (q) {
-        /* Since our node-id is the same in both DHTs, it's probably
-           profitable to query both families. */
-
-        n = random_node(q);
-        if (n) {
-            unsigned char tid[4];
-
-                       const char *msg;
-
-
-                       if ((h->af_flags & KS_DHT_AF_INET6) && (h->af_flags & KS_DHT_AF_INET4)) {
-                               msg = "v4 and v6";
-                       } else if (h->af_flags & KS_DHT_AF_INET6) {
-                               msg = "v6";
-                       } else {
-                               msg = "v4";
-                       }
-
-
-            ks_log(KS_LOG_DEBUG, "Sending find_node for %s on %s neighborhood maintenance.\n", msg, af == AF_INET6 ? "IPv6" : "IPv4");
-            make_tid(tid, "fn", 0);
-            send_find_node(h, &n->ss, tid, 4, id, sizeof(id), h->af_flags, n->reply_time >= h->now - 15);
-            pinged(h, n, q);
-        }
-        return 1;
-    }
-    return 0;
-}
-
-static int bucket_maintenance(dht_handle_t *h, int af)
-{
-    struct bucket *b;
-
-    b = af == AF_INET ? h->buckets : h->buckets6;
-
-    while (b) {
-        struct bucket *q;
-        if (b->time < h->now - 600) {
-            /* This bucket hasn't seen any positive confirmation for a long
-               time.  Pick a random id in this bucket's range, and send
-               a request to a random node. */
-            unsigned char id[20];
-            struct node *n;
-            int rc;
-
-            rc = bucket_random(b, id);
-            if (rc < 0) {
-                memcpy(id, b->first, 20);
-                       }
-
-            q = b;
-            /* If the bucket is empty, we try to fill it from a neighbour.
-               We also sometimes do it gratuitiously to recover from
-               buckets full of broken nodes. */
-            if (q->next && (q->count == 0 || (random() & 7) == 0)) {
-                q = b->next;
-                       }
-
-            if (q->count == 0 || (random() & 7) == 0) {
-                struct bucket *r;
-                r = previous_bucket(h, b);
-                if (r && r->count > 0) {
-                    q = r;
-                               }
-            }
-
-            if (q) {
-                n = random_node(q);
-                if (n) {
-                    unsigned char tid[4];
-                    int want = -1;
-
-                                       if ((h->af_flags & KS_DHT_AF_INET4) && (h->af_flags & KS_DHT_AF_INET6)) {
-                        struct bucket *otherbucket;
-                        otherbucket = find_bucket(h, id, af == AF_INET ? AF_INET6 : AF_INET);
-                        if (otherbucket && otherbucket->count < 8) {
-                            /* The corresponding bucket in the other family is emptyish -- querying both is useful. */
-                            want = WANT4 | WANT6;
-                        } else if (random() % 37 == 0) {
-                            /* Most of the time, this just adds overhead.
-                               However, it might help stitch back one of
-                               the DHTs after a network collapse, so query
-                               both, but only very occasionally. */
-                            want = WANT4 | WANT6;
-                                               }
-                    }
-
-                    ks_log(KS_LOG_DEBUG, "Sending find_node for%s bucket maintenance.\n", af == AF_INET6 ? " IPv6" : "");
-                    make_tid(tid, "fn", 0);
-                    send_find_node(h, &n->ss, tid, 4, id, sizeof(id), want, n->reply_time >= h->now - 15);
-                    pinged(h, n, q);
-                    /* In order to avoid sending queries back-to-back, give up for now and reschedule us soon. */
-                    return 1;
-                }
-            }
-        }
-        b = b->next;
-    }
-    return 0;
-}
-
-
-KS_DECLARE(int) dht_periodic(dht_handle_t *h, const void *buf, size_t buflen, ks_sockaddr_t *from) 
-//KS_DECLARE(int) dht_periodic(dht_handle_t *h, const void *buf, size_t buflen, const struct sockaddr *from, int fromlen,
-//           time_t *tosleep, dht_callback *callback, void *closure)
-{
-       unsigned char *logmsg = NULL;
-       h->now = ks_time_now_sec();
-
-    if (buflen > 0) {
-        dht_msg_type_t message;
-        unsigned char tid[16], id[20], info_hash[20], target[20];
-        unsigned char nodes[26*16], nodes6[38*16], token[128] = {0};
-        int tid_len = 16, token_len = 0;
-        int nodes_len = 26*16, nodes6_len = 38*16;
-        unsigned short port = 0;
-        unsigned char values[2048], values6[2048];
-        int values_len = 2048, values6_len = 2048;
-        int want = 0;
-        unsigned short ttid;
-               struct bencode *msg_ben = NULL;
-               struct bencode *key_args = NULL; /* Request args */
-               struct bencode *key_info_hash = NULL;
-               struct bencode *key_want = NULL;
-               struct bencode *key_token = NULL;
-               struct bencode *key_port = NULL;
-               struct bencode *key_target = NULL;
-
-               struct bencode *key_resp = NULL; /* Response values */
-               struct bencode *key_values = NULL;
-               struct bencode *key_values6 = NULL;
-               struct bencode *key_nodes = NULL;
-               struct bencode *key_nodes6 = NULL;
-
-        if (is_martian(from)) {
-            goto dontread;
-               }
-
-        if (node_blacklisted(h, from)) {
-            ks_log(KS_LOG_DEBUG, "Received packet from blacklisted node.\n");
-            goto dontread;
-        }
-
-        if (((char*)buf)[buflen] != '\0') {
-            ks_log(KS_LOG_DEBUG, "Unterminated message.\n");
-            errno = EINVAL;
-            return -1;
-        }
-
-               msg_ben = ben_decode((const void *) buf, buflen);
-               if ( !msg_ben ) {
-                       ks_log(KS_LOG_DEBUG, "Received invalid message. Unable to ben_decode it.\n");
-                       goto dontread;
-               }
-
-        message = parse_message(msg_ben, tid, &tid_len, id);
-               ks_log(KS_LOG_DEBUG, "Received bencode message[%d] from [%s] port (%d): \n\n%s\n", message, from->host, from->port, ben_print(msg_ben));
-
-        if (id_cmp(id, zeroes) == 0) {
-                       message = DHT_MSG_INVALID;
-        } else if (id_cmp(id, h->myid) == 0) {
-            ks_log(KS_LOG_DEBUG, "Received message from self.\n");
-            goto dontread;
-        }
-
-        if (message > DHT_MSG_REPLY) {
-            /* Rate limit requests. */
-            if (!token_bucket(h)) {
-                ks_log(KS_LOG_DEBUG, "Dropping request due to rate limiting.\n");
-                goto dontread;
-            }
-        }
-
-               key_args = ben_dict_get_by_str(msg_ben, "a");
-               if ( key_args ) {
-                       key_info_hash = ben_dict_get_by_str(key_args, "info_hash");
-
-                       if ( key_info_hash ) {
-                               memcpy(info_hash, ben_str_val(key_info_hash), ben_str_len(key_info_hash));
-                       }
-
-                       key_want = ben_dict_get_by_str(key_args, "want");
-                       
-                       if ( key_want && ben_is_list(key_want)) {
-                               int x = 0;
-                               for( x = 0; x < ben_list_len(key_want); x++ ) {
-                                       struct bencode *key_tmp = ben_list_get(key_want, x);
-                                       if ( !ben_cmp_with_str(key_tmp, "n4") ) {
-                                               want |= WANT4;
-                                       } else if ( !ben_cmp_with_str(key_tmp, "n6") ) {
-                                               want |= WANT6;
-                                       }
-                               }
-                       } else {
-                               want = WANT4;
-                       }
-
-                       key_target = ben_dict_get_by_str(key_args, "target");
-
-                       if ( key_target ) {
-                               memcpy(target, ben_str_val(key_target), ben_str_len(key_target));
-                       }
-
-
-                       key_token = ben_dict_get_by_str(key_args, "token");
-
-                       if ( key_token ) {
-                               token_len = ben_str_len(key_token);
-                               memcpy(token, ben_str_val(key_token), token_len);
-                       }
-
-                       key_port = ben_dict_get_by_str(key_args, "port");
-
-                       if ( key_port ) {
-                               port = ben_int_val(key_port);
-                       }
-               }
-
-               key_resp = ben_dict_get_by_str(msg_ben, "r");
-               if ( key_resp ) {
-                       key_values = ben_dict_get_by_str(key_resp, "values");
-
-                       if ( key_values ) {
-                               values_len = ben_str_len(key_values);
-                               memcpy(values, ben_str_val(key_values), values_len);
-                       }
-
-                       key_values6 = ben_dict_get_by_str(key_resp, "values6");
-
-                       if ( key_values6 ) {
-                               values6_len = ben_str_len(key_values6);
-                               memcpy(values6, ben_str_val(key_values6), values6_len);
-                       }
-
-                       key_nodes = ben_dict_get_by_str(key_resp, "nodes");
-
-                       if ( key_nodes ) {
-                               nodes_len = ben_str_len(key_nodes);
-                               memcpy(nodes, ben_str_val(key_nodes), nodes_len);
-                               ks_log(KS_LOG_DEBUG, "Parsed nodes from response with length %d\n", nodes_len);
-                       }
-
-                       key_nodes6 = ben_dict_get_by_str(key_resp, "nodes6");
-
-                       if ( key_nodes6 ) {
-                               nodes6_len = ben_str_len(key_nodes6);
-                               memcpy(nodes6, ben_str_val(key_nodes6), nodes6_len);
-                       }
-               }
-               
-               logmsg = calloc(1, buflen);
-               ks_log(KS_LOG_DEBUG, "Message type %d\n", message);
-        switch(message) {
-               case DHT_MSG_STORE_PUT:
-                       if ( buf ) {
-                               struct ks_dht_store_entry_s *entry = NULL;
-                               struct bencode *sig = NULL, *salt = NULL;
-                               struct bencode *sig_ben = NULL, *pk_ben = NULL;
-                               unsigned char *data_sig = NULL;
-                               const char *sig_binary = NULL, *pk_binary = NULL;
-                               size_t data_sig_len = 0;
-
-                               /* Handle checking callback handler, and response */
-                               if ( !key_args ) {
-                                       ks_log(KS_LOG_DEBUG, "Failed to locate 'a' field in message\n");
-                                       goto dontread;
-                               } else {
-                                       ks_log(KS_LOG_DEBUG, "Successfully located 'a' field in message\n");
-                               }
-
-                               ks_log(KS_LOG_DEBUG, "Received bencode store PUT: \n\n%s\n", ben_print(msg_ben));
-
-                               sig_ben = ben_dict_get_by_str(key_args, "sig");
-                               sig_binary = ben_str_val(sig_ben);
-                               
-                               pk_ben = ben_dict_get_by_str(key_args, "k");
-                               pk_binary = ben_str_val(pk_ben);
-                               
-                               sig = ben_dict();
-
-                               salt = ben_dict_get_by_str(key_args, "salt");
-                               if ( salt ) {
-                                       ben_dict_set(sig, ben_blob("salt", 4), ben_blob(ben_str_val(salt), ben_str_len(salt)));
-                               }
-
-                               /* TODO: fix double reference here. Need to bencode duplicate these values, and then free sig when finished encoding it */
-                               ben_dict_set(sig, ben_blob("seq", 3), ben_dict_get_by_str(key_args, "seq"));
-                               ben_dict_set(sig, ben_blob("v", 1), ben_dict_get_by_str(key_args, "v"));
-
-                               data_sig = (unsigned char *) ben_encode(&data_sig_len, sig);
-
-                               if ( !data_sig ) {
-                                       ks_log(KS_LOG_DEBUG, "Failed to encode message for signature validation\n");
-                                       goto dontread;                                  
-                               }
-
-                               if (crypto_sign_verify_detached((unsigned char *)sig_binary, data_sig, data_sig_len, (unsigned char *) pk_binary) != 0) {
-                                       ks_log(KS_LOG_DEBUG, "Signature failed to verify. Corrupted or malicious data suspected!\n");
-                                       goto dontread;                                                                          
-                               } else {
-                                       ks_log(KS_LOG_DEBUG, "Valid message store signature.\n");
-                               }
-
-                               ks_dht_store_entry_create(h, msg_ben, &entry, 600, 0);
-                               ks_dht_store_insert(h->store, entry, h->now);
-                       }
-                       break;
-               case DHT_MSG_INVALID:
-               case DHT_MSG_ERROR:
-            ks_log(KS_LOG_DEBUG, "Unparseable message: %s\n", debug_printable(buf, logmsg, buflen));
-            goto dontread;
-        case DHT_MSG_REPLY:
-            if (tid_len != 4) {
-                ks_log(KS_LOG_DEBUG, "Broken node truncates transaction ids: %s\n", debug_printable(buf, logmsg, buflen));
-                /* This is really annoying, as it means that we will
-                   time-out all our searches that go through this node.
-                   Kill it. */
-                blacklist_node(h, id, from);
-                goto dontread;
-            }
-            if (tid_match(tid, "pn", NULL)) {
-                ks_log(KS_LOG_DEBUG, "Pong!\n");
-                new_node(h, id, from, 2);
-            } else if (tid_match(tid, "fn", NULL) || tid_match(tid, "gp", NULL)) {
-                int gp = 0;
-                struct search *sr = NULL;
-                if (tid_match(tid, "gp", &ttid)) {
-                    gp = 1;
-                    sr = find_search(h, ttid, from->family);
-                }
-                ks_log(KS_LOG_DEBUG, "Nodes found (%d+%d)%s!\n", nodes_len/26, nodes6_len/38, gp ? " for get_peers" : "");
-                if (nodes_len % 26 != 0 || nodes6_len % 38 != 0) {
-                    ks_log(KS_LOG_DEBUG, "Unexpected length for node info!\n");
-                    blacklist_node(h, id, from);
-                } else if (gp && sr == NULL) {
-                    ks_log(KS_LOG_DEBUG, "Unknown search!\n");
-                    new_node(h, id, from, 1);
-                } else {
-                    int i;
-                    new_node(h, id, from, 2);
-                    for (i = 0; i < nodes_len / 26; i++) {
-                        unsigned char *ni = nodes + i * 26;
-                        struct sockaddr_in sin;
-                                               ks_sockaddr_t addr = { 0 };
-
-                        if (id_cmp(ni, h->myid) == 0) {
-                            continue;
-                                               }
-                        memset(&sin, 0, sizeof(sin));
-                        sin.sin_family = AF_INET;
-                        memcpy(&sin.sin_addr, ni + 20, 4);
-                        memcpy(&sin.sin_port, ni + 24, 2);
-
-                                               ks_addr_set_raw(&addr, &sin.sin_addr, sin.sin_port, AF_INET);
-                        new_node(h, ni, &addr, 0);
-                        if (sr && sr->af == AF_INET) {
-                            insert_search_node(h, ni, &addr, sr, 0, NULL, 0);
-                        }
-                    }
-                    for (i = 0; i < nodes6_len / 38; i++) {
-                        unsigned char *ni = nodes6 + i * 38;
-                        struct sockaddr_in6 sin6;
-                                               ks_sockaddr_t addr = { 0 };
-
-                        if (id_cmp(ni, h->myid) == 0) {
-                            continue;
-                                               }
-                        memset(&sin6, 0, sizeof(sin6));
-                        sin6.sin6_family = AF_INET6;
-                        memcpy(&sin6.sin6_addr, ni + 20, 16);
-                        memcpy(&sin6.sin6_port, ni + 36, 2);
-
-                                               ks_addr_set_raw(&addr, &sin6.sin6_addr, sin6.sin6_port, AF_INET6);
-
-                        new_node(h, ni, &addr, 0);
-                        if (sr && sr->af == AF_INET6) {
-                            insert_search_node(h, ni, &addr, sr, 0, NULL, 0);
-                        }
-                    }
-                    if (sr) {
-                        /* Since we received a reply, the number of requests in flight has decreased.  Let's push another request. */
-                        search_send_get_peers(h, sr, NULL);
-                                       }
-                }
-                if (sr) {
-                                       if ( token_len ) {
-                                               ks_log(KS_LOG_DEBUG, "token %d [%.*s]\n", token_len, token);
-                                       }
-                    insert_search_node(h, id, from, sr, 1, token, token_len);
-                    if (values_len > 0 || values6_len > 0) {
-                        ks_log(KS_LOG_DEBUG, "Got values (%d+%d)!\n", values_len / 6, values6_len / 18);
-                        if (h->callback) {
-                            if (values_len > 0) {
-                                h->callback(h->closure, KS_DHT_EVENT_VALUES, sr->id, (void*)values, values_len);
-                                                       }
-                            if (values6_len > 0) {
-                                h->callback(h->closure, KS_DHT_EVENT_VALUES6, sr->id, (void*)values6, values6_len);
-                                                       }
-                        }
-                    }
-                }
-            } else if (tid_match(tid, "ap", &ttid)) {
-                struct search *sr;
-                ks_log(KS_LOG_DEBUG, "Got reply to announce_peer.\n");
-                sr = find_search(h, ttid, from->family);
-                if (!sr) {
-                    ks_log(KS_LOG_DEBUG, "Unknown search!\n");
-                    new_node(h, id, from, 1);
-                } else {
-                    int i;
-                    new_node(h, id, from, 2);
-                    for (i = 0; i < sr->numnodes; i++) {
-                        if (id_cmp(sr->nodes[i].id, id) == 0) {
-                            sr->nodes[i].request_time = 0;
-                            sr->nodes[i].reply_time = h->now;
-                            sr->nodes[i].acked = 1;
-                            sr->nodes[i].pinged = 0;
-                            break;
-                        }
-                                       }
-                    /* See comment for gp above. */
-                    search_send_get_peers(h, sr, NULL);
-                }
-            } else {
-                ks_log(KS_LOG_DEBUG, "Unexpected reply: %s\n", debug_printable(buf, logmsg, buflen));
-            }
-            break;
-        case DHT_MSG_PING:
-            ks_log(KS_LOG_DEBUG, "Ping (%d)!\n", tid_len);
-            new_node(h, id, from, 1);
-            ks_log(KS_LOG_DEBUG, "Sending pong.\n");
-            send_pong(h, from, tid, tid_len);
-            break;
-        case DHT_MSG_FIND_NODE:
-                       if ( key_args ) {
-                               /* 
-                                  http://www.bittorrent.org/beps/bep_0005.html
-                                  http://www.bittorrent.org/beps/bep_0032.html
-                                  
-                                  find_node Query = {"t":"aa", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456"}}
-                                  bencoded = d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t2:aa1:y1:qe
-                               */
-                       
-                               ks_log(KS_LOG_DEBUG, "Find node!\n");
-                               /* Needs to fetch the from, and fromlen from the decoded message, as well as the target and want */
-                               new_node(h, id, from, 1);
-                               ks_log(KS_LOG_DEBUG, "Sending closest nodes (%d).\n", want);
-                               send_closest_nodes(h, from, tid, tid_len, target, want, 0, NULL, NULL, 0);
-                       } else {
-                               goto dontread;
-                       }
-            break;
-        case DHT_MSG_GET_PEERS:
-                       /* 
-                          http://www.bittorrent.org/beps/bep_0005.html
-
-                          get_peers Query = {"t":"aa", "y":"q", "q":"get_peers", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456"}}
-                          bencoded = d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:t2:aa1:y1:qe
-                        */
-
-            ks_log(KS_LOG_DEBUG, "Get_peers!\n");
-            new_node(h, id, from, 1);
-            if (id_cmp(info_hash, zeroes) == 0) {
-                ks_log(KS_LOG_DEBUG, "Eek!  Got get_peers with no info_hash.\n");
-                send_error(h, from, tid, tid_len, 203, "Get_peers with no info_hash");
-                break;
-            } else {
-                struct storage *st = find_storage(h, info_hash);
-                unsigned char token[TOKEN_SIZE];
-                make_token(h, from, 0, token);
-                if (st && st->numpeers > 0) {
-                     ks_log(KS_LOG_DEBUG, "Sending found%s peers.\n", from->family == AF_INET6 ? " IPv6" : "");
-                     send_closest_nodes(h, from, tid, tid_len, info_hash, want, from->family, st, token, TOKEN_SIZE);
-                } else {
-                    ks_log(KS_LOG_DEBUG, "Sending nodes for get_peers.\n");
-                    send_closest_nodes(h, from, tid, tid_len, info_hash, want, 0, NULL, token, TOKEN_SIZE);
-                }
-            }
-            break;
-        case DHT_MSG_ANNOUNCE_PEER:
-            ks_log(KS_LOG_DEBUG, "Announce peer!\n");
-            new_node(h, id, from, 1);
-            if (id_cmp(info_hash, zeroes) == 0) {
-                ks_log(KS_LOG_DEBUG, "Announce_peer with no info_hash.\n");
-                send_error(h, from, tid, tid_len, 203, "Announce_peer with no info_hash");
-                break;
-            }
-            if (!token_match(h, token, token_len, from)) {
-                ks_log(KS_LOG_DEBUG, "Incorrect token for announce_peer.\n");
-                send_error(h, from, tid, tid_len, 203, "Announce_peer with wrong token");
-                break;
-            }
-            if (port == 0) {
-                ks_log(KS_LOG_DEBUG, "Announce_peer with forbidden port %d.\n", port);
-                send_error(h, from, tid, tid_len, 203, "Announce_peer with forbidden port number");
-                break;
-            }
-            storage_store(h, info_hash, from, port);
-            /* Note that if storage_store failed, we lie to the requestor. This is to prevent them from backtracking, and hence polluting the DHT. */
-            ks_log(KS_LOG_DEBUG, "Sending peer announced.\n");
-            send_peer_announced(h, from, tid, tid_len);
-        }
-    }
-
- dontread:
-    if (h->now >= h->rotate_secrets_time) {
-        rotate_secrets(h);
-       }
-
-    if (h->now >= h->expire_stuff_time) {
-        expire_buckets(h, h->buckets);
-        expire_buckets(h, h->buckets6);
-        expire_storage(h);
-        expire_searches(h);
-    }
-
-    if (h->search_time > 0 && h->now >= h->search_time) {
-        struct search *sr;
-        sr = h->searches;
-        while (sr) {
-            if (!sr->done && sr->step_time + 5 <= h->now) {
-                search_step(h, sr);
-            }
-            sr = sr->next;
-        }
-
-        h->search_time = 0;
-
-        sr = h->searches;
-        while (sr) {
-            if (!sr->done) {
-                time_t tm = sr->step_time + 15 + random() % 10;
-                if (h->search_time == 0 || h->search_time > tm) {
-                    h->search_time = tm;
-                               }
-            }
-            sr = sr->next;
-        }
-    }
-
-    if (h->now >= h->confirm_nodes_time) {
-        int soon = 0;
-
-        soon |= bucket_maintenance(h, AF_INET);
-        soon |= bucket_maintenance(h, AF_INET6);
-
-        if (!soon) {
-            if (h->mybucket_grow_time >= h->now - 150) {
-                soon |= neighbourhood_maintenance(h, AF_INET);
-                       }
-            if (h->mybucket6_grow_time >= h->now - 150) {
-                soon |= neighbourhood_maintenance(h, AF_INET6);
-                       }
-        }
-
-        /* In order to maintain all buckets' age within 600 seconds, worst case is roughly 27 seconds, assuming the table is 22 bits deep.
-           We want to keep a margin for neighborhood maintenance, so keep this within 25 seconds. */
-        if (soon) {
-            h->confirm_nodes_time = h->now + 5 + random() % 20;
-               } else {
-            h->confirm_nodes_time = h->now + 60 + random() % 120;
-               }
-    }
-
-    if (h->confirm_nodes_time > h->now) {
-        h->tosleep = h->confirm_nodes_time - h->now;
-    } else {
-        h->tosleep = 0;
-       }
-
-    if (h->search_time > 0) {
-        if (h->search_time <= h->now) {
-            h->tosleep = 0;
-        } else if (h->tosleep > h->search_time - h->now) {
-            h->tosleep = h->search_time - h->now;
-               }
-    }
-       ks_safe_free(logmsg);
-
-       ks_dht_store_prune(h->store, h->now);
-
-    return 1;
-}
-
-KS_DECLARE(int) dht_get_nodes(dht_handle_t *h, struct sockaddr_in *sin, int *num,
-              struct sockaddr_in6 *sin6, int *num6)
-{
-    int i, j;
-    struct bucket *b;
-    struct node *n;
-
-    i = 0;
-
-    /* For restoring to work without discarding too many nodes, the list
-       must start with the contents of our bucket. */
-    b = find_bucket(h, h->myid, AF_INET);
-    if (b == NULL) {
-        goto no_ipv4;
-       }
-
-    n = b->nodes;
-    while (n && i < *num) {
-        if (node_good(h, n)) {
-            sin[i] = *(struct sockaddr_in*)&n->ss;
-            i++;
-        }
-        n = n->next;
-    }
-
-    b = h->buckets;
-    while (b && i < *num) {
-        if (!in_bucket(h->myid, b)) {
-            n = b->nodes;
-            while (n && i < *num) {
-                if (node_good(h, n)) {
-                    sin[i] = *(struct sockaddr_in*)&n->ss;
-                    i++;
-                }
-                n = n->next;
-            }
-        }
-        b = b->next;
-    }
-
- no_ipv4:
-
-    j = 0;
-
-    b = find_bucket(h, h->myid, AF_INET6);
-    if (b == NULL) {
-        goto no_ipv6;
-       }
-
-    n = b->nodes;
-    while (n && j < *num6) {
-        if (node_good(h, n)) {
-            sin6[j] = *(struct sockaddr_in6*)&n->ss;
-            j++;
-        }
-        n = n->next;
-    }
-
-    b = h->buckets6;
-    while (b && j < *num6) {
-        if (!in_bucket(h->myid, b)) {
-            n = b->nodes;
-            while (n && j < *num6) {
-                if (node_good(h, n)) {
-                    sin6[j] = *(struct sockaddr_in6*)&n->ss;
-                    j++;
-                }
-                n = n->next;
-            }
-        }
-        b = b->next;
-    }
-
- no_ipv6:
-
-    *num = i;
-    *num6 = j;
-    return i + j;
-}
-
-KS_DECLARE(int) dht_insert_node(dht_handle_t *h, const unsigned char *id, ks_sockaddr_t *sa)
-{
-    struct node *n;
-
-    if (sa->family != AF_INET) {
-        errno = EAFNOSUPPORT;
-        return -1;
-    }
-
-    n = new_node(h, id, sa, 0);
-    return !!n;
-}
-
-KS_DECLARE(int) dht_ping_node(dht_handle_t *h, ks_sockaddr_t *sa)
-{
-    unsigned char tid[4];
-
-    ks_log(KS_LOG_DEBUG, "Sending ping.\n");
-    make_tid(tid, "pn", 0);
-    return send_ping(h, sa, tid, 4);
-}
-
-/* We could use a proper bencoding printer and parser, but the format of
-   DHT messages is fairly stylised, so this seemed simpler. */
-
-#define CHECK(offset, delta, size)                      \
-    if (delta < 0 || offset + delta > size) goto fail
-
-#define INC(offset, delta, size)                        \
-    CHECK(offset, delta, size);                         \
-    offset += delta
-
-#define COPY(buf, offset, src, delta, size)             \
-    CHECK(offset, delta, size);                         \
-    memcpy(buf + offset, src, delta);                   \
-    offset += delta;
-
-#define ADD_V(buf, offset, size)                        \
-    if (h->have_v) {                                        \
-        COPY(buf, offset, h->my_v, sizeof(h->my_v), size);    \
-    }
-
-static int dht_send(dht_handle_t *h, const void *buf, size_t len, int flags, const ks_sockaddr_t *sa)
-{
-       char ip[80] = "";
-       ks_ip_t *ipt;
-
-    if (node_blacklisted(h, sa)) {
-        ks_log(KS_LOG_DEBUG, "Attempting to send to blacklisted node.\n");
-        errno = EPERM;
-        return -1;
-    }
-
-       
-       ks_ip_route(ip, sizeof(ip), sa->host);
-
-       if (!(ipt = ks_hash_search(h->iphash, ip, KS_UNLOCKED)) && h->autoroute) {
-               ipt = add_ip(h, ip, 0, sa->family);
-       }
-
-       if (!ipt) {
-               ks_log(KS_LOG_ERROR, "No route to dest\n");
-        errno = EINVAL;
-               return -1;
-       }
-
-       ks_log(KS_LOG_INFO, "Sending message to [%s] port (%d)\n", sa->host, sa->port);
-
-       if (ks_socket_sendto(ipt->sock, (void *)buf, &len, (ks_sockaddr_t *)sa) != KS_STATUS_SUCCESS) {
-               ks_log(KS_LOG_ERROR, "Socket Error (%s)\n", strerror(errno));
-               return -1;
-       }
-
-    return 0;
-}
-
-/* Sample ping packet '{"t":"aa", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}}' */
-/* http://www.bittorrent.org/beps/bep_0005.html */
-static int send_ping(dht_handle_t *h, const ks_sockaddr_t *sa, const unsigned char *tid, int tid_len)
-{
-    char buf[512];
-    int i = 0;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *bencode_a_p = ben_dict();
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));    
-       ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("ping", 4));
-       ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
-       ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
-
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
-
-    return dht_send(h, buf, i, 0, sa);
-}
-
-/* Sample pong packet '{"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}' */
-/* http://www.bittorrent.org/beps/bep_0005.html */
-static int send_pong(dht_handle_t *h, const ks_sockaddr_t *sa, const unsigned char *tid, int tid_len)
-{
-    char buf[512];
-       int i = 0;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *bencode_a_p = ben_dict();
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("r", 1));
-       ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
-       ben_dict_set(bencode_p, ben_blob("r", 1), bencode_a_p);
-
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
-
-       ks_log(KS_LOG_DEBUG, "Encoded PONG\n");
-    return dht_send(h, buf, i, 0, sa);
-}
-
-/* Sample find_node packet '{"t":"aa", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456"}}' */
-/* Sample find_node packet w/ want '{"t":"aa", "y":"q", "q":"find_node", "a": {"id":"abcdefghij0123456789", "target":"mnopqrstuvwxyz123456", "want":"n4"}}' */
-/* http://www.bittorrent.org/beps/bep_0005.html */
-/* http://www.bittorrent.org/beps/bep_0032.html for want parameter */
-static int send_find_node(dht_handle_t *h, const ks_sockaddr_t *sa,
-               const unsigned char *tid, int tid_len,
-                          const unsigned char *target, int target_len, int want, int confirm)
-{
-    char buf[512];
-       int i = 0;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *bencode_a_p = ben_dict();
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
-       ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("find_node", 9));
-       ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
-
-       if (target) ben_dict_set(bencode_a_p, ben_blob("target", 6), ben_blob(target, target_len));
-
-       if (want > 0) {
-               struct bencode *bencode_w = ben_list();
-               if (want & WANT4) {
-                       ben_list_append(bencode_w, ben_blob("n4", 2));
-               }
-               if (want & WANT6) {
-                       ben_list_append(bencode_w, ben_blob("n6", 2));
-               }
-               ben_dict_set(bencode_a_p, ben_blob("want", 4), bencode_w);
-       }
-
-       ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
-
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
-
-    return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa);
-}
-
-/* sample find_node response '{"t":"aa", "y":"r", "r": {"id":"0123456789abcdefghij", "nodes": "def456..."}}'*/
-/* http://www.bittorrent.org/beps/bep_0005.html */
-static int send_nodes_peers(dht_handle_t *h, const ks_sockaddr_t *sa,
-                 const unsigned char *tid, int tid_len,
-                 const unsigned char *nodes, int nodes_len,
-                 const unsigned char *nodes6, int nodes6_len,
-                 int af, struct storage *st,
-                 const unsigned char *token, int token_len)
-{
-    char buf[2048];
-    int i = 0, j0, j, k;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *bencode_a_p = ben_dict();
-       struct bencode *ben_array = ben_list();
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("r", 1));
-       ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
-       if (token_len)  ben_dict_set(bencode_a_p, ben_blob("token",  5), ben_blob(token, token_len));
-       if (nodes_len)  ben_dict_set(bencode_a_p, ben_blob("nodes",  5), ben_blob(nodes, nodes_len));
-       if (nodes6_len) ben_dict_set(bencode_a_p, ben_blob("nodes6", 6), ben_blob(nodes6, nodes6_len));
-
-       /* 
-          Response with peers = {"t":"aa", "y":"r", "r": {"id":"abcdefghij0123456789", "token":"aoeusnth", "values": ["axje.u", "idhtnm"]}}
-       */
-       
-    if (st && st->numpeers > 0) {
-        // We treat the storage as a circular list, and serve a randomly
-        //   chosen slice.  In order to make sure we fit within 1024 octets,
-        //   we limit ourselves to 50 peers.
-
-        j0 = random() % st->numpeers;
-        j = j0;
-        k = 0;
-
-       do {
-            if (st->peers[j].addr.family == af) {
-                               char data[18];
-                               unsigned short swapped = htons(st->peers[j].addr.port);
-                               void *ip = NULL;
-                               ks_size_t iplen = 0;
-
-                               ks_addr_raw_data(&st->peers[j].addr, &ip, &iplen);
-
-                               memcpy(data, ip, iplen);
-                               memcpy(data + iplen, &swapped, 2);
-                               ben_list_append(ben_array, ben_blob(data, iplen + 2));
-                k++;
-            }
-            j = (j + 1) % st->numpeers;
-        } while(j != j0 && k < 50);
-          ben_dict_set(bencode_a_p, ben_blob("values", 6), ben_array);
-    }
-
-       ben_dict_set(bencode_p, ben_blob("r", 1), bencode_a_p);
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
-       
-       return dht_send(h, buf, i, 0, sa);
-}
-
-static int insert_closest_node(unsigned char *nodes, int numnodes,
-                    const unsigned char *id, struct node *n)
-{
-    int i, size;
-
-    if (n->ss.family == AF_INET) {
-        size = 26;
-    } else if (n->ss.family == AF_INET6) {
-        size = 38;
-    } else {
-        abort();
-       }
-
-    for (i = 0; i< numnodes; i++) {
-        if (id_cmp(n->id, nodes + size * i) == 0) {
-            return numnodes;
-               }
-        if (xorcmp(n->id, nodes + size * i, id) < 0) {
-            break;
-               }
-    }
-
-    if (i == 8) {
-        return numnodes;
-       }
-
-    if (numnodes < 8) {
-        numnodes++;
-       }
-
-    if (i < numnodes - 1) {
-        memmove(nodes + size * (i + 1), nodes + size * i, size * (numnodes - i - 1));
-       }
-
-    if (n->ss.family == AF_INET) {
-        memcpy(nodes + size * i, n->id, 20);
-        memcpy(nodes + size * i + 20, &n->ss.v.v4.sin_addr, 4);
-        memcpy(nodes + size * i + 24, &n->ss.v.v4.sin_port, 2);
-    } else if (n->ss.family == AF_INET6) {
-        memcpy(nodes + size * i, n->id, 20);
-        memcpy(nodes + size * i + 20, &n->ss.v.v6.sin6_addr, 16);
-        memcpy(nodes + size * i + 36, &n->ss.v.v6.sin6_port, 2);
-    } else {
-        abort();
-    }
-
-    return numnodes;
-}
-
-static int buffer_closest_nodes(dht_handle_t *h, unsigned char *nodes, int numnodes, const unsigned char *id, struct bucket *b)
-{
-    struct node *n = b->nodes;
-    while (n) {
-        if (node_good(h, n)) {
-            numnodes = insert_closest_node(nodes, numnodes, id, n);
-               }
-        n = n->next;
-    }
-    return numnodes;
-}
-
-static int send_closest_nodes(dht_handle_t *h, const ks_sockaddr_t *sa,
-                                          const unsigned char *tid, int tid_len,
-                                          const unsigned char *id, int want,
-                                          int af, struct storage *st,
-                                          const unsigned char *token, int token_len)
-{
-    unsigned char nodes[8 * 26];
-    unsigned char nodes6[8 * 38];
-    int numnodes = 0, numnodes6 = 0;
-    struct bucket *b;
-
-    if (want < 0) {
-        want = sa->family == AF_INET ? WANT4 : WANT6;
-       }
-
-    if ((want & WANT4)) {
-        if ((b = find_bucket(h, id, AF_INET))) {
-            numnodes = buffer_closest_nodes(h, nodes, numnodes, id, b);
-            if (b->next) {
-                numnodes = buffer_closest_nodes(h, nodes, numnodes, id, b->next);
-                       }
-            if ((b = previous_bucket(h, b))) {
-                numnodes = buffer_closest_nodes(h, nodes, numnodes, id, b);
-                       }
-        } else {
-                       ks_log(KS_LOG_DEBUG, "send_closest_nodes did not find a 'close' ipv4 bucket\n");
-               }
-    }
-
-    if ((want & WANT6)) {
-        if ((b = find_bucket(h, id, AF_INET6))) {
-            numnodes6 = buffer_closest_nodes(h, nodes6, numnodes6, id, b);
-            if (b->next) { 
-                numnodes6 = buffer_closest_nodes(h, nodes6, numnodes6, id, b->next);
-                       }
-            if ((b = previous_bucket(h, b))) {
-                numnodes6 = buffer_closest_nodes(h, nodes6, numnodes6, id, b);
-                       }
-        } else {
-                       ks_log(KS_LOG_DEBUG, "send_closest_nodes did not find a 'close' ipv6 bucket\n");
-               }
-    }
-    ks_log(KS_LOG_DEBUG, "send_closest_nodes  (%d+%d nodes.)\n", numnodes, numnodes6);
-
-    return send_nodes_peers(h, sa, tid, tid_len,
-                            nodes, numnodes * 26,
-                            nodes6, numnodes6 * 38,
-                            af, st, token, token_len);
-}
-
-/* sample get_peers request '{"t":"aa", "y":"q", "q":"get_peers", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456"}}'*/
-/* sample get_peers w/ want '{"t":"aa", "y":"q", "q":"get_peers", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456": "want":"n4"}}'*/
-/* http://www.bittorrent.org/beps/bep_0005.html */
-/* http://www.bittorrent.org/beps/bep_0032.html for want parameter */
-static int send_get_peers(dht_handle_t *h, const ks_sockaddr_t *sa,
-                                  unsigned char *tid, int tid_len, unsigned char *infohash,
-                                  int want, int confirm)
-{
-    char buf[512];
-    int i = 0;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *bencode_a_p = ben_dict();
-       int infohash_len = infohash ? strlen((const char*)infohash) : 0;
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
-       ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("get_peers", 9));
-       ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
-       if (want > 0) {
-               struct bencode *bencode_w_p = ben_list();
-               if (want & WANT4) {
-                       ben_list_append(bencode_w_p, ben_blob("n4", 2));
-               }
-               if (want & WANT6) {
-                       ben_list_append(bencode_w_p, ben_blob("n6", 2));
-               }
-               ben_dict_set(bencode_a_p, ben_blob("want", 4), bencode_w_p);
-       }
-       ben_dict_set(bencode_a_p, ben_blob("info_hash", 9), ben_blob(infohash, infohash_len));
-       ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
-
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
-       
-       ks_log(KS_LOG_DEBUG, "Encoded GET_PEERS\n");
-
-    return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa);
-}
-/* '{"t":"aa", "y":"q", "q":"announce_peer", "a": {"id":"abcdefghij0123456789", "implied_port": 1, "info_hash":"mnopqrstuvwxyz123456", "port": 6881, "token": "aoeusnth"}}'*/
-static int send_announce_peer(dht_handle_t *h, const ks_sockaddr_t *sa,
-                                          unsigned char *tid, int tid_len,
-                                          unsigned char *infohash, unsigned short port,
-                                          unsigned char *token, int token_len, int confirm)
-{
-    char buf[512];
-    int i = 0;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *bencode_a_p = ben_dict();
-       int infohash_len = infohash ? strlen((const char*)infohash) : 0;
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("q", 1));
-       ben_dict_set(bencode_p, ben_blob("q", 1), ben_blob("announce_peer", 13));
-       ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
-       ben_dict_set(bencode_a_p, ben_blob("info_hash", 9), ben_blob(infohash, infohash_len));
-       ben_dict_set(bencode_a_p, ben_blob("port", 5), ben_int(port));
-       ben_dict_set(bencode_a_p, ben_blob("token", 5), ben_blob(token, token_len));
-       ben_dict_set(bencode_p, ben_blob("a", 1), bencode_a_p);
-
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
-       
-       ks_log(KS_LOG_DEBUG, "Encoded ANNOUNCE_PEERS\n");
-    return dht_send(h, buf, i, confirm ? MSG_CONFIRM : 0, sa);
-}
-/* '{"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}'*/
-static int send_peer_announced(dht_handle_t *h, const ks_sockaddr_t *sa, unsigned char *tid, int tid_len)
-{
-    char buf[512];
-    int i = 0;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *bencode_a_p = ben_dict();
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("r", 1));
-       ben_dict_set(bencode_a_p, ben_blob("id", 2), ben_blob(h->myid, 20));
-       ben_dict_set(bencode_p, ben_blob("r", 1), bencode_a_p);
-       
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p); /* This SHOULD free the bencode_a_p as well */
-       
-       ks_log(KS_LOG_DEBUG, "Encoded peer_announced: %s\n\n", buf);
-    return dht_send(h, buf, i, 0, sa);
-}
-
-/* '{"t":"aa", "y":"e", "e":[201, "A Generic Error Ocurred"]}'*/
-static int send_error(dht_handle_t *h, const ks_sockaddr_t *sa,
-                                         unsigned char *tid, int tid_len,
-                                         int code, const char *message)
-{
-    char buf[512];
-    int i = 0;
-       struct bencode *bencode_p = ben_dict();
-       struct bencode *ben_array = ben_list();
-
-       ben_dict_set(bencode_p, ben_blob("t", 1), ben_blob(tid, tid_len));
-       ben_dict_set(bencode_p, ben_blob("y", 1), ben_blob("e", 1));
-       ben_list_append(ben_array, ben_int(code));
-       ben_list_append(ben_array, ben_blob(message, strlen(message)));
-       ben_dict_set(bencode_p, ben_blob("e", 1), ben_array);
-
-       i = ben_encode2(buf, 512, bencode_p);
-       ben_free(bencode_p);
-       
-       ks_log(KS_LOG_DEBUG, "Encoded error: %s\n\n", buf);
-    return dht_send(h, buf, i, 0, sa);
-}
-
-#undef CHECK
-#undef INC
-#undef COPY
-#undef ADD_V
-
-/*
-
-#ifdef HAVE_MEMMEM
-
-static void *dht_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
-{
-    return memmem(haystack, haystacklen, needle, needlelen);
-}
-
-#else
-
-static void *dht_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
-{
-    const char *h = haystack;
-    const char *n = needle;
-    size_t i;
-
-  
-    if (needlelen > haystacklen)
-        return NULL;
-
-    for(i = 0; i <= haystacklen - needlelen; i++) {
-        if (memcmp(h + i, n, needlelen) == 0) {
-            return (void*)(h + i);
-               }
-    }
-    return NULL;
-}
-
-#endif
-*/
-static dht_msg_type_t parse_message(struct bencode *bencode_p,
-                                                                       unsigned char *tid_return, int *tid_len,
-                                                                       unsigned char *id_return)
-{
-       //    const unsigned char *p;
-       dht_msg_type_t type = DHT_MSG_INVALID;
-       struct bencode *b_tmp = NULL;
-       struct bencode *key_t = ben_dict_get_by_str(bencode_p, "t");
-       struct bencode *key_args = ben_dict_get_by_str(bencode_p, "a");
-       struct bencode *key_resp = ben_dict_get_by_str(bencode_p, "r");
-
-       /* Need to set tid, tid_len, and id_return. Then return the message type or msg_error. */
-
-       if ( key_t ) {
-               const char *tran = ben_str_val(key_t);
-               int tran_len = ben_str_len(key_t);
-
-               memcpy(tid_return, tran, (size_t) tran_len);
-               *tid_len = tran_len;
-       }
-
-       if ( key_args ) {
-               struct bencode *b_id = ben_dict_get_by_str( key_args, "id");
-               const char *id = b_id ? ben_str_val(b_id) : NULL;
-               int id_len = ben_str_len(b_id);
-               
-               if ( id ) {
-                       memcpy(id_return, id, id_len);
-               }
-       }
-
-       if ( key_resp ) {
-               struct bencode *b_id = ben_dict_get_by_str( key_resp, "id");
-               const char *id = b_id ? ben_str_val(b_id) : NULL;
-               int id_len = ben_str_len(b_id);
-               
-               if ( id ) {
-                       memcpy(id_return, id, id_len);
-               }
-       }
-       
-
-       if ( ben_dict_get_by_str(bencode_p, "y") && key_t ){
-               /* This message is a KRPC message(aka DHT message) */
-
-               if ( ( b_tmp = ben_dict_get_by_str(bencode_p, "y") ) ) {
-                       if ( !ben_cmp_with_str(b_tmp, "q") ) { /* Inbound queries */
-                               struct bencode *b_query = NULL;
-                               const char *val = ben_str_val(b_tmp);
-                               ks_log(KS_LOG_DEBUG, "Message Query [%s]\n", val);
-
-                               if ( !( b_query = ben_dict_get_by_str(bencode_p, "q") ) ) {
-                                       ks_log(KS_LOG_DEBUG, "Unable to locate query type field\n");
-                               } else { /* Has a query type */
-                                       const char *query_type = ben_str_val(b_query);
-                                       if (!ben_cmp_with_str(b_query, "get_peers")) {
-                                               /*
-                                                 {
-                                                   'a': {
-                                                             'id': '~\x12*\xe6L3\xba\x83\xafT\xe3\x02\x93\x0e\xae\xbd\xf8\xe1\x98\x87', 
-                                                             'info_hash': 'w"E\x85\xdd97\xd1\xfe\x13Q\xfa\xdae\x9d\x8f\x86\xddN9'
-                                                            }, 
-                                                       'q': 'get_peers', 
-                                                       't': '?\xf1', 
-                                                       'v': 'LT\x01\x00', 
-                                                       'y': 'q'
-                                                 }
-                                                */
-                                               
-                                               ks_log(KS_LOG_DEBUG, "get_peers query recieved\n");
-                                               type = DHT_MSG_GET_PEERS;
-                                               goto done;
-                                       } else if (!ben_cmp_with_str(b_query, "ping")) {
-                                               /* 
-                                                  {'a': {
-                                                         'id': 'T\x1cd2\xc1\x85\xf4>?\x84#\xa8)\xd0`\x19y\xcf;\xda'
-                                                                }, 
-                                                       'q': 'ping', 
-                                                       't': 'pn\x00\x00', 
-                                                       'v': 'JC\x00\x00', 
-                                                       'y': 'q'
-                                                  }
-                                               */
-                                               ks_log(KS_LOG_DEBUG, "ping query recieved from client \n");
-                                               type = DHT_MSG_PING;
-                                               goto done;
-                                       } else if (!ben_cmp_with_str(b_query, "find_node")) {
-                                               /*
-                                                 {'a': {
-                                                        'id': 'T\x1cq\x7f\xa9^\xf2\x97S\xceE\xad\xc9S\x9b\xa1\x1cCX\x8d',
-                                                                'target': 'T\x1cq\x7f\xa9C{\x83\xf9\xf6i&\x8b\x87*\xa2\xad\xad\x1a\xdd'
-                                                               },
-                                                  'q': 'find_node',
-                                                  't': '\x915\xbe\xfb',
-                                                  'v': 'UTu\x13',
-                                                  'y': 'q'
-                                                 }
-                                               */
-                                               type = DHT_MSG_FIND_NODE;
-                                               goto done;
-                                       } else if (!ben_cmp_with_str(b_query, "put")) {
-                                               ks_log(KS_LOG_DEBUG, "Recieved a store put request\n");
-                                               type = DHT_MSG_STORE_PUT;
-                                               goto done;
-                                       } else {
-                                               ks_log(KS_LOG_DEBUG, "Unknown query type field [%s]\n", query_type);
-                                       }
-                               }
-                               
-                       } else if ( !ben_cmp_with_str(b_tmp, "r") ) { /* Responses */
-                               const char *val = ben_str_val(b_tmp);
-                               ks_log(KS_LOG_DEBUG, "Message Response [%s]\n", val);
-                               type = DHT_MSG_REPLY;
-                               goto done;
-                       } else if ( !ben_cmp_with_str(b_tmp, "e") ) {
-                               const char *val = ben_str_val(b_tmp);
-                               ks_log(KS_LOG_DEBUG, "Message Error [%s]\n", val);
-                       } else {
-                               ks_log(KS_LOG_DEBUG, "Message Type Unknown!!!\n");
-                       }
-               } else {
-                       ks_log(KS_LOG_DEBUG, "Message Type Unknown, has no 'y' key!!!\n");
-               }
-               
-               /* 
-                  Decode the request or response 
-                  (b_tmp = ben_dict_get_by_str(bencode_p, "y"))) {
-                  ks_log(KS_LOG_DEBUG, "query value: %s\n", ben_print(b_tmp));
-               */
-       } else {
-               ks_log(KS_LOG_DEBUG, "Message not a remote DHT request nor query\n");
-       }
-
-       /* Default to MSG ERROR */
-       ks_log(KS_LOG_DEBUG, "Unknown or unsupported message type\n");
-       return type;
-
- done:
-       return type;
-
-       /*
-    if (dht_memmem(buf, buflen, "1:q4:ping", 9)) {
-        return DHT_MSG_PING;
-       }
-
-    if (dht_memmem(buf, buflen, "1:q9:find_node", 14)) {
-       return DHT_MSG_FIND_NODE;
-       }
-
-    if (dht_memmem(buf, buflen, "1:q9:get_peers", 14)) {
-        return DHT_MSG_GET_PEERS;
-       }
-
-    if (dht_memmem(buf, buflen, "1:q13:announce_peer", 19)) {
-       return DHT_MSG_ANNOUNCE_PEER;
-       }
-
-       char *val = ben_str_val(b_tmp);
-
-       */
-       
-
-       /*
-       if (tid_return) {
-        p = dht_memmem(buf, buflen, "1:t", 3);
-        if (p) {
-            long l;
-            char *q;
-            l = strtol((char*)p + 3, &q, 10);
-            if (q && *q == ':' && l > 0 && l < *tid_len) {
-                CHECK(q + 1, l);
-                memcpy(tid_return, q + 1, l);
-                *tid_len = l;
-            } else
-                *tid_len = 0;
-        }
-    }
-    if (id_return) {
-        p = dht_memmem(buf, buflen, "2:id20:", 7);
-        if (p) {
-            CHECK(p + 7, 20);
-            memcpy(id_return, p + 7, 20);
-        } else {
-            memset(id_return, 0, 20);
-        }
-    }
-    if (info_hash_return) {
-        p = dht_memmem(buf, buflen, "9:info_hash20:", 14);
-        if (p) {
-            CHECK(p + 14, 20);
-            memcpy(info_hash_return, p + 14, 20);
-        } else {
-            memset(info_hash_return, 0, 20);
-        }
-    }
-    if (port_return) {
-        p = dht_memmem(buf, buflen, "porti", 5);
-        if (p) {
-            long l;
-            char *q;
-            l = strtol((char*)p + 5, &q, 10);
-            if (q && *q == 'e' && l > 0 && l < 0x10000) {
-                *port_return = l;
-            } else {
-                *port_return = 0;
-                       }
-        } else {
-            *port_return = 0;
-               }
-    }
-    if (target_return) {
-        p = dht_memmem(buf, buflen, "6:target20:", 11);
-        if (p) {
-            CHECK(p + 11, 20);
-            memcpy(target_return, p + 11, 20);
-        } else {
-            memset(target_return, 0, 20);
-        }
-    }
-    if (token_return) {
-        p = dht_memmem(buf, buflen, "5:token", 7);
-        if (p) {
-            long l;
-            char *q;
-            l = strtol((char*)p + 7, &q, 10);
-            if (q && *q == ':' && l > 0 && l < *token_len) {
-                CHECK(q + 1, l);
-                memcpy(token_return, q + 1, l);
-                *token_len = l;
-            } else {
-                *token_len = 0;
-                       }
-        } else {
-            *token_len = 0;
-               }
-    }
-
-    if (nodes_len) {
-        p = dht_memmem(buf, buflen, "5:nodes", 7);
-        if (p) {
-            long l;
-            char *q;
-            l = strtol((char*)p + 7, &q, 10);
-            if (q && *q == ':' && l > 0 && l <= *nodes_len) {
-                CHECK(q + 1, l);
-                memcpy(nodes_return, q + 1, l);
-                *nodes_len = l;
-            } else {
-                *nodes_len = 0;
-                       }
-        } else {
-            *nodes_len = 0;
-               }
-    }
-
-    if (nodes6_len) {
-        p = dht_memmem(buf, buflen, "6:nodes6", 8);
-        if (p) {
-            long l;
-            char *q;
-            l = strtol((char*)p + 8, &q, 10);
-            if (q && *q == ':' && l > 0 && l <= *nodes6_len) {
-                CHECK(q + 1, l);
-                memcpy(nodes6_return, q + 1, l);
-                *nodes6_len = l;
-            } else {
-                *nodes6_len = 0;
-                       }
-        } else {
-            *nodes6_len = 0;
-               }
-    }
-
-    if (values_len || values6_len) {
-        p = dht_memmem(buf, buflen, "6:valuesl", 9);
-        if (p) {
-            int i = p - buf + 9;
-            int j = 0, j6 = 0;
-            while (1) {
-                long l;
-                char *q;
-                l = strtol((char*)buf + i, &q, 10);
-                if (q && *q == ':' && l > 0) {
-                    CHECK(q + 1, l);
-                    i = q + 1 + l - (char*)buf;
-                    if (l == 6) {
-                        if (j + l > *values_len) {
-                            continue;
-                                               }
-                        memcpy((char*)values_return + j, q + 1, l);
-                        j += l;
-                    } else if (l == 18) {
-                        if (j6 + l > *values6_len) {
-                            continue;
-                                               }
-                        memcpy((char*)values6_return + j6, q + 1, l);
-                        j6 += l;
-                    } else {
-                        ks_log(KS_LOG_DEBUG, "Received weird value -- %d bytes.\n", (int)l);
-                    }
-                } else {
-                    break;
-                }
-            }
-            if (i >= buflen || buf[i] != 'e') {
-                ks_log(KS_LOG_DEBUG, "eek... unexpected end for values.\n");
-                       }
-            if (values_len) {
-                *values_len = j;
-                       }
-            if (values6_len) {
-                *values6_len = j6;
-                       }
-        } else {
-            if (values_len) {
-                *values_len = 0;
-                       }
-            if (values6_len) {
-                *values6_len = 0;
-                       }
-        }
-    }
-
-    if (want_return) {
-        p = dht_memmem(buf, buflen, "4:wantl", 7);
-        if (p) {
-            int i = p - buf + 7;
-            *want_return = 0;
-            while (buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' && i + 2 + buf[i] - '0' < buflen) {
-                CHECK(buf + i + 2, buf[i] - '0');
-                if (buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0) {
-                    *want_return |= WANT4;
-                               } else if (buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0) {
-                    *want_return |= WANT6;
-                } else {
-                    ks_log(KS_LOG_DEBUG, "eek... unexpected want flag (%c)\n", buf[i]);
-                               }
-                i += 2 + buf[i] - '0';
-            }
-            if (i >= buflen || buf[i] != 'e') {
-                ks_log(KS_LOG_DEBUG, "eek... unexpected end for want.\n");
-                       }
-        } else {
-            *want_return = -1;
-        }
-    }
-
-#undef CHECK
-
-    if (dht_memmem(buf, buflen, "1:y1:r", 6)) {
-        return DHT_MSG_REPLY;
-       }
-
-    if (dht_memmem(buf, buflen, "1:y1:e", 6)) {
-        return DHT_MSG_ERROR;
-       }
-
-    if (!dht_memmem(buf, buflen, "1:y1:q", 6)) {
-        return DHT_MSG_INVALID;
-       }
-
-    if (dht_memmem(buf, buflen, "1:q4:ping", 9)) {
-        return DHT_MSG_PING;
-       }
-
-    if (dht_memmem(buf, buflen, "1:q9:find_node", 14)) {
-       return DHT_MSG_FIND_NODE;
-       }
-
-    if (dht_memmem(buf, buflen, "1:q9:get_peers", 14)) {
-        return DHT_MSG_GET_PEERS;
-       }
-
-    if (dht_memmem(buf, buflen, "1:q13:announce_peer", 19)) {
-       return DHT_MSG_ANNOUNCE_PEER;
-       }
-
-    return DHT_MSG_INVALID;
-
- overflow:
-    ks_log(KS_LOG_DEBUG, "Truncated message.\n");
-    return DHT_MSG_INVALID;
-       */
-       
-}
-
-/* b64encode function taken from kws.c. Maybe worth exposing a function like this. */
-static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static int b64encode(unsigned char *in, ks_size_t ilen, unsigned char *out, ks_size_t olen)
-{
-       int y=0,bytes=0;
-       ks_size_t x=0;
-       unsigned int b=0,l=0;
-
-       if(olen) {
-       }
-
-       for(x=0;x<ilen;x++) {
-               b = (b<<8) + in[x];
-               l += 8;
-               while (l >= 6) {
-                       out[bytes++] = c64[(b>>(l-=6))%64];
-                       if(++y!=72) {
-                               continue;
-                       }
-                       //out[bytes++] = '\n';
-                       y=0;
-               }
-       }
-
-       if (l > 0) {
-               out[bytes++] = c64[((b%16)<<(6-l))%64];
-       }
-       if (l != 0) while (l < 6) {
-               out[bytes++] = '=', l += 2;
-       }
-
-       return 0;
-}
-
-
-/* 
-   This function should generate the fields needed for the mutable message.
-
-   Save the sending for another api, and possibly a third to generate and send all in one.
-   NOTE: 
-   1. When sending a mutable message, CAS(compare and swap) values need to be validated.
-   2. Mutable messages MUST have a new key pair generated for each different mutable message. 
-      The announce key is generated as a hash from the public key. To use one key pair for multiple messages, 
-         a salt MUST be used that is unique and constant per message.
-   3. The target hash will be generated here, and will be the hash that must be used for announcing the message, and updating it.
-
-*/
-KS_DECLARE(int) ks_dht_generate_mutable_storage_args(struct bencode *data, int64_t sequence, int cas,
-                                                                                unsigned char *id, int id_len, /* querying nodes id */
-                                                                                const unsigned char *sk, const unsigned char *pk,
-                                                                                unsigned char *salt, unsigned long long salt_length,
-                                                                                unsigned char *token, unsigned long long token_length,
-                                                                                unsigned char *signature, unsigned long long *signature_length,
-                                                                                struct bencode **arguments)
-{
-       struct bencode *arg = NULL, *sig = NULL;
-       unsigned char *encoded_message = NULL, *encoded_data = NULL;
-       size_t encoded_message_size = 0, encoded_data_size = 0;
-       int err = 0;
-
-       if ( !data || !sequence || !id || !id_len || !sk || !pk ||
-                !token || !token_length || !signature || !signature_length) {
-               ks_log(KS_LOG_ERROR, "Missing required input\n");
-               return -1;
-       }
-
-       if ( arguments && *arguments) {
-               ks_log(KS_LOG_ERROR, "Arguments already defined.\n");
-               return -1;
-       }
-       
-       if ( salt && salt_length > 64 ) {
-               ks_log(KS_LOG_ERROR, "Salt is too long. Can not be longer than 64 bytes\n");
-               return -1;
-       }
-
-       if ( sequence && sequence < 0 ) {
-               ks_log(KS_LOG_ERROR, "Sequence out of acceptable range\n");
-               return -1;
-       }
-
-       encoded_data = (unsigned char *) ben_encode(&encoded_data_size, data);
-       
-       if ( encoded_data_size > 1000 ) {
-               ks_log(KS_LOG_ERROR, "Message is too long. Max is 1000 bytes\n");
-               free(encoded_data);
-               return -1;
-       }
-
-       /* Need to dynamically allocate a bencoded object for the signature. */
-       sig = ben_dict();
-
-       if ( salt ) {
-               ben_dict_set(sig, ben_blob("salt", 4), ben_blob(salt, salt_length));
-       }
-       
-       ben_dict_set(sig, ben_blob("seq", 3), ben_int(sequence));
-       ben_dict_set(sig, ben_blob("v", 1), ben_blob(encoded_data, encoded_data_size));
-
-       encoded_message = ben_encode(&encoded_message_size, sig);
-       ks_log(KS_LOG_DEBUG, "Encoded data %d [%.*s]\n", encoded_message_size, encoded_message_size, encoded_message);
-
-       err = crypto_sign_detached(signature, NULL, encoded_message, encoded_message_size, sk);
-       if ( err ) {
-               ks_log(KS_LOG_ERROR, "Failed to sign message with provided secret key\n");
-               return 1;
-       }
-
-       free(encoded_message);
-       ben_free(sig);
-
-       arg = ben_dict();
-
-       if ( cas ) {
-               ben_dict_set(arg, ben_blob("cas", 3), ben_int(cas));
-       }
-
-       ben_dict_set(arg, ben_blob("id", 2), ben_blob(id, id_len));
-       ben_dict_set(arg, ben_blob("k", 1), ben_blob(pk, 32)); /* All ed25519 public keys are 32 bytes */
-
-       if ( salt ) {
-               ben_dict_set(arg, ben_blob("salt", 4), ben_blob(salt, salt_length));
-       }
-       
-       ben_dict_set(arg, ben_blob("seq", 3), ben_int(sequence));
-       ben_dict_set(arg, ben_blob("sig", 3), ben_blob(signature, (size_t) *signature_length));
-       ben_dict_set(arg, ben_blob("token", 5), ben_blob(token, token_length));
-       ben_dict_set(arg, ben_blob("v", 1), ben_blob(encoded_data, encoded_data_size));
-
-       *arguments = arg;
-
-       free(encoded_data);
-       
-       return 0;
-}
-
-KS_DECLARE(int) ks_dht_calculate_mutable_storage_target(unsigned char *pk, unsigned char *salt, int salt_length, unsigned char *target, int target_length)
-{
-       SHA_CTX sha;
-       unsigned char sha1[20] = {0};
-
-       /* Generate target sha-1 hash */
-       SHA1_Init(&sha);
-       SHA1_Update(&sha, pk, 32);
-
-       if ( salt ) {
-               SHA1_Update(&sha, salt, salt_length);
-       }
-       
-       SHA1_Final(sha1, &sha);
-       b64encode(sha1, 20, target, target_length);
-
-       return 0;
-}
-
-KS_DECLARE(int) ks_dht_send_message_mutable_cjson(dht_handle_t *h, unsigned char *sk, unsigned char *pk, char **node_id,
-                                                                                       char *message_id, int sequence, cJSON *message, ks_time_t life)
-{
-       struct bencode *body = ben_dict();
-       char *output = NULL;
-       char *json = cJSON_PrintUnformatted(message);
-       int err = 0;
-       size_t output_len = 0;
-
-       ben_dict_set(body, ben_blob("ct", 2), ben_blob("json", 4));
-       ben_dict_set(body, ben_blob("b", 1), ben_blob(json, strlen(json)));
-
-       output = (char *)ben_encode(&output_len, body);
-
-       err = ks_dht_send_message_mutable(h, sk, pk, node_id, message_id, sequence, output, life);
-       free(json);
-       free(output);
-       ben_free(body);
-
-       return err;
-}
-
-KS_DECLARE(int) ks_dht_send_message_mutable(dht_handle_t *h, unsigned char *sk, unsigned char *pk, char **node_id,
-                                                                                       char *message_id, int sequence, char *message, ks_time_t life)
-{
-       unsigned char target[40], signature[crypto_sign_BYTES];
-       unsigned long long signature_length = crypto_sign_BYTES;
-       int message_length = strlen(message);
-       unsigned char tid[4];
-       unsigned char *salt = (unsigned char *)message_id;
-       int salt_length = strlen(message_id);
-       struct ks_dht_store_entry_s *entry = NULL;
-       struct bencode *b_message = ben_blob(message, message_length);
-       struct bencode *args = NULL, *data = NULL;
-    char buf[1500];
-       size_t buf_len = 0;
-       int err = 0;
-       h->now = ks_time_now_sec();
-
-       if ( !life ) {
-               /* Default to now plus 10 minutes */
-               life = 600;
-       }
-
-       make_tid(tid, "mm", 0);
-       
-       ks_dht_calculate_mutable_storage_target(pk, salt, salt_length, target, 40);
-
-       if ( (entry = ks_dht_store_fetch(h->store, (char *)target)) ) {
-               if ( sequence < entry->serial ) {
-                       sequence = entry->serial;
-               }
-       }
-
-
-       /*
-int ks_dht_generate_mutable_storage_args(struct bencode *data, int64_t sequence, int cas,
-                                                                                unsigned char *id, int id_len, 
-                                                                                const unsigned char *sk, const unsigned char *pk,
-                                                                                unsigned char *salt, unsigned long long salt_length,
-                                                                                unsigned char *token, unsigned long long token_length,
-                                                                                unsigned char *signature, unsigned long long *signature_length,
-                                                                                struct bencode **arguments) */
-
-       
-       err = ks_dht_generate_mutable_storage_args(b_message, sequence, 1,
-                                                                                          h->myid, 20,
-                                                                                          sk, pk,
-                                                                                          salt, salt_length,
-                                                                                          (unsigned char *) target, 40,
-                                                                                          signature, &signature_length,
-                                                                                          &args);
-
-       if ( err ) {
-               return err;
-       }
-
-       data = ben_dict();
-       ben_dict_set(data, ben_blob("a", 1), args);
-       ben_dict_set(data, ben_blob("t", 1), ben_blob(tid, 4));
-       ben_dict_set(data, ben_blob("y", 1), ben_blob("q", 1));
-       ben_dict_set(data, ben_blob("q", 1), ben_blob("put", 3));
-
-       buf_len = ben_encode2(buf, 1500, data);
-       
-       err = ks_dht_store_entry_create(h, data, &entry, life, 1);
-       if ( err ) {
-               return err;
-       }
-
-       ks_dht_store_replace(h->store, entry);
-       
-       /* dht_search() announce of this hash */
-       dht_search(h, (const unsigned char *)entry->key, h->port, AF_INET, NULL, NULL);
-
-       if ( node_id && node_id[0] ) {
-               /* We're being told where to send these messages. */
-               int x = 0;
-
-               for ( x = 0; node_id[x] != NULL; x++ ) {
-                       unsigned char node_id_bin[20] = {0};
-                       struct node *n = NULL;
-                       size_t size = 0;
-                       
-                       sodium_hex2bin(node_id_bin, 20, node_id[x], 40, ":", &size, NULL);
-                       
-                       n = find_node(h, node_id_bin, AF_INET);
-                       
-                       if ( !n ) {
-                               n = find_node(h, node_id_bin, AF_INET6);
-                       }
-                       
-                       if ( !n ) {
-                               ks_log(KS_LOG_INFO, "Unable to find node with id\n");
-                               continue;
-                       }
-
-                       err |= dht_send(h, buf, buf_len, 0, &n->ss);
-               }
-       } else {
-               /* Client api assumes that we'll figure out where to send the message.
-                  We should find a bucket that resolves to the key, and send to all nodes in that bucket.
-                */ 
-               struct bucket *b4 = find_bucket(h, (const unsigned char *)entry->key, AF_INET);
-               struct bucket *b6 = find_bucket(h, (const unsigned char *)entry->key, AF_INET6);
-               struct node *n = NULL;
-
-               if ( b4 ) {
-                       for ( n = b4->nodes; n->next; n = n->next ) {
-                               err |= dht_send(h, buf, buf_len, 0, &n->ss);
-                       }
-               }
-
-               if ( b6 ) {
-                       for ( n = b6->nodes; n->next; n = n->next ) {
-                               err |= dht_send(h, buf, buf_len, 0, &n->ss);
-                       }
-               }
-       }
-
-       return err;
-}
-
-// KS_DECLARE(int) ks_dht_send_message_mutable(
-KS_DECLARE(int) ks_dht_api_find_node(dht_handle_t *h, char *node_id_hex, char *target_hex, ks_bool_t ipv6)
-{
-       unsigned char node_id[20] = {0}, target[20] = {0}, tid[4] = {0};
-       struct node *n = NULL;
-       size_t size = 0;
-
-       if ( strlen(node_id_hex) != 40 || strlen(target_hex) != 40 ) {
-               ks_log(KS_LOG_INFO, "node_id(%s)[%d] and target(%s)[%d] must each be 40 hex characters\n", node_id_hex, strlen(node_id_hex), target_hex, strlen(target_hex));
-               return 1;
-       }
-
-       sodium_hex2bin(node_id, 20, node_id_hex, 40, ":", &size, NULL);
-       sodium_hex2bin(target, 20, target_hex, 40, ":", &size, NULL);
-       
-       n = find_node(h, node_id, ipv6 ? AF_INET6 : AF_INET);
-
-       if ( !n ) {
-               ks_log(KS_LOG_INFO, "Unable to find node with id[%s]\n", node_id_hex);
-               return 1;
-       }
-       
-       make_tid(tid, "fn", 0);
-
-       return send_find_node(h, &n->ss, tid, 4, target, sizeof(target), WANT4 | WANT6, n->reply_time >= h->now - 15);
-}
-
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */
index 89e1fd45fe6ec6701ef7fe9d8e2a96e2e1388108..bd8ce48325aa54955fe76f3a03a905dcf10821f8 100644 (file)
@@ -64,6 +64,11 @@ testdht2_SOURCES = testdht2.c tap.c
 testdht2_CFLAGS = $(AM_CFLAGS)
 testdht2_LDADD = $(TEST_LDADD)
 
+check_PROGRAMS += nodeidgen
+nodeidgen_SOURCES = nodeidgen.c tap.c
+nodeidgen_CFLAGS = $(AM_CFLAGS)
+nodeidgen_LDADD = $(TEST_LDADD)
+
 #check_PROGRAMS += testdht_net
 #testdht_net_SOURCES = testdht-net.c tap.c
 #testdht_net_CFLAGS = $(AM_CFLAGS)
diff --git a/libs/libks/test/nodeidgen.c b/libs/libks/test/nodeidgen.c
new file mode 100644 (file)
index 0000000..14f95d9
--- /dev/null
@@ -0,0 +1,16 @@
+#include <ks.h>
+#include <ks_dht.h>
+#include <ks_dht-int.h>
+#include <tap.h>
+
+int main() {
+       uint8_t nodeid[KS_DHT_NODEID_SIZE];
+       char buf[KS_DHT_NODEID_SIZE * 2 + 1];
+       
+       randombytes_buf(nodeid, KS_DHT_NODEID_SIZE);
+
+       ks_dht_hex(nodeid, buf, KS_DHT_NODEID_SIZE);
+
+       printf(buf);
+       return 0;
+}
index 59eee76cf4016a089692e25565683d7607da7794..0c726dcb73e61a86e8d7aece594a242a2c090e49 100644 (file)
@@ -1,6 +1,6 @@
 #include <ks.h>
-#include <../dht/ks_dht.h>
-#include <../dht/ks_dht-int.h>
+#include <ks_dht.h>
+#include <ks_dht-int.h>
 #include <tap.h>
 
 ks_dht_storageitem_skey_t sk;
@@ -55,6 +55,7 @@ int main() {
        //ks_size_t buflen;
   ks_status_t err;
   int mask = 0;
+  ks_dht_nodeid_t nodeid;
   ks_dht_t *dht1 = NULL;
   ks_dht_t *dht2 = NULL;
   ks_dht_t *dht3 = NULL;
@@ -112,20 +113,23 @@ int main() {
          diag("Binding to %s on ipv6\n", v6);
   }
 
-  err = ks_dht_create(&dht1, NULL, NULL);
+  ks_dht_dehex(nodeid.id, "0000000000000000000000000000000000000001", KS_DHT_NODEID_SIZE);
+  err = ks_dht_create(&dht1, NULL, NULL, &nodeid);
   ok(err == KS_STATUS_SUCCESS);
   
-  err = ks_dht_create(&dht2, NULL, NULL);
+  ks_dht_dehex(nodeid.id, "0000000000000000000000000000000000000002", KS_DHT_NODEID_SIZE);
+  err = ks_dht_create(&dht2, NULL, NULL, &nodeid);
   ok(err == KS_STATUS_SUCCESS);
 
-  err = ks_dht_create(&dht3, NULL, NULL);
+  ks_dht_dehex(nodeid.id, "0000000000000000000000000000000000000003", KS_DHT_NODEID_SIZE);
+  err = ks_dht_create(&dht3, NULL, NULL, &nodeid);
   ok(err == KS_STATUS_SUCCESS);
   
   if (have_v4) {
     err = ks_addr_set(&addr, v4, KS_DHT_DEFAULT_PORT, AF_INET);
        ok(err == KS_STATUS_SUCCESS);
        
-    err = ks_dht_bind(dht1, NULL, &addr, &ep1);
+    err = ks_dht_bind(dht1, &addr, &ep1);
     ok(err == KS_STATUS_SUCCESS);
 
        raddr1 = addr;
@@ -133,7 +137,7 @@ int main() {
        err = ks_addr_set(&addr, v4, KS_DHT_DEFAULT_PORT + 1, AF_INET);
        ok(err == KS_STATUS_SUCCESS);
        
-       err = ks_dht_bind(dht2, NULL, &addr, &ep2);
+       err = ks_dht_bind(dht2, &addr, &ep2);
        ok(err == KS_STATUS_SUCCESS);
 
        //raddr2 = addr;
@@ -141,7 +145,7 @@ int main() {
        err = ks_addr_set(&addr, v4, KS_DHT_DEFAULT_PORT + 2, AF_INET);
        ok(err == KS_STATUS_SUCCESS);
        
-       err = ks_dht_bind(dht3, NULL, &addr, &ep3);
+       err = ks_dht_bind(dht3, &addr, &ep3);
        ok(err == KS_STATUS_SUCCESS);
 
        //raddr3 = addr;
@@ -151,19 +155,19 @@ int main() {
        err = ks_addr_set(&addr, v6, KS_DHT_DEFAULT_PORT, AF_INET6);
        ok(err == KS_STATUS_SUCCESS);
          
-    err = ks_dht_bind(dht1, NULL, &addr, NULL);
+    err = ks_dht_bind(dht1, &addr, NULL);
     ok(err == KS_STATUS_SUCCESS);
 
        err = ks_addr_set(&addr, v6, KS_DHT_DEFAULT_PORT + 1, AF_INET6);
        ok(err == KS_STATUS_SUCCESS);
 
-       err = ks_dht_bind(dht2, NULL, &addr, NULL);
+       err = ks_dht_bind(dht2, &addr, NULL);
        ok(err == KS_STATUS_SUCCESS);
 
        err = ks_addr_set(&addr, v6, KS_DHT_DEFAULT_PORT + 2, AF_INET6);
        ok(err == KS_STATUS_SUCCESS);
 
-       err = ks_dht_bind(dht3, NULL, &addr, NULL);
+       err = ks_dht_bind(dht3, &addr, NULL);
        ok(err == KS_STATUS_SUCCESS);
   }
 
@@ -175,11 +179,11 @@ int main() {
 
   ks_dht_pulse(dht1, 100); // Receive and process ping query from dht2, queue and send ping response
 
-  ok(ks_dhtrt_find_node(dht1->rt_ipv4, ep2->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
+  ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht2->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
 
   ks_dht_pulse(dht2, 100); // Receive and process ping response from dht1 (PROCESSING then COMPLETING)
 
-  ok(ks_dhtrt_find_node(dht2->rt_ipv4, ep1->nodeid) != NULL); // The node should be good, and thus be returned as good
+  ok(ks_dhtrt_find_node(dht2->rt_ipv4, dht1->nodeid) != NULL); // The node should be good, and thus be returned as good
 
   ks_dht_pulse(dht2, 100); // Call finish callback and purge the job (COMPLETING)
 
@@ -189,7 +193,7 @@ int main() {
          ks_dht_pulse(dht2, 100);
          ks_dht_pulse(dht3, 100);
   }
-  ok(ks_dhtrt_find_node(dht1->rt_ipv4, ep2->nodeid) != NULL); // The node should be good by now, and thus be returned as good
+  ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht2->nodeid) != NULL); // The node should be good by now, and thus be returned as good
 
   
   ks_dht_ping(dht3, &raddr1, NULL, NULL); // (QUERYING)
@@ -198,11 +202,11 @@ int main() {
   
   ks_dht_pulse(dht1, 100); // Receive and process ping query from dht3, queue and send ping response
 
-  ok(ks_dhtrt_find_node(dht1->rt_ipv4, ep3->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
+  ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht3->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
 
   ks_dht_pulse(dht3, 100); // Receive and process ping response from dht1 (PROCESSING then COMPLETING)
 
-  ok(ks_dhtrt_find_node(dht3->rt_ipv4, ep1->nodeid) != NULL); // The node should be good, and thus be returned as good
+  ok(ks_dhtrt_find_node(dht3->rt_ipv4, dht1->nodeid) != NULL); // The node should be good, and thus be returned as good
 
   ks_dht_pulse(dht3, 100); // Call finish callback and purge the job (COMPLETING)
 
@@ -212,26 +216,26 @@ int main() {
          ks_dht_pulse(dht2, 100);
          ks_dht_pulse(dht3, 100);
   }
-  ok(ks_dhtrt_find_node(dht1->rt_ipv4, ep2->nodeid) != NULL); // The node should be good by now, and thus be returned as good
+  ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht2->nodeid) != NULL); // The node should be good by now, and thus be returned as good
 
   // Test bootstrap find_node from dht3 to dht1 to find dht2 nodeid
 
   /*
   diag("Find_Node test\n");
 
-  ks_dht_findnode(dht3, NULL, &raddr1, NULL, NULL, &ep2->nodeid);
+  ks_dht_findnode(dht3, NULL, &raddr1, NULL, NULL, &dht2->nodeid);
 
   ks_dht_pulse(dht3, 100); // Send queued findnode from dht3 to dht1
 
   ks_dht_pulse(dht1, 100); // Receive and process findnode query from dht3, queue and send findnode response
 
-  ok(ks_dhtrt_find_node(dht1->rt_ipv4, ep3->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
+  ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht3->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
 
   ks_dht_pulse(dht3, 100); // Receive and process findnode response from dht1
   
   ks_dht_pulse(dht3, 100); // Call finish callback and purge the job (COMPLETING)
 
-  ok(ks_dhtrt_find_node(dht3->rt_ipv4, ep2->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
+  ok(ks_dhtrt_find_node(dht3->rt_ipv4, dht2->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet
   
   diag("Pulsing for route table pings\n"); // Wait for route table pinging to catch up
   for (int i = 0; i < 10; ++i) {
@@ -239,12 +243,12 @@ int main() {
          ks_dht_pulse(dht2, 100);
          ks_dht_pulse(dht3, 100);
   }
-  ok(ks_dhtrt_find_node(dht3->rt_ipv4, ep2->nodeid) != NULL); // The node should be good by now, and thus be returned as good
+  ok(ks_dhtrt_find_node(dht3->rt_ipv4, dht2->nodeid) != NULL); // The node should be good by now, and thus be returned as good
   */
 
   diag("Search test\n");
   
-  ks_dht_search(dht3, dht2_search_callback, NULL, dht3->rt_ipv4, &ep2->nodeid);
+  ks_dht_search(dht3, dht2_search_callback, NULL, dht3->rt_ipv4, &dht2->nodeid);
   diag("Pulsing for route table pings\n"); // Wait for route table pinging to catch up
   for (int i = 0; i < 20; ++i) {
          ks_dht_pulse(dht1, 100);