#include "responses.h" #define LOGGER conn->server->logger #define LOG_FUNC conn->server->log_func declare_RequestHandler(Register) { Deferral(4); logInfo(log_ctx, "requested %s", req_type_name); // receive request RegisterRequest req; try_void(PacketHeader_validateContentSize(req_head, sizeof(req))); try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req)); if(conn->authorized){ try_void(sendErrorMessage(log_ctx, conn, res_head, LogSeverity_Warn, STR("is authorized in already") )); Return RESULT_VOID; } // validate username str username_str = str_null; str name_error_str = validateUsername_cstr(req.username, &username_str); if(name_error_str.data){ Defer(str_free(name_error_str)); try_void(sendErrorMessage(log_ctx, conn, res_head, LogSeverity_Warn, name_error_str )); Return RESULT_VOID; } // lock users cache try_stderrcode(pthread_mutex_lock(&conn->server->users_cache_mutex)); bool unlocked_users_cache_mutex = false; // unlock mutex on error catch Defer( if(!unlocked_users_cache_mutex) pthread_mutex_unlock(&conn->server->users_cache_mutex) ); // check if name is taken if(HashMap_tryGetPtr(&conn->server->users_name_id_map, username_str) != NULL){ try_void(sendErrorMessage_f(log_ctx, conn, res_head, LogSeverity_Warn, "Username '%s' already exists", username_str.data)); Return RESULT_VOID; } // initialize new user UserInfo user; memset(&user, 0, sizeof(UserInfo)); user.name_len = username_str.size; memcpy(user.name, username_str.data, user.name_len); memcpy(user.token, req.token, sizeof(req.token)); DateTime_getUTC(&user.registration_time_utc); // save new user to db and cache try(u64 user_id, u, idb_pushRow(conn->server->db_users_table, &user)); try_assert(user_id == List_len(conn->server->users_cache_list, UserInfo)); List_pushMany(&conn->server->users_cache_list, UserInfo, &user, 1); try_assert(HashMap_tryPush(&conn->server->users_name_id_map, username_str, &user_id)); // manually unlock mutex pthread_mutex_unlock(&conn->server->users_cache_mutex); unlocked_users_cache_mutex = true; 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)); Return RESULT_VOID; }