Compare commits
3 Commits
eb1daa721a
...
a19c5f7023
| Author | SHA1 | Date | |
|---|---|---|---|
| a19c5f7023 | |||
| eb8bad55ee | |||
| f1a8a186e0 |
2
dependencies/tlibc
vendored
2
dependencies/tlibc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 0e80a568922ae579213d5a99329fa32420f0bcb0
|
Subproject commit fe9e44a660e23c28255ba27522d15ab94044f55b
|
||||||
@ -6,8 +6,8 @@ CMP_C="gcc"
|
|||||||
CMP_CPP="g++"
|
CMP_CPP="g++"
|
||||||
STD_C="c99"
|
STD_C="c99"
|
||||||
STD_CPP="c++11"
|
STD_CPP="c++11"
|
||||||
WARN_C="-Wall -Wextra -Wno-unused-parameter"
|
WARN_C="-Wall -Wextra -Werror=return-type -Werror=pointer-arith -Wno-unused-parameter"
|
||||||
WARN_CPP="-Wall -Wextra -Wno-unused-parameter"
|
WARN_CPP="-Wall -Wextra -Werror=return-type -Werror=pointer-arith -Wno-unused-parameter"
|
||||||
SRC_C="$(find src -name '*.c')"
|
SRC_C="$(find src -name '*.c')"
|
||||||
#SRC_CPP="$(find src -name '*.cpp')"
|
#SRC_CPP="$(find src -name '*.cpp')"
|
||||||
|
|
||||||
|
|||||||
@ -28,17 +28,17 @@ void EncryptorAES_encrypt(EncryptorAES* ptr, Array(u8) src, Array(u8) dst){
|
|||||||
br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, header_size);
|
br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, header_size);
|
||||||
// write encrypted header to dst
|
// write encrypted header to dst
|
||||||
memcpy(dst.data, ptr->buf, header_size);
|
memcpy(dst.data, ptr->buf, header_size);
|
||||||
dst.data += header_size;
|
dst.data = (u8*)dst.data + header_size;
|
||||||
dst.size -= header_size;
|
dst.size -= header_size;
|
||||||
|
|
||||||
// write full blocks
|
// write full blocks
|
||||||
while(src.size > __AES_BUFFER_SIZE){
|
while(src.size > __AES_BUFFER_SIZE){
|
||||||
memcpy(ptr->buf, src.data, __AES_BUFFER_SIZE);
|
memcpy(ptr->buf, src.data, __AES_BUFFER_SIZE);
|
||||||
src.data += __AES_BUFFER_SIZE;
|
src.data = (u8*)src.data + __AES_BUFFER_SIZE;
|
||||||
src.size -= __AES_BUFFER_SIZE;
|
src.size -= __AES_BUFFER_SIZE;
|
||||||
br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE);
|
br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE);
|
||||||
memcpy(dst.data, ptr->buf, __AES_BUFFER_SIZE);
|
memcpy(dst.data, ptr->buf, __AES_BUFFER_SIZE);
|
||||||
dst.data += __AES_BUFFER_SIZE;
|
dst.data = (u8*)dst.data + __AES_BUFFER_SIZE;
|
||||||
dst.size -= __AES_BUFFER_SIZE;
|
dst.size -= __AES_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ void DecryptorAES_decrypt(DecryptorAES* ptr, Array(u8) src, Array(u8) dst, u32*
|
|||||||
// copy encrypted header from src to buffer
|
// copy encrypted header from src to buffer
|
||||||
const u32 header_size = __AES_RANDOM_BYTES_N + sizeof(EncryptedBlockInfo);
|
const u32 header_size = __AES_RANDOM_BYTES_N + sizeof(EncryptedBlockInfo);
|
||||||
memcpy(ptr->buf, src.data, header_size);
|
memcpy(ptr->buf, src.data, header_size);
|
||||||
src.data += header_size;
|
src.data = (u8*)src.data + header_size;
|
||||||
src.size -= header_size;
|
src.size -= header_size;
|
||||||
// decrypt buffer
|
// decrypt buffer
|
||||||
br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, &ptr->buf, header_size);
|
br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, &ptr->buf, header_size);
|
||||||
@ -78,11 +78,11 @@ void DecryptorAES_decrypt(DecryptorAES* ptr, Array(u8) src, Array(u8) dst, u32*
|
|||||||
// write full blocks
|
// write full blocks
|
||||||
while(src.size > __AES_BUFFER_SIZE){
|
while(src.size > __AES_BUFFER_SIZE){
|
||||||
memcpy(ptr->buf, src.data, __AES_BUFFER_SIZE);
|
memcpy(ptr->buf, src.data, __AES_BUFFER_SIZE);
|
||||||
src.data += __AES_BUFFER_SIZE;
|
src.data = (u8*)src.data + __AES_BUFFER_SIZE;
|
||||||
src.size -= __AES_BUFFER_SIZE;
|
src.size -= __AES_BUFFER_SIZE;
|
||||||
br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE);
|
br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE);
|
||||||
memcpy(dst.data, ptr->buf, __AES_BUFFER_SIZE);
|
memcpy(dst.data, ptr->buf, __AES_BUFFER_SIZE);
|
||||||
dst.data += __AES_BUFFER_SIZE;
|
dst.data = (u8*)dst.data + __AES_BUFFER_SIZE;
|
||||||
dst.size -= __AES_BUFFER_SIZE;
|
dst.size -= __AES_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
252
src/db/idb.c
Normal file
252
src/db/idb.c
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
#include "idb.h"
|
||||||
|
#include "tlibc/filesystem.h"
|
||||||
|
|
||||||
|
static const Magic32 TABLE_FILE_MAGIC = { .bytes = { 'I', 'D', 'B', 't' } };
|
||||||
|
#define IDB_VERSION 0x01
|
||||||
|
|
||||||
|
Result(void) Table_setDirtyBit(Table* t, bool val);
|
||||||
|
Result(bool) Table_getDirtyBit(Table* t);
|
||||||
|
|
||||||
|
void Table_close(Table* t){
|
||||||
|
fclose(t->table_file);
|
||||||
|
fclose(t->changes_file);
|
||||||
|
free(t->name.data);
|
||||||
|
free(t->table_file_path.data);
|
||||||
|
free(t->changes_file_path.data);
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TablePtr_destroy(void* t_ptr_ptr){
|
||||||
|
Table_close(*(Table**)t_ptr_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @param name must be null-terminated
|
||||||
|
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];
|
||||||
|
if(str_seekChar(name, c, 0) != -1){
|
||||||
|
return RESULT_ERROR_FMT(
|
||||||
|
"Table name '%s' contains forbidden character '%c'",
|
||||||
|
name.data, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Table_readHeader(Table* t){
|
||||||
|
// seek for start of the file
|
||||||
|
try_void(file_seek(t->table_file, 0, SeekOrigin_Start), )
|
||||||
|
// read header
|
||||||
|
try_void(file_readStructsExactly(t->table_file, &t->header, sizeof(t->header), 1), );
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Table_writeHeader(Table* t){
|
||||||
|
// seek for start of the file
|
||||||
|
try_void(file_seek(t->table_file, 0, SeekOrigin_Start), )
|
||||||
|
// write header
|
||||||
|
try_void(file_writeStructs(t->table_file, &t->header, sizeof(t->header), 1), );
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Table_setDirtyBit(Table* t, bool val){
|
||||||
|
t->header._dirty_bit = val;
|
||||||
|
try_void(Table_writeHeader(t), );
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(bool) Table_getDirtyBit(Table* t){
|
||||||
|
try_void(Table_readHeader(t), );
|
||||||
|
return RESULT_VALUE(i, t->header._dirty_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Table_calculateRowCount(Table* t){
|
||||||
|
try(file_size, file_getSize(t->table_file), );
|
||||||
|
i64 data_size = file_size.i - sizeof(t->header);
|
||||||
|
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",
|
||||||
|
t->name.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
t->row_count = data_size / t->header.row_size;
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Table_validateHeader(Table* t){
|
||||||
|
if(t->header.magic.n != TABLE_FILE_MAGIC.n
|
||||||
|
|| t->header.row_size == 0)
|
||||||
|
{
|
||||||
|
return RESULT_ERROR_FMT(
|
||||||
|
"Table file '%s' has invalid header",
|
||||||
|
t->table_file_path.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: check version
|
||||||
|
|
||||||
|
try(dirty_bit, Table_getDirtyBit(t), );
|
||||||
|
if(dirty_bit.i){
|
||||||
|
//TODO: handle dirty bit instead of throwing error
|
||||||
|
return RESULT_ERROR_FMT(
|
||||||
|
"Table file '%s' has dirty bit set",
|
||||||
|
t->table_file_path.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) Table_validateRowSize(Table* t, u32 row_size){
|
||||||
|
if(row_size != t->header.row_size){
|
||||||
|
Result(void) error_result = RESULT_ERROR_FMT(
|
||||||
|
"Requested row size (%u) doesn't match saved row size (%u)",
|
||||||
|
row_size, t->header.row_size);
|
||||||
|
return error_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(IncrementalDB*) idb_open(str db_dir){
|
||||||
|
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));
|
||||||
|
db->db_dir = str_copy(db_dir);
|
||||||
|
try_void(dir_create(db->db_dir.data),
|
||||||
|
idb_close(db));
|
||||||
|
HashMap_construct(&db->tables_map, Table*, TablePtr_destroy);
|
||||||
|
return RESULT_VALUE(p, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
void idb_close(IncrementalDB* db){
|
||||||
|
free(db->db_dir.data);
|
||||||
|
HashMap_destroy(&db->tables_map);
|
||||||
|
free(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(Table*) idb_getOrCreateTable(IncrementalDB* db, str _table_name, u32 row_size){
|
||||||
|
// TODO: implement whole db lock
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
str table_name_null_terminated = str_copy(_table_name);
|
||||||
|
try_void(validateTableName(table_name_null_terminated),
|
||||||
|
free(table_name_null_terminated.data));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
t->db = db;
|
||||||
|
t->name = table_name_null_terminated;
|
||||||
|
t->table_file_path = str_from_cstr(
|
||||||
|
strcat_malloc(db->db_dir.data, path_seps, t->name.data, ".table.idb"));
|
||||||
|
t->changes_file_path = str_from_cstr(
|
||||||
|
strcat_malloc(db->db_dir.data, path_seps, t->name.data, ".changes.idb"));
|
||||||
|
|
||||||
|
bool table_exists = file_exists(t->table_file_path.data);
|
||||||
|
|
||||||
|
// open or create file with table data
|
||||||
|
try(_table_file, file_openOrCreateReadWrite(t->table_file_path.data),
|
||||||
|
Table_close(t));
|
||||||
|
t->table_file = _table_file.p;
|
||||||
|
|
||||||
|
// open or create file with backups of updated rows
|
||||||
|
try(_changes_file, file_openOrCreateReadWrite(t->changes_file_path.data),
|
||||||
|
Table_close(t));
|
||||||
|
t->changes_file = _changes_file.p;
|
||||||
|
|
||||||
|
if(table_exists){
|
||||||
|
try_void(Table_readHeader(t),
|
||||||
|
Table_close(t));
|
||||||
|
try_void(Table_validateHeader(t),
|
||||||
|
Table_close(t));
|
||||||
|
try_void(Table_validateRowSize(t, row_size),
|
||||||
|
Table_close(t));
|
||||||
|
try_void(Table_calculateRowCount(t),
|
||||||
|
Table_close(t));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t->header.magic.n = TABLE_FILE_MAGIC.n;
|
||||||
|
t->header.row_size = row_size;
|
||||||
|
t->header.version = IDB_VERSION;
|
||||||
|
try_void(Table_writeHeader(t),
|
||||||
|
Table_close(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!HashMap_tryPush(&db->tables_map, t->name, &t)){
|
||||||
|
Result(void) error_result = RESULT_ERROR_FMT(
|
||||||
|
"Table '%s' is already open",
|
||||||
|
t->name.data);
|
||||||
|
Table_close(t);
|
||||||
|
return error_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_VALUE(p, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) idb_getRows(Table* t, u64 id, void* dst, u64 count){
|
||||||
|
// TODO: implement table lock
|
||||||
|
if(id + count > t->row_count){
|
||||||
|
return RESULT_ERROR_FMT(
|
||||||
|
"Can't read " IFWIN("%llu", "%lu") " rows at index " IFWIN("%llu", "%lu")
|
||||||
|
" because table '%s' has only " IFWIN("%llu", "%lu") " rows",
|
||||||
|
count, id, t->name.data, t->row_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
try_void(file_readStructsExactly(t->table_file, dst, t->header.row_size, count), );
|
||||||
|
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count){
|
||||||
|
if(id + count >= t->row_count){
|
||||||
|
return RESULT_ERROR_FMT(
|
||||||
|
"Can't update " IFWIN("%llu", "%lu") " rows at index " IFWIN("%llu", "%lu")
|
||||||
|
" because table '%s' has only " IFWIN("%llu", "%lu") " rows",
|
||||||
|
count, id, t->name.data, t->row_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
try_void(Table_setDirtyBit(t, true), );
|
||||||
|
|
||||||
|
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
|
||||||
|
try_void(file_writeStructs(t->table_file, src, t->header.row_size, count), );
|
||||||
|
|
||||||
|
try_void(Table_setDirtyBit(t, false), );
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result(u64) idb_pushRows(Table* t, const void* src, u64 count){
|
||||||
|
try_void(Table_setDirtyBit(t, true), );
|
||||||
|
|
||||||
|
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
|
||||||
|
try_void(file_writeStructs(t->table_file, src, t->header.row_size, count), );
|
||||||
|
|
||||||
|
t->row_count += count;
|
||||||
|
|
||||||
|
try_void(Table_setDirtyBit(t, false), );
|
||||||
|
return RESULT_VALUE(u, new_row_index);
|
||||||
|
}
|
||||||
50
src/db/idb.h
Normal file
50
src/db/idb.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tlibc/errors.h"
|
||||||
|
#include "tlibc/string/str.h"
|
||||||
|
#include "tlibc/collections/Array.h"
|
||||||
|
#include "tlibc/collections/HashMap.h"
|
||||||
|
|
||||||
|
typedef struct IncrementalDB IncrementalDB;
|
||||||
|
|
||||||
|
typedef union Magic32 {
|
||||||
|
u32 n;
|
||||||
|
u8 bytes[4];
|
||||||
|
} Magic32;
|
||||||
|
|
||||||
|
typedef struct TableHeader {
|
||||||
|
Magic32 magic;
|
||||||
|
u16 version;
|
||||||
|
bool _dirty_bit;
|
||||||
|
u32 row_size;
|
||||||
|
} __attribute__((aligned(256))) TableHeader;
|
||||||
|
|
||||||
|
typedef struct Table {
|
||||||
|
TableHeader header;
|
||||||
|
IncrementalDB* db;
|
||||||
|
str name;
|
||||||
|
str table_file_path;
|
||||||
|
str changes_file_path;
|
||||||
|
FILE* table_file;
|
||||||
|
FILE* changes_file;
|
||||||
|
u64 row_count;
|
||||||
|
} Table;
|
||||||
|
|
||||||
|
typedef struct IncrementalDB {
|
||||||
|
str db_dir;
|
||||||
|
HashMap(Table**) tables_map;
|
||||||
|
} IncrementalDB;
|
||||||
|
|
||||||
|
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(void) idb_getRows(Table* t, u64 id, void* dst, u64 count);
|
||||||
|
#define idb_getRow(T, ID, DST) idb_getRows(T, ID, DST, 1)
|
||||||
|
|
||||||
|
Result(u64) idb_pushRows(Table* t, const void* src, u64 count);
|
||||||
|
#define idb_pushRow(T, SRC) idb_pushRows(T, SRC, 1)
|
||||||
|
|
||||||
|
Result(void) idb_updateRows(Table* t, u64 id, const void* src, u64 count);
|
||||||
|
#define idb_updateRow(T, ID, SRC) idb_updateRows(T, ID, SRC, 1)
|
||||||
35
src/main.c
35
src/main.c
@ -2,8 +2,8 @@
|
|||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "network/socket.h"
|
#include "network/socket.h"
|
||||||
#include "tlibc/time.h"
|
#include "tlibc/time.h"
|
||||||
|
#include "db/idb.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
Result(void) test_aes(){
|
Result(void) test_aes(){
|
||||||
@ -155,10 +155,41 @@ Result(void) test_network(){
|
|||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result(void) test_db(){
|
||||||
|
try(_db, idb_open(STR("idb")), );
|
||||||
|
IncrementalDB* db = _db.p;
|
||||||
|
|
||||||
|
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(_t0, idb_getOrCreateTable(db, STR("test0"), row_size), idb_close(db));
|
||||||
|
Table* t0 = _t0.p;
|
||||||
|
printf("table '%s' created\n", t0->name.data);
|
||||||
|
printf("\t%s\n", t0->table_file_path.data);
|
||||||
|
printf("\t%s\n", t0->changes_file_path.data);
|
||||||
|
|
||||||
|
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), idb_close(db));
|
||||||
|
printf("row %u: %s\n", indices[i], buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
idb_close(db);
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
try_fatal(_10, network_init(), );
|
try_fatal(_10, network_init(), );
|
||||||
try_fatal(_20, test_aes(), );
|
// try_fatal(_20, test_aes(), );
|
||||||
// try_fatal(_30, test_network(), );
|
// try_fatal(_30, test_network(), );
|
||||||
|
try_fatal(_40, test_db(), );
|
||||||
try_fatal(_100, network_deinit(), );
|
try_fatal(_100, network_deinit(), );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#include "std_includes.h"
|
#include "internal.h"
|
||||||
#include "endpoint.h"
|
#include "endpoint.h"
|
||||||
|
|
||||||
struct sockaddr_in EndpointIPv4_toSockaddr(EndpointIPv4 end){
|
struct sockaddr_in EndpointIPv4_toSockaddr(EndpointIPv4 end){
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
#if !defined(KN_USE_WINSOCK)
|
||||||
#define KN_USE_WINSOCK 1
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
#else
|
#define KN_USE_WINSOCK 1
|
||||||
#define KN_USE_WINSOCK 0
|
#else
|
||||||
|
#define KN_USE_WINSOCK 0
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if KN_USE_WINSOCK
|
#if KN_USE_WINSOCK
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "std_includes.h"
|
#include "internal.h"
|
||||||
|
|
||||||
Result(void) network_init(){
|
Result(void) network_init(){
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
@ -7,7 +7,7 @@ Result(void) network_init(){
|
|||||||
WSADATA wsaData = {0};
|
WSADATA wsaData = {0};
|
||||||
int result = WSAStartup(MAKEWORD(2,2), &wsaData);
|
int result = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return RESULT_ERROR(sprintf_malloc(64, "WSAStartup failed with error code 0x%X", result), true);
|
return RESULT_ERROR_FMT("WSAStartup failed with error code 0x%X", result);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
@ -18,7 +18,7 @@ Result(void) network_deinit(){
|
|||||||
// Deinitialize Winsock
|
// Deinitialize Winsock
|
||||||
int result = WSACleanup();
|
int result = WSACleanup();
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return RESULT_ERROR(sprintf_malloc(64, "WSACleanup failed with error code 0x%X", result), true);
|
return RESULT_ERROR_FMT("WSACleanup failed with error code 0x%X", result);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
#include "std_includes.h"
|
#include "internal.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "errno.h"
|
#include <assert.h>
|
||||||
#include "assert.h"
|
|
||||||
|
|
||||||
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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_VALUE(i, s);
|
return RESULT_VALUE(i, s);
|
||||||
@ -22,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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
|
|
||||||
//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));
|
||||||
@ -56,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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
return RESULT_VOID;
|
return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,14 +70,14 @@ 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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
return RESULT_VALUE(i, r);
|
return RESULT_VALUE(i, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +88,7 @@ Result(i32) socket_recvfrom(Socket s, Array(u8) buffer, NULLABLE(EndpointIPv4*)
|
|||||||
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(strerror(errno), false);
|
return RESULT_ERROR_ERRNO();
|
||||||
|
|
||||||
//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));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user