[][src]Crate multistream_select

Multistream-select Protocol Negotiation

This crate implements the multistream-select protocol, which is the protocol used by libp2p to negotiate which application-layer protocol to use with the remote on a connection or substream.

Note: This crate is used primarily by core components of libp2p and it is usually not used directly on its own.

Roles

Two peers using the multistream-select negotiation protocol on an I/O stream are distinguished by their role as a dialer (or initiator) or as a listener (or responder). Thereby the dialer plays the active part, driving the protocol, whereas the listener reacts to the messages received.

The dialer has two options: it can either pick a protocol from the complete list of protocols that the listener supports, or it can directly suggest a protocol. Either way, a selected protocol is sent to the listener who can either accept (by echoing the same protocol) or reject (by responding with a message stating "not available"). If a suggested protocol is not available, the dialer may suggest another protocol. This process continues until a protocol is agreed upon, yielding a Negotiated stream, or the dialer has run out of alternatives.

See dialer_select_proto and listener_select_proto.

Negotiated

When a dialer or listener participating in a negotiation settles on a protocol to use, the DialerSelectFuture respectively ListenerSelectFuture yields a Negotiated I/O stream.

Notably, when a DialerSelectFuture resolves to a Negotiated, it may not yet have written the last negotiation message to the underlying I/O stream and may still be expecting confirmation for that protocol, despite having settled on a protocol to use.

Similarly, when a ListenerSelectFuture resolves to a Negotiated, it may not yet have sent the last negotiation message despite having settled on a protocol proposed by the dialer that it supports.

This behaviour allows both the dialer and the listener to send data relating to the negotiated protocol together with the last negotiation message(s), which, in the case of the dialer only supporting a single protocol, results in 0-RTT negotiation. Note, however, that a dialer that performs multiple 0-RTT negotiations in sequence for different protocols layered on top of each other may trigger undesirable behaviour for a listener not supporting one of the intermediate protocols. See dialer_select_proto.

Examples

For a dialer:

use bytes::Bytes;
use multistream_select::{dialer_select_proto, Version};
use futures::{Future, Sink, Stream};
use tokio_tcp::TcpStream;
use tokio::runtime::current_thread::Runtime;

#[derive(Debug, Copy, Clone)]
enum MyProto { Echo, Hello }

let client = TcpStream::connect(&"127.0.0.1:10333".parse().unwrap())
    .from_err()
    .and_then(move |io| {
        let protos = vec![b"/echo/1.0.0", b"/echo/2.5.0"];
        dialer_select_proto(io, protos, Version::V1)
    })
    .map(|(protocol, _io)| protocol);

let mut rt = Runtime::new().unwrap();
let protocol = rt.block_on(client).expect("failed to find a protocol");
println!("Negotiated protocol: {:?}", protocol);

Structs

ListenerSelectFuture

The Future returned by listener_select_proto that performs a multistream-select protocol negotiation on an underlying I/O stream.

Negotiated

An I/O stream that has settled on an (application-layer) protocol to use.

NegotiatedComplete

A Future that waits on the completion of protocol negotiation.

Enums

NegotiationError

Error that can happen when negotiating a protocol with the remote.

ProtocolError

A protocol error.

Version

Supported multistream-select protocol versions.

Functions

dialer_select_proto

Returns a Future that negotiates a protocol on the given I/O stream for a peer acting as the dialer (or initiator).

listener_select_proto

Returns a Future that negotiates a protocol on the given I/O stream for a peer acting as the listener (or responder).

Type Definitions

DialerSelectFuture

Future, returned by dialer_select_proto, which selects a protocol and dialer either trying protocols in-order, or by requesting all protocols supported by the remote upfront, from which the first protocol found in the dialer's list of protocols is selected.