def merge_node_table(self, src: RsaKey, table: bfcp_pb2.NodeTable): src_key = pubkey_to_deterministic_string(src) if src_key not in self._wait_update_nodes: # probably an error/malicious return self._wait_update_nodes.remove(src) for entry in table.entries: node_key = pubkey_to_deterministic_string(get_node_pub_key(entry)) if node_key in self._nodes: update_trust_score(self._nodes[node_key], self._nodes[src_key].trust_score, entry.trust_score) else: self._nodes[node_key] = entry self._nodes[node_key].new_trust_score( self._nodes[src].trust_score, entry.trust_score)
def _parse_initial_node_table(initial_node_table: bfcp_pb2.NodeTable)\ -> Dict[bytes, bfcp_pb2.NodeTableEntry]: result = RandomDict() for entry in initial_node_table.entries: pub_key = proto_to_pubkey(entry.node.public_key) result[pubkey_to_deterministic_string(pub_key)] = entry return result
async def update_node_table(self): self._last_update_timestamp = time() # TODO config this for i in range(10): node = self.get_random_node() await self._bfc.traffic_manager.send(bfcp_pb2.DiscoveryRequest(), get_node_pub_key(node)) self._wait_update_nodes.add( pubkey_to_deterministic_string(get_node_pub_key(node)))
def get_random_node(self) -> bfcp_pb2.NodeTableEntry: """ Get a random node for sending stuffs. :raises ValueError if there is no node. :return: a random node. """ own_pub_key_index = pubkey_to_deterministic_string(self._bfc.rsa_key) if own_pub_key_index in self._nodes: del self._nodes[own_pub_key_index] if len(self._nodes) == 0: raise ValueError("No node in the trust table.") return self._nodes.random_value()
async def send(self, msg: BouncyMessage, pub_key: Optional[RsaKey] = None) -> None: """ Sends the provided BouncyMessage to the node in the network identified by the given public key. It's also possible to send a message to the node itself. """ msg = self._wrap_into_bouncy_message(msg) if pub_key is None: pub_key = get_node_pub_key( self._bfc.trust_table_manager.get_random_node()) pub_key_index = pubkey_to_deterministic_string(pub_key) send_to = None if pub_key_index in self._open_client_sockets: send_to = self._open_client_sockets[pub_key_index] elif pub_key_index in self._open_server_sockets: send_to = self._open_server_sockets[pub_key_index] else: # We need to form a new connection node = self._bfc.trust_table_manager.get_node_by_pubkey(pub_key) if node is None: raise NodeNotFoundError( 'A node with the provided public key does not exist in the ' 'trust table') reader, writer = await asyncio.open_connection( node.node.last_known_address, node.node.last_port, loop=self._async_loop) _log.debug('New client connection on %s. Logged by %s', writer.get_extra_info('peername'), str(self._serving_host)) send_to = await self._open_new_socket_handler(reader, writer) self._register_client_socket_handler(send_to) self._open_client_sockets[pub_key_index] = send_to _log.debug( 'Sending message: %s\nTo: %s\nLogged by: %s\nThread: %d', str(msg), str( self._bfc.trust_table_manager.get_node_by_pubkey( send_to.get_peer_key())), str(self._bfc._self_node.last_port), threading.get_ident()) await send_to.send_bouncy_message(msg)
def get_node_by_pubkey( self, pub_key: RsaKey) -> Optional[bfcp_pb2.NodeTableEntry]: """ Returns a NodeTableEntry with the pub key, else return None """ return self._nodes.get(pubkey_to_deterministic_string(pub_key), None)
def _register_client_socket_handler(self, socket_handler: BfcpSocketHandler): pub_key_index = pubkey_to_deterministic_string( socket_handler.get_peer_key()) self._open_client_sockets[pub_key_index] = socket_handler