implemented main function
This commit is contained in:
parent
b08ec27629
commit
c008d759ae
2
dependencies/tlibc
vendored
2
dependencies/tlibc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit d04aac567f105cc566db7b9b8e201c1a04e4ecea
|
Subproject commit bf56984482d83d1a178f4da6483fbd350457e438
|
||||||
@ -34,13 +34,13 @@ case "$OS" in
|
|||||||
EXEC_FILE="$PROJECT.exe"
|
EXEC_FILE="$PROJECT.exe"
|
||||||
SHARED_LIB_FILE="$PROJECT.dll"
|
SHARED_LIB_FILE="$PROJECT.dll"
|
||||||
INCLUDE="$INCLUDE "
|
INCLUDE="$INCLUDE "
|
||||||
LINKER_LIBS="-lpthread -lws2_32"
|
LINKER_LIBS="-lpthread -lws2_32 -lreadline"
|
||||||
;;
|
;;
|
||||||
LINUX)
|
LINUX)
|
||||||
EXEC_FILE="$PROJECT"
|
EXEC_FILE="$PROJECT"
|
||||||
SHARED_LIB_FILE="$PROJECT.so"
|
SHARED_LIB_FILE="$PROJECT.so"
|
||||||
INCLUDE="$INCLUDE "
|
INCLUDE="$INCLUDE "
|
||||||
LINKER_LIBS=""
|
LINKER_LIBS="-lreadline"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
error "operating system $OS has no configuration variants"
|
error "operating system $OS has no configuration variants"
|
||||||
|
|||||||
101
src/client.c
Normal file
101
src/client.c
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include "client.h"
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
#include "term.h"
|
||||||
|
|
||||||
|
#define inp_eq(LITERAL) str_equals(input, STR(LITERAL))
|
||||||
|
|
||||||
|
static const str greeting_art = STR(
|
||||||
|
" ^,,^ ╱|\n"
|
||||||
|
" ( •·•) Meum! (o.o`7\n"
|
||||||
|
" / ` | Meum... |`˜ \\\n"
|
||||||
|
"\\(_,J J L l`,)/\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
static const str farewell_art = STR(
|
||||||
|
" ^,,^ ╱|\n"
|
||||||
|
" ( -.-) (>,<`7\n"
|
||||||
|
" / ` | Goodbye! |`˜ \\\n"
|
||||||
|
"\\(_,J J L l`,)/\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
Result(void) client_run() {
|
||||||
|
Deferral(128);
|
||||||
|
if(!term_init()){
|
||||||
|
Return RESULT_ERROR("can't init terminal", false);
|
||||||
|
}
|
||||||
|
using_history();
|
||||||
|
|
||||||
|
fputs(greeting_art.data, stdout);
|
||||||
|
|
||||||
|
char* input_prev = NULL;
|
||||||
|
char* input_raw = NULL;
|
||||||
|
Defer(rl_free(input_prev));
|
||||||
|
str input = str_null;
|
||||||
|
while((input_raw = readline("> "))){
|
||||||
|
rl_free(input_prev);
|
||||||
|
input_prev = input_raw;
|
||||||
|
input = str_from_cstr(input_raw);
|
||||||
|
line_trim(&input, true);
|
||||||
|
add_history(input.data);
|
||||||
|
if(input.size == 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(inp_eq("q") || inp_eq("quit") || inp_eq("exit")){
|
||||||
|
fputs(farewell_art.data, stdout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(inp_eq("clear")){
|
||||||
|
term_clear();
|
||||||
|
}
|
||||||
|
else if(inp_eq("h") || inp_eq("help")){
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(inp_eq("c") || inp_eq("connect")){
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("ERROR: unknown kommand: '%s'\n"
|
||||||
|
"Use 'h' to see list of avaliable commands\n",
|
||||||
|
input.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void line_trim(str* line, bool set_zero_at_end){
|
||||||
|
bool stop = false;
|
||||||
|
// loop forward
|
||||||
|
while(line->size > 0 && !stop){
|
||||||
|
char first_char = line->data[line->size - 1];
|
||||||
|
switch(first_char){
|
||||||
|
case '\0': case '\r': case '\n':
|
||||||
|
case '\t': case ' ':
|
||||||
|
line->data++;
|
||||||
|
line->size--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// loop backward
|
||||||
|
while(line->size > 0 && !stop)
|
||||||
|
{
|
||||||
|
char last_char = line->data[line->size - 1];
|
||||||
|
switch(last_char){
|
||||||
|
case '\0': case '\r': case '\n':
|
||||||
|
case '\t': case ' ':
|
||||||
|
line->size--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stop = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(set_zero_at_end){
|
||||||
|
line->data[line->size] = '\0';
|
||||||
|
line->isZeroTerminated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/client.h
Normal file
7
src/client.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tlibc/errors.h"
|
||||||
|
|
||||||
|
Result(void) client_run();
|
||||||
|
|
||||||
|
/// @brief removes blank characters from start and end of the line
|
||||||
|
void line_trim(str* line, bool set_zero_at_end);
|
||||||
22
src/db/idb.c
22
src/db/idb.c
@ -34,14 +34,6 @@ typedef struct IncrementalDB {
|
|||||||
} IncrementalDB;
|
} IncrementalDB;
|
||||||
|
|
||||||
static const Magic32 TABLE_FILE_MAGIC = { .bytes = { 'I', 'D', 'B', 't' } };
|
static const Magic32 TABLE_FILE_MAGIC = { .bytes = { 'I', 'D', 'B', 't' } };
|
||||||
#define IDB_VERSION 0x01
|
|
||||||
|
|
||||||
#define try_pthread(CALL) do {\
|
|
||||||
int r = CALL;\
|
|
||||||
if(r != 0){\
|
|
||||||
Return RESULT_ERROR(strerror(r), false);\
|
|
||||||
}\
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
|
|
||||||
void Table_close(Table* t){
|
void Table_close(Table* t){
|
||||||
@ -169,7 +161,7 @@ Result(IncrementalDB*) idb_open(str db_dir){
|
|||||||
db->db_dir = str_copy(db_dir);
|
db->db_dir = str_copy(db_dir);
|
||||||
try_void(dir_create(db->db_dir.data));
|
try_void(dir_create(db->db_dir.data));
|
||||||
HashMap_construct(&db->tables_map, Table*, TablePtr_destroy);
|
HashMap_construct(&db->tables_map, Table*, TablePtr_destroy);
|
||||||
try_pthread(pthread_mutex_init(&db->mutex, NULL));
|
try_stderrcode(pthread_mutex_init(&db->mutex, NULL));
|
||||||
|
|
||||||
success = true;
|
success = true;
|
||||||
Return RESULT_VALUE(p, db);
|
Return RESULT_VALUE(p, db);
|
||||||
@ -185,7 +177,7 @@ 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){
|
||||||
Deferral(64);
|
Deferral(64);
|
||||||
// db lock
|
// db lock
|
||||||
try_pthread(pthread_mutex_lock(&db->mutex));
|
try_stderrcode(pthread_mutex_lock(&db->mutex));
|
||||||
Defer(pthread_mutex_unlock(&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);
|
||||||
@ -208,7 +200,7 @@ Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str _table_name, u32 row_
|
|||||||
// value of *t must be set to zero or behavior of Table_close will be undefined
|
// value of *t must be set to zero or behavior of Table_close will be undefined
|
||||||
memset(t, 0, sizeof(Table));
|
memset(t, 0, sizeof(Table));
|
||||||
t->db = db;
|
t->db = db;
|
||||||
try_pthread(pthread_mutex_init(&t->mutex, NULL));
|
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(
|
t->table_file_path = str_from_cstr(
|
||||||
strcat_malloc(db->db_dir.data, path_seps, t->name.data, ".idb-table"));
|
strcat_malloc(db->db_dir.data, path_seps, t->name.data, ".idb-table"));
|
||||||
@ -251,7 +243,7 @@ Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str _table_name, u32 row_
|
|||||||
Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count){
|
Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count){
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
// table lock
|
// table lock
|
||||||
try_pthread(pthread_mutex_lock(&t->mutex));
|
try_stderrcode(pthread_mutex_lock(&t->mutex));
|
||||||
Defer(pthread_mutex_unlock(&t->mutex));
|
Defer(pthread_mutex_unlock(&t->mutex));
|
||||||
|
|
||||||
if(id + count > t->row_count){
|
if(id + count > t->row_count){
|
||||||
@ -274,7 +266,7 @@ Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count){
|
|||||||
Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count){
|
Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count){
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
// table lock
|
// table lock
|
||||||
try_pthread(pthread_mutex_lock(&t->mutex));
|
try_stderrcode(pthread_mutex_lock(&t->mutex));
|
||||||
Defer(pthread_mutex_unlock(&t->mutex));
|
Defer(pthread_mutex_unlock(&t->mutex));
|
||||||
|
|
||||||
if(id + count >= t->row_count){
|
if(id + count >= t->row_count){
|
||||||
@ -303,7 +295,7 @@ Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count){
|
|||||||
Result(u64) idb_pushRows(Table* t, const void* src, u64 count){
|
Result(u64) idb_pushRows(Table* t, const void* src, u64 count){
|
||||||
Deferral(16);
|
Deferral(16);
|
||||||
// table lock
|
// table lock
|
||||||
try_pthread(pthread_mutex_lock(&t->mutex));
|
try_stderrcode(pthread_mutex_lock(&t->mutex));
|
||||||
Defer(pthread_mutex_unlock(&t->mutex));
|
Defer(pthread_mutex_unlock(&t->mutex));
|
||||||
|
|
||||||
try_void(Table_setDirtyBit(t, true));
|
try_void(Table_setDirtyBit(t, true));
|
||||||
@ -323,7 +315,7 @@ Result(u64) idb_pushRows(Table* t, const void* src, u64 count){
|
|||||||
Result(u64) idb_getRowCount(Table* t){
|
Result(u64) idb_getRowCount(Table* t){
|
||||||
Deferral(8);
|
Deferral(8);
|
||||||
// table lock
|
// table lock
|
||||||
try_pthread(pthread_mutex_lock(&t->mutex));
|
try_stderrcode(pthread_mutex_lock(&t->mutex));
|
||||||
Defer(pthread_mutex_unlock(&t->mutex));
|
Defer(pthread_mutex_unlock(&t->mutex));
|
||||||
u64 count = t->row_count;
|
u64 count = t->row_count;
|
||||||
Return RESULT_VALUE(u, count);
|
Return RESULT_VALUE(u, count);
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
#include "tlibc/string/str.h"
|
|
||||||
|
#define IDB_VERSION 1
|
||||||
|
|
||||||
typedef struct IncrementalDB IncrementalDB;
|
typedef struct IncrementalDB IncrementalDB;
|
||||||
typedef struct Table Table;
|
typedef struct Table Table;
|
||||||
|
|||||||
245
src/main.c
245
src/main.c
@ -1,197 +1,66 @@
|
|||||||
#include "cryptography/cryptography.h"
|
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "network/socket.h"
|
#include "client.h"
|
||||||
#include "tlibc/time.h"
|
#include "server.h"
|
||||||
#include "db/idb.h"
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
Result(void) test_aes(){
|
typedef enum ProgramMode {
|
||||||
Deferral(64);
|
Client,
|
||||||
const str password = STR("abobus");
|
Server,
|
||||||
const Array(const char) data = str_castTo_Array(STR("0123456789_hii_"));
|
} ProgramMode;
|
||||||
|
|
||||||
u8 hash_buffer[hash_password_out_size];
|
|
||||||
// SHA256 accepts keys with size 16, 24 or 32
|
|
||||||
const u32 key_size = 32;
|
|
||||||
assert(key_size <= hash_password_out_size);
|
|
||||||
const Array(u8) key = Array_construct_size(hash_buffer, key_size);
|
|
||||||
hash_password(password, hash_buffer, 1e5);
|
|
||||||
str hash_str = hex_to_str(key, true);
|
|
||||||
printf("key [%i] %s\n", key.size, hash_str.data);
|
|
||||||
free(hash_str.data);
|
|
||||||
|
|
||||||
EncryptorAES encr;
|
#define arg_is(LITERAL) str_equals(arg_str, STR(LITERAL))
|
||||||
EncryptorAES_create(&encr, key);
|
|
||||||
Array(u8) buffer = Array_alloc_size(EncryptorAES_calcDstSize(data.size));
|
|
||||||
EncryptorAES_encrypt(&encr, data, buffer);
|
|
||||||
|
|
||||||
str encrypted_str = hex_to_str(buffer, true);
|
|
||||||
printf("data encrypted (hex): %s\n", encrypted_str.data);
|
|
||||||
free(encrypted_str.data);
|
|
||||||
|
|
||||||
DecryptorAES decr;
|
int main(const int argc, cstr const* argv){
|
||||||
DecryptorAES_create(&decr, key);
|
|
||||||
u32 decrypted_size = 0;
|
|
||||||
DecryptorAES_decrypt(&decr, buffer, buffer, &decrypted_size);
|
|
||||||
|
|
||||||
str decrypted_str = str_copy(str_construct(buffer.data, decrypted_size, false));
|
|
||||||
printf("data decrypted (utf8): %s\n", decrypted_str.data);
|
|
||||||
free(decrypted_str.data);
|
|
||||||
|
|
||||||
free(buffer.data);
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static pthread_mutex_t stdout_mutex = {0};
|
|
||||||
|
|
||||||
/// thread-safe print
|
|
||||||
#define printf_safe(ARGS...) {\
|
|
||||||
pthread_mutex_lock(&stdout_mutex);\
|
|
||||||
printf(ARGS);\
|
|
||||||
fflush(stdout);\
|
|
||||||
pthread_mutex_unlock(&stdout_mutex);\
|
|
||||||
}
|
|
||||||
|
|
||||||
/// removes blank characters from line end
|
|
||||||
void line_trim(str* line, bool set_zero_at_end){
|
|
||||||
bool stop = false;
|
|
||||||
while(line->size > 0 && !stop)
|
|
||||||
{
|
|
||||||
char last_char = line->data[line->size - 1];
|
|
||||||
switch(last_char){
|
|
||||||
case '\0': case '\r': case '\n':
|
|
||||||
case '\t': case ' ':
|
|
||||||
line->size--;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(set_zero_at_end){
|
|
||||||
line->data[line->size] = '\0';
|
|
||||||
line->isZeroTerminated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* test_server(void* data){
|
|
||||||
Deferral(64);
|
|
||||||
printf_safe("[server]: opening main socket\n");
|
|
||||||
try_fatal(Socket main_socket, i, socket_open_TCP());
|
|
||||||
Defer(socket_close(main_socket));
|
|
||||||
|
|
||||||
EndpointIPv4 server_end = EndpointIPv4_create(AddressIPv4_LOOPBACK, 24500);
|
|
||||||
try_fatal_void(socket_bind(main_socket, server_end));
|
|
||||||
try_fatal_void(socket_listen(main_socket, 64));
|
|
||||||
printf_safe("[server]: accepting client connection\n");
|
|
||||||
try_fatal(Socket client_socket, i, socket_accept(main_socket, NULL));
|
|
||||||
Defer(socket_close(client_socket));
|
|
||||||
|
|
||||||
// last byte is reserved for '\0'
|
|
||||||
Array(u8) buf = Array_construct(malloc(1024), u8, 1023);
|
|
||||||
printf_safe("[server]: receiving data from client\n");
|
|
||||||
while(true){
|
|
||||||
try_fatal(i32 read_n, i, socket_recv(client_socket, buf));
|
|
||||||
if(read_n == 0){
|
|
||||||
sleepMsec(20);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
str message = str_construct(buf.data, read_n, false);
|
|
||||||
line_trim(&message, true);
|
|
||||||
printf_safe("[server]: received '%s'\n", message.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf_safe("[server]: client socket closed\n");
|
|
||||||
perror("errno:");
|
|
||||||
Return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* test_client(void* data){
|
|
||||||
Deferral(64);
|
|
||||||
printf_safe("[client]: opening socket\n");
|
|
||||||
try_fatal(Socket client_socket, i, socket_open_TCP());
|
|
||||||
Defer(socket_close(client_socket));
|
|
||||||
|
|
||||||
printf_safe("[client]: connecting to server\n");
|
|
||||||
EndpointIPv4 server_end = EndpointIPv4_create(AddressIPv4_LOOPBACK, 24500);
|
|
||||||
try_fatal_void(socket_connect(client_socket, server_end));
|
|
||||||
|
|
||||||
Array(u8) buf = Array_alloc(u8, 1024);
|
|
||||||
printf_safe("[client]: reading stdin\n");
|
|
||||||
while(fgets(buf.data, buf.size, stdin) != NULL){
|
|
||||||
str line = str_construct(buf.data, strlen(buf.data), true);
|
|
||||||
line_trim(&line, true);
|
|
||||||
if(str_equals(line, STR("/q"))){
|
|
||||||
printf_safe("[client]: quit\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
try_fatal_void(socket_send(client_socket, str_castTo_Array(line)));
|
|
||||||
}
|
|
||||||
|
|
||||||
printf_safe("[client]: closing connection\n");
|
|
||||||
Return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(void) test_network(){
|
|
||||||
Deferral(64);
|
|
||||||
if(pthread_mutex_init(&stdout_mutex, NULL) != 0){
|
|
||||||
Return RESULT_ERROR("can't init mutex", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_t server_thread = {0};
|
|
||||||
if(pthread_create(&server_thread, NULL, test_server, NULL) != 0){
|
|
||||||
Return RESULT_ERROR("can't create server thread", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
sleepMsec(100);
|
|
||||||
test_client(NULL);
|
|
||||||
|
|
||||||
printf_safe("[main]: joining server thread\n");
|
|
||||||
if(pthread_join(server_thread, NULL) != 0){
|
|
||||||
Return RESULT_ERROR("can't join server thread", false);
|
|
||||||
}
|
|
||||||
if(pthread_mutex_destroy(&stdout_mutex) != 0){
|
|
||||||
Return RESULT_ERROR("can't destroy mutex", false);
|
|
||||||
}
|
|
||||||
printf_safe("[main]: completed\n");
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result(void) test_db(){
|
|
||||||
Deferral(64);
|
|
||||||
try(IncrementalDB* db, p, idb_open(STR("idb")));
|
|
||||||
Defer(idb_close(db));
|
|
||||||
|
|
||||||
const u32 row_size = 8;
|
|
||||||
const u32 rows_count = 5;
|
|
||||||
const char const_rows[5][8] = {
|
|
||||||
"0123456", "bebra", "abobus", "q", "DIMOOON"
|
|
||||||
};
|
|
||||||
char buffer[512];
|
|
||||||
memset(buffer, 0, 512);
|
|
||||||
|
|
||||||
try(Table* t0, p, idb_getOrCreateTable(db, STR("test0"), row_size));
|
|
||||||
printf("table 'test0' created\n");
|
|
||||||
|
|
||||||
try_void(idb_pushRows(t0, const_rows, rows_count));
|
|
||||||
|
|
||||||
const u32 indices[] = { 0, 1, 4, 3, 4, 0 };
|
|
||||||
for(u32 i = 0; i < ARRAY_LEN(indices); i++){
|
|
||||||
try_void(idb_getRow(t0, indices[i], buffer));
|
|
||||||
printf("row %u: %s\n", indices[i], buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Return RESULT_VOID;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(){
|
|
||||||
Deferral(32);
|
Deferral(32);
|
||||||
|
|
||||||
|
ProgramMode mode = Client;
|
||||||
|
cstr server_endpoint_cstr;
|
||||||
|
|
||||||
|
for(int argi = 1; argi < argc; argi++){
|
||||||
|
str arg_str = str_from_cstr(argv[argi]);
|
||||||
|
if(arg_is("-h") || arg_is("--help")){
|
||||||
|
printf(
|
||||||
|
"USAGE:\n"
|
||||||
|
"no arguments Interactive client mode.\n"
|
||||||
|
"-h, --help Show this message.\n"
|
||||||
|
"-l, --listen [addr:port] Start server.\n"
|
||||||
|
);
|
||||||
|
Return 0;
|
||||||
|
}
|
||||||
|
if(arg_is("-l") || arg_is("--listen")){
|
||||||
|
if(mode != Client){
|
||||||
|
printf("program mode is set already\n");
|
||||||
|
Return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode = Server;
|
||||||
|
if(++argi >= argc){
|
||||||
|
printfe("ERROR: no endpoint specified\n");
|
||||||
|
Return 1;
|
||||||
|
}
|
||||||
|
server_endpoint_cstr = argv[argi];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printfe("ERROR: unknown argument '%s'\n"
|
||||||
|
"Use '-h' to see list of avaliable arguments\n",
|
||||||
|
argv[argi]);
|
||||||
|
Return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try_fatal_void(network_init());
|
try_fatal_void(network_init());
|
||||||
Defer(network_deinit());
|
Defer(network_deinit());
|
||||||
// try_fatal_void(test_aes());
|
|
||||||
// try_fatal_void(test_network());
|
switch(mode){
|
||||||
try_fatal_void(test_db());
|
case Client:
|
||||||
|
try_fatal_void(client_run());
|
||||||
|
break;
|
||||||
|
case Server:
|
||||||
|
try_fatal_void(server_run(server_endpoint_cstr));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printfe("ERROR: invalid program mode %i\n", mode);
|
||||||
|
Return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Return 0;
|
Return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,11 +19,19 @@ EndpointIPv4 EndpointIPv4_fromSockaddr(struct sockaddr_in saddr){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO Endpoint functions
|
//TODO Endpoint functions
|
||||||
AddressIPv4 AddressIPv4_fromStr(cstr);
|
AddressIPv4 AddressIPv4_fromStr(cstr s);
|
||||||
|
|
||||||
str AddressIPv4_toStr(AddressIPv4 address);
|
str AddressIPv4_toStr(AddressIPv4 address);
|
||||||
|
|
||||||
EndpointIPv4 EndpointIPv4_fromStr(cstr s);
|
EndpointIPv4 EndpointIPv4_fromStr(cstr s){
|
||||||
|
u32 a, b, c, d, p;
|
||||||
|
sscanf(s, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &p);
|
||||||
|
EndpointIPv4 e = (EndpointIPv4){
|
||||||
|
.address = AddressIPv4_fromBytes(a, b, c, d),
|
||||||
|
.port = p
|
||||||
|
};
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
str EndpointIPv4_toStr(EndpointIPv4 end);
|
str EndpointIPv4_toStr(EndpointIPv4 end);
|
||||||
|
|
||||||
|
|||||||
@ -16,9 +16,9 @@ typedef union AddressIPv4 {
|
|||||||
#define AddressIPv4_INVALID AddressIPv4_fromBytes(255,255,255,255)
|
#define AddressIPv4_INVALID AddressIPv4_fromBytes(255,255,255,255)
|
||||||
#define AddressIPv4_is_invalid(ADDR) (ADDR.UintBigEndian == (u32)~0)
|
#define AddressIPv4_is_invalid(ADDR) (ADDR.UintBigEndian == (u32)~0)
|
||||||
|
|
||||||
#define AddressIPv4_fromBytes(A, B, C, D) ((AddressIPv4){.bytes={A,B,C,D}})
|
#define AddressIPv4_fromBytes(A, B, C, D) ((AddressIPv4){ .bytes = {A,B,C,D} })
|
||||||
#define AddressIPv4_fromU32(N) ((AddressIPv4){.UintBigEndian=N})
|
#define AddressIPv4_fromU32(N) ((AddressIPv4){ .UintBigEndian = N })
|
||||||
AddressIPv4 AddressIPv4_fromStr(cstr);
|
AddressIPv4 AddressIPv4_fromStr(cstr s);
|
||||||
str AddressIPv4_toStr(AddressIPv4 address);
|
str AddressIPv4_toStr(AddressIPv4 address);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "tlibc/errors.h"
|
||||||
|
|
||||||
#if !defined(KN_USE_WINSOCK)
|
#if !defined(KN_USE_WINSOCK)
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
@ -10,6 +11,9 @@
|
|||||||
|
|
||||||
#if KN_USE_WINSOCK
|
#if KN_USE_WINSOCK
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
// There you can see what error codes mean.
|
||||||
|
#include <winerror.h>
|
||||||
|
#define RESULT_ERROR_SOCKET() RESULT_ERROR(sprintf_malloc(64, "Winsock error %i", WSAGetLastError()), true)
|
||||||
#else
|
#else
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -17,4 +21,6 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define RESULT_ERROR_SOCKET() RESULT_ERROR(strerror(errno), false)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
Result(Socket) socket_open_TCP(){
|
Result(Socket) socket_open_TCP(){
|
||||||
Socket s = socket(AF_INET, SOCK_STREAM, 0);
|
Socket s = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
if(s == -1){
|
if(s == -1){
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_VALUE(i, s);
|
return RESULT_VALUE(i, s);
|
||||||
@ -21,20 +21,20 @@ void socket_close(Socket s){
|
|||||||
|
|
||||||
Result(void) socket_shutdown(Socket s, SocketShutdownType direction){
|
Result(void) socket_shutdown(Socket s, SocketShutdownType direction){
|
||||||
if(shutdown(s, (int)direction) == -1)
|
if(shutdown(s, (int)direction) == -1)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) socket_bind(Socket s, EndpointIPv4 local_end){
|
Result(void) socket_bind(Socket s, EndpointIPv4 local_end){
|
||||||
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(local_end);
|
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(local_end);
|
||||||
if(bind(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
|
if(bind(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) socket_listen(Socket s, i32 backlog){
|
Result(void) socket_listen(Socket s, i32 backlog){
|
||||||
if(listen(s, backlog) != 0)
|
if(listen(s, backlog) != 0)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ Result(Socket) socket_accept(Socket main_socket, NULLABLE(EndpointIPv4*) remote_
|
|||||||
i32 sockaddr_size = sizeof(remote_addr);
|
i32 sockaddr_size = sizeof(remote_addr);
|
||||||
Socket user_connection = accept(main_socket, (void*)&remote_addr, (void*)&sockaddr_size);
|
Socket user_connection = accept(main_socket, (void*)&remote_addr, (void*)&sockaddr_size);
|
||||||
if(user_connection == -1)
|
if(user_connection == -1)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
|
|
||||||
//TODO: add IPV6 support (struct sockaddr_in6)
|
//TODO: add IPV6 support (struct sockaddr_in6)
|
||||||
assert(sockaddr_size == sizeof(remote_addr));
|
assert(sockaddr_size == sizeof(remote_addr));
|
||||||
@ -55,14 +55,14 @@ Result(Socket) socket_accept(Socket main_socket, NULLABLE(EndpointIPv4*) remote_
|
|||||||
Result(void) socket_connect(Socket s, EndpointIPv4 remote_end){
|
Result(void) socket_connect(Socket s, EndpointIPv4 remote_end){
|
||||||
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(remote_end);
|
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(remote_end);
|
||||||
if(connect(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
|
if(connect(s, (void*)&sockaddr, sizeof(sockaddr)) != 0)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(void) socket_send(Socket s, Array(u8) buffer){
|
Result(void) socket_send(Socket s, Array(u8) buffer){
|
||||||
i32 r = send(s, buffer.data, buffer.size, 0);
|
i32 r = send(s, buffer.data, buffer.size, 0);
|
||||||
if(r < 0)
|
if(r < 0)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,25 +70,24 @@ Result(void) socket_sendto(Socket s, Array(u8) buffer, EndpointIPv4 dst){
|
|||||||
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(dst);
|
struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(dst);
|
||||||
i32 r = sendto(s, buffer.data, buffer.size, 0, (void*)&sockaddr, sizeof(sockaddr));
|
i32 r = sendto(s, buffer.data, buffer.size, 0, (void*)&sockaddr, sizeof(sockaddr));
|
||||||
if(r < 0)
|
if(r < 0)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result(i32) socket_recv(Socket s, Array(u8) buffer){
|
Result(i32) socket_recv(Socket s, Array(u8) buffer){
|
||||||
i32 r = recv(s, buffer.data, buffer.size, 0);
|
i32 r = recv(s, buffer.data, buffer.size, 0);
|
||||||
if(r < 0)
|
if(r < 0)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
return RESULT_VALUE(i, r);
|
return RESULT_VALUE(i, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, NULLABLE(EndpointIPv4*) remote_end){
|
Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, NULLABLE(EndpointIPv4*) remote_end){
|
||||||
struct sockaddr_in remote_addr = {0};
|
struct sockaddr_in remote_addr = {0};
|
||||||
i32 sockaddr_size = sizeof(remote_addr);
|
i32 sockaddr_size = sizeof(remote_addr);
|
||||||
i32 r = recvfrom(s, buffer.data, buffer.size, 0,
|
i32 r = recvfrom(s, buffer.data, buffer.size, 0,
|
||||||
(struct sockaddr*)&remote_addr, (void*)&sockaddr_size);
|
(struct sockaddr*)&remote_addr, (void*)&sockaddr_size);
|
||||||
if(r < 0)
|
if(r < 0)
|
||||||
return RESULT_ERROR_ERRNO();
|
return RESULT_ERROR_SOCKET();
|
||||||
|
|
||||||
//TODO: add IPV6 support (struct sockaddr_in6)
|
//TODO: add IPV6 support (struct sockaddr_in6)
|
||||||
assert(sockaddr_size == sizeof(remote_addr));
|
assert(sockaddr_size == sizeof(remote_addr));
|
||||||
@ -96,4 +95,4 @@ Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, NULLABLE(EndpointIPv4*)
|
|||||||
if(remote_end)
|
if(remote_end)
|
||||||
*remote_end = EndpointIPv4_fromSockaddr(remote_addr);
|
*remote_end = EndpointIPv4_fromSockaddr(remote_addr);
|
||||||
return RESULT_VALUE(i, r);
|
return RESULT_VALUE(i, r);
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/server.c
Normal file
37
src/server.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "server.h"
|
||||||
|
#include "network/socket.h"
|
||||||
|
#include "db/idb.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
typedef struct AcceptedConnection {
|
||||||
|
Socket sock;
|
||||||
|
EndpointIPv4 client_end;
|
||||||
|
} AcceptedConnection;
|
||||||
|
|
||||||
|
static void* handle_connection(void* _args);
|
||||||
|
|
||||||
|
Result(void) server_run(cstr server_endpoint_str){
|
||||||
|
Deferral(32);
|
||||||
|
EndpointIPv4 server_end = EndpointIPv4_fromStr(server_endpoint_str);
|
||||||
|
//TODO: add log
|
||||||
|
try(Socket main_socket, i, socket_open_TCP());
|
||||||
|
try_void(socket_bind(main_socket, server_end));
|
||||||
|
try_void(socket_listen(main_socket, 512));
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
AcceptedConnection* args = malloc(sizeof(AcceptedConnection));
|
||||||
|
try(args->sock, i, socket_accept(main_socket, &args->client_end));
|
||||||
|
pthread_t conn_thread = {0};
|
||||||
|
try_stderrcode(pthread_create(&conn_thread, NULL, handle_connection, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* handle_connection(void* _args){
|
||||||
|
Deferral(64);
|
||||||
|
AcceptedConnection* conn = (AcceptedConnection*)_args;
|
||||||
|
Defer(free(conn));
|
||||||
|
|
||||||
|
Return NULL;
|
||||||
|
}
|
||||||
4
src/server.h
Normal file
4
src/server.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tlibc/errors.h"
|
||||||
|
|
||||||
|
Result(void) server_run(cstr server_endpoint_str);
|
||||||
95
src/term.c
Normal file
95
src/term.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "term.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include IFWIN("windows.h", "sys/ioctl.h")
|
||||||
|
|
||||||
|
bool term_init(){
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
DWORD mode=0;
|
||||||
|
HANDLE h;
|
||||||
|
|
||||||
|
// configure stdout
|
||||||
|
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if(h == INVALID_HANDLE_VALUE)
|
||||||
|
return false;
|
||||||
|
GetConsoleMode(h, &mode);
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
mode |= ENABLE_PROCESSED_OUTPUT;
|
||||||
|
SetConsoleMode(h, mode);
|
||||||
|
|
||||||
|
// configure stdin
|
||||||
|
h = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
if(h == INVALID_HANDLE_VALUE)
|
||||||
|
return false;
|
||||||
|
GetConsoleMode(h, &mode);
|
||||||
|
mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
|
mode |= ENABLE_PROCESSED_INPUT;
|
||||||
|
SetConsoleMode(h, mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getenv_int(const char* var_name){
|
||||||
|
char* str=getenv(var_name);
|
||||||
|
if(str==NULL)
|
||||||
|
return -1;
|
||||||
|
return strtol(str, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool term_getSize(TerminalSize* out) {
|
||||||
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
|
// helps when STD_OUT is redirected to a file
|
||||||
|
HANDLE hConsoleErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
||||||
|
if(!GetConsoleScreenBufferInfo(hConsoleErr, &consoleInfo))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
out->cols = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1;
|
||||||
|
out->rows = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1;
|
||||||
|
#else
|
||||||
|
struct winsize ws = {0};
|
||||||
|
// try to get terminal size from stdin, stdout, stderr
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)==0 ||
|
||||||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)==0 ||
|
||||||
|
ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)==0 ){
|
||||||
|
out->cols=ws.ws_col;
|
||||||
|
out->rows=ws.ws_row;
|
||||||
|
}
|
||||||
|
// try to get size from environtent variables
|
||||||
|
else {
|
||||||
|
out->cols=getenv_int("COLUMNS");
|
||||||
|
out->rows=getenv_int("LINES");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return out->cols > 0 && out->rows > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Most of escape sequences can be found there
|
||||||
|
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
|
||||||
|
*/
|
||||||
|
|
||||||
|
void term_resetCursor() {
|
||||||
|
printf("\e[H");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_resetColors() {
|
||||||
|
printf("\e[0m");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_clear() {
|
||||||
|
printf("\e[0m\e[H\e[2J");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_cursorMove(u16 row, u16 column) {
|
||||||
|
printf("\e[%u;%uH",row,column);
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_cursorHide() {
|
||||||
|
printf("\e[?25l");
|
||||||
|
}
|
||||||
|
|
||||||
|
void term_cursorShow() {
|
||||||
|
printf("\e[?25h");
|
||||||
|
}
|
||||||
16
src/term.h
Normal file
16
src/term.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "tlibc/std.h"
|
||||||
|
|
||||||
|
typedef struct TerminalSize {
|
||||||
|
i16 cols;
|
||||||
|
i16 rows;
|
||||||
|
} TerminalSize;
|
||||||
|
|
||||||
|
bool term_init();
|
||||||
|
bool term_getSize(TerminalSize* out);
|
||||||
|
void term_resetCursor();
|
||||||
|
void term_resetColors();
|
||||||
|
void term_clear();
|
||||||
|
void term_cursorMove(u16 row, u16 column);
|
||||||
|
void term_cursorHide();
|
||||||
|
void term_cursorShow();
|
||||||
Loading…
Reference in New Issue
Block a user