implemented client interactive mode
This commit is contained in:
parent
c008d759ae
commit
f01c5fc8a9
2
dependencies/tlibc
vendored
2
dependencies/tlibc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit bf56984482d83d1a178f4da6483fbd350457e438
|
Subproject commit c415e2ca8ff51f41984ace8fe796187e6ad0fa27
|
||||||
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
|
|
||||||
|
Result(void) client_run();
|
||||||
Result(void) server_run(cstr server_endpoint_str);
|
Result(void) server_run(cstr server_endpoint_str);
|
||||||
234
src/client.c
234
src/client.c
@ -1,9 +1,10 @@
|
|||||||
#include "client.h"
|
#include "chat.h"
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
#include "term.h"
|
#include "term.h"
|
||||||
|
#include "network/socket.h"
|
||||||
#define inp_eq(LITERAL) str_equals(input, STR(LITERAL))
|
#include "cryptography/cryptography.h"
|
||||||
|
#include "tlibc/string/StringBuilder.h"
|
||||||
|
|
||||||
static const str greeting_art = STR(
|
static const str greeting_art = STR(
|
||||||
" ^,,^ ╱|\n"
|
" ^,,^ ╱|\n"
|
||||||
@ -19,8 +20,30 @@ static const str farewell_art = STR(
|
|||||||
"\\(_,J J L l`,)/\n"
|
"\\(_,J J L l`,)/\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static Result(void) commandExec(str command, bool* stop);
|
||||||
|
|
||||||
|
typedef struct ClientCredential {
|
||||||
|
str username;
|
||||||
|
u8 passhash_lvl2[password_hash_size];
|
||||||
|
EncryptorAES aes_enc;
|
||||||
|
DecryptorAES aes_dec;
|
||||||
|
EncryptorRSA rsa_enc;
|
||||||
|
DecryptorRSA rsa_dec;
|
||||||
|
} ClientCredential;
|
||||||
|
|
||||||
|
typedef struct ServerConnection {
|
||||||
|
EndpointIPv4 server_end;
|
||||||
|
Socket system_socket;
|
||||||
|
Socket content_socket;
|
||||||
|
EncryptorRSA rsa_enc;
|
||||||
|
EncryptorAES session_aes_enc;
|
||||||
|
DecryptorAES session_aes_dec;
|
||||||
|
} ServerConnection;
|
||||||
|
|
||||||
|
Result(ServerConnection*) connectToServer(EndpointIPv4 server_end, str server_key);
|
||||||
|
|
||||||
Result(void) client_run() {
|
Result(void) client_run() {
|
||||||
Deferral(128);
|
Deferral(32);
|
||||||
if(!term_init()){
|
if(!term_init()){
|
||||||
Return RESULT_ERROR("can't init terminal", false);
|
Return RESULT_ERROR("can't init terminal", false);
|
||||||
}
|
}
|
||||||
@ -28,74 +51,159 @@ Result(void) client_run() {
|
|||||||
|
|
||||||
fputs(greeting_art.data, stdout);
|
fputs(greeting_art.data, stdout);
|
||||||
|
|
||||||
char* input_prev = NULL;
|
char* command_input_prev = NULL;
|
||||||
char* input_raw = NULL;
|
char* command_input_raw = NULL;
|
||||||
Defer(rl_free(input_prev));
|
Defer(rl_free(command_input_prev));
|
||||||
str input = str_null;
|
str command_input = str_null;
|
||||||
while((input_raw = readline("> "))){
|
bool stop = false;
|
||||||
rl_free(input_prev);
|
while((command_input_raw = readline("> ")) && !stop){
|
||||||
input_prev = input_raw;
|
rl_free(command_input_prev);
|
||||||
input = str_from_cstr(input_raw);
|
command_input_prev = command_input_raw;
|
||||||
line_trim(&input, true);
|
command_input = str_from_cstr(command_input_raw);
|
||||||
add_history(input.data);
|
str_trim(&command_input, true);
|
||||||
if(input.size == 0){
|
if(command_input.size == 0)
|
||||||
continue;
|
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")){
|
|
||||||
|
|
||||||
}
|
add_history(command_input.data);
|
||||||
else if(inp_eq("c") || inp_eq("connect")){
|
Result(void) com_result = commandExec(command_input, &stop);
|
||||||
|
if(com_result.error){
|
||||||
}
|
str e_str = Error_toStr(com_result.error);
|
||||||
else {
|
printfe("%s\n", e_str.data);
|
||||||
printf("ERROR: unknown kommand: '%s'\n"
|
free(e_str.data);
|
||||||
"Use 'h' to see list of avaliable commands\n",
|
Error_free(com_result.error);
|
||||||
input.data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Return RESULT_VOID;
|
Return RESULT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void line_trim(str* line, bool set_zero_at_end){
|
#define inp_eq(LITERAL) str_equals(command, STR(LITERAL))
|
||||||
bool stop = false;
|
|
||||||
// loop forward
|
static ClientCredential* client_credential = NULL;
|
||||||
while(line->size > 0 && !stop){
|
|
||||||
char first_char = line->data[line->size - 1];
|
static Result(void) commandExec(str command, bool* stop){
|
||||||
switch(first_char){
|
Deferral(64);
|
||||||
case '\0': case '\r': case '\n':
|
char answer_buf[512];
|
||||||
case '\t': case ' ':
|
const u32 answer_buf_size = sizeof(answer_buf);
|
||||||
line->data++;
|
if(is_alias("q") || is_alias("quit") || is_alias("exit")){
|
||||||
line->size--;
|
fputs(farewell_art.data, stdout);
|
||||||
break;
|
*stop = true;
|
||||||
default:
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// loop backward
|
else if(is_alias("clear")){
|
||||||
while(line->size > 0 && !stop)
|
term_clear();
|
||||||
{
|
|
||||||
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){
|
else if(is_alias("h") || is_alias("help")){
|
||||||
line->data[line->size] = '\0';
|
puts(
|
||||||
line->isZeroTerminated = true;
|
"COMMANDS:\n"
|
||||||
|
"q, quit, exit Close the program.\n"
|
||||||
|
"clear Clear the screen.\n"
|
||||||
|
"j, join Join a server.\n"
|
||||||
|
"c, connect Connect to a server you joined.\n"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
else if (is_alias("j") || is_alias("join")){
|
||||||
|
puts("Enter server address (ip:port): ");
|
||||||
|
fgets(answer_buf, answer_buf_size, stdin);
|
||||||
|
EndpointIPv4 new_server_end;
|
||||||
|
try_void(EndpointIPv4_parse(answer_buf, &new_server_end));
|
||||||
|
puts("Enter server key (): ");
|
||||||
|
fgets(answer_buf, answer_buf_size, stdin);
|
||||||
|
str new_server_key = str_from_cstr(answer_buf);
|
||||||
|
try(ServerConnection* conn, p, connectToServer(new_server_end, new_server_key));
|
||||||
|
}
|
||||||
|
else if(is_alias("c") || is_alias("connect")){
|
||||||
|
// TODO: read saved servers from database
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Return RESULT_ERROR_FMT("unknown kommand: '%s'\n"
|
||||||
|
"Use 'h' to see list of avaliable commands\n",
|
||||||
|
command.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientCredential_free(ClientCredential* cred){
|
||||||
|
if(cred == NULL)
|
||||||
|
return;
|
||||||
|
free(cred->username.data);
|
||||||
|
free(cred);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __passhash_lvl_iter 1e5
|
||||||
|
|
||||||
|
static Result(ClientCredential*) ClientCredential_create(str username, str password){
|
||||||
|
Deferral(32);
|
||||||
|
ClientCredential* cred = (ClientCredential*)malloc(sizeof(ClientCredential));
|
||||||
|
memset(cred, 0, sizeof(ClientCredential));
|
||||||
|
bool success = false;
|
||||||
|
Defer(
|
||||||
|
if(!success)
|
||||||
|
ClientCredential_free(cred);
|
||||||
|
);
|
||||||
|
|
||||||
|
cred->username = str_copy(username);
|
||||||
|
|
||||||
|
// concat password and username
|
||||||
|
StringBuilder sb = StringBuilder_alloc(username.size + password.size + 1);
|
||||||
|
Defer(StringBuilder_destroy(&sb));
|
||||||
|
StringBuilder_append_str(&sb, password);
|
||||||
|
StringBuilder_append_str(&sb, username);
|
||||||
|
|
||||||
|
// lvl 1 hash - is being used to generate rsa keys
|
||||||
|
u8 passhash_lvl1[password_hash_size];
|
||||||
|
hash_password(StringBuilder_getStr(&sb), passhash_lvl1, __passhash_lvl_iter);
|
||||||
|
// lvl 2 hash - is being used to authorize client on server
|
||||||
|
str _passhash_lvl1_str = str_construct(passhash_lvl1, password_hash_size, false);
|
||||||
|
hash_password(_passhash_lvl1_str, cred->passhash_lvl2, __passhash_lvl_iter);
|
||||||
|
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
return RESULT_VALUE(p, cred);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ServerConnection_close(ServerConnection* conn){
|
||||||
|
if(conn == NULL)
|
||||||
|
return;
|
||||||
|
socket_close(conn->system_socket);
|
||||||
|
socket_close(conn->content_socket);
|
||||||
|
free(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result(ServerConnection*) connectToServer(EndpointIPv4 server_end, str server_key){
|
||||||
|
Deferral(64);
|
||||||
|
if(client_credential == NULL){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
str end_str = EndpointIPv4_toStr(server_end);
|
||||||
|
Defer(free(end_str.data));
|
||||||
|
if(EndpointIPv4_is_invalid(server_end)){
|
||||||
|
Return RESULT_ERROR_FMT("endpoint is invalid: %s", end_str.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerConnection* conn = (ServerConnection*)malloc(sizeof(ServerConnection));
|
||||||
|
memset(conn, 0, sizeof(ServerConnection));
|
||||||
|
bool success = false;
|
||||||
|
Defer(
|
||||||
|
if(!success)
|
||||||
|
ServerConnection_close(conn);
|
||||||
|
);
|
||||||
|
|
||||||
|
printf("connecting to server %s\n", end_str.data);
|
||||||
|
try(conn->system_socket, i, socket_open_TCP());
|
||||||
|
try_void(socket_connect(conn->system_socket, server_end));
|
||||||
|
|
||||||
|
// ask user name and password
|
||||||
|
// calculate key pair from password hash
|
||||||
|
// send client public key to server
|
||||||
|
// request server info
|
||||||
|
// show server info
|
||||||
|
// save server info to user's db
|
||||||
|
// hash password more times
|
||||||
|
// request log in
|
||||||
|
// if not registered, request registration and then log in
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
Return RESULT_VALUE(p, conn);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
#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);
|
|
||||||
@ -4,13 +4,14 @@
|
|||||||
#include "tlibc/string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
#include "bearssl_block.h"
|
#include "bearssl_block.h"
|
||||||
#include "bearssl_rand.h"
|
#include "bearssl_rand.h"
|
||||||
|
#include "bearssl_rsa.h"
|
||||||
|
|
||||||
/// @brief hashes password multiple times using its own hash as salt
|
/// @brief hashes password multiple times using its own hash as salt
|
||||||
/// @param password some byte array
|
/// @param password some byte array
|
||||||
/// @param out_buffer u8[hash_password_out_size]
|
/// @param out_buffer u8[password_hash_size]
|
||||||
/// @param iterations number of iterations
|
/// @param iterations number of iterations
|
||||||
void hash_password(str password, u8* out_buffer, i32 iterations);
|
void hash_password(str password, u8* out_buffer, i32 iterations);
|
||||||
#define hash_password_out_size 32
|
#define password_hash_size 32
|
||||||
|
|
||||||
|
|
||||||
typedef struct EncryptedBlockInfo {
|
typedef struct EncryptedBlockInfo {
|
||||||
@ -59,7 +60,11 @@ void DecryptorAES_decrypt(DecryptorAES* ptr, Array(u8) src, Array(u8) dst, u32*
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct EncryptorRSA EncryptorRSA;
|
typedef struct EncryptorRSA {
|
||||||
|
br_rsa_public_key public_key;
|
||||||
|
} EncryptorRSA;
|
||||||
|
|
||||||
|
|
||||||
typedef struct DecryptorRSA DecryptorRSA;
|
typedef struct DecryptorRSA {
|
||||||
|
br_rsa_private_key private_key;
|
||||||
|
} DecryptorRSA;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
|
||||||
void hash_password(str password, u8* out_buffer, i32 iterations){
|
void hash_password(str password, u8* out_buffer, i32 iterations){
|
||||||
assert(hash_password_out_size == br_sha256_SIZE);;
|
assert(password_hash_size == br_sha256_SIZE);;
|
||||||
memset(out_buffer, 0, br_sha256_SIZE);
|
memset(out_buffer, 0, br_sha256_SIZE);
|
||||||
br_sha256_context sha256_ctx;
|
br_sha256_context sha256_ctx;
|
||||||
br_sha256_init(&sha256_ctx);
|
br_sha256_init(&sha256_ctx);
|
||||||
@ -11,7 +11,7 @@ void hash_password(str password, u8* out_buffer, i32 iterations){
|
|||||||
for(i32 i = 0; i < iterations; i++){
|
for(i32 i = 0; i < iterations; i++){
|
||||||
br_sha256_update(&sha256_ctx, password.data, password.size);
|
br_sha256_update(&sha256_ctx, password.data, password.size);
|
||||||
br_sha256_out(&sha256_ctx, out_buffer);
|
br_sha256_out(&sha256_ctx, out_buffer);
|
||||||
br_sha256_update(&sha256_ctx, out_buffer, hash_password_out_size);
|
br_sha256_update(&sha256_ctx, out_buffer, password_hash_size);
|
||||||
}
|
}
|
||||||
br_sha256_out(&sha256_ctx, out_buffer);
|
br_sha256_out(&sha256_ctx, out_buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "client.h"
|
#include "chat.h"
|
||||||
#include "server.h"
|
|
||||||
|
|
||||||
typedef enum ProgramMode {
|
typedef enum ProgramMode {
|
||||||
Client,
|
Client,
|
||||||
@ -20,9 +19,9 @@ int main(const int argc, cstr const* argv){
|
|||||||
if(arg_is("-h") || arg_is("--help")){
|
if(arg_is("-h") || arg_is("--help")){
|
||||||
printf(
|
printf(
|
||||||
"USAGE:\n"
|
"USAGE:\n"
|
||||||
"no arguments Interactive client mode.\n"
|
"no arguments Interactive client mode.\n"
|
||||||
"-h, --help Show this message.\n"
|
"-h, --help Show this message.\n"
|
||||||
"-l, --listen [addr:port] Start server.\n"
|
"-l, --listen [addr:port] Start server.\n"
|
||||||
);
|
);
|
||||||
Return 0;
|
Return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,20 +18,42 @@ EndpointIPv4 EndpointIPv4_fromSockaddr(struct sockaddr_in saddr){
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Endpoint functions
|
Result(void) AddressIPv4_parse(cstr s, AddressIPv4* addr){
|
||||||
AddressIPv4 AddressIPv4_fromStr(cstr s);
|
*addr = AddressIPv4_INVALID;
|
||||||
|
u32 a, b, c, d;
|
||||||
str AddressIPv4_toStr(AddressIPv4 address);
|
if(sscanf(s, "%u.%u.%u.%u", &a, &b, &c, &d) != 4){
|
||||||
|
return RESULT_ERROR_FMT("can't parse as AddressIPv4: '%s'", s);
|
||||||
EndpointIPv4 EndpointIPv4_fromStr(cstr s){
|
}
|
||||||
u32 a, b, c, d, p;
|
*addr = AddressIPv4_fromBytes(a, b, c, d);
|
||||||
sscanf(s, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &p);
|
return RESULT_VOID;
|
||||||
EndpointIPv4 e = (EndpointIPv4){
|
|
||||||
.address = AddressIPv4_fromBytes(a, b, c, d),
|
|
||||||
.port = p
|
|
||||||
};
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
str EndpointIPv4_toStr(EndpointIPv4 end);
|
|
||||||
|
|
||||||
|
Result(void) EndpointIPv4_parse(cstr s, EndpointIPv4* end){
|
||||||
|
*end = EndpointIPv4_INVALID;
|
||||||
|
u32 a, b, c, d, p;
|
||||||
|
if(sscanf(s, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &p) != 5){
|
||||||
|
return RESULT_ERROR_FMT("can't parse as EndpointIPv4: '%s'", s);
|
||||||
|
}
|
||||||
|
*end = EndpointIPv4_create(AddressIPv4_fromBytes(a, b, c, d), p);
|
||||||
|
return RESULT_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
str AddressIPv4_toStr(AddressIPv4 addr){
|
||||||
|
char* data = malloc(16);
|
||||||
|
memset(data, 0, 16);
|
||||||
|
sprintf(data, "%u.%u.%u.%u",
|
||||||
|
addr.bytes[0], addr.bytes[1],
|
||||||
|
addr.bytes[2], addr.bytes[3]);
|
||||||
|
return str_from_cstr(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
str EndpointIPv4_toStr(EndpointIPv4 end){
|
||||||
|
char* data = malloc(24);
|
||||||
|
memset(data, 0, 24);
|
||||||
|
sprintf(data, "%u.%u.%u.%u:%u",
|
||||||
|
end.address.bytes[0], end.address.bytes[1],
|
||||||
|
end.address.bytes[2], end.address.bytes[3],
|
||||||
|
end.port);
|
||||||
|
return str_from_cstr(data);
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#include "tlibc/std.h"
|
#include "tlibc/std.h"
|
||||||
#include "tlibc/string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
|
|
||||||
#define port_INVALID ((port)~0)
|
#define port_INVALID ((u16)~0)
|
||||||
#define port_is_invalid(PORT) (PORT == port_INVALID)
|
#define port_is_invalid(PORT) (PORT == port_INVALID)
|
||||||
|
|
||||||
|
|
||||||
@ -18,8 +18,8 @@ typedef union AddressIPv4 {
|
|||||||
|
|
||||||
#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 s);
|
Result(void) AddressIPv4_parse(cstr s, AddressIPv4* addr);
|
||||||
str AddressIPv4_toStr(AddressIPv4 address);
|
str AddressIPv4_toStr(AddressIPv4 addr);
|
||||||
|
|
||||||
|
|
||||||
typedef struct EndpointIPv4 {
|
typedef struct EndpointIPv4 {
|
||||||
@ -31,8 +31,5 @@ typedef struct EndpointIPv4 {
|
|||||||
#define EndpointIPv4_is_invalid(ENDP) (AddressIPv4_is_invalid(ENDP.address) || port_is_invalid(ENDP.port))
|
#define EndpointIPv4_is_invalid(ENDP) (AddressIPv4_is_invalid(ENDP.address) || port_is_invalid(ENDP.port))
|
||||||
|
|
||||||
#define EndpointIPv4_create(ADDR, PORT) ((EndpointIPv4){ADDR, PORT})
|
#define EndpointIPv4_create(ADDR, PORT) ((EndpointIPv4){ADDR, PORT})
|
||||||
EndpointIPv4 EndpointIPv4_fromStr(cstr s);
|
Result(void) EndpointIPv4_parse(cstr s, EndpointIPv4* end);
|
||||||
str EndpointIPv4_toStr(EndpointIPv4 end);
|
str EndpointIPv4_toStr(EndpointIPv4 end);
|
||||||
|
|
||||||
struct sockaddr_in EndpointIPv4_toSockaddr(EndpointIPv4 end);
|
|
||||||
EndpointIPv4 EndpointIPv4_fromSockaddr(struct sockaddr_in saddr);
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "tlibc/errors.h"
|
#include "tlibc/errors.h"
|
||||||
|
#include "endpoint.h"
|
||||||
|
|
||||||
#if !defined(KN_USE_WINSOCK)
|
#if !defined(KN_USE_WINSOCK)
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
#if defined(_WIN64) || defined(_WIN32)
|
||||||
@ -24,3 +25,6 @@
|
|||||||
|
|
||||||
#define RESULT_ERROR_SOCKET() RESULT_ERROR(strerror(errno), false)
|
#define RESULT_ERROR_SOCKET() RESULT_ERROR(strerror(errno), false)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct sockaddr_in EndpointIPv4_toSockaddr(EndpointIPv4 end);
|
||||||
|
EndpointIPv4 EndpointIPv4_fromSockaddr(struct sockaddr_in saddr);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#include "server.h"
|
#include "chat.h"
|
||||||
#include "network/socket.h"
|
#include "network/socket.h"
|
||||||
#include "db/idb.h"
|
#include "db/idb.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user