libp2p_core/upgrade.rs
1// Copyright 2018 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21//! Contains everything related to upgrading a connection or a substream to use a protocol.
22//!
23//! After a connection with a remote has been successfully established or a substream successfully
24//! opened, the next step is to *upgrade* this connection or substream to use a protocol.
25//!
26//! This is where the `UpgradeInfo`, `InboundUpgrade` and `OutboundUpgrade` traits come into play.
27//! The `InboundUpgrade` and `OutboundUpgrade` traits are implemented on types that represent a
28//! collection of one or more possible protocols for respectively an ingoing or outgoing
29//! connection or substream.
30//!
31//! > **Note**: Multiple versions of the same protocol are treated as different protocols.
32//! > For example, `/foo/1.0.0` and `/foo/1.1.0` are totally unrelated as far as
33//! > upgrading is concerned.
34//!
35//! # Upgrade process
36//!
37//! An upgrade is performed in two steps:
38//!
39//! - A protocol negotiation step. The `UpgradeInfo::protocol_info` method is called to determine
40//! which protocols are supported by the trait implementation. The `multistream-select` protocol
41//! is used in order to agree on which protocol to use amongst the ones supported.
42//!
43//! - A handshake. After a successful negotiation, the `InboundUpgrade::upgrade_inbound` or
44//! `OutboundUpgrade::upgrade_outbound` method is called. This method will return a `Future` that
45//! performs a handshake. This handshake is considered mandatory, however in practice it is
46//! possible for the trait implementation to return a dummy `Future` that doesn't perform any
47//! action and immediately succeeds.
48//!
49//! After an upgrade is successful, an object of type `InboundUpgrade::Output` or
50//! `OutboundUpgrade::Output` is returned. The actual object depends on the implementation and
51//! there is no constraint on the traits that it should implement, however it is expected that it
52//! can be used by the user to control the behaviour of the protocol.
53//!
54//! > **Note**: You can use the `apply_inbound` or `apply_outbound` methods to try upgrade a
55//! connection or substream. However if you use the recommended `Swarm` or
56//! `ProtocolsHandler` APIs, the upgrade is automatically handled for you and you don't
57//! need to use these methods.
58//!
59
60mod apply;
61mod denied;
62mod either;
63mod error;
64mod from_fn;
65mod map;
66mod optional;
67mod select;
68mod transfer;
69
70use futures::future::Future;
71
72pub use crate::Negotiated;
73pub use multistream_select::{Version, NegotiatedComplete, NegotiationError, ProtocolError};
74pub use self::{
75 apply::{apply, apply_inbound, apply_outbound, InboundUpgradeApply, OutboundUpgradeApply},
76 denied::DeniedUpgrade,
77 either::EitherUpgrade,
78 error::UpgradeError,
79 from_fn::{from_fn, FromFnUpgrade},
80 map::{MapInboundUpgrade, MapOutboundUpgrade, MapInboundUpgradeErr, MapOutboundUpgradeErr},
81 optional::OptionalUpgrade,
82 select::SelectUpgrade,
83 transfer::{write_one, write_with_len_prefix, write_varint, read_one, ReadOneError, read_varint},
84};
85
86/// Types serving as protocol names.
87///
88/// # Context
89///
90/// In situations where we provide a list of protocols that we support,
91/// the elements of that list are required to implement the [`ProtocolName`] trait.
92///
93/// Libp2p will call [`ProtocolName::protocol_name`] on each element of that list, and transmit the
94/// returned value on the network. If the remote accepts a given protocol, the element
95/// serves as the return value of the function that performed the negotiation.
96///
97/// # Example
98///
99/// ```
100/// use libp2p_core::ProtocolName;
101///
102/// enum MyProtocolName {
103/// Version1,
104/// Version2,
105/// Version3,
106/// }
107///
108/// impl ProtocolName for MyProtocolName {
109/// fn protocol_name(&self) -> &[u8] {
110/// match *self {
111/// MyProtocolName::Version1 => b"/myproto/1.0",
112/// MyProtocolName::Version2 => b"/myproto/2.0",
113/// MyProtocolName::Version3 => b"/myproto/3.0",
114/// }
115/// }
116/// }
117/// ```
118///
119pub trait ProtocolName {
120 /// The protocol name as bytes. Transmitted on the network.
121 ///
122 /// **Note:** Valid protocol names must start with `/` and
123 /// not exceed 140 bytes in length.
124 fn protocol_name(&self) -> &[u8];
125}
126
127impl<T: AsRef<[u8]>> ProtocolName for T {
128 fn protocol_name(&self) -> &[u8] {
129 self.as_ref()
130 }
131}
132
133/// Common trait for upgrades that can be applied on inbound substreams, outbound substreams,
134/// or both.
135pub trait UpgradeInfo {
136 /// Opaque type representing a negotiable protocol.
137 type Info: ProtocolName + Clone;
138 /// Iterator returned by `protocol_info`.
139 type InfoIter: IntoIterator<Item = Self::Info>;
140
141 /// Returns the list of protocols that are supported. Used during the negotiation process.
142 fn protocol_info(&self) -> Self::InfoIter;
143}
144
145/// Possible upgrade on an inbound connection or substream.
146pub trait InboundUpgrade<C>: UpgradeInfo {
147 /// Output after the upgrade has been successfully negotiated and the handshake performed.
148 type Output;
149 /// Possible error during the handshake.
150 type Error;
151 /// Future that performs the handshake with the remote.
152 type Future: Future<Output = Result<Self::Output, Self::Error>>;
153
154 /// After we have determined that the remote supports one of the protocols we support, this
155 /// method is called to start the handshake.
156 ///
157 /// The `info` is the identifier of the protocol, as produced by `protocol_info`.
158 fn upgrade_inbound(self, socket: C, info: Self::Info) -> Self::Future;
159}
160
161/// Extension trait for `InboundUpgrade`. Automatically implemented on all types that implement
162/// `InboundUpgrade`.
163pub trait InboundUpgradeExt<C>: InboundUpgrade<C> {
164 /// Returns a new object that wraps around `Self` and applies a closure to the `Output`.
165 fn map_inbound<F, T>(self, f: F) -> MapInboundUpgrade<Self, F>
166 where
167 Self: Sized,
168 F: FnOnce(Self::Output) -> T
169 {
170 MapInboundUpgrade::new(self, f)
171 }
172
173 /// Returns a new object that wraps around `Self` and applies a closure to the `Error`.
174 fn map_inbound_err<F, T>(self, f: F) -> MapInboundUpgradeErr<Self, F>
175 where
176 Self: Sized,
177 F: FnOnce(Self::Error) -> T
178 {
179 MapInboundUpgradeErr::new(self, f)
180 }
181}
182
183impl<C, U: InboundUpgrade<C>> InboundUpgradeExt<C> for U {}
184
185/// Possible upgrade on an outbound connection or substream.
186pub trait OutboundUpgrade<C>: UpgradeInfo {
187 /// Output after the upgrade has been successfully negotiated and the handshake performed.
188 type Output;
189 /// Possible error during the handshake.
190 type Error;
191 /// Future that performs the handshake with the remote.
192 type Future: Future<Output = Result<Self::Output, Self::Error>>;
193
194 /// After we have determined that the remote supports one of the protocols we support, this
195 /// method is called to start the handshake.
196 ///
197 /// The `info` is the identifier of the protocol, as produced by `protocol_info`.
198 fn upgrade_outbound(self, socket: C, info: Self::Info) -> Self::Future;
199}
200
201/// Extention trait for `OutboundUpgrade`. Automatically implemented on all types that implement
202/// `OutboundUpgrade`.
203pub trait OutboundUpgradeExt<C>: OutboundUpgrade<C> {
204 /// Returns a new object that wraps around `Self` and applies a closure to the `Output`.
205 fn map_outbound<F, T>(self, f: F) -> MapOutboundUpgrade<Self, F>
206 where
207 Self: Sized,
208 F: FnOnce(Self::Output) -> T
209 {
210 MapOutboundUpgrade::new(self, f)
211 }
212
213 /// Returns a new object that wraps around `Self` and applies a closure to the `Error`.
214 fn map_outbound_err<F, T>(self, f: F) -> MapOutboundUpgradeErr<Self, F>
215 where
216 Self: Sized,
217 F: FnOnce(Self::Error) -> T
218 {
219 MapOutboundUpgradeErr::new(self, f)
220 }
221}
222
223impl<C, U: OutboundUpgrade<C>> OutboundUpgradeExt<C> for U {}
224