X-Git-Url: http://git.bytex64.net/?a=blobdiff_plain;f=common%2Fstringring.c;fp=common%2Fstringring.c;h=c788db8e0ce0fe58690fcb116fdfa1f10e574184;hb=973130f7802a00204d7b032bd941b2d9cdac8e81;hp=0000000000000000000000000000000000000000;hpb=b8fe46e27d53b5a03b5d27b59bae40a6445e9b8d;p=blerg.git 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; +}