示例#1
0
    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)
示例#2
0
    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)