Skip to content

Instantly share code, notes, and snippets.

@kpp
Last active December 20, 2017 14:15
Show Gist options
  • Save kpp/b31eff18cf4ee9768f3267042f10a19b to your computer and use it in GitHub Desktop.
Save kpp/b31eff18cf4ee9768f3267042f10a19b to your computer and use it in GitHub Desktop.
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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment