Update server.c
Fixed minor bugs Fixed logging system Optimization Redirects to HTTPS when available
This commit is contained in:
517
server.c
517
server.c
@@ -9,14 +9,19 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <cJSON.h>
|
#include <cJSON.h>
|
||||||
#include <stdio_ext.h>
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
|
||||||
#include "server_config.h"
|
#include "server_config.h"
|
||||||
|
|
||||||
#define MAX_REQUEST_SIZE 8192
|
#define MAX_REQUEST_SIZE 8192
|
||||||
#define MAX_LOG_SIZE 2048
|
#define MAX_LOG_SIZE 2048
|
||||||
#define MAX_CLIENT_THREADS 100
|
#define MAX_CLIENTS 1024
|
||||||
|
#define MAX_EVENTS 1024
|
||||||
|
|
||||||
#define BOLD "\x1b[1m"
|
#define BOLD "\x1b[1m"
|
||||||
#define RED "\x1b[31m"
|
#define RED "\x1b[31m"
|
||||||
@@ -28,10 +33,14 @@
|
|||||||
ServerConfig config;
|
ServerConfig config;
|
||||||
char server_log[MAX_LOG_SIZE];
|
char server_log[MAX_LOG_SIZE];
|
||||||
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
pthread_t client_threads[MAX_CLIENT_THREADS];
|
pthread_t client_threads[MAX_CLIENTS];
|
||||||
int num_client_threads = 0;
|
int num_client_threads = 0;
|
||||||
pthread_mutex_t thread_count_mutex = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t thread_count_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
SSL_CTX *ssl_ctx = NULL;
|
SSL_CTX *ssl_ctx = NULL;
|
||||||
|
volatile sig_atomic_t server_running = 1;
|
||||||
|
int http_socket = -1;
|
||||||
|
int https_socket = -1;
|
||||||
|
int epoll_fd;
|
||||||
|
|
||||||
void *handle_http_client(void *arg);
|
void *handle_http_client(void *arg);
|
||||||
void *handle_https_client(void *arg);
|
void *handle_https_client(void *arg);
|
||||||
@@ -43,20 +52,27 @@ void configure_ssl_context(SSL_CTX *ctx);
|
|||||||
void *start_http_server(void *arg);
|
void *start_http_server(void *arg);
|
||||||
void *start_https_server(void *arg);
|
void *start_https_server(void *arg);
|
||||||
void shutdown_server();
|
void shutdown_server();
|
||||||
|
int parse_request_line(char *request_buffer, char *method, char *url, char *protocol);
|
||||||
|
|
||||||
void initialize_openssl() {
|
void initialize_openssl() {
|
||||||
SSL_library_init();
|
if (!SSL_library_init()) {
|
||||||
|
perror(BOLD RED "Error initializing OpenSSL library" RESET);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cleanup_openssl() {
|
void cleanup_openssl() {
|
||||||
if (ssl_ctx) {
|
if (ssl_ctx) {
|
||||||
SSL_CTX_free(ssl_ctx);
|
SSL_CTX_free(ssl_ctx);
|
||||||
|
ssl_ctx = NULL;
|
||||||
}
|
}
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SSL_CTX *create_ssl_context() {
|
SSL_CTX *create_ssl_context() {
|
||||||
const SSL_METHOD *method = TLS_server_method();
|
const SSL_METHOD *method = TLS_server_method();
|
||||||
SSL_CTX *ctx = SSL_CTX_new(method);
|
SSL_CTX *ctx = SSL_CTX_new(method);
|
||||||
@@ -83,68 +99,112 @@ void configure_ssl_context(SSL_CTX *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *start_http_server(void *arg) {
|
void *start_http_server(void *arg) {
|
||||||
int http_socket = socket(AF_INET, SOCK_STREAM, 0);
|
http_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (http_socket < 0) {
|
if (http_socket < 0) {
|
||||||
perror(BOLD RED "Error: "RESET"creating HTTP socket");
|
perror(BOLD RED "Error creating HTTP socket" RESET);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sockaddr_in http_address;
|
int reuse = 1;
|
||||||
memset(&http_address, 0, sizeof(http_address));
|
if (setsockopt(http_socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
|
||||||
|
perror(BOLD RED "Error setting SO_REUSEADDR" RESET);
|
||||||
|
close(http_socket);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in http_address = {0};
|
||||||
http_address.sin_family = AF_INET;
|
http_address.sin_family = AF_INET;
|
||||||
AF_INET;
|
|
||||||
http_address.sin_addr.s_addr = INADDR_ANY;
|
http_address.sin_addr.s_addr = INADDR_ANY;
|
||||||
http_address.sin_port = htons(config.port);
|
http_address.sin_port = htons(config.port);
|
||||||
|
|
||||||
if (bind(http_socket, (struct sockaddr *)&http_address, sizeof(http_address)) < 0) {
|
if (bind(http_socket, (struct sockaddr *)&http_address, sizeof(http_address)) < 0) {
|
||||||
perror(BOLD RED "Error: "RESET" binding HTTP socket");
|
perror(BOLD RED "Error binding HTTP socket" RESET);
|
||||||
close(http_socket);
|
close(http_socket);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(http_socket, 50) < 0) {
|
if (listen(http_socket, 50) < 0) {
|
||||||
perror(BOLD RED"Error: "RESET"listening on HTTP socket");
|
perror(BOLD RED "Error listening on HTTP socket" RESET);
|
||||||
close(http_socket);
|
close(http_socket);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_event( "HTTP server started.");
|
epoll_fd = epoll_create1(0); // Create epoll instance
|
||||||
|
if (epoll_fd == -1) {
|
||||||
while (config.running) {
|
perror("epoll_create1");
|
||||||
int client_socket = accept(http_socket, NULL, NULL);
|
close(http_socket); // Close the socket before exiting
|
||||||
if (client_socket < 0) {
|
pthread_exit(NULL);
|
||||||
perror(BOLD RED"Error: "RESET"accepting HTTP connection");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&thread_count_mutex);
|
|
||||||
if (num_client_threads < MAX_CLIENT_THREADS) {
|
|
||||||
pthread_t client_thread;
|
|
||||||
int *client_socket_ptr = malloc(sizeof(int));
|
|
||||||
*client_socket_ptr = client_socket;
|
|
||||||
|
|
||||||
if (pthread_create(&client_thread, NULL, handle_http_client, client_socket_ptr) == 0) {
|
|
||||||
client_threads[num_client_threads++] = client_thread;
|
|
||||||
} else {
|
|
||||||
perror(BOLD RED "Error: " RESET "creating HTTP client thread");
|
|
||||||
close(client_socket);
|
|
||||||
free(client_socket_ptr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log_event("Max client threads reached, rejecting connection.");
|
|
||||||
close(client_socket);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&thread_count_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct epoll_event ev;
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.fd = http_socket;
|
||||||
|
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, http_socket, &ev) == -1) {
|
||||||
|
perror("epoll_ctl: http_socket");
|
||||||
|
close(http_socket);
|
||||||
|
close(epoll_fd); // Close epoll fd
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_event("HTTP server started.");
|
||||||
|
|
||||||
|
struct epoll_event events[MAX_EVENTS];
|
||||||
|
while (config.running && server_running) {
|
||||||
|
int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 100); // 100ms timeout
|
||||||
|
if (nfds == -1) {
|
||||||
|
if (errno != EINTR) { // Ignore interrupts for shutdown
|
||||||
|
perror("epoll_wait");
|
||||||
|
break; // Exit loop on error
|
||||||
|
}
|
||||||
|
continue; // Continue if it was an interrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < nfds; ++i) {
|
||||||
|
if (events[i].data.fd == http_socket) {
|
||||||
|
// New connection
|
||||||
|
struct sockaddr_in client_addr;
|
||||||
|
socklen_t addr_size = sizeof(client_addr);
|
||||||
|
int client_socket = accept(http_socket, (struct sockaddr *)&client_addr, &addr_size);
|
||||||
|
if (client_socket < 0) {
|
||||||
|
perror("accept");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&thread_count_mutex);
|
||||||
|
if (num_client_threads < MAX_CLIENTS) {
|
||||||
|
pthread_t client_thread;
|
||||||
|
int *client_socket_ptr = malloc(sizeof(int));
|
||||||
|
*client_socket_ptr = client_socket;
|
||||||
|
|
||||||
|
if (pthread_create(&client_thread, NULL, handle_http_client, client_socket_ptr) == 0) {
|
||||||
|
client_threads[num_client_threads++] = client_thread;
|
||||||
|
} else {
|
||||||
|
perror("Error creating HTTP client thread");
|
||||||
|
close(client_socket);
|
||||||
|
free(client_socket_ptr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_event("Max client threads reached, rejecting connection.");
|
||||||
|
close(client_socket);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&thread_count_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, http_socket, NULL);
|
||||||
close(http_socket);
|
close(http_socket);
|
||||||
|
close(epoll_fd);
|
||||||
|
log_event("HTTP server stopped.");
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void *start_https_server(void *arg) {
|
void *start_https_server(void *arg) {
|
||||||
int https_socket = socket(AF_INET, SOCK_STREAM, 0);
|
https_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if (https_socket < 0) {
|
if (https_socket < 0) {
|
||||||
perror(BOLD RED"Error: "RESET"creating HTTPS socket");
|
perror(BOLD RED "Error creating HTTPS socket" RESET);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,20 +215,20 @@ void *start_https_server(void *arg) {
|
|||||||
https_address.sin_port = htons(443);
|
https_address.sin_port = htons(443);
|
||||||
|
|
||||||
if (bind(https_socket, (struct sockaddr *)&https_address, sizeof(https_address)) < 0) {
|
if (bind(https_socket, (struct sockaddr *)&https_address, sizeof(https_address)) < 0) {
|
||||||
perror(BOLD RED"Error: "RESET"binding HTTPS socket");
|
perror(BOLD RED "Error binding HTTPS socket" RESET);
|
||||||
close(https_socket);
|
close(https_socket);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(https_socket, 50) < 0) {
|
if (listen(https_socket, 50) < 0) {
|
||||||
perror(BOLD RED"Error: "RESET"listening on HTTPS socket");
|
perror(BOLD RED "Error listening on HTTPS socket" RESET);
|
||||||
close(https_socket);
|
close(https_socket);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_event("HTTPS server started.");
|
log_event("HTTPS server started.");
|
||||||
|
|
||||||
while (config.running) {
|
while (config.running && server_running) {
|
||||||
int client_socket = accept(https_socket, NULL, NULL);
|
int client_socket = accept(https_socket, NULL, NULL);
|
||||||
if (client_socket < 0) {
|
if (client_socket < 0) {
|
||||||
perror("Error accepting HTTPS connection");
|
perror("Error accepting HTTPS connection");
|
||||||
@@ -176,7 +236,7 @@ void *start_https_server(void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&thread_count_mutex);
|
pthread_mutex_lock(&thread_count_mutex);
|
||||||
if (num_client_threads < MAX_CLIENT_THREADS) {
|
if (num_client_threads < MAX_CLIENTS) {
|
||||||
pthread_t client_thread;
|
pthread_t client_thread;
|
||||||
int *client_socket_ptr = malloc(sizeof(int));
|
int *client_socket_ptr = malloc(sizeof(int));
|
||||||
*client_socket_ptr = client_socket;
|
*client_socket_ptr = client_socket;
|
||||||
@@ -199,48 +259,69 @@ void *start_https_server(void *arg) {
|
|||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *handle_http_client(void *arg) {
|
void *handle_http_client(void *arg) {
|
||||||
int client_socket = *((int *)arg);
|
int client_socket = *((int *)arg);
|
||||||
free(arg);
|
free(arg);
|
||||||
|
|
||||||
char buffer[MAX_REQUEST_SIZE];
|
char request_buffer[MAX_REQUEST_SIZE];
|
||||||
ssize_t bytes_received = recv(client_socket, buffer, MAX_REQUEST_SIZE - 1, 0);
|
ssize_t bytes_received = recv(client_socket, request_buffer, MAX_REQUEST_SIZE - 1, 0);
|
||||||
if (bytes_received > 0) {
|
|
||||||
buffer[bytes_received] = '\0';
|
if (!server_running) {
|
||||||
log_event("Received HTTP request");
|
close(client_socket); // Close socket before exiting
|
||||||
send(client_socket, "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, HTTP!", 48, 0);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(client_socket);
|
if (bytes_received > 0) {
|
||||||
pthread_exit(NULL);
|
request_buffer[bytes_received] = '\0';
|
||||||
}
|
log_event("Received HTTP request");
|
||||||
|
|
||||||
void *handle_https_client(void *arg) {
|
char method[8], url[256], protocol[16];
|
||||||
int client_socket = *((int *)arg);
|
if (parse_request_line(request_buffer, method, url, protocol) != 0) {
|
||||||
free(arg);
|
log_event("Invalid request line.");
|
||||||
|
const char *bad_request_response = "HTTP/1.1 400 Bad Request\r\n\r\nInvalid Request";
|
||||||
|
send(client_socket, bad_request_response, strlen(bad_request_response), 0);
|
||||||
|
close(client_socket);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
SSL *ssl = SSL_new(ssl_ctx);
|
if (config.use_https) { // Check if HTTPS is enabled
|
||||||
SSL_set_fd(ssl, client_socket);
|
char redirect_response[512];
|
||||||
|
snprintf(redirect_response, sizeof(redirect_response),
|
||||||
|
"HTTP/1.1 301 Moved Permanently\r\n"
|
||||||
|
"Location: https://%s%s\r\n\r\n", config.server_name, url);
|
||||||
|
send(client_socket, redirect_response, strlen(redirect_response), 0);
|
||||||
|
log_event("Redirecting to HTTPS"); // Log the redirection
|
||||||
|
close(client_socket);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (SSL_accept(ssl) > 0) {
|
if (strstr(url, "..") || strstr(url, "//")) {
|
||||||
char filepath[256];
|
log_event("Blocked potential directory traversal attempt.");
|
||||||
snprintf(filepath, sizeof(filepath), "www/%s", "index.html");
|
const char *forbidden_response = "HTTP/1.1 403 Forbidden\r\n\r\nAccess Denied";
|
||||||
|
send(client_socket, forbidden_response, strlen(forbidden_response), 0);
|
||||||
|
close(client_socket);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char filepath[512];
|
||||||
|
snprintf(filepath, sizeof(filepath), "www%s", (*url == '/' && url[1] == '\0') ? "/index.html" : url);
|
||||||
|
|
||||||
int fd = open(filepath, O_RDONLY);
|
int fd = open(filepath, O_RDONLY);
|
||||||
|
|
||||||
if (strstr(filepath, "..")) {
|
|
||||||
const char *forbiden_access = "HTTP/1.1 403 Forbidden\r\n\r\nAccess Denied";
|
|
||||||
SSL_write(ssl, forbiden_access, strlen(forbiden_access));
|
|
||||||
log_event("Potential directory traversal attempt detected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
const char *not_found_response = "HTTP/1.1 404 Not Found\r\n\r\nFile Not Found";
|
const char *not_found_response = "HTTP/1.1 404 Not Found\r\n\r\nFile Not Found";
|
||||||
SSL_write(ssl, not_found_response, strlen(not_found_response));
|
send(client_socket, not_found_response, strlen(not_found_response), 0);
|
||||||
log_event("File not found, sent 404.");
|
log_event("File not found, sent 404.");
|
||||||
} else {
|
} else {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
fstat(fd, &st);
|
if (fstat(fd, &st) == -1) {
|
||||||
|
log_event("Error getting file size.");
|
||||||
|
const char *internal_server_error = "HTTP/1.1 500 Internal Server Error\r\n\r\nInternal Server Error";
|
||||||
|
send(client_socket, internal_server_error, strlen(internal_server_error), 0);
|
||||||
|
close(fd);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
off_t file_size = st.st_size;
|
off_t file_size = st.st_size;
|
||||||
|
|
||||||
char response_header[256];
|
char response_header[256];
|
||||||
@@ -251,90 +332,224 @@ void *handle_https_client(void *arg) {
|
|||||||
"\r\n",
|
"\r\n",
|
||||||
file_size);
|
file_size);
|
||||||
|
|
||||||
|
send(client_socket, response_header, strlen(response_header), 0);
|
||||||
|
|
||||||
ssize_t total_sent = 0, bytes_sent;
|
char file_buffer[1024];
|
||||||
size_t header_len = strlen(response_header);
|
|
||||||
|
|
||||||
while (total_sent < header_len) {
|
|
||||||
bytes_sent = SSL_write(ssl, response_header + total_sent, header_len - total_sent);
|
|
||||||
if (bytes_sent <= 0) {
|
|
||||||
log_event("Failed to send HTTPS header.");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
total_sent += bytes_sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char buffer[1024];
|
|
||||||
ssize_t bytes_read;
|
ssize_t bytes_read;
|
||||||
total_sent = 0;
|
while ((bytes_read = read(fd, file_buffer, sizeof(file_buffer))) > 0) {
|
||||||
|
if (send(client_socket, file_buffer, bytes_read, 0) < 0) {
|
||||||
while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
|
log_event("Error sending file content.");
|
||||||
size_t body_len = bytes_read;
|
break;
|
||||||
while (total_sent < body_len) {
|
|
||||||
bytes_sent = SSL_write(ssl, buffer + total_sent, body_len - total_sent);
|
|
||||||
|
|
||||||
if (bytes_sent <= 0) {
|
|
||||||
log_event("Failed to send HTTPS body.");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
total_sent += bytes_sent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (bytes_read < 0) {
|
|
||||||
log_event("Error reading from file.");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
log_event("Sent HTTPS response successfully.");
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
log_event("Served requested file successfully.");
|
||||||
}
|
}
|
||||||
} else {
|
} else if (bytes_received < 0) {
|
||||||
log_event("SSL handshake failed.");
|
perror("Error receiving request");
|
||||||
|
log_event("Error receiving request");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(client_socket);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
SSL_shutdown(ssl);
|
|
||||||
SSL_free(ssl);
|
|
||||||
close(client_socket);
|
close(client_socket);
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown_server() {
|
|
||||||
config.running = 0;
|
|
||||||
|
|
||||||
int dummy_socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (dummy_socket >= 0) {
|
|
||||||
struct sockaddr_in server_addr;
|
|
||||||
memset(&server_addr, 0, sizeof(server_addr));
|
|
||||||
server_addr.sin_family = AF_INET;
|
|
||||||
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
|
||||||
server_addr.sin_port = htons(config.port);
|
|
||||||
|
|
||||||
if (connect(dummy_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
|
void *handle_https_client(void *arg) {
|
||||||
perror("Failed to connect to the server");
|
int client_socket = *((int *)arg);
|
||||||
}
|
free(arg);
|
||||||
close(dummy_socket);
|
|
||||||
} else {
|
SSL *ssl = SSL_new(ssl_ctx);
|
||||||
perror("Failed to create dummy socket");
|
if (!ssl) {
|
||||||
|
log_event("SSL_new failed");
|
||||||
|
close(client_socket);
|
||||||
|
pthread_exit(NULL);
|
||||||
}
|
}
|
||||||
|
SSL_set_fd(ssl, client_socket);
|
||||||
|
|
||||||
|
if (!server_running) {
|
||||||
|
SSL_free(ssl); // Free SSL context if server is not running
|
||||||
|
close(client_socket);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_accept(ssl) <= 0) {
|
||||||
|
perror("SSL_accept error");
|
||||||
|
ERR_print_errors_fp(stderr);
|
||||||
|
log_event("SSL handshake failed.");
|
||||||
|
SSL_free(ssl); // Free SSL context on failure
|
||||||
|
close(client_socket);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_event("SSL handshake successful!");
|
||||||
|
|
||||||
|
char buffer[MAX_REQUEST_SIZE];
|
||||||
|
ssize_t bytes_received = SSL_read(ssl, buffer, MAX_REQUEST_SIZE - 1);
|
||||||
|
|
||||||
|
if (bytes_received < 0) {
|
||||||
|
perror("SSL_read error");
|
||||||
|
ERR_print_errors_fp(stderr);
|
||||||
|
log_event("SSL_read failed");
|
||||||
|
goto cleanup;
|
||||||
|
} else if (bytes_received == 0) {
|
||||||
|
log_event("Client closed connection");
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
|
buffer[bytes_received] = '\0';
|
||||||
|
log_event("Received HTTPS request:");
|
||||||
|
log_event(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
char method[8], url[256], protocol[16];
|
||||||
|
if (parse_request_line(buffer, method, url, protocol) != 0) {
|
||||||
|
log_event("Invalid request line.");
|
||||||
|
const char *bad_request_response = "HTTP/1.1 400 Bad Request\r\n\r\nInvalid Request";
|
||||||
|
SSL_write(ssl, bad_request_response, strlen(bad_request_response));
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
|
log_event("Method:");
|
||||||
|
log_event(method);
|
||||||
|
log_event("URL:");
|
||||||
|
log_event(url);
|
||||||
|
log_event("Protocol:");
|
||||||
|
log_event(protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(url, "..") || strstr(url, "//")) {
|
||||||
|
log_event("Blocked potential directory traversal attempt.");
|
||||||
|
const char *forbidden_response = "HTTP/1.1 403 Forbidden\r\n\r\nAccess Denied";
|
||||||
|
SSL_write(ssl, forbidden_response, strlen(forbidden_response));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
char filepath[512];
|
||||||
|
snprintf(filepath, sizeof(filepath), "www%s", (*url == '/' && url[1] == '\0') ? "/index.html" : url);
|
||||||
|
log_event("Filepath:");
|
||||||
|
log_event(filepath);
|
||||||
|
|
||||||
|
int fd = open(filepath, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
perror("open error");
|
||||||
|
log_event("File open failed");
|
||||||
|
const char *not_found_response = "HTTP/1.1 404 Not Found\r\n\r\nFile Not Found";
|
||||||
|
SSL_write(ssl, not_found_response, strlen(not_found_response));
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) == -1) {
|
||||||
|
perror("fstat error");
|
||||||
|
log_event("Error getting file size.");
|
||||||
|
const char *internal_server_error = "HTTP/1.1 500 Internal Server Error\r\n\r\nInternal Server Error";
|
||||||
|
SSL_write(ssl, internal_server_error, strlen(internal_server_error));
|
||||||
|
close(fd);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t file_size = st.st_size;
|
||||||
|
|
||||||
|
char response_header[256];
|
||||||
|
snprintf(response_header, sizeof(response_header),
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Length: %ld\r\n"
|
||||||
|
"Content-Type: text/html\r\n"
|
||||||
|
"\r\n",
|
||||||
|
file_size);
|
||||||
|
|
||||||
|
SSL_write(ssl, response_header, strlen(response_header));
|
||||||
|
|
||||||
|
char file_buffer[1024];
|
||||||
|
ssize_t bytes_read;
|
||||||
|
while ((bytes_read = read(fd, file_buffer, sizeof(file_buffer))) > 0) {
|
||||||
|
if (SSL_write(ssl, file_buffer, bytes_read) <= 0) {
|
||||||
|
perror("SSL_write error");
|
||||||
|
log_event("Error sending file content.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
log_event("Served requested file successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (ssl) {
|
||||||
|
SSL_shutdown(ssl);
|
||||||
|
SSL_free(ssl);
|
||||||
|
}
|
||||||
|
close(client_socket);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void shutdown_server() {
|
||||||
|
log_event("Shutting down server...");
|
||||||
|
|
||||||
|
config.running = 0;
|
||||||
|
server_running = 0;
|
||||||
|
|
||||||
|
if (http_socket != -1) {
|
||||||
|
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, http_socket, NULL);
|
||||||
|
close(http_socket);
|
||||||
|
http_socket = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.use_https && https_socket != -1) {
|
||||||
|
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, https_socket, NULL);
|
||||||
|
close(https_socket);
|
||||||
|
https_socket = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(epoll_fd);
|
||||||
|
|
||||||
pthread_mutex_lock(&thread_count_mutex);
|
pthread_mutex_lock(&thread_count_mutex);
|
||||||
for (int i = 0; i < num_client_threads; i++) {
|
for (int i = 0; i < num_client_threads; i++) {
|
||||||
if (client_threads[i] != 0) {
|
if (client_threads[i] != 0) {
|
||||||
pthread_cancel(client_threads[i]);
|
|
||||||
pthread_join(client_threads[i], NULL);
|
pthread_join(client_threads[i], NULL);
|
||||||
|
client_threads[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
num_client_threads = 0;
|
num_client_threads = 0;
|
||||||
pthread_mutex_unlock(&thread_count_mutex);
|
pthread_mutex_unlock(&thread_count_mutex);
|
||||||
|
|
||||||
cleanup_openssl();
|
cleanup_openssl();
|
||||||
|
|
||||||
log_event("Server shutdown completed.");
|
log_event("Server shutdown completed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int parse_request_line(char *request_buffer, char *method, char *url, char *protocol) {
|
||||||
|
char *saveptr1, *saveptr2;
|
||||||
|
char *line = strtok_r(request_buffer, "\r\n", &saveptr1);
|
||||||
|
|
||||||
|
if (line == NULL) return -1;
|
||||||
|
|
||||||
|
char *token = strtok_r(line, " ", &saveptr2);
|
||||||
|
if (token == NULL) return -1;
|
||||||
|
strncpy(method, token, 7); method[7] = '\0';
|
||||||
|
|
||||||
|
token = strtok_r(NULL, " ", &saveptr2);
|
||||||
|
if (token == NULL) return -1;
|
||||||
|
strncpy(url, token, 255); url[255] = '\0';
|
||||||
|
|
||||||
|
token = strtok_r(NULL, " ", &saveptr2);
|
||||||
|
if (token == NULL) return -1;
|
||||||
|
strncpy(protocol, token, 15); protocol[15] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void signal_handler(int sig) {
|
||||||
|
if (sig == SIGINT || sig == SIGTERM) {
|
||||||
|
server_running = 0;
|
||||||
|
log_event("Signal received, shutting down...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
if (load_config("server.json", &config) != 0) {
|
if (load_config("server.json", &config) != 0) {
|
||||||
printf("Using default configuration.\n");
|
printf("Using default configuration.\n");
|
||||||
@@ -348,19 +563,36 @@ int main() {
|
|||||||
configure_ssl_context(ssl_ctx);
|
configure_ssl_context(ssl_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_t http_thread, https_thread;
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = signal_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
|
||||||
|
if (sigaction(SIGINT, &sa, NULL) == -1) {
|
||||||
|
perror("sigaction (SIGINT)");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (sigaction(SIGTERM, &sa, NULL) == -1) {
|
||||||
|
perror("sigaction (SIGTERM)");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t http_thread, https_thread;
|
||||||
pthread_create(&http_thread, NULL, start_http_server, NULL);
|
pthread_create(&http_thread, NULL, start_http_server, NULL);
|
||||||
if (config.use_https) {
|
if (config.use_https) {
|
||||||
pthread_create(&https_thread, NULL, start_https_server, NULL);
|
pthread_create(&https_thread, NULL, start_https_server, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (config.running) {
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown_server();
|
||||||
pthread_join(http_thread, NULL);
|
pthread_join(http_thread, NULL);
|
||||||
if (config.use_https) {
|
if (config.use_https) {
|
||||||
pthread_join(https_thread, NULL);
|
pthread_join(https_thread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown_server();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,22 +602,33 @@ void log_event(const char *message) {
|
|||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
struct tm tm = *localtime(&t);
|
struct tm tm = *localtime(&t);
|
||||||
char timestamp[64];
|
char timestamp[64];
|
||||||
|
|
||||||
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &tm);
|
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &tm);
|
||||||
|
|
||||||
size_t remaining_size = MAX_LOG_SIZE - strlen(server_log) - 2;
|
char log_dir[512];
|
||||||
if (remaining_size > 0) {
|
strncpy(log_dir, config.log_file, sizeof(log_dir) - 1);
|
||||||
snprintf(server_log + strlen(server_log), remaining_size, "%s: %s\n", timestamp, message);
|
log_dir[sizeof(log_dir) - 1] = '\0';
|
||||||
|
char *dir_path = dirname(log_dir);
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(dir_path, &st) != 0) {
|
||||||
|
if (mkdir(dir_path, 0777) != 0) {
|
||||||
|
fprintf(stderr, "Error creating log directory (%s): %s\n", dir_path, strerror(errno));
|
||||||
|
pthread_mutex_unlock(&log_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *logfile = fopen(config.log_file, "a");
|
FILE *logfile = fopen(config.log_file, "a");
|
||||||
if (logfile) {
|
if (!logfile) {
|
||||||
fprintf(logfile, "%s: %s\n", timestamp, message);
|
fprintf(stderr, "Error opening log file (%s): %s\n", config.log_file, strerror(errno));
|
||||||
fclose(logfile);
|
pthread_mutex_unlock(&log_mutex);
|
||||||
} else {
|
return;
|
||||||
perror("Error opening log file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fprintf(logfile, "%s: %s\n", timestamp, message) < 0) {
|
||||||
|
fprintf(stderr, "Error writing to log file: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
fclose(logfile);
|
||||||
|
|
||||||
pthread_mutex_unlock(&log_mutex);
|
pthread_mutex_unlock(&log_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user