Initial commit of libdht. - libdht - A simple helper library for distributed hash tables.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit 0f07ba665e3bb84594cbaaac03393a72d26219e8
 (HTM) Author: Christoph Lohmann <20h@r-36.net>
       Date:   Tue,  8 Mar 2011 02:25:40 +0100
       
       Initial commit of libdht.
       
       Diffstat:
         LICENSE                             |      21 +++++++++++++++++++++
         Makefile                            |      69 ++++++++++++++++++++++++++++++
         README.md                           |      49 +++++++++++++++++++++++++++++++
         config.mk                           |      23 +++++++++++++++++++++++
         dht.c                               |     260 +++++++++++++++++++++++++++++++
         dht.h                               |     118 +++++++++++++++++++++++++++++++
         dhtlist.c                           |     166 +++++++++++++++++++++++++++++++
         dhttest.c                           |     113 +++++++++++++++++++++++++++++++
         ind.c                               |      99 +++++++++++++++++++++++++++++++
         ind.h                               |      22 ++++++++++++++++++++++
       
       10 files changed, 940 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/LICENSE b/LICENSE
       @@ -0,0 +1,21 @@
       +MIT/X Consortium License
       +
       +© 2011 Christoph Lohmann <20h@r-36.net>
       +
       +Permission is hereby granted, free of charge, to any person obtaining a
       +copy of this software and associated documentation files (the "Software"),
       +tto deal in the Software without restriction, including without limitation
       +tthe 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.
 (DIR) diff --git a/Makefile b/Makefile
       @@ -0,0 +1,69 @@
       +# libdht - simple dht library
       +# See LICENSE file for copyright and license details.
       +
       +include config.mk
       +
       +SRC = dht.c ind.c dhtlist.c
       +OBJ = ${SRC:.c=.o}
       +SOUT = ${NAME}.a
       +DOUT = ${NAME}.so
       +
       +all: options ${SOUT} ${DOUT} 
       +
       +options:
       +        @echo ${NAME} build options:
       +        @echo "CFLAGS   = ${CFLAGS}"
       +        @echo "LDFLAGS  = ${LDFLAGS}"
       +        @echo "CC       = ${CC}"
       +
       +.c.o:
       +        @echo CC $<
       +        @${CC} -c ${CFLAGS} $<
       +
       +${OBJ}: config.mk
       +
       +${SOUT}: ${OBJ} 
       +        @ar rcs ${SOUT} ${OBJ}
       +
       +${DOUT}: ${OBJ} 
       +        @${CC} -shared ${OBJ} -o ${DOUT}
       +
       +dhttest: ${OBJ} dhttest.o
       +        @echo CC -o $@
       +        @${CC} -o $@ ${OBJ} dhttest.o ${LDFLAGS}
       +
       +ttest: dhttest
       +        @echo running dhttest
       +        ./dhttest
       +
       +clean:
       +        @echo cleaning
       +        @rm -f *.so *.a ${NAME} ${OBJ} dhttest dhttest.o ${NAME}-${VERSION}.tar.gz
       +
       +dist: clean
       +        @echo creating dist tarball
       +        @mkdir -p ${NAME}-${VERSION}
       +        @cp -R LICENSE Makefile README.md config.mk \
       +                ${SRC} *.h ${NAME}-${VERSION}
       +        @tar -cf ${NAME}-${VERSION}.tar ${NAME}-${VERSION}
       +        @gzip ${NAME}-${VERSION}.tar
       +        @rm -rf ${NAME}-${VERSION}
       +
       +install: all
       +        @echo installing libraries to ${DESTDIR}${PREFIX}/lib
       +        @mkdir -p ${DESTDIR}${PREFIX}/lib
       +        @cp -f ${NAME}.a ${NAME}.so ${DESTDIR}${PREFIX}/lib
       +        @chmod 755 ${DESTDIR}${PREFIX}/lib/${NAME}.*
       +        @echo installing header file to ${DESTDIR}${PREFIX}/include
       +        @mkdir -p ${DESTDIR}${PREFIX}/include
       +        @cp -f dht.h ${DESTDIR}${PREFIX}/include
       +        @chmod 644 ${DESTDIR}${PREFIX}/include/dht.h
       +
       +uninstall:
       +        @echo removing libraries from ${DESTDIR}${PREFIX}/bin
       +        @rm -f ${DESTDIR}${PREFIX}/lib/${NAME}.*
       +        @echo removing header file from ${DESTDIR}${PREFIX}/include
       +        @rm -f ${DESTDIR}${PREFIX}/include/dht.h
       +
       +.PHONY: all options clean dist install uninstall test
       +# DO NOT DELETE
 (DIR) diff --git a/README.md b/README.md
       @@ -0,0 +1,49 @@
       +# libdht - a kadmelia helper function library
       +
       +The algorithm was taken from [here](https://gist.github.com/240988).
       +
       +## Installation
       +
       +        make
       +        make install
       +
       +## How to use it
       +
       +        #include <dht.h>
       +
       +        dht_t *dht;
       +        dhtnode_t *node;
       +        char id[IDLENGTH];
       +        llist_t *llist;
       +
       +        dht = dht_new("localhost");
       +
       +        /*
       +         * Set some node, which appeared on the network.
       +         */
       +        node = dhtnode_new();
       +        dhtnode_setid(node);
       +        dhtnode_setaddr("127.0.0.1:7689");
       +        dht_update(dht, node);
       +        dhtnode_free(node);
       +
       +        /*
       +         * Get at maximum five nodes next to the target node
       +         */
       +        dhtnode_setid(node);
       +        dhtnode_setaddr("8.8.8.8:6669");
       +        llist = dht_getclosest(dht, node, 5);
       +        forllist(llist, elem)
       +                dosomething(((dhtnode_t *)elem->data)->addr);
       +        dhtnode_free(node);
       +
       +        /*
       +         * Cleanup.
       +         */
       +        dht_free(dht);
       +
       +## Thread safety
       +
       +This library is not thread safe. The critical part is the list hand-
       +ling.
       +
 (DIR) diff --git a/config.mk b/config.mk
       @@ -0,0 +1,23 @@
       +# libdht metadata
       +NAME = libdht
       +VERSION = 0.2
       +
       +# Customize below to fit your system
       +
       +# paths
       +PREFIX = /usr
       +MANPREFIX = ${PREFIX}/share/man
       +
       +# includes and libs
       +INCS = -I. -I/usr/include
       +LIBS = -L/usr/lib -lc
       +
       +# flags
       +CPPFLAGS = -DVERSION=\"${VERSION}\"
       +CFLAGS = -g -fPIC -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
       +LDFLAGS = -g ${LIBS}
       +#LDFLAGS = -s ${LIBS}
       +
       +# compiler and linker
       +CC = cc
       +
 (DIR) diff --git a/dht.c b/dht.c
       @@ -0,0 +1,260 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#include <unistd.h>
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <string.h>
       +#include <strings.h>
       +#include <time.h>
       +
       +#include "dht.h"
       +#include "ind.h"
       +
       +dhtnode_t *
       +dhtnode_mkid(dhtnode_t *node)
       +{
       +        srand((unsigned int)time(NULL)*rand());
       +
       +        for (int i = 0; i < sizeof(node->id); i++)
       +                node->id[i] = rand() & 0xFF;
       +
       +        return node;
       +}
       +
       +dhtnode_t *
       +dhtnode_setid(dhtnode_t *node, char id[IDLENGTH])
       +{
       +        memmove(node->id, id, sizeof(node->id));
       +
       +        return node;
       +}
       +
       +dhtnode_t *
       +dhtnode_setaddr(dhtnode_t *node, char *addr)
       +{
       +        node->addr = memdup(addr, strlen(addr)+1);
       +
       +        return node;
       +}
       +
       +dhtnode_t *
       +dhtnode_new(void)
       +{
       +        dhtnode_t *node;
       +
       +        node = mallocz(sizeof(dhtnode_t), 2);
       +
       +        return node;
       +}
       +
       +void
       +dhtnode_free(dhtnode_t *node)
       +{
       +        free(node);
       +}
       +
       +void
       +dhtnode_print(dhtnode_t *node)
       +{
       +        printf("dhtnode[id=");
       +        for (int i = 0; i < sizeof(node->id); i++)
       +                printf("%.2x", node->id[i] & 0xFF);
       +        printf(", addr='");
       +        if (node->addr != NULL)
       +                printf("%s", node->addr);
       +        printf("']\n");
       +}
       +
       +int
       +dhtnode_cmp(dhtnode_t *node1, dhtnode_t *node2)
       +{
       +        return memcmp(node1->id, node2->id, sizeof(node1->id));
       +}
       +
       +dhtnode_t *
       +dhtnode_xor(dhtnode_t *node1, dhtnode_t *node2)
       +{
       +        dhtnode_t *ret;
       +
       +        ret = dhtnode_new();
       +        for (int i = 0; i < sizeof(ret->id); i++)
       +                ret->id[i] = node1->id[i] ^ node2->id[i];
       +
       +        return ret;
       +}
       +
       +int
       +dhtnode_prefixlen(dhtnode_t *node)
       +{
       +        for (int i = 0; i < sizeof(node->id); i++)
       +                for (int j = 0; j < 8; j++)
       +                        if ((node->id[i] >> (7-j)) & 0x1)
       +                                return i * 8 + j;
       +        return sizeof(node->id) * 8 - 1;
       +}
       +
       +dhtrouting_t *
       +dhtrouting_new(dhtnode_t *node)
       +{
       +        dhtrouting_t *route;
       +
       +        route = mallocz(sizeof(dhtrouting_t), 2);
       +        for (int i = 0; i < nelem(route->buckets); i++)
       +                route->buckets[i] = dhtlist_new();
       +        route->node = node;
       +
       +        return route;
       +}
       +
       +void
       +dhtrouting_free(dhtrouting_t *route)
       +{
       +
       +        for (int i = 0; i < nelem(route->buckets); i++)
       +                dhtlist_free(route->buckets[i]);
       +        dhtnode_free(route->node);
       +        free(route);
       +}
       +
       +dhtrouting_t *
       +dhtrouting_update(dhtrouting_t *route, dhtnode_t *node)
       +{
       +        dhtlist_t *bucket;
       +        dhtlistelem_t *elem;
       +        dhtnode_t *xornode;
       +        int bucketnum;
       +
       +        xornode = dhtnode_xor(route->node, node);
       +        bucketnum = dhtnode_prefixlen(xornode);
       +        dhtnode_free(xornode);
       +        bucket = route->buckets[bucketnum];
       +
       +        forodhtlist(bucket, elem)
       +                if (!dhtnode_cmp(elem->node, node))
       +                        break;
       +        if (elem == NULL) {
       +                if (bucket->len < IDLENGTH)
       +                        dhtlist_push(bucket, node);
       +                else
       +                        return NULL;
       +        } else
       +                dhtlist_move(bucket, elem, 0);
       +
       +        return route;
       +}
       +
       +dhtlist_t *
       +dhtrouting_sortnodes(dhtlist_t *dhtlist, dhtnode_t *target)
       +{
       +        dhtnode_t *xornode1, *xornode2, *swap;
       +        int sorted;
       +
       +        sorted = 0;
       +
       +        while(!sorted) {
       +                sorted = 1;
       +                fordhtlist(dhtlist, elem) {
       +                        if (elem->next == NULL)
       +                                break;
       +                        xornode1 = dhtnode_xor(elem->node, target);
       +                        xornode2 = dhtnode_xor(elem->next->node, target);
       +
       +                        if (dhtnode_cmp(xornode1, xornode2) > 0) {
       +                                swap = elem->next->node;
       +                                elem->next->node = elem->node;
       +                                elem->node = swap;
       +                                sorted = 0;
       +                        }
       +                        dhtnode_free(xornode1);
       +                        dhtnode_free(xornode2);
       +                }
       +        }
       +
       +        return dhtlist;
       +}
       +
       +dhtlist_t *
       +dhtrouting_addnodes(dhtlist_t *dhtlist, dhtlist_t *bucket, dhtnode_t *target,
       +                int max)
       +{
       +        fordhtlist(bucket, elem) {
       +                if (dhtlist->len >= max)
       +                        break;
       +                dhtlist_add(dhtlist, elem->node);
       +        }
       +
       +        return dhtrouting_sortnodes(dhtlist, target);
       +}
       +
       +dhtlist_t *
       +dhtrouting_findclosest(dhtrouting_t *route, dhtnode_t *target, int max)
       +{
       +        int bucketnum;
       +        dhtnode_t *xornode;
       +        dhtlist_t *retnodes;
       +
       +        retnodes = dhtlist_new();
       +
       +        xornode = dhtnode_xor(route->node, target);
       +        bucketnum = dhtnode_prefixlen(xornode);
       +        dhtnode_free(xornode);
       +
       +        dhtrouting_addnodes(retnodes, route->buckets[bucketnum], target, max);
       +        for (int i = 1; ((bucketnum-i) >= 0
       +                                || (bucketnum+i) < IDLENGTH * 8)
       +                        && retnodes->len < max; i++) {
       +                if (bucketnum-i >= 0) {
       +                        dhtrouting_addnodes(retnodes,
       +                                        route->buckets[bucketnum-i],
       +                                        target, max);
       +                }
       +                if (bucketnum+i < IDLENGTH * 8) {
       +                        dhtrouting_addnodes(retnodes,
       +                                        route->buckets[bucketnum+i],
       +                                        target, max);
       +                }
       +        }
       +
       +        return retnodes;
       +}
       +
       +dht_t *
       +dht_new(char *localhost)
       +{
       +        dht_t *dht;
       +        dhtnode_t *node;
       +
       +        node = dhtnode_new();
       +        dhtnode_mkid(node);
       +        dhtnode_setaddr(node, localhost);
       +
       +        dht = mallocz(sizeof(dht_t), 2);
       +        dht->routing = dhtrouting_new(node);
       +
       +        return dht;
       +}
       +
       +void
       +dht_free(dht_t *dht)
       +{
       +        dhtrouting_free(dht->routing);
       +        free(dht);
       +}
       +
       +dhtlist_t *
       +dht_find(dht_t *dht, dhtnode_t *target, int max)
       +{
       +        return dhtrouting_findclosest(dht->routing, target, max);
       +}
       +
       +dht_t *
       +dht_update(dht_t *dht, dhtnode_t *node)
       +{
       +        dhtrouting_update(dht->routing, node);
       +
       +        return dht;
       +}
       +
 (DIR) diff --git a/dht.h b/dht.h
       @@ -0,0 +1,118 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#ifndef __DHT_H__
       +#define __DHT_H__
       +
       +/*
       + * List functions. Most of them aren't needed, but provided.
       + */
       +
       +#define fordhtlist(list, elem) for (dhtlistelem_t *elem = (list)->first; elem;\
       +                elem = elem->next)
       +
       +#define forodhtlist(list, elem) for (elem = (list)->first; elem;\
       +                elem = elem->next)
       +
       +ttypedef struct dhtnode_t dhtnode_t;
       +
       +ttypedef struct dhtlistelem_t dhtlistelem_t;
       +struct dhtlistelem_t {
       +        dhtlistelem_t *next;
       +        dhtlistelem_t *prev;
       +
       +        dhtnode_t *node;
       +};
       +
       +ttypedef struct dhtlist_t dhtlist_t;
       +struct dhtlist_t {
       +        dhtlistelem_t *first;
       +        dhtlistelem_t *last;
       +        int len;
       +};
       +
       +dhtlistelem_t *dhtlistelem_set(dhtlistelem_t *elem, dhtnode_t *node);
       +dhtlistelem_t *dhtlistelem_new(dhtnode_t *node);
       +void dhtlistelem_free(dhtlistelem_t *elem);
       +
       +dhtlist_t *dhtlist_new(void);
       +void dhtlist_free(dhtlist_t *dhtlist);
       +dhtlistelem_t *dhtlist_addelem(dhtlist_t *dhtlist, dhtlistelem_t *elem);
       +dhtlistelem_t *dhtlist_add(dhtlist_t *dhtlist, dhtnode_t *node);
       +dhtlistelem_t *dhtlist_push(dhtlist_t *dhtlist, dhtnode_t *node);
       +void dhtlist_delelemlinks(dhtlist_t *dhtlist, dhtlistelem_t *elem);
       +void dhtlist_delelem(dhtlist_t *dhtlist, dhtlistelem_t *elem);
       +dhtlistelem_t *dhtlist_insert(dhtlist_t *dhtlist, dhtlistelem_t *elem, int idx);
       +dhtlistelem_t *dhtlist_move(dhtlist_t *dhtlist, dhtlistelem_t *elem, int idx);
       +void dhtlist_print(dhtlist_t *dhtlist);
       +
       +/*
       + * DHT functions.
       + */
       +#define IDLENGTH 20
       +
       +struct dhtnode_t {
       +        char id[IDLENGTH];
       +        char *addr;
       +};
       +
       +ttypedef struct dhtrouting_t dhtrouting_t;
       +struct dhtrouting_t {
       +        dhtnode_t *node;
       +        dhtlist_t *buckets[IDLENGTH * 8];
       +};
       +
       +ttypedef struct dht_t dht_t;
       +struct dht_t {
       +        dhtrouting_t *routing;
       +};
       +
       +/*
       + * These functions are used for handling the dhtnodes, which is simply
       + * the ID of the specific host.
       + */
       +dhtnode_t *dhtnode_mkid(dhtnode_t *node);
       +dhtnode_t *dhtnode_setid(dhtnode_t *node, char id[IDLENGTH]);
       +dhtnode_t *dhtnode_setaddr(dhtnode_t *node, char *addr);
       +dhtnode_t *dhtnode_new(void);
       +void dhtnode_free(dhtnode_t *node);
       +
       +/*
       + * These are internal functions for the dhtnode.
       + */
       +void dhtnode_print(dhtnode_t *node);
       +int dhtnode_cmp(dhtnode_t *node1, dhtnode_t *node2);
       +dhtnode_t *dhtnode_xor(dhtnode_t *node1, dhtnode_t *node2);
       +int dhtnode_prefixlen(dhtnode_t *node);
       +
       +/*
       + * These are internal routing functions.
       + */
       +dhtrouting_t *dhtrouting_new(dhtnode_t *node);
       +void dhtrouting_free(dhtrouting_t *route);
       +dhtrouting_t *dhtrouting_update(dhtrouting_t *route, dhtnode_t *node);
       +dhtlist_t *dhtrouting_findclosest(dhtrouting_t *route, dhtnode_t *target,
       +                int max);
       +
       +/*
       + * These are the high-level functions for dht handling.
       + */
       +
       +dht_t *dht_new(char *network); /* network is a unique identifier */
       +void dht_free(dht_t *dht);
       +
       +/*
       + * This function will get you a dhtlist with a maximum of max elements,
       + * which are the closest nodes to your position.
       + */
       +dhtlist_t *dht_find(dht_t *dht, dhtnode_t *target, int max);
       +
       +/*
       + * When a new node appears, add it to your internal routing buckets.
       + */
       +dht_t *dht_update(dht_t *dht, dhtnode_t *node);
       +
       +#endif
       +
 (DIR) diff --git a/dhtlist.c b/dhtlist.c
       @@ -0,0 +1,166 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#define _GNU_SOURCE
       +#include <unistd.h>
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <string.h>
       +#include <sys/types.h>
       +#include <regex.h>
       +
       +#include "ind.h"
       +#include "dht.h"
       +
       +dhtlistelem_t *
       +dhtlistelem_set(dhtlistelem_t *elem, dhtnode_t *node)
       +{
       +        elem->node = node;
       +
       +        return elem;
       +}
       +
       +dhtlistelem_t *
       +dhtlistelem_new(dhtnode_t *node)
       +{
       +        return dhtlistelem_set(mallocz(sizeof(dhtlistelem_t), 2), node);
       +}
       +
       +void
       +dhtlistelem_free(dhtlistelem_t *elem)
       +{
       +        free(elem);
       +}
       +
       +dhtlist_t *
       +dhtlist_new(void)
       +{
       +        return (dhtlist_t *)mallocz(sizeof(dhtlist_t), 2);
       +}
       +
       +void
       +dhtlist_free(dhtlist_t *node)
       +{
       +        dhtlistelem_t *elem;
       +
       +        if (node->first != NULL) {
       +                for (elem = node->first;;) {
       +                        if (elem->next != NULL) {
       +                                elem = elem->next;
       +                                free(elem->prev);
       +                        } else {
       +                                free(elem);
       +                                break;
       +                        }
       +                }
       +        }
       +        free(node);
       +}
       +
       +dhtlistelem_t *
       +dhtlist_addelem(dhtlist_t *dhtlist, dhtlistelem_t *elem)
       +{
       +        if (dhtlist->first == NULL)
       +                dhtlist->first = elem;
       +        if (dhtlist->last == NULL)
       +                dhtlist->last = elem;
       +        else {
       +                dhtlist->last->next = elem;
       +                elem->prev = dhtlist->last;
       +                dhtlist->last = elem;
       +        }
       +        dhtlist->len++;
       +
       +        return elem;
       +}
       +
       +dhtlistelem_t *
       +dhtlist_add(dhtlist_t *dhtlist, dhtnode_t *node)
       +{
       +        return dhtlist_addelem(dhtlist, dhtlistelem_new(node));
       +}
       +
       +dhtlistelem_t *
       +dhtlist_push(dhtlist_t *dhtlist, dhtnode_t *node)
       +{
       +        dhtlistelem_t *elem;
       +
       +        elem = dhtlistelem_new(node);
       +
       +        if (dhtlist->first == NULL)
       +                dhtlist->first = elem;
       +        else {
       +                dhtlist->first->prev = elem;
       +                elem->next = dhtlist->first;
       +                dhtlist->first = elem;
       +        }
       +        if (dhtlist->last == NULL)
       +                dhtlist->last = elem;
       +        dhtlist->len++;
       +
       +        return elem;
       +}
       +
       +void
       +dhtlist_delelemlinks(dhtlist_t *dhtlist, dhtlistelem_t *elem)
       +{
       +        dhtlistelem_t *prev, *next;
       +
       +        prev = elem->prev;
       +        next = elem->next;
       +
       +        if (prev != NULL)
       +                prev->next = next;
       +        if (next != NULL)
       +                next->prev = prev;
       +        if (dhtlist->first == elem)
       +                dhtlist->first = next;
       +        if (dhtlist->last == elem)
       +                dhtlist->last = prev;
       +        dhtlist->len--;
       +}
       +
       +dhtlistelem_t *
       +dhtlist_insert(dhtlist_t *dhtlist, dhtlistelem_t *elem, int idx)
       +{
       +        int i;
       +        dhtlistelem_t *next;
       +
       +        i = 0;
       +
       +        if (idx > dhtlist->len-1)
       +                return NULL;
       +        if (idx == dhtlist->len-1)
       +                return dhtlist_addelem(dhtlist, elem);
       +
       +        forodhtlist(dhtlist, next)
       +                if (i == idx)
       +                        break;
       +
       +        if (next->prev != NULL)
       +                next->prev->next = elem;
       +        elem->prev = next->prev;
       +        next->prev = elem;
       +        elem->next = next;
       +        dhtlist->len++;
       +
       +        return elem;
       +}
       +
       +dhtlistelem_t *
       +dhtlist_move(dhtlist_t *dhtlist, dhtlistelem_t *elem, int idx)
       +{
       +        dhtlist_delelemlinks(dhtlist, elem);
       +        return dhtlist_insert(dhtlist, elem, idx);
       +}
       +
       +void
       +dhtlist_print(dhtlist_t *dhtlist)
       +{
       +        fordhtlist(dhtlist, elem)
       +                printf("%p\n", (void *)elem);
       +        fflush(stdout);
       +}
       +
 (DIR) diff --git a/dhttest.c b/dhttest.c
       @@ -0,0 +1,113 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#include <unistd.h>
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <strings.h>
       +
       +#include "dht.h"
       +
       +int
       +main(void)
       +{
       +        dht_t *dht;
       +        dhtnode_t *node, *node78;
       +        char nodename[17];
       +        dhtlist_t *results;
       +
       +        bzero(nodename, sizeof(nodename));
       +        dht = dht_new("testnetwork");
       +
       +        for (int i = 0; i < 4096; i++) {
       +                node = dhtnode_new();
       +                dhtnode_mkid(node);
       +                snprintf(nodename, sizeof(nodename)-1, "node%d", i);
       +                dhtnode_setaddr(node, nodename);
       +
       +                if(dht_update(dht, node) == NULL) {
       +                        dhtnode_free(node);
       +                        break;
       +                }
       +
       +                if (i == 78)
       +                        node78 = node;
       +        }
       +        printf("4096 nodes created.\n");
       +
       +        printf("node78:\n");
       +        dhtnode_print(node78);
       +        printf("nearby node78 is:\n");
       +        results = dht_find(dht, node78, 5);
       +        fordhtlist(results, elem)
       +                dhtnode_print(elem->node);
       +        dhtlist_free(results);
       +
       +        node = dhtnode_new();
       +        dhtnode_mkid(node);
       +        printf("noderand:\n");
       +        dhtnode_print(node);
       +        printf("nearby noderand is:\n");
       +        results = dht_find(dht, node, 10);
       +        fordhtlist(results, elem)
       +                dhtnode_print(elem->node);
       +        dhtlist_free(results);
       +        dhtnode_free(node);
       +
       +        dht_free(dht);
       +
       +        dht = dht_new("localhost");
       +        dhtnode_setid(dht->routing->node, "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00"
       +                        "\x00\x00\x00\x00\x00\x00\00\x00\x00\x00\x00");
       +
       +        node = dhtnode_new();
       +        dhtnode_setid(node, "\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00"
       +                        "\x00\x00\x00\x00\x00\x00\00\x00\x00\x00\x00");
       +        dhtnode_setaddr(node, "node1");
       +        dht_update(dht, node);
       +
       +        node = dhtnode_new();
       +        dhtnode_setid(node, "\x11\x11\x11\x11\x00\x00\x00\x00\x00"
       +                        "\x00\x00\x00\x00\x00\x00\00\x00\x00\x00\x00");
       +        dhtnode_setaddr(node, "node2");
       +        dht_update(dht, node);
       +
       +        node = dhtnode_new();
       +        dhtnode_setid(node, "\x22\x22\x22\x22\x00\x00\x00\x00\x00"
       +                        "\x00\x00\x00\x00\x00\x00\00\x00\x00\x00\x00");
       +        dhtnode_setaddr(node, "nodesearch");
       +        printf("searching for one nearby node\n");
       +        results = dht_find(dht, node, 1);
       +        fordhtlist(results, elem)
       +                dhtnode_print(elem->node);
       +        dhtlist_free(results);
       +        dhtnode_free(node);
       +
       +        node = dhtnode_new();
       +        dhtnode_setid(node, "\xFF\xFF\xFF\xF0\x00\x00\x00\x00\x00"
       +                        "\x00\x00\x00\x00\x00\x00\00\x00\x00\x00\x00");
       +        dhtnode_setaddr(node, "nodesearch2");
       +        printf("searching for 10 nearby nodes\n");
       +        results = dht_find(dht, node, 10);
       +        fordhtlist(results, elem)
       +                dhtnode_print(elem->node);
       +        dhtlist_free(results);
       +        dhtnode_free(node);
       +
       +        node = dhtnode_new();
       +        dhtnode_setid(node, "\x11\x11\x11\x11\x00\x00\x00\x00\x00"
       +                        "\x00\x00\x00\x00\x00\x00\00\x00\x00\x00\x00");
       +        dhtnode_setaddr(node, "nodesearch3");
       +        printf("searching for one nearby nodes\n");
       +        results = dht_find(dht, node, 1);
       +        fordhtlist(results, elem)
       +                dhtnode_print(elem->node);
       +        dhtlist_free(results);
       +        dhtnode_free(node);
       +        dht_free(dht);
       +
       +        return 0;
       +}
       +
 (DIR) diff --git a/ind.c b/ind.c
       @@ -0,0 +1,99 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#include <unistd.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <stdarg.h>
       +#include <fcntl.h>
       +#include <string.h>
       +#include <ctype.h>
       +#include <errno.h>
       +
       +#include "ind.h"
       +
       +void
       +die(char *fmt, ...)
       +{
       +        va_list fmtargs;
       +
       +        va_start(fmtargs, fmt);
       +        vfprintf(stderr, fmt, fmtargs);
       +        va_end(fmtargs);
       +
       +        exit(EXIT_FAILURE);
       +}
       +
       +void
       +edie(char *fmt, ...)
       +{
       +        va_list fmtargs;
       +
       +        va_start(fmtargs, fmt);
       +        vfprintf(stderr, fmt, fmtargs);
       +        va_end(fmtargs);
       +
       +        perror(NULL);
       +
       +        exit(EXIT_FAILURE);
       +}
       +
       +void *
       +reallocz(void *p, int l, int z)
       +{
       +        p = realloc(p, l);
       +        if(p == NULL)
       +                edie("realloc");
       +        if(z > 0)
       +                memset(p, 0, l);
       +
       +        return p;
       +}
       +
       +void *
       +mallocz(int l, int z)
       +{
       +        return reallocz(NULL, l, z);
       +}
       +
       +void *
       +memdup(void *p, int l)
       +{
       +        char *ret;
       +
       +        ret = reallocz(NULL, l, 2);
       +        memmove(ret, p, l);
       +
       +        return (void *)ret;
       +}
       +
       +char *
       +vsmprintf(char *fmt, va_list fmtargs)
       +{
       +        char *ret;
       +        int size;
       +
       +        ret = "";
       +
       +        size = vsnprintf(ret, 0, fmt, fmtargs);
       +        ret = reallocz(NULL, ++size, 2);
       +        vsnprintf(ret, size, fmt, fmtargs);
       +
       +        return ret;
       +}
       +
       +char *
       +smprintf(char *fmt, ...)
       +{
       +        va_list fmtargs;
       +        char *ret;
       +
       +        va_start(fmtargs, fmt);
       +        ret = vsmprintf(fmt, fmtargs);
       +        va_end(fmtargs);
       +
       +        return ret;
       +}
       +
 (DIR) diff --git a/ind.h b/ind.h
       @@ -0,0 +1,22 @@
       +/*
       + * Copy me if you can.
       + * by 20h
       + */
       +
       +#ifndef __IND_H__
       +#define __IND_H__
       +
       +#define nelem(x) (sizeof(x) / sizeof((x)[0]))
       +
       +#include <stdarg.h>
       +
       +void die(char *fmt, ...);
       +void edie(char *fmt, ...);
       +void *reallocz(void *p, int l, int z);
       +void *mallocz(int l, int z);
       +void *memdup(void *p, int l);
       +char *vsmprintf(char *fmt, va_list fmtargs);
       +char *smprintf(char *fmt, ...);
       +
       +#endif
       +