Refactor code for consistency and readability

- Updated function parameter formatting to use consistent pointer notation.
- Removed unnecessary whitespace and adjusted comments for clarity.
- Improved variable declarations and initializations in websocket.c for better readability.
- Ensured consistent use of types and formatting across server_config and websocket headers.
- Enhanced overall code style to align with best practices.
This commit is contained in:
2025-12-17 15:26:36 +01:00
parent c1a3aff71e
commit a38df76922
12 changed files with 1100 additions and 1024 deletions

View File

@@ -15,7 +15,7 @@ typedef enum
CONFIG_RUNNING, CONFIG_RUNNING,
CONFIG_SERVER_NAME, CONFIG_SERVER_NAME,
CONFIG_LOG_MODE, CONFIG_LOG_MODE,
CONFIG_VERBOSE, // Keep for backwards compatibility CONFIG_VERBOSE, // Keep for backwards compatibility
CONFIG_ENABLE_HTTP2, CONFIG_ENABLE_HTTP2,
CONFIG_ENABLE_WEBSOCKET, CONFIG_ENABLE_WEBSOCKET,
CONFIG_WWW_PATH, CONFIG_WWW_PATH,
@@ -23,14 +23,11 @@ typedef enum
CONFIG_SSL_CERT_PATH, CONFIG_SSL_CERT_PATH,
CONFIG_SSL_KEY_PATH, CONFIG_SSL_KEY_PATH,
CONFIG_UNKNOWN CONFIG_UNKNOWN
} ConfigKey; } ConfigKey;
// Trim whitespace from both ends of a string // Trim whitespace from both ends of a string
static char *trim_whitespace(char *str) static char* trim_whitespace(char* str)
{ {
char *end;
// Trim leading space // Trim leading space
while (isspace((unsigned char)*str)) while (isspace((unsigned char)*str))
str++; str++;
@@ -39,7 +36,7 @@ static char *trim_whitespace(char *str)
return str; return str;
// Trim trailing space // Trim trailing space
end = str + strlen(str) - 1; char* end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) while (end > str && isspace((unsigned char)*end))
end--; end--;
@@ -48,7 +45,7 @@ static char *trim_whitespace(char *str)
} }
// Parse a boolean value (true/false, yes/no, on/off, 1/0) // Parse a boolean value (true/false, yes/no, on/off, 1/0)
static bool parse_bool(const char *value) static bool parse_bool(const char* value)
{ {
if (strcasecmp(value, "true") == 0 || if (strcasecmp(value, "true") == 0 ||
strcasecmp(value, "yes") == 0 || strcasecmp(value, "yes") == 0 ||
@@ -59,8 +56,9 @@ static bool parse_bool(const char *value)
} }
return false; return false;
} }
// Parse log mode value (off/classic/debug/advanced) // Parse log mode value (off/classic/debug/advanced)
static LogMode parse_log_mode(const char *value) static LogMode parse_log_mode(const char* value)
{ {
if (strcasecmp(value, "off") == 0 || strcmp(value, "0") == 0) if (strcasecmp(value, "off") == 0 || strcmp(value, "0") == 0)
return LOG_MODE_OFF; return LOG_MODE_OFF;
@@ -71,15 +69,15 @@ static LogMode parse_log_mode(const char *value)
return LOG_MODE_DEBUG; return LOG_MODE_DEBUG;
if (strcasecmp(value, "advanced") == 0) if (strcasecmp(value, "advanced") == 0)
return LOG_MODE_ADVANCED; return LOG_MODE_ADVANCED;
return LOG_MODE_CLASSIC; // Default return LOG_MODE_CLASSIC; // Default
} }
// Map string to enum // Map string to enum
static ConfigKey get_config_key(const char *key) static ConfigKey get_config_key(const char* key)
{ {
static const struct static const struct
{ {
const char *name; const char* name;
ConfigKey key; ConfigKey key;
} key_map[] = { } key_map[] = {
{"port", CONFIG_PORT}, {"port", CONFIG_PORT},
@@ -89,7 +87,7 @@ static ConfigKey get_config_key(const char *key)
{"running", CONFIG_RUNNING}, {"running", CONFIG_RUNNING},
{"server_name", CONFIG_SERVER_NAME}, {"server_name", CONFIG_SERVER_NAME},
{"log_mode", CONFIG_LOG_MODE}, {"log_mode", CONFIG_LOG_MODE},
{"verbose", CONFIG_VERBOSE}, // Keep for backwards compatibility {"verbose", CONFIG_VERBOSE}, // Keep for backwards compatibility
{"enable_http2", CONFIG_ENABLE_HTTP2}, {"enable_http2", CONFIG_ENABLE_HTTP2},
{"enable_websocket", CONFIG_ENABLE_WEBSOCKET}, {"enable_websocket", CONFIG_ENABLE_WEBSOCKET},
{"www_path", CONFIG_WWW_PATH}, {"www_path", CONFIG_WWW_PATH},
@@ -109,15 +107,15 @@ static ConfigKey get_config_key(const char *key)
return CONFIG_UNKNOWN; return CONFIG_UNKNOWN;
} }
int load_config(const char *filename, ServerConfig *config) int load_config(const char* filename, ServerConfig* config)
{ {
if (!filename || strlen(filename) > 4096) if (!filename || strlen(filename) > 4096)
{ {
fprintf(stderr, "Invalid config filename\n"); fprintf(stderr, "Invalid config filename\n");
return 1; return 1;
} }
FILE *fp = fopen(filename, "r"); FILE* fp = fopen(filename, "r");
if (!fp) if (!fp)
{ {
perror("Error opening config file"); perror("Error opening config file");
@@ -135,7 +133,7 @@ int load_config(const char *filename, ServerConfig *config)
line[strcspn(line, "\r\n")] = 0; line[strcspn(line, "\r\n")] = 0;
// Trim whitespace // Trim whitespace
char *trimmed = trim_whitespace(line); char* trimmed = trim_whitespace(line);
// Skip empty lines and comments // Skip empty lines and comments
if (trimmed[0] == '\0' || trimmed[0] == '#' || trimmed[0] == ';') if (trimmed[0] == '\0' || trimmed[0] == '#' || trimmed[0] == ';')
@@ -144,7 +142,7 @@ int load_config(const char *filename, ServerConfig *config)
} }
// Find the delimiter (= or space) // Find the delimiter (= or space)
char *delim = strchr(trimmed, '='); char* delim = strchr(trimmed, '=');
if (!delim) if (!delim)
{ {
// Try space as delimiter // Try space as delimiter
@@ -159,8 +157,8 @@ int load_config(const char *filename, ServerConfig *config)
// Split into key and value // Split into key and value
*delim = '\0'; *delim = '\0';
char *key = trim_whitespace(trimmed); char* key = trim_whitespace(trimmed);
char *value = trim_whitespace(delim + 1); char* value = trim_whitespace(delim + 1);
// Remove quotes from value if present // Remove quotes from value if present
if ((value[0] == '"' || value[0] == '\'') && if ((value[0] == '"' || value[0] == '\'') &&
@@ -173,7 +171,7 @@ int load_config(const char *filename, ServerConfig *config)
switch (get_config_key(key)) switch (get_config_key(key))
{ {
case CONFIG_PORT: case CONFIG_PORT:
config->port = atoi(value); config->port = strcoll(value, value);
printf("load_config: port = %d\n", config->port); printf("load_config: port = %d\n", config->port);
break; break;
@@ -189,7 +187,7 @@ int load_config(const char *filename, ServerConfig *config)
break; break;
case CONFIG_MAX_THREADS: case CONFIG_MAX_THREADS:
config->max_threads = atoi(value); config->max_threads = strcoll(value, value);
printf("load_config: max_threads = %d\n", config->max_threads); printf("load_config: max_threads = %d\n", config->max_threads);
break; break;
@@ -210,21 +208,28 @@ int load_config(const char *filename, ServerConfig *config)
if (strcmp(config->server_name, "Your_domain/IP") == 0) if (strcmp(config->server_name, "Your_domain/IP") == 0)
{ {
fprintf(stderr, "WARNING: server_name is set to default\n" fprintf(stderr, "WARNING: server_name is set to default\n"
"Please set server_name in server.conf to the server's IP address or domain name for proper operation.\n"); "Please set server_name in server.conf to the server's IP address or domain name for proper operation.\n");
} }
break; break;
case CONFIG_LOG_MODE: case CONFIG_LOG_MODE:
config->log_mode = parse_log_mode(value); config->log_mode = parse_log_mode(value);
printf("load_config: log_mode = %s\n", printf("load_config: log_mode = %s\n",
config->log_mode == LOG_MODE_OFF ? "off" : config->log_mode == LOG_MODE_OFF
config->log_mode == LOG_MODE_DEBUG ? "debug" : ? "off"
config->log_mode == LOG_MODE_ADVANCED ? "advanced" : "classic"); : config->log_mode == LOG_MODE_DEBUG
? "debug"
: config->log_mode == LOG_MODE_ADVANCED
? "advanced"
: "classic");
break; break;
case CONFIG_VERBOSE: case CONFIG_VERBOSE:
// Backwards compatibility: map verbose boolean to log_mode // Backwards compatibility: map verbose boolean to log_mode
if (parse_bool(value)) { if (parse_bool(value))
{
config->log_mode = LOG_MODE_CLASSIC; config->log_mode = LOG_MODE_CLASSIC;
} else { }
else
{
config->log_mode = LOG_MODE_OFF; config->log_mode = LOG_MODE_OFF;
} }
printf("load_config: verbose (legacy) -> log_mode = %s\n", printf("load_config: verbose (legacy) -> log_mode = %s\n",
@@ -256,7 +261,7 @@ int load_config(const char *filename, ServerConfig *config)
break; break;
case CONFIG_MAX_CONNECTIONS: case CONFIG_MAX_CONNECTIONS:
config->max_connections = atoi(value); config->max_connections = strcoll(value, value);
printf("load_config: max_connections: = %d\n", config->max_connections); printf("load_config: max_connections: = %d\n", config->max_connections);
break; break;

View File

@@ -10,19 +10,19 @@
#include <errno.h> #include <errno.h>
extern ServerConfig config; extern ServerConfig config;
extern void log_event(const char *message); extern void log_event(const char* message);
extern char *get_mime_type(const char *filepath); extern char* get_mime_type(const char* filepath);
extern char *sanitize_url(const char *url); extern char* sanitize_url(const char* url);
// ALPN callback - select HTTP/2 protocol // ALPN callback - select HTTP/2 protocol
int alpn_select_proto_cb(SSL *ssl, const unsigned char **out, int alpn_select_proto_cb(SSL* ssl, const unsigned char** out,
unsigned char *outlen, const unsigned char *in, unsigned char* outlen, const unsigned char* in,
unsigned int inlen, void *arg) unsigned int inlen, void* arg)
{ {
(void)ssl; (void)ssl;
(void)arg; (void)arg;
int ret = nghttp2_select_next_protocol((unsigned char **)out, outlen, int ret = nghttp2_select_next_protocol((unsigned char**)out, outlen,
in, inlen); in, inlen);
if (ret == 1) if (ret == 1)
@@ -37,17 +37,17 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
} }
// No match, use HTTP/1.1 as fallback // No match, use HTTP/1.1 as fallback
*out = (const unsigned char *)"http/1.1"; *out = (const unsigned char*)"http/1.1";
*outlen = 8; *outlen = 8;
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_OK;
} }
// Data read callback for nghttp2 // Data read callback for nghttp2
static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, static ssize_t file_read_callback(nghttp2_session* session, int32_t stream_id,
uint8_t *buf, size_t length, uint8_t* buf, size_t length,
uint32_t *data_flags, uint32_t* data_flags,
nghttp2_data_source *source, nghttp2_data_source* source,
void *user_data) void* user_data)
{ {
(void)session; (void)session;
(void)stream_id; (void)stream_id;
@@ -56,8 +56,7 @@ static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
int fd = source->fd; int fd = source->fd;
ssize_t nread; ssize_t nread;
while ((nread = read(fd, buf, length)) == -1 && errno == EINTR) while ((nread = read(fd, buf, length)) == -1 && errno == EINTR);
;
if (nread == -1) if (nread == -1)
{ {
@@ -73,13 +72,13 @@ static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
} }
// Send callback for nghttp2 // Send callback for nghttp2
static ssize_t send_callback(nghttp2_session *session, const uint8_t *data, static ssize_t send_callback(nghttp2_session* session, const uint8_t* data,
size_t length, int flags, void *user_data) size_t length, int flags, void* user_data)
{ {
(void)session; (void)session;
(void)flags; (void)flags;
http2_session_t *h2_session = (http2_session_t *)user_data; http2_session_t* h2_session = (http2_session_t*)user_data;
ssize_t rv; ssize_t rv;
if (h2_session->ssl) if (h2_session->ssl)
@@ -112,13 +111,13 @@ static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
} }
// Receive callback for nghttp2 // Receive callback for nghttp2
static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf, static ssize_t recv_callback(nghttp2_session* session, uint8_t* buf,
size_t length, int flags, void *user_data) size_t length, int flags, void* user_data)
{ {
(void)session; (void)session;
(void)flags; (void)flags;
http2_session_t *h2_session = (http2_session_t *)user_data; http2_session_t* h2_session = (http2_session_t*)user_data;
ssize_t rv; ssize_t rv;
if (h2_session->ssl) if (h2_session->ssl)
@@ -159,9 +158,9 @@ static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf,
} }
// Frame receive callback // Frame receive callback
static int on_frame_recv_callback(nghttp2_session *session, static int on_frame_recv_callback(nghttp2_session* session,
const nghttp2_frame *frame, const nghttp2_frame* frame,
void *user_data) void* user_data)
{ {
(void)user_data; (void)user_data;
@@ -173,28 +172,29 @@ static int on_frame_recv_callback(nghttp2_session *session,
log_event("HTTP/2: Received HEADERS frame (request)"); log_event("HTTP/2: Received HEADERS frame (request)");
// Get stream data // Get stream data
http2_stream_data_t *stream_data = http2_stream_data_t* stream_data =
(http2_stream_data_t *)nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); (http2_stream_data_t*)nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (stream_data && (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) if (stream_data && (frame->hd.flags & NGHTTP2_FLAG_END_STREAM))
{ {
// Request is complete, send response // Request is complete, send response
char *path = stream_data->request_path; char* path = stream_data->request_path;
if (strlen(path) == 0) if (strlen(path) == 0)
{ {
strcpy(path, "/"); strcpy(path, "/");
} }
// Sanitize URL // Sanitize URL
char *sanitized = sanitize_url(path); char* sanitized = sanitize_url(path);
if (!sanitized) if (!sanitized)
{ {
log_event("HTTP/2: Blocked malicious URL"); log_event("HTTP/2: Blocked malicious URL");
// Send 403 error // Send 403 error
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
{(uint8_t *)":status", (uint8_t *)"403", 7, 3, NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)":status", (uint8_t*)"403", 7, 3, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}}; {(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
};
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL); nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
break; break;
} }
@@ -213,8 +213,9 @@ static int on_frame_recv_callback(nghttp2_session *session,
// Send 404 error // Send 404 error
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
{(uint8_t *)":status", (uint8_t *)"404", 7, 3, NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)":status", (uint8_t*)"404", 7, 3, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}}; {(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
};
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL); nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
break; break;
} }
@@ -228,8 +229,9 @@ static int on_frame_recv_callback(nghttp2_session *session,
// Send 500 error // Send 500 error
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
{(uint8_t *)":status", (uint8_t *)"500", 7, 3, NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)":status", (uint8_t*)"500", 7, 3, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}}; {(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
};
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL); nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
break; break;
} }
@@ -238,17 +240,18 @@ static int on_frame_recv_callback(nghttp2_session *session,
{ {
close(fd); close(fd);
log_event("HTTP/2: File size out of bounds"); log_event("HTTP/2: File size out of bounds");
// Send 500 error // Send 500 error
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
{(uint8_t *)":status", (uint8_t *)"500", 7, 3, NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)":status", (uint8_t*)"500", 7, 3, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}}; {(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
};
nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL); nghttp2_submit_response(session, frame->hd.stream_id, hdrs, 2, NULL);
break; break;
} }
// Get MIME type // Get MIME type
char *mime_type = get_mime_type(filepath); char* mime_type = get_mime_type(filepath);
if (!mime_type) if (!mime_type)
{ {
mime_type = strdup("application/octet-stream"); mime_type = strdup("application/octet-stream");
@@ -260,7 +263,7 @@ static int on_frame_recv_callback(nghttp2_session *session,
stream_data->mime_type = mime_type; stream_data->mime_type = mime_type;
// Build response headers - allocate content length string // Build response headers - allocate content length string
char *content_length = malloc(32); char* content_length = malloc(32);
if (!content_length) if (!content_length)
{ {
close(fd); close(fd);
@@ -274,10 +277,14 @@ static int on_frame_recv_callback(nghttp2_session *session,
stream_data->content_length = content_length; stream_data->content_length = content_length;
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
{(uint8_t *)":status", (uint8_t *)"200", 7, 3, NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)":status", (uint8_t*)"200", 7, 3, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-type", (uint8_t *)mime_type, 12, strlen(mime_type), NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)"content-type", (uint8_t*)mime_type, 12, strlen(mime_type), NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-length", (uint8_t *)content_length, 14, strlen(content_length), NGHTTP2_NV_FLAG_NONE}, {
{(uint8_t *)"server", (uint8_t *)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}}; (uint8_t*)"content-length", (uint8_t*)content_length, 14, strlen(content_length),
NGHTTP2_NV_FLAG_NONE
},
{(uint8_t*)"server", (uint8_t*)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}
};
// Submit response with file data provider // Submit response with file data provider
nghttp2_data_provider data_prd; nghttp2_data_provider data_prd;
@@ -307,15 +314,15 @@ static int on_frame_recv_callback(nghttp2_session *session,
} }
// Stream close callback // Stream close callback
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, static int on_stream_close_callback(nghttp2_session* session, int32_t stream_id,
uint32_t error_code, void *user_data) uint32_t error_code, void* user_data)
{ {
(void)error_code; (void)error_code;
(void)user_data; (void)user_data;
// Get stream data and clean up // Get stream data and clean up
http2_stream_data_t *stream_data = http2_stream_data_t* stream_data =
(http2_stream_data_t *)nghttp2_session_get_stream_user_data(session, stream_id); (http2_stream_data_t*)nghttp2_session_get_stream_user_data(session, stream_id);
if (stream_data) if (stream_data)
{ {
@@ -340,11 +347,11 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
} }
// Header callback // Header callback
static int on_header_callback(nghttp2_session *session, static int on_header_callback(nghttp2_session* session,
const nghttp2_frame *frame, const nghttp2_frame* frame,
const uint8_t *name, size_t namelen, const uint8_t* name, size_t namelen,
const uint8_t *value, size_t valuelen, const uint8_t* value, size_t valuelen,
uint8_t flags, void *user_data) uint8_t flags, void* user_data)
{ {
(void)flags; (void)flags;
(void)user_data; (void)user_data;
@@ -356,8 +363,8 @@ static int on_header_callback(nghttp2_session *session,
} }
// Get stream data // Get stream data
http2_stream_data_t *stream_data = http2_stream_data_t* stream_data =
(http2_stream_data_t *)nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); (http2_stream_data_t*)nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
if (!stream_data) if (!stream_data)
{ {
@@ -367,7 +374,9 @@ static int on_header_callback(nghttp2_session *session,
// Process request headers // Process request headers
if (namelen == 5 && memcmp(name, ":path", 5) == 0) if (namelen == 5 && memcmp(name, ":path", 5) == 0)
{ {
size_t copy_len = valuelen < sizeof(stream_data->request_path) - 1 ? valuelen : sizeof(stream_data->request_path) - 1; size_t copy_len = valuelen < sizeof(stream_data->request_path) - 1
? valuelen
: sizeof(stream_data->request_path) - 1;
memcpy(stream_data->request_path, value, copy_len); memcpy(stream_data->request_path, value, copy_len);
stream_data->request_path[copy_len] = '\0'; stream_data->request_path[copy_len] = '\0';
@@ -380,9 +389,9 @@ static int on_header_callback(nghttp2_session *session,
} }
// Begin headers callback // Begin headers callback
static int on_begin_headers_callback(nghttp2_session *session, static int on_begin_headers_callback(nghttp2_session* session,
const nghttp2_frame *frame, const nghttp2_frame* frame,
void *user_data) void* user_data)
{ {
(void)session; (void)session;
(void)user_data; (void)user_data;
@@ -394,7 +403,7 @@ static int on_begin_headers_callback(nghttp2_session *session,
} }
// Allocate stream data // Allocate stream data
http2_stream_data_t *stream_data = calloc(1, sizeof(http2_stream_data_t)); http2_stream_data_t* stream_data = calloc(1, sizeof(http2_stream_data_t));
if (!stream_data) if (!stream_data)
{ {
return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -404,14 +413,14 @@ static int on_begin_headers_callback(nghttp2_session *session,
stream_data->fd = -1; stream_data->fd = -1;
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id, stream_data); nghttp2_session_set_stream_user_data(session, frame->hd.stream_id, stream_data);
free(stream_data);
return 0; return 0;
} }
// Data chunk receive callback // Data chunk receive callback
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags, static int on_data_chunk_recv_callback(nghttp2_session* session, uint8_t flags,
int32_t stream_id, const uint8_t *data, int32_t stream_id, const uint8_t* data,
size_t len, void *user_data) size_t len, void* user_data)
{ {
(void)session; (void)session;
(void)flags; (void)flags;
@@ -425,14 +434,14 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
} }
// Initialize HTTP/2 session // Initialize HTTP/2 session
int http2_session_init(http2_session_t *h2_session, int client_socket, SSL *ssl) int http2_session_init(http2_session_t* h2_session, int client_socket, SSL* ssl)
{ {
h2_session->client_socket = client_socket; h2_session->client_socket = client_socket;
h2_session->ssl = ssl; h2_session->ssl = ssl;
h2_session->handshake_complete = false; h2_session->handshake_complete = false;
// Setup callbacks // Setup callbacks
nghttp2_session_callbacks *callbacks; nghttp2_session_callbacks* callbacks;
nghttp2_session_callbacks_new(&callbacks); nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
@@ -456,7 +465,8 @@ int http2_session_init(http2_session_t *h2_session, int client_socket, SSL *ssl)
// Send initial SETTINGS frame // Send initial SETTINGS frame
nghttp2_settings_entry settings[] = { nghttp2_settings_entry settings[] = {
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}, {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100},
{NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 65535}}; {NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, 65535}
};
rv = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE, rv = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE,
settings, sizeof(settings) / sizeof(settings[0])); settings, sizeof(settings) / sizeof(settings[0]));
@@ -474,7 +484,7 @@ int http2_session_init(http2_session_t *h2_session, int client_socket, SSL *ssl)
} }
// Cleanup HTTP/2 session // Cleanup HTTP/2 session
void http2_session_cleanup(http2_session_t *h2_session) void http2_session_cleanup(http2_session_t* h2_session)
{ {
if (h2_session->session) if (h2_session->session)
{ {
@@ -484,18 +494,19 @@ void http2_session_cleanup(http2_session_t *h2_session)
} }
// Send HTTP/2 response // Send HTTP/2 response
int http2_send_response(http2_session_t *h2_session, int32_t stream_id, int http2_send_response(http2_session_t* h2_session, int32_t stream_id,
const char *data, size_t len, bool end_stream) const char* data, size_t len, bool end_stream)
{ {
(void)data; // Unused in current implementation (void)data; // Unused in current implementation
(void)len; // Unused in current implementation (void)len; // Unused in current implementation
(void)end_stream; // Unused in current implementation (void)end_stream; // Unused in current implementation
// Send response headers // Send response headers
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
{(uint8_t *)":status", (uint8_t *)"200", 7, 3, NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)":status", (uint8_t*)"200", 7, 3, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-type", (uint8_t *)"text/html", 12, 9, NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)"content-type", (uint8_t*)"text/html", 12, 9, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"server", (uint8_t *)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}}; {(uint8_t*)"server", (uint8_t*)"Carbon/2.0", 6, 10, NGHTTP2_NV_FLAG_NONE}
};
int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 3, NULL); int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 3, NULL);
if (rv != 0) if (rv != 0)
@@ -507,15 +518,16 @@ int http2_send_response(http2_session_t *h2_session, int32_t stream_id,
} }
// Send HTTP/2 error response // Send HTTP/2 error response
int http2_send_error(http2_session_t *h2_session, int32_t stream_id, int http2_send_error(http2_session_t* h2_session, int32_t stream_id,
int status_code, const char *message) int status_code, const char* message)
{ {
char status_str[4]; char status_str[4];
snprintf(status_str, sizeof(status_str), "%d", status_code); snprintf(status_str, sizeof(status_str), "%d", status_code);
nghttp2_nv hdrs[] = { nghttp2_nv hdrs[] = {
{(uint8_t *)":status", (uint8_t *)status_str, 7, strlen(status_str), NGHTTP2_NV_FLAG_NONE}, {(uint8_t*)":status", (uint8_t*)status_str, 7, strlen(status_str), NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"content-type", (uint8_t *)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}}; {(uint8_t*)"content-type", (uint8_t*)"text/plain", 12, 10, NGHTTP2_NV_FLAG_NONE}
};
int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 2, NULL); int rv = nghttp2_submit_response(h2_session->session, stream_id, hdrs, 2, NULL);
if (rv != 0) if (rv != 0)
@@ -526,7 +538,7 @@ int http2_send_error(http2_session_t *h2_session, int32_t stream_id,
if (message) if (message)
{ {
nghttp2_data_provider prd; nghttp2_data_provider prd;
prd.source.ptr = (void *)message; prd.source.ptr = (void*)message;
prd.read_callback = NULL; prd.read_callback = NULL;
nghttp2_submit_data(h2_session->session, NGHTTP2_FLAG_END_STREAM, nghttp2_submit_data(h2_session->session, NGHTTP2_FLAG_END_STREAM,
@@ -537,7 +549,7 @@ int http2_send_error(http2_session_t *h2_session, int32_t stream_id,
} }
// Handle HTTP/2 connection // Handle HTTP/2 connection
int http2_handle_connection(http2_session_t *h2_session) int http2_handle_connection(http2_session_t* h2_session)
{ {
// Receive and process frames first // Receive and process frames first
int rv = nghttp2_session_recv(h2_session->session); int rv = nghttp2_session_recv(h2_session->session);
@@ -573,4 +585,4 @@ int http2_handle_connection(http2_session_t *h2_session)
} }
return 1; return 1;
} }

View File

@@ -8,8 +8,8 @@
// HTTP/2 session context // HTTP/2 session context
typedef struct typedef struct
{ {
nghttp2_session *session; nghttp2_session* session;
SSL *ssl; SSL* ssl;
int client_socket; int client_socket;
bool handshake_complete; bool handshake_complete;
} http2_session_t; } http2_session_t;
@@ -19,25 +19,25 @@ typedef struct
{ {
int32_t stream_id; int32_t stream_id;
char request_path[256]; char request_path[256];
char *request_method; char* request_method;
int fd; // File descriptor for response int fd; // File descriptor for response
size_t file_size; size_t file_size;
char *mime_type; char* mime_type;
char *content_length; char* content_length;
} http2_stream_data_t; } http2_stream_data_t;
// Function prototypes // Function prototypes
int http2_session_init(http2_session_t *session, int client_socket, SSL *ssl); int http2_session_init(http2_session_t* session, int client_socket, SSL* ssl);
void http2_session_cleanup(http2_session_t *session); void http2_session_cleanup(http2_session_t* session);
int http2_handle_connection(http2_session_t *session); int http2_handle_connection(http2_session_t* session);
int http2_send_response(http2_session_t *session, int32_t stream_id, int http2_send_response(http2_session_t* session, int32_t stream_id,
const char *data, size_t len, bool end_stream); const char* data, size_t len, bool end_stream);
int http2_send_error(http2_session_t *session, int32_t stream_id, int http2_send_error(http2_session_t* session, int32_t stream_id,
int status_code, const char *message); int status_code, const char* message);
// ALPN callback for protocol selection // ALPN callback for protocol selection
int alpn_select_proto_cb(SSL *ssl, const unsigned char **out, int alpn_select_proto_cb(SSL* ssl, const unsigned char** out,
unsigned char *outlen, const unsigned char *in, unsigned char* outlen, const unsigned char* in,
unsigned int inlen, void *arg); unsigned int inlen, void* arg);
#endif #endif

View File

@@ -1,6 +1,5 @@
#include "logging.h" #include "logging.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -9,6 +8,7 @@
#include <errno.h> #include <errno.h>
#include <libgen.h> #include <libgen.h>
#include <ctype.h> #include <ctype.h>
#include <stdarg.h>
// ANSI color codes // ANSI color codes
#define COLOR_RESET "\x1b[0m" #define COLOR_RESET "\x1b[0m"
@@ -33,7 +33,7 @@ static LogConfig g_log_config = {
.include_source_location = false, .include_source_location = false,
.colorize_console = true, .colorize_console = true,
.log_file = "log/server.log", .log_file = "log/server.log",
.max_file_size = 100 * 1024 * 1024, // 100MB .max_file_size = 100 * 1024 * 1024, // 100MB
.max_backup_files = 5 .max_backup_files = 5
}; };
@@ -41,7 +41,8 @@ static pthread_mutex_t g_log_mutex = PTHREAD_MUTEX_INITIALIZER;
static bool g_log_initialized = false; static bool g_log_initialized = false;
// Performance tracking // Performance tracking
typedef struct { typedef struct
{
char operation[64]; char operation[64];
struct timeval start_time; struct timeval start_time;
bool active; bool active;
@@ -52,96 +53,101 @@ static PerfTracker g_perf_trackers[MAX_PERF_TRACKERS];
static pthread_mutex_t g_perf_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t g_perf_mutex = PTHREAD_MUTEX_INITIALIZER;
// Get color for log level // Get color for log level
static const char *get_level_color(LogLevel level) static const char* get_level_color(LogLevel level)
{ {
switch (level) { switch (level)
case LOG_LEVEL_ERROR: return COLOR_RED; {
case LOG_LEVEL_WARN: return COLOR_YELLOW; case LOG_LEVEL_ERROR: return COLOR_RED;
case LOG_LEVEL_INFO: return COLOR_GREEN; case LOG_LEVEL_WARN: return COLOR_YELLOW;
case LOG_LEVEL_DEBUG: return COLOR_CYAN; case LOG_LEVEL_INFO: return COLOR_GREEN;
case LOG_LEVEL_TRACE: return COLOR_MAGENTA; case LOG_LEVEL_DEBUG: return COLOR_CYAN;
default: return COLOR_WHITE; case LOG_LEVEL_TRACE: return COLOR_MAGENTA;
default: return COLOR_WHITE;
} }
} }
// Get level prefix // Get level prefix
static const char *get_level_prefix(LogLevel level) static const char* get_level_prefix(LogLevel level)
{ {
switch (level) { switch (level)
case LOG_LEVEL_ERROR: return "ERROR"; {
case LOG_LEVEL_WARN: return "WARN "; case LOG_LEVEL_ERROR: return "ERROR";
case LOG_LEVEL_INFO: return "INFO "; case LOG_LEVEL_WARN: return "WARN ";
case LOG_LEVEL_DEBUG: return "DEBUG"; case LOG_LEVEL_INFO: return "INFO ";
case LOG_LEVEL_TRACE: return "TRACE"; case LOG_LEVEL_DEBUG: return "DEBUG";
default: return "?????"; case LOG_LEVEL_TRACE: return "TRACE";
default: return "?????";
} }
} }
// Get category name // Get category name
static const char *get_category_name(LogCategory cat) static const char* get_category_name(LogCategory cat)
{ {
switch (cat) { switch (cat)
case LOG_CAT_GENERAL: return "GENERAL"; {
case LOG_CAT_SECURITY: return "SECURITY"; case LOG_CAT_GENERAL: return "GENERAL";
case LOG_CAT_NETWORK: return "NETWORK"; case LOG_CAT_SECURITY: return "SECURITY";
case LOG_CAT_HTTP: return "HTTP"; case LOG_CAT_NETWORK: return "NETWORK";
case LOG_CAT_SSL: return "SSL"; case LOG_CAT_HTTP: return "HTTP";
case LOG_CAT_WEBSOCKET: return "WEBSOCKET"; case LOG_CAT_SSL: return "SSL";
case LOG_CAT_CACHE: return "CACHE"; case LOG_CAT_WEBSOCKET: return "WEBSOCKET";
case LOG_CAT_PERFORMANCE: return "PERF"; case LOG_CAT_CACHE: return "CACHE";
default: return "UNKNOWN"; case LOG_CAT_PERFORMANCE: return "PERF";
default: return "UNKNOWN";
} }
} }
const char *log_level_to_string(LogLevel level) const char* log_level_to_string(LogLevel level)
{ {
switch (level) { switch (level)
case LOG_LEVEL_OFF: return "off"; {
case LOG_LEVEL_ERROR: return "error"; case LOG_LEVEL_OFF: return "off";
case LOG_LEVEL_WARN: return "warn"; case LOG_LEVEL_ERROR: return "error";
case LOG_LEVEL_INFO: return "info"; case LOG_LEVEL_WARN: return "warn";
case LOG_LEVEL_DEBUG: return "debug"; case LOG_LEVEL_INFO: return "info";
case LOG_LEVEL_TRACE: return "trace"; case LOG_LEVEL_DEBUG: return "debug";
default: return "unknown"; case LOG_LEVEL_TRACE: return "trace";
default: return "unknown";
} }
} }
const char *log_mode_to_string(LogLevel level) const char* log_mode_to_string(LogLevel level)
{ {
switch (level) { switch (level)
case LOG_LEVEL_OFF: return "off"; {
case LOG_LEVEL_ERROR: case LOG_LEVEL_OFF: return "off";
case LOG_LEVEL_WARN: case LOG_LEVEL_ERROR:
case LOG_LEVEL_INFO: return "classic"; case LOG_LEVEL_WARN:
case LOG_LEVEL_DEBUG: return "debug"; case LOG_LEVEL_INFO: return "classic";
case LOG_LEVEL_TRACE: return "advanced"; case LOG_LEVEL_DEBUG: return "debug";
default: return "classic"; case LOG_LEVEL_TRACE: return "advanced";
default: return "classic";
} }
} }
LogLevel log_level_from_string(const char *str) LogLevel log_level_from_string(const char* str)
{ {
if (!str) return LOG_LEVEL_INFO; if (!str) return LOG_LEVEL_INFO;
// Handle mode names // Handle mode names
if (strcasecmp(str, "off") == 0) return LOG_LEVEL_OFF; if (strcasecmp(str, "off") == 0) return LOG_LEVEL_OFF;
if (strcasecmp(str, "classic") == 0) return LOG_LEVEL_INFO; if (strcasecmp(str, "classic") == 0) return LOG_LEVEL_INFO;
if (strcasecmp(str, "debug") == 0) return LOG_LEVEL_DEBUG; if (strcasecmp(str, "debug") == 0) return LOG_LEVEL_DEBUG;
if (strcasecmp(str, "advanced") == 0) return LOG_LEVEL_TRACE; if (strcasecmp(str, "advanced") == 0) return LOG_LEVEL_TRACE;
// Handle level names // Handle level names
if (strcasecmp(str, "error") == 0) return LOG_LEVEL_ERROR; if (strcasecmp(str, "error") == 0) return LOG_LEVEL_ERROR;
if (strcasecmp(str, "warn") == 0) return LOG_LEVEL_WARN; if (strcasecmp(str, "warn") == 0) return LOG_LEVEL_WARN;
if (strcasecmp(str, "warning") == 0) return LOG_LEVEL_WARN; if (strcasecmp(str, "warning") == 0) return LOG_LEVEL_WARN;
if (strcasecmp(str, "info") == 0) return LOG_LEVEL_INFO; if (strcasecmp(str, "info") == 0) return LOG_LEVEL_INFO;
if (strcasecmp(str, "trace") == 0) return LOG_LEVEL_TRACE; if (strcasecmp(str, "trace") == 0) return LOG_LEVEL_TRACE;
// Handle boolean-like values for backwards compatibility // Handle boolean-like values for backwards compatibility
if (strcasecmp(str, "true") == 0 || strcmp(str, "1") == 0) if (strcasecmp(str, "true") == 0 || strcmp(str, "1") == 0)
return LOG_LEVEL_INFO; return LOG_LEVEL_INFO;
if (strcasecmp(str, "false") == 0 || strcmp(str, "0") == 0) if (strcasecmp(str, "false") == 0 || strcmp(str, "0") == 0)
return LOG_LEVEL_OFF; return LOG_LEVEL_OFF;
return LOG_LEVEL_INFO; return LOG_LEVEL_INFO;
} }
@@ -151,23 +157,30 @@ static void rotate_logs(void)
struct stat st; struct stat st;
if (stat(g_log_config.log_file, &st) != 0) if (stat(g_log_config.log_file, &st) != 0)
return; return;
if (st.st_size < (off_t)g_log_config.max_file_size) if (st.st_size < (off_t)g_log_config.max_file_size)
return; return;
// Rotate existing backup files // Rotate existing backup files
char old_path[512], new_path[512]; char old_path[512], new_path[512];
for (int i = g_log_config.max_backup_files - 1; i >= 0; i--) { for (int i = g_log_config.max_backup_files - 1; i >= 0; i--)
if (i == 0) { {
if (i == 0)
{
snprintf(old_path, sizeof(old_path), "%s", g_log_config.log_file); snprintf(old_path, sizeof(old_path), "%s", g_log_config.log_file);
} else { }
else
{
snprintf(old_path, sizeof(old_path), "%s.%d", g_log_config.log_file, i); snprintf(old_path, sizeof(old_path), "%s.%d", g_log_config.log_file, i);
} }
snprintf(new_path, sizeof(new_path), "%s.%d", g_log_config.log_file, i + 1); snprintf(new_path, sizeof(new_path), "%s.%d", g_log_config.log_file, i + 1);
if (i + 1 >= g_log_config.max_backup_files) { if (i + 1 >= g_log_config.max_backup_files)
{
unlink(old_path); unlink(old_path);
} else { }
else
{
rename(old_path, new_path); rename(old_path, new_path);
} }
} }
@@ -179,32 +192,35 @@ static void ensure_log_directory(void)
char log_dir[512]; char log_dir[512];
strncpy(log_dir, g_log_config.log_file, sizeof(log_dir) - 1); strncpy(log_dir, g_log_config.log_file, sizeof(log_dir) - 1);
log_dir[sizeof(log_dir) - 1] = '\0'; log_dir[sizeof(log_dir) - 1] = '\0';
char *dir_path = dirname(log_dir); char* dir_path = dirname(log_dir);
if (!dir_path || strcmp(dir_path, ".") == 0) if (!dir_path || strcmp(dir_path, ".") == 0)
return; return;
struct stat st; struct stat st;
if (stat(dir_path, &st) != 0) { if (stat(dir_path, &st) != 0)
if (mkdir(dir_path, 0755) != 0 && errno != EEXIST) { {
if (mkdir(dir_path, 0755) != 0 && errno != EEXIST)
{
fprintf(stderr, "Failed to create log directory: %s\n", strerror(errno)); fprintf(stderr, "Failed to create log directory: %s\n", strerror(errno));
} }
} }
} }
void log_init(LogConfig *config) void log_init(LogConfig* config)
{ {
pthread_mutex_lock(&g_log_mutex); pthread_mutex_lock(&g_log_mutex);
if (config) { if (config)
{
memcpy(&g_log_config, config, sizeof(LogConfig)); memcpy(&g_log_config, config, sizeof(LogConfig));
} }
ensure_log_directory(); ensure_log_directory();
g_log_initialized = true; g_log_initialized = true;
pthread_mutex_unlock(&g_log_mutex); pthread_mutex_unlock(&g_log_mutex);
LOG_INFO(LOG_CAT_GENERAL, "Logging system initialized [mode=%s, level=%s]", LOG_INFO(LOG_CAT_GENERAL, "Logging system initialized [mode=%s, level=%s]",
log_mode_to_string(g_log_config.level), log_mode_to_string(g_log_config.level),
log_level_to_string(g_log_config.level)); log_level_to_string(g_log_config.level));
@@ -231,168 +247,193 @@ void log_set_categories(LogCategory categories)
pthread_mutex_unlock(&g_log_mutex); pthread_mutex_unlock(&g_log_mutex);
} }
void log_write(LogLevel level, LogCategory category, const char *file, void log_write(LogLevel level, LogCategory category, const char* file,
int line, const char *func, const char *fmt, ...) int line, const char* func, const char* fmt, ...)
{ {
// Quick check without lock // Quick check without lock
if (level == LOG_LEVEL_OFF || g_log_config.level == LOG_LEVEL_OFF) if (level == LOG_LEVEL_OFF || g_log_config.level == LOG_LEVEL_OFF)
return; return;
if (level > g_log_config.level) if (level > g_log_config.level)
return; return;
if (!(category & g_log_config.categories)) if (!(category & g_log_config.categories))
return; return;
pthread_mutex_lock(&g_log_mutex); pthread_mutex_lock(&g_log_mutex);
// Get timestamp // Get timestamp
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
struct tm tm; struct tm tm;
localtime_r(&tv.tv_sec, &tm); localtime_r(&tv.tv_sec, &tm);
char timestamp[64] = ""; char timestamp[64] = "";
if (g_log_config.include_timestamp) { if (g_log_config.include_timestamp)
{
snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d.%03ld", snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d.%03ld",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000); tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000);
} }
// Get thread ID // Get thread ID
char thread_id[32] = ""; char thread_id[32] = "";
if (g_log_config.include_thread_id) { if (g_log_config.include_thread_id)
{
snprintf(thread_id, sizeof(thread_id), "%lu", (unsigned long)pthread_self()); snprintf(thread_id, sizeof(thread_id), "%lu", (unsigned long)pthread_self());
} }
// Get source location // Get source location
char source_loc[256] = ""; char source_loc[256] = "";
if (g_log_config.include_source_location && file && func) { if (g_log_config.include_source_location && file && func)
const char *filename = strrchr(file, '/'); {
const char* filename = strrchr(file, '/');
filename = filename ? filename + 1 : file; filename = filename ? filename + 1 : file;
snprintf(source_loc, sizeof(source_loc), "%s:%d:%s", filename, line, func); snprintf(source_loc, sizeof(source_loc), "%s:%d:%s", filename, line, func);
} }
// Format the message // Format the message
char message[4096]; char message[4096];
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vsnprintf(message, sizeof(message), fmt, args); vsnprintf(message, sizeof(message), fmt, args);
va_end(args); va_end(args);
// Build log entry based on format // Build log entry based on format
char log_entry[8192]; char log_entry[8192];
if (g_log_config.format == LOG_FORMAT_JSON) { if (g_log_config.format == LOG_FORMAT_JSON)
{
snprintf(log_entry, sizeof(log_entry), snprintf(log_entry, sizeof(log_entry),
"{\"timestamp\":\"%s\",\"level\":\"%s\",\"category\":\"%s\"," "{\"timestamp\":\"%s\",\"level\":\"%s\",\"category\":\"%s\","
"\"pid\":%d,\"tid\":\"%s\",\"source\":\"%s\",\"message\":\"%s\"}\n", "\"pid\":%d,\"tid\":\"%s\",\"source\":\"%s\",\"message\":\"%s\"}\n",
timestamp, get_level_prefix(level), get_category_name(category), timestamp, get_level_prefix(level), get_category_name(category),
getpid(), thread_id, source_loc, message); getpid(), thread_id, source_loc, message);
} else if (g_log_config.format == LOG_FORMAT_SYSLOG) { }
else if (g_log_config.format == LOG_FORMAT_SYSLOG)
{
// Syslog-compatible format // Syslog-compatible format
snprintf(log_entry, sizeof(log_entry), snprintf(log_entry, sizeof(log_entry),
"<%d>%s %s[%d]: [%s] %s\n", "<%d>%s %s[%d]: [%s] %s\n",
level, timestamp, "carbon", getpid(), level, timestamp, "carbon", getpid(),
get_category_name(category), message); get_category_name(category), message);
} else { }
else
{
// Plain text format // Plain text format
if (g_log_config.include_source_location && source_loc[0]) { if (g_log_config.include_source_location && source_loc[0])
{
snprintf(log_entry, sizeof(log_entry), snprintf(log_entry, sizeof(log_entry),
"[%s] [%s] [PID:%d] [TID:%s] [%s] [%s] %s\n", "[%s] [%s] [PID:%d] [TID:%s] [%s] [%s] %s\n",
timestamp, get_level_prefix(level), getpid(), thread_id, timestamp, get_level_prefix(level), getpid(), thread_id,
get_category_name(category), source_loc, message); get_category_name(category), source_loc, message);
} else { }
else
{
snprintf(log_entry, sizeof(log_entry), snprintf(log_entry, sizeof(log_entry),
"[%s] [%s] [PID:%d] [TID:%s] [%s] %s\n", "[%s] [%s] [PID:%d] [TID:%s] [%s] %s\n",
timestamp, get_level_prefix(level), getpid(), thread_id, timestamp, get_level_prefix(level), getpid(), thread_id,
get_category_name(category), message); get_category_name(category), message);
} }
} }
// Write to console // Write to console
if (g_log_config.console_output) { if (g_log_config.console_output)
if (g_log_config.colorize_console && isatty(STDOUT_FILENO)) { {
if (g_log_config.colorize_console && isatty(STDOUT_FILENO))
{
fprintf(stdout, "%s%s%s", get_level_color(level), log_entry, COLOR_RESET); fprintf(stdout, "%s%s%s", get_level_color(level), log_entry, COLOR_RESET);
} else { }
else
{
fputs(log_entry, stdout); fputs(log_entry, stdout);
} }
fflush(stdout); fflush(stdout);
} }
// Write to file // Write to file
if (g_log_config.file_output && g_log_config.log_file[0]) { if (g_log_config.file_output && g_log_config.log_file[0])
{
rotate_logs(); rotate_logs();
FILE *fp = fopen(g_log_config.log_file, "a"); FILE* fp = fopen(g_log_config.log_file, "a");
if (fp) { if (fp)
{
fputs(log_entry, fp); fputs(log_entry, fp);
fflush(fp); fflush(fp);
fclose(fp); fclose(fp);
} }
} }
pthread_mutex_unlock(&g_log_mutex); pthread_mutex_unlock(&g_log_mutex);
} }
// Backwards compatible log_event function // Backwards compatible log_event function
void log_event(const char *message) void log_event(const char* message)
{ {
if (!message) return; if (!message) return;
log_write(LOG_LEVEL_INFO, LOG_CAT_GENERAL, NULL, 0, NULL, "%s", message); log_write(LOG_LEVEL_INFO, LOG_CAT_GENERAL, NULL, 0, NULL, "%s", message);
} }
// Secure logging - sanitizes potentially sensitive data // Secure logging - sanitizes potentially sensitive data
void log_secure(LogLevel level, LogCategory category, const char *fmt, ...) void log_secure(LogLevel level, LogCategory category, const char* fmt, ...)
{ {
char message[4096]; char message[4096];
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
vsnprintf(message, sizeof(message), fmt, args); vsnprintf(message, sizeof(message), fmt, args);
va_end(args); va_end(args);
// Sanitize common sensitive patterns // Sanitize common sensitive patterns
char *patterns[] = { char* patterns[] = {
"password", "passwd", "pwd", "secret", "token", "key", "auth", "password", "passwd", "pwd", "secret", "token", "key", "auth",
"credential", "credit", "ssn", "api_key", "apikey", NULL "credential", "credit", "ssn", "api_key", "apikey", NULL
}; };
char sanitized[4096]; char sanitized[4096];
strncpy(sanitized, message, sizeof(sanitized) - 1); strncpy(sanitized, message, sizeof(sanitized) - 1);
sanitized[sizeof(sanitized) - 1] = '\0'; sanitized[sizeof(sanitized) - 1] = '\0';
// Convert to lowercase for pattern matching // Convert to lowercase for pattern matching
char lower[4096]; char lower[4096];
for (size_t i = 0; i < strlen(sanitized) && i < sizeof(lower) - 1; i++) { for (size_t i = 0; i < strlen(sanitized) && i < sizeof(lower) - 1; i++)
{
lower[i] = tolower((unsigned char)sanitized[i]); lower[i] = tolower((unsigned char)sanitized[i]);
} }
lower[strlen(sanitized)] = '\0'; lower[strlen(sanitized)] = '\0';
// Check for sensitive patterns // Check for sensitive patterns
bool has_sensitive = false; bool has_sensitive = false;
for (int i = 0; patterns[i]; i++) { for (int i = 0; patterns[i]; i++)
if (strstr(lower, patterns[i])) { {
if (strstr(lower, patterns[i]))
{
has_sensitive = true; has_sensitive = true;
break; break;
} }
} }
if (has_sensitive) { if (has_sensitive)
{
log_write(level, category, NULL, 0, NULL, "[REDACTED] Message contained sensitive data"); log_write(level, category, NULL, 0, NULL, "[REDACTED] Message contained sensitive data");
} else { }
else
{
log_write(level, category, NULL, 0, NULL, "%s", sanitized); log_write(level, category, NULL, 0, NULL, "%s", sanitized);
} }
} }
void log_perf_start(const char *operation) void log_perf_start(const char* operation)
{ {
if (g_log_config.level < LOG_LEVEL_DEBUG) if (g_log_config.level < LOG_LEVEL_DEBUG)
return; return;
pthread_mutex_lock(&g_perf_mutex); pthread_mutex_lock(&g_perf_mutex);
for (int i = 0; i < MAX_PERF_TRACKERS; i++) { for (int i = 0; i < MAX_PERF_TRACKERS; i++)
if (!g_perf_trackers[i].active) { {
if (!g_perf_trackers[i].active)
{
strncpy(g_perf_trackers[i].operation, operation, sizeof(g_perf_trackers[i].operation) - 1); strncpy(g_perf_trackers[i].operation, operation, sizeof(g_perf_trackers[i].operation) - 1);
g_perf_trackers[i].operation[sizeof(g_perf_trackers[i].operation) - 1] = '\0'; g_perf_trackers[i].operation[sizeof(g_perf_trackers[i].operation) - 1] = '\0';
gettimeofday(&g_perf_trackers[i].start_time, NULL); gettimeofday(&g_perf_trackers[i].start_time, NULL);
@@ -400,88 +441,106 @@ void log_perf_start(const char *operation)
break; break;
} }
} }
pthread_mutex_unlock(&g_perf_mutex); pthread_mutex_unlock(&g_perf_mutex);
} }
void log_perf_end(const char *operation) void log_perf_end(const char* operation)
{ {
if (g_log_config.level < LOG_LEVEL_DEBUG) if (g_log_config.level < LOG_LEVEL_DEBUG)
return; return;
struct timeval end_time; struct timeval end_time;
gettimeofday(&end_time, NULL); gettimeofday(&end_time, NULL);
pthread_mutex_lock(&g_perf_mutex); pthread_mutex_lock(&g_perf_mutex);
for (int i = 0; i < MAX_PERF_TRACKERS; i++) { for (int i = 0; i < MAX_PERF_TRACKERS; i++)
if (g_perf_trackers[i].active && {
strcmp(g_perf_trackers[i].operation, operation) == 0) { if (g_perf_trackers[i].active &&
strcmp(g_perf_trackers[i].operation, operation) == 0)
{
long elapsed_us = (end_time.tv_sec - g_perf_trackers[i].start_time.tv_sec) * 1000000 + long elapsed_us = (end_time.tv_sec - g_perf_trackers[i].start_time.tv_sec) * 1000000 +
(end_time.tv_usec - g_perf_trackers[i].start_time.tv_usec); (end_time.tv_usec - g_perf_trackers[i].start_time.tv_usec);
g_perf_trackers[i].active = false; g_perf_trackers[i].active = false;
pthread_mutex_unlock(&g_perf_mutex); pthread_mutex_unlock(&g_perf_mutex);
if (elapsed_us > 1000000) { if (elapsed_us > 1000000)
{
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f s", operation, elapsed_us / 1000000.0); LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f s", operation, elapsed_us / 1000000.0);
} else if (elapsed_us > 1000) { }
else if (elapsed_us > 1000)
{
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f ms", operation, elapsed_us / 1000.0); LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %.2f ms", operation, elapsed_us / 1000.0);
} else { }
else
{
LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %ld µs", operation, elapsed_us); LOG_DEBUG(LOG_CAT_PERFORMANCE, "%s completed in %ld µs", operation, elapsed_us);
} }
return; return;
} }
} }
pthread_mutex_unlock(&g_perf_mutex); pthread_mutex_unlock(&g_perf_mutex);
} }
void log_hexdump(const char *label, const void *data, size_t len) void log_hexdump(const char* label, const void* data, size_t len)
{ {
if (g_log_config.level < LOG_LEVEL_TRACE) if (g_log_config.level < LOG_LEVEL_TRACE)
return; return;
if (!data || len == 0) if (!data || len == 0)
return; return;
// Limit output size // Limit output size
if (len > 256) { if (len > 256)
{
LOG_TRACE(LOG_CAT_GENERAL, "%s: [%zu bytes, showing first 256]", label, len); LOG_TRACE(LOG_CAT_GENERAL, "%s: [%zu bytes, showing first 256]", label, len);
len = 256; len = 256;
} }
const unsigned char *bytes = (const unsigned char *)data; const unsigned char* bytes = (const unsigned char*)data;
char line[80]; char line[80];
char ascii[17]; char ascii[17];
for (size_t i = 0; i < len; i += 16) { for (size_t i = 0; i < len; i += 16)
{
int pos = snprintf(line, sizeof(line), "%04zx: ", i); int pos = snprintf(line, sizeof(line), "%04zx: ", i);
if (pos < 0) pos = 0; if (pos < 0) pos = 0;
if ((size_t) pos>= sizeof(line)) pos = sizeof(line) -1; if ((size_t)pos >= sizeof(line)) pos = sizeof(line) - 1;
for (size_t j = 0; j < 16; j++) { for (size_t j = 0; j < 16; j++)
if (i + j < len) { {
if (i + j < len)
{
int written = snprintf(line + pos, sizeof(line) - pos, "%02x ", bytes[i + j]); int written = snprintf(line + pos, sizeof(line) - pos, "%02x ", bytes[i + j]);
if (written > 0 && (size_t)(pos + written) < sizeof(line)) { if (written > 0 && (size_t)(pos + written) < sizeof(line))
{
pos += written; pos += written;
} else { }
pos = sizeof(line) -1; else
{
pos = sizeof(line) - 1;
} }
ascii[j] = isprint(bytes[i + j]) ? bytes[i + j] : '.'; ascii[j] = isprint(bytes[i + j]) ? bytes[i + j] : '.';
} else { }
else
{
int written = snprintf(line + pos, sizeof(line) - pos, " "); int written = snprintf(line + pos, sizeof(line) - pos, " ");
if (written > 0 && (size_t)(pos + written)) { if (written > 0 && (size_t)(pos + written))
{
pos += written; pos += written;
} else { }
else
{
ascii[j] = ' '; ascii[j] = ' ';
} }
} }
} }
ascii[16] = '\0'; ascii[16] = '\0';
LOG_TRACE(LOG_CAT_GENERAL, "%s: %s |%s|", label, line, ascii); LOG_TRACE(LOG_CAT_GENERAL, "%s: %s |%s|", label, line, ascii);
} }
} }

View File

@@ -2,22 +2,22 @@
#define LOGGING_H #define LOGGING_H
#include <stdbool.h> #include <stdbool.h>
#include <stdarg.h>
#include <pthread.h> #include <pthread.h>
#include <time.h>
// Log levels // Log levels
typedef enum { typedef enum
LOG_LEVEL_OFF = 0, // No logging {
LOG_LEVEL_ERROR = 1, // Only errors LOG_LEVEL_OFF = 0, // No logging
LOG_LEVEL_WARN = 2, // Errors + warnings LOG_LEVEL_ERROR = 1, // Only errors
LOG_LEVEL_INFO = 3, // Classic mode: errors + warnings + info LOG_LEVEL_WARN = 2, // Errors + warnings
LOG_LEVEL_DEBUG = 4, // Debug mode: all above + debug messages LOG_LEVEL_INFO = 3, // Classic mode: errors + warnings + info
LOG_LEVEL_TRACE = 5 // Advanced mode: everything including traces LOG_LEVEL_DEBUG = 4, // Debug mode: all above + debug messages
LOG_LEVEL_TRACE = 5 // Advanced mode: everything including traces
} LogLevel; } LogLevel;
// Log categories for filtering // Log categories for filtering
typedef enum { typedef enum
{
LOG_CAT_GENERAL = 0x01, LOG_CAT_GENERAL = 0x01,
LOG_CAT_SECURITY = 0x02, LOG_CAT_SECURITY = 0x02,
LOG_CAT_NETWORK = 0x04, LOG_CAT_NETWORK = 0x04,
@@ -30,14 +30,16 @@ typedef enum {
} LogCategory; } LogCategory;
// Log output formats // Log output formats
typedef enum { typedef enum
LOG_FORMAT_PLAIN = 0, // Simple text format {
LOG_FORMAT_JSON = 1, // JSON structured format LOG_FORMAT_PLAIN = 0, // Simple text format
LOG_FORMAT_SYSLOG = 2 // Syslog compatible format LOG_FORMAT_JSON = 1, // JSON structured format
LOG_FORMAT_SYSLOG = 2 // Syslog compatible format
} LogFormat; } LogFormat;
// Logger configuration // Logger configuration
typedef struct { typedef struct
{
LogLevel level; LogLevel level;
LogCategory categories; LogCategory categories;
LogFormat format; LogFormat format;
@@ -53,7 +55,7 @@ typedef struct {
} LogConfig; } LogConfig;
// Initialize the logging system // Initialize the logging system
void log_init(LogConfig *config); void log_init(LogConfig* config);
// Cleanup logging system // Cleanup logging system
void log_cleanup(void); void log_cleanup(void);
@@ -65,8 +67,8 @@ void log_set_level(LogLevel level);
void log_set_categories(LogCategory categories); void log_set_categories(LogCategory categories);
// Core logging functions // Core logging functions
void log_write(LogLevel level, LogCategory category, const char *file, void log_write(LogLevel level, LogCategory category, const char* file,
int line, const char *func, const char *fmt, ...); int line, const char* func, const char* fmt, ...);
// Convenience macros with source location // Convenience macros with source location
#define LOG_ERROR(cat, ...) \ #define LOG_ERROR(cat, ...) \
@@ -89,21 +91,21 @@ void log_write(LogLevel level, LogCategory category, const char *file,
log_write(level, LOG_CAT_SECURITY, __FILE__, __LINE__, __func__, __VA_ARGS__) log_write(level, LOG_CAT_SECURITY, __FILE__, __LINE__, __func__, __VA_ARGS__)
// Simple backwards-compatible log function // Simple backwards-compatible log function
void log_event(const char *message); void log_event(const char* message);
// Log mode string conversion // Log mode string conversion
const char *log_level_to_string(LogLevel level); const char* log_level_to_string(LogLevel level);
LogLevel log_level_from_string(const char *str); LogLevel log_level_from_string(const char* str);
const char *log_mode_to_string(LogLevel level); const char* log_mode_to_string(LogLevel level);
// Secure logging (sanitizes sensitive data) // Secure logging (sanitizes sensitive data)
void log_secure(LogLevel level, LogCategory category, const char *fmt, ...); void log_secure(LogLevel level, LogCategory category, const char* fmt, ...);
// Performance logging with timing // Performance logging with timing
void log_perf_start(const char *operation); void log_perf_start(const char* operation);
void log_perf_end(const char *operation); void log_perf_end(const char* operation);
// Hex dump for debugging binary data (only in TRACE level) // Hex dump for debugging binary data (only in TRACE level)
void log_hexdump(const char *label, const void *data, size_t len); void log_hexdump(const char* label, const void* data, size_t len);
#endif #endif

View File

@@ -5,33 +5,33 @@
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h>
#define MAX_MMAP_CACHE_SIZE 100 #define MAX_MMAP_CACHE_SIZE 100
#define MAX_MMAP_FILE_SIZE (10 * 1024 * 1024) // 10MB #define MAX_MMAP_FILE_SIZE (10 * 1024 * 1024) // 10MB
#define BUFFER_POOL_SIZE 64 #define BUFFER_POOL_SIZE 64
#define DEFAULT_BUFFER_SIZE 32768 #define DEFAULT_BUFFER_SIZE 32768
// Global cache structures // Global cache structures
static mmap_cache_entry_t *mmap_cache = NULL; static mmap_cache_entry_t* mmap_cache = NULL;
static int mmap_cache_size = 0; static int mmap_cache_size = 0;
static pthread_mutex_t mmap_cache_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t mmap_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
static buffer_pool_t *buffer_pool = NULL; static buffer_pool_t* buffer_pool = NULL;
static pthread_mutex_t buffer_pool_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t buffer_pool_mutex = PTHREAD_MUTEX_INITIALIZER;
// Pre-allocated response headers // Pre-allocated response headers
const char *response_200_header = "HTTP/1.1 200 OK\r\n"; const char* response_200_header = "HTTP/1.1 200 OK\r\n";
const char *response_404_header = "HTTP/1.1 404 Not Found\r\n\r\nFile Not Found"; const char* response_404_header = "HTTP/1.1 404 Not Found\r\n\r\nFile Not Found";
const char *response_403_header = "HTTP/1.1 403 Forbidden\r\n\r\nAccess Denied"; const char* response_403_header = "HTTP/1.1 403 Forbidden\r\n\r\nAccess Denied";
const char *response_429_header = "HTTP/1.1 429 Too Many Requests\r\n\r\nRate limit exceeded"; const char* response_429_header = "HTTP/1.1 429 Too Many Requests\r\n\r\nRate limit exceeded";
const char *response_500_header = "HTTP/1.1 500 Internal Server Error\r\n\r\nInternal Server Error"; const char* response_500_header = "HTTP/1.1 500 Internal Server Error\r\n\r\nInternal Server Error";
const char *response_503_header = "HTTP/1.1 503 Service Unavailable\r\n\r\nServer overloaded"; const char* response_503_header = "HTTP/1.1 503 Service Unavailable\r\n\r\nServer overloaded";
// Common MIME types cache // Common MIME types cache
typedef struct { typedef struct
const char *ext; {
const char *mime; const char* ext;
const char* mime;
} mime_cache_t; } mime_cache_t;
static const mime_cache_t mime_cache[] = { static const mime_cache_t mime_cache[] = {
@@ -55,9 +55,12 @@ static const mime_cache_t mime_cache[] = {
{NULL, NULL} {NULL, NULL}
}; };
const char *get_mime_from_cache(const char *ext) { const char* get_mime_from_cache(const char* ext)
for (int i = 0; mime_cache[i].ext != NULL; i++) { {
if (strcasecmp(ext, mime_cache[i].ext) == 0) { for (int i = 0; mime_cache[i].ext != NULL; i++)
{
if (strcasecmp(ext, mime_cache[i].ext) == 0)
{
return mime_cache[i].mime; return mime_cache[i].mime;
} }
} }
@@ -65,7 +68,7 @@ const char *get_mime_from_cache(const char *ext) {
} }
// Task queue implementation // Task queue implementation
void init_task_queue(task_queue_t *queue) void init_task_queue(task_queue_t* queue)
{ {
queue->head = NULL; queue->head = NULL;
queue->tail = NULL; queue->tail = NULL;
@@ -74,14 +77,14 @@ void init_task_queue(task_queue_t *queue)
pthread_cond_init(&queue->cond, NULL); pthread_cond_init(&queue->cond, NULL);
} }
void enqueue_task(task_queue_t *queue, int socket_fd, SSL *ssl, bool is_https) void enqueue_task(task_queue_t* queue, int socket_fd, SSL* ssl, bool is_https)
{ {
if (queue->count >= WORKER_QUEUE_SIZE - 1) if (queue->count >= WORKER_QUEUE_SIZE - 1)
{ {
return; return;
} }
connection_task_t *task = malloc(sizeof(connection_task_t)); connection_task_t* task = malloc(sizeof(connection_task_t));
if (!task) if (!task)
return; return;
@@ -107,7 +110,7 @@ void enqueue_task(task_queue_t *queue, int socket_fd, SSL *ssl, bool is_https)
pthread_mutex_unlock(&queue->mutex); pthread_mutex_unlock(&queue->mutex);
} }
connection_task_t *dequeue_task(task_queue_t *queue) connection_task_t* dequeue_task(task_queue_t* queue)
{ {
pthread_mutex_lock(&queue->mutex); pthread_mutex_lock(&queue->mutex);
@@ -116,7 +119,7 @@ connection_task_t *dequeue_task(task_queue_t *queue)
pthread_cond_wait(&queue->cond, &queue->mutex); pthread_cond_wait(&queue->cond, &queue->mutex);
} }
connection_task_t *task = queue->head; connection_task_t* task = queue->head;
queue->head = task->next; queue->head = task->next;
if (queue->head == NULL) if (queue->head == NULL)
@@ -129,14 +132,14 @@ connection_task_t *dequeue_task(task_queue_t *queue)
return task; return task;
} }
void destroy_task_queue(task_queue_t *queue) void destroy_task_queue(task_queue_t* queue)
{ {
pthread_mutex_lock(&queue->mutex); pthread_mutex_lock(&queue->mutex);
connection_task_t *current = queue->head; connection_task_t* current = queue->head;
while (current) while (current)
{ {
connection_task_t *next = current->next; connection_task_t* next = current->next;
free(current); free(current);
current = next; current = next;
} }
@@ -152,7 +155,7 @@ void init_mmap_cache(void)
mmap_cache = calloc(MAX_MMAP_CACHE_SIZE, sizeof(mmap_cache_entry_t)); mmap_cache = calloc(MAX_MMAP_CACHE_SIZE, sizeof(mmap_cache_entry_t));
} }
mmap_cache_entry_t *get_cached_file(const char *path) mmap_cache_entry_t* get_cached_file(const char* path)
{ {
pthread_mutex_lock(&mmap_cache_mutex); pthread_mutex_lock(&mmap_cache_mutex);
@@ -165,7 +168,7 @@ mmap_cache_entry_t *get_cached_file(const char *path)
pthread_mutex_unlock(&mmap_cache_mutex); pthread_mutex_unlock(&mmap_cache_mutex);
return NULL; return NULL;
} }
mmap_cache[i].last_access = time(NULL); mmap_cache[i].last_access = time(NULL);
mmap_cache[i].ref_count++; mmap_cache[i].ref_count++;
pthread_mutex_unlock(&mmap_cache_mutex); pthread_mutex_unlock(&mmap_cache_mutex);
@@ -177,7 +180,7 @@ mmap_cache_entry_t *get_cached_file(const char *path)
return NULL; return NULL;
} }
void cache_file_mmap(const char *path, size_t size, const char *mime_type) void cache_file_mmap(const char* path, size_t size, const char* mime_type)
{ {
if (size > MAX_MMAP_FILE_SIZE) if (size > MAX_MMAP_FILE_SIZE)
return; return;
@@ -239,7 +242,7 @@ void cache_file_mmap(const char *path, size_t size, const char *mime_type)
return; return;
} }
void *mapped = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); void* mapped = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd); close(fd);
if (mapped == MAP_FAILED) if (mapped == MAP_FAILED)
@@ -263,7 +266,7 @@ void cache_file_mmap(const char *path, size_t size, const char *mime_type)
pthread_mutex_unlock(&mmap_cache_mutex); pthread_mutex_unlock(&mmap_cache_mutex);
} }
void release_cached_file(mmap_cache_entry_t *entry) void release_cached_file(mmap_cache_entry_t* entry)
{ {
pthread_mutex_lock(&mmap_cache_mutex); pthread_mutex_lock(&mmap_cache_mutex);
entry->ref_count--; entry->ref_count--;
@@ -298,7 +301,7 @@ void init_buffer_pool(void)
for (int i = 0; i < BUFFER_POOL_SIZE; i++) for (int i = 0; i < BUFFER_POOL_SIZE; i++)
{ {
buffer_pool_t *buf = malloc(sizeof(buffer_pool_t)); buffer_pool_t* buf = malloc(sizeof(buffer_pool_t));
if (buf) if (buf)
{ {
buf->buffer = malloc(DEFAULT_BUFFER_SIZE); buf->buffer = malloc(DEFAULT_BUFFER_SIZE);
@@ -312,19 +315,19 @@ void init_buffer_pool(void)
pthread_mutex_unlock(&buffer_pool_mutex); pthread_mutex_unlock(&buffer_pool_mutex);
} }
char *get_buffer_from_pool(size_t min_size) char* get_buffer_from_pool(size_t min_size)
{ {
if (min_size > DEFAULT_BUFFER_SIZE * 4) if (min_size > DEFAULT_BUFFER_SIZE * 4)
{ {
// For very large requests, allocate directly // For very large requests, allocate directly
return malloc(min_size); return malloc(min_size);
} }
pthread_mutex_lock(&buffer_pool_mutex); pthread_mutex_lock(&buffer_pool_mutex);
buffer_pool_t *current = buffer_pool; buffer_pool_t* current = buffer_pool;
buffer_pool_t *best_fit = NULL; buffer_pool_t* best_fit = NULL;
// Find best fit buffer (smallest that fits) // Find best fit buffer (smallest that fits)
while (current) while (current)
{ {
@@ -337,7 +340,7 @@ char *get_buffer_from_pool(size_t min_size)
} }
current = current->next; current = current->next;
} }
if (best_fit) if (best_fit)
{ {
best_fit->in_use = true; best_fit->in_use = true;
@@ -350,11 +353,11 @@ char *get_buffer_from_pool(size_t min_size)
return malloc(min_size); return malloc(min_size);
} }
void return_buffer_to_pool(char *buffer) void return_buffer_to_pool(char* buffer)
{ {
pthread_mutex_lock(&buffer_pool_mutex); pthread_mutex_lock(&buffer_pool_mutex);
buffer_pool_t *current = buffer_pool; buffer_pool_t* current = buffer_pool;
while (current) while (current)
{ {
if (current->buffer == buffer) if (current->buffer == buffer)
@@ -376,10 +379,10 @@ void cleanup_buffer_pool(void)
{ {
pthread_mutex_lock(&buffer_pool_mutex); pthread_mutex_lock(&buffer_pool_mutex);
buffer_pool_t *current = buffer_pool; buffer_pool_t* current = buffer_pool;
while (current) while (current)
{ {
buffer_pool_t *next = current->next; buffer_pool_t* next = current->next;
free(current->buffer); free(current->buffer);
free(current); free(current);
current = next; current = next;

View File

@@ -14,15 +14,15 @@
typedef struct connection_task_t typedef struct connection_task_t
{ {
int socket_fd; int socket_fd;
SSL *ssl; SSL* ssl;
bool is_https; bool is_https;
struct connection_task_t *next; struct connection_task_t* next;
} connection_task_t; } connection_task_t;
typedef struct typedef struct
{ {
connection_task_t *head; connection_task_t* head;
connection_task_t *tail; connection_task_t* tail;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond; pthread_cond_t cond;
int count; int count;
@@ -31,51 +31,51 @@ typedef struct
// Memory-mapped file cache // Memory-mapped file cache
typedef struct typedef struct
{ {
char *path; char* path;
void *mmap_data; void* mmap_data;
size_t size; size_t size;
void *compressed_data; void* compressed_data;
size_t compressed_size; size_t compressed_size;
time_t last_access; time_t last_access;
char *mime_type; char* mime_type;
int ref_count; int ref_count;
} mmap_cache_entry_t; } mmap_cache_entry_t;
// Response buffer pool // Response buffer pool
typedef struct buffer_pool_t typedef struct buffer_pool_t
{ {
char *buffer; char* buffer;
size_t size; size_t size;
bool in_use; bool in_use;
struct buffer_pool_t *next; struct buffer_pool_t* next;
} buffer_pool_t; } buffer_pool_t;
// Function declarations // Function declarations
void init_task_queue(task_queue_t *queue); void init_task_queue(task_queue_t* queue);
void enqueue_task(task_queue_t *queue, int socket_fd, SSL *ssl, bool is_https); void enqueue_task(task_queue_t* queue, int socket_fd, SSL* ssl, bool is_https);
connection_task_t *dequeue_task(task_queue_t *queue); connection_task_t* dequeue_task(task_queue_t* queue);
void destroy_task_queue(task_queue_t *queue); void destroy_task_queue(task_queue_t* queue);
void init_mmap_cache(void); void init_mmap_cache(void);
mmap_cache_entry_t *get_cached_file(const char *path); mmap_cache_entry_t* get_cached_file(const char* path);
void cache_file_mmap(const char *path, size_t size, const char *mime_type); void cache_file_mmap(const char* path, size_t size, const char* mime_type);
void release_cached_file(mmap_cache_entry_t *entry); void release_cached_file(mmap_cache_entry_t* entry);
void cleanup_mmap_cache(void); void cleanup_mmap_cache(void);
void init_buffer_pool(void); void init_buffer_pool(void);
char *get_buffer_from_pool(size_t min_size); char* get_buffer_from_pool(size_t min_size);
void return_buffer_to_pool(char *buffer); void return_buffer_to_pool(char* buffer);
void cleanup_buffer_pool(void); void cleanup_buffer_pool(void);
// Pre-allocated response headers // Pre-allocated response headers
extern const char *response_200_header; extern const char* response_200_header;
extern const char *response_404_header; extern const char* response_404_header;
extern const char *response_403_header; extern const char* response_403_header;
extern const char *response_429_header; extern const char* response_429_header;
extern const char *response_500_header; extern const char* response_500_header;
extern const char *response_503_header; extern const char* response_503_header;
// MIME type cache // MIME type cache
const char *get_mime_from_cache(const char *ext); const char* get_mime_from_cache(const char* ext);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
#include <stdio.h>
#include <string.h> #include <string.h>
#include "server_config.h" #include "server_config.h"
void init_config(ServerConfig *config) void init_config(ServerConfig* config)
{ {
config->port = 8080; config->port = 8080;
config->use_https = false; config->use_https = false;
@@ -10,7 +9,7 @@ void init_config(ServerConfig *config)
config->max_threads = 4; config->max_threads = 4;
config->running = true; config->running = true;
config->automatic_startup = false; config->automatic_startup = false;
config->log_mode = LOG_MODE_CLASSIC; // Default to classic logging config->log_mode = LOG_MODE_CLASSIC; // Default to classic logging
strcpy(config->server_name, "127.0.0.1"); strcpy(config->server_name, "127.0.0.1");
config->enable_http2 = false; config->enable_http2 = false;
config->enable_websocket = false; config->enable_websocket = false;
@@ -18,4 +17,4 @@ void init_config(ServerConfig *config)
config->max_connections = 1024; config->max_connections = 1024;
strcpy(config->ssl_cert_path, "ssl/cert/cert.pem"); strcpy(config->ssl_cert_path, "ssl/cert/cert.pem");
strcpy(config->ssl_key_path, "ssl/key/key.key"); strcpy(config->ssl_key_path, "ssl/key/key.key");
} }

View File

@@ -4,7 +4,8 @@
#include <stdbool.h> #include <stdbool.h>
// Log modes // Log modes
typedef enum { typedef enum
{
LOG_MODE_OFF = 0, LOG_MODE_OFF = 0,
LOG_MODE_CLASSIC = 1, LOG_MODE_CLASSIC = 1,
LOG_MODE_DEBUG = 2, LOG_MODE_DEBUG = 2,
@@ -20,7 +21,7 @@ typedef struct
bool running; bool running;
bool automatic_startup; bool automatic_startup;
char server_name[256]; char server_name[256];
LogMode log_mode; // Replaces verbose - supports off/classic/debug/advanced LogMode log_mode; // Replaces verbose - supports off/classic/debug/advanced
bool enable_http2; bool enable_http2;
bool enable_websocket; bool enable_websocket;
char www_path[256]; char www_path[256];
@@ -29,8 +30,8 @@ typedef struct
char ssl_key_path[256]; char ssl_key_path[256];
} ServerConfig; } ServerConfig;
int load_config(const char *filename, ServerConfig *config); int load_config(const char* filename, ServerConfig* config);
void init_config(ServerConfig *config); void init_config(ServerConfig* config);
void log_event(const char *message); void log_event(const char* message);
#endif #endif

View File

@@ -13,21 +13,19 @@
#define SHA1_DIGEST_LENGTH 20 #define SHA1_DIGEST_LENGTH 20
// Base64 encode function // Base64 encode function
static char *base64_encode(const unsigned char *input, int length) static char* base64_encode(const unsigned char* input, int length)
{ {
BIO *bmem, *b64; BIO *bmem = BIO_new(BIO_s_mem()), *b64 = BIO_new(BIO_f_base64());;
BUF_MEM *bptr; BUF_MEM* bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem); b64 = BIO_push(b64, bmem);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
BIO_write(b64, input, length); BIO_write(b64, input, length);
BIO_flush(b64); BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr); BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length + 1); char* buff = (char*)malloc(bptr->length + 1);
if (!buff) { if (!buff)
{
BIO_free_all(b64); BIO_free_all(b64);
return NULL; return NULL;
} }
@@ -40,15 +38,16 @@ static char *base64_encode(const unsigned char *input, int length)
} }
// Generate WebSocket accept key from client key // Generate WebSocket accept key from client key
char *ws_generate_accept_key(const char *client_key) char* ws_generate_accept_key(const char* client_key)
{ {
if (!client_key || strlen(client_key) > 128) { if (!client_key || strlen(client_key) > 128)
return NULL; // Security: validate input length {
return NULL; // Security: validate input length
} }
char combined[256]; char combined[256];
int written = snprintf(combined, sizeof(combined), "%s%s", client_key, WS_GUID); int written = snprintf(combined, sizeof(combined), "%s%s", client_key, WS_GUID);
if (written < 0 || written >= (int)sizeof(combined)) if (written < 0 || written >= (int)sizeof(combined))
{ {
return NULL; return NULL;
@@ -56,15 +55,17 @@ char *ws_generate_accept_key(const char *client_key)
unsigned char hash[SHA1_DIGEST_LENGTH]; unsigned char hash[SHA1_DIGEST_LENGTH];
unsigned int hash_len = 0; unsigned int hash_len = 0;
EVP_MD_CTX *ctx = EVP_MD_CTX_new(); EVP_MD_CTX* ctx = EVP_MD_CTX_new();
if (!ctx) { if (!ctx)
{
return NULL; return NULL;
} }
if (EVP_DigestInit_ex(ctx, EVP_sha1(), NULL) != 1 || if (EVP_DigestInit_ex(ctx, EVP_sha1(), NULL) != 1 ||
EVP_DigestUpdate(ctx, combined, strlen(combined)) != 1 || EVP_DigestUpdate(ctx, combined, strlen(combined)) != 1 ||
EVP_DigestFinal_ex(ctx, hash, &hash_len) != 1) { EVP_DigestFinal_ex(ctx, hash, &hash_len) != 1)
{
EVP_MD_CTX_free(ctx); EVP_MD_CTX_free(ctx);
return NULL; return NULL;
} }
@@ -74,20 +75,20 @@ char *ws_generate_accept_key(const char *client_key)
} }
// Handle WebSocket handshake // Handle WebSocket handshake
int ws_handle_handshake(int client_socket, const char *request, char *response, size_t response_size) int ws_handle_handshake(int client_socket, const char* request, char* response, size_t response_size)
{ {
(void)client_socket; // Unused in this implementation (void)client_socket; // Unused in this implementation
// Extract Sec-WebSocket-Key from request // Extract Sec-WebSocket-Key from request
const char *key_header = "Sec-WebSocket-Key: "; const char* key_header = "Sec-WebSocket-Key: ";
char *key_start = strstr(request, key_header); char* key_start = strstr(request, key_header);
if (!key_start) if (!key_start)
{ {
return -1; return -1;
} }
key_start += strlen(key_header); key_start += strlen(key_header);
char *key_end = strstr(key_start, "\r\n"); char* key_end = strstr(key_start, "\r\n");
if (!key_end) if (!key_end)
{ {
return -1; return -1;
@@ -95,7 +96,7 @@ int ws_handle_handshake(int client_socket, const char *request, char *response,
char client_key[256]; char client_key[256];
size_t key_len = key_end - key_start; size_t key_len = key_end - key_start;
if (key_len >= sizeof(client_key) || key_len == 0 || key_len > 1024) if (key_len >= sizeof(client_key) || key_len == 0)
{ {
return -1; return -1;
} }
@@ -103,7 +104,7 @@ int ws_handle_handshake(int client_socket, const char *request, char *response,
client_key[key_len] = '\0'; client_key[key_len] = '\0';
// Generate accept key // Generate accept key
char *accept_key = ws_generate_accept_key(client_key); char* accept_key = ws_generate_accept_key(client_key);
if (!accept_key) if (!accept_key)
{ {
return -1; return -1;
@@ -111,36 +112,36 @@ int ws_handle_handshake(int client_socket, const char *request, char *response,
// Create handshake response // Create handshake response
int written = snprintf(response, response_size, int written = snprintf(response, response_size,
"HTTP/1.1 101 Switching Protocols\r\n" "HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n" "Upgrade: websocket\r\n"
"Connection: Upgrade\r\n" "Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %s\r\n" "Sec-WebSocket-Accept: %s\r\n"
"\r\n", "\r\n",
accept_key); accept_key);
free(accept_key); free(accept_key);
if (written < 0 || written >= (int)response_size) if (written < 0 || written >= (int)response_size)
{ {
return -1; return -1;
} }
return 0; return 0;
} }
// Handle WebSocket handshake for SSL connections // Handle WebSocket handshake for SSL connections
int ws_handle_handshake_ssl(SSL *ssl, const char *request, char *response, size_t response_size) int ws_handle_handshake_ssl(SSL* ssl, const char* request, char* response, size_t response_size)
{ {
(void)ssl; // Use the same logic, just different transport (void)ssl; // Use the same logic, just different transport
return ws_handle_handshake(0, request, response, response_size); return ws_handle_handshake(0, request, response, response_size);
} }
// Parse WebSocket frame // Parse WebSocket frame
int ws_parse_frame(const uint8_t *data, size_t len, ws_frame_header_t *header, uint8_t **payload) int ws_parse_frame(const uint8_t* data, size_t len, ws_frame_header_t* header, uint8_t** payload)
{ {
// Maximum allowed WebSocket payload size (10MB) // Maximum allowed WebSocket payload size (10MB)
#define MAX_WEBSOCKET_PAYLOAD (10 * 1024 * 1024) #define MAX_WEBSOCKET_PAYLOAD (10 * 1024 * 1024)
if (len < 2) if (len < 2)
{ {
return -1; return -1;
@@ -195,7 +196,7 @@ int ws_parse_frame(const uint8_t *data, size_t len, ws_frame_header_t *header, u
} }
// Unmask payload if masked // Unmask payload if masked
*payload = (uint8_t *)malloc(header->payload_length); *payload = (uint8_t*)malloc(header->payload_length);
if (!*payload) if (!*payload)
{ {
return -1; return -1;
@@ -217,10 +218,10 @@ int ws_parse_frame(const uint8_t *data, size_t len, ws_frame_header_t *header, u
} }
// Create WebSocket frame // Create WebSocket frame
int ws_create_frame(uint8_t *buffer, size_t buffer_size, uint8_t opcode, const uint8_t *payload, size_t payload_len) int ws_create_frame(uint8_t* buffer, size_t buffer_size, uint8_t opcode, const uint8_t* payload, size_t payload_len)
{ {
size_t header_size; size_t header_size;
// Calculate total frame size first // Calculate total frame size first
if (payload_len < 126) if (payload_len < 126)
{ {
@@ -234,13 +235,13 @@ int ws_create_frame(uint8_t *buffer, size_t buffer_size, uint8_t opcode, const u
{ {
header_size = 10; header_size = 10;
} }
// Check buffer size before writing anything // Check buffer size before writing anything
if (buffer_size < header_size + payload_len) if (buffer_size < header_size + payload_len)
{ {
return -1; return -1;
} }
size_t offset = 0; size_t offset = 0;
// First byte: FIN + opcode // First byte: FIN + opcode
@@ -277,7 +278,7 @@ int ws_create_frame(uint8_t *buffer, size_t buffer_size, uint8_t opcode, const u
} }
// Send WebSocket frame // Send WebSocket frame
int ws_send_frame(ws_connection_t *conn, uint8_t opcode, const uint8_t *payload, size_t payload_len) int ws_send_frame(ws_connection_t* conn, uint8_t opcode, const uint8_t* payload, size_t payload_len)
{ {
// Allocate buffer with enough space for header (max 10 bytes) + payload // Allocate buffer with enough space for header (max 10 bytes) + payload
// Check for integer overflow // Check for integer overflow
@@ -285,7 +286,7 @@ int ws_send_frame(ws_connection_t *conn, uint8_t opcode, const uint8_t *payload,
{ {
return -1; return -1;
} }
size_t max_frame_size = 10 + payload_len; size_t max_frame_size = 10 + payload_len;
if (max_frame_size > 65536) if (max_frame_size > 65536)
{ {
@@ -319,19 +320,19 @@ int ws_send_frame(ws_connection_t *conn, uint8_t opcode, const uint8_t *payload,
} }
// Send text message // Send text message
int ws_send_text(ws_connection_t *conn, const char *text) int ws_send_text(ws_connection_t* conn, const char* text)
{ {
return ws_send_frame(conn, WS_OPCODE_TEXT, (const uint8_t *)text, strlen(text)); return ws_send_frame(conn, WS_OPCODE_TEXT, (const uint8_t*)text, strlen(text));
} }
// Send pong response // Send pong response
int ws_send_pong(ws_connection_t *conn, const uint8_t *payload, size_t payload_len) int ws_send_pong(ws_connection_t* conn, const uint8_t* payload, size_t payload_len)
{ {
return ws_send_frame(conn, WS_OPCODE_PONG, payload, payload_len); return ws_send_frame(conn, WS_OPCODE_PONG, payload, payload_len);
} }
// Close WebSocket connection // Close WebSocket connection
void ws_close_connection(ws_connection_t *conn, uint16_t status_code) void ws_close_connection(ws_connection_t* conn, uint16_t status_code)
{ {
uint8_t close_payload[2]; uint8_t close_payload[2];
close_payload[0] = (status_code >> 8) & 0xFF; close_payload[0] = (status_code >> 8) & 0xFF;
@@ -348,7 +349,7 @@ void ws_close_connection(ws_connection_t *conn, uint16_t status_code)
} }
// Validate UTF-8 encoding // Validate UTF-8 encoding
bool ws_is_valid_utf8(const uint8_t *data, size_t len) bool ws_is_valid_utf8(const uint8_t* data, size_t len)
{ {
size_t i = 0; size_t i = 0;
while (i < len) while (i < len)
@@ -371,7 +372,8 @@ bool ws_is_valid_utf8(const uint8_t *data, size_t len)
} }
else if ((data[i] & 0xF8) == 0xF0) else if ((data[i] & 0xF8) == 0xF0)
{ {
if (i + 3 >= len || (data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80 || (data[i + 3] & 0xC0) != 0x80) if (i + 3 >= len || (data[i + 1] & 0xC0) != 0x80 || (data[i + 2] & 0xC0) != 0x80 || (data[i + 3] & 0xC0) !=
0x80)
return false; return false;
i += 4; i += 4;
} }

View File

@@ -27,23 +27,23 @@ typedef struct
typedef struct typedef struct
{ {
int socket_fd; int socket_fd;
SSL *ssl; SSL* ssl;
bool is_ssl; bool is_ssl;
bool handshake_complete; bool handshake_complete;
} ws_connection_t; } ws_connection_t;
// Function prototypes // Function prototypes
int ws_handle_handshake(int client_socket, const char *request, char *response, size_t response_size); int ws_handle_handshake(int client_socket, const char* request, char* response, size_t response_size);
int ws_handle_handshake_ssl(SSL *ssl, const char *request, char *response, size_t response_size); int ws_handle_handshake_ssl(SSL* ssl, const char* request, char* response, size_t response_size);
int ws_parse_frame(const uint8_t *data, size_t len, ws_frame_header_t *header, uint8_t **payload); int ws_parse_frame(const uint8_t* data, size_t len, ws_frame_header_t* header, uint8_t** payload);
int ws_create_frame(uint8_t *buffer, size_t buffer_size, uint8_t opcode, const uint8_t *payload, size_t payload_len); int ws_create_frame(uint8_t* buffer, size_t buffer_size, uint8_t opcode, const uint8_t* payload, size_t payload_len);
int ws_send_frame(ws_connection_t *conn, uint8_t opcode, const uint8_t *payload, size_t payload_len); int ws_send_frame(ws_connection_t* conn, uint8_t opcode, const uint8_t* payload, size_t payload_len);
int ws_send_text(ws_connection_t *conn, const char *text); int ws_send_text(ws_connection_t* conn, const char* text);
int ws_send_pong(ws_connection_t *conn, const uint8_t *payload, size_t payload_len); int ws_send_pong(ws_connection_t* conn, const uint8_t* payload, size_t payload_len);
void ws_close_connection(ws_connection_t *conn, uint16_t status_code); void ws_close_connection(ws_connection_t* conn, uint16_t status_code);
// Helper functions // Helper functions
char *ws_generate_accept_key(const char *client_key); char* ws_generate_accept_key(const char* client_key);
bool ws_is_valid_utf8(const uint8_t *data, size_t len); bool ws_is_valid_utf8(const uint8_t* data, size_t len);
#endif #endif