diff --git a/dependencies/tlibc b/dependencies/tlibc index adaf5cc..ae0fa95 160000 --- a/dependencies/tlibc +++ b/dependencies/tlibc @@ -1 +1 @@ -Subproject commit adaf5cc31199b8b70404f30b51a0e4ef822d6fab +Subproject commit ae0fa95d6aee2a7427c3e3575d74af1ed360e6e5 diff --git a/src/client/ServerConnection.c b/src/client/ServerConnection.c index 670cda3..6657e78 100644 --- a/src/client/ServerConnection.c +++ b/src/client/ServerConnection.c @@ -66,8 +66,8 @@ Result(ServerConnection*) ServerConnection_open(cstr server_link_cstr){ // send PacketHeader and ClientHandshake // encryption by server public key - PacketHeader packet_header = {0}; - ClientHandshake client_handshake = {0}; + PacketHeader packet_header; + ClientHandshake client_handshake; try_void(ClientHandshake_tryConstruct(&client_handshake, &packet_header, conn->session_key)); try_void(EncryptedSocketTCP_sendStructRSA(&conn->sock, &conn->rsa_enc, &packet_header)); @@ -80,26 +80,24 @@ Result(ServerConnection*) ServerConnection_open(cstr server_link_cstr){ // handle server response switch(packet_header.type){ case PacketType_ErrorMessage: { - u32 err_msg_size = packet_header.content_size; - if(err_msg_size > conn->sock.recv_buf.size) - err_msg_size = conn->sock.recv_buf.size; - Array(u8) err_buf = Array_alloc_size(err_msg_size + 1); + ErrorMessage err_msg; + try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &err_msg)); + if(err_msg.msg_size > conn->sock.recv_buf.size) + err_msg.msg_size = conn->sock.recv_buf.size; + Array(u8) err_buf = Array_alloc_size(err_msg.msg_size + 1); bool err_msg_completed = false; - Defer( - if(!err_msg_completed) - free(err_buf.data); - ); + Defer(if(!err_msg_completed) free(err_buf.data)); - // receive error message + // receive message content try_void( EncryptedSocketTCP_recv( &conn->sock, - Array_sliceTo(err_buf, err_msg_size), + Array_sliceTo(err_buf, err_msg.msg_size), SocketRecvFlag_WholeBuffer ) ); - ((u8*)err_buf.data)[err_msg_size] = 0; + ((u8*)err_buf.data)[err_msg.msg_size] = 0; err_msg_completed = true; Return RESULT_ERROR((char*)err_buf.data, true); } diff --git a/src/common_constants.h b/src/common_constants.h index 7095110..a2b8ec6 100644 --- a/src/common_constants.h +++ b/src/common_constants.h @@ -2,7 +2,7 @@ #include "tlibc/std.h" #define USERNAME_SIZE_MIN 2 -#define USERNAME_SIZE_MAX 63 +#define USERNAME_SIZE_MAX 31 #define PASSWORD_SIZE_MIN 8 #define PASSWORD_SIZE_MAX 31 #define PASSWORD_HASH_SIZE 32 diff --git a/src/cryptography/AES.h b/src/cryptography/AES.h index 5cbfc84..2dd8fc7 100644 --- a/src/cryptography/AES.h +++ b/src/cryptography/AES.h @@ -15,7 +15,6 @@ #define AESStream_DEFAULT_CLASS (&br_aes_big_ctr_vtable) -//TODO: use PKS#7 instead of this garbage typedef struct EncryptedBlockHeader { u8 padding_size; } ATTRIBUTE_ALIGNED(16) EncryptedBlockHeader; diff --git a/src/db/idb.c b/src/db/idb.c index 71cffbc..02ac64c 100644 --- a/src/db/idb.c +++ b/src/db/idb.c @@ -286,8 +286,8 @@ Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count){ if(id + count > t->row_count){ Return RESULT_ERROR_FMT( - "Can't read " IFWIN("%llu", "%lu") " rows at index " IFWIN("%llu", "%lu") - " because table '%s' has only " IFWIN("%llu", "%lu") " rows", + "Can't read "FMT_u64" rows at index "FMT_u64 + " because table '%s' has only "FMT_u64" rows", count, id, t->name.data, t->row_count); } @@ -325,8 +325,8 @@ Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count){ if(id + count >= t->row_count){ Return RESULT_ERROR_FMT( - "Can't update " IFWIN("%llu", "%lu") " rows at index " IFWIN("%llu", "%lu") - " because table '%s' has only " IFWIN("%llu", "%lu") " rows", + "Can't update "FMT_u64" rows at index "FMT_u64 + " because table '%s' has only "FMT_u64" rows", count, id, t->name.data, t->row_count); } diff --git a/src/network/tcp-chat-protocol/constant.c b/src/network/tcp-chat-protocol/constant.c index 7c6ef44..c15a91b 100644 --- a/src/network/tcp-chat-protocol/constant.c +++ b/src/network/tcp-chat-protocol/constant.c @@ -21,14 +21,15 @@ Result(void) PacketHeader_validateType(PacketHeader* ptr, u16 expected_type){ Result(void) PacketHeader_validateContentSize(PacketHeader* ptr, u64 expected_size){ if(ptr->content_size != expected_size){ return RESULT_ERROR_FMT( - "expected message with content_size " IFWIN("%llu", "%lu") - ", but received with content_size " IFWIN("%llu", "%lu"), + "expected message with content_size "FMT_u64 + ", but received with content_size "FMT_u64, expected_size, ptr->content_size); } return RESULT_VOID; } void PacketHeader_construct(PacketHeader* ptr, u8 protocol_version, u16 type, u64 content_size){ + memset(ptr, 0, sizeof(*ptr)); ptr->magic.n = PacketHeader_MAGIC.n; ptr->protocol_version = protocol_version; ptr->type = type; diff --git a/src/network/tcp-chat-protocol/v1.c b/src/network/tcp-chat-protocol/v1.c index 3776970..b2f54b9 100644 --- a/src/network/tcp-chat-protocol/v1.c +++ b/src/network/tcp-chat-protocol/v1.c @@ -1,13 +1,55 @@ #include "v1.h" +str validateUsername_cstr(char username[USERNAME_SIZE_MAX+1], str* out_username_str){ + // must end with 0 + if(username[USERNAME_SIZE_MAX] != '\0'){ + return STR("Username string doesn't end correctly"); + } + + str u = str_from_cstr(username); + str error_str = validateUsername_str(u); + if(error_str.data) + return error_str; + + *out_username_str = u; + return str_null; +} + +str validateUsername_str(str username){ + if(username.size < USERNAME_SIZE_MIN){ + return STR("Username length is too small"); + } + + for(u32 i = 0; i < username.size; i++){ + char c = username.data[i]; + if (char_isLatinLower(c) || + char_isLatinUpper(c) || + char_isDigit(c) || + c == '.' || c == '_' || c == '-') + continue; + + return STR("Username contains restricted characters. " + "Allowed characters: latin, digits, ._-"); + } + + return str_null; +} + #define _PacketHeader_construct(T) \ PacketHeader_construct(header, PROTOCOL_VERSION, PacketType_##T, sizeof(T)) +void ErrorMessage_construct(ErrorMessage* ptr, PacketHeader* header, u32 msg_size){ + _PacketHeader_construct(ErrorMessage); + memset(ptr, 0, sizeof(*ptr)); + ptr->msg_size = msg_size; +} + Result(void) ClientHandshake_tryConstruct(ClientHandshake* ptr, PacketHeader* header, Array(u8) session_key) { Deferral(1); _PacketHeader_construct(ClientHandshake); + memset(ptr, 0, sizeof(*ptr)); try_assert(session_key.size == sizeof(ptr->session_key)); memcpy(ptr->session_key, session_key.data, session_key.size); @@ -19,6 +61,7 @@ void ServerHandshake_construct(ServerHandshake* ptr, PacketHeader* header, u64 session_id) { _PacketHeader_construct(ServerHandshake); + memset(ptr, 0, sizeof(*ptr)); ptr->session_id = session_id; } @@ -26,14 +69,31 @@ void ServerPublicInfoRequest_construct(ServerPublicInfoRequest *ptr, PacketHeade ServerPublicInfo property) { _PacketHeader_construct(ServerPublicInfoRequest); + memset(ptr, 0, sizeof(*ptr)); ptr->property = property; } +void ServerPublicInfoResponse_construct(ServerPublicInfoResponse* ptr, PacketHeader* header, + u32 data_size) +{ + _PacketHeader_construct(ServerPublicInfoResponse); + memset(ptr, 0, sizeof(*ptr)); + ptr->data_size = data_size; +} + Result(void) LoginRequest_tryConstruct(LoginRequest *ptr, PacketHeader* header, - Array(u8) token) + str username, Array(u8) token) { Deferral(1); _PacketHeader_construct(LoginRequest); + memset(ptr, 0, sizeof(*ptr)); + + str username_check_error = validateUsername_str(username); + if(username_check_error.data){ + Return RESULT_ERROR(username_check_error.data, false); + } + memcpy(ptr->username, username.data, username.size); + ptr->username[username.size] = 0; try_assert(token.size == sizeof(ptr->token)); memcpy(ptr->token, token.data, token.size); @@ -45,6 +105,8 @@ void LoginResponse_construct(LoginResponse* ptr, PacketHeader* header, u64 user_id, u64 landing_channel_id) { _PacketHeader_construct(LoginResponse); + memset(ptr, 0, sizeof(*ptr)); + ptr->user_id = user_id; ptr->landing_channel_id = landing_channel_id; } @@ -54,8 +116,12 @@ Result(void) RegisterRequest_tryConstruct(RegisterRequest *ptr, PacketHeader* he { Deferral(1); _PacketHeader_construct(RegisterRequest); + memset(ptr, 0, sizeof(*ptr)); - try_assert(username.size >= USERNAME_SIZE_MIN && username.size <= USERNAME_SIZE_MAX); + str username_check_error = validateUsername_str(username); + if(username_check_error.data){ + Return RESULT_ERROR(username_check_error.data, false); + } memcpy(ptr->username, username.data, username.size); ptr->username[username.size] = 0; @@ -69,5 +135,6 @@ void RegisterResponse_construct(RegisterResponse *ptr, PacketHeader* header, u64 user_id) { _PacketHeader_construct(RegisterResponse); + memset(ptr, 0, sizeof(*ptr)); ptr->user_id = user_id; } diff --git a/src/network/tcp-chat-protocol/v1.h b/src/network/tcp-chat-protocol/v1.h index 0b223bf..b48ae0a 100644 --- a/src/network/tcp-chat-protocol/v1.h +++ b/src/network/tcp-chat-protocol/v1.h @@ -8,6 +8,18 @@ #define ALIGN_PACKET_STRUCT ATTRIBUTE_ALIGNED(8) +/* +Valid username: +- must end with '\0' +- USERNAME_SIZE_MIN <= size <= USERNAME_SIZE_MAX +- allowed characters: latin, digits, ._- +*/ +/// validates username char[] and constructs str from it +/// @return str_null on success, stack-allocated error message on fail +str validateUsername_cstr(char username[USERNAME_SIZE_MAX+1], str* out_username_str) ATTRIBUTE_WARN_UNUSED_RESULT; + +str validateUsername_str(str username) ATTRIBUTE_WARN_UNUSED_RESULT; + typedef enum PacketType { PacketType_Invalid, @@ -23,9 +35,15 @@ typedef enum PacketType { } ATTRIBUTE_PACKED PacketType; -// typedef struct ErrorMessage { -// /* stream of size header.content_size */ -// } ErrorMessage; +#define ERROR_MESSAGE_MAX_SIZE 8192 + +typedef struct ErrorMessage { + u32 msg_size; // <= ERROR_MESSAGE_MAX_SIZE + /* stream of size msg_size */ +} ErrorMessage; + +void ErrorMessage_construct(ErrorMessage* ptr, PacketHeader* header, + u32 msg_size); typedef struct ClientHandshake { @@ -57,17 +75,22 @@ void ServerPublicInfoRequest_construct(ServerPublicInfoRequest* ptr, PacketHeade ServerPublicInfo property); -// typedef struct ServerPublicInfoResponse { -// /* stream of size header.content_size */ -// } ServerPublicInfoResponse; +typedef struct ServerPublicInfoResponse { + u32 data_size; + /* stream of size data_size */ +} ServerPublicInfoResponse; + +void ServerPublicInfoResponse_construct(ServerPublicInfoResponse* ptr, PacketHeader* header, + u32 data_size); typedef struct LoginRequest { + char username[USERNAME_SIZE_MAX + 1]; // null-terminated u8 token[PASSWORD_HASH_SIZE]; } ALIGN_PACKET_STRUCT LoginRequest; Result(void) LoginRequest_tryConstruct(LoginRequest* ptr, PacketHeader* header, - Array(u8) token); + str username, Array(u8) token); typedef struct LoginResponse { diff --git a/src/server/ClientConnection.c b/src/server/ClientConnection.c index de80e4e..80e2250 100644 --- a/src/server/ClientConnection.c +++ b/src/server/ClientConnection.c @@ -32,14 +32,14 @@ Result(ClientConnection*) ClientConnection_accept(ConnectionHandlerArgs* args) RSADecryptor_construct(&rsa_dec, &args->server->cred.rsa_sk); // receive PacketHeader - PacketHeader packet_header = {0}; + PacketHeader packet_header; try_void(EncryptedSocketTCP_recvStructRSA(&conn->sock, &rsa_dec, &packet_header)); try_void(PacketHeader_validateMagic(&packet_header)); try_void(PacketHeader_validateType(&packet_header, PacketType_ClientHandshake)); try_void(PacketHeader_validateContentSize(&packet_header, sizeof(ClientHandshake))); // receive ClientHandshake - ClientHandshake client_handshake = {0}; + ClientHandshake client_handshake; try_void(EncryptedSocketTCP_recvStructRSA(&conn->sock, &rsa_dec, &client_handshake)); // use received session key @@ -47,7 +47,7 @@ Result(ClientConnection*) ClientConnection_accept(ConnectionHandlerArgs* args) EncryptedSocketTCP_changeKey(&conn->sock, conn->session_key); // send PacketHeader and ServerHandshake over encrypted TCP socket - ServerHandshake server_handshake = {0}; + ServerHandshake server_handshake; ServerHandshake_construct(&server_handshake, &packet_header, conn->session_id); try_void(EncryptedSocketTCP_sendStruct(&conn->sock, &packet_header)); diff --git a/src/server/request_handlers/Login.c b/src/server/request_handlers/Login.c index 67fcdb7..b7f2847 100644 --- a/src/server/request_handlers/Login.c +++ b/src/server/request_handlers/Login.c @@ -4,22 +4,74 @@ declare_RequestHandler(Login) { Deferral(4); - logDebug(log_ctx, "requested %s", req_type_name); - - LoginRequest req = {0}; + logInfo(log_ctx, "requested %s", req_type_name); + + // receive request + LoginRequest req; try_void(PacketHeader_validateContentSize(req_head, sizeof(req))); try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req)); - //TODO: try authorize client - u64 user_id; - u64 landing_channel_id; + if(conn->authorized){ + try_void(sendErrorMessage(log_ctx, false, conn, res_head, + STR("is logged in already"))); + Return RESULT_VOID; + } - LoginResponse res = {0}; - LoginResponse_construct(&res, res_head, user_id, landing_channel_id); + // validate username + str username_str = str_null; + str username_check_error = validateUsername_cstr(req.username, &username_str); + if(username_check_error.data){ + try_void(sendErrorMessage(log_ctx, false, conn, res_head, username_check_error)); + Return RESULT_VOID; + } + + // cakculate hash of received token + u8 token_hash[PASSWORD_HASH_SIZE]; + hash_password( + Array_construct_size(req.token, sizeof(req.token)), + token_hash, + PASSWORD_HASH_LVL_ROUNDS + ); + + // lock users cache + try_stderrcode(pthread_mutex_lock(&server->users_cache_mutex)); + bool unlocked_users_cache_mutex = false; + Defer(if(!unlocked_users_cache_mutex) pthread_mutex_unlock(&server->users_cache_mutex)); + + // try get id from name cache + u64* id_ptr = HashMap_tryGetPtr(&server->users_name_id_map, username_str); + if(id_ptr == NULL){ + try_void(sendErrorMessage_f(log_ctx, false, conn, res_head, + "Username '%s' is not registered\n", + username_str.data)); + Return RESULT_VOID; + } + u64 user_id = *id_ptr; + + // get user by id + try_assert(List_len(server->users_cache_list, User) < user_id); + User* u = &List_index(server->users_cache_list, User, user_id); + + // validate token hash + if(memcmp(token_hash, u->token_hash, sizeof(token_hash)) != 0){ + try_void(sendErrorMessage(log_ctx, false, conn, res_head, + STR("wrong password"))); + Return RESULT_VOID; + } + + // manually unlock mutex + pthread_mutex_unlock(&server->users_cache_mutex); + unlocked_users_cache_mutex = true; + + // authorize + conn->authorized = true; + logInfo(log_ctx, "authorized user '%s'", username_str.data); + + // send response + LoginResponse res; + LoginResponse_construct(&res, res_head, user_id, server->landing_channel_id); try_void(EncryptedSocketTCP_sendStruct(&conn->sock, res_head)); try_void(EncryptedSocketTCP_sendStruct(&conn->sock, &res)); - conn->authorized = true; - logInfo(log_ctx, "client authorized"); Return RESULT_VOID; } diff --git a/src/server/request_handlers/Register.c b/src/server/request_handlers/Register.c index bc955c5..b6d6eac 100644 --- a/src/server/request_handlers/Register.c +++ b/src/server/request_handlers/Register.c @@ -3,29 +3,18 @@ declare_RequestHandler(Register) { Deferral(4); - logDebug(log_ctx, "requested %s", req_type_name); + logInfo(log_ctx, "requested %s", req_type_name); - RegisterRequest req = {0}; + // receive request + RegisterRequest req; try_void(PacketHeader_validateContentSize(req_head, sizeof(req))); try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req)); - //TODO: reject usernames with restricted characters - // must end with 0 - if(req.username[sizeof(req.username - 1)] != 0){ - try(char* err_msg, p, sendErrorMessage(conn, res_head, - "Username is incorrect\n")); - logWarn(log_ctx, "%s", err_msg); - free(err_msg); - Return RESULT_VOID; - } - // check username size - str username_str = str_from_cstr(req.username); - if(username_str.size < USERNAME_SIZE_MIN){ - try(char* err_msg, p, sendErrorMessage(conn, res_head, - "Username length (in bytes) must be >= %i and <= %i\n", - USERNAME_SIZE_MIN, USERNAME_SIZE_MAX)); - logWarn(log_ctx, "%s", err_msg); - free(err_msg); + // validate username + str username_str = str_null; + str username_check_error = validateUsername_cstr(req.username, &username_str); + if(username_check_error.data){ + try_void(sendErrorMessage(log_ctx, false, conn, res_head, username_check_error)); Return RESULT_VOID; } @@ -36,11 +25,9 @@ declare_RequestHandler(Register) // check if name is taken if(HashMap_tryGetPtr(&server->users_name_id_map, username_str) != NULL){ - try(char* err_msg, p, sendErrorMessage(conn, res_head, - "User with name '%s' already exists\n", + try_void(sendErrorMessage_f(log_ctx, false, conn, res_head, + "Username'%s' already exists\n", username_str.data)); - logWarn(log_ctx, "%s", err_msg); - free(err_msg); Return RESULT_VOID; } @@ -66,7 +53,10 @@ declare_RequestHandler(Register) pthread_mutex_unlock(&server->users_cache_mutex); unlocked_users_cache_mutex = true; - RegisterResponse res = {0}; + logInfo(log_ctx, "registered user '%s'", username_str.data); + + // send response + RegisterResponse res; RegisterResponse_construct(&res, res_head, user_id); try_void(EncryptedSocketTCP_sendStruct(&conn->sock, res_head)); try_void(EncryptedSocketTCP_sendStruct(&conn->sock, &res)); diff --git a/src/server/request_handlers/ServerPublicInfo.c b/src/server/request_handlers/ServerPublicInfo.c index e1485d2..4466bee 100644 --- a/src/server/request_handlers/ServerPublicInfo.c +++ b/src/server/request_handlers/ServerPublicInfo.c @@ -3,21 +3,20 @@ declare_RequestHandler(ServerPublicInfo) { Deferral(4); - logDebug(log_ctx, "requested %s", req_type_name); + logInfo(log_ctx, "requested %s", req_type_name); - ServerPublicInfoRequest req = {0}; + // receive request + ServerPublicInfoRequest req; try_void(PacketHeader_validateContentSize(req_head, sizeof(req))); try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req)); - //TODO: try find requested info + // find requested info Array(u8) content; switch(req.property){ default:{ - try(char* err_msg, p, sendErrorMessage(conn, res_head, + try_void(sendErrorMessage_f(log_ctx, false, conn, res_head, "Unknown ServerPublicInfo property %u", req.property)); - logWarn(log_ctx, "%s", err_msg); - free(err_msg); Return RESULT_VOID; } case ServerPublicInfo_Name: @@ -28,9 +27,11 @@ declare_RequestHandler(ServerPublicInfo) break; } - PacketHeader_construct(res_head, - PROTOCOL_VERSION, PacketType_ServerPublicInfoResponse, content.size); + // send response + ServerPublicInfoResponse res; + ServerPublicInfoResponse_construct(&res, res_head, content.size); try_void(EncryptedSocketTCP_sendStruct(&conn->sock, res_head)); + try_void(EncryptedSocketTCP_sendStruct(&conn->sock, &res)); try_void(EncryptedSocketTCP_send(&conn->sock, content)); Return RESULT_VOID; diff --git a/src/server/request_handlers/request_handlers.h b/src/server/request_handlers/request_handlers.h index df93459..901661e 100644 --- a/src/server/request_handlers/request_handlers.h +++ b/src/server/request_handlers/request_handlers.h @@ -4,10 +4,17 @@ #include "log.h" -Result(char*) __sendErrorMessage_va(ClientConnection* conn, PacketHeader* res_head, +Result(void) sendErrorMessage(cstr log_ctx, bool logAsError, + ClientConnection* conn, PacketHeader* res_head, + str msg); + +Result(void) __sendErrorMessage_fv(cstr log_ctx, bool logAsError, + ClientConnection* conn, PacketHeader* res_head, cstr format, va_list argv); -Result(char*) sendErrorMessage(ClientConnection* conn, PacketHeader* res_head, - cstr format, ...) ATTRIBUTE_CHECK_FORMAT_PRINTF(3, 4); + +Result(void) sendErrorMessage_f(cstr log_ctx, bool logAsError, + ClientConnection* conn, PacketHeader* res_head, + cstr format, ...) ATTRIBUTE_CHECK_FORMAT_PRINTF(5, 6); #define declare_RequestHandler(TYPE) \ diff --git a/src/server/request_handlers/send_error.c b/src/server/request_handlers/send_error.c index f0d8c99..2c02083 100644 --- a/src/server/request_handlers/send_error.c +++ b/src/server/request_handlers/send_error.c @@ -1,34 +1,54 @@ #include "request_handlers.h" +#include "log.h" -Result(char*) __sendErrorMessage_va(ClientConnection* conn, PacketHeader* res_head, +Result(void) sendErrorMessage(cstr log_ctx, bool logAsError, + ClientConnection* conn, PacketHeader* res_head, + str msg) +{ + Deferral(1); + + //limit ErrorMessage size to fit into EncryptedSocketTCP.internal_buffer_size + if(msg.size > ERROR_MESSAGE_MAX_SIZE) + msg.size = ERROR_MESSAGE_MAX_SIZE; + + if(logAsError){ + logError(log_ctx, FMT_str, msg.size, msg.data); + } else { + logWarn(log_ctx, FMT_str, msg.size, msg.data); + } + + ErrorMessage res; + ErrorMessage_construct(&res, res_head, msg.size); + try_void(EncryptedSocketTCP_sendStruct(&conn->sock, res_head)); + try_void(EncryptedSocketTCP_sendStruct(&conn->sock, &res)); + try_void(EncryptedSocketTCP_send(&conn->sock, str_castTo_Array(msg))); + + Return RESULT_VOID; +} + +Result(void) __sendErrorMessage_fv(cstr log_ctx, bool logAsError, + ClientConnection* conn, PacketHeader* res_head, cstr format, va_list argv) { Deferral(4); - - Array(u8) err_buf; - err_buf.data = vsprintf_malloc(format, argv); - err_buf.size = strlen(err_buf.data); - //limit ErrorMessage size to fit into EncryptedSocketTCP.internal_buffer_size - if(err_buf.size > NETWORK_BUFFER_SIZE) - err_buf.size = NETWORK_BUFFER_SIZE; - bool err_complete = false; - Defer(if(!err_complete) free(err_buf.data)); - PacketHeader_construct(res_head, - PROTOCOL_VERSION, PacketType_ErrorMessage, err_buf.size); - try_void(EncryptedSocketTCP_sendStruct(&conn->sock, res_head)); - try_void(EncryptedSocketTCP_send(&conn->sock, err_buf)); + str msg = str_from_cstr(vsprintf_malloc(format, argv)); + Defer(free(msg.data)); + try_void(sendErrorMessage(log_ctx, logAsError, conn, res_head, msg)); - err_complete = true; - Return RESULT_VALUE(p, err_buf.data); + Return RESULT_VOID; } -Result(char*) sendErrorMessage(ClientConnection* conn, PacketHeader* res_head, +Result(void) sendErrorMessage_f(cstr log_ctx, bool logAsError, + ClientConnection* conn, PacketHeader* res_head, cstr format, ...) { + Deferral(1); + va_list argv; va_start(argv, format); - ResultVar(char*) err_msg = __sendErrorMessage_va(conn, res_head, format, argv); - va_end(argv); - return err_msg; + Defer(va_end(argv)); + try_void(__sendErrorMessage_fv(log_ctx, logAsError, conn, res_head, format, argv)); + + return RESULT_VOID; } diff --git a/src/server/request_handlers/template b/src/server/request_handlers/template index 360a4dc..5e016b7 100644 --- a/src/server/request_handlers/template +++ b/src/server/request_handlers/template @@ -1,9 +1,20 @@ #include "request_handlers.h" -declare_RequestHandler(T) +declare_RequestHandler(NAME) { Deferral(4); - logDebug(log_ctx, "requested %s", req_type_name); + logInfo(log_ctx, "requested %s", req_type_name); + // receive request + NAME##Request req; + try_void(PacketHeader_validateContentSize(req_head, sizeof(req))); + try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req)); + + // send response + NAME##Response res; + NAME##Response_construct(&res, res_head, ); + try_void(EncryptedSocketTCP_sendStruct(&conn->sock, res_head)); + try_void(EncryptedSocketTCP_sendStruct(&conn->sock, &res)); + Return RESULT_VOID; } diff --git a/src/server/server.c b/src/server/server.c index e78c358..adf067f 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -52,6 +52,14 @@ Result(Server*) Server_createFromConfig(cstr config_path){ try_void(config_findValue(config_str, STR("description"), &tmp_str, true)); server->description = str_copy(tmp_str); + // parse landing_channel_id + try_void(config_findValue(config_str, STR("landing_channel_id"), &tmp_str, true)); + char* lci_cstr = str_copy(tmp_str).data; + Defer(free(lci_cstr)); + if(sscanf(lci_cstr, FMT_u64, &server->landing_channel_id) != 1){ + Return RESULT_ERROR("can't parse 'landing_channel_id' value as number", false); + } + // parse local_address try_void(config_findValue(config_str, STR("local_address"), &tmp_str, true)); char* local_end_cstr = str_copy(tmp_str).data; @@ -133,7 +141,7 @@ Result(void) Server_run(Server* server){ static void* handleConnection(void* _args){ ConnectionHandlerArgs* args = (ConnectionHandlerArgs*)_args; char log_ctx[64]; - sprintf(log_ctx, "Session-" IFWIN("%llx", "%lx"), args->session_id); + sprintf(log_ctx, "Session-"FMT_x64, args->session_id); ResultVar(void) r = try_handleConnection(args, log_ctx); if(r.error){ @@ -159,8 +167,8 @@ static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_c logInfo(log_ctx, "session accepted"); // handle requests - PacketHeader req_head = {0}; - PacketHeader res_head = {0}; + PacketHeader req_head; + PacketHeader res_head; while(true){ sleepMsec(20); //TODO: implement some additional check if socket is dead or not @@ -171,12 +179,9 @@ static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_c switch(req_head.type){ // send error message and close connection default: - try(char* err_msg, p, - sendErrorMessage(conn, &res_head, - "Received unexpected packet of type %u", - req_head.type)); - logWarn(log_ctx, "%s", err_msg); - free(err_msg); + try_void(sendErrorMessage_f(log_ctx, false, conn, &res_head, + "Received unexpected packet of type %u", + req_head.type)); Return RESULT_VOID; // unauthorized requests diff --git a/src/server/server.h b/src/server/server.h index a03d54c..c6ab4e4 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -45,6 +45,7 @@ void ClientConnection_close(ClientConnection* conn); typedef struct Server { str name; str description; + u64 landing_channel_id; EndpointIPv4 local_end; ServerCredentials cred; IncrementalDB* db;