Compare commits
No commits in common. "d53557dbb65930600fe80c7ae48c4f10b7dddd73" and "344b4375f9dafc4671d70832d42b56af4fb1f28b" have entirely different histories.
d53557dbb6
...
344b4375f9
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -7,7 +7,7 @@
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/bin/tcp-chat",
|
||||
"windows": { "program": "${workspaceFolder}/bin/tcp-chat.exe" },
|
||||
"args": [ "-l" ],
|
||||
"args": [ "-l", "127.0.0.1:9988" ],
|
||||
"preLaunchTask": "build_exec_dbg",
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/bin",
|
||||
|
||||
8
dependencies/bearssl.config
vendored
8
dependencies/bearssl.config
vendored
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
DEP_WORKING_DIR="$DEPENDENCIES_DIR"
|
||||
DEP_WORKING_DIR="dependencies/BearSSL"
|
||||
|
||||
projconfig_path="bearssl.project.config"
|
||||
projconfig_path="../bearssl.project.config"
|
||||
if [[ "$TASK" = *_dbg ]]; then
|
||||
dep_build_target="build_static_lib_dbg"
|
||||
else
|
||||
@ -10,10 +10,10 @@ fi
|
||||
|
||||
DEP_PRE_BUILD_COMMAND=""
|
||||
DEP_BUILD_COMMAND="cbuild -c $projconfig_path $dep_build_target"
|
||||
DEP_POST_BUILD_COMMAND=""
|
||||
DEP_POST_BUILD_COMMAND="mv -v cbuild.log ../bin/cbuild_bearssl.log"
|
||||
DEP_CLEAN_COMMAND="cbuild -c $projconfig_path clean"
|
||||
|
||||
DEP_DYNAMIC_OUT_FILES=""
|
||||
DEP_STATIC_OUT_FILES="bin/libbearssl.a"
|
||||
DEP_STATIC_OUT_FILES="../bin/libbearssl.a"
|
||||
DEP_OTHER_OUT_FILES=""
|
||||
PRESERVE_OUT_DIRECTORY_STRUCTURE=false
|
||||
|
||||
134
dependencies/bearssl.project.config
vendored
134
dependencies/bearssl.project.config
vendored
@ -1,20 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
CBUILD_VERSION=2.3.1
|
||||
CBUILD_VERSION=2.2.3
|
||||
|
||||
PROJECT="bearssl"
|
||||
CMP_C="gcc"
|
||||
CMP_CPP="g++"
|
||||
STD_C="c99"
|
||||
STD_C="c11"
|
||||
STD_CPP="c++11"
|
||||
WARN_C="-Wno-unknown-pragmas"
|
||||
WARN_CPP="$WARN_C"
|
||||
# WARN_CPP="-Wall -Wextra"
|
||||
|
||||
SRC_C="$(find BearSSL/src -name '*.c')"
|
||||
SRC_CPP="$(find BearSSL/src -name '*.cpp')"
|
||||
SRC_C="$(find src -name '*.c')"
|
||||
#SRC_CPP="$(find src -name '*.cpp')"
|
||||
|
||||
# Directory with dependency configs.
|
||||
# See cbuild/example_dependency_configs
|
||||
DEPENDENCY_CONFIGS_DIR='.'
|
||||
DEPENDENCY_CONFIGS_DIR='..'
|
||||
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
|
||||
ENABLED_DEPENDENCIES=''
|
||||
|
||||
@ -23,11 +23,11 @@ ENABLED_DEPENDENCIES=''
|
||||
# ├── static_libs/ - Symbolic links to static libraries used by linker. Cleans on each call of build task.
|
||||
# ├── static_libs/ - Symbolic links to dynamic libraries used by linker. Cleans on each call of build task.
|
||||
# └── profile/ - gcc *.gcda profiling info files
|
||||
OBJDIR="BearSSL/obj"
|
||||
OUTDIR="bin"
|
||||
OBJDIR="obj"
|
||||
OUTDIR="../bin"
|
||||
STATIC_LIB_FILE="lib$PROJECT.a"
|
||||
|
||||
INCLUDE="-IBearSSL/src -IBearSSL/inc"
|
||||
INCLUDE="-I./src -I./inc"
|
||||
|
||||
# OS-specific options
|
||||
case "$OS" in
|
||||
@ -35,32 +35,13 @@ case "$OS" in
|
||||
EXEC_FILE="$PROJECT.exe"
|
||||
SHARED_LIB_FILE="$PROJECT.dll"
|
||||
LINKER_LIBS=""
|
||||
INCLUDE="$INCLUDE "
|
||||
DEFINE=""
|
||||
;;
|
||||
LINUX)
|
||||
EXEC_FILE="$PROJECT"
|
||||
SHARED_LIB_FILE="$PROJECT.so"
|
||||
LINKER_LIBS=""
|
||||
INCLUDE="$INCLUDE -DBR_USE_GETENTROPY=0"
|
||||
;;
|
||||
*)
|
||||
error "operating system $OS has no configuration variants"
|
||||
;;
|
||||
esac
|
||||
|
||||
# OS-specific options
|
||||
case "$OS" in
|
||||
WINDOWS)
|
||||
EXEC_FILE="$PROJECT.exe"
|
||||
SHARED_LIB_FILE="$PROJECT.dll"
|
||||
INCLUDE="$INCLUDE "
|
||||
LINKER_LIBS=""
|
||||
;;
|
||||
LINUX)
|
||||
EXEC_FILE="$PROJECT"
|
||||
SHARED_LIB_FILE="$PROJECT.so"
|
||||
INCLUDE="$INCLUDE "
|
||||
LINKER_LIBS=""
|
||||
DEFINE="-DBR_USE_GETENTROPY=0"
|
||||
;;
|
||||
*)
|
||||
error "operating system $OS has no configuration variants"
|
||||
@ -77,64 +58,64 @@ case "$TASK" in
|
||||
# -fprofile-use enables compiler to use profiling info files to optimize executable
|
||||
# -fprofile-prefix-path sets path where profiling info about objects are be saved
|
||||
# -fdata-sections -ffunction-sections -Wl,--gc-sections removes unused code
|
||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects -fdata-sections -ffunction-sections -Wl,--gc-sections"
|
||||
C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin -fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects -fdata-sections -ffunction-sections -Wl,--gc-sections"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||
PRE_TASK_SCRIPT=""
|
||||
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=
|
||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# creates executable with debug info and no optimizations
|
||||
build_exec_dbg)
|
||||
C_ARGS="-O0 -g3"
|
||||
C_ARGS="$DEFINE -O0 -g3"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||
PRE_TASK_SCRIPT=""
|
||||
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=
|
||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# creates shared library
|
||||
build_shared_lib)
|
||||
C_ARGS="-O2 -fpic -flto -shared"
|
||||
C_ARGS="$DEFINE -O2 -fpic -flto -shared"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
|
||||
PRE_TASK_SCRIPT=""
|
||||
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=
|
||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# creates shared library with debug symbols and no optimizations
|
||||
build_shared_lib_dbg)
|
||||
C_ARGS="-O0 -g3 -fpic -shared"
|
||||
C_ARGS="$DEFINE -O0 -g3 -fpic -shared"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
|
||||
PRE_TASK_SCRIPT=""
|
||||
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=
|
||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# creates static library
|
||||
build_static_lib)
|
||||
C_ARGS="-O2 -fpic -fdata-sections -ffunction-sections"
|
||||
C_ARGS="$DEFINE -O2 -fpic -fdata-sections -ffunction-sections"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
PRE_TASK_SCRIPT=""
|
||||
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=
|
||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# creates static library with debug symbols and no optimizations
|
||||
build_static_lib_dbg)
|
||||
C_ARGS="-O0 -g3"
|
||||
C_ARGS="$DEFINE -O0 -g3"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
PRE_TASK_SCRIPT=""
|
||||
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=
|
||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# executes $EXEC_FILE
|
||||
exec)
|
||||
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
|
||||
TASK_SCRIPT=cbuild/default_tasks/exec.sh
|
||||
;;
|
||||
# executes $EXEC_FILE with valgrind memory checker
|
||||
valgrind)
|
||||
VALGRIND_ARGS="-s --read-var-info=yes --track-origins=yes --fullpath-after=$(pwd)/ --leak-check=full --show-leak-kinds=all"
|
||||
TASK_SCRIPT="@cbuild/default_tasks/valgrind.sh"
|
||||
TASK_SCRIPT=cbuild/default_tasks/valgrind.sh
|
||||
;;
|
||||
# generates profiling info
|
||||
profile)
|
||||
@ -145,28 +126,25 @@ case "$TASK" in
|
||||
# -pg adds code to executable, that generates file containing function call info (gmon.out)
|
||||
# -fprofile-generate generates executable with profiling code
|
||||
# -fprofile-prefix-path sets path where profiling info about objects will be saved
|
||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
|
||||
C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||
TASK_SCRIPT="@cbuild/default_tasks/profile.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||
TASK_SCRIPT=cbuild/default_tasks/profile.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# compiles program with -pg and runs it with gprof
|
||||
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||
# requires graphviz (https://www.graphviz.org/download/source/)
|
||||
gprof)
|
||||
OUTDIR="$OUTDIR/gprof"
|
||||
# arguments that emit some call counter code and disable optimizations to see function names
|
||||
# https://github.com/msys2/MINGW-packages/issues/8503#issuecomment-1365475205
|
||||
C_ARGS="-O0 -g -pg -no-pie -fno-omit-frame-pointer
|
||||
-fno-inline-functions -fno-inline-functions-called-once
|
||||
-fno-optimize-sibling-calls -fopenmp"
|
||||
# -pg adds code to executable, that generates file containing function call info (gmon.out)
|
||||
C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin -pg"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||
TASK_SCRIPT="@cbuild/default_tasks/gprof.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||
TASK_SCRIPT=cbuild/default_tasks/gprof.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# compiles program and runs it with callgrind (part of valgrind)
|
||||
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||
@ -175,32 +153,32 @@ case "$TASK" in
|
||||
callgrind)
|
||||
OUTDIR="$OUTDIR/callgrind"
|
||||
# -pg adds code to executable, that generates file containing function call info (gmon.out)
|
||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin"
|
||||
C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||
TASK_SCRIPT="@cbuild/default_tasks/callgrind.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||
TASK_SCRIPT=cbuild/default_tasks/callgrind.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# compiles executable with sanitizers and executes it to find errors and warnings
|
||||
sanitize)
|
||||
OUTDIR="$OUTDIR/sanitize"
|
||||
C_ARGS="-O0 -g3 -fsanitize=undefined,address"
|
||||
C_ARGS="$DEFINE -O0 -g3 -fsanitize=undefined,address"
|
||||
CPP_ARGS="$C_ARGS"
|
||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
|
||||
POST_TASK_SCRIPT=""
|
||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||
TASK_SCRIPT=cbuild/default_tasks/exec.sh
|
||||
POST_TASK_SCRIPT=
|
||||
;;
|
||||
# rebuilds specified dependencies
|
||||
# EXAMPLE: `cbuild rebuild_dependencies=libexample1,fonts`
|
||||
# 'all' can be specified to rebuild all dependencies
|
||||
rebuild_dependencies)
|
||||
TASK_SCRIPT="@cbuild/default_tasks/rebuild_dependencies.sh"
|
||||
TASK_SCRIPT=cbuild/default_tasks/rebuild_dependencies.sh
|
||||
;;
|
||||
# deletes generated files
|
||||
clean)
|
||||
TASK_SCRIPT="@cbuild/default_tasks/clean.sh"
|
||||
TASK_SCRIPT=cbuild/default_tasks/clean.sh
|
||||
;;
|
||||
# nothing to do
|
||||
"" | no_task)
|
||||
|
||||
11
dependencies/bearssl.project.config.user.default
vendored
11
dependencies/bearssl.project.config.user.default
vendored
@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Project user config is ignored by git.
|
||||
# Here you can add variables that users might want to change
|
||||
# on their local machine, without commiting to the repository.
|
||||
|
||||
# Directory where you install dependencies.
|
||||
# Do not confuse with DEPENDENCY_CONFIGS_DIR
|
||||
# Example:
|
||||
# libexample source code is at `../libexample`, and dependency config
|
||||
# that specifies how to build this lib is at `dependencies/libexample.config`
|
||||
DEPENDENCIES_DIR="."
|
||||
2
dependencies/tlibc
vendored
2
dependencies/tlibc
vendored
@ -1 +1 @@
|
||||
Subproject commit 1775b27980d550dd9a50a81b11d797c51253ab22
|
||||
Subproject commit bb3b096262106fcc503c03b1555ca196d5b780e9
|
||||
7
dependencies/tlibc.config
vendored
7
dependencies/tlibc.config
vendored
@ -1,14 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DEP_WORKING_DIR="$DEPENDENCIES_DIR/tlibc"
|
||||
DEP_WORKING_DIR="dependencies/tlibc"
|
||||
DEP_PRE_BUILD_COMMAND=""
|
||||
DEP_POST_BUILD_COMMAND=""
|
||||
if [[ "$TASK" = *_dbg ]]; then
|
||||
dep_build_target="build_static_lib_dbg"
|
||||
else
|
||||
dep_build_target="build_static_lib"
|
||||
fi
|
||||
DEP_PRE_BUILD_COMMAND=""
|
||||
DEP_BUILD_COMMAND="cbuild $dep_build_target"
|
||||
DEP_POST_BUILD_COMMAND=""
|
||||
DEP_CLEAN_COMMAND="cbuild clean"
|
||||
DEP_DYNAMIC_OUT_FILES=""
|
||||
DEP_STATIC_OUT_FILES="bin/tlibc.a"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
CBUILD_VERSION=2.3.1
|
||||
CBUILD_VERSION=2.3.0
|
||||
|
||||
PROJECT="tcp-chat"
|
||||
CMP_C="gcc"
|
||||
@ -35,7 +35,7 @@ OBJDIR="obj"
|
||||
OUTDIR="bin"
|
||||
STATIC_LIB_FILE="$PROJECT.a"
|
||||
|
||||
INCLUDE="-Isrc -I$DEPENDENCIES_DIR/BearSSL/inc -I$DEPENDENCIES_DIR/tlibc/include"
|
||||
INCLUDE="-Isrc -Idependencies/BearSSL/inc -Idependencies/tlibc/include"
|
||||
|
||||
# OS-specific options
|
||||
case "$OS" in
|
||||
|
||||
@ -8,4 +8,4 @@
|
||||
# Example:
|
||||
# libexample source code is at `../libexample`, and dependency config
|
||||
# that specifies how to build this lib is at `dependencies/libexample.config`
|
||||
DEPENDENCIES_DIR="dependencies"
|
||||
DEPENDENCIES_DIR=".."
|
||||
|
||||
@ -28,7 +28,7 @@ Result(void) config_findValue(str config_str, str key, str* value, bool throwNot
|
||||
|
||||
if(throwNotFoundError){
|
||||
char* key_cstr = str_copy(key).data;
|
||||
char* err_msg = sprintf_malloc("can't find key '%s'", key_cstr);
|
||||
char* err_msg = sprintf_malloc(key.size + 64, "can't find key '%s'", key_cstr);
|
||||
free(key_cstr);
|
||||
return RESULT_ERROR(err_msg, true);
|
||||
}
|
||||
|
||||
152
src/db/idb.c
152
src/db/idb.c
@ -2,14 +2,12 @@
|
||||
#include "magic.h"
|
||||
#include "tlibc/filesystem.h"
|
||||
#include "tlibc/collections/HashMap.h"
|
||||
#include "cryptography/AES.h"
|
||||
#include <pthread.h>
|
||||
|
||||
typedef struct TableFileHeader {
|
||||
Magic32 magic;
|
||||
u16 version;
|
||||
bool _dirty_bit;
|
||||
bool encrypted;
|
||||
u32 row_size;
|
||||
} ATTRIBUTE_ALIGNED(256) TableFileHeader;
|
||||
|
||||
@ -23,14 +21,10 @@ typedef struct Table {
|
||||
FILE* changes_file;
|
||||
pthread_mutex_t mutex;
|
||||
u64 row_count;
|
||||
AESBlockEncryptor enc;
|
||||
AESBlockDecryptor dec;
|
||||
Array(u8) enc_buf;
|
||||
} Table;
|
||||
|
||||
typedef struct IncrementalDB {
|
||||
str db_dir;
|
||||
Array(u8) aes_key;
|
||||
HashMap(Table**) tables_map;
|
||||
pthread_mutex_t mutex;
|
||||
} IncrementalDB;
|
||||
@ -45,17 +39,16 @@ void Table_close(Table* t){
|
||||
free(t->table_file_path.data);
|
||||
free(t->changes_file_path.data);
|
||||
pthread_mutex_destroy(&t->mutex);
|
||||
free(t->enc_buf.data);
|
||||
free(t);
|
||||
}
|
||||
|
||||
// element destructor for HashMap(Table*)
|
||||
static void TablePtr_free(void* t_ptr_ptr){
|
||||
void TablePtr_destroy(void* t_ptr_ptr){
|
||||
Table_close(*(Table**)t_ptr_ptr);
|
||||
}
|
||||
|
||||
/// @param name must be null-terminated
|
||||
static Result(void) validateTableName(str name){
|
||||
Result(void) validateTableName(str name){
|
||||
char forbidden_characters[] = { '/', '\\', ':', ';', '?', '"', '\'', '\n', '\r', '\t'};
|
||||
for(u32 i = 0; i < ARRAY_LEN(forbidden_characters); i++) {
|
||||
char c = forbidden_characters[i];
|
||||
@ -69,7 +62,7 @@ static Result(void) validateTableName(str name){
|
||||
return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) Table_readHeader(Table* t){
|
||||
Result(void) Table_readHeader(Table* t){
|
||||
Deferral(4);
|
||||
// seek for start of the file
|
||||
try_void(file_seek(t->table_file, 0, SeekOrigin_Start));
|
||||
@ -78,7 +71,7 @@ static Result(void) Table_readHeader(Table* t){
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) Table_writeHeader(Table* t){
|
||||
Result(void) Table_writeHeader(Table* t){
|
||||
Deferral(4);
|
||||
// seek for start of the file
|
||||
try_void(file_seek(t->table_file, 0, SeekOrigin_Start));
|
||||
@ -87,42 +80,35 @@ static Result(void) Table_writeHeader(Table* t){
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) Table_setDirtyBit(Table* t, bool val){
|
||||
Result(void) Table_setDirtyBit(Table* t, bool val){
|
||||
Deferral(4);
|
||||
t->header._dirty_bit = val;
|
||||
try_void(Table_writeHeader(t));
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(bool) Table_getDirtyBit(Table* t){
|
||||
Result(bool) Table_getDirtyBit(Table* t){
|
||||
Deferral(4);
|
||||
try_void(Table_readHeader(t));
|
||||
Return RESULT_VALUE(i, t->header._dirty_bit);
|
||||
}
|
||||
|
||||
static u32 Table_calcEncryptedRowSize(Table* t){
|
||||
return AESBlockEncryptor_calcDstSize(t->header.row_size);
|
||||
}
|
||||
|
||||
static Result(void) Table_calculateRowCount(Table* t){
|
||||
Result(void) Table_calculateRowCount(Table* t){
|
||||
Deferral(4);
|
||||
try(i64 file_size, i, file_getSize(t->table_file));
|
||||
i64 data_size = file_size - sizeof(t->header);
|
||||
i64 row_size_in_file = t->header.encrypted
|
||||
? Table_calcEncryptedRowSize(t)
|
||||
: t->header.row_size;
|
||||
if(data_size % row_size_in_file != 0){
|
||||
if(data_size % t->header.row_size != 0){
|
||||
//TODO: fix table instead of trowing error
|
||||
Return RESULT_ERROR_FMT(
|
||||
"Table '%s' has invalid size. Last row is incomplete.",
|
||||
"Table '%s' has invalid size. Last row is incomplete",
|
||||
t->name.data);
|
||||
}
|
||||
|
||||
t->row_count = data_size / row_size_in_file;
|
||||
t->row_count = data_size / t->header.row_size;
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) Table_validateHeader(Table* t){
|
||||
Result(void) Table_validateHeader(Table* t){
|
||||
Deferral(4);
|
||||
if(t->header.magic.n != TABLE_FILE_MAGIC.n
|
||||
|| t->header.row_size == 0)
|
||||
@ -145,24 +131,7 @@ static Result(void) Table_validateHeader(Table* t){
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) Table_validateEncryption(Table* t){
|
||||
bool db_encrypted = t->db->aes_key.size != 0;
|
||||
if(t->header.encrypted && !db_encrypted){
|
||||
return RESULT_ERROR_FMT("Table '%s' is encrypted, but db->aes_key is not set."
|
||||
"Database '%s' is encrypted and must have not-null encryption key.",
|
||||
t->name.data, t->db->db_dir.data);
|
||||
}
|
||||
|
||||
if(!t->header.encrypted && db_encrypted){
|
||||
return RESULT_ERROR_FMT("table '%s' is not encrypted, but db->aes_key is set."
|
||||
"Do not set encryption key for not encrypted database '%s'.",
|
||||
t->name.data, t->db->db_dir.data);
|
||||
}
|
||||
|
||||
return RESULT_VOID;
|
||||
}
|
||||
|
||||
static Result(void) Table_validateRowSize(Table* t, u32 row_size){
|
||||
Result(void) Table_validateRowSize(Table* t, u32 row_size){
|
||||
if(row_size != t->header.row_size){
|
||||
ResultVar(void) error_result = RESULT_ERROR_FMT(
|
||||
"Requested row size (%u) doesn't match saved row size (%u)",
|
||||
@ -173,24 +142,18 @@ static Result(void) Table_validateRowSize(Table* t, u32 row_size){
|
||||
return RESULT_VOID;
|
||||
}
|
||||
|
||||
Result(IncrementalDB*) idb_open(str db_dir, NULLABLE(Array(u8) aes_key)){
|
||||
Result(IncrementalDB*) idb_open(str db_dir){
|
||||
Deferral(16);
|
||||
try_assert(aes_key.size == 0 || aes_key.size == 16 || aes_key.size == 24 || aes_key.size == 32);
|
||||
|
||||
IncrementalDB* db = (IncrementalDB*)malloc(sizeof(IncrementalDB));
|
||||
// value of *db must be set to zero or behavior of idb_close will be undefined
|
||||
memset(db, 0, sizeof(IncrementalDB));
|
||||
// if object construction fails, destroy incomplete object
|
||||
bool success = false;
|
||||
Defer(if(!success) idb_close(db));
|
||||
|
||||
if(aes_key.size != 0){
|
||||
db->aes_key = Array_copy(aes_key);
|
||||
}
|
||||
|
||||
// value of *db must be set to zero or behavior of idb_close will be undefined
|
||||
memset(db, 0, sizeof(IncrementalDB));
|
||||
db->db_dir = str_copy(db_dir);
|
||||
try_void(dir_create(db->db_dir.data));
|
||||
HashMap_construct(&db->tables_map, Table*, TablePtr_free);
|
||||
HashMap_construct(&db->tables_map, Table*, TablePtr_destroy);
|
||||
try_stderrcode(pthread_mutex_init(&db->mutex, NULL));
|
||||
|
||||
success = true;
|
||||
@ -199,37 +162,36 @@ Result(IncrementalDB*) idb_open(str db_dir, NULLABLE(Array(u8) aes_key)){
|
||||
|
||||
void idb_close(IncrementalDB* db){
|
||||
free(db->db_dir.data);
|
||||
free(db->aes_key.data);
|
||||
HashMap_destroy(&db->tables_map);
|
||||
pthread_mutex_destroy(&db->mutex);
|
||||
free(db);
|
||||
}
|
||||
|
||||
Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str table_name, u32 row_size){
|
||||
Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str _table_name, u32 row_size){
|
||||
Deferral(16);
|
||||
// db lock
|
||||
try_stderrcode(pthread_mutex_lock(&db->mutex));
|
||||
Defer(pthread_mutex_unlock(&db->mutex));
|
||||
|
||||
Table** tpp = HashMap_tryGetPtr(&db->tables_map, table_name);
|
||||
Table** tpp = HashMap_tryGetPtr(&db->tables_map, _table_name);
|
||||
if(tpp != NULL){
|
||||
Table* existing_table = *tpp;
|
||||
try_void(Table_validateRowSize(existing_table, row_size));
|
||||
Return RESULT_VALUE(p, existing_table);
|
||||
}
|
||||
|
||||
try_void(validateTableName(table_name));
|
||||
try_void(validateTableName(_table_name));
|
||||
|
||||
Table* t = (Table*)malloc(sizeof(Table));
|
||||
// value of *t must be set to zero or behavior of Table_close will be undefined
|
||||
memset(t, 0, sizeof(Table));
|
||||
// if object construction fails, destroy incomplete object
|
||||
bool success = false;
|
||||
Defer(if(!success) Table_close(t));
|
||||
|
||||
// value of *t must be set to zero or behavior of Table_close will be undefined
|
||||
memset(t, 0, sizeof(Table));
|
||||
t->db = db;
|
||||
try_stderrcode(pthread_mutex_init(&t->mutex, NULL));
|
||||
t->name = str_copy(table_name);
|
||||
t->name = str_copy(_table_name);
|
||||
t->table_file_path = str_from_cstr(
|
||||
strcat_malloc(db->db_dir.data, path_seps, t->name.data, ".idb-table"));
|
||||
t->changes_file_path = str_from_cstr(
|
||||
@ -246,7 +208,6 @@ Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str table_name, u32 row_s
|
||||
// read table file
|
||||
try_void(Table_readHeader(t));
|
||||
try_void(Table_validateHeader(t));
|
||||
try_void(Table_validateEncryption(t));
|
||||
try_void(Table_validateRowSize(t, row_size));
|
||||
try_void(Table_calculateRowCount(t));
|
||||
}
|
||||
@ -255,18 +216,9 @@ Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str table_name, u32 row_s
|
||||
t->header.magic.n = TABLE_FILE_MAGIC.n;
|
||||
t->header.row_size = row_size;
|
||||
t->header.version = IDB_VERSION;
|
||||
t->header.encrypted = db->aes_key.size != 0;
|
||||
t->header._dirty_bit = false;
|
||||
try_void(Table_writeHeader(t));
|
||||
}
|
||||
|
||||
if(t->header.encrypted){
|
||||
AESBlockEncryptor_construct(&t->enc, db->aes_key, AESBlockEncryptor_DEFAULT_CLASS);
|
||||
AESBlockDecryptor_construct(&t->dec, db->aes_key, AESBlockDecryptor_DEFAULT_CLASS);
|
||||
u32 row_size_in_file = Table_calcEncryptedRowSize(t);
|
||||
t->enc_buf = Array_alloc_size(row_size_in_file);
|
||||
}
|
||||
|
||||
if(!HashMap_tryPush(&db->tables_map, t->name, &t)){
|
||||
ResultVar(void) error_result = RESULT_ERROR_FMT(
|
||||
"Table '%s' is already open",
|
||||
@ -291,28 +243,12 @@ Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count){
|
||||
count, id, t->name.data, t->row_count);
|
||||
}
|
||||
|
||||
u32 row_size = t->header.row_size;
|
||||
u32 row_size_in_file = t->header.encrypted ? t->enc_buf.size : row_size;
|
||||
i64 file_pos = sizeof(t->header) + id * row_size_in_file;
|
||||
i64 file_pos = sizeof(t->header) + id * t->header.row_size;
|
||||
|
||||
// seek for the row position in file
|
||||
try_void(file_seek(t->table_file, file_pos, SeekOrigin_Start));
|
||||
|
||||
// read rows from file
|
||||
for(u64 i = 0; i < count; i++){
|
||||
void* row_ptr = (u8*)dst + row_size * i;
|
||||
void* read_dst = t->header.encrypted ? t->enc_buf.data : row_ptr;
|
||||
try_void(file_readStructsExactly(t->table_file, read_dst, row_size_in_file, 1));
|
||||
if(t->header.encrypted) {
|
||||
try_void(
|
||||
AESBlockDecryptor_decrypt(
|
||||
&t->dec,
|
||||
t->enc_buf,
|
||||
Array_construct_size(row_ptr, row_size)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
try_void(file_readStructsExactly(t->table_file, dst, t->header.row_size, count));
|
||||
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
@ -333,31 +269,15 @@ Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count){
|
||||
try_void(Table_setDirtyBit(t, true));
|
||||
Defer(IGNORE_RESULT Table_setDirtyBit(t, false));
|
||||
|
||||
u32 row_size = t->header.row_size;
|
||||
u32 row_size_in_file = t->header.encrypted ? t->enc_buf.size : row_size;
|
||||
i64 file_pos = sizeof(t->header) + id * row_size_in_file;
|
||||
i64 file_pos = sizeof(t->header) + id * t->header.row_size;
|
||||
|
||||
// TODO: set dirty bit in backup file too
|
||||
// TODO: save old values to the backup file
|
||||
|
||||
// seek for the row position in file
|
||||
try_void(file_seek(t->table_file, file_pos, SeekOrigin_Start));
|
||||
|
||||
// replace rows in file
|
||||
for(u64 i = 0; i < count; i++){
|
||||
void* row_ptr = (u8*)src + row_size * i;
|
||||
if(t->header.encrypted){
|
||||
try_void(
|
||||
AESBlockEncryptor_encrypt(
|
||||
&t->enc,
|
||||
Array_construct_size(row_ptr, row_size),
|
||||
t->enc_buf
|
||||
)
|
||||
);
|
||||
row_ptr = t->enc_buf.data;
|
||||
}
|
||||
try_void(file_writeStructs(t->table_file, row_ptr, row_size_in_file, 1));
|
||||
}
|
||||
try_void(file_writeStructs(t->table_file, src, t->header.row_size, count));
|
||||
|
||||
Return RESULT_VOID;
|
||||
}
|
||||
@ -371,30 +291,14 @@ Result(u64) idb_pushRows(Table* t, const void* src, u64 count){
|
||||
try_void(Table_setDirtyBit(t, true));
|
||||
Defer(IGNORE_RESULT Table_setDirtyBit(t, false));
|
||||
|
||||
u32 row_size = t->header.row_size;
|
||||
u32 row_size_in_file = t->header.encrypted ? t->enc_buf.size : row_size;
|
||||
const u64 new_row_index = t->row_count;
|
||||
|
||||
// seek for end of the file
|
||||
try_void(file_seek(t->table_file, 0, SeekOrigin_End));
|
||||
|
||||
// write new rows to the file
|
||||
for(u64 i = 0; i < count; i++){
|
||||
void* row_ptr = (u8*)src + row_size * i;
|
||||
if(t->header.encrypted){
|
||||
try_void(
|
||||
AESBlockEncryptor_encrypt(
|
||||
&t->enc,
|
||||
Array_construct_size(row_ptr, row_size),
|
||||
t->enc_buf
|
||||
)
|
||||
);
|
||||
row_ptr = t->enc_buf.data;
|
||||
}
|
||||
try_void(file_writeStructs(t->table_file, row_ptr, row_size_in_file, 1));
|
||||
t->row_count++;
|
||||
}
|
||||
try_void(file_writeStructs(t->table_file, src, t->header.row_size, count));
|
||||
|
||||
t->row_count += count;
|
||||
Return RESULT_VALUE(u, new_row_index);
|
||||
}
|
||||
|
||||
|
||||
@ -9,10 +9,11 @@ typedef struct IncrementalDB IncrementalDB;
|
||||
typedef struct Table Table;
|
||||
|
||||
|
||||
Result(IncrementalDB*) idb_open(str db_dir, NULLABLE(Array(u8) aes_key));
|
||||
Result(IncrementalDB*) idb_open(str db_dir);
|
||||
void idb_close(IncrementalDB* db);
|
||||
|
||||
Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str table_name, u32 row_size);
|
||||
|
||||
Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str _table_name, u32 row_size);
|
||||
|
||||
Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count);
|
||||
#define idb_getRow(T, ID, DST) idb_getRows(T, ID, DST, 1)
|
||||
|
||||
181
src/main.c
181
src/main.c
@ -1,8 +1,6 @@
|
||||
#include "network/network.h"
|
||||
#include "client/client.h"
|
||||
#include "server/server.h"
|
||||
#include "tlibc/tlibc.h"
|
||||
#include "tlibc/base64.h"
|
||||
|
||||
#define _DEFAULT_CONFIG_PATH_CLIENT "tcp-chat-client.config"
|
||||
#define _DEFAULT_CONFIG_PATH_SERVER "tcp-chat-server.config"
|
||||
@ -12,8 +10,6 @@ typedef enum ProgramMode {
|
||||
ServerMode,
|
||||
RsaGenStdin,
|
||||
RsaGenRandom,
|
||||
RandomBytes,
|
||||
RandomBytesBase64,
|
||||
} ProgramMode;
|
||||
|
||||
#define arg_is(LITERAL) str_equals(arg_str, STR(LITERAL))
|
||||
@ -21,19 +17,15 @@ typedef enum ProgramMode {
|
||||
int main(const int argc, cstr const* argv){
|
||||
Deferral(32);
|
||||
|
||||
try_fatal_void(tlibc_init());
|
||||
Defer(tlibc_deinit());
|
||||
try_fatal_void(network_init());
|
||||
Defer(network_deinit());
|
||||
|
||||
if(br_prng_seeder_system(NULL) == NULL){
|
||||
printfe("Can't get system random seeder. Bearssl is compiled incorrectly.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ProgramMode mode = ClientMode;
|
||||
cstr server_endpoint_cstr = NULL;
|
||||
cstr config_path = NULL;
|
||||
u32 size_arg = 0;
|
||||
u32 key_size = 0;
|
||||
|
||||
for(int argi = 1; argi < argc; argi++){
|
||||
str arg_str = str_from_cstr(argv[argi]);
|
||||
@ -42,7 +34,7 @@ int main(const int argc, cstr const* argv){
|
||||
"USAGE:\n"
|
||||
"no arguments Interactive client mode.\n"
|
||||
"-h, --help Show this message.\n"
|
||||
"-l, --listen Start server.\n"
|
||||
"-l, --listen [addr:port] Start server.\n"
|
||||
"--config [path] Load config from specified path.\n"
|
||||
" Default path for config is '" _DEFAULT_CONFIG_PATH_CLIENT "' or '" _DEFAULT_CONFIG_PATH_SERVER "'\n"
|
||||
"--rsa-gen-stdin [size] Generate RSA private and public keys based on stdin data (64Kb max).\n"
|
||||
@ -50,10 +42,6 @@ int main(const int argc, cstr const* argv){
|
||||
" Usage: `cat somefile | tcp-chat --gen-rsa-stdin`\n"
|
||||
"--rsa-gen-random [size] Generate random RSA private and public keys.\n"
|
||||
" size: 2048 / 3072 (default) / 4096\n"
|
||||
"--random-bytes [size] Generate random bytes.\n"
|
||||
" size: any number (default=32)\n"
|
||||
"--random-bytes-base64 [size] Generate random bytes and print them in base64 encoding.\n"
|
||||
" size: any number (default=32)\n"
|
||||
);
|
||||
Return 0;
|
||||
}
|
||||
@ -62,7 +50,13 @@ int main(const int argc, cstr const* argv){
|
||||
printf("program mode is set already\n");
|
||||
Return 1;
|
||||
}
|
||||
|
||||
mode = ServerMode;
|
||||
if(++argi >= argc){
|
||||
printfe("ERROR: no endpoint specified\n");
|
||||
Return 1;
|
||||
}
|
||||
server_endpoint_cstr = argv[argi];
|
||||
}
|
||||
else if(arg_is("--config")){
|
||||
if(++argi >= argc){
|
||||
@ -79,9 +73,9 @@ int main(const int argc, cstr const* argv){
|
||||
|
||||
mode = RsaGenStdin;
|
||||
if(++argi >= argc){
|
||||
size_arg = RSA_DEFAULT_KEY_SIZE;
|
||||
key_size = RSA_DEFAULT_KEY_SIZE;
|
||||
}
|
||||
else if(sscanf(argv[argi], "%u", &size_arg) != 1){
|
||||
else if(sscanf(argv[argi], "%u", &key_size) != 1){
|
||||
printfe("ERROR: no key size specified\n");
|
||||
}
|
||||
}
|
||||
@ -94,40 +88,12 @@ int main(const int argc, cstr const* argv){
|
||||
|
||||
mode = RsaGenRandom;
|
||||
if(++argi >= argc){
|
||||
size_arg = RSA_DEFAULT_KEY_SIZE;
|
||||
key_size = RSA_DEFAULT_KEY_SIZE;
|
||||
}
|
||||
else if(sscanf(argv[argi], "%u", &size_arg) != 1){
|
||||
else if(sscanf(argv[argi], "%u", &key_size) != 1){
|
||||
printfe("ERROR: no key size specified\n");
|
||||
}
|
||||
}
|
||||
else if(arg_is("--random-bytes")){
|
||||
if(mode != ClientMode){
|
||||
printf("program mode is set already\n");
|
||||
Return 1;
|
||||
}
|
||||
|
||||
mode = RandomBytes;
|
||||
if(++argi >= argc){
|
||||
size_arg = 32;
|
||||
}
|
||||
else if(sscanf(argv[argi], "%u", &size_arg) != 1){
|
||||
printfe("ERROR: no size specified\n");
|
||||
}
|
||||
}
|
||||
else if(arg_is("--random-bytes-base64")){
|
||||
if(mode != ClientMode){
|
||||
printf("program mode is set already\n");
|
||||
Return 1;
|
||||
}
|
||||
|
||||
mode = RandomBytesBase64;
|
||||
if(++argi >= argc){
|
||||
size_arg = 32;
|
||||
}
|
||||
else if(sscanf(argv[argi], "%u", &size_arg) != 1){
|
||||
printfe("ERROR: no size specified\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
printfe("ERROR: unknown argument '%s'\n"
|
||||
"Use '-h' to see list of avaliable arguments\n",
|
||||
@ -136,6 +102,9 @@ int main(const int argc, cstr const* argv){
|
||||
}
|
||||
}
|
||||
|
||||
try_fatal_void(network_init());
|
||||
Defer(network_deinit());
|
||||
|
||||
switch(mode){
|
||||
case ClientMode: {
|
||||
if(!config_path)
|
||||
@ -153,104 +122,58 @@ int main(const int argc, cstr const* argv){
|
||||
|
||||
try_fatal(Server* server, p, Server_createFromConfig(config_path));
|
||||
Defer(Server_free(server));
|
||||
try_fatal_void(Server_run(server));
|
||||
try_fatal_void(Server_run(server, server_endpoint_cstr));
|
||||
break;
|
||||
}
|
||||
|
||||
case RsaGenStdin: {
|
||||
printfe("reading stdin...\n");
|
||||
Array(u8) input_buf = Array_alloc_size(64*1024);
|
||||
Defer(free(input_buf.data));
|
||||
br_hmac_drbg_context rng = { .vtable = &br_hmac_drbg_vtable };
|
||||
br_hmac_drbg_init(&rng, &br_sha256_vtable, NULL, 0);
|
||||
i64 read_n = 0;
|
||||
do {
|
||||
read_n = fread(input_buf.data, 1, input_buf.size, stdin);
|
||||
if(read_n < 0){
|
||||
size_t input_max_size = 64*1024;
|
||||
char* input_buf = malloc(input_max_size);
|
||||
Defer(free(input_buf));
|
||||
size_t read_n = fread(input_buf, 1, input_max_size, stdin);
|
||||
if(read_n == 0){
|
||||
printfe("ERROR: no input\n");
|
||||
Return 1;
|
||||
}
|
||||
// put bytes to rng as seed
|
||||
br_hmac_drbg_update(&rng, input_buf.data, read_n);
|
||||
} while(read_n == input_buf.size);
|
||||
printfe("generating RSA key pair based on stdin...\n");
|
||||
br_rsa_private_key sk;
|
||||
br_rsa_public_key pk;
|
||||
try_fatal_void(RSA_generateKeyPair(size_arg, &sk, &pk, &rng.vtable));
|
||||
Defer(
|
||||
RSA_destroyPrivateKey(&sk);
|
||||
RSA_destroyPublicKey(&pk);
|
||||
);
|
||||
str input_str = str_construct(input_buf, read_n, false);
|
||||
printfe("generating RSA key pair based on stdin...\n");
|
||||
br_rsa_private_key sk;
|
||||
br_rsa_public_key pk;
|
||||
try_fatal_void(RSA_generateKeyPairFromPassword(key_size, &sk, &pk, input_str));
|
||||
Defer(
|
||||
RSA_destroyPrivateKey(&sk);
|
||||
RSA_destroyPublicKey(&pk);
|
||||
);
|
||||
|
||||
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
||||
printf("rsa_private_key = %s\n", sk_str.data);
|
||||
free(sk_str.data);
|
||||
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
||||
printf("rsa_private_key = %s\n", sk_str.data);
|
||||
free(sk_str.data);
|
||||
|
||||
str pk_str = RSA_serializePublicKey_base64(&pk);
|
||||
printf("\nrsa_public_key = %s\n", pk_str.data);
|
||||
free(pk_str.data);
|
||||
str pk_str = RSA_serializePublicKey_base64(&pk);
|
||||
printf("\nrsa_public_key = %s\n", pk_str.data);
|
||||
free(pk_str.data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RsaGenRandom: {
|
||||
printfe("generating random RSA key pair...\n");
|
||||
br_rsa_private_key sk;
|
||||
br_rsa_public_key pk;
|
||||
try_fatal_void(RSA_generateKeyPairFromSystemRandom(size_arg, &sk, &pk));
|
||||
Defer(
|
||||
RSA_destroyPrivateKey(&sk);
|
||||
RSA_destroyPublicKey(&pk);
|
||||
);
|
||||
printfe("generating random RSA key pair...\n");
|
||||
br_rsa_private_key sk;
|
||||
br_rsa_public_key pk;
|
||||
try_fatal_void(RSA_generateKeyPairFromSystemRandom(key_size, &sk, &pk));
|
||||
Defer(
|
||||
RSA_destroyPrivateKey(&sk);
|
||||
RSA_destroyPublicKey(&pk);
|
||||
);
|
||||
|
||||
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
||||
printf("rsa_private_key = %s\n", sk_str.data);
|
||||
free(sk_str.data);
|
||||
str sk_str = RSA_serializePrivateKey_base64(&sk);
|
||||
printf("rsa_private_key = %s\n", sk_str.data);
|
||||
free(sk_str.data);
|
||||
|
||||
str pk_str = RSA_serializePublicKey_base64(&pk);
|
||||
printf("\nrsa_public_key = %s\n", pk_str.data);
|
||||
free(pk_str.data);
|
||||
break;
|
||||
}
|
||||
|
||||
case RandomBytes: {
|
||||
printfe("generating random bytes...\n");
|
||||
br_hmac_drbg_context rng = { .vtable = &br_hmac_drbg_vtable };
|
||||
rng_init_sha256_seedFromSystem(&rng.vtable);
|
||||
Array(u8) random_buf = Array_alloc_size(1024);
|
||||
u32 full_buffers_n = size_arg / random_buf.size;
|
||||
u32 remaining_n = size_arg % random_buf.size;
|
||||
while(full_buffers_n > 0){
|
||||
full_buffers_n--;
|
||||
br_hmac_drbg_generate(&rng, random_buf.data, random_buf.size);
|
||||
fwrite(random_buf.data, 1, random_buf.size, stdout);
|
||||
str pk_str = RSA_serializePublicKey_base64(&pk);
|
||||
printf("\nrsa_public_key = %s\n", pk_str.data);
|
||||
free(pk_str.data);
|
||||
}
|
||||
|
||||
br_hmac_drbg_generate(&rng, random_buf.data, remaining_n);
|
||||
fwrite(random_buf.data, 1, remaining_n, stdout);
|
||||
break;
|
||||
}
|
||||
|
||||
case RandomBytesBase64: {
|
||||
printfe("generating random bytes...\n");
|
||||
br_hmac_drbg_context rng = { .vtable = &br_hmac_drbg_vtable };
|
||||
rng_init_sha256_seedFromSystem(&rng.vtable);
|
||||
Array(u8) random_buf = Array_alloc_size(1024);
|
||||
Array(u8) base64_buf = Array_alloc_size(base64_encodedSize(random_buf.size));
|
||||
u32 full_buffers_n = size_arg / random_buf.size;
|
||||
u32 remaining_n = size_arg % random_buf.size;
|
||||
u32 enc_size = 0;
|
||||
while(full_buffers_n > 0){
|
||||
full_buffers_n--;
|
||||
br_hmac_drbg_generate(&rng, random_buf.data, random_buf.size);
|
||||
enc_size = base64_encode(random_buf.data, random_buf.size, base64_buf.data);
|
||||
fwrite(base64_buf.data, 1, enc_size, stdout);
|
||||
}
|
||||
|
||||
br_hmac_drbg_generate(&rng, random_buf.data, remaining_n);
|
||||
enc_size = base64_encode(random_buf.data, remaining_n, base64_buf.data);
|
||||
fwrite(base64_buf.data, 1, enc_size, stdout);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printfe("ERROR: invalid program mode %i\n", mode);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "tlibc/errors.h"
|
||||
#include "endpoint.h"
|
||||
#include "network.h"
|
||||
|
||||
#if !defined(KN_USE_WINSOCK)
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
@ -31,10 +30,10 @@
|
||||
|
||||
#if KN_USE_WINSOCK
|
||||
#define RESULT_ERROR_SOCKET()\
|
||||
RESULT_ERROR_CODE_FMT(WINSOCK2, WSAGetLastError(), "Winsock error %i (look in <winerror.h>)", WSAGetLastError());
|
||||
RESULT_ERROR(sprintf_malloc(64, "Winsock error %i (look in <winerror.h>)", WSAGetLastError()), true);
|
||||
#else
|
||||
#define RESULT_ERROR_SOCKET()\
|
||||
RESULT_ERROR_ERRNO();
|
||||
RESULT_ERROR(strerror(errno), false);
|
||||
#endif
|
||||
|
||||
struct sockaddr_in EndpointIPv4_toSockaddr(EndpointIPv4 end);
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
#include "network.h"
|
||||
#include "internal.h"
|
||||
|
||||
ErrorCodePage_define(WINSOCK2);
|
||||
|
||||
Result(void) network_init(){
|
||||
#if _WIN32
|
||||
ErrorCodePage_register(WINSOCK2);
|
||||
// Initialize Winsock
|
||||
WSADATA wsaData = {0};
|
||||
int result = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
#include "tlibc/errors.h"
|
||||
|
||||
ErrorCodePage_declare(WINSOCK2);
|
||||
|
||||
Result(void) network_init();
|
||||
void network_deinit();
|
||||
|
||||
@ -24,8 +24,8 @@ Result(ClientConnection*) ClientConnection_accept(ConnectionHandlerArgs* args)
|
||||
conn->session_key = Array_alloc_size(AES_SESSION_KEY_SIZE);
|
||||
// correct session key will be received from client later
|
||||
Array_memset(conn->session_key, 0);
|
||||
EncryptedSocketTCP_construct(&conn->sock, args->accepted_socket_tcp, NETWORK_BUFFER_SIZE, conn->session_key);
|
||||
try_void(socket_TCP_enableAliveChecks_default(args->accepted_socket_tcp));
|
||||
EncryptedSocketTCP_construct(&conn->sock, args->accepted_socket, NETWORK_BUFFER_SIZE, conn->session_key);
|
||||
try_void(socket_TCP_enableAliveChecks_default(args->accepted_socket));
|
||||
|
||||
// decrypt the rsa messages using server private key
|
||||
RSADecryptor rsa_dec;
|
||||
|
||||
@ -11,20 +11,6 @@ declare_RequestHandler(ServerPublicInfo)
|
||||
|
||||
//TODO: try find requested info
|
||||
Array(u8) content;
|
||||
switch(req.property){
|
||||
default:
|
||||
try(char* err_msg, p, sendErrorMessage(conn, res_head,
|
||||
"unknown ServerPublicInfo property %u", req.property));
|
||||
logWarn(log_ctx, "%s", err_msg);
|
||||
Return RESULT_VOID;
|
||||
break;
|
||||
case ServerPublicInfo_Name:
|
||||
content = str_castTo_Array(server->name);
|
||||
break;
|
||||
case ServerPublicInfo_Description:
|
||||
content = str_castTo_Array(server->name);
|
||||
break;
|
||||
}
|
||||
|
||||
PacketHeader_construct(res_head,
|
||||
PROTOCOL_VERSION, PacketType_ServerPublicInfoResponse, content.size);
|
||||
|
||||
@ -4,20 +4,20 @@
|
||||
#include "log.h"
|
||||
|
||||
|
||||
Result(char*) __sendErrorMessage_va(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(char*) __sendErrorMessage(ClientConnection* conn, PacketHeader* req_head, PacketHeader* res_head,
|
||||
u32 msg_buf_size, cstr format, va_list argv);
|
||||
Result(char*) sendErrorMessage(ClientConnection* conn, PacketHeader* req_head, PacketHeader* res_head,
|
||||
u32 msg_buf_size, cstr format, ...) ATTRIBUTE_CHECK_FORMAT_PRINTF(5, 6);
|
||||
|
||||
|
||||
#define declare_RequestHandler(TYPE) \
|
||||
Result(void) handleRequest_##TYPE( \
|
||||
Server* server, cstr log_ctx, cstr req_type_name, \
|
||||
cstr log_ctx, cstr req_type_name, \
|
||||
ClientConnection* conn, PacketHeader* req_head, PacketHeader* res_head)
|
||||
|
||||
#define case_handleRequest(TYPE) \
|
||||
case PacketType_##TYPE##Request:\
|
||||
try_void(handleRequest_##TYPE(args->server, log_ctx, #TYPE, conn, &req_head, &res_head));\
|
||||
try_void(handleRequest_##TYPE(log_ctx, #TYPE, conn, &req_head, &res_head));\
|
||||
break;
|
||||
|
||||
declare_RequestHandler(ServerPublicInfo);
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
#include "request_handlers.h"
|
||||
|
||||
Result(char*) __sendErrorMessage_va(ClientConnection* conn, PacketHeader* res_head,
|
||||
cstr format, va_list argv)
|
||||
Result(char*) __sendErrorMessage(ClientConnection* conn, PacketHeader* req_head, PacketHeader* res_head,
|
||||
u32 msg_buf_size, cstr format, va_list argv)
|
||||
{
|
||||
Deferral(4);
|
||||
(void)req_head;
|
||||
|
||||
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;
|
||||
//TODO: limit ErrorMessage size to fit into EncryptedSocketTCP.internal_buffer_size
|
||||
Array(u8) err_buf = Array_alloc(u8, msg_buf_size);
|
||||
bool err_complete = false;
|
||||
Defer(if(!err_complete) free(err_buf.data));
|
||||
vsprintf(err_buf.data, format, argv);
|
||||
err_buf.size = strlen(err_buf.data);
|
||||
|
||||
PacketHeader_construct(res_head,
|
||||
PROTOCOL_VERSION, PacketType_ErrorMessage, err_buf.size);
|
||||
@ -23,12 +22,12 @@ Result(char*) __sendErrorMessage_va(ClientConnection* conn, PacketHeader* res_he
|
||||
Return RESULT_VALUE(p, err_buf.data);
|
||||
}
|
||||
|
||||
Result(char*) sendErrorMessage(ClientConnection* conn, PacketHeader* res_head,
|
||||
cstr format, ...)
|
||||
Result(char*) sendErrorMessage(ClientConnection* conn, PacketHeader* req_head, PacketHeader* res_head,
|
||||
u32 msg_buf_size, cstr format, ...)
|
||||
{
|
||||
va_list argv;
|
||||
va_start(argv, format);
|
||||
ResultVar(char*) err_msg = __sendErrorMessage_va(conn, res_head, format, argv);
|
||||
ResultVar(char*) err_msg = __sendErrorMessage(conn, req_head, res_head, msg_buf_size, format, argv);
|
||||
va_end(argv);
|
||||
return err_msg;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include <pthread.h>
|
||||
#include "tlibc/filesystem.h"
|
||||
#include "tlibc/time.h"
|
||||
#include "tlibc/base64.h"
|
||||
#include "db/idb.h"
|
||||
#include "server.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
@ -17,7 +17,6 @@ void Server_free(Server* server){
|
||||
free(server->name.data);
|
||||
free(server->description.data);
|
||||
ServerCredentials_destroy(&server->cred);
|
||||
idb_close(server->db);
|
||||
}
|
||||
|
||||
Result(Server*) Server_createFromConfig(cstr config_path){
|
||||
@ -49,12 +48,6 @@ 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 local_address
|
||||
try_void(config_findValue(config_str, STR("local_address"), &tmp_str, true));
|
||||
char* local_end_cstr = str_copy(tmp_str).data;
|
||||
Defer(free(local_end_cstr));
|
||||
try_void(EndpointIPv4_parse(local_end_cstr, &server->local_end));
|
||||
|
||||
// parse rsa_private_key
|
||||
try_void(config_findValue(config_str, STR("rsa_private_key"), &tmp_str, true));
|
||||
char* sk_base64_cstr = str_copy(tmp_str).data;
|
||||
@ -67,37 +60,29 @@ Result(Server*) Server_createFromConfig(cstr config_path){
|
||||
|
||||
try_void(ServerCredentials_tryConstruct(&server->cred, sk_base64_cstr, pk_base64_cstr));
|
||||
|
||||
// parse db_key
|
||||
try_void(config_findValue(config_str, STR("db_aes_key"), &tmp_str, true));
|
||||
Array(u8) db_aes_key = Array_alloc_size(base64_decodedSize(tmp_str.data, tmp_str.size));
|
||||
base64_decode(tmp_str.data, tmp_str.size, db_aes_key.data);
|
||||
|
||||
// parse db_dir and open db
|
||||
try_void(config_findValue(config_str, STR("db_dir"), &tmp_str, true));
|
||||
try(server->db, p, idb_open(tmp_str, db_aes_key));
|
||||
|
||||
success = true;
|
||||
Return RESULT_VALUE(p, server);
|
||||
}
|
||||
|
||||
Result(void) Server_run(Server* server){
|
||||
Result(void) Server_run(Server* server, cstr server_endpoint_cstr){
|
||||
Deferral(16);
|
||||
cstr log_ctx = "ListenerThread";
|
||||
logInfo(log_ctx, "starting server");
|
||||
|
||||
EndpointIPv4 server_end;
|
||||
try_void(EndpointIPv4_parse(server_endpoint_cstr, &server_end));
|
||||
|
||||
logDebug(log_ctx, "initializing main socket");
|
||||
try(Socket main_socket, i, socket_open_TCP());
|
||||
try_void(socket_bind(main_socket, server->local_end));
|
||||
try_void(socket_bind(main_socket, server_end));
|
||||
try_void(socket_listen(main_socket, 512));
|
||||
str local_end_str = EndpointIPv4_toStr(server->local_end);
|
||||
Defer(free(local_end_str.data));
|
||||
logInfo(log_ctx, "server is listening at %s", local_end_str.data);
|
||||
logInfo(log_ctx, "server is listening at %s", server_endpoint_cstr);
|
||||
|
||||
u64 session_id = 1;
|
||||
while(true){
|
||||
ConnectionHandlerArgs* args = (ConnectionHandlerArgs*)malloc(sizeof(ConnectionHandlerArgs));
|
||||
args->server = server;
|
||||
try(args->accepted_socket_tcp, i,
|
||||
try(args->accepted_socket, i,
|
||||
socket_accept(main_socket, &args->client_end));
|
||||
args->session_id = session_id++;
|
||||
pthread_t conn_thread = {0};
|
||||
@ -152,8 +137,9 @@ static Result(void) try_handleConnection(ConnectionHandlerArgs* args, cstr log_c
|
||||
// send error message and close connection
|
||||
default:
|
||||
try(char* err_msg, p,
|
||||
sendErrorMessage(conn, &res_head,
|
||||
"Received unexpected packet of type %u",
|
||||
sendErrorMessage(
|
||||
conn, &req_head, &res_head,
|
||||
128, "Received unexpected packet of type %u",
|
||||
req_head.type
|
||||
)
|
||||
);
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
#include "cryptography/AES.h"
|
||||
#include "cryptography/RSA.h"
|
||||
#include "network/encrypted_sockets.h"
|
||||
#include "db/idb.h"
|
||||
|
||||
typedef struct Server Server;
|
||||
|
||||
@ -28,7 +27,7 @@ typedef struct ClientConnection {
|
||||
|
||||
typedef struct ConnectionHandlerArgs {
|
||||
Server* server;
|
||||
Socket accepted_socket_tcp;
|
||||
Socket accepted_socket;
|
||||
EndpointIPv4 client_end;
|
||||
u64 session_id;
|
||||
} ConnectionHandlerArgs;
|
||||
@ -41,11 +40,9 @@ void ClientConnection_close(ClientConnection* conn);
|
||||
typedef struct Server {
|
||||
str name;
|
||||
str description;
|
||||
EndpointIPv4 local_end;
|
||||
ServerCredentials cred;
|
||||
IncrementalDB* db;
|
||||
} Server;
|
||||
|
||||
Result(Server*) Server_createFromConfig(cstr config_path);
|
||||
void Server_free(Server* server);
|
||||
Result(void) Server_run(Server* server);
|
||||
Result(void) Server_run(Server* server, cstr server_endpoint_cstr);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user