wire up flow control polling through connection
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use {ConnectionError, Frame, FrameSize};
|
use {ConnectionError, Frame, FrameSize};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use frame::{self, StreamId};
|
use frame::{self, StreamId};
|
||||||
use proto::{self, Peer, ReadySink, WindowSize};
|
use proto::{self, Peer, ReadySink, FlowTransporter, WindowSize};
|
||||||
use server::Server;
|
use server::Server;
|
||||||
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
@@ -32,44 +32,22 @@ pub fn new<T, P, B>(transport: proto::Transport<T, P, B::Buf>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
impl<T, P, B> Connection<T, P, B>
|
||||||
|
where T: FlowTransporter,
|
||||||
|
B: IntoBuf,
|
||||||
|
{
|
||||||
/// Polls for the amount of additional data that may be sent to a remote.
|
/// Polls for the amount of additional data that may be sent to a remote.
|
||||||
///
|
///
|
||||||
/// Connection and stream updates are distinct.
|
/// Connection and stream updates are distinct.
|
||||||
pub fn poll_window_update(&mut self, _id: StreamId) -> Poll<WindowSize, ConnectionError> {
|
pub fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<WindowSize, ConnectionError> {
|
||||||
// let added = if id.is_zero() {
|
self.inner.poll_remote_window_update(id)
|
||||||
// self.remote_flow_controller.take_window_update()
|
|
||||||
// } else {
|
|
||||||
// self.streams.get_mut(&id).and_then(|s| s.take_send_window_update())
|
|
||||||
// };
|
|
||||||
// match added {
|
|
||||||
// Some(incr) => Ok(Async::Ready(incr)),
|
|
||||||
// None => {
|
|
||||||
// self.blocked_window_update = Some(task::current());
|
|
||||||
// Ok(Async::NotReady)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increases the amount of data that the remote endpoint may send.
|
/// Increases the amount of data that the remote endpoint may send.
|
||||||
///
|
///
|
||||||
/// Connection and stream updates are distinct.
|
/// Connection and stream updates are distinct.
|
||||||
pub fn increment_window_size(&mut self, _id: StreamId, _incr: WindowSize) {
|
pub fn grow_local_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError> {
|
||||||
// assert!(self.sending_window_update.is_none());
|
self.inner.grow_local_window(id, incr)
|
||||||
// let added = if id.is_zero() {
|
|
||||||
// self.local_flow_controller.grow_window(incr);
|
|
||||||
// self.local_flow_controller.take_window_update()
|
|
||||||
// } else {
|
|
||||||
// self.streams.get_mut(&id).and_then(|s| {
|
|
||||||
// s.grow_recv_window(incr);
|
|
||||||
// s.take_recv_window_update()
|
|
||||||
// })
|
|
||||||
// };
|
|
||||||
// if let Some(added) = added {
|
|
||||||
// self.sending_window_update = Some(frame::WindowUpdate::new(id, added));
|
|
||||||
// }
|
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,9 +128,8 @@ impl<T, P, B> Stream for Connection<T, P, B>
|
|||||||
// is called here.
|
// is called here.
|
||||||
try_ready!(self.inner.poll_complete());
|
try_ready!(self.inner.poll_complete());
|
||||||
|
|
||||||
// If the sender sink is ready, we attempt to poll the underlying
|
// If the write buffer is cleared, attempt to poll the underlying
|
||||||
// stream once more because it, may have been made ready by flushing
|
// stream once more because it, may have been made ready.
|
||||||
// the sink.
|
|
||||||
try_ready!(self.inner.poll())
|
try_ready!(self.inner.poll())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -215,17 +192,12 @@ impl<T, P, B> Sink for Connection<T, P, B>
|
|||||||
|
|
||||||
match item {
|
match item {
|
||||||
Frame::Headers { id, headers, end_of_stream } => {
|
Frame::Headers { id, headers, end_of_stream } => {
|
||||||
|
// This is a one-way conversion. By checking `poll_ready` first (above),
|
||||||
|
// it's already been determined that the inner `Sink` can accept the item.
|
||||||
|
// If the item is rejected, then there is a bug.
|
||||||
let frame = P::convert_send_message(id, headers, end_of_stream);
|
let frame = P::convert_send_message(id, headers, end_of_stream);
|
||||||
|
let res = self.inner.start_send(Headers(frame))?;
|
||||||
// We already ensured that the upstream can handle the frame, so
|
|
||||||
// panic if it gets rejected.
|
|
||||||
let res = try!(self.inner.start_send(Headers(frame)));
|
|
||||||
|
|
||||||
// This is a one-way conversion. By checking `poll_ready` first,
|
|
||||||
// it's already been determined that the inner `Sink` can accept
|
|
||||||
// the item. If the item is rejected, then there is a bug.
|
|
||||||
assert!(res.is_ready());
|
assert!(res.is_ready());
|
||||||
|
|
||||||
Ok(AsyncSink::Ready)
|
Ok(AsyncSink::Ready)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use error;
|
|||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::*;
|
use proto::*;
|
||||||
|
|
||||||
use futures::*;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FlowControl<T> {
|
pub struct FlowControl<T> {
|
||||||
@@ -18,11 +18,17 @@ pub struct FlowControl<T> {
|
|||||||
/// Tracks the onnection-level flow control window for receiving data from the remote.
|
/// Tracks the onnection-level flow control window for receiving data from the remote.
|
||||||
remote_flow_controller: FlowController,
|
remote_flow_controller: FlowController,
|
||||||
|
|
||||||
/// When `poll_window_update` is not ready, then the calling task is saved to be
|
/// Holds the list of streams on which local window updates may be sent.
|
||||||
/// notified later. Access to poll_window_update must not be shared across tasks.
|
// XXX It would be cool if this didn't exist.
|
||||||
blocked_window_update: Option<task::Task>,
|
pending_local_window_updates: VecDeque<StreamId>,
|
||||||
|
|
||||||
sending_window_update: Option<frame::WindowUpdate>,
|
/// If a window update can't be sent immediately, it may need to be saved to be sent later.
|
||||||
|
sending_local_window_update: Option<frame::WindowUpdate>,
|
||||||
|
|
||||||
|
/// When `poll_remote_window_update` is not ready, then the calling task is saved to
|
||||||
|
/// be notified later. Access to poll_window_update must not be shared across tasks,
|
||||||
|
/// as we only track a single task (and *not* i.e. a task per stream id).
|
||||||
|
blocked_remote_window_update: Option<task::Task>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> FlowControl<T>
|
impl<T, U> FlowControl<T>
|
||||||
@@ -41,41 +47,38 @@ impl<T, U> FlowControl<T>
|
|||||||
initial_remote_window_size,
|
initial_remote_window_size,
|
||||||
local_flow_controller: FlowController::new(initial_local_window_size),
|
local_flow_controller: FlowController::new(initial_local_window_size),
|
||||||
remote_flow_controller: FlowController::new(initial_remote_window_size),
|
remote_flow_controller: FlowController::new(initial_remote_window_size),
|
||||||
blocked_window_update: None,
|
blocked_remote_window_update: None,
|
||||||
sending_window_update: None,
|
sending_local_window_update: None,
|
||||||
|
pending_local_window_updates: VecDeque::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: StreamTransporter> FlowControl<T> {
|
impl<T: StreamTransporter> FlowControl<T> {
|
||||||
fn claim_local_window(&mut self, id: &StreamId, len: WindowSize) -> Result<(), ConnectionError> {
|
fn claim_local_window(&mut self, id: &StreamId, len: WindowSize) -> Result<(), ConnectionError> {
|
||||||
if id.is_zero() {
|
let res = if id.is_zero() {
|
||||||
return self.local_flow_controller.claim_window(len)
|
self.local_flow_controller.claim_window(len)
|
||||||
.map_err(|_| error::Reason::FlowControlError.into());
|
} else if let Some(mut stream) = self.inner.streams_mut().get_mut(&id) {
|
||||||
}
|
stream.claim_local_window(len)
|
||||||
|
} else {
|
||||||
|
// Ignore updates for non-existent streams.
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(mut stream) = self.streams_mut().get_mut(&id) {
|
res.map_err(|_| error::Reason::FlowControlError.into())
|
||||||
return stream.claim_local_window(len)
|
|
||||||
.map_err(|_| error::Reason::FlowControlError.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore updates for non-existent streams.
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn claim_remote_window(&mut self, id: &StreamId, len: WindowSize) -> Result<(), ConnectionError> {
|
fn claim_remote_window(&mut self, id: &StreamId, len: WindowSize) -> Result<(), ConnectionError> {
|
||||||
if id.is_zero() {
|
let res = if id.is_zero() {
|
||||||
return self.local_flow_controller.claim_window(len)
|
self.local_flow_controller.claim_window(len)
|
||||||
.map_err(|_| error::Reason::FlowControlError.into());
|
} else if let Some(mut stream) = self.inner.streams_mut().get_mut(&id) {
|
||||||
}
|
stream.claim_remote_window(len)
|
||||||
|
} else {
|
||||||
|
// Ignore updates for non-existent streams.
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(mut stream) = self.streams_mut().get_mut(&id) {
|
res.map_err(|_| error::Reason::FlowControlError.into())
|
||||||
return stream.claim_remote_window(len)
|
|
||||||
.map_err(|_| error::Reason::FlowControlError.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore updates for non-existent streams.
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a window update received from the remote, indicating that the local may
|
/// Handles a window update received from the remote, indicating that the local may
|
||||||
@@ -87,35 +90,93 @@ impl<T: StreamTransporter> FlowControl<T> {
|
|||||||
if incr == 0 {
|
if incr == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let added = if id.is_zero() {
|
|
||||||
|
if id.is_zero() {
|
||||||
self.remote_flow_controller.grow_window(incr);
|
self.remote_flow_controller.grow_window(incr);
|
||||||
true
|
} else if let Some(mut s) = self.inner.streams_mut().get_mut(&id) {
|
||||||
} else if let Some(mut s) = self.streams_mut().get_mut(&id) {
|
|
||||||
s.grow_remote_window(incr);
|
s.grow_remote_window(incr);
|
||||||
true
|
|
||||||
} else {
|
} else {
|
||||||
false
|
// Ignore updates for non-existent streams.
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
if added {
|
|
||||||
if let Some(task) = self.blocked_window_update.take() {
|
if let Some(task) = self.blocked_remote_window_update.take() {
|
||||||
task.notify();
|
task.notify();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: StreamTransporter> FlowTransporter for FlowControl<T> {
|
||||||
|
fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<WindowSize, ConnectionError> {
|
||||||
|
if id.is_zero() {
|
||||||
|
if let Some(sz) = self.remote_flow_controller.take_window_update() {
|
||||||
|
return Ok(Async::Ready(sz));
|
||||||
|
}
|
||||||
|
} else if let Some(mut stream) = self.inner.streams_mut().get_mut(&id) {
|
||||||
|
if let Some(sz) = stream.take_remote_window_update() {
|
||||||
|
return Ok(Async::Ready(sz));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(error::User::InvalidStreamId.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.blocked_remote_window_update = Some(task::current());
|
||||||
|
return Ok(Async::NotReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grow_local_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError> {
|
||||||
|
if id.is_zero() {
|
||||||
|
self.local_flow_controller.grow_window(incr);
|
||||||
|
self.pending_local_window_updates.push_back(id);
|
||||||
|
Ok(())
|
||||||
|
} else if let Some(mut stream) = self.inner.streams_mut().get_mut(&id) {
|
||||||
|
stream.grow_local_window(incr);
|
||||||
|
self.pending_local_window_updates.push_back(id);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(error::User::InvalidStreamId.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: StreamTransporter> StreamTransporter for FlowControl<T> {
|
||||||
|
#[inline]
|
||||||
|
fn streams(&self) -> &StreamMap {
|
||||||
|
self.inner.streams()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn streams_mut(&mut self) -> &mut StreamMap {
|
||||||
|
self.inner.streams_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, U> FlowControl<T>
|
impl<T, U> FlowControl<T>
|
||||||
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||||
|
T: StreamTransporter,
|
||||||
{
|
{
|
||||||
/// Attempts to send a window update to the remote, if one is pending.
|
/// Returns ready when there are no pending window updates to send.
|
||||||
fn poll_sending_window_update(&mut self) -> Poll<(), ConnectionError> {
|
fn poll_send_local_window_updates(&mut self) -> Poll<(), ConnectionError> {
|
||||||
if let Some(f) = self.sending_window_update.take() {
|
if let Some(f) = self.sending_local_window_update.take() {
|
||||||
if self.inner.start_send(f.into())?.is_not_ready() {
|
if self.inner.start_send(f.into())?.is_not_ready() {
|
||||||
self.sending_window_update = Some(f);
|
self.sending_local_window_update = Some(f);
|
||||||
return Ok(Async::NotReady);
|
return Ok(Async::NotReady);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while let Some(id) = self.pending_local_window_updates.pop_front() {
|
||||||
|
let update = self.inner.streams_mut().get_mut(&id)
|
||||||
|
.and_then(|mut s| s.take_local_window_update())
|
||||||
|
.map(|incr| frame::WindowUpdate::new(id, incr));
|
||||||
|
|
||||||
|
if let Some(f) = update {
|
||||||
|
if self.inner.start_send(f.into())?.is_not_ready() {
|
||||||
|
self.sending_local_window_update = Some(f);
|
||||||
|
return Ok(Async::NotReady);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Async::Ready(()))
|
Ok(Async::Ready(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,8 +197,8 @@ impl<T, U> FlowControl<T>
|
|||||||
/// > 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.
|
||||||
impl<T> ConnectionTransporter for FlowControl<T>
|
impl<T> ApplySettings for FlowControl<T>
|
||||||
where T: ConnectionTransporter,
|
where T: ApplySettings,
|
||||||
T: StreamTransporter
|
T: StreamTransporter
|
||||||
{
|
{
|
||||||
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
@@ -149,15 +210,13 @@ impl<T> ConnectionTransporter for FlowControl<T>
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
let mut streams = self.inner.streams_mut();
|
||||||
let mut streams = self.streams_mut();
|
if new_window_size < old_window_size {
|
||||||
if new_window_size < old_window_size {
|
let decr = old_window_size - new_window_size;
|
||||||
let decr = old_window_size - new_window_size;
|
streams.shrink_all_local_windows(decr);
|
||||||
streams.shrink_all_local_windows(decr);
|
} else {
|
||||||
} else {
|
let incr = new_window_size - old_window_size;
|
||||||
let incr = new_window_size - old_window_size;
|
streams.grow_all_local_windows(incr);
|
||||||
streams.grow_all_local_windows(incr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.initial_local_window_size = new_window_size;
|
self.initial_local_window_size = new_window_size;
|
||||||
@@ -173,15 +232,13 @@ impl<T> ConnectionTransporter for FlowControl<T>
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
let mut streams = self.inner.streams_mut();
|
||||||
let mut streams = self.streams_mut();
|
if new_window_size < old_window_size {
|
||||||
if new_window_size < old_window_size {
|
let decr = old_window_size - new_window_size;
|
||||||
let decr = old_window_size - new_window_size;
|
streams.shrink_all_remote_windows(decr);
|
||||||
streams.shrink_all_remote_windows(decr);
|
} else {
|
||||||
} else {
|
let incr = new_window_size - old_window_size;
|
||||||
let incr = new_window_size - old_window_size;
|
streams.grow_all_remote_windows(incr);
|
||||||
streams.grow_all_remote_windows(incr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.initial_remote_window_size = new_window_size;
|
self.initial_remote_window_size = new_window_size;
|
||||||
@@ -189,16 +246,6 @@ impl<T> ConnectionTransporter for FlowControl<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: StreamTransporter> StreamTransporter for FlowControl<T> {
|
|
||||||
fn streams(&self) -> &StreamMap {
|
|
||||||
self.inner.streams()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn streams_mut(&mut self) -> &mut StreamMap {
|
|
||||||
self.inner.streams_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Stream for FlowControl<T>
|
impl<T> Stream for FlowControl<T>
|
||||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||||
T: StreamTransporter,
|
T: StreamTransporter,
|
||||||
@@ -230,23 +277,40 @@ impl<T> Stream for FlowControl<T>
|
|||||||
|
|
||||||
impl<T, U> Sink for FlowControl<T>
|
impl<T, U> Sink for FlowControl<T>
|
||||||
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||||
|
T: ReadySink,
|
||||||
T: StreamTransporter,
|
T: StreamTransporter,
|
||||||
{
|
{
|
||||||
type SinkItem = T::SinkItem;
|
type SinkItem = T::SinkItem;
|
||||||
type SinkError = T::SinkError;
|
type SinkError = T::SinkError;
|
||||||
|
|
||||||
fn start_send(&mut self, item: Frame<U>) -> StartSend<T::SinkItem, T::SinkError> {
|
fn start_send(&mut self, frame: Frame<U>) -> StartSend<T::SinkItem, T::SinkError> {
|
||||||
use frame::Frame::*;
|
use frame::Frame::*;
|
||||||
|
|
||||||
if let &Data(ref v) = &item {
|
if self.poll_send_local_window_updates()?.is_not_ready() {
|
||||||
self.claim_remote_window(&v.stream_id(), v.len())?;
|
return Ok(AsyncSink::NotReady(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inner.start_send(item)
|
match frame {
|
||||||
|
Data(v) => {
|
||||||
|
// Before claiming space, ensure that the transport will accept the frame.
|
||||||
|
if self.inner.poll_ready()?.is_not_ready() {
|
||||||
|
return Ok(AsyncSink::NotReady(Data(v)));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.claim_remote_window(&v.stream_id(), v.len())?;
|
||||||
|
|
||||||
|
let res = self.inner.start_send(Data(v))?;
|
||||||
|
assert!(res.is_ready());
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
frame => self.inner.start_send(frame),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_complete(&mut self) -> Poll<(), T::SinkError> {
|
fn poll_complete(&mut self) -> Poll<(), T::SinkError> {
|
||||||
self.inner.poll_complete()
|
try_ready!(self.inner.poll_complete());
|
||||||
|
self.poll_send_local_window_updates()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,6 +321,7 @@ impl<T, U> ReadySink for FlowControl<T>
|
|||||||
T: StreamTransporter,
|
T: StreamTransporter,
|
||||||
{
|
{
|
||||||
fn poll_ready(&mut self) -> Poll<(), ConnectionError> {
|
fn poll_ready(&mut self) -> Poll<(), ConnectionError> {
|
||||||
self.inner.poll_ready()
|
try_ready!(self.inner.poll_ready());
|
||||||
|
self.poll_send_local_window_updates()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use {hpack, ConnectionError};
|
use {hpack, ConnectionError};
|
||||||
use frame::{self, Frame, Kind};
|
use frame::{self, Frame, Kind};
|
||||||
use frame::DEFAULT_SETTINGS_HEADER_TABLE_SIZE;
|
use frame::DEFAULT_SETTINGS_HEADER_TABLE_SIZE;
|
||||||
use proto::{ConnectionTransporter, ReadySink};
|
use proto::{ApplySettings, ReadySink};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ impl<T> FramedRead<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ConnectionTransporter> ConnectionTransporter for FramedRead<T> {
|
impl<T: ApplySettings> ApplySettings for FramedRead<T> {
|
||||||
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
self.inner.get_mut().apply_local_settings(set)
|
self.inner.get_mut().apply_local_settings(set)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use {hpack, ConnectionError, FrameSize};
|
use {hpack, ConnectionError, FrameSize};
|
||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::{ConnectionTransporter, ReadySink};
|
use proto::{ApplySettings, ReadySink};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
@@ -78,7 +78,7 @@ impl<T, B> FramedWrite<T, B>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, B> ConnectionTransporter for FramedWrite<T, B> {
|
impl<T, B> ApplySettings for FramedWrite<T, B> {
|
||||||
fn apply_local_settings(&mut self, _set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
fn apply_local_settings(&mut self, _set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
use {frame, ConnectionError, Peer, StreamId};
|
||||||
|
use bytes::{Buf, IntoBuf};
|
||||||
|
use fnv::FnvHasher;
|
||||||
|
use futures::*;
|
||||||
|
use ordermap::{Entry, OrderMap};
|
||||||
|
use std::hash::BuildHasherDefault;
|
||||||
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
use tokio_io::codec::length_delimited;
|
||||||
|
|
||||||
mod connection;
|
mod connection;
|
||||||
mod flow_control;
|
mod flow_control;
|
||||||
mod flow_controller;
|
mod flow_controller;
|
||||||
@@ -20,17 +29,6 @@ pub use self::settings::Settings;
|
|||||||
pub use self::stream_tracker::StreamTracker;
|
pub use self::stream_tracker::StreamTracker;
|
||||||
use self::state::StreamState;
|
use self::state::StreamState;
|
||||||
|
|
||||||
use {frame, ConnectionError, Peer, StreamId};
|
|
||||||
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
|
||||||
use tokio_io::codec::length_delimited;
|
|
||||||
|
|
||||||
use bytes::{Buf, IntoBuf};
|
|
||||||
|
|
||||||
use ordermap::{Entry, OrderMap};
|
|
||||||
use fnv::FnvHasher;
|
|
||||||
use std::hash::BuildHasherDefault;
|
|
||||||
|
|
||||||
/// Represents the internals of an HTTP2 connection.
|
/// Represents the internals of an HTTP2 connection.
|
||||||
///
|
///
|
||||||
/// A transport consists of several layers (_transporters_) and is arranged from _top_
|
/// A transport consists of several layers (_transporters_) and is arranged from _top_
|
||||||
@@ -100,7 +98,7 @@ impl StreamMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Allows settings to be applied from the top of the stack to the lower levels.d
|
/// Allows settings to be applied from the top of the stack to the lower levels.d
|
||||||
pub trait ConnectionTransporter {
|
pub trait ApplySettings {
|
||||||
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>;
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>;
|
||||||
fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>;
|
fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>;
|
||||||
}
|
}
|
||||||
@@ -110,6 +108,11 @@ pub trait StreamTransporter {
|
|||||||
fn streams_mut(&mut self) -> &mut StreamMap;
|
fn streams_mut(&mut self) -> &mut StreamMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FlowTransporter {
|
||||||
|
fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<WindowSize, ConnectionError>;
|
||||||
|
fn grow_local_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError>;
|
||||||
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
use frame::{Frame, Ping, SettingSet};
|
use frame::{Frame, Ping, SettingSet};
|
||||||
use futures::*;
|
use futures::*;
|
||||||
use proto::{ConnectionTransporter, ReadySink};
|
use proto::{ApplySettings, ReadySink};
|
||||||
|
|
||||||
/// Acknowledges ping requests from the remote.
|
/// Acknowledges ping requests from the remote.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -22,7 +22,7 @@ impl<T, U> PingPong<T, U>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ConnectionTransporter, U> ConnectionTransporter for PingPong<T, U> {
|
impl<T: ApplySettings, U> ApplySettings for PingPong<T, U> {
|
||||||
fn apply_local_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> {
|
fn apply_local_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> {
|
||||||
self.inner.apply_local_settings(set)
|
self.inner.apply_local_settings(set)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use ConnectionError;
|
use {StreamId, ConnectionError};
|
||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::{ConnectionTransporter, ReadySink, StreamMap, StreamTransporter};
|
use proto::{ApplySettings, ReadySink, StreamMap, StreamTransporter, FlowTransporter, WindowSize};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
use tokio_io::AsyncRead;
|
use tokio_io::AsyncRead;
|
||||||
@@ -8,6 +8,8 @@ use bytes::BufMut;
|
|||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Settings<T> {
|
pub struct Settings<T> {
|
||||||
// Upstream transport
|
// Upstream transport
|
||||||
@@ -23,7 +25,7 @@ pub struct Settings<T> {
|
|||||||
remaining_acks: usize,
|
remaining_acks: usize,
|
||||||
|
|
||||||
// True when the local settings must be flushed to the remote
|
// True when the local settings must be flushed to the remote
|
||||||
is_dirty: bool,
|
is_local_dirty: bool,
|
||||||
|
|
||||||
// True when we have received a settings frame from the remote.
|
// True when we have received a settings frame from the remote.
|
||||||
received_remote: bool,
|
received_remote: bool,
|
||||||
@@ -38,7 +40,7 @@ impl<T, U> Settings<T>
|
|||||||
local: local,
|
local: local,
|
||||||
remote: frame::SettingSet::default(),
|
remote: frame::SettingSet::default(),
|
||||||
remaining_acks: 0,
|
remaining_acks: 0,
|
||||||
is_dirty: true,
|
is_local_dirty: true,
|
||||||
received_remote: false,
|
received_remote: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,18 +62,18 @@ impl<T, U> Settings<T>
|
|||||||
local: self.local,
|
local: self.local,
|
||||||
remote: self.remote,
|
remote: self.remote,
|
||||||
remaining_acks: self.remaining_acks,
|
remaining_acks: self.remaining_acks,
|
||||||
is_dirty: self.is_dirty,
|
is_local_dirty: self.is_local_dirty,
|
||||||
received_remote: self.received_remote,
|
received_remote: self.received_remote,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_send_pending(&mut self) -> Poll<(), ConnectionError> {
|
fn try_send_pending(&mut self) -> Poll<(), ConnectionError> {
|
||||||
trace!("try_send_pending; dirty={} acks={}", self.is_dirty, self.remaining_acks);
|
trace!("try_send_pending; dirty={} acks={}", self.is_local_dirty, self.remaining_acks);
|
||||||
if self.is_dirty {
|
if self.is_local_dirty {
|
||||||
let frame = frame::Settings::new(self.local.clone());
|
let frame = frame::Settings::new(self.local.clone());
|
||||||
try_ready!(self.try_send(frame));
|
try_ready!(self.try_send(frame));
|
||||||
|
|
||||||
self.is_dirty = false;
|
self.is_local_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while self.remaining_acks > 0 {
|
while self.remaining_acks > 0 {
|
||||||
@@ -104,10 +106,20 @@ impl<T: StreamTransporter> StreamTransporter for Settings<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: FlowTransporter> FlowTransporter for Settings<T> {
|
||||||
|
fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<WindowSize, ConnectionError> {
|
||||||
|
self.inner.poll_remote_window_update(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grow_local_window(&mut self, id: StreamId, incr: WindowSize) -> Result<(), ConnectionError> {
|
||||||
|
self.inner.grow_local_window(id, incr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, U> Stream for Settings<T>
|
impl<T, U> Stream for Settings<T>
|
||||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||||
T: ConnectionTransporter,
|
T: ApplySettings,
|
||||||
{
|
{
|
||||||
type Item = Frame;
|
type Item = Frame;
|
||||||
type Error = ConnectionError;
|
type Error = ConnectionError;
|
||||||
@@ -120,14 +132,13 @@ impl<T, U> Stream for Settings<T>
|
|||||||
debug!("received remote settings ack");
|
debug!("received remote settings ack");
|
||||||
// TODO: Handle acks
|
// TODO: Handle acks
|
||||||
} else {
|
} else {
|
||||||
// Received new settings, queue an ACK
|
// Apply the settings before saving them and sending
|
||||||
self.remaining_acks += 1;
|
// acknowledgements.
|
||||||
|
|
||||||
// Apply the settings before saving them.
|
|
||||||
let settings = v.into_set();
|
let settings = v.into_set();
|
||||||
self.inner.apply_remote_settings(&settings)?;
|
self.inner.apply_remote_settings(&settings)?;
|
||||||
self.remote = settings;
|
self.remote = settings;
|
||||||
|
|
||||||
|
self.remaining_acks += 1;
|
||||||
let _ = try!(self.try_send_pending());
|
let _ = try!(self.try_send_pending());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ use error::User::InvalidStreamId;
|
|||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::*;
|
use proto::*;
|
||||||
|
|
||||||
use futures::*;
|
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -44,10 +42,12 @@ impl<T, P, U> StreamTracker<T, P>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T, P> StreamTransporter for StreamTracker<T, P> {
|
impl<T, P> StreamTransporter for StreamTracker<T, P> {
|
||||||
|
#[inline]
|
||||||
fn streams(&self) -> &StreamMap {
|
fn streams(&self) -> &StreamMap {
|
||||||
&self.streams
|
&self.streams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn streams_mut(&mut self) -> &mut StreamMap {
|
fn streams_mut(&mut self) -> &mut StreamMap {
|
||||||
&mut self.streams
|
&mut self.streams
|
||||||
}
|
}
|
||||||
@@ -71,8 +71,8 @@ impl<T, P> StreamTransporter for StreamTracker<T, P> {
|
|||||||
/// > exceed the new value or allow streams to complete.
|
/// > exceed the new value or allow streams to complete.
|
||||||
///
|
///
|
||||||
/// This module does NOT close streams when the setting changes.
|
/// This module does NOT close streams when the setting changes.
|
||||||
impl<T, P> ConnectionTransporter for StreamTracker<T, P>
|
impl<T, P> ApplySettings for StreamTracker<T, P>
|
||||||
where T: ConnectionTransporter
|
where T: ApplySettings
|
||||||
{
|
{
|
||||||
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
self.local_max_concurrency = set.max_concurrent_streams();
|
self.local_max_concurrency = set.max_concurrent_streams();
|
||||||
|
|||||||
Reference in New Issue
Block a user