implemented Login and Register requests
This commit is contained in:
parent
23c98e14df
commit
806f0359d0
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -7,7 +7,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/bin/tcp-chat",
|
"program": "${workspaceFolder}/bin/tcp-chat",
|
||||||
"windows": { "program": "${workspaceFolder}/bin/tcp-chat.exe" },
|
"windows": { "program": "${workspaceFolder}/bin/tcp-chat.exe" },
|
||||||
// "args": [ "-l" ],
|
"args": [ "-l" ],
|
||||||
"preLaunchTask": "build_exec_dbg",
|
"preLaunchTask": "build_exec_dbg",
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/bin",
|
"cwd": "${workspaceFolder}/bin",
|
||||||
|
|||||||
2
dependencies/tlibc
vendored
2
dependencies/tlibc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit ec164dc4e92dd20401b97e979507ec8f04f04af7
|
Subproject commit 225a48a8d98fb5ba7edf80e882a8ae2c40852407
|
||||||
@ -26,3 +26,9 @@ Result(void) Client_getServerName(Client* self, str* out_name);
|
|||||||
/// @param self connected client
|
/// @param self connected client
|
||||||
/// @param out_name owned by Client, fetched from server during Client_connect
|
/// @param out_name owned by Client, fetched from server during Client_connect
|
||||||
Result(void) Client_getServerDescription(Client* self, str* out_desc);
|
Result(void) Client_getServerDescription(Client* self, str* out_desc);
|
||||||
|
|
||||||
|
/// Create new account on connected server
|
||||||
|
Result(void) Client_register(Client* self, u64* out_user_id);
|
||||||
|
|
||||||
|
/// Authorize on connected server
|
||||||
|
Result(void) Client_login(Client* self, u64* out_user_id, u64* out_landing_channel_id);
|
||||||
|
|||||||
@ -6,10 +6,13 @@
|
|||||||
#define PASSWORD_SIZE_MIN 8
|
#define PASSWORD_SIZE_MIN 8
|
||||||
#define PASSWORD_SIZE_MAX 31
|
#define PASSWORD_SIZE_MAX 31
|
||||||
#define PASSWORD_HASH_SIZE 32
|
#define PASSWORD_HASH_SIZE 32
|
||||||
|
#define HOSTADDR_SIZE_MIN 4
|
||||||
|
#define HOSTADDR_SIZE_MAX 255
|
||||||
|
#define PRIVATE_KEY_BASE64_SIZE_MAX 1724
|
||||||
|
#define PUBLIC_KEY_BASE64_SIZE_MAX 699
|
||||||
|
#define SERVER_NAME_SIZE_MIN 1
|
||||||
|
#define SERVER_NAME_SIZE_MAX 127
|
||||||
|
#define SERVER_DESC_SIZE_MAX 1023
|
||||||
#define CHANNEL_NAME_SIZE_MIN 1
|
#define CHANNEL_NAME_SIZE_MIN 1
|
||||||
#define CHANNEL_NAME_SIZE_MAX 127
|
#define CHANNEL_NAME_SIZE_MAX 127
|
||||||
#define CHANNEL_DESC_SIZE_MAX 1023
|
#define CHANNEL_DESC_SIZE_MAX 1023
|
||||||
#define PRIVATE_KEY_BASE64_SIZE_MAX 1724
|
|
||||||
#define PUBLIC_KEY_BASE64_SIZE_MAX 699
|
|
||||||
#define HOSTADDR_SIZE_MIN 4
|
|
||||||
#define HOSTADDR_SIZE_MAX 255
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include "cli/ClientCLI/ClientCLI.h"
|
#include "cli/ClientCLI/ClientCLI.h"
|
||||||
#include "cli/ClientCLI/db_tables.h"
|
|
||||||
#include "cli/term.h"
|
#include "cli/term.h"
|
||||||
#include "tcp-chat/common_constants.h"
|
#include "tcp-chat/common_constants.h"
|
||||||
#include "tlibc/time.h"
|
#include "tlibc/time.h"
|
||||||
@ -23,22 +22,28 @@ static const str farewell_art = STR(
|
|||||||
#define is_alias(LITERAL) str_equals(command, STR(LITERAL))
|
#define is_alias(LITERAL) str_equals(command, STR(LITERAL))
|
||||||
|
|
||||||
static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* password_out);
|
static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* password_out);
|
||||||
static Result(void) ClientCLI_commandExec(ClientCLI* self, str command, bool* stop);
|
static Result(void) ClientCLI_execCommand(ClientCLI* self, str command, bool* stop);
|
||||||
static Result(void) ClientCLI_openUserDB(ClientCLI* self);
|
static Result(void) ClientCLI_openUserDB(ClientCLI* self);
|
||||||
static Result(void) ClientCLI_saveServerInfo(ClientCLI* self,
|
static Result(Server*) ClientCLI_saveServerInfo(ClientCLI* self,
|
||||||
cstr server_addr_cstr, cstr server_pk_base64,
|
str addr, str pk_base64, str name, str desc);
|
||||||
str server_name, str server_description);
|
static Result(Server*) ClientCLI_joinNewServer(ClientCLI* self);
|
||||||
|
static Result(Server*) ClientCLI_selectServerFromCache(ClientCLI* self);
|
||||||
|
static Result(void) ClientCLI_showServerInfo(ClientCLI* self, Server* server);
|
||||||
|
static Result(void) ClientCLI_register(ClientCLI* self);
|
||||||
|
static Result(void) ClientCLI_login(ClientCLI* self);
|
||||||
|
|
||||||
void ClientCLI_destroy(ClientCLI* self){
|
void ClientCLI_destroy(ClientCLI* self){
|
||||||
if(!self)
|
if(!self)
|
||||||
return;
|
return;
|
||||||
Client_free(self->client);
|
Client_free(self->client);
|
||||||
idb_close(self->user_db);
|
idb_close(self->db);
|
||||||
|
pthread_mutex_destroy(&self->servers_cache_mutex);
|
||||||
|
List_destroy(self->servers_cache_list);
|
||||||
|
HashMap_destroy(&self->servers_addr_id_map);
|
||||||
}
|
}
|
||||||
void ClientCLI_construct(ClientCLI* self){
|
void ClientCLI_construct(ClientCLI* self){
|
||||||
self->client = NULL;
|
self->client = NULL;
|
||||||
self->user_db = NULL;
|
self->db = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) ClientCLI_run(ClientCLI* self) {
|
Result(void) ClientCLI_run(ClientCLI* self) {
|
||||||
@ -46,7 +51,7 @@ Result(void) ClientCLI_run(ClientCLI* self) {
|
|||||||
|
|
||||||
try_void(term_init());
|
try_void(term_init());
|
||||||
term_clear();
|
term_clear();
|
||||||
printf("%s\n", greeting_art.data);
|
printf(FMT_str"\n", greeting_art.size, greeting_art.data);
|
||||||
|
|
||||||
// create Client
|
// create Client
|
||||||
str username = str_null, password = str_null;
|
str username = str_null, password = str_null;
|
||||||
@ -75,11 +80,11 @@ Result(void) ClientCLI_run(ClientCLI* self) {
|
|||||||
if(command_input.size == 0)
|
if(command_input.size == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ResultVar(void) com_result = ClientCLI_commandExec(self, command_input, &stop);
|
ResultVar(void) com_result = ClientCLI_execCommand(self, command_input, &stop);
|
||||||
if(com_result.error){
|
if(com_result.error){
|
||||||
Error_addCallPos(com_result.error, ErrorCallPos_here());
|
Error_addCallPos(com_result.error, ErrorCallPos_here());
|
||||||
str e_str = Error_toStr(com_result.error);
|
str e_str = Error_toStr(com_result.error);
|
||||||
printf("%s\n", e_str.data);
|
printf(FMT_str"\n", e_str.size, e_str.data);
|
||||||
str_free(e_str);
|
str_free(e_str);
|
||||||
Error_free(com_result.error);
|
Error_free(com_result.error);
|
||||||
}
|
}
|
||||||
@ -105,6 +110,7 @@ static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* pas
|
|||||||
printf("ERROR: username length (in bytes) must be >= %i and <= %i\n",
|
printf("ERROR: username length (in bytes) must be >= %i and <= %i\n",
|
||||||
USERNAME_SIZE_MIN, USERNAME_SIZE_MAX);
|
USERNAME_SIZE_MIN, USERNAME_SIZE_MAX);
|
||||||
}
|
}
|
||||||
|
//TODO: validate username characters
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +137,11 @@ static Result(void) ClientCLI_askUserNameAndPassword(str* username_out, str* pas
|
|||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result(void) ClientCLI_commandExec(ClientCLI* self, str command, bool* stop){
|
static Result(void) ClientCLI_execCommand(ClientCLI* self, str command, bool* stop){
|
||||||
Deferral(64);
|
Deferral(64);
|
||||||
|
|
||||||
if(is_alias("q") || is_alias("quit") || is_alias("exit")){
|
if(is_alias("q") || is_alias("quit") || is_alias("exit")){
|
||||||
printf("%s\n", farewell_art.data);
|
printf(FMT_str"\n", farewell_art.size, farewell_art.data);
|
||||||
*stop = true;
|
*stop = true;
|
||||||
}
|
}
|
||||||
else if(is_alias("clear")){
|
else if(is_alias("clear")){
|
||||||
@ -143,55 +149,37 @@ static Result(void) ClientCLI_commandExec(ClientCLI* self, str command, bool* st
|
|||||||
}
|
}
|
||||||
else if(is_alias("h") || is_alias("help")){
|
else if(is_alias("h") || is_alias("help")){
|
||||||
printf(
|
printf(
|
||||||
"COMMANDS:\n"
|
"COMMANDS:\n"
|
||||||
"h, help Show this message.\n"
|
"Without connection:\n"
|
||||||
"q, quit, exit Close the program.\n"
|
" h, help Show this message.\n"
|
||||||
"clear Clear the screen.\n"
|
" q, quit, exit Close the program.\n"
|
||||||
"j, join Join a server.\n"
|
" clear Clear the screen.\n"
|
||||||
"c, connect Connect to a server you joined.\n"
|
"Connection:\n"
|
||||||
|
" j, join Join a new server and select it.\n"
|
||||||
|
" s, select Select a server you joined before.\n"
|
||||||
|
"After connection:\n"
|
||||||
|
" r, register Create account on selected server\n"
|
||||||
|
" l, login Authorize on selected server\n"
|
||||||
|
"Authorized:\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (is_alias("j") || is_alias("join")){
|
else if (is_alias("j") || is_alias("join")){
|
||||||
// ask server address
|
// ask address and key, connect to server
|
||||||
printf("Enter server address (ip:port):\n");
|
try_void(ClientCLI_joinNewServer(self));
|
||||||
char server_addr_cstr[HOSTADDR_SIZE_MAX + 1];
|
}
|
||||||
try_void(term_readLine(server_addr_cstr, sizeof(server_addr_cstr)));
|
else if(is_alias("s") || is_alias("select")){
|
||||||
str server_addr_str = str_from_cstr(server_addr_cstr);
|
// show scrollable list of servers, get selected one
|
||||||
str_trim(&server_addr_str, true);
|
try_void(ClientCLI_selectServerFromCache(self));
|
||||||
|
}
|
||||||
// ask server public key
|
else if(is_alias("r") || is_alias("register")){
|
||||||
printf("Enter server public key (RSA-Public-<SIZE>:<DATA>):\n");
|
try_void(ClientCLI_register(self));
|
||||||
char server_pk_cstr[PUBLIC_KEY_BASE64_SIZE_MAX + 1];
|
}
|
||||||
try_void(term_readLine(server_pk_cstr, sizeof(server_pk_cstr)));
|
else if(is_alias("l") || is_alias("login")){
|
||||||
str server_pk_str = str_from_cstr(server_pk_cstr);
|
try_void(ClientCLI_login(self));
|
||||||
str_trim(&server_pk_str, true);
|
// TODO: call Client_runIO():
|
||||||
|
|
||||||
// connect to server
|
|
||||||
printf("connecting to server...\n");
|
|
||||||
try_void(Client_connect(self->client, server_addr_cstr, server_pk_cstr));
|
|
||||||
printf("connection established\n");
|
|
||||||
|
|
||||||
// show server info
|
|
||||||
str server_name = str_null;
|
|
||||||
str server_description = str_null;
|
|
||||||
try_void(Client_getServerName(self->client, &server_name));
|
|
||||||
try_void(Client_getServerName(self->client, &server_description));
|
|
||||||
printf("server name: %s\n", server_name.data);
|
|
||||||
printf("server description: %s\n", server_description.data);
|
|
||||||
|
|
||||||
try_void(ClientCLI_saveServerInfo(self, server_addr_cstr, server_pk_cstr,
|
|
||||||
server_name, server_description));
|
|
||||||
// TODO: ask in loop: log in / register
|
|
||||||
|
|
||||||
//TODO: call Client_runIO():
|
|
||||||
// function with infinite loop which sends and receives messages
|
// function with infinite loop which sends and receives messages
|
||||||
// with navigation across server channels
|
// with navigation across server channels
|
||||||
}
|
}
|
||||||
else if(is_alias("c") || is_alias("connect")){
|
|
||||||
// TODO: read saved servers from database
|
|
||||||
// TODO: show scrollable list of servers, get selected one
|
|
||||||
// TODO: ask in loop: log in / register
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
printf("ERROR: unknown command.\n"
|
printf("ERROR: unknown command.\n"
|
||||||
"Use 'h' to see list of avaliable commands\n");
|
"Use 'h' to see list of avaliable commands\n");
|
||||||
@ -200,6 +188,127 @@ static Result(void) ClientCLI_commandExec(ClientCLI* self, str command, bool* st
|
|||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_joinNewServer(ClientCLI* self){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
// ask server address
|
||||||
|
printf("Enter server address (ip:port):\n");
|
||||||
|
char server_addr_cstr[HOSTADDR_SIZE_MAX + 1];
|
||||||
|
try_void(term_readLine(server_addr_cstr, sizeof(server_addr_cstr)));
|
||||||
|
str server_addr_str = str_from_cstr(server_addr_cstr);
|
||||||
|
str_trim(&server_addr_str, true);
|
||||||
|
|
||||||
|
// ask server public key
|
||||||
|
printf("Enter server public key (RSA-Public-<SIZE>:<DATA>):\n");
|
||||||
|
char server_pk_cstr[PUBLIC_KEY_BASE64_SIZE_MAX + 1];
|
||||||
|
try_void(term_readLine(server_pk_cstr, sizeof(server_pk_cstr)));
|
||||||
|
str server_pk_str = str_from_cstr(server_pk_cstr);
|
||||||
|
str_trim(&server_pk_str, true);
|
||||||
|
|
||||||
|
printf("Connecting to server...\n");
|
||||||
|
try_void(Client_connect(self->client, server_addr_cstr, server_pk_cstr));
|
||||||
|
printf("Connection established\n");
|
||||||
|
|
||||||
|
str server_name = str_null;
|
||||||
|
str server_description = str_null;
|
||||||
|
try_void(Client_getServerName(self->client, &server_name));
|
||||||
|
try_void(Client_getServerDescription(self->client, &server_description));
|
||||||
|
try(Server* server, p, ClientCLI_saveServerInfo(self,
|
||||||
|
server_addr_str, server_pk_str,
|
||||||
|
server_name, server_description));
|
||||||
|
|
||||||
|
try_void(ClientCLI_showServerInfo(self, server));
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_selectServerFromCache(ClientCLI* self){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
// lock servers cache
|
||||||
|
try_stderrcode(pthread_mutex_lock(&self->servers_cache_mutex));
|
||||||
|
Defer(pthread_mutex_unlock(&self->servers_cache_mutex));
|
||||||
|
|
||||||
|
u32 servers_count = List_len(self->servers_cache_list, Server);
|
||||||
|
if(servers_count == 0){
|
||||||
|
printf("No servers found in cache\n");
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(u32 id = 0; id < servers_count; id++){
|
||||||
|
Server* row = &List_index(self->servers_cache_list, Server, id);
|
||||||
|
printf("[%02u] "FMT_str"\n", id, row->name_len, row->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[32];
|
||||||
|
u32 id = -1;
|
||||||
|
while(true) {
|
||||||
|
printf("Type 'q' to cancel\n");
|
||||||
|
printf("Select server (number): ");
|
||||||
|
try_void(term_readLine(buf, sizeof(buf)));
|
||||||
|
str input_line = str_from_cstr(buf);
|
||||||
|
str_trim(&input_line, true);
|
||||||
|
if(str_equals(input_line, STR("q"))){
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
if(sscanf(buf, FMT_u32, &id) != 1){
|
||||||
|
printf("ERROR: not a number\n");
|
||||||
|
}
|
||||||
|
else if(id >= servers_count){
|
||||||
|
printf("ERROR: not a server number: %u\n", id);
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
Server* server = &List_index(self->servers_cache_list, Server, id);
|
||||||
|
|
||||||
|
printf("Connecting to '"FMT_str"'...\n", server->address_len, server->address);
|
||||||
|
try_void(Client_connect(self->client, server->address, server->pk_base64));
|
||||||
|
printf("Connection established\n");
|
||||||
|
|
||||||
|
bool server_info_changed = false;
|
||||||
|
// update cached server name
|
||||||
|
str name = str_null;
|
||||||
|
try_void(Client_getServerName(self->client, &name));
|
||||||
|
if(!str_equals(name, str_construct(server->name, server->name_len, true))){
|
||||||
|
server_info_changed = true;
|
||||||
|
if(name.size > SERVER_NAME_SIZE_MAX)
|
||||||
|
name.size = SERVER_NAME_SIZE_MAX;
|
||||||
|
server->name_len = name.size;
|
||||||
|
memcpy(server->name, name.data, server->name_len);
|
||||||
|
}
|
||||||
|
// update cached server description
|
||||||
|
str desc = str_null;
|
||||||
|
try_void(Client_getServerDescription(self->client, &desc));
|
||||||
|
if(!str_equals(desc, str_construct(server->desc, server->desc_len, true))){
|
||||||
|
server_info_changed = true;
|
||||||
|
if(desc.size > SERVER_DESC_SIZE_MAX)
|
||||||
|
desc.size = SERVER_DESC_SIZE_MAX;
|
||||||
|
server->desc_len = desc.size;
|
||||||
|
memcpy(server->desc, desc.data, server->desc_len);
|
||||||
|
}
|
||||||
|
if(server_info_changed){
|
||||||
|
try_void(idb_updateRow(self->db_servers_table, id, server));
|
||||||
|
}
|
||||||
|
|
||||||
|
try_void(ClientCLI_showServerInfo(self, server));
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_showServerInfo(ClientCLI* self, Server* server){
|
||||||
|
Deferral(8);
|
||||||
|
(void)self;
|
||||||
|
|
||||||
|
printf("Server Name: "FMT_str"\n", server->name_len, server->name);
|
||||||
|
printf("Host Address: "FMT_str"\n", server->address_len, server->address);
|
||||||
|
printf("Description:\n"FMT_str"\n\n", server->desc_len, server->desc);
|
||||||
|
printf("Public Key:\n" FMT_str"\n\n", server->pk_base64_len, server->pk_base64);
|
||||||
|
printf("Type 'register' if you don't have an account on the server.\n");
|
||||||
|
printf("Type 'login' to authorize on the server.\n");
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
static Result(void) ClientCLI_openUserDB(ClientCLI* self){
|
static Result(void) ClientCLI_openUserDB(ClientCLI* self){
|
||||||
Deferral(8);
|
Deferral(8);
|
||||||
|
|
||||||
@ -207,42 +316,105 @@ static Result(void) ClientCLI_openUserDB(ClientCLI* self){
|
|||||||
Array(u8) user_data_key = Client_getUserDataKey(self->client);
|
Array(u8) user_data_key = Client_getUserDataKey(self->client);
|
||||||
str user_db_dir = str_from_cstr(strcat_malloc("client-db", path_seps, username.data));
|
str user_db_dir = str_from_cstr(strcat_malloc("client-db", path_seps, username.data));
|
||||||
Defer(free(user_db_dir.data));
|
Defer(free(user_db_dir.data));
|
||||||
try(self->user_db, p, idb_open(user_db_dir, user_data_key));
|
try(self->db, p, idb_open(user_db_dir, user_data_key));
|
||||||
|
|
||||||
|
// load servers table
|
||||||
|
pthread_mutex_init(&self->servers_cache_mutex, NULL);
|
||||||
|
try(self->db_servers_table, p, idb_getOrCreateTable(self->db, STR("servers"), sizeof(Server)));
|
||||||
|
// load whole table to list
|
||||||
|
try(u64 servers_count, u, idb_getRowCount(self->db_servers_table));
|
||||||
|
self->servers_cache_list = List_alloc(Server, servers_count);
|
||||||
|
try_void(idb_getRows(self->db_servers_table, 0, self->servers_cache_list.data, servers_count));
|
||||||
|
self->servers_cache_list.size = sizeof(Server) * servers_count;
|
||||||
|
// build address-id map
|
||||||
|
HashMap_construct(&self->servers_addr_id_map, u64, NULL);
|
||||||
|
for(u64 id = 0; id < servers_count; id++){
|
||||||
|
Server* row = &List_index(self->servers_cache_list, Server, id);
|
||||||
|
str key = str_construct(row->address, row->address_len, true);
|
||||||
|
if(!HashMap_tryPush(&self->servers_addr_id_map, key, &id)){
|
||||||
|
Return RESULT_ERROR_FMT("duplicate server address '"FMT_str"'", key.size, key.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result(void) ClientCLI_saveServerInfo(ClientCLI* self,
|
static Result(Server*) ClientCLI_saveServerInfo(ClientCLI* self,
|
||||||
cstr server_addr_cstr, cstr server_pk_base64,
|
str addr, str pk_base64, str name, str desc){
|
||||||
str server_name, str server_description){
|
|
||||||
Deferral(8);
|
Deferral(8);
|
||||||
|
|
||||||
ServerInfo si;
|
// create new server info
|
||||||
memset(&si, 0, sizeof(ServerInfo));
|
Server server;
|
||||||
|
memset(&server, 0, sizeof(Server));
|
||||||
// address
|
// address
|
||||||
si.address_len = strlen(server_addr_cstr);
|
if(addr.size > HOSTADDR_SIZE_MAX)
|
||||||
memcpy(si.address, server_addr_cstr, si.address_len);
|
addr.size = HOSTADDR_SIZE_MAX;
|
||||||
si.address[si.address_len] = 0;
|
server.address_len = addr.size;
|
||||||
|
memcpy(server.address, addr.data, server.address_len);
|
||||||
// public key
|
// public key
|
||||||
si.pk_base64_len = strlen(server_pk_base64);
|
if(pk_base64.size > PUBLIC_KEY_BASE64_SIZE_MAX)
|
||||||
memcpy(si.pk_base64, server_addr_cstr, si.pk_base64_len);
|
pk_base64.size = PUBLIC_KEY_BASE64_SIZE_MAX;
|
||||||
si.pk_base64[si.pk_base64_len] = 0;
|
server.pk_base64_len = pk_base64.size;
|
||||||
|
memcpy(server.pk_base64, pk_base64.data, server.pk_base64_len);
|
||||||
// name
|
// name
|
||||||
si.name_len = server_name.size;
|
if(name.size > SERVER_NAME_SIZE_MAX)
|
||||||
memcpy(si.name, server_name.data, si.name_len);
|
name.size = SERVER_NAME_SIZE_MAX;
|
||||||
si.name[si.name_len] = 0;
|
server.name_len = name.size;
|
||||||
|
memcpy(server.name, name.data, server.name_len);
|
||||||
// description
|
// description
|
||||||
si.desc_len = server_name.size;
|
if(desc.size > SERVER_DESC_SIZE_MAX)
|
||||||
memcpy(si.desc, server_description.data, si.desc_len);
|
desc.size = SERVER_DESC_SIZE_MAX;
|
||||||
si.desc[si.desc_len] = 0;
|
server.desc_len = desc.size;
|
||||||
|
memcpy(server.desc, desc.data, server.desc_len);
|
||||||
|
|
||||||
// TODO: check server_address_id_cache_map
|
// lock servers cache
|
||||||
(void)self;
|
try_stderrcode(pthread_mutex_lock(&self->servers_cache_mutex));
|
||||||
// TODO: save server info to user's db
|
Defer(pthread_mutex_unlock(&self->servers_cache_mutex));
|
||||||
|
|
||||||
|
// try find server id in cache
|
||||||
|
Server* cached_row_ptr = NULL;
|
||||||
|
u64* id_ptr = NULL;
|
||||||
|
id_ptr = HashMap_tryGetPtr(&self->servers_addr_id_map, addr);
|
||||||
|
if(id_ptr){
|
||||||
|
// update existing server
|
||||||
|
u64 id = *id_ptr;
|
||||||
|
try_void(idb_updateRow(self->db_servers_table, id, &server));
|
||||||
|
try_assert(id < List_len(self->servers_cache_list, Server));
|
||||||
|
cached_row_ptr = &List_index(self->servers_cache_list, Server, id);
|
||||||
|
memcpy(cached_row_ptr, &server, sizeof(Server));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// push new server
|
||||||
|
try(u64 id, u, idb_pushRow(self->db_servers_table, &server));
|
||||||
|
try_assert(id == List_len(self->servers_cache_list, Server));
|
||||||
|
List_pushMany(&self->servers_cache_list, Server, &server, 1);
|
||||||
|
cached_row_ptr = &List_index(self->servers_cache_list, Server, id);
|
||||||
|
try_assert(HashMap_tryPush(&self->servers_addr_id_map, addr, &id));
|
||||||
|
}
|
||||||
|
|
||||||
|
Return RESULT_VALUE(p, cached_row_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_register(ClientCLI* self){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
u64 user_id = 0;
|
||||||
|
try_void(Client_register(self->client, &user_id));
|
||||||
|
printf("Registered successfully\n");
|
||||||
|
printf("user_id: "FMT_u64"\n", user_id);
|
||||||
|
// TODO: use user_id somewhere
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(void) ClientCLI_login(ClientCLI* self){
|
||||||
|
Deferral(8);
|
||||||
|
|
||||||
|
u64 user_id = 0, landing_channel_id = 0;
|
||||||
|
try_void(Client_login(self->client, &user_id, &landing_channel_id));
|
||||||
|
printf("Authorized successfully\n");
|
||||||
|
printf("user_id: "FMT_u64", landing_channel_id: "FMT_u64"\n", user_id, landing_channel_id);
|
||||||
|
// TODO: use user_id, landing_channel_id somewhere
|
||||||
|
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "tlibc/collections/HashMap.h"
|
||||||
|
#include "tlibc/collections/List.h"
|
||||||
#include "tcp-chat/client.h"
|
#include "tcp-chat/client.h"
|
||||||
#include "db/idb.h"
|
#include "db/idb.h"
|
||||||
|
#include "cli/ClientCLI/db_tables.h"
|
||||||
|
|
||||||
typedef struct ClientCLI {
|
typedef struct ClientCLI {
|
||||||
Client* client;
|
Client* client;
|
||||||
IncrementalDB* user_db;
|
IncrementalDB* db;
|
||||||
|
Table* db_servers_table;
|
||||||
|
pthread_mutex_t servers_cache_mutex;
|
||||||
|
List(Server) servers_cache_list; // index is id
|
||||||
|
HashMap(u64) servers_addr_id_map; // key is server address
|
||||||
} ClientCLI;
|
} ClientCLI;
|
||||||
|
|
||||||
void ClientCLI_construct(ClientCLI* self);
|
void ClientCLI_construct(ClientCLI* self);
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
#include "tcp-chat/common_constants.h"
|
#include "tcp-chat/common_constants.h"
|
||||||
#include "tlibc/time.h"
|
#include "tlibc/time.h"
|
||||||
|
|
||||||
typedef struct ServerInfo {
|
typedef struct Server {
|
||||||
char address[HOSTADDR_SIZE_MAX + 1];
|
|
||||||
u16 address_len;
|
u16 address_len;
|
||||||
char pk_base64[PUBLIC_KEY_BASE64_SIZE_MAX + 1];
|
char address[HOSTADDR_SIZE_MAX + 1];
|
||||||
u32 pk_base64_len;
|
u32 pk_base64_len;
|
||||||
char name[CHANNEL_NAME_SIZE_MAX + 1];
|
char pk_base64[PUBLIC_KEY_BASE64_SIZE_MAX + 1];
|
||||||
u16 name_len;
|
u16 name_len;
|
||||||
char desc[CHANNEL_DESC_SIZE_MAX + 1];
|
char name[SERVER_NAME_SIZE_MAX + 1];
|
||||||
u16 desc_len;
|
u16 desc_len;
|
||||||
} ATTRIBUTE_ALIGNED(16*1024) ServerInfo;
|
char desc[SERVER_DESC_SIZE_MAX + 1];
|
||||||
|
} ATTRIBUTE_ALIGNED(16*1024) Server;
|
||||||
|
|||||||
@ -39,6 +39,7 @@ Result(ServerConnection*) ServerConnection_open(cstr server_addr_cstr, cstr serv
|
|||||||
|
|
||||||
// connect to server address
|
// connect to server address
|
||||||
try(Socket _s, i, socket_open_TCP());
|
try(Socket _s, i, socket_open_TCP());
|
||||||
|
// TODO: client socket waits infinitely if server is paused on breakpoint
|
||||||
try_void(socket_TCP_enableAliveChecks_default(_s));
|
try_void(socket_TCP_enableAliveChecks_default(_s));
|
||||||
try_void(socket_connect(_s, conn->server_end));
|
try_void(socket_connect(_s, conn->server_end));
|
||||||
EncryptedSocketTCP_construct(&conn->sock, _s, NETWORK_BUFFER_SIZE, conn->session_key);
|
EncryptedSocketTCP_construct(&conn->sock, _s, NETWORK_BUFFER_SIZE, conn->session_key);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "client/client_internal.h"
|
#include "client/client_internal.h"
|
||||||
|
#include "client/requests/requests.h"
|
||||||
|
|
||||||
void Client_free(Client* self){
|
void Client_free(Client* self){
|
||||||
if(!self)
|
if(!self)
|
||||||
@ -63,17 +64,58 @@ Array(u8) Client_getUserDataKey(Client* client){
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result(void) Client_getServerName(Client* self, str* out_name){
|
Result(void) Client_getServerName(Client* self, str* out_name){
|
||||||
if(self->server_connection == NULL){
|
Deferral(1);
|
||||||
return RESULT_ERROR("Client is not connected to a server", false);
|
try_assert(self != NULL);
|
||||||
}
|
try_assert(self->server_connection != NULL);
|
||||||
|
|
||||||
*out_name = self->server_connection->server_name;
|
*out_name = self->server_connection->server_name;
|
||||||
return RESULT_VOID;
|
|
||||||
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) Client_getServerDescription(Client* self, str* out_desc){
|
Result(void) Client_getServerDescription(Client* self, str* out_desc){
|
||||||
if(self->server_connection == NULL){
|
Deferral(1);
|
||||||
return RESULT_ERROR("Client is not connected to a server", false);
|
try_assert(self != NULL);
|
||||||
}
|
try_assert(self->server_connection != NULL);
|
||||||
|
|
||||||
*out_desc = self->server_connection->server_description;
|
*out_desc = self->server_connection->server_description;
|
||||||
return RESULT_VOID;
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Client_register(Client* self, u64* out_user_id){
|
||||||
|
Deferral(1);
|
||||||
|
try_assert(self != NULL);
|
||||||
|
try_assert(self->server_connection != NULL);
|
||||||
|
|
||||||
|
PacketHeader req_head, res_head;
|
||||||
|
RegisterRequest req;
|
||||||
|
RegisterResponse res;
|
||||||
|
// TODO: hash token with server public key
|
||||||
|
try_void(RegisterRequest_tryConstruct(&req, &req_head, self->username, self->token));
|
||||||
|
try_void(sendRequest(&self->server_connection->sock, &req_head, &req));
|
||||||
|
try_void(recvResponse(&self->server_connection->sock, &res_head, &res, PacketType_RegisterResponse));
|
||||||
|
self->server_connection->user_id = res.user_id;
|
||||||
|
*out_user_id = res.user_id;
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Client_login(Client* self, u64* out_user_id, u64* out_landing_channel_id){
|
||||||
|
Deferral(1);
|
||||||
|
try_assert(self != NULL);
|
||||||
|
try_assert(self->server_connection != NULL);
|
||||||
|
|
||||||
|
PacketHeader req_head, res_head;
|
||||||
|
LoginRequest req;
|
||||||
|
LoginResponse res;
|
||||||
|
// TODO: hash token with server public key
|
||||||
|
try_void(LoginRequest_tryConstruct(&req, &req_head, self->username, self->token));
|
||||||
|
try_void(sendRequest(&self->server_connection->sock, &req_head, &req));
|
||||||
|
try_void(recvResponse(&self->server_connection->sock, &res_head, &res, PacketType_LoginResponse));
|
||||||
|
self->server_connection->user_id = res.user_id;
|
||||||
|
*out_user_id = res.user_id;
|
||||||
|
*out_landing_channel_id = res.landing_channel_id;
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ typedef struct ServerConnection {
|
|||||||
EncryptedSocketTCP sock;
|
EncryptedSocketTCP sock;
|
||||||
str server_name;
|
str server_name;
|
||||||
str server_description;
|
str server_description;
|
||||||
|
u64 user_id;
|
||||||
} ServerConnection;
|
} ServerConnection;
|
||||||
|
|
||||||
/// @param server_addr_cstr
|
/// @param server_addr_cstr
|
||||||
|
|||||||
@ -27,9 +27,7 @@ Result(void) config_findValue(str config_str, str key, str* value, bool throwNot
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(throwNotFoundError){
|
if(throwNotFoundError){
|
||||||
char* key_cstr = str_copy(key).data;
|
char* err_msg = sprintf_malloc("can't find key '"FMT_str"'", key.size, key.data);
|
||||||
char* err_msg = sprintf_malloc("can't find key '%s'", key_cstr);
|
|
||||||
free(key_cstr);
|
|
||||||
return RESULT_ERROR(err_msg, true);
|
return RESULT_ERROR(err_msg, true);
|
||||||
}
|
}
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
|
|||||||
@ -103,9 +103,10 @@ Result(u32) AESBlockDecryptor_decrypt(AESBlockDecryptor* ptr,
|
|||||||
Array(u8) src, Array(u8) dst)
|
Array(u8) src, Array(u8) dst)
|
||||||
{
|
{
|
||||||
Deferral(4);
|
Deferral(4);
|
||||||
try_assert(src.size >= AESBlockEncryptor_calcDstSize(0));
|
u32 overhead_size = AESBlockEncryptor_calcDstSize(0);
|
||||||
|
try_assert(src.size >= overhead_size);
|
||||||
try_assert(src.size % 16 == 0 && "src must be array of 16-byte blocks");
|
try_assert(src.size % 16 == 0 && "src must be array of 16-byte blocks");
|
||||||
try_assert(dst.size >= src.size);
|
try_assert(dst.size >= src.size - overhead_size);
|
||||||
|
|
||||||
// read IV from the beginning of src
|
// read IV from the beginning of src
|
||||||
__Array_readNext(ptr->iv, &src, __AES_BLOCK_IV_SIZE);
|
__Array_readNext(ptr->iv, &src, __AES_BLOCK_IV_SIZE);
|
||||||
|
|||||||
@ -86,6 +86,9 @@ static Result(void) Table_writeHeader(Table* t){
|
|||||||
try_void(file_seek(t->table_file, 0, SeekOrigin_Start));
|
try_void(file_seek(t->table_file, 0, SeekOrigin_Start));
|
||||||
// write header
|
// write header
|
||||||
try_void(file_writeStructs(t->table_file, &t->header, sizeof(t->header), 1));
|
try_void(file_writeStructs(t->table_file, &t->header, sizeof(t->header), 1));
|
||||||
|
// TODO: add more fflush calls
|
||||||
|
fflush(t->table_file);
|
||||||
|
fflush(t->changes_file);
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +190,7 @@ Result(IncrementalDB*) idb_open(str db_dir, NULLABLE(Array(u8) aes_key)){
|
|||||||
|
|
||||||
if(aes_key.size != 0){
|
if(aes_key.size != 0){
|
||||||
db->aes_key = Array_copy(aes_key);
|
db->aes_key = Array_copy(aes_key);
|
||||||
|
//TODO: validate aes encryption key
|
||||||
}
|
}
|
||||||
|
|
||||||
db->db_dir = str_copy(db_dir);
|
db->db_dir = str_copy(db_dir);
|
||||||
|
|||||||
@ -93,7 +93,6 @@ Result(void) LoginRequest_tryConstruct(LoginRequest *ptr, PacketHeader* header,
|
|||||||
Return RESULT_ERROR(username_check_error.data, false);
|
Return RESULT_ERROR(username_check_error.data, false);
|
||||||
}
|
}
|
||||||
memcpy(ptr->username, username.data, username.size);
|
memcpy(ptr->username, username.data, username.size);
|
||||||
ptr->username[username.size] = 0;
|
|
||||||
|
|
||||||
try_assert(token.size == sizeof(ptr->token));
|
try_assert(token.size == sizeof(ptr->token));
|
||||||
memcpy(ptr->token, token.data, token.size);
|
memcpy(ptr->token, token.data, token.size);
|
||||||
@ -123,7 +122,6 @@ Result(void) RegisterRequest_tryConstruct(RegisterRequest *ptr, PacketHeader* he
|
|||||||
Return RESULT_ERROR(username_check_error.data, false);
|
Return RESULT_ERROR(username_check_error.data, false);
|
||||||
}
|
}
|
||||||
memcpy(ptr->username, username.data, username.size);
|
memcpy(ptr->username, username.data, username.size);
|
||||||
ptr->username[username.size] = 0;
|
|
||||||
|
|
||||||
try_assert(token.size == sizeof(ptr->token));
|
try_assert(token.size == sizeof(ptr->token));
|
||||||
memcpy(ptr->token, token.data, token.size);
|
memcpy(ptr->token, token.data, token.size);
|
||||||
|
|||||||
@ -3,15 +3,15 @@
|
|||||||
#include "tlibc/time.h"
|
#include "tlibc/time.h"
|
||||||
|
|
||||||
typedef struct User {
|
typedef struct User {
|
||||||
char name[USERNAME_SIZE_MAX + 1]; // null-terminated
|
|
||||||
u16 name_len;
|
u16 name_len;
|
||||||
|
char name[USERNAME_SIZE_MAX + 1]; // null-terminated
|
||||||
u8 token_hash[PASSWORD_HASH_SIZE]; // token is hashed again on server side
|
u8 token_hash[PASSWORD_HASH_SIZE]; // token is hashed again on server side
|
||||||
DateTime registration_time;
|
DateTime registration_time;
|
||||||
} ATTRIBUTE_ALIGNED(256) User;
|
} ATTRIBUTE_ALIGNED(256) User;
|
||||||
|
|
||||||
typedef struct Channel {
|
typedef struct Channel {
|
||||||
char name[CHANNEL_NAME_SIZE_MAX + 1];
|
|
||||||
u16 name_len;
|
u16 name_len;
|
||||||
char desc[CHANNEL_DESC_SIZE_MAX + 1];
|
char name[CHANNEL_NAME_SIZE_MAX + 1];
|
||||||
u16 desc_len;
|
u16 desc_len;
|
||||||
|
char desc[CHANNEL_DESC_SIZE_MAX + 1];
|
||||||
} ATTRIBUTE_ALIGNED(4*1024) Channel;
|
} ATTRIBUTE_ALIGNED(4*1024) Channel;
|
||||||
|
|||||||
@ -16,7 +16,7 @@ declare_RequestHandler(Login)
|
|||||||
if(conn->authorized){
|
if(conn->authorized){
|
||||||
try_void(sendErrorMessage(server, log_ctx, conn, res_head,
|
try_void(sendErrorMessage(server, log_ctx, conn, res_head,
|
||||||
LogSeverity_Warn,
|
LogSeverity_Warn,
|
||||||
STR("is logged in already")
|
STR("is authorized in already")
|
||||||
));
|
));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ declare_RequestHandler(Login)
|
|||||||
if(id_ptr == NULL){
|
if(id_ptr == NULL){
|
||||||
try_void(sendErrorMessage_f(server, log_ctx, conn, res_head,
|
try_void(sendErrorMessage_f(server, log_ctx, conn, res_head,
|
||||||
LogSeverity_Warn,
|
LogSeverity_Warn,
|
||||||
"Username '%s' is not registered\n",
|
"Username '%s' is not registered",
|
||||||
username_str.data
|
username_str.data
|
||||||
));
|
));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
@ -58,7 +58,7 @@ declare_RequestHandler(Login)
|
|||||||
u64 user_id = *id_ptr;
|
u64 user_id = *id_ptr;
|
||||||
|
|
||||||
// get user by id
|
// get user by id
|
||||||
try_assert(List_len(server->users_cache_list, User) < user_id);
|
try_assert(user_id < List_len(server->users_cache_list, User));
|
||||||
User* u = &List_index(server->users_cache_list, User, user_id);
|
User* u = &List_index(server->users_cache_list, User, user_id);
|
||||||
|
|
||||||
// validate token hash
|
// validate token hash
|
||||||
|
|||||||
@ -13,6 +13,14 @@ declare_RequestHandler(Register)
|
|||||||
try_void(PacketHeader_validateContentSize(req_head, sizeof(req)));
|
try_void(PacketHeader_validateContentSize(req_head, sizeof(req)));
|
||||||
try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req));
|
try_void(EncryptedSocketTCP_recvStruct(&conn->sock, &req));
|
||||||
|
|
||||||
|
if(conn->authorized){
|
||||||
|
try_void(sendErrorMessage(server, log_ctx, conn, res_head,
|
||||||
|
LogSeverity_Warn,
|
||||||
|
STR("is authorized in already")
|
||||||
|
));
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
// validate username
|
// validate username
|
||||||
str username_str = str_null;
|
str username_str = str_null;
|
||||||
str username_check_error = validateUsername_cstr(req.username, &username_str);
|
str username_check_error = validateUsername_cstr(req.username, &username_str);
|
||||||
@ -27,13 +35,17 @@ declare_RequestHandler(Register)
|
|||||||
// lock users cache
|
// lock users cache
|
||||||
try_stderrcode(pthread_mutex_lock(&server->users_cache_mutex));
|
try_stderrcode(pthread_mutex_lock(&server->users_cache_mutex));
|
||||||
bool unlocked_users_cache_mutex = false;
|
bool unlocked_users_cache_mutex = false;
|
||||||
Defer(if(!unlocked_users_cache_mutex) pthread_mutex_unlock(&server->users_cache_mutex));
|
// unlock mutex on error catch
|
||||||
|
Defer(
|
||||||
|
if(!unlocked_users_cache_mutex)
|
||||||
|
pthread_mutex_unlock(&server->users_cache_mutex)
|
||||||
|
);
|
||||||
|
|
||||||
// check if name is taken
|
// check if name is taken
|
||||||
if(HashMap_tryGetPtr(&server->users_name_id_map, username_str) != NULL){
|
if(HashMap_tryGetPtr(&server->users_name_id_map, username_str) != NULL){
|
||||||
try_void(sendErrorMessage_f(server, log_ctx, conn, res_head,
|
try_void(sendErrorMessage_f(server, log_ctx, conn, res_head,
|
||||||
LogSeverity_Warn,
|
LogSeverity_Warn,
|
||||||
"Username'%s' already exists\n",
|
"Username'%s' already exists",
|
||||||
username_str.data));
|
username_str.data));
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
@ -42,9 +54,8 @@ declare_RequestHandler(Register)
|
|||||||
User user;
|
User user;
|
||||||
memset(&user, 0, sizeof(User));
|
memset(&user, 0, sizeof(User));
|
||||||
|
|
||||||
memcpy(user.name, username_str.data, username_str.size);
|
|
||||||
user.name_len = username_str.size;
|
user.name_len = username_str.size;
|
||||||
user.name[user.name_len] = 0;
|
memcpy(user.name, username_str.data, user.name_len);
|
||||||
|
|
||||||
hash_password(
|
hash_password(
|
||||||
Array_construct_size(req.token, sizeof(req.token)),
|
Array_construct_size(req.token, sizeof(req.token)),
|
||||||
@ -56,8 +67,8 @@ declare_RequestHandler(Register)
|
|||||||
|
|
||||||
// save new user to db and cache
|
// save new user to db and cache
|
||||||
try(u64 user_id, u, idb_pushRow(server->db_users_table, &user));
|
try(u64 user_id, u, idb_pushRow(server->db_users_table, &user));
|
||||||
try_assert(List_len(server->users_cache_list, User) == user_id);
|
try_assert(user_id == List_len(server->users_cache_list, User));
|
||||||
List_push(&server->users_cache_list, User, user);
|
List_pushMany(&server->users_cache_list, User, &user, 1);
|
||||||
try_assert(HashMap_tryPush(&server->users_name_id_map, username_str, &user_id));
|
try_assert(HashMap_tryPush(&server->users_name_id_map, username_str, &user_id));
|
||||||
|
|
||||||
// manually unlock mutex
|
// manually unlock mutex
|
||||||
|
|||||||
@ -33,29 +33,29 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
|
|||||||
Deferral(16);
|
Deferral(16);
|
||||||
cstr log_ctx = "ServerInit";
|
cstr log_ctx = "ServerInit";
|
||||||
|
|
||||||
Server* server = (Server*)malloc(sizeof(Server));
|
Server* self = (Server*)malloc(sizeof(Server));
|
||||||
memset(server, 0, sizeof(Server));
|
memset(self, 0, sizeof(Server));
|
||||||
bool success = false;
|
bool success = false;
|
||||||
Defer(if(!success) Server_free(server));
|
Defer(if(!success) Server_free(self));
|
||||||
|
|
||||||
server->logger = logger;
|
self->logger = logger;
|
||||||
server->log_func = log_func;
|
self->log_func = log_func;
|
||||||
logDebug(log_ctx, "parsing config");
|
logDebug(log_ctx, "parsing config");
|
||||||
|
|
||||||
// parse name
|
// parse name
|
||||||
str tmp_str = str_null;
|
str tmp_str = str_null;
|
||||||
try_void(config_findValue(config_str, STR("name"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("name"), &tmp_str, true));
|
||||||
server->name = str_copy(tmp_str);
|
self->name = str_copy(tmp_str);
|
||||||
|
|
||||||
// parse description
|
// parse description
|
||||||
try_void(config_findValue(config_str, STR("description"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("description"), &tmp_str, true));
|
||||||
server->description = str_copy(tmp_str);
|
self->description = str_copy(tmp_str);
|
||||||
|
|
||||||
// parse landing_channel_id
|
// parse landing_channel_id
|
||||||
try_void(config_findValue(config_str, STR("landing_channel_id"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("landing_channel_id"), &tmp_str, true));
|
||||||
char* lci_cstr = str_copy(tmp_str).data;
|
char* lci_cstr = str_copy(tmp_str).data;
|
||||||
Defer(free(lci_cstr));
|
Defer(free(lci_cstr));
|
||||||
if(sscanf(lci_cstr, FMT_u64, &server->landing_channel_id) != 1){
|
if(sscanf(lci_cstr, FMT_u64, &self->landing_channel_id) != 1){
|
||||||
Return RESULT_ERROR("can't parse 'landing_channel_id' value as number", false);
|
Return RESULT_ERROR("can't parse 'landing_channel_id' value as number", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
|
|||||||
try_void(config_findValue(config_str, STR("local_address"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("local_address"), &tmp_str, true));
|
||||||
char* local_end_cstr = str_copy(tmp_str).data;
|
char* local_end_cstr = str_copy(tmp_str).data;
|
||||||
Defer(free(local_end_cstr));
|
Defer(free(local_end_cstr));
|
||||||
try_void(EndpointIPv4_parse(local_end_cstr, &server->local_end));
|
try_void(EndpointIPv4_parse(local_end_cstr, &self->local_end));
|
||||||
|
|
||||||
// parse rsa_private_key
|
// parse rsa_private_key
|
||||||
try_void(config_findValue(config_str, STR("rsa_private_key"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("rsa_private_key"), &tmp_str, true));
|
||||||
@ -75,8 +75,8 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
|
|||||||
char* pk_base64_cstr = str_copy(tmp_str).data;
|
char* pk_base64_cstr = str_copy(tmp_str).data;
|
||||||
Defer(free(pk_base64_cstr));
|
Defer(free(pk_base64_cstr));
|
||||||
|
|
||||||
try_void(RSA_parsePrivateKey_base64(sk_base64_cstr, &server->rsa_sk));
|
try_void(RSA_parsePrivateKey_base64(sk_base64_cstr, &self->rsa_sk));
|
||||||
try_void(RSA_parsePublicKey_base64(pk_base64_cstr, &server->rsa_pk));
|
try_void(RSA_parsePublicKey_base64(pk_base64_cstr, &self->rsa_pk));
|
||||||
|
|
||||||
// parse db_aes_key
|
// parse db_aes_key
|
||||||
try_void(config_findValue(config_str, STR("db_aes_key"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("db_aes_key"), &tmp_str, true));
|
||||||
@ -86,27 +86,30 @@ Result(Server*) Server_create(str config_str, void* logger, LogFunction_t log_fu
|
|||||||
|
|
||||||
// parse db_dir and open db
|
// parse db_dir and open db
|
||||||
try_void(config_findValue(config_str, STR("db_dir"), &tmp_str, true));
|
try_void(config_findValue(config_str, STR("db_dir"), &tmp_str, true));
|
||||||
try(server->db, p, idb_open(tmp_str, db_aes_key));
|
try(self->db, p, idb_open(tmp_str, db_aes_key));
|
||||||
|
|
||||||
// build users cache
|
// build users cache
|
||||||
pthread_mutex_init(&server->users_cache_mutex, NULL);
|
logDebug(log_ctx, "loading users...");
|
||||||
try(server->db_users_table, p, idb_getOrCreateTable(server->db, STR("users"), sizeof(User)));
|
pthread_mutex_init(&self->users_cache_mutex, NULL);
|
||||||
try(u64 users_count, u, idb_getRowCount(server->db_users_table));
|
try(self->db_users_table, p, idb_getOrCreateTable(self->db, STR("users"), sizeof(User)));
|
||||||
server->users_cache_list = List_alloc(User, users_count);
|
|
||||||
HashMap_construct(&server->users_name_id_map, u64, NULL);
|
|
||||||
// load whole table to list
|
// load whole table to list
|
||||||
try_void(idb_getRows(server->db_users_table, 0, server->users_cache_list.data, users_count));
|
try(u64 users_count, u, idb_getRowCount(self->db_users_table));
|
||||||
|
self->users_cache_list = List_alloc(User, users_count);
|
||||||
|
try_void(idb_getRows(self->db_users_table, 0, self->users_cache_list.data, users_count));
|
||||||
|
self->users_cache_list.size = sizeof(User) * users_count;
|
||||||
// build name-id map
|
// build name-id map
|
||||||
|
HashMap_construct(&self->users_name_id_map, u64, NULL);
|
||||||
for(u64 id = 0; id < users_count; id++){
|
for(u64 id = 0; id < users_count; id++){
|
||||||
User* u = &List_index(server->users_cache_list, User, id);
|
User* row = &List_index(self->users_cache_list, User, id);
|
||||||
str key = str_construct(u->name, u->name_len, true);
|
str key = str_construct(row->name, row->name_len, true);
|
||||||
if(!HashMap_tryPush(&server->users_name_id_map, key, &id)){
|
if(!HashMap_tryPush(&self->users_name_id_map, key, &id)){
|
||||||
Return RESULT_ERROR_FMT("duplicate user name '%s'", u->name);
|
Return RESULT_ERROR_FMT("duplicate user name '"FMT_str"'", key.size, key.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logDebug(log_ctx, "loaded "FMT_u64" users", users_count);
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
Return RESULT_VALUE(p, server);
|
Return RESULT_VALUE(p, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef LOGGER
|
#undef LOGGER
|
||||||
@ -155,7 +158,7 @@ static void* handleConnection(void* _args){
|
|||||||
if(r.error){
|
if(r.error){
|
||||||
Error_addCallPos(r.error, ErrorCallPos_here());
|
Error_addCallPos(r.error, ErrorCallPos_here());
|
||||||
str e_str = Error_toStr(r.error);
|
str e_str = Error_toStr(r.error);
|
||||||
logError(log_ctx, "%s", e_str.data);
|
logError(log_ctx, FMT_str, e_str.size, e_str.data);
|
||||||
str_free(e_str);
|
str_free(e_str);
|
||||||
Error_free(r.error);
|
Error_free(r.error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,8 +28,8 @@ typedef struct Server {
|
|||||||
IncrementalDB* db;
|
IncrementalDB* db;
|
||||||
Table* db_users_table;
|
Table* db_users_table;
|
||||||
pthread_mutex_t users_cache_mutex;
|
pthread_mutex_t users_cache_mutex;
|
||||||
List(User) users_cache_list; // index is id
|
List(User) users_cache_list; // index is id
|
||||||
HashMap(u64) users_name_id_map; //key is user name
|
HashMap(u64) users_name_id_map; // key is user name
|
||||||
} Server;
|
} Server;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user