tcp-chat/src/server/server.c

124 lines
3.8 KiB
C

#include <pthread.h>
#include "tlibc/filesystem.h"
#include "db/idb.h"
#include "server.h"
#include "config.h"
#include "log.h"
#include "network/tcp-chat-protocol/v1.h"
typedef struct ConnectionHandlerArgs {
Socket accepted_socket;
EndpointIPv4 client_end;
u64 session_id;
} ConnectionHandlerArgs;
static void* handle_connection(void* _args);
static Result(void) try_handle_connection(ConnectionHandlerArgs* args, cstr log_ctx);
static ServerCredentials* _server_credentials = NULL;
static Result(void) parseConfig(cstr config_path){
Deferral(8);
// open file
try(FILE* config_file, p, file_open(config_path, FO_ReadExisting));
Defer(file_close(config_file));
// read whole file into Array(char)
try(i64 config_file_size, i, file_getSize(config_file));
Array(char) config_buf = Array_alloc(char, config_file_size);
Defer(free(config_buf.data));
try_void(file_readBytesArray(config_file, config_buf));
str config_str = Array_castTo_str(config_buf, false);
str sk_base64;
str pk_base64;
try_void(config_findValue(config_str, STR("rsa_private_key"), &sk_base64, true));
try_void(config_findValue(config_str, STR("rsa_public_key"), &pk_base64, true));
char* sk_base64_cstr = str_copy(sk_base64).data;
char* pk_base64_cstr = str_copy(pk_base64).data;
Defer(
free(sk_base64_cstr);
free(pk_base64_cstr);
);
try(_server_credentials, p, ServerCredentials_create(sk_base64_cstr, pk_base64_cstr));
Return RESULT_VOID;
}
Result(void) server_run(cstr server_endpoint_cstr, cstr config_path){
Deferral(32);
cstr log_ctx = "Server/MainThread";
logInfo(log_ctx, "starting server");
logDebug(log_ctx, "parsing config");
try_void(parseConfig(config_path));
Defer(ServerCredentials_free(_server_credentials));
logDebug(log_ctx, "initializing main socket");
EndpointIPv4 server_end;
EndpointIPv4_parse(server_endpoint_cstr, &server_end);
try(Socket main_socket, i, socket_open_TCP());
try_void(socket_bind(main_socket, server_end));
try_void(socket_listen(main_socket, 512));
logInfo(log_ctx, "server is listening at %s", server_endpoint_cstr);
u64 session_id = 1;
while(true){
ConnectionHandlerArgs* args = (ConnectionHandlerArgs*)malloc(sizeof(ConnectionHandlerArgs));
try(args->accepted_socket, i, socket_accept(main_socket, &args->client_end));
args->session_id = session_id++;
pthread_t conn_thread = {0};
//TODO: use async IO instead of threads to not waste system resources
// while waiting for incoming data in 100500 threads
try_stderrcode(pthread_create(&conn_thread, NULL, handle_connection, args));
try_stderrcode(pthread_detach(conn_thread));
}
Return RESULT_VOID;
}
static void* handle_connection(void* _args){
ConnectionHandlerArgs* args = (ConnectionHandlerArgs*)_args;
char log_ctx[64];
sprintf(log_ctx, "Session-" IFWIN("%llx", "%lx"), args->session_id);
Result(void) r = try_handle_connection(args, log_ctx);
if(r.error){
str error_s = Error_toStr(r.error);
logError(log_ctx, "%s", error_s.data);
free(error_s.data);
}
return NULL;
}
static Result(void) try_handle_connection(ConnectionHandlerArgs* args, cstr log_ctx){
Deferral(64);
Defer(free(args));
ClientConnection* conn = NULL;
Defer(
ClientConnection_close(conn);
logInfo(log_ctx, "session closed");
);
// establish encrypted connection
try(conn, p,
ClientConnection_accept(
_server_credentials,
args->accepted_socket,
args->client_end,
args->session_id
)
);
logInfo(log_ctx, "session accepted");
// handle unauthorized requests
while(true){
sleepMsec(10);
}
Return RESULT_VOID;
}