diff --git a/libs/libks/Makefile.am b/libs/libks/Makefile.am index 897236bd1c..353b444386 100644 --- a/libs/libks/Makefile.am +++ b/libs/libks/Makefile.am @@ -13,6 +13,7 @@ libks_la_SOURCES += src/ks_time.c src/ks_printf.c src/ks_hash.c src/ks_q.c src/k libks_la_SOURCES += src/ks_ssl.c src/kws.c src/ks_rng.c libks_la_SOURCES += src/utp/utp_api.cpp src/utp/utp_callbacks.cpp src/utp/utp_hash.cpp src/utp/utp_internal.cpp libks_la_SOURCES += src/utp/utp_packedsockaddr.cpp src/utp/utp_utils.cpp src/ks_bencode.c +libks_la_SOURCES += src/dht/ks_dht.c src/dht/ks_dht_endpoint.c src/dht/ks_dht_nodeid.c libks_la_SOURCES += crypt/aeskey.c crypt/aestab.c crypt/sha2.c crypt/twofish.c crypt/aes_modes.c crypt/aescrypt.c crypt/twofish_cfb.c #aes.h aescpp.h brg_endian.h aesopt.h aestab.h brg_types.h sha2.h twofish.h @@ -28,6 +29,7 @@ library_include_HEADERS += src/include/ks_dso.h src/include/ks_dht.h src/include library_include_HEADERS += src/include/ks_printf.h src/include/ks_hash.h src/include/ks_ssl.h src/include/kws.h library_include_HEADERS += src/utp/utp_internal.h src/utp/utp.h src/utp/utp_types.h src/utp/utp_callbacks.h src/utp/utp_templates.h library_include_HEADERS += src/utp/utp_hash.h src/utp/utp_packedsockaddr.h src/utp/utp_utils.h src/include/ks_utp.h +library_include_HEADERS += src/dht/ks_dht.h src/dht/ks_dht-int.h src/dht/ks_dht_endpoint.h src/dht/ks_dht_endpoint-int.h src/dht/ks_dht_nodeid.h tests: libks.la $(MAKE) -C test tests diff --git a/libs/libks/src/dht/ks_dht-int.h b/libs/libks/src/dht/ks_dht-int.h new file mode 100644 index 0000000000..f878faaabf --- /dev/null +++ b/libs/libks/src/dht/ks_dht-int.h @@ -0,0 +1,25 @@ +#ifndef KS_DHT_INT_H +#define KS_DHT_INT_H + +#include "ks.h" + +KS_BEGIN_EXTERN_C + + +KS_DECLARE(ks_status_t) ks_dht2_idle(ks_dht2_t *dht); +KS_DECLARE(ks_status_t) ks_dht2_process(ks_dht2_t *dht, ks_sockaddr_t *raddr); + +KS_END_EXTERN_C + +#endif /* KS_DHT_INT_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: + */ diff --git a/libs/libks/src/dht/ks_dht.c b/libs/libks/src/dht/ks_dht.c new file mode 100644 index 0000000000..7a25d78b4b --- /dev/null +++ b/libs/libks/src/dht/ks_dht.c @@ -0,0 +1,220 @@ +#include "ks_dht.h" +#include "ks_dht-int.h" +#include "ks_dht_endpoint-int.h" +#include "sodium.h" + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_alloc(ks_dht2_t **dht, ks_pool_t *pool) +{ + ks_bool_t pool_alloc = !pool; + ks_dht2_t *d; + + ks_assert(dht); + + if (pool_alloc) ks_pool_open(&pool); + *dht = d = ks_pool_alloc(pool, sizeof(ks_dht2_t)); + + d->pool = pool; + d->pool_alloc = pool_alloc; + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_free(ks_dht2_t *dht) +{ + ks_pool_t *pool = dht->pool; + ks_bool_t pool_alloc = dht->pool_alloc; + + ks_pool_free(pool, dht); + if (pool_alloc) { + ks_pool_close(&pool); + } + + return KS_STATUS_SUCCESS; +} + + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_init(ks_dht2_t *dht, const uint8_t *nodeid) +{ + ks_assert(dht); + + if (ks_dht2_nodeid_init(&dht->nodeid, nodeid) != KS_STATUS_SUCCESS) { + return KS_STATUS_FAIL; + } + + dht->bind_ipv4 = KS_FALSE; + dht->bind_ipv6 = KS_FALSE; + + dht->endpoints = NULL; + dht->endpoints_size = 0; + ks_hash_create(&dht->endpoints_hash, KS_HASH_MODE_DEFAULT, KS_HASH_FLAG_RWLOCK, dht->pool); + dht->endpoints_poll = NULL; + + dht->recv_buffer_length = 0; + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_deinit(ks_dht2_t *dht) +{ + ks_assert(dht); + + dht->recv_buffer_length = 0; + // @todo dht->endpoints_poll deinit + // @todo dht->endpoints deinit + ks_hash_destroy(&dht->endpoints_hash); + dht->bind_ipv4 = KS_FALSE; + dht->bind_ipv6 = KS_FALSE; + ks_dht2_nodeid_deinit(&dht->nodeid); + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_bind(ks_dht2_t *dht, const ks_sockaddr_t *addr) +{ + ks_dht2_endpoint_t *ep; + ks_socket_t sock; + int32_t epindex; + + ks_assert(dht); + ks_assert(addr); + ks_assert(addr->family == AF_INET || addr->family == AF_INET6); + ks_assert(addr->port); + + //if (!addr->port) { + // addr->port = KS_DHT_DEFAULT_PORT; + //} + + dht->bind_ipv4 |= addr->family == AF_INET; + dht->bind_ipv6 |= addr->family == AF_INET6; + + // @todo start of ks_dht2_endpoint_bind + if ((sock = socket(addr->family, SOCK_DGRAM, IPPROTO_UDP)) == KS_SOCK_INVALID) { + return KS_STATUS_FAIL; + } + + // @todo shouldn't ks_addr_bind take a const addr *? + if (ks_addr_bind(sock, (ks_sockaddr_t *)addr) != KS_STATUS_SUCCESS) { + ks_socket_close(&sock); + return KS_STATUS_FAIL; + } + + if (ks_dht2_endpoint_alloc(&ep, dht->pool) != KS_STATUS_SUCCESS) { + ks_socket_close(&sock); + return KS_STATUS_FAIL; + } + + if (ks_dht2_endpoint_init(ep, addr, sock) != KS_STATUS_SUCCESS) { + ks_dht2_endpoint_free(ep); + ks_socket_close(&sock); + return KS_STATUS_FAIL; + } + + ks_socket_option(ep->sock, SO_REUSEADDR, KS_TRUE); + ks_socket_option(ep->sock, KS_SO_NONBLOCK, KS_TRUE); + + // @todo end of ks_dht2_endpoint_bind + + epindex = dht->endpoints_size++; + dht->endpoints = (ks_dht2_endpoint_t **)ks_pool_resize(dht->pool, + (void *)dht->endpoints, + sizeof(ks_dht2_endpoint_t *) * dht->endpoints_size); + dht->endpoints[epindex] = ep; + ks_hash_insert(dht->endpoints_hash, ep->addr.host, ep); + + dht->endpoints_poll = (struct pollfd *)ks_pool_resize(dht->pool, + (void *)dht->endpoints_poll, + sizeof(struct pollfd) * dht->endpoints_size); + dht->endpoints_poll[epindex].fd = ep->sock; + dht->endpoints_poll[epindex].events = POLLIN | POLLERR; + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_pulse(ks_dht2_t *dht, int32_t timeout) +{ + int32_t result; + + ks_assert(dht); + ks_assert (timeout >= 0); + + // @todo why was old DHT code checking for poll descriptor resizing here? + + if (timeout == 0) { + // @todo deal with default timeout, should return quickly but not hog the CPU polling + } + + result = ks_poll(dht->endpoints_poll, dht->endpoints_size, timeout); + if (result < 0) { + return KS_STATUS_FAIL; + } + + if (result == 0) { + ks_dht2_idle(dht); + return KS_STATUS_TIMEOUT; + } + + for (int32_t i = 0; i < dht->endpoints_size; ++i) { + if (dht->endpoints_poll[i].revents & POLLIN) { + ks_sockaddr_t raddr = KS_SA_INIT; + dht->recv_buffer_length = KS_DHT_RECV_BUFFER_SIZE; + + raddr.family = dht->endpoints[i]->addr.family; + if (ks_socket_recvfrom(dht->endpoints_poll[i].fd, dht->recv_buffer, &dht->recv_buffer_length, &raddr) == KS_STATUS_SUCCESS) { + ks_dht2_process(dht, &raddr); + } + } + } + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_idle(ks_dht2_t *dht) +{ + ks_assert(dht); + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_process(ks_dht2_t *dht, ks_sockaddr_t *raddr) +{ + ks_assert(dht); + ks_assert(raddr); + + return KS_STATUS_SUCCESS; +} + + +/* 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: + */ diff --git a/libs/libks/src/dht/ks_dht.h b/libs/libks/src/dht/ks_dht.h new file mode 100644 index 0000000000..63c2852ba3 --- /dev/null +++ b/libs/libks/src/dht/ks_dht.h @@ -0,0 +1,61 @@ +#ifndef KS_DHT_H +#define KS_DHT_H + +#include "ks.h" +#include "ks_bencode.h" + +#include "ks_dht_endpoint.h" +#include "ks_dht_nodeid.h" + +KS_BEGIN_EXTERN_C + + +#define KS_DHT_DEFAULT_PORT 5309 +#define KS_DHT_RECV_BUFFER_SIZE 0xFFFF + + +typedef struct ks_dht2_s ks_dht2_t; +struct ks_dht2_s { + ks_pool_t *pool; + ks_bool_t pool_alloc; + + ks_dht2_nodeid_t nodeid; + + ks_bool_t bind_ipv4; + ks_bool_t bind_ipv6; + + ks_dht2_endpoint_t **endpoints; + int32_t endpoints_size; + ks_hash_t *endpoints_hash; + struct pollfd *endpoints_poll; + + uint8_t recv_buffer[KS_DHT_RECV_BUFFER_SIZE]; + ks_size_t recv_buffer_length; +}; + + +KS_DECLARE(ks_status_t) ks_dht2_alloc(ks_dht2_t **dht, ks_pool_t *pool); +KS_DECLARE(ks_status_t) ks_dht2_free(ks_dht2_t *dht); + + +KS_DECLARE(ks_status_t) ks_dht2_init(ks_dht2_t *dht, const uint8_t *nodeid); +KS_DECLARE(ks_status_t) ks_dht2_deinit(ks_dht2_t *dht); + + +KS_DECLARE(ks_status_t) ks_dht2_bind(ks_dht2_t *dht, const ks_sockaddr_t *addr); +KS_DECLARE(ks_status_t) ks_dht2_pulse(ks_dht2_t *dht, int32_t timeout); + +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: + */ diff --git a/libs/libks/src/dht/ks_dht_endpoint-int.h b/libs/libks/src/dht/ks_dht_endpoint-int.h new file mode 100644 index 0000000000..c8361aca0b --- /dev/null +++ b/libs/libks/src/dht/ks_dht_endpoint-int.h @@ -0,0 +1,28 @@ +#ifndef KS_DHT_ENDPOINT_INT_H +#define KS_DHT_ENDPOINT_INT_H + +#include "ks.h" + +KS_BEGIN_EXTERN_C + +KS_DECLARE(ks_status_t) ks_dht2_endpoint_alloc(ks_dht2_endpoint_t **endpoint, ks_pool_t *pool); +KS_DECLARE(ks_status_t) ks_dht2_endpoint_free(ks_dht2_endpoint_t *endpoint); + +KS_DECLARE(ks_status_t) ks_dht2_endpoint_init(ks_dht2_endpoint_t *endpoint, const ks_sockaddr_t *addr, ks_socket_t sock); +KS_DECLARE(ks_status_t) ks_dht2_endpoint_deinit(ks_dht2_endpoint_t *endpoint); + +KS_END_EXTERN_C + +#endif /* KS_DHT_ENDPOINT_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: +*/ diff --git a/libs/libks/src/dht/ks_dht_endpoint.c b/libs/libks/src/dht/ks_dht_endpoint.c new file mode 100644 index 0000000000..2818a7c98f --- /dev/null +++ b/libs/libks/src/dht/ks_dht_endpoint.c @@ -0,0 +1,68 @@ +#include "ks_dht_endpoint.h" +#include "ks_dht_endpoint-int.h" + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_endpoint_alloc(ks_dht2_endpoint_t **endpoint, ks_pool_t *pool) +{ + ks_dht2_endpoint_t *ep; + + ks_assert(endpoint); + ks_assert(pool); + + *endpoint = ep = ks_pool_alloc(pool, sizeof(ks_dht2_endpoint_t)); + ep->pool = pool; + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_endpoint_free(ks_dht2_endpoint_t *endpoint) +{ + ks_assert(endpoint); + + ks_pool_free(endpoint->pool, endpoint); + + return KS_STATUS_SUCCESS; +} + + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_endpoint_init(ks_dht2_endpoint_t *endpoint, const ks_sockaddr_t *addr, ks_socket_t sock) +{ + ks_assert(endpoint); + ks_assert(addr); + ks_assert(addr->family == AF_INET || addr->family == AF_INET6); + + endpoint->addr = *addr; + endpoint->sock = sock; + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_endpoint_deinit(ks_dht2_endpoint_t *endpoint) +{ + ks_assert(endpoint); + + return KS_STATUS_SUCCESS; +} + + +/* 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: + */ diff --git a/libs/libks/src/dht/ks_dht_endpoint.h b/libs/libks/src/dht/ks_dht_endpoint.h new file mode 100644 index 0000000000..6d9df0551d --- /dev/null +++ b/libs/libks/src/dht/ks_dht_endpoint.h @@ -0,0 +1,29 @@ +#ifndef KS_DHT_ENDPOINT_H +#define KS_DHT_ENDPOINT_H + +#include "ks.h" + +KS_BEGIN_EXTERN_C + +typedef struct ks_dht2_endpoint_s ks_dht2_endpoint_t; +struct ks_dht2_endpoint_s { + ks_pool_t *pool; + ks_sockaddr_t addr; + ks_socket_t sock; +}; + +KS_END_EXTERN_C + +#endif /* KS_DHT_ENDPOINT_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: +*/ diff --git a/libs/libks/src/dht/ks_dht_nodeid.c b/libs/libks/src/dht/ks_dht_nodeid.c new file mode 100644 index 0000000000..752f9ac70e --- /dev/null +++ b/libs/libks/src/dht/ks_dht_nodeid.c @@ -0,0 +1,70 @@ +#include "ks_dht_nodeid.h" +#include "sodium.h" + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_nodeid_alloc(ks_dht2_nodeid_t **nodeid, ks_pool_t *pool) +{ + ks_dht2_nodeid_t *nid; + + ks_assert(nodeid); + ks_assert(pool); + + *nodeid = nid = ks_pool_alloc(pool, sizeof(ks_dht2_nodeid_t)); + nid->pool = pool; + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_nodeid_free(ks_dht2_nodeid_t *nodeid) +{ + ks_assert(nodeid); + + ks_pool_free(nodeid->pool, nodeid); + + return KS_STATUS_SUCCESS; +} + + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_nodeid_init(ks_dht2_nodeid_t *nodeid, const uint8_t *id) +{ + ks_assert(nodeid); + ks_assert(id); + + if (!id) { + randombytes_buf(nodeid->id, KS_DHT_NODEID_LENGTH); + } else { + memcpy(nodeid->id, id, KS_DHT_NODEID_LENGTH); + } + + return KS_STATUS_SUCCESS; +} + +/** + * + */ +KS_DECLARE(ks_status_t) ks_dht2_nodeid_deinit(ks_dht2_nodeid_t *nodeid) +{ + ks_assert(nodeid); + + return KS_STATUS_SUCCESS; +} + + +/* 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: + */ diff --git a/libs/libks/src/dht/ks_dht_nodeid.h b/libs/libks/src/dht/ks_dht_nodeid.h new file mode 100644 index 0000000000..5eef173b7c --- /dev/null +++ b/libs/libks/src/dht/ks_dht_nodeid.h @@ -0,0 +1,36 @@ +#ifndef KS_DHT_NODEID_H +#define KS_DHT_NODEID_H + +#include "ks.h" + +KS_BEGIN_EXTERN_C + +#define KS_DHT_NODEID_LENGTH 20 + +typedef struct ks_dht2_nodeid_s ks_dht2_nodeid_t; +struct ks_dht2_nodeid_s { + ks_pool_t *pool; + uint8_t id[KS_DHT_NODEID_LENGTH]; +}; + +KS_DECLARE(ks_status_t) ks_dht2_nodeid_alloc(ks_dht2_nodeid_t **nodeid, ks_pool_t *pool); +KS_DECLARE(ks_status_t) ks_dht2_nodeid_free(ks_dht2_nodeid_t *nodeid); + +KS_DECLARE(ks_status_t) ks_dht2_nodeid_init(ks_dht2_nodeid_t *nodeid, const uint8_t *id); +KS_DECLARE(ks_status_t) ks_dht2_nodeid_deinit(ks_dht2_nodeid_t *nodeid); + +KS_END_EXTERN_C + +#endif /* KS_DHT_NODEID_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: + */ +