tcp-chat/src/server/ClientConnection.c
2025-11-02 15:26:30 +05:00

90 lines
2.7 KiB
C

#include "server.h"
#include "network/tcp-chat-protocol/v1.h"
void ClientConnection_close(ClientConnection* conn){
if(conn == NULL)
return;
socket_close(conn->sock.sock);
free(conn->session_key.data);
free(conn);
}
Result(ClientConnection*) ClientConnection_accept(ServerCredentials* server_credentials,
Socket sock_tcp, EndpointIPv4 client_end, u64 session_id)
{
Deferral(32);
ClientConnection* conn = (ClientConnection*)malloc(sizeof(ClientConnection));
memset(conn, 0, sizeof(*conn));
bool success = false;
Defer(
if(!success)
ClientConnection_close(conn);
);
conn->client_end = client_end;
conn->session_id = session_id;
conn->session_key = Array_alloc_size(AES_SESSION_KEY_SIZE);
Array(u8) enc_buf = Array_alloc_size(8*1024);
Defer(free(enc_buf.data));
Array(u8) dec_buf = Array_alloc_size(8*1024);
Defer(free(dec_buf.data));
u32 enc_size = 0, dec_size = 0;
// TODO: set socket timeout to 5 seconds
// receive message encrypted by server public key
try(enc_size, u,
socket_recv(
sock_tcp,
Array_sliceBefore(enc_buf, server_credentials->rsa_pk.nlen),
SocketRecvFlag_WaitAll
)
);
// decrypt the message using server private key
RSADecryptor rsa_dec;
RSADecryptor_construct(&rsa_dec, &server_credentials->rsa_sk);
try(dec_size, u,
RSADecryptor_decrypt(
&rsa_dec,
Array_sliceBefore(enc_buf, enc_size),
dec_buf
)
);
// validate client handshake
if(dec_size != sizeof(ClientHandshake)){
Return RESULT_ERROR_FMT(
"decrypted message (size: %u) is not a ClientHandshake (size: %u)",
dec_size, (u32)sizeof(ClientHandshake)
);
}
ClientHandshake* client_handshake = dec_buf.data;
try_void(PacketHeader_validateMagic(&client_handshake->header));
if(client_handshake->header.type != PacketType_ClientHandshake){
Return RESULT_ERROR_FMT(
"received message of unexpected type: %u",
client_handshake->header.type
);
}
// use received session key
memcpy(conn->session_key.data, client_handshake->session_key, conn->session_key.size);
EncryptedSocketTCP_construct(&conn->sock, sock_tcp, conn->session_key);
// construct ServerHandshake in dec_buf
ServerHandshake_construct((ServerHandshake*)dec_buf.data, session_id);
// send ServerHandshake over encrypted TCP socket
try_void(
EncryptedSocketTCP_send(
&conn->sock,
Array_sliceBefore(dec_buf, sizeof(ServerHandshake)),
enc_buf
)
);
success = true;
Return RESULT_VALUE(p, conn);
}