From 973130f7802a00204d7b032bd941b2d9cdac8e81 Mon Sep 17 00:00:00 2001 From: Chip Black Date: Wed, 2 Jul 2014 22:23:20 -0500 Subject: [PATCH 1/1] Add stringring implementation --- Makefile | 2 +- common/stringring.c | 174 ++++++++++++++++++++++++++++++++++++++++++++ common/stringring.h | 30 ++++++++ 3 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 common/stringring.c create mode 100644 common/stringring.h diff --git a/Makefile b/Makefile index 40ebc63..c66d758 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ HTTP_LIBDIRS = $(MHD_LIBDIR) $(YAJL_LIBDIR) CGI_LIBDIRS = $(CGI_UTIL_LIBDIR) $(YAJL_LIBDIR) targets = blerg.a blerg_auth.a blergtool blerglatest blerg.cgi perl-lib www/build/enyo-blerg.js -blerg_a_objects = database/database.o database/tags.o database/util.o database/configuration.o database/subscription.o common/stringbucket.o +blerg_a_objects = database/database.o database/tags.o database/util.o database/configuration.o database/subscription.o common/stringbucket.o common/stringring.o blerg_auth_a_objects = common/auth.o common/md5.o blergtool_objects = tools/blergtool.o blerg.a blerglatest_objects = tools/blerglatest.o blerg.a common/json.o diff --git a/common/stringring.c b/common/stringring.c new file mode 100644 index 0000000..c788db8 --- /dev/null +++ b/common/stringring.c @@ -0,0 +1,174 @@ +/* Blerg is (C) 2011 The Dominion of Awesome, and is distributed under a + * BSD-style license. Please see the COPYING file for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STRINGRING_DATA_CHECK() \ + if (sh == NULL) \ + return 0; \ + if (data == NULL) \ + return 0; \ + if (data[0] == 0) \ + return 0; + + +struct stringring_handle * stringring_open(const char *filename) { + struct stringring_handle *sh; + struct stat st; + int initialize = 0; + + sh = malloc(sizeof(struct stringring_handle)); + if (sh == NULL) { + perror("stringring_handle malloc"); + return NULL; + } + + sh->fd = open(filename, O_RDWR | O_CREAT, 0600); + flock(sh->fd, LOCK_EX); + if (sh->fd == -1) { + perror("stringring open"); + goto stringring_open__open_failed; + } + + fstat(sh->fd, &st); + if (st.st_size < sizeof(struct stringring)) { + ftruncate(sh->fd, sizeof(struct stringring)); + initialize = 1; + } + sh->sr = mmap(NULL, sizeof(struct stringring), PROT_READ | PROT_WRITE, MAP_SHARED, sh->fd, 0); + if (sh->sr == MAP_FAILED) { + perror("stringring mmap"); + goto stringring_open__map_failed; + } + + if (initialize) { + stringring_clear(sh); + } + flock(sh->fd, LOCK_UN); + + return sh; + +stringring_open__map_failed: + flock(sh->fd, LOCK_UN); + fclose(sh->fd); +stringring_open__open_failed: + free(sh); + return NULL; +} + +void stringring_close(struct stringring_handle *sh) { + if (sh == NULL) + return; + + if (sh->sr != NULL) + munmap(sh->sr, sizeof(struct stringring)); + + if (sh->fd > -1) + close(sh->fd); + + free(sh); +} + +int stringring_add(struct stringring_handle *sh, const char *data) { + STRINGRING_DATA_CHECK(); + + flock(sh->fd, LOCK_EX); + if (sh->sr->counter == 0) { + sh->sr->counter = STRINGRING_N_ENTRIES - 1; + } else { + sh->sr->counter--; + } + + int data_len = strlen(data); + sh->sr->entries[sh->sr->counter].timestamp = time(NULL); + strncpy(sh->sr->entries[sh->sr->counter].data, data, STRINGRING_DATA_SIZE); + if (data_len < STRINGRING_DATA_SIZE) { + /* zero out the rest of the data */ + memset(sh->sr->entries[sh->sr->counter].data + data_len, 0, STRINGRING_DATA_SIZE - data_len); + } + flock(sh->fd, LOCK_UN); + + return 1; +} + +int stringring_find_unlocked(struct stringring_handle *sh, const char *data, uint64_t cutoff) { + int n, i; + + i = sh->sr->counter; + for (n = 0; n < STRINGRING_N_ENTRIES; n++) { + if (sh->sr->entries[i].timestamp > 0 && + sh->sr->entries[i].timestamp > cutoff && + strncmp(sh->sr->entries[i].data, data, STRINGRING_DATA_SIZE) == 0) { + return i; + } + i = (i + 1) % STRINGRING_N_ENTRIES; + } + + return -1; +} + +int stringring_find(struct stringring_handle *sh, const char *data, unsigned int max_age) { + int ret; + uint64_t cutoff = (max_age > 0 ? time(NULL) - max_age : 0); + + flock(sh->fd, LOCK_SH); + ret = stringring_find_unlocked(sh, data, cutoff); + flock(sh->fd, LOCK_UN); + + return ret; +} + +int stringring_remove_index_unlocked(struct stringring_handle *sh, int idx) { + if (sh == NULL) + return 0; + if (idx < 0 || idx >= STRINGRING_N_ENTRIES) + return 0; + + sh->sr->entries[idx].timestamp = 0; + memset(sh->sr->entries[idx].data, 0, STRINGRING_DATA_SIZE); + + return 1; +} + +int stringring_remove_index(struct stringring_handle *sh, int idx) { + int ret; + + flock(sh->fd, LOCK_EX); + ret = stringring_remove_index_unlocked(sh, idx); + flock(sh->fd, LOCK_UN); + + return ret; +} + +int stringring_remove(struct stringring_handle *sh, const char *data) { + STRINGRING_DATA_CHECK(); + int ret; + + flock(sh->fd, LOCK_EX); + ret = stringring_remove_index_unlocked(sh, + stringring_find_unlocked(sh, data, 0)); + flock(sh->fd, LOCK_UN); + + return ret; +} + +int stringring_clear(struct stringring_handle *sh) { + if (sh == NULL) + return 0; + + flock(sh->fd, LOCK_EX); + memset(sh->sr, 0, sizeof(struct stringring)); + flock(sh->fd, LOCK_UN); + + return 1; +} diff --git a/common/stringring.h b/common/stringring.h new file mode 100644 index 0000000..7aedeb4 --- /dev/null +++ b/common/stringring.h @@ -0,0 +1,30 @@ +#ifndef _STRINGRING_H +#define _STRINGRING_H + +#include + +#define STRINGRING_DATA_SIZE 32 +#define STRINGRING_N_ENTRIES 102 + +struct stringring { + uint8_t counter; + uint8_t reserved[15]; + struct { + uint64_t timestamp; + uint8_t data[STRINGRING_DATA_SIZE]; + } entries[STRINGRING_N_ENTRIES]; +}; + +struct stringring_handle { + int fd; + struct stringring *sr; +}; + +struct stringring_handle * stringring_open(const char *filename); +void stringring_close(struct stringring_handle *sh); +int stringring_add(struct stringring_handle *sh, const char *data); +int stringring_find(struct stringring_handle *sh, const char *data, unsigned int max_age); +int stringring_remove(struct stringring_handle *sh, const char *data); +int stringring_clear(struct stringring_handle *sh); + +#endif /* _STRINGRING_H */ -- 2.25.1