From 81440f9a4e2d8d105bade578bc1e11ec6780ca81 Mon Sep 17 00:00:00 2001 From: moon Date: Sat, 13 Sep 2025 23:13:07 +0330 Subject: feature impls + directories --- src/ratelimit.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/ratelimit.c (limited to 'src/ratelimit.c') diff --git a/src/ratelimit.c b/src/ratelimit.c new file mode 100644 index 0000000..c6f0e01 --- /dev/null +++ b/src/ratelimit.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include + +#define TABLE_SIZE 2048 +#define MAX_KEY_LEN 46 +#define STALE_SECONDS 30 + +struct rl_entry { + char ip[ MAX_KEY_LEN ]; + time_t last_request; + int count; + int in_use; +}; + +struct rl_table { + struct rl_entry entries[ TABLE_SIZE ]; + pthread_mutex_t mutex; +}; + +struct rl_table* global_ratelimit = NULL; + +void ratelimit_init(void) { + if (global_ratelimit != NULL) return; + + struct rl_table* table = malloc(sizeof(struct rl_table)); + if (!table) { + perror("failed to alloc ratelimit table"); + exit(1); + } + memset(table->entries, 0, sizeof(table->entries)); + pthread_mutex_init(&table->mutex, NULL); + + global_ratelimit = table; +} + +static uint32_t hash_ip(const char* ip) { + uint32_t hash = 5381; + while (*ip) hash = (hash << 5) + hash + *ip++; + return hash % TABLE_SIZE; +} + +int ratelimit_check(const char* ip) { + ratelimit_init(); + pthread_mutex_lock(&global_ratelimit->mutex); + + time_t now = time(NULL); + uint32_t index = hash_ip(ip); + uint32_t probes = 0; + + while (probes < TABLE_SIZE) { + struct rl_entry* entry = &global_ratelimit->entries[ index ]; + + if (!entry->in_use) { + strncpy(entry->ip, ip, MAX_KEY_LEN - 1); + entry->ip[ MAX_KEY_LEN - 1 ] = '\0'; + entry->last_request = now; + entry->count = 1; + entry->in_use = 1; + pthread_mutex_unlock(&global_ratelimit->mutex); + return 1; + } + + if (strcmp(entry->ip, ip) == 0) { + if (now > entry->last_request) { + entry->last_request = now; + entry->count = 1; + } else if (entry->count >= 4) { + pthread_mutex_unlock(&global_ratelimit->mutex); + return 0; + } else { + entry->count++; + } + pthread_mutex_unlock(&global_ratelimit->mutex); + return 1; + } + + if (entry->in_use && (now - entry->last_request) > STALE_SECONDS) { + entry->in_use = 0; + entry->count = 0; + entry->last_request = 0; + entry->ip[ 0 ] = '\0'; + strncpy(entry->ip, ip, MAX_KEY_LEN - 1); + entry->ip[ MAX_KEY_LEN - 1 ] = '\0'; + entry->last_request = now; + entry->count = 1; + entry->in_use = 1; + pthread_mutex_unlock(&global_ratelimit->mutex); + return 1; + } + + index = (index + 1) % TABLE_SIZE; + probes++; + } + + pthread_mutex_unlock(&global_ratelimit->mutex); + return 0; +} + +void ratelimit_free(struct rl_table* table) { + if (table) { + pthread_mutex_destroy(&table->mutex); + free(table); + } +} -- cgit v1.2.3