ascii-chat 0.8.38
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
6#include <ascii-chat/network/rate_limit/rate_limit.h>
7#include <ascii-chat/network/rate_limit/memory.h>
8#include <ascii-chat/network/rate_limit/sqlite.h>
9#include <ascii-chat/log/logging.h>
10#include <ascii-chat/util/time.h>
11#include <stdlib.h>
12#include <string.h>
13#include <time.h>
14
15// Event type strings for logging
16static const char *event_type_strings[RATE_EVENT_MAX] = {
17 [RATE_EVENT_SESSION_CREATE] = "session_create",
18 [RATE_EVENT_SESSION_LOOKUP] = "session_lookup",
19 [RATE_EVENT_SESSION_JOIN] = "session_join",
20 [RATE_EVENT_CONNECTION] = "connection",
21 [RATE_EVENT_IMAGE_FRAME] = "image_frame",
22 [RATE_EVENT_AUDIO] = "audio",
23 [RATE_EVENT_PING] = "ping",
24 [RATE_EVENT_CLIENT_JOIN] = "client_join",
25 [RATE_EVENT_CONTROL] = "control",
26};
27
28// Default rate limits: conservative defaults to prevent abuse
29// Debug builds have relaxed limits for development/testing
30const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX] = {
31// ACDS discovery server limits
32#ifdef NDEBUG
33 // Release mode: production limits (144 FPS video, 172 FPS audio)
34 [RATE_EVENT_SESSION_CREATE] = {.max_events = 10, .window_secs = 60}, // 10 creates per minute
35 [RATE_EVENT_SESSION_LOOKUP] = {.max_events = 30, .window_secs = 60}, // 30 lookups per minute
36 [RATE_EVENT_SESSION_JOIN] = {.max_events = 20, .window_secs = 60}, // 20 joins per minute
37 [RATE_EVENT_CONNECTION] = {.max_events = 50, .window_secs = 60}, // 50 connections per minute
38 [RATE_EVENT_IMAGE_FRAME] = {.max_events = 8640, .window_secs = 60}, // 8640 frames/min = 144 FPS
39 [RATE_EVENT_AUDIO] = {.max_events = 10320, .window_secs = 60}, // 10320 packets/min = 172 FPS
40 [RATE_EVENT_PING] = {.max_events = 120, .window_secs = 60}, // 120 pings/min = 2 Hz max
41 [RATE_EVENT_CLIENT_JOIN] = {.max_events = 10, .window_secs = 60}, // 10 joins per minute
42 [RATE_EVENT_CONTROL] = {.max_events = 100, .window_secs = 60}, // 100 control packets/min
43#else
44 // Debug mode: slightly relaxed limits for development/testing (1.5x production limits)
45 [RATE_EVENT_SESSION_CREATE] = {.max_events = 15, .window_secs = 60}, // 15 creates per minute
46 [RATE_EVENT_SESSION_LOOKUP] = {.max_events = 45, .window_secs = 60}, // 45 lookups per minute
47 [RATE_EVENT_SESSION_JOIN] = {.max_events = 30, .window_secs = 60}, // 30 joins per minute
48 [RATE_EVENT_CONNECTION] = {.max_events = 75, .window_secs = 60}, // 75 connections per minute
49 [RATE_EVENT_IMAGE_FRAME] = {.max_events = 12960, .window_secs = 60}, // 12960 frames/min = 216 FPS
50 [RATE_EVENT_AUDIO] = {.max_events = 15480, .window_secs = 60}, // 15480 packets/min = 258 FPS
51 [RATE_EVENT_PING] = {.max_events = 180, .window_secs = 60}, // 180 pings/min = 3 Hz
52 [RATE_EVENT_CLIENT_JOIN] = {.max_events = 25, .window_secs = 60}, // 25 joins per minute (for testing reconnects)
53 [RATE_EVENT_CONTROL] = {.max_events = 150, .window_secs = 60}, // 150 control packets/min
54#endif
55};
56
57// ============================================================================
58// Backend Interface
59// ============================================================================
60
65 const rate_limiter_backend_ops_t *ops;
67};
68
69// ============================================================================
70// Public API Implementation
71// ============================================================================
72
73rate_limiter_t *rate_limiter_create_memory(void) {
74 rate_limiter_t *limiter = malloc(sizeof(rate_limiter_t));
75 if (!limiter) {
76 log_error("Failed to allocate rate limiter");
77 return NULL;
78 }
79
80 limiter->backend_data = memory_backend_create();
81 if (!limiter->backend_data) {
82 free(limiter);
83 return NULL;
84 }
85
86 limiter->ops = &memory_backend_ops;
87 return limiter;
88}
89
90rate_limiter_t *rate_limiter_create_sqlite(const char *db_path) {
91 rate_limiter_t *limiter = malloc(sizeof(rate_limiter_t));
92 if (!limiter) {
93 log_error("Failed to allocate rate limiter");
94 return NULL;
95 }
96
97 limiter->backend_data = sqlite_backend_create(db_path);
98 if (!limiter->backend_data) {
99 free(limiter);
100 return NULL;
101 }
102
103 limiter->ops = &sqlite_backend_ops;
104 return limiter;
105}
106
107void rate_limiter_set_sqlite_db(rate_limiter_t *limiter, void *db) {
108 if (!limiter || !limiter->backend_data) {
109 return;
110 }
111
112 // Call the SQLite backend function to set the database handle
113 sqlite_backend_set_db(limiter->backend_data, (sqlite3 *)db);
114}
115
116void rate_limiter_destroy(rate_limiter_t *limiter) {
117 if (!limiter) {
118 return;
119 }
120
121 if (limiter->ops && limiter->ops->destroy) {
122 limiter->ops->destroy(limiter->backend_data);
123 }
124
125 free(limiter);
126}
127
128asciichat_error_t rate_limiter_check(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type,
129 const rate_limit_config_t *config, bool *allowed) {
130 if (!limiter || !limiter->ops || !limiter->ops->check) {
131 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rate limiter");
132 }
133
134 if (!ip_address || !allowed) {
135 return SET_ERRNO(ERROR_INVALID_PARAM, "ip_address or allowed is NULL");
136 }
137
138 if (event_type >= RATE_EVENT_MAX) {
139 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid event_type: %d", event_type);
140 }
141
142 return limiter->ops->check(limiter->backend_data, ip_address, event_type, config, allowed);
143}
144
145asciichat_error_t rate_limiter_record(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type) {
146 if (!limiter || !limiter->ops || !limiter->ops->record) {
147 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rate limiter");
148 }
149
150 if (!ip_address) {
151 return SET_ERRNO(ERROR_INVALID_PARAM, "ip_address is NULL");
152 }
153
154 if (event_type >= RATE_EVENT_MAX) {
155 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid event_type: %d", event_type);
156 }
157
158 return limiter->ops->record(limiter->backend_data, ip_address, event_type);
159}
160
161asciichat_error_t rate_limiter_prune(rate_limiter_t *limiter, uint32_t max_age_secs) {
162 if (!limiter || !limiter->ops || !limiter->ops->cleanup) {
163 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid rate limiter");
164 }
165
166 return limiter->ops->cleanup(limiter->backend_data, max_age_secs);
167}
168
169// ============================================================================
170// Helper Functions (available to backends)
171// ============================================================================
172
176const char *rate_limiter_event_type_string(rate_event_type_t event_type) {
177 if (event_type >= RATE_EVENT_MAX) {
178 return "unknown";
179 }
180 return event_type_strings[event_type];
181}
void * memory_backend_create(void)
const rate_limiter_backend_ops_t memory_backend_ops
asciichat_error_t rate_limiter_record(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type)
Definition rate_limit.c:145
void rate_limiter_destroy(rate_limiter_t *limiter)
Definition rate_limit.c:116
void rate_limiter_set_sqlite_db(rate_limiter_t *limiter, void *db)
Definition rate_limit.c:107
rate_limiter_t * rate_limiter_create_memory(void)
Definition rate_limit.c:73
const char * rate_limiter_event_type_string(rate_event_type_t event_type)
Get event type string for logging.
Definition rate_limit.c:176
rate_limiter_t * rate_limiter_create_sqlite(const char *db_path)
Definition rate_limit.c:90
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)
Definition rate_limit.c:128
const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX]
Definition rate_limit.c:30
asciichat_error_t rate_limiter_prune(rate_limiter_t *limiter, uint32_t max_age_secs)
Definition rate_limit.c:161
void sqlite_backend_set_db(void *backend_data, sqlite3 *db)
Set SQLite database handle for backend.
Definition sqlite.c:167
void * sqlite_backend_create(const char *db_path)
Definition sqlite.c:145
const rate_limiter_backend_ops_t sqlite_backend_ops
Definition sqlite.c:174
Rate limiter structure.
Definition rate_limit.c:64
void * backend_data
Backend-specific data.
Definition rate_limit.c:66
const rate_limiter_backend_ops_t * ops
Backend operations.
Definition rate_limit.c:65