1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
// Copyright 2017 Parity Technologies (UK) Ltd. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! # 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`](self::Negotiated) stream, or the dialer has run out of //! alternatives. //! //! See [`dialer_select_proto`](self::dialer_select_proto) and //! [`listener_select_proto`](self::listener_select_proto). //! //! ## [`Negotiated`](self::Negotiated) //! //! When a dialer or listener participating in a negotiation settles //! on a protocol to use, the [`DialerSelectFuture`] respectively //! [`ListenerSelectFuture`] yields a [`Negotiated`](self::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`](self::dialer_select_proto). //! //! ## Examples //! //! For a dialer: //! //! ```no_run //! # fn main() { //! use async_std::net::TcpStream; //! use multistream_select::{dialer_select_proto, Version}; //! use futures::prelude::*; //! //! async_std::task::block_on(async move { //! let socket = TcpStream::connect("127.0.0.1:10333").await.unwrap(); //! //! let protos = vec![b"/echo/1.0.0", b"/echo/2.5.0"]; //! let (protocol, _io) = dialer_select_proto(socket, protos, Version::V1).await.unwrap(); //! //! println!("Negotiated protocol: {:?}", protocol); //! // You can now use `_io` to communicate with the remote. //! }); //! # } //! ``` //! mod dialer_select; mod length_delimited; mod listener_select; mod negotiated; mod protocol; mod tests; pub use self::negotiated::{Negotiated, NegotiatedComplete, NegotiationError}; pub use self::protocol::{ProtocolError, Version}; pub use self::dialer_select::{dialer_select_proto, DialerSelectFuture}; pub use self::listener_select::{listener_select_proto, ListenerSelectFuture};