async def stream_reader_writer_to_connection( self, swrt: Tuple[asyncio.StreamReader, asyncio.StreamWriter, OnConnectFunc], server_port: int, ) -> Connection: """ Maps a tuple of (StreamReader, StreamWriter, on_connect) to a Connection object, which also stores the type of connection (str). It is also added to the global list. """ sr, sw, on_connect = swrt con = Connection(self._local_type, None, sr, sw, server_port, on_connect) self.log.info(f"Connection with {con.get_peername()} established") return con
async def perform_handshake( self, connection: Connection) -> AsyncGenerator[Connection, None]: """ Performs handshake with this new connection, and yields the connection. If the handshake is unsuccessful, or we already have a connection with this peer, the connection is closed, and nothing is yielded. """ # Send handshake message outbound_handshake = Message( "handshake", Handshake( config["network_id"], protocol_version, self._node_id, uint16(self._port), self._local_type, ), ) try: await connection.send(outbound_handshake) # Read handshake message full_message = await connection.read_one_message() inbound_handshake = Handshake(**full_message.data) if (full_message.function != "handshake" or not inbound_handshake or not inbound_handshake.node_type): raise InvalidHandshake("Invalid handshake") if inbound_handshake.node_id == self._node_id: raise InvalidHandshake( f"Should not connect to ourselves, aborting handshake.") # Makes sure that we only start one connection with each peer connection.node_id = inbound_handshake.node_id connection.peer_server_port = int(inbound_handshake.server_port) connection.connection_type = inbound_handshake.node_type if not self.global_connections.add(connection): raise InvalidHandshake(f"Duplicate connection to {connection}") # Send Ack message await connection.send(Message("handshake_ack", HandshakeAck())) # Read Ack message full_message = await connection.read_one_message() if full_message.function != "handshake_ack": raise InvalidAck("Invalid ack") if inbound_handshake.version != protocol_version: raise IncompatibleProtocolVersion( f"Our node version {protocol_version} is not compatible with peer\ {connection} version {inbound_handshake.version}") log.info(( f"Handshake with {NodeType(connection.connection_type).name} {connection.get_peername()} " f"{connection.node_id}" f" established")) # Only yield a connection if the handshake is succesful and the connection is not a duplicate. yield connection except ( IncompatibleProtocolVersion, InvalidAck, InvalidHandshake, asyncio.IncompleteReadError, ConnectionResetError, Exception, ) as e: log.warning( f"{e}, handshake not completed. Connection not created.") # Make sure to close the connection even if it's not in global connections connection.close() # Remove the conenction from global connections self.global_connections.close(connection)
async def perform_handshake( self, connection: Connection) -> AsyncGenerator[Connection, None]: """ Performs handshake with this new connection, and yields the connection. If the handshake is unsuccessful, or we already have a connection with this peer, the connection is closed, and nothing is yielded. """ # Send handshake message outbound_handshake = Message( "handshake", Handshake( self._network_id, protocol_version, self._node_id, uint16(self._port), self._local_type, ), ) try: await connection.send(outbound_handshake) # Read handshake message full_message = await connection.read_one_message() inbound_handshake = Handshake(**full_message.data) if (full_message.function != "handshake" or not inbound_handshake or not inbound_handshake.node_type): raise ProtocolError(Err.INVALID_HANDSHAKE) if inbound_handshake.node_id == self._node_id: raise ProtocolError(Err.SELF_CONNECTION) # Makes sure that we only start one connection with each peer connection.node_id = inbound_handshake.node_id connection.peer_server_port = int(inbound_handshake.server_port) connection.connection_type = inbound_handshake.node_type if not self.global_connections.add(connection): raise ProtocolError(Err.DUPLICATE_CONNECTION, [False]) # Send Ack message await connection.send(Message("handshake_ack", HandshakeAck())) # Read Ack message full_message = await connection.read_one_message() if full_message.function != "handshake_ack": raise ProtocolError(Err.INVALID_ACK) if inbound_handshake.version != protocol_version: raise ProtocolError( Err.INCOMPATIBLE_PROTOCOL_VERSION, [protocol_version, inbound_handshake.version], ) self.log.info(( f"Handshake with {NodeType(connection.connection_type).name} {connection.get_peername()} " f"{connection.node_id}" f" established")) # Only yield a connection if the handshake is succesful and the connection is not a duplicate. yield connection except ( ProtocolError, asyncio.IncompleteReadError, OSError, Exception, ) as e: self.log.warning( f"{e}, handshake not completed. Connection not created.") # Make sure to close the connection even if it's not in global connections connection.close() # Remove the conenction from global connections self.global_connections.close(connection)