ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
sqlite.c
Go to the documentation of this file.
1
9#include "log/logging.h"
10#include <sqlite3.h>
11#include <string.h>
12
16typedef struct {
17 sqlite3 *db;
19
20// Event type strings for database storage
21static const char *event_type_strings[RATE_EVENT_MAX] = {
22 [RATE_EVENT_SESSION_CREATE] = "session_create",
23 [RATE_EVENT_SESSION_LOOKUP] = "session_lookup",
24 [RATE_EVENT_SESSION_JOIN] = "session_join",
25 [RATE_EVENT_CONNECTION] = "connection",
26 [RATE_EVENT_IMAGE_FRAME] = "image_frame",
27 [RATE_EVENT_AUDIO] = "audio",
28 [RATE_EVENT_PING] = "ping",
29 [RATE_EVENT_CLIENT_JOIN] = "client_join",
30 [RATE_EVENT_CONTROL] = "control",
31};
32
33static asciichat_error_t sqlite_check(void *backend_data, const char *ip_address, rate_event_type_t event_type,
34 const rate_limit_config_t *config, bool *allowed) {
35 sqlite_backend_t *backend = (sqlite_backend_t *)backend_data;
36
37 // Use provided config or default
38 const rate_limit_config_t *limit = config ? config : &DEFAULT_RATE_LIMITS[event_type];
39
40 // Get current time
42 uint64_t window_start_ms = now_ms - ((uint64_t)limit->window_secs * 1000);
43
44 // Count events in the time window
45 const char *sql = "SELECT COUNT(*) FROM rate_events "
46 "WHERE ip_address = ? AND event_type = ? AND timestamp >= ?";
47
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));
52 }
53
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);
57
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));
62 }
63
64 uint32_t event_count = (uint32_t)sqlite3_column_int(stmt, 0);
65 sqlite3_finalize(stmt);
66
67 // Check if limit exceeded
68 *allowed = (event_count < limit->max_events);
69
70 if (!*allowed) {
71 log_warn("Rate limit exceeded for %s (event: %s, count: %u/%u)", ip_address,
72 rate_limiter_event_type_string(event_type), event_count, limit->max_events);
73 }
74
75 return ASCIICHAT_OK;
76}
77
78static asciichat_error_t sqlite_record(void *backend_data, const char *ip_address, rate_event_type_t event_type) {
79 sqlite_backend_t *backend = (sqlite_backend_t *)backend_data;
80
81 // Get current time
83
84 // Insert event
85 const char *sql = "INSERT INTO rate_events (ip_address, event_type, timestamp) VALUES (?, ?, ?)";
86
87 sqlite3_stmt *stmt = NULL;
88 int rc = sqlite3_prepare_v2(backend->db, sql, -1, &stmt, NULL);
89 if (rc != SQLITE_OK) {
90 return SET_ERRNO(ERROR_CONFIG, "Failed to prepare rate limit insert: %s", sqlite3_errmsg(backend->db));
91 }
92
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);
96
97 rc = sqlite3_step(stmt);
98 sqlite3_finalize(stmt);
99
100 if (rc != SQLITE_DONE) {
101 return SET_ERRNO(ERROR_CONFIG, "Failed to record rate event: %s", sqlite3_errmsg(backend->db));
102 }
103
104 log_debug("Rate event recorded: %s - %s", ip_address, rate_limiter_event_type_string(event_type));
105 return ASCIICHAT_OK;
106}
107
108static asciichat_error_t sqlite_cleanup(void *backend_data, uint32_t max_age_secs) {
109 sqlite_backend_t *backend = (sqlite_backend_t *)backend_data;
110
111 // Default to 1 hour cleanup window
112 if (max_age_secs == 0) {
113 max_age_secs = 3600;
114 }
115
116 // Calculate cutoff time
118 uint64_t cutoff_ms = now_ms - ((uint64_t)max_age_secs * 1000);
119
120 // Delete old events
121 const char *sql = "DELETE FROM rate_events WHERE timestamp < ?";
122
123 sqlite3_stmt *stmt = NULL;
124 int rc = sqlite3_prepare_v2(backend->db, sql, -1, &stmt, NULL);
125 if (rc != SQLITE_OK) {
126 return SET_ERRNO(ERROR_CONFIG, "Failed to prepare rate limit cleanup: %s", sqlite3_errmsg(backend->db));
127 }
128
129 sqlite3_bind_int64(stmt, 1, (sqlite3_int64)cutoff_ms);
130
131 rc = sqlite3_step(stmt);
132 int changes = sqlite3_changes(backend->db);
133 sqlite3_finalize(stmt);
134
135 if (rc != SQLITE_DONE) {
136 return SET_ERRNO(ERROR_CONFIG, "Failed to cleanup rate events: %s", sqlite3_errmsg(backend->db));
137 }
138
139 if (changes > 0) {
140 log_debug("Cleaned up %d old rate events", changes);
141 }
142
143 return ASCIICHAT_OK;
144}
145
146static void sqlite_destroy(void *backend_data) {
147 sqlite_backend_t *backend = (sqlite_backend_t *)backend_data;
148 if (!backend) {
149 return;
150 }
151
152 // Note: We don't close the database here because it's owned by the caller
153 // (ACDS server manages the database lifecycle)
154 free(backend);
155}
156
157void *sqlite_backend_create(const char *db_path) {
158 (void)db_path; // Database is provided externally, not created here
159
160 sqlite_backend_t *backend = malloc(sizeof(sqlite_backend_t));
161 if (!backend) {
162 log_error("Failed to allocate SQLite backend");
163 return NULL;
164 }
165
166 memset(backend, 0, sizeof(*backend));
167
168 // Database handle will be set after creation by ACDS
169 // This is a placeholder backend that will be initialized later
170 log_debug("SQLite rate limiter backend allocated (database will be set externally)");
171 return backend;
172}
173
179void sqlite_backend_set_db(void *backend_data, sqlite3 *db) {
180 sqlite_backend_t *backend = (sqlite_backend_t *)backend_data;
181 if (backend) {
182 backend->db = db;
183 }
184}
185
187 .check = sqlite_check,
188 .record = sqlite_record,
189 .cleanup = sqlite_cleanup,
190 .destroy = sqlite_destroy,
191};
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
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_CONFIG
Definition error_codes.h:54
#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.
Definition rate_limit.c:175
const char * rate_limiter_event_type_string(rate_event_type_t event_type)
Helper: Get event type string for logging.
Definition rate_limit.c:184
const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX]
Default rate limits for each event type.
Definition rate_limit.c:29
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 window_secs
Time window in seconds.
Definition rate_limit.h:68
Backend operations vtable.
Definition rate_limit.h:83
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
SQLite backend data.
Definition sqlite.c:16
sqlite3 * db
SQLite database handle.
Definition sqlite.c:17