libp2p / rust-libp2p

The Rust Implementation of the libp2p networking stack.
https://libp2p.io
MIT License
4.34k stars 905 forks source link

transports/{noise,tls}: Select muxer in security handshake #2994

Open mxinden opened 1 year ago

mxinden commented 1 year ago

Description

Implement muxer selection in libp2p-noise and libp2p-tls according to the specification https://github.com/libp2p/specs/pull/446.

Motivation

This document discribes an imporvement on the connection upgrade process. The goal of the improvement is to reduce the number of RTTs that takes to select the muxer of a connection. The solution relies on the ability of the security protocol's handshake process to negotiate higher level protocols, which enables the muxer selection to be carried out along with security protocol handshake. The proposed solution saves the RTT of multistream selection for muxers.

See https://github.com/libp2p/specs/pull/446/

Requirements

1. 2. 3.

Open questions

Are you planning to do it yourself in a pull request?

No

MaboroshiChan commented 1 year ago

Investigation

I have found that the following codes establish security protocols and multiplexer protocols

pub fn authenticate<C, D, U, E>(
        self,
        upgrade: U,
    ) -> Authenticated<AndThen<T, impl FnOnce(C, ConnectedPoint) -> Authenticate<C, U> + Clone>>
    where
        T: Transport<Output = C>,
        C: AsyncRead + AsyncWrite + Unpin,
        D: AsyncRead + AsyncWrite + Unpin,
        U: InboundUpgrade<Negotiated<C>, Output = (PeerId, D), Error = E>,
        U: OutboundUpgrade<Negotiated<C>, Output = (PeerId, D), Error = E> + Clone,
        E: Error + 'static,
    {
        let version = self.version;
        Authenticated(Builder::new(
            self.inner.and_then(move |conn, endpoint| Authenticate {
                inner: upgrade::apply(conn, upgrade, endpoint, version),
            }),
            version,
        ))
    }
pub fn multiplex<C, M, U, E>(
        self,
        upgrade: U,
    ) -> Multiplexed<AndThen<T, impl FnOnce((PeerId, C), ConnectedPoint) -> Multiplex<C, U> + Clone>>
    where
        T: Transport<Output = (PeerId, C)>,
        C: AsyncRead + AsyncWrite + Unpin,
        M: StreamMuxer,
        U: InboundUpgrade<Negotiated<C>, Output = M, Error = E>,
        U: OutboundUpgrade<Negotiated<C>, Output = M, Error = E> + Clone,
        E: Error + 'static,
    {
        let version = self.0.version;
        Multiplexed(self.0.inner.and_then(move |(i, c), endpoint| {
            let upgrade = upgrade::apply(c, upgrade, endpoint, version);

            Multiplex {
                peer_id: Some(i),
                upgrade,
            }
        }))
    }

These two functions authenticate and multiplex call the function upgrade::apply.

Here we have the implementation of upgrade::apply function,

pub fn apply<C, U>(
    conn: C,
    up: U,
    cp: ConnectedPoint,
    v: Version,
) -> Either<InboundUpgradeApply<C, U>, OutboundUpgradeApply<C, U>>
where
    C: AsyncRead + AsyncWrite + Unpin,
    U: InboundUpgrade<Negotiated<C>> + OutboundUpgrade<Negotiated<C>>,
{
    match cp {
        ConnectedPoint::Dialer { role_override, .. } if role_override.is_dialer() => {
            Either::Right(apply_outbound(conn, up, v))
        }
        _ => Either::Left(apply_inbound(conn, up)),
    }
}

functions named apply_inbound and apply_outbound are called.

Both functions also call multistream_select::listener_select_proto and multistream_select::dialer_select_proto respectively, which involve multistream-select mechanism.

By investigating the codes, these two functions will be called twice. One for selecting the security protocol, and the other for multiplexer protocol.

MaboroshiChan commented 1 year ago

Solution

The solution would be required to modify both authenticate and multiplex functions