TCP_Secure_Connection
status: NO_STATUS | CONNECTED | UNCONFIRMED | CONFIRMED
identifier: UID, autoincremented across all connections in TCP_Server
public_key: PK of the connection (taken from handshake)
connections: inited with zeros, keeps links to clients to communicate with
NUM_CLIENT_CONNECTIONS: (256 - NUM_RESERVED_PORTS)
NUM_RESERVED_PORTS: 16
struct {
uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
uint32_t index; // get_TCP_connection_index(other.PK)
uint8_t other_id; // index of this.public_key in other.connections
} connections[NUM_CLIENT_CONNECTIONS];
index of connections is: find free slot for the given PK or connection.public_key == PK
last_pinged: timestamp
ping_id: random int to check pong response
TCP_Server
accepted_key_list: a 'hashmap<PK, int>'. when a connection is accepted
we take the index of the first free position from `accepted_connection_array`
(with status=NO_STATUS) and insert it into `accepted_key_list` by
the PK of the connection (PK from handshake)
accepted_connection_array: array of reusable connections
connections can be added to the first free position (with status=NO_STATUS)
or the connection can be removed, notifying all connectected??? (TODO)
people that connectection is dead
get_TCP_connection_index(pk): return index from `accepted_key_list` by PK.
index is constant for the connection during lifetime of the connection.
each incoming message: {
handle_TCP_packet() or shutdown_connection_gracefully()
}
shutdown_connection_gracefully: {
for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) {
rm_connection_index(TCP_server, &TCP_server->accepted_connection_array[index], i);
}
kill socket
}
rm_connection_index(TCP_server, self_connection, connection_id): {
if connection_id is out of range of self_connection.connectections
return Error
link_to_other = self_connection.connectections[connection_id]
if link_to_other is not initialized
return Error
if link_to_other.status == ONLINE {
// remove the current connection from other connection
other_connection_id = link_to_other.index
other_connection = TCP_server->accepted_connection_array[index]
self_index_in_other = link_to_other.other_id
// actually clear it
other_connection.connections[self_index_in_other].index = 0
other_connection.connections[self_index_in_other].other_id = 0
other_connection.connections[self_index_in_other].status = OFFLINE
}
// clear link:
link_to_other.status = 0
link_to_other.index = 0
link_to_other.other_id = 0
}
handle_TCP_packet:
Client Server Other Client
1)
RouteRequest -> handle_TCP_routing_req()
<- RouteResponse
<- ConnectNotification
-> ConnectNotification
handle_TCP_routing_req(TCP_Server, self_connection_id, other_pk): {
fn get_link_index(TCP_Secure_Connection* self, other_pk) {
if self.pk == other_pk
// connection_id: 0 is a bad id, it should start from 16
// so the client knows there is nobody there or they sent a wrong pk to connect with
return RouteResponse {connection_id: 0, pk: other_pk}
// find index of already connected pk
index = self.connections.find(|connection| connection.pk == other_pk)
// or
if index is none
// find a free slot (status == 0 means the slot was zeroed)
index = self.connections.filter(|connection| connectection.status == 0).first()
return index
}
self = TCP_Server.accepted_connection_array[self_connection_id]
other_link_index = get_link_index(self, other_pk)
// if no existing connection or no free slot
if other_link_index is none
// send bad RouteResponse as error
return RouteResponse {connection_id: 0, pk: other_pk}
send_routing_response(self, other_link_index + NUM_RESERVED_PORTS, other_pk);
// insert other_pk by other_link_index to return RouteResponse with the same
// connection_id: other_link_index for the same other_pk
link_to_other = self.connectections[other_link_index];
link_to_other.public_key = other_pk
link_to_other.status = OFFLINE
// connect them together
other_connection_id = get_TCP_connection_index(TCP_server, other_pk)
if other_connection_id is none
leave link_to_other OFFLINE, because it is not connected to TCP server yet
else
other = TCP_Server.accepted_connection_array[other_connection_id]
self_link_index = get_link_index(other, self.pk)
link_to_self = other.connectections[self_link_index]
link_to_self.pk = self.public_key
// mark both links online
link_to_self.status = ONLINE
link_to_other.status = ONLINE
// connect indices
link_to_self.index = self_connection_id
link_to_self.other_id = other_link_index
link_to_other.index = other_connection_id
link_to_other.other_id = self_link_index
send_connect_notification(self, other_link_index);
send_connect_notification(other, self_link_index);
}
2)
RouteResponse -> Error
3)
ConnectNotification -> handle_connection_notification
<- ()
handle_connection_notification:
do nothing
4)
DisconnectNotification -> handle_disconnection_notification
<- ()
handle_disconnection_notification: {
return rm_connection_index(TCP_server, self_connection, DisconnectNotification.connection_id - NUM_RESERVED_PORTS)
}
5)
PingRequest -> handle_ping_request
<- PongResponse
handle_ping_request: {
create corresponding PongResponse (^C ^V ping_id from PingRequest)
}
6)
PongResponse -> handle_pong_response
<- ()
handle_pong_response: {
check PongResponse.ping_id == latest PingRequest.ping_id, if not equal return Error
}
7)
OobSend -> handle_oob_send
<- ()
handle_oob_send:
TODO
8)
OobReceive -> Error
9)
OnionRequest: TODO
10)
OnionResponse -> Error
11)
Data: TODO