66 lines
1.4 KiB
C
66 lines
1.4 KiB
C
#pragma once
|
|
#include <stddef.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
|
|
#ifdef RATELIMIT_THREADSAFE
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
typedef struct {
|
|
ratelimit_table_type value;
|
|
int count;
|
|
double window_start;
|
|
} ratelimit_t;
|
|
|
|
static struct {
|
|
ratelimit_t data[256];
|
|
size_t next;
|
|
#ifdef RATELIMIT_THREADSAFE
|
|
pthread_mutex_t lock;
|
|
#endif
|
|
} ratelimit_table = { {0}, 0
|
|
#ifdef RATELIMIT_THREADSAFE
|
|
, PTHREAD_MUTEX_INITIALIZER
|
|
#endif
|
|
};
|
|
|
|
static int rate_limited(ratelimit_table_type value, float window, int rate_limit) {
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
double now = ts.tv_sec + ts.tv_nsec * 1e-9;
|
|
|
|
#ifdef RATELIMIT_THREADSAFE
|
|
pthread_mutex_lock(&ratelimit_table.lock);
|
|
#endif
|
|
|
|
ratelimit_t* e = (void*)0;
|
|
for (size_t i = 0; i < 256; i++) {
|
|
if (memcmp(ratelimit_table.data[i].value, value, sizeof(ratelimit_table_type)) == 0) {
|
|
e = &ratelimit_table.data[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!e) {
|
|
e = &ratelimit_table.data[ratelimit_table.next++];
|
|
memcpy(e->value, value, sizeof(ratelimit_table_type));
|
|
e->window_start = now;
|
|
e->count = 0;
|
|
}
|
|
|
|
if (now - e->window_start >= window) {
|
|
e->window_start = now;
|
|
e->count = 0;
|
|
}
|
|
|
|
const int allowed = e->count < rate_limit;
|
|
if (allowed) e->count++;
|
|
|
|
#ifdef RATELIMIT_THREADSAFE
|
|
pthread_mutex_unlock(&ratelimit_table.lock);
|
|
#endif
|
|
|
|
return allowed ? 0 : 1;
|
|
}
|