From d1c4602f80e395d1d6ab0453b8f0a6cc10aefadf Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 16 Jul 2024 01:51:04 +0000 Subject: Refactor dcache, add prep for shibari-cache Signed-off-by: Laurent Bercot --- src/cache/cache.c | 6 + src/cache/conf.c | 36 +++++ src/cache/dcache-internal.h | 18 --- src/cache/dcache_add.c | 85 ---------- src/cache/dcache_clean_expired.c | 20 --- src/cache/dcache_delete.c | 19 --- src/cache/dcache_free.c | 22 --- src/cache/dcache_init.c | 55 ------- src/cache/dcache_load.c | 81 ---------- src/cache/dcache_save.c | 73 --------- src/cache/dcache_search.c | 15 -- src/cache/deps-exe/shibari-cache | 8 + src/cache/deps-lib/dcache | 8 - src/cache/shibari-cache-internal.h | 97 ++++++++++++ src/cache/shibari-cache.c | 276 +++++++++++++-------------------- src/cache/tcpconnection.c | 49 ++++++ src/cache/udpqueue.c | 80 ++++++++++ src/config/defaults.c | 1 + src/config/lexparse.c | 24 +++ src/libdcache/dcache-internal.h | 18 +++ src/libdcache/dcache_add.c | 85 ++++++++++ src/libdcache/dcache_clean_expired.c | 20 +++ src/libdcache/dcache_delete.c | 19 +++ src/libdcache/dcache_free.c | 22 +++ src/libdcache/dcache_init.c | 55 +++++++ src/libdcache/dcache_load.c | 82 ++++++++++ src/libdcache/dcache_save.c | 73 +++++++++ src/libdcache/dcache_search.c | 15 ++ src/libdcache/deps-lib/dcache | 8 + src/server/deps-exe/shibari-server-tcp | 1 + src/server/deps-exe/shibari-server-udp | 1 + 31 files changed, 810 insertions(+), 562 deletions(-) create mode 100644 src/cache/cache.c create mode 100644 src/cache/conf.c delete mode 100644 src/cache/dcache-internal.h delete mode 100644 src/cache/dcache_add.c delete mode 100644 src/cache/dcache_clean_expired.c delete mode 100644 src/cache/dcache_delete.c delete mode 100644 src/cache/dcache_free.c delete mode 100644 src/cache/dcache_init.c delete mode 100644 src/cache/dcache_load.c delete mode 100644 src/cache/dcache_save.c delete mode 100644 src/cache/dcache_search.c create mode 100644 src/cache/deps-exe/shibari-cache delete mode 100644 src/cache/deps-lib/dcache create mode 100644 src/cache/shibari-cache-internal.h create mode 100644 src/cache/tcpconnection.c create mode 100644 src/cache/udpqueue.c create mode 100644 src/libdcache/dcache-internal.h create mode 100644 src/libdcache/dcache_add.c create mode 100644 src/libdcache/dcache_clean_expired.c create mode 100644 src/libdcache/dcache_delete.c create mode 100644 src/libdcache/dcache_free.c create mode 100644 src/libdcache/dcache_init.c create mode 100644 src/libdcache/dcache_load.c create mode 100644 src/libdcache/dcache_save.c create mode 100644 src/libdcache/dcache_search.c create mode 100644 src/libdcache/deps-lib/dcache diff --git a/src/cache/cache.c b/src/cache/cache.c new file mode 100644 index 0000000..8c820fb --- /dev/null +++ b/src/cache/cache.c @@ -0,0 +1,6 @@ +/* ISC license. */ + +#include +#include "shibari-cache-internal.h" + +dcache_t cache = DCACHE_ZERO ; diff --git a/src/cache/conf.c b/src/cache/conf.c new file mode 100644 index 0000000..ea35646 --- /dev/null +++ b/src/cache/conf.c @@ -0,0 +1,36 @@ +/* ISC license. */ + +#include +#include + +#include +#include + +#include "shibari-cache-internal.h" + +#include + +int conf_getb (cdb const *c, char const *key, size_t keylen, cdb_data *data) +{ + if (keylen > 4096) return (errno = EINVAL, 0) ; + switch (cdb_find(c, data, key, keylen)) + { + case -1 : return (errno = EILSEQ, 0) ; + case 0 : return (errno = ENOENT, 0) ; + default : return 1 ; + } +} + +int conf_get (cdb const *c, char const *key, cdb_data *data) +{ + return conf_get(c, key, strlen(key), data) ; +} + +int conf_get_uint32 (cdb const *c, char const *key, uint32_t *value) +{ + cdb_data data ; + if (!conf_get(conf, key, &data)) return 0 ; + if (data.len != 4) return (errno = EPROTO, 0) ; + uint32_unpack_big(data.s, value) ; + return 1 ; +} diff --git a/src/cache/dcache-internal.h b/src/cache/dcache-internal.h deleted file mode 100644 index 2a2e36f..0000000 --- a/src/cache/dcache-internal.h +++ /dev/null @@ -1,18 +0,0 @@ -/* ISC license. */ - -#ifndef SHIBARI_DCACHE_INTERNAL_H -#define SHIBARI_DCACHE_INTERNAL_H - -#include - -#include -#include - -#include - -#define DNODE(z, i) GENSETDYN_P(dcache_node_t, &(z)->storage, i) -#define DCACHE_NODE_OVERHEAD (32 + sizeof(dcache_node_t) + 3 * sizeof(avlnode)) - -extern void dcache_delete (dcache_t *, uint32_t) ; - -#endif diff --git a/src/cache/dcache_add.c b/src/cache/dcache_add.c deleted file mode 100644 index 7260726..0000000 --- a/src/cache/dcache_add.c +++ /dev/null @@ -1,85 +0,0 @@ -/* ISC license. */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include "dcache-internal.h" - -static void uniquify (avltree const *tree, tain *stamp) -{ - static tain const nano = { .sec = TAI_ZERO, .nano = 1 } ; - uint32_t dummy ; - while (avltree_search(tree, stamp, &dummy)) - tain_add(stamp, stamp, &nano) ; -} - -static inline void dcache_gc_by_entry (dcache_t *z, uint64_t max) -{ - while (z->size > max) - { - uint32_t oldest ; - if (!avltree_min(&z->by_entry, &oldest)) break ; - dcache_delete(z, oldest) ; - } -} - -static inline int dcache_add_node (dcache_t *z, dcache_node_t const *node) -{ - uint32_t i ; - dcache_node_t *y ; - if (!gensetdyn_new(&z->storage, &i)) return 0 ; - y = DNODE(z, i) ; *y = *node ; - uniquify(&z->by_entry, &y->entry) ; - uniquify(&z->by_expire, &y->expire) ; - if (!avltree_insert(&z->by_key, i)) goto err1 ; - if (!avltree_insert(&z->by_entry, i)) goto err2 ; - if (!avltree_insert(&z->by_expire, i)) goto err3 ; - return 1 ; - - err3: - avltree_delete(&z->by_entry, &y->entry) ; - err2: - avltree_delete(&z->by_key, &y->key) ; - err1: - gensetdyn_delete(&z->storage, i) ; - return 0 ; -} - -static inline int dcache_add_unbounded (dcache_t *z, char const *key, uint16_t keylen, char const *data, uint16_t datalen, tain const *expire, tain const *stamp) -{ - uint32_t len = (uint32_t)keylen + (uint32_t)datalen ; - dcache_node_t y = { .key = { .s = alloc(len) } } ; - if (!y.key.s) return 0 ; - memcpy(y.key.s, key, keylen) ; - memcpy(y.key.s + keylen, data, datalen) ; - y.key.len = keylen ; - y.datalen = datalen ; - y.entry = *stamp ; - y.expire = *expire ; - if (!dcache_add_node(z, &y)) - { - alloc_free(y.key.s) ; - return 0 ; - } - z->size += DCACHE_NODE_OVERHEAD + len ; - z->motion += DCACHE_NODE_OVERHEAD + len ; - return 1 ; -} - -int dcache_add (dcache_t *z, uint64_t max, char const *key, uint16_t keylen, char const *data, uint16_t datalen, tain const *expire, tain const *stamp) -{ - uint64_t size = DCACHE_NODE_OVERHEAD + keylen + datalen ; - if (size > max) return (errno = EINVAL, 0) ; - if (z->size > max - size) dcache_clean_expired(z, stamp) ; - if (z->size > max - size) dcache_gc_by_entry(z, max - size) ; - return dcache_add_unbounded(z, key, keylen, data, datalen, expire, stamp) ; -} diff --git a/src/cache/dcache_clean_expired.c b/src/cache/dcache_clean_expired.c deleted file mode 100644 index 0e23443..0000000 --- a/src/cache/dcache_clean_expired.c +++ /dev/null @@ -1,20 +0,0 @@ -/* ISC license. */ - -#include - -#include -#include - -#include -#include "dcache-internal.h" - -void dcache_clean_expired (dcache_t *z, tain const *stamp) -{ - for (;;) - { - uint32_t i ; - if (!avltree_min(&z->by_expire, &i)) break ; - if (tain_less(stamp, &DNODE(z, i)->expire)) break ; - dcache_delete(z, i) ; - } -} diff --git a/src/cache/dcache_delete.c b/src/cache/dcache_delete.c deleted file mode 100644 index 92a5fcc..0000000 --- a/src/cache/dcache_delete.c +++ /dev/null @@ -1,19 +0,0 @@ -/* ISC license. */ - -#include -#include -#include - -#include -#include "dcache-internal.h" - -void dcache_delete (dcache_t *z, uint32_t i) -{ - dcache_node_t *y = DNODE(z, i) ; - avltree_delete(&z->by_expire, &y->expire) ; - avltree_delete(&z->by_entry, &y->entry) ; - avltree_delete(&z->by_key, &y->key) ; - alloc_free(y->key.s) ; - z->size -= DCACHE_NODE_OVERHEAD + y->key.len + y->datalen ; - gensetdyn_delete(&z->storage, i) ; -} diff --git a/src/cache/dcache_free.c b/src/cache/dcache_free.c deleted file mode 100644 index 16c074e..0000000 --- a/src/cache/dcache_free.c +++ /dev/null @@ -1,22 +0,0 @@ -/* ISC license. */ - -#include -#include -#include - -#include - -static void dcache_node_free (void *p) -{ - alloc_free(((dcache_node_t *)p)->key.s) ; -} - -void dcache_free (dcache_t *z) -{ - static dcache_t const dcache_zero = DCACHE_ZERO ; - avltree_free(&z->by_expire) ; - avltree_free(&z->by_entry) ; - avltree_free(&z->by_key) ; - gensetdyn_deepfree(&z->storage, &dcache_node_free) ; - *z = dcache_zero ; -} diff --git a/src/cache/dcache_init.c b/src/cache/dcache_init.c deleted file mode 100644 index d42ec62..0000000 --- a/src/cache/dcache_init.c +++ /dev/null @@ -1,55 +0,0 @@ -/* ISC license. */ - -#include -#include - -#include -#include -#include -#include - -#include - -static int key_cmp (void const *a, void const *b, void *x) -{ - dcache_key_t const *ka = a ; - dcache_key_t const *kb = b ; - if (ka->len < kb->len) return -1 ; - if (kb->len < ka->len) return 1 ; - (void)x ; - return memcmp(ka->s, kb->s, ka->len) ; -} - -static int tain_cmp (void const *a, void const *b, void *x) -{ - tain const *ta = a ; - tain const *tb = b ; - (void)x ; - return tain_less(ta, tb) ? -1 : tain_less(tb, ta) ; -} - -static void *key_dtok (uint32_t d, void *x) -{ - return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->key ; -} - -static void *entry_dtok (uint32_t d, void *x) -{ - return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->entry ; -} - -static void *expire_dtok (uint32_t d, void *x) -{ - return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->expire ; -} - - -void dcache_init (dcache_t *z, uint64_t max) -{ - gensetdyn_init(&z->storage, sizeof(dcache_node_t), max >> 9, 3, 8) ; - avltree_init(&z->by_key, max >> 9, 3, 8, &key_dtok, &key_cmp, &z->storage) ; - avltree_init(&z->by_entry, max >> 9, 3, 8, &entry_dtok, &tain_cmp, &z->storage) ; - avltree_init(&z->by_expire, max >> 9, 3, 8, &expire_dtok, &tain_cmp, &z->storage) ; - z->size = 0 ; - z->motion = 0 ; -} diff --git a/src/cache/dcache_load.c b/src/cache/dcache_load.c deleted file mode 100644 index a0ff233..0000000 --- a/src/cache/dcache_load.c +++ /dev/null @@ -1,81 +0,0 @@ -/* ISC license. */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -static inline int dcache_load_node (dcache_t *z, uint64_t max, buffer *b) -{ - tain entry = { .nano = 0 } ; - tain expire = { .nano = 0 } ; - uint16_t keylen ; - uint16_t datalen ; - char pack[TAI_PACK * 2 + 4] ; - ssize_t r = buffer_get(b, pack, TAI_PACK * 2 + 4) ; - if (!r) return 0 ; - if (r < TAI_PACK * 2 + 4) return -1 ; - tai_unpack(pack, tain_secp(&entry)) ; - tai_unpack(pack + TAI_PACK, tain_secp(&expire)) ; - uint16_unpack_big(pack + TAI_PACK * 2, &keylen) ; - uint16_unpack_big(pack + TAI_PACK * 2 + 2, &datalen) ; - { - uint32_t len = (uint32_t)keylen + (uint32_t)datalen ; - char blob[len+1] ; /* 128 kB max, it's ok */ - r = buffer_get(b, blob, len+1) ; - if (!r) return (errno = EPIPE, -1) ; - if (r < len) return -1 ; - if (blob[len]) return (errno = EPROTO, -1) ; - if (!dcache_add(z, max, blob, keylen, blob + keylen, datalen, &expire, &entry)) return -1 ; - } - return 1 ; -} - -static inline int dcache_load_from_buffer (dcache_t *z, uint64_t max, buffer *b) -{ - { - char banner[sizeof(DCACHE_MAGIC) - 1] ; - char pack[8] ; - if (buffer_get(b, banner, sizeof(DCACHE_MAGIC) - 1) < sizeof(DCACHE_MAGIC) - 1) - return 0 ; - if (memcmp(banner, DCACHE_MAGIC, sizeof(DCACHE_MAGIC) - 1)) return 0 ; - if (buffer_get(b, pack, 8) < 8) return 0 ; - uint64_unpack_big(pack, &z->size) ; - if (buffer_get(b, pack, 8) < 8) return 0 ; - uint64_unpack_big(pack, &z->motion) ; - } - for (;;) - { - int r = dcache_load_node(z, max, b) ; - if (r < 0) return 0 ; - if (!r) break ; - } - return 1 ; -} - -#define N 8192 - -int dcache_load (dcache_t *z, uint64_t max, char const *file) -{ - char buf[N] ; - buffer b ; - int fd = open_readb(file) ; - if (fd == -1) return 0 ; - buffer_init(&b, &buffer_read, fd, buf, N) ; - if (!dcache_load_from_buffer(z, max, &b)) goto err ; - fd_close(fd) ; - return 1 ; - - err: - dcache_free(z) ; - fd_close(fd) ; - return 0 ; -} diff --git a/src/cache/dcache_save.c b/src/cache/dcache_save.c deleted file mode 100644 index 7277771..0000000 --- a/src/cache/dcache_save.c +++ /dev/null @@ -1,73 +0,0 @@ -/* ISC license. */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static int write_node_iter (void *data, void *aux) -{ - dcache_node_t *y = data ; - buffer *b = aux ; - char pack[TAI_PACK * 2 + 4] ; - tai_pack(pack, tain_secp(&y->entry)) ; - tai_pack(pack + TAI_PACK, tain_secp(&y->expire)) ; - uint16_pack(pack + TAI_PACK * 2, y->key.len) ; - uint16_pack(pack + TAI_PACK * 2 + 2, y->datalen) ; - if (buffer_put(b, pack, TAI_PACK * 2 + 4) == -1) return 0 ; - if (buffer_put(b, y->key.s, y->key.len + y->datalen) == -1) return 0 ; - if (buffer_put(b, "", 1) == -1) return 0 ; - return 1 ; -} - -static inline int dcache_save_to_buffer (dcache_t const *z, buffer *b) -{ - char pack[16] ; - if (buffer_puts(b, DCACHE_MAGIC) == -1) return 0 ; - uint64_pack_big(pack, z->size) ; - uint64_pack_big(pack + 8, z->motion) ; - if (buffer_put(b, pack, 16) < 16) return 0 ; - - /* XXX: can gensetdyn_iter blow up the stack if z->storage is huge? */ - if (gensetdyn_iter_nocancel((gensetdyn *)&z->storage, gensetdyn_n(&z->storage), &write_node_iter, b) < gensetdyn_n(&z->storage)) return 0 ; - - return buffer_flush(b) ; -} - -#define N 8192 - -int dcache_save (dcache_t const *z, char const *file) -{ - size_t len = strlen(file) ; - int fd ; - buffer b ; - char buf[N] ; - char tmp[len + 20] ; - memcpy(tmp, file, len) ; - memcpy(tmp + len, ":dcache_save:XXXXXX", 20) ; - fd = mkstemp(tmp) ; - if (fd == -1) return 0 ; - buffer_init(&b, &buffer_write, fd, buf, N) ; - if (!dcache_save_to_buffer(z, &b) || fsync(fd) < 0) goto err2 ; - fd_close(fd) ; - if (rename(tmp, file) == -1) goto err1 ; - return 1 ; - - err2: - fd_close(fd) ; - err1: - unlink_void(tmp) ; - return 0 ; -} diff --git a/src/cache/dcache_search.c b/src/cache/dcache_search.c deleted file mode 100644 index 0239b88..0000000 --- a/src/cache/dcache_search.c +++ /dev/null @@ -1,15 +0,0 @@ -/* ISC license. */ - -#include - -#include - -#include -#include "dcache-internal.h" - -dcache_node_t *dcache_search (dcache_t *z, char const *key, uint16_t keylen) -{ - uint32_t i ; - dcache_key_t k = { .s = (char *)key, .len = keylen } ; - return avltree_search(&z->by_key, &k, &i) ? DNODE(z, i) : 0 ; -} diff --git a/src/cache/deps-exe/shibari-cache b/src/cache/deps-exe/shibari-cache new file mode 100644 index 0000000..841cf80 --- /dev/null +++ b/src/cache/deps-exe/shibari-cache @@ -0,0 +1,8 @@ +cache.o +conf.o +${LIBDCACHE} +${LIBSHIBARI_COMMON} +-ls6dns +-lskarnet +${SOCKET_LIB} +${SYSCLOCK_LIB} diff --git a/src/cache/deps-lib/dcache b/src/cache/deps-lib/dcache deleted file mode 100644 index fcc09a0..0000000 --- a/src/cache/deps-lib/dcache +++ /dev/null @@ -1,8 +0,0 @@ -dcache_add.o -dcache_clean_expired.o -dcache_delete.o -dcache_free.o -dcache_init.o -dcache_load.o -dcache_save.o -dcache_search.o diff --git a/src/cache/shibari-cache-internal.h b/src/cache/shibari-cache-internal.h new file mode 100644 index 0000000..7e03282 --- /dev/null +++ b/src/cache/shibari-cache-internal.h @@ -0,0 +1,97 @@ +/* ISC license. */ + +#ifndef SHIBARI_CACHE_INTERNAL_H +#define SHIBARI_CACHE_INTERNAL_H + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define MAXXED 1000 + + /* cache */ + +extern dcache_t cache ; + + + /* conf */ + +extern int conf_getb (cdb const *, char const *, size_t, cdb_data *) ; +extern int conf_get (cdb const *, char const *, cdb_data *) ; +extern int conf_get_uint32 (cdb const *, char const *, uint32_t *) ; + + + /* tcpconnection */ + +typedef struct tcpconnection_s tcpconnection, *tcpconnection_ref ; +struct tcpconnection_s +{ + bufalloc out ; + stralloc in ; + uint32_t instate ; +} ; +#define TCPCONNECTION_ZERO { .out = BUFALLOC_ZERO, .in = STRALLOC_ZERO, .instate = 0 } + +extern genset *tcpconn ; /* tcpconnection */ +#define ntcp (genset_n(tcpconn)) + + + /* udpqueue */ + +typedef struct udp4msg_s udp4msg, *udp4msg_ref ; +struct udp4msg_s +{ + char ip[4] ; + uint16_t port ; + uint16_t len ; +} ; +#define UDP4MSG_ZERO { .ip = { 0 }, .port = 0, .len = 0 } + +typedef struct udp6msg_s udp6msg, *udp6msg_ref ; +struct udp4msg_s +{ + char ip[16] ; + uint16_t port ; + uint16_t len ; +} ; +#define UDP6MSG_ZERO { .ip = { 0 }, .port = 0, .len = 0 } + +typedef struct udpqueue_s udpqueue, *udpqueue_ref ; +struct udpqueue_s +{ + int fd ; + stralloc storage ; + genalloc messages ; /* udp[46]msg */ +} ; +#define UDPQUEUE_ZERO { .fd = -1, .storage = STRALLOC_ZERO, .messages = GENALLOC_ZERO } + +extern int udpqueue_add4 (udpqueue *, char const *, uint16_t) ; +extern int udpqueue_flush4 (udpqueue *) ; + +#ifdef SKALIBS_IPV6_ENABLED +extern int udpqueue_add6 (udpqueue *, char const *, uint16_t) ; +extern int udpqueue_flush6 (udpqueue *) ; +#endif + + + /* main */ + +typedef struct query_s query, *query_ref ; +struct query_s +{ + s6dns_engine_t dt ; + size_t origin ; +} ; + +extern uint32_t verbosity ; +extern cdb confdb ; +extern size_t n4, n6 ; + +#endif diff --git a/src/cache/shibari-cache.c b/src/cache/shibari-cache.c index 1d88556..09743d9 100644 --- a/src/cache/shibari-cache.c +++ b/src/cache/shibari-cache.c @@ -8,136 +8,42 @@ #include #include -#include #include #include #include #include -#include #include #include -#include #include #include -#include #include #include #include #include +#include +#inclide -#include - +#include #include #include -#define USAGE "shibari-cache [ -U ] [ -v verbosity ] [ -d notif ] [ -D cachedumpfile ] [ -w wtimeout ] [ -i rulesdir | -x rulesfile ] ip[_port]..." -#define dieusage() strerr_dieusage(100, USAGE) - - -static char const *dumpfile = 0 ; - +#include "shibari-cache-internal.h" -typedef struct shibari_ip4_s shibari_ip4 ; -struct shibari_ip4_s -{ - int fd ; - char ip[4] ; -} ; +#define USAGE "shibari-cache [ -U ] [ -d notif ] [ -f conf.cdb ] [ -D cachedumpfile ] [ -w wtimeout ] [ -i rulesdir | -x rulesfile ]" +#define dieusage() strerr_dieusage(100, USAGE) -typedef struct shibari_ip6_s shibari_ip6 ; -struct shibari_ip6_s -{ - int fd ; - char ip[16] ; -} ; -static inline void argv_pass1 (char const *const *argv, unsigned int *n4, unsigned int *n6) -{ - char ip[16] ; - for (; *argv ; argv++) - if (ip6_scan(argv, ip)) -#ifdef SKALIBS_IPV6_ENABLED - n6++ ; -#else - strerr_dief1x(100, "IPv6 listening addresses unsupported on this system") ; -#endif - else n4++ ; -} +uint32_t verbosity ; +cdb confdb = CDB_ZERO ; +size_t n4 = 0, n6 = 0, ntcp = 0 ; -static inline void argv_pass2 (char const *const *argv, shibari_ip4 *ip4, shibari_ip6 *ip6, uint16_t *ports) -{ - unsigned int i4 = 0, i6 = 0 ; - char ip[16] ; - size_t len ; - for (; *argv ; argv++) - { - len = ip6_scan(argv, ip) ; - if (len) - { - if (argv[0][len] == '_') - { - uint16_t port ; - if (!uint160_scan(*argv + len + 1)) - strerr_dief - } - } - } -} +static int cont = 1 ; +static int sfd = -1 ; +static char const *dumpfile = 0 ; -static inline void reload_cdbs (void) -{ - cdb newtdb = CDB_ZERO ; - if (!cdb_init(&newtdb, tdbfile)) - { - if (verbosity) strerr_warnwu2sys("reopen DNS data file ", tdbfile) ; - } - else - { - cdb_free(&tdb) ; - tdb = newtdb ; - } - if (rulestype == 2) - { - cdb newrules = CDB_ZERO ; - if (!cdb_init(&newrules, rulesfile)) - { - if (verbosity) strerr_warnwu2sys("reopen access rules file ", rulesfile) ; - } - else - { - cdb_free(&rules) ; - rules = newrules ; - } - } -} -static int check_rules (ip46 const *remoteip, s6_accessrules_params_t *params, char const **loc) +static inline void reload (void) { - s6_accessrules_result_t r ; - params->env.len = 0 ; - params->exec.len = 0 ; - r = rulestype == 2 ? - s6_accessrules_ip46_cdb(remoteip, &rules, params) : - s6_accessrules_ip46_fs(remoteip, rulesfile, params) ; - if (r != S6_ACCESSRULES_ALLOW) return 0 ; - - if (params->env.len) - { - char const *p ; - if (params->env.s[params->env.len - 1]) - { - if (verbosity) - { - char fmt[IP46_FMT] ; - fmt[ip46_fmt(fmt, remoteip)] = 0 ; - strerr_warnw6x("invalid environment parameters in rules ", rulestype == 2 ? "cdb " : "directory ", rulesfile, " for ip ", fmt, " - denying connection") ; - } - return 0 ; - } - p = memmem(params->env.s, params->env.len - 1, VAR "=", sizeof(VAR)) ; - if (p && (p == params->env.s || !p[-1])) *loc = p + sizeof(VAR) ; - } - return 1 ; } static inline void handle_signals (void) @@ -147,16 +53,18 @@ static inline void handle_signals (void) case -1 : strerr_diefu1sys(111, "read selfpipe") ; case 0 : return ; case SIGTERM : cont = 0 ; break ; - case SIGHUP : reload_cdbs() ; break ; - case SIGALRM : dump_cache() ; break ; + case SIGHUP : reload() ; break ; + case SIGALRM : dump_cache(dumpfile) ; break ; default : break ; } } int main (int argc, char const *const *argv) { + char const *conffile = SHIBARI_SYSCONFDIR "/shibari-cache.conf.cdb" ; unsigned int notif = 0 ; - unsigned int n4 = 0, n6 = 0 ; + char const *ip4 ; + char const *ip6 ; uid_t uid = 0 ; gid_t gid = 0 ; PROG = "shibari-cache" ; @@ -165,13 +73,13 @@ int main (int argc, char const *const *argv) subgetopt l = SUBGETOPT_ZERO ; for (;;) { - int opt = subgetopt_r(argc, argv, "Uv:d:D:w:i:x:", &l) ; + int opt = subgetopt_r(argc, argv, "Ud:f:D:w:i:x:", &l) ; if (opt == -1) break ; switch (opt) { case 'U' : flagdrop = 1 ; break ; - case 'v' : if (!uint320_scan(l.arg, &verbosity)) dieusage() ; break ; case 'd' : if (!uint0_scan(l.arg, ¬if)) dieusage() ; break ; + case 'f' : conffile = l.arg ; break ; case 'D' : dumpfile = l.arg ; break ; case 'w' : if (!uint0_scan(l.arg, &wtimeout)) dieusage() ; break ; case 'i' : rulesfile = l.arg ; rulestype = 1 ; break ; @@ -180,8 +88,6 @@ int main (int argc, char const *const *argv) } } argc -= l.ind ; argv += l.ind ; - if (!argc) default_iplist ; - if (!ip46_scan(argv[0], &localip)) dieusage() ; if (flagdrop) { @@ -203,80 +109,118 @@ int main (int argc, char const *const *argv) close(0) ; close(1) ; - x[0].fd = selfpipe_init() ; - if (x[0].fd == -1) strerr_diefu1sys(111, "create selfpipe") ; + sfd = selfpipe_init() ; + if (sfd == -1) strerr_diefu1sys(111, "create selfpipe") ; if (!sig_altignore(SIGPIPE)) strerr_diefu1sys(111, "ignore SIGPIPE") ; { sigset_t set ; sigemptyset(&set) ; sigaddset(&set, SIGHUP) ; sigaddset(&set, SIGTERM) ; + sigaddset(&set, SIGALRM) ; if (!selfpipe_trapset(&set)) strerr_diefu1sys(111, "trap signals") ; } - if (!cdb_init(&tdb, tdbfile)) strerr_diefu2sys(111, "open cdb file ", tdbfile) ; - if (rulestype == 2 && !cdb_init(&rules, rulesfile)) strerr_diefu2sys(111, "open rules file ", rulesfile) ; - - x[1].fd = socket_udp46_nb(ip46_is6(&localip)) ; - if (x[1].fd == -1) strerr_diefu1sys(111, "create socket") ; - if (socket_bind46_reuse(x[1].fd, &localip, localport) == -1) strerr_diefu1sys(111, "bind socket") ; - - if (gid && setgid(gid) == -1) strerr_diefu1sys(111, "setgid") ; - if (uid && setuid(uid) == -1) strerr_diefu1sys(111, "setuid") ; - if (!tain_now_set_stopwatch_g()) strerr_diefu1sys(111, "initialize clock") ; + if (!cdb_init(&confdb, conffile)) strerr_diefu2sys(111, "open cdb file ", conffile) ; - shibari_log_start(verbosity, &localip, localport) ; - if (notif) { - write(notif, "\n", 1) ; - close(notif) ; + cdb_data data ; + if (!conf_get_uint32(&confdb, "G:logv", &verbosity)) + strerr_diefu1sys(111, "read verbosity from config") ; + if (!conf_get_uint32(&confdb, "G:maxtcp", &maxtcp)) + strerr_diefu1sys(111, "read maxtcp from config") ; + if (maxtcp > 4000 || maxtcp < 1) + strerr_dief1x(102, "invalid maxtcp in config") ; + if (!conf_get(&confdb, "G:listen4", &data)) + strerr_diefu3sys(111, "read ", "G:listen4", " entry from config") ; + if (data.len & 3) + strerr_diefu2sys(102, "invalid length for ", "G:listen4") ; + n4 = data.len >> 2 ; + ip4 = data.s ; +#ifdef SKALIBS_IPV6_ENABLED + if (!conf_get(&confdb, "G:listen6", &data)) + strerr_diefu3sys(111, "read ", "G:listen6", " entry from config") ; + if (data.len & 15) + strerr_diefu2sys(102, "invalid length for ", "G:listen6") ; + n6 = data.len >> 4 ; + ip6 = data.s ; +#endif } + if (!n4 && !n6) strerr_diefu1x(102, "no listen addresses configured" ; - while (cont) { - tain wstamp = TAIN_INFINITE ; - char const *loc = 0 ; - s6dns_message_header_t hdr ; - s6dns_message_counts_t counts ; - s6dns_domain_t name ; - unsigned int rcode ; - ssize_t r ; - uint16_t qtype ; - uint16_t remoteport ; - ip46 remoteip ; + genalloc queries = GENALLOC_ZERO ; /* query */ + int fd4[n4 ? n4 : 1][2] ; + int fd6[n6 ? n6 : 1][2] ; + tcpconnection tcpconn_storage[maxtcp] ; + uint32_t tcpconn_freelist[maxtcp] ; + genset tcpconn_genset ; + tcpconn = &tcpconn_genset ; + GENSET_init(tcpconn, tcpconnection, tcpconn_storage, tcpconn_freelist, maxtcp) ; + + for (size_t i = 0 ; i < n4 ; i++) + { + fd4[i][0] = socket_udp4_nbcoe() ; + if (fd4[i][0] == -1) strerr_diefu1sys(111, "create udp4 socket") ; + if (socket_bind4_reuse(fd4[i][0], ip4 + (i << 2), 53) == -1) + { + char fmt[IP4_FMT] ; + fmt[ip4_fmt(fmt, ip4 + (i << 2))] = 0 ; + strerr_diefu3sys(111, "bind to ip ", fmt, " UDP port 53") ; + } + fd4[i][1] = socket_tcp4_nbcoe() ; + if (fd4[i][1] == -1) strerr_diefu1sys(111, "create tcp4 socket") ; + if (socket_bind4_reuse(fd4[i][1], ip4 + (i << 2), 53) == -1) + { + char fmt[IP4_FMT] ; + fmt[ip4_fmt(fmt, ip4 + (i << 2))] = 0 ; + strerr_diefu3sys(111, "bind to ip ", fmt, " TCP port 53") ; + } + } +#ifdef SKALIBS_IPV6_ENABLED + for (size_t i = 0 ; i < n6 ; i++) + { + fd6[i][0] = socket_udp6_nbcoe() ; + if (fd6[i][0] == -1) strerr_diefu1sys(111, "create udp6 socket") ; + if (socket_bind6_reuse(fd6[i][0], ip6 + (i << 4), 53) == -1) + { + char fmt[IP6_FMT] ; + fmt[ip6_fmt(fmt, ip6 + (i << 4))] = 0 ; + strerr_diefu3sys(111, "bind to ip ", fmt, " UDP port 53") ; + } + fd6[i][1] = socket_tcp6_nbcoe() ; + if (fd6[i][1] == -1) strerr_diefu1sys(111, "create tcp6 socket") ; + if (socket_bind4_reuse(fd6[i][1], ip6 + (i << 4), 53) == -1) + { + char fmt[IP6_FMT] ; + fmt[ip6_fmt(fmt, ip6 + (i << 4))] = 0 ; + strerr_diefu3sys(111, "bind to ip ", fmt, " TCP port 53") ; + } + } +#endif - if (iopause_g(x, 2, &wstamp) == -1) strerr_diefu1sys(111, "iopause") ; - if (x[0].revents & IOPAUSE_EXCEPT) strerr_dief1x(111, "trouble with selfpipe") ; - if (x[0].revents & IOPAUSE_READ) { handle_signals() ; continue ; } + if (gid && setgid(gid) == -1) strerr_diefu1sys(111, "setgid") ; + if (uid && setuid(uid) == -1) strerr_diefu1sys(111, "setuid") ; + if (!tain_now_set_stopwatch_g()) strerr_diefu1sys(111, "initialize clock") ; - r = sanitize_read(socket_recv46(x[1].fd, buf, 512, &remoteip, &remoteport, ip46_is6(&localip))) ; - if (!r) continue ; - if (r == -1) strerr_diefu1sys(111, "recv from socket") ; - if (rulestype && !check_rules(&remoteip, ¶ms, &loc)) continue ; - if (!s6dns_message_parse_init(&hdr, &counts, buf, r, &rcode)) continue ; - if (hdr.opcode) { rcode = 4 ; goto answer ; } - if (!s6dns_message_parse_question(&counts, &name, &qtype, buf, r, &rcode) || !s6dns_domain_encode(&name)) + if (notif) { - rcode = errno == ENOTSUP ? 4 : 1 ; - goto answer ; + write(notif, "\n", 1) ; + close(notif) ; } - shibari_log_queryplus(verbosity, &name, qtype, &remoteip, remoteport) ; - tain_wallclock_read(&wstamp) ; - rcode = shibari_packet_tdb_answer_query(&pkt, &tdb, &hdr, &name, qtype, loc, &wstamp) ; - answer: - if (rcode && rcode != 3) + while (cont) { - shibari_packet_begin(&pkt, hdr.id, &name, qtype) ; - pkt.hdr.rcode = rcode ; - shibari_packet_end(&pkt) ; + size_t n = genalloc_len(query, &queries) ; + iopause_fd x[1 + n4 + n6 + n] ; + x[0].fd = sfd ; + x[0].events = IOPAUSE_READ ; + for (size_t i = 0 ; i < n4 ; i++) + { + } } - shibari_log_answer(verbosity, &pkt.hdr, pkt.pos) ; - tain_add_g(&wstamp, &wtto) ; - if (socket_sendnb46_g(x[1].fd, buf, pkt.pos, &remoteip, remoteport, &wstamp) < pkt.pos && verbosity) - strerr_warnwu1sys("send answer") ; - } + } shibari_log_exit(verbosity, 0) ; return 0 ; } diff --git a/src/cache/tcpconnection.c b/src/cache/tcpconnection.c new file mode 100644 index 0000000..7c7f714 --- /dev/null +++ b/src/cache/tcpconnection.c @@ -0,0 +1,49 @@ +/* ISC license. */ + +#include + +#include + +#include "shibari-cache-internal.h" + +genset *tcpconn = 0 ; + +static inline int check (char const *key, size_t keylen) +{ + cdb_data data ; + return cdb_find(&confdb, &data, key, keylen) ; +} + +int tcp4_access (char const *ip) +{ + int r ; + char key[9] = "A4:" ; + uint8_t i = 33 ; + memcpy(key+4, ip, 4) ; + key[8] = 0 ; + while (i--) + { + key[3] = i ; + key[4 + (i>>3)] &= ~(1U << (7 - (i & 7))) ; + r = check(key, 8) ; + if (r) return r ; + } + return 0 ; +} + +int tcp6_access (char const *ip) +{ + int r ; + char key[21] = "A6:" ; + uint8_t i = 129 ; + memcpy(key+4, ip, 16) ; + key[20] = 0 ; + while (i--) + { + key[3] = i ; + key[4 + (i>>3)] &= ~(1U << (7 - (i & 7))) ; + r = check(key, 20) ; + if (r) return r ; + } + return 0 ; +} diff --git a/src/cache/udpqueue.c b/src/cache/udpqueue.c new file mode 100644 index 0000000..022df3d --- /dev/null +++ b/src/cache/udpqueue.c @@ -0,0 +1,80 @@ +/* ISC license. */ + +#include + +#include +#include +#include +#include + +#include "shibari-cache-internal.h" + +int udpqueue_add4 (udpqueue *q, char const *ip, uint16_t port, char const *s, uint16_t len) +{ + udp4msg msg = { .port = port, .len = len } ; + if (!stralloc_readyplus(&q->storage, len)) return 0 ; + memcpy(msg.ip, ip, 4) ; + if (!genalloc_append(udp4msg, &q->messages, &msg)) return 0 ; + stralloc_catb(&q->storage, s, len) ; + return 1 ; +} + +int udpqueue_flush4 (udpqueue *q) +{ + size_t n = genalloc_n(udp4msg, &q->messages) ; + size_t shead = 0, head = 0 ; + while (head < n) + { + udp4msg const *msg = genalloc_s(udp4msg, &q->messages) + head ; + ssize_t r = socket_send4(q->fd, q->storage.s + shead, msg->len, msg->ip, msg->port) ; + if (r <= 0) goto adjust ; + shead += msg->len ; + } + q->storage.len = 0 ; + genalloc_setlen(udp4msg, &q->messages, 0) ; + return 1 ; + + adjust: + memmove(q->storage.s, q->storage.s + shead, q->storage.len - shead) ; + q->storage.len -= shead ; + memmove(genalloc_s(&udp4msg, &q->messages), genalloc_s(&udp4msg, &q->messages) + head, (n - head) * sizeof(udp4msg)) ; + genalloc_setlen(&udp4msg, &q->messages, n - head) ; + return 0 ; +} + +#ifdef SKALIBS_IPv6_ENABLED + +int udpqueue_add6 (udpqueue *q, char const *ip, uint16_t port, char const *s, uint16_t len) +{ + udp6msg msg = { .port = port, .len = len } ; + if (!stralloc_readyplus(&q->storage, len)) return 0 ; + memcpy(msg.ip, ip, 16) ; + if (!genalloc_append(udp6msg, &q->messages, &msg)) return 0 ; + stralloc_catb(&q->storage, s, len) ; + return 1 ; +} + +int udpqueue_flush6 (udpqueue *q) +{ + size_t n = genalloc_n(udp6msg, &q->messages) ; + size_t shead = 0, head = 0 ; + while (head < n) + { + udp6msg const *msg = genalloc_s(udp4msg, &q->messages) + head ; + ssize_t r = socket_send6(q->fd, q->storage.s + shead, msg->len, msg->ip, msg->port) ; + if (r <= 0) goto adjust ; + shead += msg->len ; + } + q->storage.len = 0 ; + genalloc_setlen(udp6msg, &q->messages, 0) ; + return 1 ; + + adjust: + memmove(q->storage.s, q->storage.s + shead, q->storage.len - shead) ; + q->storage.len -= shead ; + memmove(genalloc_s(&udp6msg, &q->messages), genalloc_s(&udp6msg, &q->messages) + head, (n - head) * sizeof(udp6msg)) ; + genalloc_setlen(&udp6msg, &q->messages, n - head) ; + return 0 ; +} + +#endif diff --git a/src/config/defaults.c b/src/config/defaults.c index 14fce76..d4ff2a8 100644 --- a/src/config/defaults.c +++ b/src/config/defaults.c @@ -18,6 +18,7 @@ struct defaults_s static struct defaults_s const defaults[] = { RECU32("G:logv", 1), + RECU32("G:maxtcp", 256), REC("G:listen4", "\0\0\0\0\0\35", 6), REC("G:listen6", "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\35", 18), diff --git a/src/config/lexparse.c b/src/config/lexparse.c index 9987fbd..f1b3600 100644 --- a/src/config/lexparse.c +++ b/src/config/lexparse.c @@ -38,6 +38,7 @@ struct namevalue_s enum directivevalue_e { T_VERBOSITY, + T_MAXTCP, T_LISTEN, T_SERVER, T_FORWARD, @@ -87,6 +88,20 @@ static inline void parse_verbosity (char const *s, size_t const *word, size_t n, add_unique("G:logv", pack, 4, md) ; } +static inline void parse_maxtcp (char const *s, size_t const *word, size_t n, mdt const *md) +{ + uint32_t max ; + char pack[4] ; + if (n != 1) + strerr_dief8x(1, "too ", n ? "many" : "few", " arguments to directive ", "maxtcp", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; + if (!uint320_scan(s + word[0], &max)) + strerr_dief7x(1, " argument to directive ", "maxtcp", " must be an integer ", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; + if (max > 4000) + strerr_dief7x(1, " argument to directive ", "maxtcp", " must be 4000 or less ", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; + uint32_pack_big(pack, max) ; + add_unique("G:maxtcp", pack, 4, md) ; +} + static inline void parse_listen (char const *s, size_t const *word, size_t n, mdt const *md) { if (!n) @@ -140,8 +155,10 @@ static inline void process_line (char const *s, size_t const *word, size_t n, md { static struct namevalue_s const directives[] = { + { .name = "accept", .value = T_ACCEPT }, { .name = "forward", .value = T_FORWARD }, { .name = "listen", .value = T_LISTEN }, + { .name = "maxtcp", .value = T_MAXTCP }, { .name = "server", .value = T_SERVER }, { .name = "verbosity", .value = T_VERBOSITY }, } ; @@ -157,9 +174,15 @@ static inline void process_line (char const *s, size_t const *word, size_t n, md case T_VERBOSITY : parse_verbosity(s, word, n, md) ; break ; + case T_MAXTCP : + parse_maxtcp(s, word, n, md) ; + break ; case T_LISTEN : parse_listen(s, word, n, md) ; break ; + case T_ACCEPT : + parse_accept(s, word, n, md) ; + break ; case T_SERVER : parse_server(s, word, n, md, 0) ; break ; @@ -227,4 +250,5 @@ void conf_lexparse (buffer *b, char const *ifile) } genalloc_free(size_t, &words) ; stralloc_free(&sa) ; + default_accept() ; } diff --git a/src/libdcache/dcache-internal.h b/src/libdcache/dcache-internal.h new file mode 100644 index 0000000..7a21044 --- /dev/null +++ b/src/libdcache/dcache-internal.h @@ -0,0 +1,18 @@ +/* ISC license. */ + +#ifndef DCACHE_INTERNAL_H +#define DCACHE_INTERNAL_H + +#include + +#include +#include + +#include + +#define DNODE(z, i) GENSETDYN_P(dcache_node_t, &(z)->storage, i) +#define DCACHE_NODE_OVERHEAD (32 + sizeof(dcache_node_t) + 3 * sizeof(avlnode)) + +extern void dcache_delete (dcache_t *, uint32_t) ; + +#endif diff --git a/src/libdcache/dcache_add.c b/src/libdcache/dcache_add.c new file mode 100644 index 0000000..7260726 --- /dev/null +++ b/src/libdcache/dcache_add.c @@ -0,0 +1,85 @@ +/* ISC license. */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "dcache-internal.h" + +static void uniquify (avltree const *tree, tain *stamp) +{ + static tain const nano = { .sec = TAI_ZERO, .nano = 1 } ; + uint32_t dummy ; + while (avltree_search(tree, stamp, &dummy)) + tain_add(stamp, stamp, &nano) ; +} + +static inline void dcache_gc_by_entry (dcache_t *z, uint64_t max) +{ + while (z->size > max) + { + uint32_t oldest ; + if (!avltree_min(&z->by_entry, &oldest)) break ; + dcache_delete(z, oldest) ; + } +} + +static inline int dcache_add_node (dcache_t *z, dcache_node_t const *node) +{ + uint32_t i ; + dcache_node_t *y ; + if (!gensetdyn_new(&z->storage, &i)) return 0 ; + y = DNODE(z, i) ; *y = *node ; + uniquify(&z->by_entry, &y->entry) ; + uniquify(&z->by_expire, &y->expire) ; + if (!avltree_insert(&z->by_key, i)) goto err1 ; + if (!avltree_insert(&z->by_entry, i)) goto err2 ; + if (!avltree_insert(&z->by_expire, i)) goto err3 ; + return 1 ; + + err3: + avltree_delete(&z->by_entry, &y->entry) ; + err2: + avltree_delete(&z->by_key, &y->key) ; + err1: + gensetdyn_delete(&z->storage, i) ; + return 0 ; +} + +static inline int dcache_add_unbounded (dcache_t *z, char const *key, uint16_t keylen, char const *data, uint16_t datalen, tain const *expire, tain const *stamp) +{ + uint32_t len = (uint32_t)keylen + (uint32_t)datalen ; + dcache_node_t y = { .key = { .s = alloc(len) } } ; + if (!y.key.s) return 0 ; + memcpy(y.key.s, key, keylen) ; + memcpy(y.key.s + keylen, data, datalen) ; + y.key.len = keylen ; + y.datalen = datalen ; + y.entry = *stamp ; + y.expire = *expire ; + if (!dcache_add_node(z, &y)) + { + alloc_free(y.key.s) ; + return 0 ; + } + z->size += DCACHE_NODE_OVERHEAD + len ; + z->motion += DCACHE_NODE_OVERHEAD + len ; + return 1 ; +} + +int dcache_add (dcache_t *z, uint64_t max, char const *key, uint16_t keylen, char const *data, uint16_t datalen, tain const *expire, tain const *stamp) +{ + uint64_t size = DCACHE_NODE_OVERHEAD + keylen + datalen ; + if (size > max) return (errno = EINVAL, 0) ; + if (z->size > max - size) dcache_clean_expired(z, stamp) ; + if (z->size > max - size) dcache_gc_by_entry(z, max - size) ; + return dcache_add_unbounded(z, key, keylen, data, datalen, expire, stamp) ; +} diff --git a/src/libdcache/dcache_clean_expired.c b/src/libdcache/dcache_clean_expired.c new file mode 100644 index 0000000..0e23443 --- /dev/null +++ b/src/libdcache/dcache_clean_expired.c @@ -0,0 +1,20 @@ +/* ISC license. */ + +#include + +#include +#include + +#include +#include "dcache-internal.h" + +void dcache_clean_expired (dcache_t *z, tain const *stamp) +{ + for (;;) + { + uint32_t i ; + if (!avltree_min(&z->by_expire, &i)) break ; + if (tain_less(stamp, &DNODE(z, i)->expire)) break ; + dcache_delete(z, i) ; + } +} diff --git a/src/libdcache/dcache_delete.c b/src/libdcache/dcache_delete.c new file mode 100644 index 0000000..92a5fcc --- /dev/null +++ b/src/libdcache/dcache_delete.c @@ -0,0 +1,19 @@ +/* ISC license. */ + +#include +#include +#include + +#include +#include "dcache-internal.h" + +void dcache_delete (dcache_t *z, uint32_t i) +{ + dcache_node_t *y = DNODE(z, i) ; + avltree_delete(&z->by_expire, &y->expire) ; + avltree_delete(&z->by_entry, &y->entry) ; + avltree_delete(&z->by_key, &y->key) ; + alloc_free(y->key.s) ; + z->size -= DCACHE_NODE_OVERHEAD + y->key.len + y->datalen ; + gensetdyn_delete(&z->storage, i) ; +} diff --git a/src/libdcache/dcache_free.c b/src/libdcache/dcache_free.c new file mode 100644 index 0000000..16c074e --- /dev/null +++ b/src/libdcache/dcache_free.c @@ -0,0 +1,22 @@ +/* ISC license. */ + +#include +#include +#include + +#include + +static void dcache_node_free (void *p) +{ + alloc_free(((dcache_node_t *)p)->key.s) ; +} + +void dcache_free (dcache_t *z) +{ + static dcache_t const dcache_zero = DCACHE_ZERO ; + avltree_free(&z->by_expire) ; + avltree_free(&z->by_entry) ; + avltree_free(&z->by_key) ; + gensetdyn_deepfree(&z->storage, &dcache_node_free) ; + *z = dcache_zero ; +} diff --git a/src/libdcache/dcache_init.c b/src/libdcache/dcache_init.c new file mode 100644 index 0000000..d42ec62 --- /dev/null +++ b/src/libdcache/dcache_init.c @@ -0,0 +1,55 @@ +/* ISC license. */ + +#include +#include + +#include +#include +#include +#include + +#include + +static int key_cmp (void const *a, void const *b, void *x) +{ + dcache_key_t const *ka = a ; + dcache_key_t const *kb = b ; + if (ka->len < kb->len) return -1 ; + if (kb->len < ka->len) return 1 ; + (void)x ; + return memcmp(ka->s, kb->s, ka->len) ; +} + +static int tain_cmp (void const *a, void const *b, void *x) +{ + tain const *ta = a ; + tain const *tb = b ; + (void)x ; + return tain_less(ta, tb) ? -1 : tain_less(tb, ta) ; +} + +static void *key_dtok (uint32_t d, void *x) +{ + return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->key ; +} + +static void *entry_dtok (uint32_t d, void *x) +{ + return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->entry ; +} + +static void *expire_dtok (uint32_t d, void *x) +{ + return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->expire ; +} + + +void dcache_init (dcache_t *z, uint64_t max) +{ + gensetdyn_init(&z->storage, sizeof(dcache_node_t), max >> 9, 3, 8) ; + avltree_init(&z->by_key, max >> 9, 3, 8, &key_dtok, &key_cmp, &z->storage) ; + avltree_init(&z->by_entry, max >> 9, 3, 8, &entry_dtok, &tain_cmp, &z->storage) ; + avltree_init(&z->by_expire, max >> 9, 3, 8, &expire_dtok, &tain_cmp, &z->storage) ; + z->size = 0 ; + z->motion = 0 ; +} diff --git a/src/libdcache/dcache_load.c b/src/libdcache/dcache_load.c new file mode 100644 index 0000000..d1b9274 --- /dev/null +++ b/src/libdcache/dcache_load.c @@ -0,0 +1,82 @@ +/* ISC license. */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static inline int dcache_load_node (dcache_t *z, uint64_t max, buffer *b) +{ + tain entry = { .nano = 0 } ; + tain expire = { .nano = 0 } ; + uint16_t keylen ; + uint16_t datalen ; + char pack[TAI_PACK * 2 + 4] ; + ssize_t r = buffer_get(b, pack, TAI_PACK * 2 + 4) ; + if (!r) return 0 ; + if (r < TAI_PACK * 2 + 4) return -1 ; + tai_unpack(pack, tain_secp(&entry)) ; + tai_unpack(pack + TAI_PACK, tain_secp(&expire)) ; + uint16_unpack_big(pack + TAI_PACK * 2, &keylen) ; + uint16_unpack_big(pack + TAI_PACK * 2 + 2, &datalen) ; + { + uint32_t len = (uint32_t)keylen + (uint32_t)datalen ; + char blob[len+1] ; /* 128 kB max, it's ok */ + r = buffer_get(b, blob, len+1) ; + if (!r) return (errno = EPIPE, -1) ; + if (r < len) return -1 ; + if (blob[len]) return (errno = EPROTO, -1) ; + if (!dcache_add(z, max, blob, keylen, blob + keylen, datalen, &expire, &entry)) return -1 ; + } + return 1 ; +} + +static inline int dcache_load_from_buffer (dcache_t *z, uint64_t max, buffer *b) +{ + { + char banner[sizeof(DCACHE_MAGIC) - 1] ; + char pack[8] ; + if (buffer_get(b, banner, sizeof(DCACHE_MAGIC) - 1) < sizeof(DCACHE_MAGIC) - 1) + return 0 ; + if (memcmp(banner, DCACHE_MAGIC, sizeof(DCACHE_MAGIC) - 1)) return 0 ; + if (buffer_get(b, pack, 8) < 8) return 0 ; + uint64_unpack_big(pack, &z->size) ; + if (buffer_get(b, pack, 8) < 8) return 0 ; + uint64_unpack_big(pack, &z->motion) ; + } + for (;;) + { + int r = dcache_load_node(z, max, b) ; + if (r < 0) return 0 ; + if (!r) break ; + } + return 1 ; +} + +#define N 8192 + +int dcache_load (dcache_t *z, uint64_t max, char const *file) +{ + char buf[N] ; + buffer b ; + int fd = open_readb(file) ; + if (fd == -1) return 0 ; + buffer_init(&b, &buffer_read, fd, buf, N) ; + if (!dcache_load_from_buffer(z, max, &b)) goto err ; + fd_close(fd) ; + return 1 ; + + err: + dcache_free(z) ; + fd_close(fd) ; + return 0 ; +} diff --git a/src/libdcache/dcache_save.c b/src/libdcache/dcache_save.c new file mode 100644 index 0000000..7277771 --- /dev/null +++ b/src/libdcache/dcache_save.c @@ -0,0 +1,73 @@ +/* ISC license. */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int write_node_iter (void *data, void *aux) +{ + dcache_node_t *y = data ; + buffer *b = aux ; + char pack[TAI_PACK * 2 + 4] ; + tai_pack(pack, tain_secp(&y->entry)) ; + tai_pack(pack + TAI_PACK, tain_secp(&y->expire)) ; + uint16_pack(pack + TAI_PACK * 2, y->key.len) ; + uint16_pack(pack + TAI_PACK * 2 + 2, y->datalen) ; + if (buffer_put(b, pack, TAI_PACK * 2 + 4) == -1) return 0 ; + if (buffer_put(b, y->key.s, y->key.len + y->datalen) == -1) return 0 ; + if (buffer_put(b, "", 1) == -1) return 0 ; + return 1 ; +} + +static inline int dcache_save_to_buffer (dcache_t const *z, buffer *b) +{ + char pack[16] ; + if (buffer_puts(b, DCACHE_MAGIC) == -1) return 0 ; + uint64_pack_big(pack, z->size) ; + uint64_pack_big(pack + 8, z->motion) ; + if (buffer_put(b, pack, 16) < 16) return 0 ; + + /* XXX: can gensetdyn_iter blow up the stack if z->storage is huge? */ + if (gensetdyn_iter_nocancel((gensetdyn *)&z->storage, gensetdyn_n(&z->storage), &write_node_iter, b) < gensetdyn_n(&z->storage)) return 0 ; + + return buffer_flush(b) ; +} + +#define N 8192 + +int dcache_save (dcache_t const *z, char const *file) +{ + size_t len = strlen(file) ; + int fd ; + buffer b ; + char buf[N] ; + char tmp[len + 20] ; + memcpy(tmp, file, len) ; + memcpy(tmp + len, ":dcache_save:XXXXXX", 20) ; + fd = mkstemp(tmp) ; + if (fd == -1) return 0 ; + buffer_init(&b, &buffer_write, fd, buf, N) ; + if (!dcache_save_to_buffer(z, &b) || fsync(fd) < 0) goto err2 ; + fd_close(fd) ; + if (rename(tmp, file) == -1) goto err1 ; + return 1 ; + + err2: + fd_close(fd) ; + err1: + unlink_void(tmp) ; + return 0 ; +} diff --git a/src/libdcache/dcache_search.c b/src/libdcache/dcache_search.c new file mode 100644 index 0000000..0239b88 --- /dev/null +++ b/src/libdcache/dcache_search.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include + +#include + +#include +#include "dcache-internal.h" + +dcache_node_t *dcache_search (dcache_t *z, char const *key, uint16_t keylen) +{ + uint32_t i ; + dcache_key_t k = { .s = (char *)key, .len = keylen } ; + return avltree_search(&z->by_key, &k, &i) ? DNODE(z, i) : 0 ; +} diff --git a/src/libdcache/deps-lib/dcache b/src/libdcache/deps-lib/dcache new file mode 100644 index 0000000..fcc09a0 --- /dev/null +++ b/src/libdcache/deps-lib/dcache @@ -0,0 +1,8 @@ +dcache_add.o +dcache_clean_expired.o +dcache_delete.o +dcache_free.o +dcache_init.o +dcache_load.o +dcache_save.o +dcache_search.o diff --git a/src/server/deps-exe/shibari-server-tcp b/src/server/deps-exe/shibari-server-tcp index c25f645..5a43e40 100644 --- a/src/server/deps-exe/shibari-server-tcp +++ b/src/server/deps-exe/shibari-server-tcp @@ -2,3 +2,4 @@ ${LIBSHIBARI_SERVER} ${LIBSHIBARI_COMMON} -ls6dns -lskarnet +${SYSCLOCK_LIB} diff --git a/src/server/deps-exe/shibari-server-udp b/src/server/deps-exe/shibari-server-udp index 0c1f81d..bfe41cd 100644 --- a/src/server/deps-exe/shibari-server-udp +++ b/src/server/deps-exe/shibari-server-udp @@ -4,3 +4,4 @@ ${LIBSHIBARI_COMMON} -ls6 -lskarnet ${SOCKET_LIB} +${SYSCLOCK_LIB} -- cgit v1.3.1