#include #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; }