From c008d759ae44cdddec25b7c3a1d28ef897038a05 Mon Sep 17 00:00:00 2001 From: Timerix Date: Sun, 10 Aug 2025 21:39:51 +0300 Subject: [PATCH] implemented main function --- dependencies/tlibc | 2 +- project.config | 4 +- src/client.c | 101 +++++++++++++++++ src/client.h | 7 ++ src/db/idb.c | 22 ++-- src/db/idb.h | 3 +- src/main.c | 245 ++++++++++------------------------------- src/network/endpoint.c | 12 +- src/network/endpoint.h | 6 +- src/network/internal.h | 6 + src/network/socket.c | 23 ++-- src/server.c | 37 +++++++ src/server.h | 4 + src/term.c | 95 ++++++++++++++++ src/term.h | 16 +++ 15 files changed, 359 insertions(+), 224 deletions(-) create mode 100644 src/client.c create mode 100644 src/client.h create mode 100644 src/server.c create mode 100644 src/server.h create mode 100644 src/term.c create mode 100644 src/term.h diff --git a/dependencies/tlibc b/dependencies/tlibc index d04aac5..bf56984 160000 --- a/dependencies/tlibc +++ b/dependencies/tlibc @@ -1 +1 @@ -Subproject commit d04aac567f105cc566db7b9b8e201c1a04e4ecea +Subproject commit bf56984482d83d1a178f4da6483fbd350457e438 diff --git a/project.config b/project.config index a1c32fb..a0b4ad8 100644 --- a/project.config +++ b/project.config @@ -34,13 +34,13 @@ case "$OS" in EXEC_FILE="$PROJECT.exe" SHARED_LIB_FILE="$PROJECT.dll" INCLUDE="$INCLUDE " - LINKER_LIBS="-lpthread -lws2_32" + LINKER_LIBS="-lpthread -lws2_32 -lreadline" ;; LINUX) EXEC_FILE="$PROJECT" SHARED_LIB_FILE="$PROJECT.so" INCLUDE="$INCLUDE " - LINKER_LIBS="" + LINKER_LIBS="-lreadline" ;; *) error "operating system $OS has no configuration variants" diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..a283db5 --- /dev/null +++ b/src/client.c @@ -0,0 +1,101 @@ +#include "client.h" +#include +#include +#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; + } +} diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..2dc7d97 --- /dev/null +++ b/src/client.h @@ -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); diff --git a/src/db/idb.c b/src/db/idb.c index d958421..26d4e9d 100644 --- a/src/db/idb.c +++ b/src/db/idb.c @@ -34,14 +34,6 @@ typedef struct IncrementalDB { } IncrementalDB; 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){ @@ -169,7 +161,7 @@ Result(IncrementalDB*) idb_open(str db_dir){ db->db_dir = str_copy(db_dir); try_void(dir_create(db->db_dir.data)); 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; 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){ Deferral(64); // db lock - try_pthread(pthread_mutex_lock(&db->mutex)); + try_stderrcode(pthread_mutex_lock(&db->mutex)); Defer(pthread_mutex_unlock(&db->mutex)); 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 memset(t, 0, sizeof(Table)); 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->table_file_path = str_from_cstr( 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){ Deferral(16); // table lock - try_pthread(pthread_mutex_lock(&t->mutex)); + try_stderrcode(pthread_mutex_lock(&t->mutex)); Defer(pthread_mutex_unlock(&t->mutex)); 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){ Deferral(16); // table lock - try_pthread(pthread_mutex_lock(&t->mutex)); + try_stderrcode(pthread_mutex_lock(&t->mutex)); Defer(pthread_mutex_unlock(&t->mutex)); 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){ Deferral(16); // table lock - try_pthread(pthread_mutex_lock(&t->mutex)); + try_stderrcode(pthread_mutex_lock(&t->mutex)); Defer(pthread_mutex_unlock(&t->mutex)); 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){ Deferral(8); // table lock - try_pthread(pthread_mutex_lock(&t->mutex)); + try_stderrcode(pthread_mutex_lock(&t->mutex)); Defer(pthread_mutex_unlock(&t->mutex)); u64 count = t->row_count; Return RESULT_VALUE(u, count); diff --git a/src/db/idb.h b/src/db/idb.h index 62045b0..3cefa7b 100644 --- a/src/db/idb.h +++ b/src/db/idb.h @@ -1,7 +1,8 @@ #pragma once #include "tlibc/errors.h" -#include "tlibc/string/str.h" + +#define IDB_VERSION 1 typedef struct IncrementalDB IncrementalDB; typedef struct Table Table; diff --git a/src/main.c b/src/main.c index 16e16ad..afe535f 100755 --- a/src/main.c +++ b/src/main.c @@ -1,197 +1,66 @@ -#include "cryptography/cryptography.h" #include "network/network.h" -#include "network/socket.h" -#include "tlibc/time.h" -#include "db/idb.h" -#include -#include +#include "client.h" +#include "server.h" -Result(void) test_aes(){ - Deferral(64); - const str password = STR("abobus"); - const Array(const char) data = str_castTo_Array(STR("0123456789_hii_")); - - 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); +typedef enum ProgramMode { + Client, + Server, +} ProgramMode; - EncryptorAES encr; - 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); +#define arg_is(LITERAL) str_equals(arg_str, STR(LITERAL)) - DecryptorAES decr; - 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(){ +int main(const int argc, cstr const* argv){ 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()); Defer(network_deinit()); - // try_fatal_void(test_aes()); - // try_fatal_void(test_network()); - try_fatal_void(test_db()); + + switch(mode){ + 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; } diff --git a/src/network/endpoint.c b/src/network/endpoint.c index 598d615..4ba20de 100755 --- a/src/network/endpoint.c +++ b/src/network/endpoint.c @@ -19,11 +19,19 @@ EndpointIPv4 EndpointIPv4_fromSockaddr(struct sockaddr_in saddr){ } //TODO Endpoint functions -AddressIPv4 AddressIPv4_fromStr(cstr); +AddressIPv4 AddressIPv4_fromStr(cstr s); 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); diff --git a/src/network/endpoint.h b/src/network/endpoint.h index 4bcd427..1e26d30 100755 --- a/src/network/endpoint.h +++ b/src/network/endpoint.h @@ -16,9 +16,9 @@ typedef union AddressIPv4 { #define AddressIPv4_INVALID AddressIPv4_fromBytes(255,255,255,255) #define AddressIPv4_is_invalid(ADDR) (ADDR.UintBigEndian == (u32)~0) -#define AddressIPv4_fromBytes(A, B, C, D) ((AddressIPv4){.bytes={A,B,C,D}}) -#define AddressIPv4_fromU32(N) ((AddressIPv4){.UintBigEndian=N}) -AddressIPv4 AddressIPv4_fromStr(cstr); +#define AddressIPv4_fromBytes(A, B, C, D) ((AddressIPv4){ .bytes = {A,B,C,D} }) +#define AddressIPv4_fromU32(N) ((AddressIPv4){ .UintBigEndian = N }) +AddressIPv4 AddressIPv4_fromStr(cstr s); str AddressIPv4_toStr(AddressIPv4 address); diff --git a/src/network/internal.h b/src/network/internal.h index 607e3ce..89ecc18 100644 --- a/src/network/internal.h +++ b/src/network/internal.h @@ -1,4 +1,5 @@ #pragma once +#include "tlibc/errors.h" #if !defined(KN_USE_WINSOCK) #if defined(_WIN64) || defined(_WIN32) @@ -10,6 +11,9 @@ #if KN_USE_WINSOCK #include + // There you can see what error codes mean. + #include + #define RESULT_ERROR_SOCKET() RESULT_ERROR(sprintf_malloc(64, "Winsock error %i", WSAGetLastError()), true) #else #include #include @@ -17,4 +21,6 @@ #include #include #include + + #define RESULT_ERROR_SOCKET() RESULT_ERROR(strerror(errno), false) #endif diff --git a/src/network/socket.c b/src/network/socket.c index 605bf4d..fbbd663 100755 --- a/src/network/socket.c +++ b/src/network/socket.c @@ -5,7 +5,7 @@ Result(Socket) socket_open_TCP(){ Socket s = socket(AF_INET, SOCK_STREAM, 0); if(s == -1){ - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); } return RESULT_VALUE(i, s); @@ -21,20 +21,20 @@ void socket_close(Socket s){ Result(void) socket_shutdown(Socket s, SocketShutdownType direction){ if(shutdown(s, (int)direction) == -1) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); return RESULT_VOID; } Result(void) socket_bind(Socket s, EndpointIPv4 local_end){ struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(local_end); if(bind(s, (void*)&sockaddr, sizeof(sockaddr)) != 0) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); return RESULT_VOID; } Result(void) socket_listen(Socket s, i32 backlog){ if(listen(s, backlog) != 0) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); return RESULT_VOID; } @@ -43,7 +43,7 @@ Result(Socket) socket_accept(Socket main_socket, NULLABLE(EndpointIPv4*) remote_ i32 sockaddr_size = sizeof(remote_addr); Socket user_connection = accept(main_socket, (void*)&remote_addr, (void*)&sockaddr_size); if(user_connection == -1) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); //TODO: add IPV6 support (struct sockaddr_in6) 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){ struct sockaddr_in sockaddr = EndpointIPv4_toSockaddr(remote_end); if(connect(s, (void*)&sockaddr, sizeof(sockaddr)) != 0) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); return RESULT_VOID; } Result(void) socket_send(Socket s, Array(u8) buffer){ i32 r = send(s, buffer.data, buffer.size, 0); if(r < 0) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); 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); i32 r = sendto(s, buffer.data, buffer.size, 0, (void*)&sockaddr, sizeof(sockaddr)); if(r < 0) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); return RESULT_VOID; } Result(i32) socket_recv(Socket s, Array(u8) buffer){ i32 r = recv(s, buffer.data, buffer.size, 0); if(r < 0) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); return RESULT_VALUE(i, r); } - Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, NULLABLE(EndpointIPv4*) remote_end){ struct sockaddr_in remote_addr = {0}; i32 sockaddr_size = sizeof(remote_addr); i32 r = recvfrom(s, buffer.data, buffer.size, 0, (struct sockaddr*)&remote_addr, (void*)&sockaddr_size); if(r < 0) - return RESULT_ERROR_ERRNO(); + return RESULT_ERROR_SOCKET(); //TODO: add IPV6 support (struct sockaddr_in6) assert(sockaddr_size == sizeof(remote_addr)); @@ -96,4 +95,4 @@ Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, NULLABLE(EndpointIPv4*) if(remote_end) *remote_end = EndpointIPv4_fromSockaddr(remote_addr); return RESULT_VALUE(i, r); -} \ No newline at end of file +} diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..bfa7423 --- /dev/null +++ b/src/server.c @@ -0,0 +1,37 @@ +#include "server.h" +#include "network/socket.h" +#include "db/idb.h" +#include + +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; +} diff --git a/src/server.h b/src/server.h new file mode 100644 index 0000000..05deac6 --- /dev/null +++ b/src/server.h @@ -0,0 +1,4 @@ +#pragma once +#include "tlibc/errors.h" + +Result(void) server_run(cstr server_endpoint_str); diff --git a/src/term.c b/src/term.c new file mode 100644 index 0000000..9da8345 --- /dev/null +++ b/src/term.c @@ -0,0 +1,95 @@ +#include "term.h" +#include +#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"); +} diff --git a/src/term.h b/src/term.h new file mode 100644 index 0000000..3b7b971 --- /dev/null +++ b/src/term.h @@ -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();