wire up remote settings application
This commit is contained in:
@@ -23,6 +23,10 @@ impl SettingSet {
|
|||||||
pub fn initial_window_size(&self) -> u32 {
|
pub fn initial_window_size(&self) -> u32 {
|
||||||
self.initial_window_size.unwrap_or(65_535)
|
self.initial_window_size.unwrap_or(65_535)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn max_concurrent_streams(&self) -> Option<u32> {
|
||||||
|
self.max_concurrent_streams
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An enum that lists all valid settings that can be sent in a SETTINGS
|
/// An enum that lists all valid settings that can be sent in a SETTINGS
|
||||||
|
|||||||
@@ -101,11 +101,11 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
|||||||
assert!(self.sending_window_update.is_none());
|
assert!(self.sending_window_update.is_none());
|
||||||
|
|
||||||
let added = if id.is_zero() {
|
let added = if id.is_zero() {
|
||||||
self.local_flow_controller.increment_window_size(incr);
|
self.local_flow_controller.grow_window(incr);
|
||||||
self.local_flow_controller.take_window_update()
|
self.local_flow_controller.take_window_update()
|
||||||
} else {
|
} else {
|
||||||
self.streams.get_mut(&id).and_then(|s| {
|
self.streams.get_mut(&id).and_then(|s| {
|
||||||
s.increment_recv_window_size(incr);
|
s.grow_recv_window(incr);
|
||||||
s.take_recv_window_update()
|
s.take_recv_window_update()
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@@ -126,10 +126,10 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let added = if id.is_zero() {
|
let added = if id.is_zero() {
|
||||||
self.remote_flow_controller.increment_window_size(incr);
|
self.remote_flow_controller.grow_window(incr);
|
||||||
true
|
true
|
||||||
} else if let Some(mut s) = self.streams.get_mut(&id) {
|
} else if let Some(mut s) = self.streams.get_mut(&id) {
|
||||||
s.increment_send_window_size(incr);
|
s.grow_send_window(incr);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::{ReadySink, StreamMap, StreamTransporter, WindowSize};
|
use proto::{ReadySink, StreamMap, ConnectionTransporter, StreamTransporter};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FlowControl<T> {
|
pub struct FlowControl<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
|
initial_local_window_size: u32,
|
||||||
|
initial_remote_window_size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> FlowControl<T>
|
impl<T, U> FlowControl<T>
|
||||||
@@ -14,8 +16,85 @@ impl<T, U> FlowControl<T>
|
|||||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||||
T: StreamTransporter
|
T: StreamTransporter
|
||||||
{
|
{
|
||||||
pub fn new(inner: T) -> FlowControl<T> {
|
pub fn new(initial_local_window_size: u32,
|
||||||
FlowControl { inner }
|
initial_remote_window_size: u32,
|
||||||
|
inner: T)
|
||||||
|
-> FlowControl<T>
|
||||||
|
{
|
||||||
|
FlowControl {
|
||||||
|
inner,
|
||||||
|
initial_local_window_size,
|
||||||
|
initial_remote_window_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies an update to an endpoint's initial window size.
|
||||||
|
///
|
||||||
|
/// Per RFC 7540 §6.9.2
|
||||||
|
///
|
||||||
|
/// > In addition to changing the flow-control window for streams that are not yet
|
||||||
|
/// > active, a SETTINGS frame can alter the initial flow-control window size for
|
||||||
|
/// > streams with active flow-control windows (that is, streams in the "open" or
|
||||||
|
/// > "half-closed (remote)" state). When the value of SETTINGS_INITIAL_WINDOW_SIZE
|
||||||
|
/// > changes, a receiver MUST adjust the size of all stream flow-control windows that
|
||||||
|
/// > it maintains by the difference between the new value and the old value.
|
||||||
|
/// >
|
||||||
|
/// > A change to `SETTINGS_INITIAL_WINDOW_SIZE` can cause the available space in a
|
||||||
|
/// > flow-control window to become negative. A sender MUST track the negative
|
||||||
|
/// > 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
|
||||||
|
/// > positive.
|
||||||
|
impl<T> ConnectionTransporter for FlowControl<T>
|
||||||
|
where T: ConnectionTransporter,
|
||||||
|
T: StreamTransporter
|
||||||
|
{
|
||||||
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.inner.apply_local_settings(set)?;
|
||||||
|
|
||||||
|
let old_window_size = self.initial_local_window_size;
|
||||||
|
let new_window_size = set.initial_window_size();
|
||||||
|
if new_window_size == old_window_size {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut streams = self.streams_mut();
|
||||||
|
if new_window_size < old_window_size {
|
||||||
|
let decr = old_window_size - new_window_size;
|
||||||
|
streams.shrink_local_window(decr);
|
||||||
|
} else {
|
||||||
|
let incr = new_window_size - old_window_size;
|
||||||
|
streams.grow_local_window(incr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.initial_local_window_size = new_window_size;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.inner.apply_remote_settings(set)?;
|
||||||
|
|
||||||
|
let old_window_size = self.initial_remote_window_size;
|
||||||
|
let new_window_size = set.initial_window_size();
|
||||||
|
if new_window_size == old_window_size {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut streams = self.streams_mut();
|
||||||
|
if new_window_size < old_window_size {
|
||||||
|
let decr = old_window_size - new_window_size;
|
||||||
|
streams.shrink_remote_window(decr);
|
||||||
|
} else {
|
||||||
|
let incr = new_window_size - old_window_size;
|
||||||
|
streams.grow_remote_window(incr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.initial_remote_window_size = new_window_size;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ impl FlowController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Applies a window increment immediately.
|
/// Applies a window increment immediately.
|
||||||
pub fn increment_window_size(&mut self, sz: WindowSize) {
|
pub fn grow_window(&mut self, sz: WindowSize) {
|
||||||
if sz <= self.underflow {
|
if sz <= self.underflow {
|
||||||
self.underflow -= sz;
|
self.underflow -= sz;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -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::ReadySink;
|
use proto::{ConnectionTransporter, ReadySink};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
|
|
||||||
@@ -103,6 +103,16 @@ impl<T> FramedRead<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: ConnectionTransporter> ConnectionTransporter for FramedRead<T> {
|
||||||
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.inner.get_mut().apply_local_settings(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.inner.get_mut().apply_remote_settings(set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Stream for FramedRead<T>
|
impl<T> Stream for FramedRead<T>
|
||||||
where T: AsyncRead,
|
where T: AsyncRead,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use {hpack, ConnectionError, FrameSize};
|
use {hpack, ConnectionError, FrameSize};
|
||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::ReadySink;
|
use proto::{ConnectionTransporter, ReadySink};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
@@ -78,6 +78,16 @@ impl<T, B> FramedWrite<T, B>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, B> ConnectionTransporter for FramedWrite<T, B> {
|
||||||
|
fn apply_local_settings(&mut self, _set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_remote_settings(&mut self, _set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, B> Sink for FramedWrite<T, B>
|
impl<T, B> Sink for FramedWrite<T, B>
|
||||||
where T: AsyncWrite,
|
where T: AsyncWrite,
|
||||||
B: Buf,
|
B: Buf,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ 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, Peer, StreamId};
|
use {frame, ConnectionError, Peer, StreamId};
|
||||||
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
use tokio_io::codec::length_delimited;
|
use tokio_io::codec::length_delimited;
|
||||||
@@ -31,7 +31,20 @@ use ordermap::OrderMap;
|
|||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
/// Represents
|
/// Represents the internals of an HTTP2 connection.
|
||||||
|
///
|
||||||
|
/// A transport consists of several layers (_transporters_) and is arranged from _top_
|
||||||
|
/// (near the application) to _bottom_ (near the network). Each transporter implements a
|
||||||
|
/// Stream of frames received from the remote, and a ReadySink of frames sent to the
|
||||||
|
/// remote.
|
||||||
|
///
|
||||||
|
/// At the top of the transport, the Settings module is responsible for:
|
||||||
|
/// - Transmitting local settings to the remote.
|
||||||
|
/// - Sending settings acknowledgements for all settings frames received from the remote.
|
||||||
|
/// - Exposing settings upward to the Connection.
|
||||||
|
///
|
||||||
|
/// All transporters below Settings must apply relevant settings before passing a frame on
|
||||||
|
/// to another level. For example, if the frame writer n
|
||||||
type Transport<T, B> =
|
type Transport<T, B> =
|
||||||
Settings<
|
Settings<
|
||||||
FlowControl<
|
FlowControl<
|
||||||
@@ -44,15 +57,46 @@ type Framer<T, B> =
|
|||||||
FramedRead<
|
FramedRead<
|
||||||
FramedWrite<T, B>>;
|
FramedWrite<T, B>>;
|
||||||
|
|
||||||
|
|
||||||
pub type WindowSize = u32;
|
pub type WindowSize = u32;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
struct StreamMap {
|
pub struct StreamMap {
|
||||||
inner: OrderMap<StreamId, StreamState, BuildHasherDefault<FnvHasher>>
|
inner: OrderMap<StreamId, StreamState, BuildHasherDefault<FnvHasher>>
|
||||||
}
|
}
|
||||||
|
|
||||||
trait StreamTransporter {
|
impl StreamMap {
|
||||||
|
fn shrink_local_window(&mut self, decr: u32) {
|
||||||
|
for (_, mut s) in &mut self.inner {
|
||||||
|
s.shrink_recv_window(decr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grow_local_window(&mut self, incr: u32) {
|
||||||
|
for (_, mut s) in &mut self.inner {
|
||||||
|
s.grow_recv_window(incr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shrink_remote_window(&mut self, decr: u32) {
|
||||||
|
for (_, mut s) in &mut self.inner {
|
||||||
|
s.shrink_send_window(decr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grow_remote_window(&mut self, incr: u32) {
|
||||||
|
for (_, mut s) in &mut self.inner {
|
||||||
|
s.grow_send_window(incr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows settings to be applied from the top of the stack to the lower levels.d
|
||||||
|
pub trait ConnectionTransporter {
|
||||||
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>;
|
||||||
|
fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait StreamTransporter {
|
||||||
fn streams(&self)-> &StreamMap;
|
fn streams(&self)-> &StreamMap;
|
||||||
fn streams_mut(&mut self) -> &mut StreamMap;
|
fn streams_mut(&mut self) -> &mut StreamMap;
|
||||||
}
|
}
|
||||||
@@ -70,6 +114,8 @@ pub fn from_io<T, P, B>(io: T, settings: frame::SettingSet)
|
|||||||
|
|
||||||
// To avoid code duplication, we're going to go this route. It is a bit
|
// To avoid code duplication, we're going to go this route. It is a bit
|
||||||
// weird, but oh well...
|
// weird, but oh well...
|
||||||
|
//
|
||||||
|
// We first create a Settings directly around a framed writer
|
||||||
let settings = Settings::new(
|
let settings = Settings::new(
|
||||||
framed_write, settings);
|
framed_write, settings);
|
||||||
|
|
||||||
@@ -92,30 +138,32 @@ pub fn server_handshaker<T, B>(io: T, settings: frame::SettingSet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a full H2 transport from the server handshaker
|
/// Create a full H2 transport from the server handshaker
|
||||||
pub fn from_server_handshaker<T, P, B>(transport: Settings<FramedWrite<T, B::Buf>>)
|
pub fn from_server_handshaker<T, P, B>(settings: Settings<FramedWrite<T, B::Buf>>)
|
||||||
-> Connection<T, P, B>
|
-> Connection<T, P, B>
|
||||||
where T: AsyncRead + AsyncWrite,
|
where T: AsyncRead + AsyncWrite,
|
||||||
P: Peer,
|
P: Peer,
|
||||||
B: IntoBuf,
|
B: IntoBuf,
|
||||||
{
|
{
|
||||||
let settings = transport.swap_inner(|io| {
|
let initial_local_window_size = settings.local_settings().initial_window_size();
|
||||||
// Delimit the frames
|
let initial_remote_window_size = settings.remote_settings().initial_window_size();
|
||||||
let framed_read = length_delimited::Builder::new()
|
let local_max_concurrency = settings.local_settings().max_concurrent_streams();
|
||||||
|
let remote_max_concurrency = settings.remote_settings().max_concurrent_streams();
|
||||||
|
|
||||||
|
// Replace Settings' writer with a full transport.
|
||||||
|
let transport = settings.swap_inner(|io| {
|
||||||
|
// Delimit the frames.
|
||||||
|
let framer = length_delimited::Builder::new()
|
||||||
.big_endian()
|
.big_endian()
|
||||||
.length_field_length(3)
|
.length_field_length(3)
|
||||||
.length_adjustment(9)
|
.length_adjustment(9)
|
||||||
.num_skip(0) // Don't skip the header
|
.num_skip(0) // Don't skip the header
|
||||||
.new_read(io);
|
.new_read(io);
|
||||||
|
|
||||||
// Map to `Frame` types
|
FlowControl::new(initial_local_window_size, initial_remote_window_size,
|
||||||
let framed = FramedRead::new(framed_read);
|
StreamTracker::new(local_max_concurrency, remote_max_concurrency,
|
||||||
|
|
||||||
FlowControl::new(
|
|
||||||
StreamTracker::new(
|
|
||||||
PingPong::new(
|
PingPong::new(
|
||||||
framed)))
|
FramedRead::new(framer))))
|
||||||
});
|
});
|
||||||
|
|
||||||
// Finally, return the constructed `Connection`
|
connection::new(transport)
|
||||||
connection::new(settings)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
use frame::{Frame, Ping};
|
use frame::{Frame, Ping, SettingSet};
|
||||||
use futures::*;
|
use futures::*;
|
||||||
use proto::ReadySink;
|
use proto::{ConnectionTransporter, ReadySink};
|
||||||
|
|
||||||
/// Acknowledges ping requests from the remote.
|
/// Acknowledges ping requests from the remote.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -22,6 +22,16 @@ impl<T, U> PingPong<T, U>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: ConnectionTransporter, U> ConnectionTransporter for PingPong<T, U> {
|
||||||
|
fn apply_local_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.inner.apply_local_settings(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_remote_settings(&mut self, set: &SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.inner.apply_remote_settings(set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, U> PingPong<T, U>
|
impl<T, U> PingPong<T, U>
|
||||||
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::ReadySink;
|
use proto::{ConnectionTransporter, ReadySink, StreamMap, StreamTransporter};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
use tokio_io::AsyncRead;
|
use tokio_io::AsyncRead;
|
||||||
@@ -94,9 +94,20 @@ impl<T, U> Settings<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: StreamTransporter> StreamTransporter for Settings<T> {
|
||||||
|
fn streams(&self) -> &StreamMap {
|
||||||
|
self.inner.streams()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn streams_mut(&mut self) -> &mut StreamMap {
|
||||||
|
self.inner.streams_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
{
|
{
|
||||||
type Item = Frame;
|
type Item = Frame;
|
||||||
type Error = ConnectionError;
|
type Error = ConnectionError;
|
||||||
@@ -112,8 +123,10 @@ impl<T, U> Stream for Settings<T>
|
|||||||
// Received new settings, queue an ACK
|
// Received new settings, queue an ACK
|
||||||
self.remaining_acks += 1;
|
self.remaining_acks += 1;
|
||||||
|
|
||||||
// Save off the settings
|
// Apply the settings before saving them.
|
||||||
self.remote = v.into_set();
|
let settings = v.into_set();
|
||||||
|
self.inner.apply_remote_settings(&settings)?;
|
||||||
|
self.remote = settings;
|
||||||
|
|
||||||
let _ = try!(self.try_send_pending());
|
let _ = try!(self.try_send_pending());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ use proto::FlowController;
|
|||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum StreamState {
|
pub enum StreamState {
|
||||||
Idle,
|
Idle,
|
||||||
ReservedLocal,
|
// TODO: these states shouldn't count against concurrency limits:
|
||||||
ReservedRemote,
|
//ReservedLocal,
|
||||||
|
//ReservedRemote,
|
||||||
Open {
|
Open {
|
||||||
local: PeerState,
|
local: PeerState,
|
||||||
remote: PeerState,
|
remote: PeerState,
|
||||||
@@ -65,7 +66,7 @@ impl StreamState {
|
|||||||
/// caller should send the the returned window size increment to the remote.
|
/// caller should send the the returned window size increment to the remote.
|
||||||
///
|
///
|
||||||
/// If the remote is closed, None is returned.
|
/// If the remote is closed, None is returned.
|
||||||
pub fn increment_send_window_size(&mut self, incr: u32) {
|
pub fn grow_send_window(&mut self, incr: u32) {
|
||||||
use self::StreamState::*;
|
use self::StreamState::*;
|
||||||
use self::PeerState::*;
|
use self::PeerState::*;
|
||||||
|
|
||||||
@@ -75,11 +76,27 @@ impl StreamState {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
&mut Open { remote: Data(ref mut fc), .. } |
|
&mut Open { remote: Data(ref mut fc), .. } |
|
||||||
&mut HalfClosedLocal(Data(ref mut fc)) => fc.increment_window_size(incr),
|
&mut HalfClosedLocal(Data(ref mut fc)) => fc.grow_window(incr),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn shrink_send_window(&mut self, decr: u32) {
|
||||||
|
use self::StreamState::*;
|
||||||
|
use self::PeerState::*;
|
||||||
|
|
||||||
|
if decr == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
&mut Open { local: Data(ref mut fc), .. } |
|
||||||
|
&mut HalfClosedLocal(Data(ref mut fc)) => fc.shrink_window(decr),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Consumes newly-advertised capacity to inform the local endpoint it may send more
|
/// Consumes newly-advertised capacity to inform the local endpoint it may send more
|
||||||
/// data.
|
/// data.
|
||||||
pub fn take_send_window_update(&mut self) -> Option<u32> {
|
pub fn take_send_window_update(&mut self) -> Option<u32> {
|
||||||
@@ -98,7 +115,7 @@ impl StreamState {
|
|||||||
///
|
///
|
||||||
/// Returns the amount of capacity created, accounting for window size changes. The
|
/// Returns the amount of capacity created, accounting for window size changes. The
|
||||||
/// caller should send the the returned window size increment to the remote.
|
/// caller should send the the returned window size increment to the remote.
|
||||||
pub fn increment_recv_window_size(&mut self, incr: u32) {
|
pub fn grow_recv_window(&mut self, incr: u32) {
|
||||||
use self::StreamState::*;
|
use self::StreamState::*;
|
||||||
use self::PeerState::*;
|
use self::PeerState::*;
|
||||||
|
|
||||||
@@ -108,7 +125,22 @@ impl StreamState {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
&mut Open { local: Data(ref mut fc), .. } |
|
&mut Open { local: Data(ref mut fc), .. } |
|
||||||
&mut HalfClosedRemote(Data(ref mut fc)) => fc.increment_window_size(incr),
|
&mut HalfClosedRemote(Data(ref mut fc)) => fc.grow_window(incr),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shrink_recv_window(&mut self, decr: u32) {
|
||||||
|
use self::StreamState::*;
|
||||||
|
use self::PeerState::*;
|
||||||
|
|
||||||
|
if decr == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
&mut Open { local: Data(ref mut fc), .. } |
|
||||||
|
&mut HalfClosedRemote(Data(ref mut fc)) => fc.shrink_window(decr),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,46 +158,6 @@ impl StreamState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies an update to the remote's initial window size.
|
|
||||||
///
|
|
||||||
/// Per RFC 7540 §6.9.2
|
|
||||||
///
|
|
||||||
/// > In addition to changing the flow-control window for streams that are not yet
|
|
||||||
/// > active, a SETTINGS frame can alter the initial flow-control window size for
|
|
||||||
/// > streams with active flow-control windows (that is, streams in the "open" or
|
|
||||||
/// > "half-closed (remote)" state). When the value of SETTINGS_INITIAL_WINDOW_SIZE
|
|
||||||
/// > changes, a receiver MUST adjust the size of all stream flow-control windows that
|
|
||||||
/// > it maintains by the difference between the new value and the old value.
|
|
||||||
/// >
|
|
||||||
/// > A change to `SETTINGS_INITIAL_WINDOW_SIZE` can cause the available space in a
|
|
||||||
/// > flow-control window to become negative. A sender MUST track the negative
|
|
||||||
/// > 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
|
|
||||||
/// > positive.
|
|
||||||
pub fn update_initial_recv_window_size(&mut self, old: u32, new: u32) {
|
|
||||||
use self::StreamState::*;
|
|
||||||
use self::PeerState::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
&mut Open { remote: Data(ref mut fc), .. } |
|
|
||||||
&mut HalfClosedLocal(Data(ref mut fc)) => {
|
|
||||||
if new < old {
|
|
||||||
fc.shrink_window(old - new);
|
|
||||||
} else {
|
|
||||||
fc.increment_window_size(new - old);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO Connection doesn't have an API for local updates yet.
|
|
||||||
pub fn update_initial_send_window_size(&mut self, _old: u32, _new: u32) {
|
|
||||||
//use self::StreamState::*;
|
|
||||||
//use self::PeerState::*;
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transition the state to represent headers being received.
|
/// Transition the state to represent headers being received.
|
||||||
///
|
///
|
||||||
/// Returns true if this state transition results in iniitializing the
|
/// Returns true if this state transition results in iniitializing the
|
||||||
@@ -212,8 +204,6 @@ impl StreamState {
|
|||||||
Closed | HalfClosedRemote(..) => {
|
Closed | HalfClosedRemote(..) => {
|
||||||
Err(ProtocolError.into())
|
Err(ProtocolError.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,8 +291,6 @@ impl StreamState {
|
|||||||
Closed | HalfClosedLocal(..) => {
|
Closed | HalfClosedLocal(..) => {
|
||||||
Err(UnexpectedFrameType.into())
|
Err(UnexpectedFrameType.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,72 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::{ReadySink, StreamMap, StreamTransporter, WindowSize};
|
use proto::{ReadySink, StreamMap, ConnectionTransporter, StreamTransporter};
|
||||||
|
|
||||||
use futures::*;
|
use futures::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StreamTracker<T> {
|
pub struct StreamTracker<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
|
streams: StreamMap,
|
||||||
|
local_max_concurrency: Option<u32>,
|
||||||
|
remote_max_concurrency: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> StreamTracker<T>
|
impl<T, U> StreamTracker<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>
|
||||||
{
|
{
|
||||||
pub fn new(inner: T) -> StreamTracker<T> {
|
pub fn new(local_max_concurrency: Option<u32>,
|
||||||
StreamTracker { inner }
|
remote_max_concurrency: Option<u32>,
|
||||||
|
inner: T)
|
||||||
|
-> StreamTracker<T>
|
||||||
|
{
|
||||||
|
StreamTracker {
|
||||||
|
inner,
|
||||||
|
streams: StreamMap::default(),
|
||||||
|
local_max_concurrency,
|
||||||
|
remote_max_concurrency,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> StreamTransporter for StreamTracker<T> {
|
impl<T> StreamTransporter for StreamTracker<T> {
|
||||||
fn streams(&self) -> &StreamMap {
|
fn streams(&self) -> &StreamMap {
|
||||||
unimplemented!()
|
&self.streams
|
||||||
}
|
}
|
||||||
|
|
||||||
fn streams_mut(&mut self) -> &mut StreamMap {
|
fn streams_mut(&mut self) -> &mut StreamMap {
|
||||||
unimplemented!()
|
&mut self.streams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles updates to `SETTINGS_MAX_CONCURRENT_STREAMS`.
|
||||||
|
///
|
||||||
|
/// > Indicates the maximum number of concurrent streams that the sender will allow. This
|
||||||
|
/// > limit is directional: it applies to the number of streams that the sender permits the
|
||||||
|
/// > receiver to create. Initially, there is no limit to this value. It is recommended that
|
||||||
|
/// > this value be no smaller than 100, so as to not unnecessarily limit parallelism.
|
||||||
|
/// >
|
||||||
|
/// > A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special by
|
||||||
|
/// > endpoints. A zero value does prevent the creation of new streams; however, this can
|
||||||
|
/// > also happen for any limit that is exhausted with active streams. Servers SHOULD only
|
||||||
|
/// > set a zero value for short durations; if a server does not wish to accept requests,
|
||||||
|
/// > closing the connection is more appropriate.
|
||||||
|
///
|
||||||
|
/// > An endpoint that wishes to reduce the value of SETTINGS_MAX_CONCURRENT_STREAMS to a
|
||||||
|
/// > value that is below the current number of open streams can either close streams that
|
||||||
|
/// > exceed the new value or allow streams to complete.
|
||||||
|
///
|
||||||
|
/// This module does NOT close streams when the setting changes.
|
||||||
|
impl<T: ConnectionTransporter> ConnectionTransporter for StreamTracker<T> {
|
||||||
|
fn apply_local_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.local_max_concurrency = set.max_concurrent_streams();
|
||||||
|
self.inner.apply_local_settings(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_remote_settings(&mut self, set: &frame::SettingSet) -> Result<(), ConnectionError> {
|
||||||
|
self.remote_max_concurrency = set.max_concurrent_streams();
|
||||||
|
self.inner.apply_remote_settings(set)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user