yamux/
lib.rs

1// Copyright (c) 2018-2019 Parity Technologies (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 or MIT license, at your option.
4//
5// A copy of the Apache License, Version 2.0 is included in the software as
6// LICENSE-APACHE and a copy of the MIT license is included in the software
7// as LICENSE-MIT. You may also obtain a copy of the Apache License, Version 2.0
8// at https://www.apache.org/licenses/LICENSE-2.0 and a copy of the MIT license
9// at https://opensource.org/licenses/MIT.
10
11//! This crate implements the [Yamux specification][1].
12//!
13//! It multiplexes independent I/O streams over reliable, ordered connections,
14//! such as TCP/IP.
15//!
16//! The two primary objects, clients of this crate interact with, are:
17//!
18//! - [`Connection`], which wraps the underlying I/O resource, e.g. a socket, and
19//!   provides methods for opening outbound or accepting inbound streams.
20//! - [`Stream`], which implements [`futures::io::AsyncRead`] and
21//!   [`futures::io::AsyncWrite`].
22//!
23//! [1]: https://github.com/hashicorp/yamux/blob/master/spec.md
24
25#![forbid(unsafe_code)]
26
27mod chunks;
28mod error;
29mod frame;
30
31pub(crate) mod connection;
32mod tagged_stream;
33
34pub use crate::connection::{Connection, Mode, Packet, Stream};
35pub use crate::error::ConnectionError;
36pub use crate::frame::{
37    header::{HeaderDecodeError, StreamId},
38    FrameDecodeError,
39};
40
41pub const DEFAULT_CREDIT: u32 = 256 * 1024; // as per yamux specification
42
43pub type Result<T> = std::result::Result<T, ConnectionError>;
44
45/// The maximum number of streams we will open without an acknowledgement from the other peer.
46///
47/// This enables a very basic form of backpressure on the creation of streams.
48const MAX_ACK_BACKLOG: usize = 256;
49
50/// Default maximum number of bytes a Yamux data frame might carry as its
51/// payload when being send. Larger Payloads will be split.
52///
53/// The data frame payload size is not restricted by the yamux specification.
54/// Still, this implementation restricts the size to:
55///
56/// 1. Reduce delays sending time-sensitive frames, e.g. window updates.
57/// 2. Minimize head-of-line blocking across streams.
58/// 3. Enable better interleaving of send and receive operations, as each is
59///    carried out atomically instead of concurrently with its respective
60///    counterpart.
61///
62/// For details on why this concrete value was chosen, see
63/// https://github.com/paritytech/yamux/issues/100.
64const DEFAULT_SPLIT_SEND_SIZE: usize = 16 * 1024;
65
66/// Specifies when window update frames are sent.
67#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68pub enum WindowUpdateMode {
69    /// Send window updates as soon as a [`Stream`]'s receive window drops to 0.
70    ///
71    /// This ensures that the sender can resume sending more data as soon as possible
72    /// but a slow reader on the receiving side may be overwhelmed, i.e. it accumulates
73    /// data in its buffer which may reach its limit (see `set_max_buffer_size`).
74    /// In this mode, window updates merely prevent head of line blocking but do not
75    /// effectively exercise back pressure on senders.
76    #[deprecated(note = "Use `WindowUpdateMode::OnRead` instead.")]
77    OnReceive,
78
79    /// Send window updates only when data is read on the receiving end.
80    ///
81    /// This ensures that senders do not overwhelm receivers and keeps buffer usage
82    /// low.
83    OnRead,
84}
85
86/// Yamux configuration.
87///
88/// The default configuration values are as follows:
89///
90/// - receive window = 256 KiB
91/// - max. buffer size (per stream) = 1 MiB
92/// - max. number of streams = 8192
93/// - window update mode = on read
94/// - read after close = true
95/// - split send size = 16 KiB
96#[derive(Debug, Clone)]
97pub struct Config {
98    receive_window: u32,
99    max_buffer_size: usize,
100    max_num_streams: usize,
101    window_update_mode: WindowUpdateMode,
102    read_after_close: bool,
103    split_send_size: usize,
104}
105
106impl Default for Config {
107    fn default() -> Self {
108        Config {
109            receive_window: DEFAULT_CREDIT,
110            max_buffer_size: 1024 * 1024,
111            max_num_streams: 8192,
112            window_update_mode: WindowUpdateMode::OnRead,
113            read_after_close: true,
114            split_send_size: DEFAULT_SPLIT_SEND_SIZE,
115        }
116    }
117}
118
119impl Config {
120    /// Set the receive window per stream (must be >= 256 KiB).
121    ///
122    /// # Panics
123    ///
124    /// If the given receive window is < 256 KiB.
125    pub fn set_receive_window(&mut self, n: u32) -> &mut Self {
126        assert!(n >= DEFAULT_CREDIT);
127        self.receive_window = n;
128        self
129    }
130
131    /// Set the max. buffer size per stream.
132    pub fn set_max_buffer_size(&mut self, n: usize) -> &mut Self {
133        self.max_buffer_size = n;
134        self
135    }
136
137    /// Set the max. number of streams.
138    pub fn set_max_num_streams(&mut self, n: usize) -> &mut Self {
139        self.max_num_streams = n;
140        self
141    }
142
143    /// Set the window update mode to use.
144    pub fn set_window_update_mode(&mut self, m: WindowUpdateMode) -> &mut Self {
145        self.window_update_mode = m;
146        self
147    }
148
149    /// Allow or disallow streams to read from buffered data after
150    /// the connection has been closed.
151    pub fn set_read_after_close(&mut self, b: bool) -> &mut Self {
152        self.read_after_close = b;
153        self
154    }
155
156    /// Set the max. payload size used when sending data frames. Payloads larger
157    /// than the configured max. will be split.
158    pub fn set_split_send_size(&mut self, n: usize) -> &mut Self {
159        self.split_send_size = n;
160        self
161    }
162}
163
164// Check that we can safely cast a `usize` to a `u64`.
165static_assertions::const_assert! {
166    std::mem::size_of::<usize>() <= std::mem::size_of::<u64>()
167}
168
169// Check that we can safely cast a `u32` to a `usize`.
170static_assertions::const_assert! {
171    std::mem::size_of::<u32>() <= std::mem::size_of::<usize>()
172}