use bytes::{Buf, BufMut};
use coding::{BufExt, BufMutExt};
use {VERSION, Side};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct TransportParameters {
pub initial_max_stream_data: u32,
pub initial_max_data: u32,
pub idle_timeout: u16,
pub stateless_reset_token: Option<[u8; 16]>,
pub initial_max_streams_bidi: u16,
pub initial_max_streams_uni: u16,
pub max_packet_size: Option<u16>,
pub ack_delay_exponent: u8,
}
const DEFAULT_ACK_DELAY_EXPONENT: u8 = 3;
impl Default for TransportParameters {
fn default() -> Self { Self {
initial_max_stream_data: 64 * 1024,
initial_max_data: 64 * 1024,
idle_timeout: 10,
stateless_reset_token: None,
initial_max_streams_bidi: 0,
initial_max_streams_uni: 0,
max_packet_size: None,
ack_delay_exponent: DEFAULT_ACK_DELAY_EXPONENT,
}}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Fail)]
pub enum Error {
#[fail(display = "version negotiation was tampered with")]
VersionNegotiation,
#[fail(display = "parameter had illegal value")]
IllegalValue,
#[fail(display = "parameters were malformed")]
Malformed,
}
impl TransportParameters {
pub fn write<W: BufMut>(&self, side: Side, w: &mut W) {
if side == Side::Server {
w.write::<u32>(VERSION); w.write::<u8>(8); w.write::<u32>(0x0a1a2a3a); w.write::<u32>(VERSION); } else {
w.write::<u32>(VERSION); }
let mut buf = Vec::with_capacity(22);
buf.write::<u16>(0x0000);
buf.write::<u16>(4);
buf.write::<u32>(self.initial_max_stream_data);
buf.write::<u16>(0x0001);
buf.write::<u16>(4);
buf.write::<u32>(self.initial_max_data);
buf.write::<u16>(0x0003);
buf.write::<u16>(2);
buf.write::<u16>(self.idle_timeout);
if let Some(ref x) = self.stateless_reset_token {
buf.write::<u16>(0x0006);
buf.write::<u16>(16);
buf.put_slice(x);
}
if self.initial_max_streams_bidi != 0 {
buf.write::<u16>(0x0002);
buf.write::<u16>(2);
buf.write::<u16>(self.initial_max_streams_bidi);
}
if self.initial_max_streams_uni != 0 {
buf.write::<u16>(0x0008);
buf.write::<u16>(2);
buf.write::<u16>(self.initial_max_streams_uni);
}
if let Some(x) = self.max_packet_size {
buf.write::<u16>(0x0005);
buf.write::<u16>(2);
buf.write::<u16>(x);
}
if self.ack_delay_exponent != DEFAULT_ACK_DELAY_EXPONENT {
buf.write::<u16>(0x0007);
buf.write::<u16>(1);
buf.write::<u8>(self.ack_delay_exponent);
}
w.write::<u16>(buf.len() as u16);
w.put_slice(&buf);
}
pub fn read<R: Buf>(side: Side, r: &mut R) -> Result<Self, Error> {
if side == Side::Server {
if r.remaining() < 26 { return Err(Error::Malformed); }
r.get::<u32>().unwrap();
} else {
if r.remaining() < 31 { return Err(Error::Malformed); }
let negotiated = r.get::<u32>().unwrap();
if negotiated != VERSION { return Err(Error::VersionNegotiation); }
let supported_bytes = r.get::<u8>().unwrap();
if supported_bytes < 4 || supported_bytes > 252 || supported_bytes % 4 != 0 {
return Err(Error::Malformed);
}
let mut found = false;
for _ in 0..(supported_bytes / 4) {
found |= r.get::<u32>().unwrap() == negotiated;
}
if !found { return Err(Error::VersionNegotiation); }
}
let mut initial_max_stream_data = false;
let mut initial_max_data = false;
let mut idle_timeout = false;
let mut initial_max_streams_bidi = false;
let mut initial_max_streams_uni = false;
let mut ack_delay_exponent = false;
let mut params = Self::default();
let params_len = r.get::<u16>().unwrap();
if params_len as usize != r.remaining() { return Err(Error::Malformed); }
while r.has_remaining() {
if r.remaining() < 4 { return Err(Error::Malformed); }
let id = r.get::<u16>().unwrap();
let len = r.get::<u16>().unwrap();
if r.remaining() < len as usize { return Err(Error::Malformed); }
match id {
0x0000 => {
if len != 4 || initial_max_stream_data { return Err(Error::Malformed); }
params.initial_max_stream_data = r.get::<u32>().unwrap();
initial_max_stream_data = true;
}
0x0001 => {
if len != 4 || initial_max_data { return Err(Error::Malformed); }
params.initial_max_data = r.get::<u32>().unwrap();
initial_max_data = true;
}
0x0003 => {
if len != 2 || idle_timeout { return Err(Error::Malformed); }
params.idle_timeout = r.get::<u16>().unwrap();
idle_timeout = true;
}
0x0006 => {
if len != 16 || params.stateless_reset_token.is_some() { return Err(Error::Malformed); }
let mut tok = [0; 16];
r.copy_to_slice(&mut tok);
params.stateless_reset_token = Some(tok);
}
0x0002 => {
if len != 2 || initial_max_streams_bidi { return Err(Error::Malformed); }
params.initial_max_streams_bidi = r.get::<u16>().unwrap();
initial_max_streams_bidi = true;
}
0x0008 => {
if len != 2 || initial_max_streams_uni { return Err(Error::Malformed); }
params.initial_max_streams_uni = r.get::<u16>().unwrap();
initial_max_streams_uni = true;
}
0x0005 => {
if len != 2 || params.max_packet_size.is_some() { return Err(Error::Malformed); }
params.max_packet_size = Some(r.get::<u16>().unwrap());
}
0x0007 => {
if len != 1 || ack_delay_exponent { return Err(Error::Malformed); }
params.ack_delay_exponent = r.get::<u8>().unwrap();
ack_delay_exponent = true;
if params.ack_delay_exponent > 20 { return Err(Error::IllegalValue); }
}
_ => r.advance(len as usize),
}
}
if initial_max_stream_data && initial_max_data && idle_timeout {
Ok(params)
} else {
Err(Error::IllegalValue)
}
}
}
#[cfg(test)]
mod test {
use super::*;
use bytes::IntoBuf;
#[test]
fn coding() {
let mut buf = Vec::new();
let params = TransportParameters {
initial_max_streams_bidi: 16,
initial_max_streams_uni: 16,
ack_delay_exponent: 2,
max_packet_size: Some(1200),
..TransportParameters::default()
};
params.write(Side::Client, &mut buf);
assert_eq!(TransportParameters::read(Side::Server, &mut buf.into_buf()).unwrap(), params);
}
}