ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
rate_limit.c File Reference

🚦 Rate limiting implementation with backend abstraction More...

Go to the source code of this file.

Data Structures

struct  rate_limiter_s
 Rate limiter structure. More...
 

Functions

rate_limiter_t * rate_limiter_create_memory (void)
 
rate_limiter_t * rate_limiter_create_sqlite (const char *db_path)
 
void rate_limiter_set_sqlite_db (rate_limiter_t *limiter, void *db)
 
void rate_limiter_destroy (rate_limiter_t *limiter)
 
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)
 
asciichat_error_t rate_limiter_record (rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type)
 
asciichat_error_t rate_limiter_prune (rate_limiter_t *limiter, uint32_t max_age_secs)
 
const char * rate_limiter_event_type_string (rate_event_type_t event_type)
 Get event type string for logging.
 

Variables

const rate_limit_config_t DEFAULT_RATE_LIMITS [RATE_EVENT_MAX]
 

Detailed Description

🚦 Rate limiting implementation with backend abstraction

Definition in file rate_limit.c.

Function Documentation

◆ rate_limiter_check()

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 at line 128 of file rate_limit.c.

129 {
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}

Referenced by check_and_record_rate_limit().

◆ rate_limiter_create_memory()

rate_limiter_t * rate_limiter_create_memory ( void  )

Definition at line 73 of file rate_limit.c.

73 {
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}
void * memory_backend_create(void)
const rate_limiter_backend_ops_t memory_backend_ops

References memory_backend_create(), and memory_backend_ops.

Referenced by server_main().

◆ rate_limiter_create_sqlite()

rate_limiter_t * rate_limiter_create_sqlite ( const char *  db_path)

Definition at line 90 of file rate_limit.c.

90 {
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}
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

References sqlite_backend_create(), and sqlite_backend_ops.

Referenced by acds_server_init().

◆ rate_limiter_destroy()

void rate_limiter_destroy ( rate_limiter_t *  limiter)

Definition at line 116 of file rate_limit.c.

116 {
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}

Referenced by acds_server_init(), acds_server_shutdown(), and server_main().

◆ rate_limiter_event_type_string()

const char * rate_limiter_event_type_string ( rate_event_type_t  event_type)

Get event type string for logging.

Definition at line 176 of file rate_limit.c.

176 {
177 if (event_type >= RATE_EVENT_MAX) {
178 return "unknown";
179 }
180 return event_type_strings[event_type];
181}

◆ rate_limiter_prune()

asciichat_error_t rate_limiter_prune ( rate_limiter_t *  limiter,
uint32_t  max_age_secs 
)

Definition at line 161 of file rate_limit.c.

161 {
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}

◆ rate_limiter_record()

asciichat_error_t rate_limiter_record ( rate_limiter_t *  limiter,
const char *  ip_address,
rate_event_type_t  event_type 
)

Definition at line 145 of file rate_limit.c.

145 {
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}

Referenced by check_and_record_rate_limit().

◆ rate_limiter_set_sqlite_db()

void rate_limiter_set_sqlite_db ( rate_limiter_t *  limiter,
void *  db 
)

Definition at line 107 of file rate_limit.c.

107 {
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}
void sqlite_backend_set_db(void *backend_data, sqlite3 *db)
Set SQLite database handle for backend.
Definition sqlite.c:167

References sqlite_backend_set_db().

Referenced by acds_server_init().

Variable Documentation

◆ DEFAULT_RATE_LIMITS

const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX]
Initial value:
= {
[RATE_EVENT_SESSION_CREATE] = {.max_events = 15, .window_secs = 60},
[RATE_EVENT_SESSION_LOOKUP] = {.max_events = 45, .window_secs = 60},
[RATE_EVENT_SESSION_JOIN] = {.max_events = 30, .window_secs = 60},
[RATE_EVENT_CONNECTION] = {.max_events = 75, .window_secs = 60},
[RATE_EVENT_IMAGE_FRAME] = {.max_events = 12960, .window_secs = 60},
[RATE_EVENT_AUDIO] = {.max_events = 15480, .window_secs = 60},
[RATE_EVENT_PING] = {.max_events = 180, .window_secs = 60},
[RATE_EVENT_CLIENT_JOIN] = {.max_events = 25, .window_secs = 60},
[RATE_EVENT_CONTROL] = {.max_events = 150, .window_secs = 60},
}

Definition at line 30 of file rate_limit.c.

30 {
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};