Introduce shared module for widely used types

This removes the dependency from connection on endpoint which I always found
ugly, and generally shrinks some of our larger modules by extracting types
that are not tightly coupled to their those modules' other contents.
This commit is contained in:
Dirkjan Ochtman
2019-03-30 12:20:20 +01:00
committed by Benjamin Saunders
parent c66937e55b
commit f63fd2b811
8 changed files with 342 additions and 324 deletions
+7 -35
View File
@@ -13,17 +13,19 @@ use slog::Logger;
use crate::assembler::Assembler;
use crate::coding::BufMutExt;
use crate::crypto::{
self, reset_token_for, Crypto, CryptoClientConfig, CryptoSession, HeaderCrypto,
RingHeaderCrypto, TlsSession, ACK_DELAY_EXPONENT,
reset_token_for, Crypto, CryptoClientConfig, CryptoSession, HeaderCrypto, RingHeaderCrypto,
TlsSession, ACK_DELAY_EXPONENT,
};
use crate::dedup::Dedup;
use crate::endpoint::TransportConfig;
use crate::frame::FrameStruct;
use crate::packet::{
set_payload_length, ConnectionId, EcnCodepoint, Header, LongType, Packet, PacketNumber,
PartialDecode, SpaceId, LONG_RESERVED_BITS, SHORT_RESERVED_BITS,
set_payload_length, Header, LongType, Packet, PacketNumber, PartialDecode, SpaceId,
LONG_RESERVED_BITS, SHORT_RESERVED_BITS,
};
use crate::range_set::RangeSet;
use crate::shared::{
ClientConfig, ConnectionEvent, ConnectionId, EcnCodepoint, EndpointEvent, TransportConfig,
};
use crate::stream::{self, ReadError, Streams, WriteError};
use crate::transport_parameters::{self, TransportParameters};
use crate::{
@@ -3106,12 +3108,6 @@ mod state {
}
}
#[derive(Clone)]
pub struct ClientConfig {
pub server_name: String,
pub tls_config: Arc<crypto::ClientConfig>,
}
/// Represents one or more packets subject to retransmission
#[derive(Debug, Clone)]
struct SentPacket {
@@ -3134,30 +3130,6 @@ struct SentPacket {
/// Ensures we can always fit all our ACKs in a single minimum-MTU packet with room to spare
const MAX_ACK_BLOCKS: usize = 64;
/// Events to be sent to the Connection
pub enum ConnectionEvent {
Datagram {
now: Instant,
remote: SocketAddr,
ecn: Option<EcnCodepoint>,
first_decode: PartialDecode,
remaining: Option<BytesMut>,
},
NewIdentifiers(Vec<(u64, ConnectionId)>),
Timer(Instant, Timer),
}
/// Events to be sent to the Endpoint
#[derive(Clone, Debug)]
pub enum EndpointEvent {
Closed {
remote: SocketAddr,
},
NeedIdentifiers,
/// Stop routing connection ID for this sequence number to this `Connection`
RetireConnectionId(u64),
}
/// Encoding of I/O operations to emit on upcoming `poll_io` calls
#[derive(Debug)]
struct IoQueue {
+2 -1
View File
@@ -17,7 +17,8 @@ pub use rustls::{ClientConfig, ClientSession, ServerConfig, ServerSession, Sessi
use webpki::DNSNameRef;
use crate::coding::{BufExt, BufMutExt};
use crate::packet::{ConnectionId, PacketNumber, LONG_HEADER_FORM};
use crate::packet::{PacketNumber, LONG_HEADER_FORM};
use crate::shared::ConnectionId;
use crate::transport_parameters::TransportParameters;
use crate::{ConnectError, Side, TransportError, MAX_CID_SIZE, MIN_CID_SIZE, RESET_TOKEN_SIZE};
+8 -174
View File
@@ -1,4 +1,3 @@
use std::cmp;
use std::collections::{HashMap, VecDeque};
use std::net::SocketAddr;
use std::ops::{Index, IndexMut};
@@ -15,16 +14,20 @@ use slab::Slab;
use slog::{self, Logger};
use crate::coding::BufMutExt;
use crate::connection::{initial_close, ClientConfig, Connection, ConnectionEvent, EndpointEvent};
use crate::connection::{initial_close, Connection};
use crate::crypto::{
self, reset_token_for, Crypto, CryptoClientConfig, CryptoServerConfig, RingHeaderCrypto,
TokenKey,
};
use crate::packet::{ConnectionId, EcnCodepoint, Header, Packet, PacketDecodeError, PartialDecode};
use crate::packet::{Header, Packet, PacketDecodeError, PartialDecode};
use crate::shared::{
ClientConfig, ConfigError, ConnectionEvent, ConnectionId, EcnCodepoint, EndpointEvent,
TransportConfig,
};
use crate::transport_parameters::TransportParameters;
use crate::{
varint, Side, Transmit, TransportError, LOC_CID_COUNT, MAX_CID_SIZE, MIN_CID_SIZE,
MIN_INITIAL_SIZE, RESET_TOKEN_SIZE, VERSION,
Side, Transmit, TransportError, LOC_CID_COUNT, MAX_CID_SIZE, MIN_CID_SIZE, MIN_INITIAL_SIZE,
RESET_TOKEN_SIZE, VERSION,
};
/// The main entry point to the library
@@ -592,163 +595,6 @@ pub(crate) struct ConnectionMeta {
loc_cids: HashMap<u64, ConnectionId>,
}
/// Parameters governing the core QUIC state machine
///
/// This should be tuned to suit the application. In particular, window sizes for streams, stream
/// data, and overall connection data should be set differently depending on the expected round trip
/// time, link capacity, memory availability, and rate of stream creation. Tuning for higher
/// bandwidths and latencies increases worst-case memory consumption, but does not impair
/// performance at lower bandwidths and latencies. The default configuration is tuned for a 100Mbps
/// link with a 100ms round trip time, with remote endpoints opening at most 320 new streams per
/// second. Applications which do not require remotely-initiated streams should set the stream
/// windows to zero.
pub struct TransportConfig {
/// Maximum number of bidirectional streams that may be initiated by the peer but not yet
/// accepted locally
///
/// Must be nonzero for the peer to open any bidirectional streams.
///
/// Any number of streams may be in flight concurrently. However, to ensure predictable resource
/// use, the number of streams which the peer has initiated but which the local application has
/// not yet accepted will be kept below this threshold.
///
/// Because it takes at least one round trip for an endpoint to open a new stream and be
/// notified of its peer's flow control updates, this imposes a hard upper bound on the number
/// of streams that may be opened per round-trip. In other words, this should be set to at least
/// the desired number of streams opened per unit time, multiplied by the round trip time.
///
/// Note that worst-case memory use is directly proportional to `stream_window_bidi *
/// stream_receive_window`, with an upper bound proportional to `receive_window`.
pub stream_window_bidi: u64,
/// Variant of `stream_window_bidi` affecting unidirectional streams
pub stream_window_uni: u64,
/// Maximum duration of inactivity to accept before timing out the connection (ms).
///
/// The actual value used is the minimum of this and the peer's own idle timeout. 0 for none.
pub idle_timeout: u64,
/// Maximum number of bytes the peer may transmit without acknowledgement on any one stream
/// before becoming blocked.
///
/// This should be set to at least the expected connection latency multiplied by the maximum
/// desired throughput. Setting this smaller than `receive_window` helps ensure that a single
/// stream doesn't monopolize receive buffers, which may otherwise occur if the application
/// chooses not to read from a large stream for a time while still requiring data on other
/// streams.
pub stream_receive_window: u64,
/// Maximum number of bytes the peer may transmit across all streams of a connection before
/// becoming blocked.
///
/// This should be set to at least the expected connection latency multiplied by the maximum
/// desired throughput. Larger values can be useful to allow maximum throughput within a
/// stream while another is blocked.
pub receive_window: u64,
/// Maximum number of bytes to transmit to a peer without acknowledgment
///
/// Provides an upper bound on memory when communicating with peers that issue large amounts of
/// flow control credit. Endpoints that wish to handle large numbers of connections robustly
/// should take care to set this low enough to guarantee memory exhaustion does not occur if
/// every connection uses the entire window.
pub send_window: u64,
/// Maximum number of tail loss probes before an RTO fires.
pub max_tlps: u32,
/// Maximum reordering in packet number space before FACK style loss detection considers a
/// packet lost.
pub packet_threshold: u32,
/// Maximum reordering in time space before time based loss detection considers a packet lost.
/// 0.16 format, added to 1
pub time_threshold: u16,
/// The length of the peers delayed ack timer (μs).
pub delayed_ack_timeout: u64,
/// The RTT used before an RTT sample is taken (μs)
pub initial_rtt: u64,
/// The max packet size that was used for calculating default and minimum congestion windows.
pub max_datagram_size: u64,
/// Default limit on the amount of outstanding data in bytes.
///
/// Recommended value: `min(10 * max_datagram_size, max(2 * max_datagram_size, 14600))`
pub initial_window: u64,
/// Default minimum congestion window.
///
/// Recommended value: `2 * max_datagram_size`.
pub minimum_window: u64,
/// Reduction in congestion window when a new loss event is detected. 0.16 format
pub loss_reduction_factor: u16,
/// Number of consecutive PTOs after which network is considered to be experiencing persistent congestion.
pub persistent_congestion_threshold: u32,
/// Number of milliseconds of inactivity before sending a keep-alive packet
///
/// Keep-alive packets prevent an inactive but otherwise healthy connection from timing out.
///
/// 0 to disable, which is the default. Only one side of any given connection needs keep-alive
/// enabled for the connection to be preserved. Must be set lower than the idle_timeout of both
/// peers to be effective.
pub keep_alive_interval: u32,
}
impl Default for TransportConfig {
fn default() -> Self {
const EXPECTED_RTT: u64 = 100; // ms
const MAX_STREAM_BANDWIDTH: u64 = 12500 * 1000; // bytes/s
// Window size needed to avoid pipeline
// stalls
const STREAM_RWND: u64 = MAX_STREAM_BANDWIDTH / 1000 * EXPECTED_RTT;
const MAX_DATAGRAM_SIZE: u64 = 1200;
TransportConfig {
stream_window_bidi: 32,
stream_window_uni: 32,
idle_timeout: 10_000,
stream_receive_window: STREAM_RWND,
receive_window: 8 * STREAM_RWND,
send_window: 8 * STREAM_RWND,
max_tlps: 2,
packet_threshold: 3,
time_threshold: 0x2000, // 1/8
delayed_ack_timeout: 25 * 1000,
initial_rtt: EXPECTED_RTT as u64 * 1000,
max_datagram_size: MAX_DATAGRAM_SIZE,
initial_window: cmp::min(
10 * MAX_DATAGRAM_SIZE,
cmp::max(2 * MAX_DATAGRAM_SIZE, 14600),
),
minimum_window: 2 * MAX_DATAGRAM_SIZE,
loss_reduction_factor: 0x8000, // 1/2
persistent_congestion_threshold: 2,
keep_alive_interval: 0,
}
}
}
impl TransportConfig {
fn validate(&self, log: &Logger) -> Result<(), ConfigError> {
if let Some((name, _)) = [
("stream_window_bidi", self.stream_window_bidi),
("stream_window_uni", self.stream_window_uni),
("receive_window", self.receive_window),
("stream_receive_window", self.stream_receive_window),
("idle_timeout", self.idle_timeout),
]
.iter()
.find(|&&(_, x)| x > varint::MAX_VALUE)
{
return Err(ConfigError::VarIntBounds(name));
}
if self.idle_timeout != 0 && self.keep_alive_interval as u64 >= self.idle_timeout {
warn!(
log,
"keep-alive interval {} is ineffective due to lower idle timeout {}",
self.keep_alive_interval,
self.idle_timeout
);
}
Ok(())
}
}
/// Global configuration for the endpoint, affecting all connections
pub struct EndpointConfig {
/// Length of connection IDs for the endpoint.
@@ -834,18 +680,6 @@ impl Default for ServerConfig {
}
}
/// Errors in the configuration of an endpoint
#[derive(Debug, Error)]
pub enum ConfigError {
/// The supplied configuration contained an invalid value
#[error(display = "illegal configuration value: {}", _0)]
IllegalValue(&'static str),
/// A configuration field that will be encoded as a variable-length integer exceeds the 0..2^62
/// range
#[error(display = "{} must be at most 2^62-1", _0)]
VarIntBounds(&'static str),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct ConnectionHandle(pub usize);
+1 -1
View File
@@ -4,8 +4,8 @@ use std::{fmt, io, mem};
use bytes::{Buf, BufMut, Bytes};
use crate::coding::{self, BufExt, BufMutExt, UnexpectedEnd};
use crate::packet::EcnCodepoint;
use crate::range_set::RangeSet;
use crate::shared::EcnCodepoint;
use crate::{
varint, ConnectionId, Directionality, StreamId, TransportError, TransportErrorCode,
MAX_CID_SIZE, MIN_CID_SIZE, RESET_TOKEN_SIZE,
+7 -8
View File
@@ -18,6 +18,7 @@ use std::time::Duration;
mod assembler;
pub mod coding;
mod dedup;
mod packet;
mod range_set;
#[cfg(test)]
mod tests;
@@ -25,10 +26,7 @@ mod transport_parameters;
pub mod varint;
mod connection;
pub use crate::connection::{
Connection, ConnectionError, ConnectionEvent, EndpointEvent, Event, Timer, TimerSetting,
TimerUpdate,
};
pub use crate::connection::{Connection, ConnectionError, Event, Timer, TimerSetting, TimerUpdate};
mod crypto;
pub use crate::crypto::{ClientConfig, TokenKey};
@@ -39,12 +37,13 @@ pub use crate::frame::{ApplicationClose, ConnectionClose};
mod endpoint;
pub use crate::endpoint::{
ConfigError, ConnectError, ConnectionHandle, DatagramEvent, Endpoint, EndpointConfig,
ServerConfig, TransportConfig,
ConnectError, ConnectionHandle, DatagramEvent, Endpoint, EndpointConfig, ServerConfig,
};
mod packet;
pub use crate::packet::{ConnectionId, EcnCodepoint};
mod shared;
pub use crate::shared::{
ConfigError, ConnectionEvent, ConnectionId, EcnCodepoint, EndpointEvent, TransportConfig,
};
mod stream;
pub use crate::stream::{ReadError, WriteError};
+3 -104
View File
@@ -1,14 +1,14 @@
use std::{cmp::Ordering, fmt, io, ops::Range, str};
use std::{cmp::Ordering, io, ops::Range, str};
use bytes::{BigEndian, Buf, BufMut, ByteOrder, Bytes, BytesMut};
use err_derive::Error;
use rand::Rng;
use slog;
use crate::coding::{self, BufExt, BufMutExt};
use crate::crypto::{HeaderCrypto, RingHeaderCrypto};
use crate::shared::ConnectionId;
use crate::varint;
use crate::{MAX_CID_SIZE, MIN_CID_SIZE, VERSION};
use crate::VERSION;
// Due to packet number encryption, it is impossible to fully decode a header
// (which includes a variable-length packet number) without crypto context.
@@ -770,80 +770,6 @@ impl From<coding::UnexpectedEnd> for PacketDecodeError {
}
}
/// Protocol-level identifier for a connection.
///
/// Mainly useful for identifying this connection's packets on the wire with tools like Wireshark.
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ConnectionId {
pub len: u8,
pub bytes: [u8; MAX_CID_SIZE],
}
impl ConnectionId {
pub fn new(bytes: &[u8]) -> Self {
debug_assert!(
bytes.is_empty() || (bytes.len() >= MIN_CID_SIZE && bytes.len() <= MAX_CID_SIZE)
);
let mut res = Self {
len: bytes.len() as u8,
bytes: [0; MAX_CID_SIZE],
};
res.bytes[..bytes.len()].clone_from_slice(&bytes);
res
}
pub fn random<R: Rng>(rng: &mut R, len: usize) -> Self {
debug_assert!(len <= MAX_CID_SIZE);
let mut res = Self {
len: len as u8,
bytes: [0; MAX_CID_SIZE],
};
let mut rng_bytes = [0; MAX_CID_SIZE];
rng.fill_bytes(&mut rng_bytes);
res.bytes[..len].clone_from_slice(&rng_bytes[..len]);
res
}
}
impl ::std::ops::Deref for ConnectionId {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes[0..self.len as usize]
}
}
impl ::std::ops::DerefMut for ConnectionId {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.bytes[0..self.len as usize]
}
}
impl fmt::Debug for ConnectionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.bytes[0..self.len as usize].fmt(f)
}
}
impl fmt::Display for ConnectionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.iter() {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl slog::Value for ConnectionId {
fn serialize(
&self,
_: &slog::Record<'_>,
key: slog::Key,
serializer: &mut dyn slog::Serializer,
) -> slog::Result {
serializer.emit_arguments(key, &format_args!("{}", self))
}
}
pub fn set_payload_length(packet: &mut [u8], header_len: usize, pn_len: usize, tag_len: usize) {
let len = packet.len() - header_len + pn_len + tag_len;
assert!(len < 2usize.pow(14)); // Fits in reserved space
@@ -860,33 +786,6 @@ pub const SHORT_RESERVED_BITS: u8 = 0x18;
pub const LONG_RESERVED_BITS: u8 = 0x0c;
const KEY_PHASE_BIT: u8 = 0x04;
/// Explicit congestion notification codepoint
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum EcnCodepoint {
ECT0 = 0b10,
ECT1 = 0b01,
CE = 0b11,
}
impl EcnCodepoint {
pub fn from_bits(x: u8) -> Option<Self> {
use self::EcnCodepoint::*;
Some(match x & 0b11 {
0b10 => ECT0,
0b01 => ECT1,
0b11 => CE,
_ => {
return None;
}
})
}
pub fn bits(self) -> u8 {
self as u8
}
}
/// Packet number space identifiers
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum SpaceId {
+313
View File
@@ -0,0 +1,313 @@
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Instant;
use std::{cmp, fmt};
use bytes::BytesMut;
use err_derive::Error;
use rand::Rng;
use slog::Logger;
use crate::connection::Timer;
use crate::packet::PartialDecode;
use crate::{crypto, varint, MAX_CID_SIZE, MIN_CID_SIZE};
/// Parameters governing the core QUIC state machine
///
/// This should be tuned to suit the application. In particular, window sizes for streams, stream
/// data, and overall connection data should be set differently depending on the expected round trip
/// time, link capacity, memory availability, and rate of stream creation. Tuning for higher
/// bandwidths and latencies increases worst-case memory consumption, but does not impair
/// performance at lower bandwidths and latencies. The default configuration is tuned for a 100Mbps
/// link with a 100ms round trip time, with remote endpoints opening at most 320 new streams per
/// second. Applications which do not require remotely-initiated streams should set the stream
/// windows to zero.
pub struct TransportConfig {
/// Maximum number of bidirectional streams that may be initiated by the peer but not yet
/// accepted locally
///
/// Must be nonzero for the peer to open any bidirectional streams.
///
/// Any number of streams may be in flight concurrently. However, to ensure predictable resource
/// use, the number of streams which the peer has initiated but which the local application has
/// not yet accepted will be kept below this threshold.
///
/// Because it takes at least one round trip for an endpoint to open a new stream and be
/// notified of its peer's flow control updates, this imposes a hard upper bound on the number
/// of streams that may be opened per round-trip. In other words, this should be set to at least
/// the desired number of streams opened per unit time, multiplied by the round trip time.
///
/// Note that worst-case memory use is directly proportional to `stream_window_bidi *
/// stream_receive_window`, with an upper bound proportional to `receive_window`.
pub stream_window_bidi: u64,
/// Variant of `stream_window_bidi` affecting unidirectional streams
pub stream_window_uni: u64,
/// Maximum duration of inactivity to accept before timing out the connection (ms).
///
/// The actual value used is the minimum of this and the peer's own idle timeout. 0 for none.
pub idle_timeout: u64,
/// Maximum number of bytes the peer may transmit without acknowledgement on any one stream
/// before becoming blocked.
///
/// This should be set to at least the expected connection latency multiplied by the maximum
/// desired throughput. Setting this smaller than `receive_window` helps ensure that a single
/// stream doesn't monopolize receive buffers, which may otherwise occur if the application
/// chooses not to read from a large stream for a time while still requiring data on other
/// streams.
pub stream_receive_window: u64,
/// Maximum number of bytes the peer may transmit across all streams of a connection before
/// becoming blocked.
///
/// This should be set to at least the expected connection latency multiplied by the maximum
/// desired throughput. Larger values can be useful to allow maximum throughput within a
/// stream while another is blocked.
pub receive_window: u64,
/// Maximum number of bytes to transmit to a peer without acknowledgment
///
/// Provides an upper bound on memory when communicating with peers that issue large amounts of
/// flow control credit. Endpoints that wish to handle large numbers of connections robustly
/// should take care to set this low enough to guarantee memory exhaustion does not occur if
/// every connection uses the entire window.
pub send_window: u64,
/// Maximum number of tail loss probes before an RTO fires.
pub max_tlps: u32,
/// Maximum reordering in packet number space before FACK style loss detection considers a
/// packet lost.
pub packet_threshold: u32,
/// Maximum reordering in time space before time based loss detection considers a packet lost.
/// 0.16 format, added to 1
pub time_threshold: u16,
/// The length of the peers delayed ack timer (μs).
pub delayed_ack_timeout: u64,
/// The RTT used before an RTT sample is taken (μs)
pub initial_rtt: u64,
/// The max packet size that was used for calculating default and minimum congestion windows.
pub max_datagram_size: u64,
/// Default limit on the amount of outstanding data in bytes.
///
/// Recommended value: `min(10 * max_datagram_size, max(2 * max_datagram_size, 14600))`
pub initial_window: u64,
/// Default minimum congestion window.
///
/// Recommended value: `2 * max_datagram_size`.
pub minimum_window: u64,
/// Reduction in congestion window when a new loss event is detected. 0.16 format
pub loss_reduction_factor: u16,
/// Number of consecutive PTOs after which network is considered to be experiencing persistent congestion.
pub persistent_congestion_threshold: u32,
/// Number of milliseconds of inactivity before sending a keep-alive packet
///
/// Keep-alive packets prevent an inactive but otherwise healthy connection from timing out.
///
/// 0 to disable, which is the default. Only one side of any given connection needs keep-alive
/// enabled for the connection to be preserved. Must be set lower than the idle_timeout of both
/// peers to be effective.
pub keep_alive_interval: u32,
}
impl Default for TransportConfig {
fn default() -> Self {
const EXPECTED_RTT: u64 = 100; // ms
const MAX_STREAM_BANDWIDTH: u64 = 12500 * 1000; // bytes/s
// Window size needed to avoid pipeline
// stalls
const STREAM_RWND: u64 = MAX_STREAM_BANDWIDTH / 1000 * EXPECTED_RTT;
const MAX_DATAGRAM_SIZE: u64 = 1200;
TransportConfig {
stream_window_bidi: 32,
stream_window_uni: 32,
idle_timeout: 10_000,
stream_receive_window: STREAM_RWND,
receive_window: 8 * STREAM_RWND,
send_window: 8 * STREAM_RWND,
max_tlps: 2,
packet_threshold: 3,
time_threshold: 0x2000, // 1/8
delayed_ack_timeout: 25 * 1000,
initial_rtt: EXPECTED_RTT as u64 * 1000,
max_datagram_size: MAX_DATAGRAM_SIZE,
initial_window: cmp::min(
10 * MAX_DATAGRAM_SIZE,
cmp::max(2 * MAX_DATAGRAM_SIZE, 14600),
),
minimum_window: 2 * MAX_DATAGRAM_SIZE,
loss_reduction_factor: 0x8000, // 1/2
persistent_congestion_threshold: 2,
keep_alive_interval: 0,
}
}
}
impl TransportConfig {
pub(crate) fn validate(&self, log: &Logger) -> Result<(), ConfigError> {
if let Some((name, _)) = [
("stream_window_bidi", self.stream_window_bidi),
("stream_window_uni", self.stream_window_uni),
("receive_window", self.receive_window),
("stream_receive_window", self.stream_receive_window),
("idle_timeout", self.idle_timeout),
]
.iter()
.find(|&&(_, x)| x > varint::MAX_VALUE)
{
return Err(ConfigError::VarIntBounds(name));
}
if self.idle_timeout != 0 && self.keep_alive_interval as u64 >= self.idle_timeout {
warn!(
log,
"keep-alive interval {} is ineffective due to lower idle timeout {}",
self.keep_alive_interval,
self.idle_timeout
);
}
Ok(())
}
}
/// Errors in the configuration of an endpoint
#[derive(Debug, Error)]
pub enum ConfigError {
/// The supplied configuration contained an invalid value
#[error(display = "illegal configuration value: {}", _0)]
IllegalValue(&'static str),
/// A configuration field that will be encoded as a variable-length integer exceeds the 0..2^62
/// range
#[error(display = "{} must be at most 2^62-1", _0)]
VarIntBounds(&'static str),
}
/// Events to be sent to the Connection
pub enum ConnectionEvent {
Datagram {
now: Instant,
remote: SocketAddr,
ecn: Option<EcnCodepoint>,
first_decode: PartialDecode,
remaining: Option<BytesMut>,
},
NewIdentifiers(Vec<(u64, ConnectionId)>),
Timer(Instant, Timer),
}
/// Events to be sent to the Endpoint
#[derive(Clone, Debug)]
pub enum EndpointEvent {
Closed {
remote: SocketAddr,
},
NeedIdentifiers,
/// Stop routing connection ID for this sequence number to this `Connection`
RetireConnectionId(u64),
}
/// Protocol-level identifier for a connection.
///
/// Mainly useful for identifying this connection's packets on the wire with tools like Wireshark.
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ConnectionId {
pub len: u8,
pub bytes: [u8; MAX_CID_SIZE],
}
impl ConnectionId {
pub fn new(bytes: &[u8]) -> Self {
debug_assert!(
bytes.is_empty() || (bytes.len() >= MIN_CID_SIZE && bytes.len() <= MAX_CID_SIZE)
);
let mut res = Self {
len: bytes.len() as u8,
bytes: [0; MAX_CID_SIZE],
};
res.bytes[..bytes.len()].clone_from_slice(&bytes);
res
}
pub fn random<R: Rng>(rng: &mut R, len: usize) -> Self {
debug_assert!(len <= MAX_CID_SIZE);
let mut res = Self {
len: len as u8,
bytes: [0; MAX_CID_SIZE],
};
let mut rng_bytes = [0; MAX_CID_SIZE];
rng.fill_bytes(&mut rng_bytes);
res.bytes[..len].clone_from_slice(&rng_bytes[..len]);
res
}
}
impl ::std::ops::Deref for ConnectionId {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes[0..self.len as usize]
}
}
impl ::std::ops::DerefMut for ConnectionId {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.bytes[0..self.len as usize]
}
}
impl fmt::Debug for ConnectionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.bytes[0..self.len as usize].fmt(f)
}
}
impl fmt::Display for ConnectionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.iter() {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl slog::Value for ConnectionId {
fn serialize(
&self,
_: &slog::Record<'_>,
key: slog::Key,
serializer: &mut dyn slog::Serializer,
) -> slog::Result {
serializer.emit_arguments(key, &format_args!("{}", self))
}
}
/// Explicit congestion notification codepoint
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum EcnCodepoint {
ECT0 = 0b10,
ECT1 = 0b01,
CE = 0b11,
}
impl EcnCodepoint {
pub fn from_bits(x: u8) -> Option<Self> {
use self::EcnCodepoint::*;
Some(match x & 0b11 {
0b10 => ECT0,
0b01 => ECT1,
0b11 => CE,
_ => {
return None;
}
})
}
pub fn bits(self) -> u8 {
self as u8
}
}
#[derive(Clone)]
pub struct ClientConfig {
pub server_name: String,
pub tls_config: Arc<crypto::ClientConfig>,
}
+1 -1
View File
@@ -4,7 +4,7 @@ use bytes::{Buf, BufMut};
use err_derive::Error;
use crate::coding::{BufExt, BufMutExt, UnexpectedEnd};
use crate::packet::ConnectionId;
use crate::shared::ConnectionId;
use crate::{
varint, Side, TransportConfig, TransportError, MAX_CID_SIZE, MIN_CID_SIZE, RESET_TOKEN_SIZE,
VERSION,