ok, starting to look good

This commit is contained in:
Oliver Gould
2017-07-13 02:24:36 +00:00
parent 41ffd1d44f
commit cbd3e17283
9 changed files with 168 additions and 130 deletions

View File

@@ -1,10 +1,11 @@
use FrameSize;
use frame::{util, Frame, Head, Error, StreamId, Kind}; use frame::{util, Frame, Head, Error, StreamId, Kind};
use bytes::{BufMut, Bytes, Buf}; use bytes::{BufMut, Bytes, Buf};
#[derive(Debug)] #[derive(Debug)]
pub struct Data<T = Bytes> { pub struct Data<T = Bytes> {
stream_id: StreamId, stream_id: StreamId,
data_len: usize, data_len: FrameSize,
data: T, data: T,
flags: DataFlag, flags: DataFlag,
pad_len: Option<u8>, pad_len: Option<u8>,
@@ -29,7 +30,7 @@ impl Data<Bytes> {
}; };
Ok(Data { Ok(Data {
stream_id: head.stream_id(), stream_id: head.stream_id(),
data_len: payload.len(), data_len: payload.len() as FrameSize,
data: payload, data: payload,
flags: flags, flags: flags,
pad_len: pad_len, pad_len: pad_len,
@@ -54,7 +55,7 @@ impl<T> Data<T> {
Head::new(Kind::Data, self.flags.into(), self.stream_id) Head::new(Kind::Data, self.flags.into(), self.stream_id)
} }
pub fn len(&self) -> usize { pub fn len(&self) -> FrameSize {
self.data_len self.data_len
} }
@@ -66,20 +67,21 @@ impl<T> Data<T> {
impl<T: Buf> Data<T> { impl<T: Buf> Data<T> {
pub fn from_buf(stream_id: StreamId, data: T) -> Self { pub fn from_buf(stream_id: StreamId, data: T) -> Self {
Data { Data {
stream_id: stream_id, stream_id,
data_len: data.remaining(), data_len: data.remaining() as FrameSize,
data: data, data,
flags: DataFlag::default(), flags: DataFlag::default(),
pad_len: None, pad_len: None,
} }
} }
pub fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) { pub fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) {
if self.len() > dst.remaining_mut() { let len = self.len() as usize;
if len > dst.remaining_mut() {
unimplemented!(); unimplemented!();
} }
self.head().encode(self.len(), dst); self.head().encode(len, dst);
dst.put(&mut self.data); dst.put(&mut self.data);
} }
} }

View File

@@ -1,3 +1,4 @@
use FrameSize;
use frame::{Frame, Error, Head, Kind, StreamId}; use frame::{Frame, Error, Head, Kind, StreamId};
use bytes::{BytesMut, BufMut, BigEndian}; use bytes::{BytesMut, BufMut, BigEndian};
@@ -45,7 +46,7 @@ const ACK: u8 = 0x1;
const ALL: u8 = ACK; const ALL: u8 = ACK;
pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096; pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096;
pub const DEFAULT_MAX_FRAME_SIZE: usize = 16_384; pub const DEFAULT_MAX_FRAME_SIZE: FrameSize = 16_384;
// ===== impl Settings ===== // ===== impl Settings =====

View File

@@ -40,6 +40,8 @@ pub use proto::Connection;
use bytes::Bytes; use bytes::Bytes;
pub type FrameSize = u32;
/// An H2 connection frame /// An H2 connection frame
#[derive(Debug)] #[derive(Debug)]
pub enum Frame<T, B = Bytes> { pub enum Frame<T, B = Bytes> {
@@ -52,7 +54,7 @@ pub enum Frame<T, B = Bytes> {
id: StreamId, id: StreamId,
data: B, data: B,
/// TODO figure out how to make this a requirement on `B` /// TODO figure out how to make this a requirement on `B`
data_len: usize, data_len: FrameSize,
end_of_stream: bool, end_of_stream: bool,
}, },
Trailers { Trailers {

View File

@@ -1,8 +1,8 @@
use Frame; use {Frame, FrameSize};
use client::Client; use client::Client;
use error::{self, ConnectionError}; use error::{self, ConnectionError};
use frame::{self, StreamId}; use frame::{self, StreamId};
use proto::{self, Peer, ReadySink, State, FlowController}; use proto::{self, Peer, ReadySink, State, FlowController, WindowSize};
use server::Server; use server::Server;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
@@ -26,12 +26,12 @@ pub struct Connection<T, P, B: IntoBuf = Bytes> {
peer: PhantomData<P>, peer: PhantomData<P>,
/// Tracks connection-level flow control. /// Tracks connection-level flow control.
local_flow_controller: FlowController, recv_flow_controller: FlowController,
remote_flow_controller: FlowController, send_flow_controller: FlowController,
pending_local_window_update: Option<frame::WindowUpdate>, pending_send_window_update: Option<frame::WindowUpdate>,
blocked_remote_window_update: Option<task::Task>, blocked_recv_window_update: Option<task::Task>,
} }
type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>; type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>;
@@ -42,37 +42,47 @@ pub fn new<T, P, B>(transport: proto::Inner<T, B::Buf>)
P: Peer, P: Peer,
B: IntoBuf, B: IntoBuf,
{ {
let local_window_size = transport.local_settings().initial_window_size(); let recv_window_size = transport.local_settings().initial_window_size();
let remote_window_size = transport.remote_settings().initial_window_size(); let send_window_size = transport.remote_settings().initial_window_size();
Connection { Connection {
inner: transport, inner: transport,
streams: StreamMap::default(), streams: StreamMap::default(),
peer: PhantomData, peer: PhantomData,
local_flow_controller: FlowController::new(local_window_size), recv_flow_controller: FlowController::new(recv_window_size),
remote_flow_controller: FlowController::new(remote_window_size), send_flow_controller: FlowController::new(send_window_size),
pending_local_window_update: None, pending_send_window_update: None,
blocked_remote_window_update: None, blocked_recv_window_update: None,
} }
} }
impl<T, P, B: IntoBuf> Connection<T, P, B> { impl<T, P, B: IntoBuf> Connection<T, P, B> {
pub fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<u32, ConnectionError> { #[inline]
if id.is_zero() { fn claim_connection_recv_window(&mut self, len: WindowSize) -> Result<(), ConnectionError> {
return match self.local_flow_controller.take_window_update() { self.recv_flow_controller.claim_window(len)
Some(incr) => Ok(Async::Ready(incr)), .map_err(|_| error::Reason::FlowControlError.into())
None => { }
self.blocked_remote_window_update = Some(task::current());
Ok(Async::NotReady)
}
};
}
match self.streams.get_mut(&id).and_then(|mut s| s.take_remote_window_update()) { #[inline]
fn claim_connection_send_window(&mut self, len: WindowSize) -> Result<(), ConnectionError> {
self.send_flow_controller.claim_window(len)
.map_err(|_| error::Reason::FlowControlError.into())
}
// TODO check max frame size
pub fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<WindowSize, ConnectionError> {
let added = if id.is_zero() {
self.send_flow_controller.take_window_update()
} else {
self.streams.get_mut(&id).and_then(|mut s| s.take_recv_window_update())
};
match added {
Some(incr) => Ok(Async::Ready(incr)), Some(incr) => Ok(Async::Ready(incr)),
None => { None => {
self.blocked_remote_window_update = Some(task::current()); self.blocked_recv_window_update = Some(task::current());
Ok(Async::NotReady) Ok(Async::NotReady)
} }
} }
@@ -83,18 +93,18 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
/// ///
/// Connection window updates (StreamId=0) and stream window must be published /// Connection window updates (StreamId=0) and stream window must be published
/// distinctly. /// distinctly.
pub fn init_send_window_update(&mut self, id: StreamId, incr: u32) { pub fn init_send_window_update(&mut self, id: StreamId, incr: WindowSize) {
assert!(self.pending_local_window_update.is_none()); assert!(self.pending_send_window_update.is_none());
let added = if id.is_zero() { let added = if id.is_zero() {
self.remote_flow_controller.add_to_window(incr); self.send_flow_controller.add_to_window(incr);
self.remote_flow_controller.take_window_update() self.send_flow_controller.take_window_update()
} else { } else {
self.streams.get_mut(&id).and_then(|mut s| s.send_window_update(incr)) self.streams.get_mut(&id).and_then(|mut s| s.send_window_update(incr))
}; };
if let Some(added) = added { if let Some(added) = added {
self.pending_local_window_update = Some(frame::WindowUpdate::new(id, added)); self.pending_send_window_update = Some(frame::WindowUpdate::new(id, added));
} }
} }
@@ -102,9 +112,9 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
/// ///
/// Connection window updates (id=0) and stream window updates are advertised /// Connection window updates (id=0) and stream window updates are advertised
/// distinctly. /// distinctly.
fn recv_window_update(&mut self, id: StreamId, incr: u32) { fn recv_window_update(&mut self, id: StreamId, incr: WindowSize) {
if id.is_zero() { if id.is_zero() {
return self.remote_flow_controller.add_to_window(incr); return self.recv_flow_controller.add_to_window(incr);
} }
if let Some(mut s) = self.streams.get_mut(&id) { if let Some(mut s) = self.streams.get_mut(&id) {
@@ -116,28 +126,34 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
impl<T, P, B> Connection<T, P, B> impl<T, P, B> Connection<T, P, B>
where T: AsyncRead + AsyncWrite, where T: AsyncRead + AsyncWrite,
P: Peer, P: Peer,
B: IntoBuf, B: IntoBuf
{ {
/// Attempts to send a window update to the remote.
fn poll_send_window_update(&mut self) -> Poll<(), ConnectionError> { fn poll_send_window_update(&mut self) -> Poll<(), ConnectionError> {
if let Some(f) = self.pending_local_window_update.take() { if let Some(f) = self.pending_send_window_update.take() {
if self.inner.start_send(f.into())?.is_not_ready() { if self.inner.start_send(f.into())?.is_not_ready() {
self.pending_local_window_update = Some(f); self.pending_send_window_update = Some(f);
return Ok(Async::NotReady); return Ok(Async::NotReady);
} }
} }
Ok(Async::Ready(())) Ok(Async::Ready(()))
} }
}
// Note: this is bytes-specific for now so that we can know the payload's length.
impl<T, P> Connection<T, P, Bytes>
where T: AsyncRead + AsyncWrite,
P: Peer,
{
pub fn send_data(self, pub fn send_data(self,
id: StreamId, id: StreamId,
data: B, data: Bytes,
data_len: usize,
end_of_stream: bool) end_of_stream: bool)
-> sink::Send<Self> -> sink::Send<Self>
{ {
self.send(Frame::Data { self.send(Frame::Data {
id, id,
data_len, data_len: data.len() as FrameSize,
data, data,
end_of_stream, end_of_stream,
}) })
@@ -196,10 +212,15 @@ impl<T, P, B> Stream for Connection<T, P, B>
let frame = match try!(self.inner.poll()) { let frame = match try!(self.inner.poll()) {
Async::Ready(f) => f, Async::Ready(f) => f,
Async::NotReady => { Async::NotReady => {
// Because receiving new frames may depend on ensuring that the // Receiving new frames may depend on ensuring that the write buffer
// write buffer is clear, `poll_complete` is called here. // is clear (e.g. if window updates need to be sent), so `poll_ready`
let _ = try!(self.poll_complete()); // is called here.
return Ok(Async::NotReady); try_ready!(self.poll_ready());
// If the snder sink is ready, we attempt to poll the underlying
// stream once more because it, may have been made ready by flushing
// the sink.
try_ready!(self.inner.poll())
} }
}; };
@@ -234,22 +255,30 @@ impl<T, P, B> Stream for Connection<T, P, B>
} }
Some(Data(v)) => { Some(Data(v)) => {
let stream_id = v.stream_id(); let id = v.stream_id();
let end_of_stream = v.is_end_stream(); let end_of_stream = v.is_end_stream();
match self.streams.get_mut(&stream_id) {
self.claim_connection_recv_window(v.len())?;
match self.streams.get_mut(&id) {
None => return Err(error::Reason::ProtocolError.into()), None => return Err(error::Reason::ProtocolError.into()),
Some(state) => try!(state.recv_data(end_of_stream, v.len())), Some(state) => state.recv_data(end_of_stream, v.len())?,
} }
Frame::Data { Frame::Data {
id: stream_id, id,
end_of_stream,
data_len: v.len(), data_len: v.len(),
data: v.into_payload(), data: v.into_payload(),
end_of_stream,
} }
} }
Some(WindowUpdate(v)) => { Some(WindowUpdate(v)) => {
// When a window update is read from the remote, apply that update to
// the proper stream.
self.recv_window_update(v.stream_id(), v.size_increment()); self.recv_window_update(v.stream_id(), v.size_increment());
// There's nothing to return yet, so continue attempting to read
// additional frames.
continue; continue;
} }
@@ -278,11 +307,11 @@ impl<T, P, B> Sink for Connection<T, P, B>
// First ensure that the upstream can process a new item. This ensures, for // First ensure that the upstream can process a new item. This ensures, for
// instance, that any pending local window updates have been sent to the remote // instance, that any pending local window updates have been sent to the remote
// before sending any other frames. // before sending any other (i.e. DATA) frames.
if try!(self.poll_ready()).is_not_ready() { if try!(self.poll_ready()).is_not_ready() {
return Ok(AsyncSink::NotReady(item)); return Ok(AsyncSink::NotReady(item));
} }
assert!(self.pending_local_window_update.is_none()); assert!(self.pending_send_window_update.is_none());
match item { match item {
Frame::Headers { id, headers, end_of_stream } => { Frame::Headers { id, headers, end_of_stream } => {
@@ -324,6 +353,8 @@ impl<T, P, B> Sink for Connection<T, P, B>
} }
Frame::Data { id, data, data_len, end_of_stream } => { Frame::Data { id, data, data_len, end_of_stream } => {
self.claim_connection_send_window(data_len)?;
// The stream must be initialized at this point // The stream must be initialized at this point
match self.streams.get_mut(&id) { match self.streams.get_mut(&id) {
None => return Err(error::User::InactiveStreamId.into()), None => return Err(error::User::InactiveStreamId.into()),
@@ -331,14 +362,15 @@ impl<T, P, B> Sink for Connection<T, P, B>
} }
let mut frame = frame::Data::from_buf(id, data.into_buf()); let mut frame = frame::Data::from_buf(id, data.into_buf());
if end_of_stream { if end_of_stream {
frame.set_end_stream(); frame.set_end_stream();
} }
let res = try!(self.inner.start_send(frame.into())); let res = try!(self.inner.start_send(frame.into()));
// poll_ready has already been called. // poll_ready has already been called.
assert!(res.is_ready()); assert!(res.is_ready());
Ok(AsyncSink::Ready) Ok(AsyncSink::Ready)
} }

View File

@@ -1,17 +1,19 @@
use proto::WindowSize;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct WindowUnderflow; pub struct WindowUnderflow;
pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 65_535; pub const DEFAULT_INITIAL_WINDOW_SIZE: WindowSize = 65_535;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct FlowController { pub struct FlowController {
/// Amount that may be claimed. /// Amount that may be claimed.
window_size: u32, window_size: WindowSize,
/// Amount to be removed by future increments. /// Amount to be removed by future increments.
underflow: u32, underflow: WindowSize,
/// The amount that has been incremented but not yet advertised (to the application or /// The amount that has been incremented but not yet advertised (to the application or
/// the remote). /// the remote).
next_window_update: u32, next_window_update: WindowSize,
} }
impl Default for FlowController { impl Default for FlowController {
@@ -21,7 +23,7 @@ impl Default for FlowController {
} }
impl FlowController { impl FlowController {
pub fn new(window_size: u32) -> FlowController { pub fn new(window_size: WindowSize) -> FlowController {
FlowController { FlowController {
window_size, window_size,
underflow: 0, underflow: 0,
@@ -29,19 +31,15 @@ impl FlowController {
} }
} }
pub fn window_size(&self) -> u32 {
self.window_size
}
/// Reduce future capacity of the window. /// Reduce future capacity of the window.
/// ///
/// This accomodates updates to SETTINGS_INITIAL_WINDOW_SIZE. /// This accomodates updates to SETTINGS_INITIAL_WINDOW_SIZE.
pub fn shrink_window(&mut self, decr: u32) { pub fn shrink_window(&mut self, decr: WindowSize) {
self.underflow += decr; self.underflow += decr;
} }
/// Claim the provided amount from the window, if there is enough space. /// Claim the provided amount from the window, if there is enough space.
pub fn claim_window(&mut self, sz: u32) -> Result<(), WindowUnderflow> { pub fn claim_window(&mut self, sz: WindowSize) -> Result<(), WindowUnderflow> {
if self.window_size < sz { if self.window_size < sz {
return Err(WindowUnderflow); return Err(WindowUnderflow);
} }
@@ -51,7 +49,7 @@ impl FlowController {
} }
/// Applies a window increment immediately. /// Applies a window increment immediately.
pub fn add_to_window(&mut self, sz: u32) { pub fn add_to_window(&mut self, sz: WindowSize) {
if sz <= self.underflow { if sz <= self.underflow {
self.underflow -= sz; self.underflow -= sz;
return; return;
@@ -64,7 +62,7 @@ impl FlowController {
} }
/// Obtains and clears an unadvertised window update. /// Obtains and clears an unadvertised window update.
pub fn take_window_update(&mut self) -> Option<u32> { pub fn take_window_update(&mut self) -> Option<WindowSize> {
if self.next_window_update == 0 { if self.next_window_update == 0 {
return None; return None;
} }

View File

@@ -46,12 +46,24 @@ impl<T> FramedRead<T> {
unimplemented!(); unimplemented!();
} }
let frame = match head.kind() { let kind = head.kind();
debug!("received {:?}", kind);
let frame = match kind {
Kind::Settings => {
frame::Settings::load(head, &bytes[frame::HEADER_LEN..])?.into()
}
Kind::Ping => {
frame::Ping::load(head, &bytes[frame::HEADER_LEN..])?.into()
}
Kind::WindowUpdate => {
frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..])?.into()
}
Kind::Data => { Kind::Data => {
let _ = bytes.split_to(frame::HEADER_LEN); let _ = bytes.split_to(frame::HEADER_LEN);
let frame = try!(frame::Data::load(head, bytes)); frame::Data::load(head, bytes)?.into()
frame.into()
} }
Kind::Headers => { Kind::Headers => {
let mut buf = Cursor::new(bytes); let mut buf = Cursor::new(bytes);
buf.set_position(frame::HEADER_LEN as u64); buf.set_position(frame::HEADER_LEN as u64);
@@ -67,41 +79,25 @@ impl<T> FramedRead<T> {
frame.into() frame.into()
} }
Kind::Priority => unimplemented!(),
// TODO
Kind::Reset => { Kind::Reset => {
let frame = try!(frame::Reset::load(head, &bytes[frame::HEADER_LEN..])); let _todo = try!(frame::Reset::load(head, &bytes[frame::HEADER_LEN..]));
debug!("decoded; frame={:?}", frame); unimplemented!();
// TODO: implement
return Ok(None);
}
Kind::Settings => {
let frame = try!(frame::Settings::load(head, &bytes[frame::HEADER_LEN..]));
frame.into()
}
Kind::PushPromise => {
debug!("received PUSH_PROMISE");
// TODO: implement
return Ok(None);
}
Kind::Ping => {
try!(frame::Ping::load(head, &bytes[frame::HEADER_LEN..])).into()
} }
Kind::GoAway => { Kind::GoAway => {
let frame = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..])); let _todo = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..]));
debug!("decoded; frame={:?}", frame);
unimplemented!(); unimplemented!();
} }
Kind::WindowUpdate => { Kind::PushPromise |
// TODO: IMPLEMENT Kind::Priority |
let frame = try!(frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..])); Kind::Continuation |
debug!("decoded; frame={:?}", frame); Kind::Unknown => {
return Ok(None); unimplemented!()
},
Kind::Continuation => {
unimplemented!();
} }
Kind::Unknown => return Ok(None),
}; };
debug!("decoded; frame={:?}", frame);
Ok(Some(frame)) Ok(Some(frame))
} }

View File

@@ -1,4 +1,4 @@
use {hpack, ConnectionError}; use {hpack, ConnectionError, FrameSize};
use frame::{self, Frame}; use frame::{self, Frame};
use proto::ReadySink; use proto::ReadySink;
@@ -24,7 +24,7 @@ pub struct FramedWrite<T, B> {
next: Option<Next<B>>, next: Option<Next<B>>,
/// Max frame size, this is specified by the peer /// Max frame size, this is specified by the peer
max_frame_size: usize, max_frame_size: FrameSize,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -74,7 +74,7 @@ impl<T, B> FramedWrite<T, B>
} }
fn frame_len(&self, data: &frame::Data<B>) -> usize { fn frame_len(&self, data: &frame::Data<B>) -> usize {
cmp::min(self.max_frame_size, data.len()) cmp::min(self.max_frame_size, data.len()) as usize
} }
} }
@@ -94,7 +94,7 @@ impl<T, B> Sink for FramedWrite<T, B>
match item { match item {
Frame::Data(mut v) => { Frame::Data(mut v) => {
if v.len() >= CHAIN_THRESHOLD { if v.len() >= (CHAIN_THRESHOLD as FrameSize) {
let head = v.head(); let head = v.head();
let len = self.frame_len(&v); let len = self.frame_len(&v);

View File

@@ -35,6 +35,9 @@ type Framed<T, B> =
FramedRead< FramedRead<
FramedWrite<T, B>>; FramedWrite<T, B>>;
pub type WindowSize = u32;
/// Create a full H2 transport from an I/O handle. /// Create a full H2 transport from an I/O handle.
/// ///
/// This is called as the final step of the client handshake future. /// This is called as the final step of the client handshake future.

View File

@@ -1,4 +1,4 @@
use Peer; use {FrameSize, Peer};
use error::ConnectionError; use error::ConnectionError;
use error::Reason::*; use error::Reason::*;
use error::User::*; use error::User::*;
@@ -102,7 +102,7 @@ impl State {
} }
} }
pub fn take_remote_window_update(&mut self) -> Option<u32> { pub fn take_recv_window_update(&mut self) -> Option<u32> {
use self::State::*; use self::State::*;
use self::PeerState::*; use self::PeerState::*;
@@ -129,7 +129,7 @@ impl State {
/// > flow-control window and MUST NOT send new flow-controlled frames until it /// > flow-control window and MUST NOT send new flow-controlled frames until it
/// > receives WINDOW_UPDATE frames that cause the flow-control window to become /// > receives WINDOW_UPDATE frames that cause the flow-control window to become
/// > positive. /// > positive.
pub fn update_remote_initial_window_size(&mut self, old: u32, new: u32) { pub fn update_initial_recv_window_size(&mut self, old: u32, new: u32) {
use self::State::*; use self::State::*;
use self::PeerState::*; use self::PeerState::*;
@@ -147,7 +147,7 @@ impl State {
} }
/// TODO Connection doesn't have an API for local updates yet. /// TODO Connection doesn't have an API for local updates yet.
pub fn update_local_initial_window_size(&mut self, _old: u32, _new: u32) { pub fn update_initial_send_window_size(&mut self, _old: u32, _new: u32) {
//use self::State::*; //use self::State::*;
//use self::PeerState::*; //use self::PeerState::*;
unimplemented!() unimplemented!()
@@ -159,7 +159,7 @@ impl State {
/// stream id. `Err` is returned if this is an invalid state transition. /// stream id. `Err` is returned if this is an invalid state transition.
pub fn recv_headers<P: Peer>(&mut self, pub fn recv_headers<P: Peer>(&mut self,
eos: bool, eos: bool,
remote_window_size: u32) initial_recv_window_size: u32)
-> Result<bool, ConnectionError> -> Result<bool, ConnectionError>
{ {
use self::State::*; use self::State::*;
@@ -171,7 +171,7 @@ impl State {
if eos { if eos {
*self = HalfClosedRemote(local); *self = HalfClosedRemote(local);
} else { } else {
*self = Open { local, remote: Data(FlowController::new(remote_window_size)) }; *self = Open { local, remote: Data(FlowController::new(initial_recv_window_size)) };
} }
Ok(true) Ok(true)
} }
@@ -191,7 +191,7 @@ impl State {
if eos { if eos {
*self = Closed; *self = Closed;
} else { } else {
*self = HalfClosedLocal(Data(FlowController::new(remote_window_size))); *self = HalfClosedLocal(Data(FlowController::new(initial_recv_window_size)));
}; };
Ok(false) Ok(false)
} }
@@ -204,22 +204,22 @@ impl State {
} }
} }
pub fn recv_data(&mut self, eos: bool, len: usize) -> Result<(), ConnectionError> { pub fn recv_data(&mut self, eos: bool, len: FrameSize) -> Result<(), ConnectionError> {
use self::State::*; use self::State::*;
match *self { match *self {
Open { local, remote } => { Open { local, mut remote } => {
try!(remote.check_is_data(ProtocolError.into())); try!(remote.check_is_data(ProtocolError.into()));
try!(remote.check_window_size(len, FlowControlError.into())); try!(remote.claim_window_size(len, FlowControlError.into()));
if eos { if eos {
*self = HalfClosedRemote(local); *self = HalfClosedRemote(local);
} }
Ok(()) Ok(())
} }
HalfClosedLocal(remote) => { HalfClosedLocal(mut remote) => {
try!(remote.check_is_data(ProtocolError.into())); try!(remote.check_is_data(ProtocolError.into()));
try!(remote.check_window_size(len, FlowControlError.into())); try!(remote.claim_window_size(len, FlowControlError.into()));
if eos { if eos {
*self = Closed; *self = Closed;
} }
@@ -238,7 +238,11 @@ impl State {
/// ///
/// Returns true if this state transition results in initializing the stream /// Returns true if this state transition results in initializing the stream
/// id. `Err` is returned if this is an invalid state transition. /// id. `Err` is returned if this is an invalid state transition.
pub fn send_headers<P: Peer>(&mut self, eos: bool, local_window_size: u32) -> Result<bool, ConnectionError> { pub fn send_headers<P: Peer>(&mut self,
eos: bool,
initial_send_window_size: u32)
-> Result<bool, ConnectionError>
{
use self::State::*; use self::State::*;
use self::PeerState::*; use self::PeerState::*;
@@ -248,7 +252,7 @@ impl State {
HalfClosedLocal(Headers) HalfClosedLocal(Headers)
} else { } else {
Open { Open {
local: Data(FlowController::new(local_window_size)), local: Data(FlowController::new(initial_send_window_size)),
remote: Headers, remote: Headers,
} }
}; };
@@ -262,7 +266,7 @@ impl State {
*self = if eos { *self = if eos {
HalfClosedLocal(remote) HalfClosedLocal(remote)
} else { } else {
let local = Data(FlowController::new(local_window_size)); let local = Data(FlowController::new(initial_send_window_size));
Open { local, remote } Open { local, remote }
}; };
@@ -275,7 +279,7 @@ impl State {
*self = if eos { *self = if eos {
Closed Closed
} else { } else {
HalfClosedRemote(Data(FlowController::new(local_window_size))) HalfClosedRemote(Data(FlowController::new(initial_send_window_size)))
}; };
Ok(false) Ok(false)
@@ -289,22 +293,22 @@ impl State {
} }
} }
pub fn send_data(&mut self, eos: bool, len: usize) -> Result<(), ConnectionError> { pub fn send_data(&mut self, eos: bool, len: FrameSize) -> Result<(), ConnectionError> {
use self::State::*; use self::State::*;
match *self { match *self {
Open { local, remote } => { Open { mut local, remote } => {
try!(local.check_is_data(UnexpectedFrameType.into())); try!(local.check_is_data(UnexpectedFrameType.into()));
try!(local.check_window_size(len, FlowControlViolation.into())); try!(local.claim_window_size(len, FlowControlViolation.into()));
if eos { if eos {
*self = HalfClosedLocal(remote); *self = HalfClosedLocal(remote);
} }
Ok(()) Ok(())
} }
HalfClosedRemote(local) => { HalfClosedRemote(mut local) => {
try!(local.check_is_data(UnexpectedFrameType.into())); try!(local.check_is_data(UnexpectedFrameType.into()));
try!(local.check_window_size(len, FlowControlViolation.into())); try!(local.claim_window_size(len, FlowControlViolation.into()));
if eos { if eos {
*self = Closed; *self = Closed;
} }
@@ -353,10 +357,10 @@ impl PeerState {
} }
#[inline] #[inline]
fn check_window_size(&self, len: usize, err: ConnectionError) -> Result<(), ConnectionError> { fn claim_window_size(&mut self, sz: FrameSize, err: ConnectionError) -> Result<(), ConnectionError> {
use self::PeerState::*; use self::PeerState::*;
match self { match self {
&Data(ref fc) if len <= fc.window_size() as usize=> Ok(()), &mut Data(ref mut fc) => fc.claim_window(sz).map_err(|_| err),
_ => Err(err), _ => Err(err),
} }
} }