ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
rate_limit.c
Go to the documentation of this file.
1
9#include "log/logging.h"
10#include <stdlib.h>
11#include <string.h>
12#include <time.h>
13
14// Event type strings for logging
15static const char *event_type_strings[RATE_EVENT_MAX] = {
16 [RATE_EVENT_SESSION_CREATE] = "session_create",
17 [RATE_EVENT_SESSION_LOOKUP] = "session_lookup",
18 [RATE_EVENT_SESSION_JOIN] = "session_join",
19 [RATE_EVENT_CONNECTION] = "connection",
20 [RATE_EVENT_IMAGE_FRAME] = "image_frame",
21 [RATE_EVENT_AUDIO] = "audio",
22 [RATE_EVENT_PING] = "ping",
23 [RATE_EVENT_CLIENT_JOIN] = "client_join",
24 [RATE_EVENT_CONTROL] = "control",
25};
26
27// Default rate limits: conservative defaults to prevent abuse
28// Debug builds have relaxed limits for development/testing
30// ACDS discovery server limits
31#ifdef NDEBUG
32 // Release mode: production limits (144 FPS video, 172 FPS audio)
33 [RATE_EVENT_SESSION_CREATE] = {.max_events = 10, .window_secs = 60}, // 10 creates per minute
34 [RATE_EVENT_SESSION_LOOKUP] = {.max_events = 30, .window_secs = 60}, // 30 lookups per minute
35 [RATE_EVENT_SESSION_JOIN] = {.max_events = 20, .window_secs = 60}, // 20 joins per minute
36 [RATE_EVENT_CONNECTION] = {.max_events = 50, .window_secs = 60}, // 50 connections per minute
37 [RATE_EVENT_IMAGE_FRAME] = {.max_events = 8640, .window_secs = 60}, // 8640 frames/min = 144 FPS
38 [RATE_EVENT_AUDIO] = {.max_events = 10320, .window_secs = 60}, // 10320 packets/min = 172 FPS
39 [RATE_EVENT_PING] = {.max_events = 120, .window_secs = 60}, // 120 pings/min = 2 Hz max
40 [RATE_EVENT_CLIENT_JOIN] = {.max_events = 10, .window_secs = 60}, // 10 joins per minute
41 [RATE_EVENT_CONTROL] = {.max_events = 100, .window_secs = 60}, // 100 control packets/min
42#else
43 // Debug mode: slightly relaxed limits for development/testing (1.5x production limits)
44 [RATE_EVENT_SESSION_CREATE] = {.max_events = 15, .window_secs = 60}, // 15 creates per minute
45 [RATE_EVENT_SESSION_LOOKUP] = {.max_events = 45, .window_secs = 60}, // 45 lookups per minute
46 [RATE_EVENT_SESSION_JOIN] = {.max_events = 30, .window_secs = 60}, // 30 joins per minute
47 [RATE_EVENT_CONNECTION] = {.max_events = 75, .window_secs = 60}, // 75 connections per minute
48 [RATE_EVENT_IMAGE_FRAME] = {.max_events = 12960, .window_secs = 60}, // 12960 frames/min = 216 FPS
49 [RATE_EVENT_AUDIO] = {.max_events = 15480, .window_secs = 60}, // 15480 packets/min = 258 FPS
50 [RATE_EVENT_PING] = {.max_events = 180, .window_secs = 60}, // 180 pings/min = 3 Hz
51 [RATE_EVENT_CLIENT_JOIN] = {.max_events = 25, .window_secs = 60}, // 25 joins per minute (for testing reconnects)
52 [RATE_EVENT_CONTROL] = {.max_events = 150, .window_secs = 60}, // 150 control packets/min
53#endif
54};
55
56// ============================================================================
57// Backend Interface
58// ============================================================================
59
67
68// ============================================================================
69// Public API Implementation
70// ============================================================================
71
73 rate_limiter_t *limiter = malloc(sizeof(rate_limiter_t));
74 if (!limiter) {
75 log_error("Failed to allocate rate limiter");
76 return NULL;
77 }
78
80 if (!limiter->backend_data) {
81 free(limiter);
82 return NULL;
83 }
84
85 limiter->ops = &memory_backend_ops;
86 return limiter;
87}
88
90 rate_limiter_t *limiter = malloc(sizeof(rate_limiter_t));
91 if (!limiter) {
92 log_error("Failed to allocate rate limiter");
93 return NULL;
94 }
95
96 limiter->backend_data = sqlite_backend_create(db_path);
97 if (!limiter->backend_data) {
98 free(limiter);
99 return NULL;
100 }
101
102 limiter->ops = &sqlite_backend_ops;
103 return limiter;
104}
105
107 if (!limiter || !limiter->backend_data) {
108 return;
109 }
110
111 // Call the SQLite backend function to set the database handle
112 sqlite_backend_set_db(limiter->backend_data, (sqlite3 *)db);
113}
114
116 if (!limiter) {
117 return;
118 }
119
120 if (limiter->ops && limiter->ops->destroy) {
121 limiter->ops->destroy(limiter->backend_data);
122 }
123
124 free(limiter);
125}
126
127asciichat_error_t rate_limiter_check(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type,
128 const rate_limit_config_t *config, bool *allowed) {
129 if (!limiter || !limiter->ops || !limiter->ops->check) {
130 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rate limiter");
131 }
132
133 if (!ip_address || !allowed) {
134 return SET_ERRNO(ERROR_INVALID_PARAM, "ip_address or allowed is NULL");
135 }
136
137 if (event_type >= RATE_EVENT_MAX) {
138 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid event_type: %d", event_type);
139 }
140
141 return limiter->ops->check(limiter->backend_data, ip_address, event_type, config, allowed);
142}
143
144asciichat_error_t rate_limiter_record(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type) {
145 if (!limiter || !limiter->ops || !limiter->ops->record) {
146 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rate limiter");
147 }
148
149 if (!ip_address) {
150 return SET_ERRNO(ERROR_INVALID_PARAM, "ip_address is NULL");
151 }
152
153 if (event_type >= RATE_EVENT_MAX) {
154 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid event_type: %d", event_type);
155 }
156
157 return limiter->ops->record(limiter->backend_data, ip_address, event_type);
158}
159
161 if (!limiter || !limiter->ops || !limiter->ops->cleanup) {
162 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rate limiter");
163 }
164
165 return limiter->ops->cleanup(limiter->backend_data, max_age_secs);
166}
167
168// ============================================================================
169// Helper Functions (available to backends)
170// ============================================================================
171
176 struct timespec ts;
177 clock_gettime(CLOCK_REALTIME, &ts);
178 return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
179}
180
185 if (event_type >= RATE_EVENT_MAX) {
186 return "unknown";
187 }
188 return event_type_strings[event_type];
189}
unsigned int uint32_t
Definition common.h:58
unsigned long long uint64_t
Definition common.h:59
#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)
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
#define log_error(...)
Log an ERROR message.
📝 Logging API with multiple log levels and terminal output control
void * memory_backend_create(void)
Create memory backend instance.
const rate_limiter_backend_ops_t memory_backend_ops
Memory backend operations vtable.
🧠 In-memory rate limiting backend interface
asciichat_error_t rate_limiter_cleanup(rate_limiter_t *limiter, uint32_t max_age_secs)
Clean up old rate limit events.
Definition rate_limit.c:160
asciichat_error_t rate_limiter_record(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type)
Record a rate limit event.
Definition rate_limit.c:144
void rate_limiter_destroy(rate_limiter_t *limiter)
Destroy rate limiter and free resources.
Definition rate_limit.c:115
void rate_limiter_set_sqlite_db(rate_limiter_t *limiter, void *db)
Set SQLite database handle for rate limiter.
Definition rate_limit.c:106
rate_limiter_t * rate_limiter_create_memory(void)
Create in-memory rate limiter.
Definition rate_limit.c:72
uint64_t rate_limiter_get_time_ms(void)
Get current time in milliseconds.
Definition rate_limit.c:175
const char * rate_limiter_event_type_string(rate_event_type_t event_type)
Get event type string for logging.
Definition rate_limit.c:184
rate_limiter_t * rate_limiter_create_sqlite(const char *db_path)
Create SQLite-backed rate limiter.
Definition rate_limit.c:89
asciichat_error_t rate_limiter_check(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type, const rate_limit_config_t *config, bool *allowed)
Check if an event from an IP address should be rate limited.
Definition rate_limit.c:127
const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX]
Default rate limits for each event type.
Definition rate_limit.c:29
🚦 Rate limiting API with pluggable backends
rate_event_type_t
Rate limit event types.
Definition rate_limit.h:46
@ RATE_EVENT_SESSION_LOOKUP
Session lookup.
Definition rate_limit.h:49
@ RATE_EVENT_CONTROL
Control packets (CAPABILITIES, STREAM_START/STOP, LEAVE)
Definition rate_limit.h:58
@ RATE_EVENT_SESSION_JOIN
Session join.
Definition rate_limit.h:50
@ RATE_EVENT_CONNECTION
New connection.
Definition rate_limit.h:53
@ RATE_EVENT_PING
Ping/pong keepalive (PACKET_TYPE_PING, PACKET_TYPE_PONG)
Definition rate_limit.h:56
@ RATE_EVENT_SESSION_CREATE
Session creation.
Definition rate_limit.h:48
@ RATE_EVENT_AUDIO
Audio packet (PACKET_TYPE_AUDIO, PACKET_TYPE_AUDIO_BATCH)
Definition rate_limit.h:55
@ RATE_EVENT_MAX
Sentinel value.
Definition rate_limit.h:60
@ RATE_EVENT_IMAGE_FRAME
Image frame from client (PACKET_TYPE_IMAGE_FRAME)
Definition rate_limit.h:54
@ RATE_EVENT_CLIENT_JOIN
Client join request (PACKET_TYPE_CLIENT_JOIN)
Definition rate_limit.h:57
void sqlite_backend_set_db(void *backend_data, sqlite3 *db)
Set SQLite database handle for backend.
Definition sqlite.c:179
void * sqlite_backend_create(const char *db_path)
Create SQLite backend instance.
Definition sqlite.c:157
const rate_limiter_backend_ops_t sqlite_backend_ops
SQLite backend operations vtable.
Definition sqlite.c:186
💾 SQLite rate limiting backend interface
Rate limit configuration.
Definition rate_limit.h:66
uint32_t max_events
Maximum events allowed.
Definition rate_limit.h:67
Backend operations vtable.
Definition rate_limit.h:83
void(* destroy)(void *backend_data)
Definition rate_limit.h:91
asciichat_error_t(* cleanup)(void *backend_data, uint32_t max_age_secs)
Definition rate_limit.h:89
asciichat_error_t(* record)(void *backend_data, const char *ip_address, rate_event_type_t event_type)
Definition rate_limit.h:87
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)
Definition rate_limit.h:84
Rate limiter structure.
Definition rate_limit.c:63
void * backend_data
Backend-specific data.
Definition rate_limit.c:65
const rate_limiter_backend_ops_t * ops
Backend operations.
Definition rate_limit.c:64
⏱️ High-precision timing utilities using sokol_time.h and uthash