45 const char *sql =
"SELECT COUNT(*) FROM rate_events "
46 "WHERE ip_address = ? AND event_type = ? AND timestamp >= ?";
48 sqlite3_stmt *stmt = NULL;
49 int rc = sqlite3_prepare_v2(backend->db, sql, -1, &stmt, NULL);
50 if (rc != SQLITE_OK) {
51 return SET_ERRNO(
ERROR_CONFIG,
"Failed to prepare rate limit query: %s", sqlite3_errmsg(backend->db));
54 sqlite3_bind_text(stmt, 1, ip_address, -1, SQLITE_STATIC);
55 sqlite3_bind_text(stmt, 2, event_type_strings[event_type], -1, SQLITE_STATIC);
56 sqlite3_bind_int64(stmt, 3, (sqlite3_int64)window_start_ms);
58 rc = sqlite3_step(stmt);
59 if (rc != SQLITE_ROW) {
60 sqlite3_finalize(stmt);
61 return SET_ERRNO(
ERROR_CONFIG,
"Failed to execute rate limit query: %s", sqlite3_errmsg(backend->db));
65 sqlite3_finalize(stmt);
68 *allowed = (event_count < limit->max_events);
71 log_warn(
"Rate limit exceeded for %s (event: %s, count: %u/%u)", ip_address,
85 const char *sql =
"INSERT INTO rate_events (ip_address, event_type, timestamp) VALUES (?, ?, ?)";
87 sqlite3_stmt *stmt = NULL;
88 int rc = sqlite3_prepare_v2(backend->
db, sql, -1, &stmt, NULL);
89 if (rc != SQLITE_OK) {
93 sqlite3_bind_text(stmt, 1, ip_address, -1, SQLITE_STATIC);
94 sqlite3_bind_text(stmt, 2, event_type_strings[event_type], -1, SQLITE_STATIC);
95 sqlite3_bind_int64(stmt, 3, (sqlite3_int64)now_ms);
97 rc = sqlite3_step(stmt);
98 sqlite3_finalize(stmt);
100 if (rc != SQLITE_DONE) {
112 if (max_age_secs == 0) {
121 const char *sql =
"DELETE FROM rate_events WHERE timestamp < ?";
123 sqlite3_stmt *stmt = NULL;
124 int rc = sqlite3_prepare_v2(backend->
db, sql, -1, &stmt, NULL);
125 if (rc != SQLITE_OK) {
129 sqlite3_bind_int64(stmt, 1, (sqlite3_int64)cutoff_ms);
131 rc = sqlite3_step(stmt);
132 int changes = sqlite3_changes(backend->
db);
133 sqlite3_finalize(stmt);
135 if (rc != SQLITE_DONE) {
140 log_debug(
"Cleaned up %d old rate events", changes);
146static void sqlite_destroy(
void *backend_data) {
162 log_error(
"Failed to allocate SQLite backend");
166 memset(backend, 0,
sizeof(*backend));
170 log_debug(
"SQLite rate limiter backend allocated (database will be set externally)");
187 .
check = sqlite_check,
188 .record = sqlite_record,
189 .cleanup = sqlite_cleanup,
190 .destroy = sqlite_destroy,
unsigned long long uint64_t
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_debug(...)
Log a DEBUG message.
📝 Logging API with multiple log levels and terminal output control
uint64_t rate_limiter_get_time_ms(void)
Helper: Get current time in milliseconds.
const char * rate_limiter_event_type_string(rate_event_type_t event_type)
Helper: Get event type string for logging.
const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX]
Default rate limits for each event type.
rate_event_type_t
Rate limit event types.
@ RATE_EVENT_SESSION_LOOKUP
Session lookup.
@ RATE_EVENT_CONTROL
Control packets (CAPABILITIES, STREAM_START/STOP, LEAVE)
@ RATE_EVENT_SESSION_JOIN
Session join.
@ RATE_EVENT_CONNECTION
New connection.
@ RATE_EVENT_PING
Ping/pong keepalive (PACKET_TYPE_PING, PACKET_TYPE_PONG)
@ RATE_EVENT_SESSION_CREATE
Session creation.
@ RATE_EVENT_AUDIO
Audio packet (PACKET_TYPE_AUDIO, PACKET_TYPE_AUDIO_BATCH)
@ RATE_EVENT_MAX
Sentinel value.
@ RATE_EVENT_IMAGE_FRAME
Image frame from client (PACKET_TYPE_IMAGE_FRAME)
@ RATE_EVENT_CLIENT_JOIN
Client join request (PACKET_TYPE_CLIENT_JOIN)
void sqlite_backend_set_db(void *backend_data, sqlite3 *db)
Set SQLite database handle for backend.
void * sqlite_backend_create(const char *db_path)
Create SQLite backend instance.
const rate_limiter_backend_ops_t sqlite_backend_ops
SQLite backend operations vtable.
💾 SQLite rate limiting backend interface
Rate limit configuration.
uint32_t window_secs
Time window in seconds.
Backend operations vtable.
asciichat_error_t(* check)(void *backend_data, const char *ip_address, rate_event_type_t event_type, const rate_limit_config_t *config, bool *allowed)
sqlite3 * db
SQLite database handle.