wire up remote settings application
This commit is contained in:
@@ -23,6 +23,10 @@ impl SettingSet {
|
||||
pub fn initial_window_size(&self) -> u32 {
|
||||
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
|
||||
|
||||
@@ -101,11 +101,11 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
||||
assert!(self.sending_window_update.is_none());
|
||||
|
||||
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()
|
||||
} else {
|
||||
self.streams.get_mut(&id).and_then(|s| {
|
||||
s.increment_recv_window_size(incr);
|
||||
s.grow_recv_window(incr);
|
||||
s.take_recv_window_update()
|
||||
})
|
||||
};
|
||||
@@ -126,10 +126,10 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
||||
}
|
||||
|
||||
let added = if id.is_zero() {
|
||||
self.remote_flow_controller.increment_window_size(incr);
|
||||
self.remote_flow_controller.grow_window(incr);
|
||||
true
|
||||
} else if let Some(mut s) = self.streams.get_mut(&id) {
|
||||
s.increment_send_window_size(incr);
|
||||
s.grow_send_window(incr);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use ConnectionError;
|
||||
use frame::{self, Frame};
|
||||
use proto::{ReadySink, StreamMap, StreamTransporter, WindowSize};
|
||||
use proto::{ReadySink, StreamMap, ConnectionTransporter, StreamTransporter};
|
||||
|
||||
use futures::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FlowControl<T> {
|
||||
inner: T,
|
||||
initial_local_window_size: u32,
|
||||
initial_remote_window_size: u32,
|
||||
}
|
||||
|
||||
impl<T, U> FlowControl<T>
|
||||
@@ -14,8 +16,85 @@ impl<T, U> FlowControl<T>
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
T: StreamTransporter
|
||||
{
|
||||
pub fn new(inner: T) -> FlowControl<T> {
|
||||
FlowControl { inner }
|
||||
pub fn new(initial_local_window_size: u32,
|
||||
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.
|
||||
pub fn increment_window_size(&mut self, sz: WindowSize) {
|
||||
pub fn grow_window(&mut self, sz: WindowSize) {
|
||||
if sz <= self.underflow {
|
||||
self.underflow -= sz;
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use {hpack, ConnectionError};
|
||||
use frame::{self, Frame, Kind};
|
||||
use frame::DEFAULT_SETTINGS_HEADER_TABLE_SIZE;
|
||||
use proto::ReadySink;
|
||||
use proto::{ConnectionTransporter, ReadySink};
|
||||
|
||||
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>
|
||||
where T: AsyncRead,
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use {hpack, ConnectionError, FrameSize};
|
||||
use frame::{self, Frame};
|
||||
use proto::ReadySink;
|
||||
use proto::{ConnectionTransporter, ReadySink};
|
||||
|
||||
use futures::*;
|
||||
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>
|
||||
where T: AsyncWrite,
|
||||
B: Buf,
|
||||
|
||||
@@ -20,7 +20,7 @@ pub use self::settings::Settings;
|
||||
pub use self::stream_tracker::StreamTracker;
|
||||
use self::state::StreamState;
|
||||
|
||||
use {frame, Peer, StreamId};
|
||||
use {frame, ConnectionError, Peer, StreamId};
|
||||
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_io::codec::length_delimited;
|
||||
@@ -31,7 +31,20 @@ use ordermap::OrderMap;
|
||||
use fnv::FnvHasher;
|
||||
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> =
|
||||
Settings<
|
||||
FlowControl<
|
||||
@@ -44,15 +57,46 @@ type Framer<T, B> =
|
||||
FramedRead<
|
||||
FramedWrite<T, B>>;
|
||||
|
||||
|
||||
pub type WindowSize = u32;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StreamMap {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct StreamMap {
|
||||
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_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
|
||||
// weird, but oh well...
|
||||
//
|
||||
// We first create a Settings directly around a framed writer
|
||||
let settings = Settings::new(
|
||||
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
|
||||
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>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
P: Peer,
|
||||
B: IntoBuf,
|
||||
{
|
||||
let settings = transport.swap_inner(|io| {
|
||||
// Delimit the frames
|
||||
let framed_read = length_delimited::Builder::new()
|
||||
let initial_local_window_size = settings.local_settings().initial_window_size();
|
||||
let initial_remote_window_size = settings.remote_settings().initial_window_size();
|
||||
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()
|
||||
.length_field_length(3)
|
||||
.length_adjustment(9)
|
||||
.num_skip(0) // Don't skip the header
|
||||
.new_read(io);
|
||||
|
||||
// Map to `Frame` types
|
||||
let framed = FramedRead::new(framed_read);
|
||||
|
||||
FlowControl::new(
|
||||
StreamTracker::new(
|
||||
FlowControl::new(initial_local_window_size, initial_remote_window_size,
|
||||
StreamTracker::new(local_max_concurrency, remote_max_concurrency,
|
||||
PingPong::new(
|
||||
framed)))
|
||||
FramedRead::new(framer))))
|
||||
});
|
||||
|
||||
// Finally, return the constructed `Connection`
|
||||
connection::new(settings)
|
||||
connection::new(transport)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use ConnectionError;
|
||||
use frame::{Frame, Ping};
|
||||
use frame::{Frame, Ping, SettingSet};
|
||||
use futures::*;
|
||||
use proto::ReadySink;
|
||||
use proto::{ConnectionTransporter, ReadySink};
|
||||
|
||||
/// Acknowledges ping requests from the remote.
|
||||
#[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>
|
||||
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use ConnectionError;
|
||||
use frame::{self, Frame};
|
||||
use proto::ReadySink;
|
||||
use proto::{ConnectionTransporter, ReadySink, StreamMap, StreamTransporter};
|
||||
|
||||
use futures::*;
|
||||
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>
|
||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
T: ConnectionTransporter,
|
||||
{
|
||||
type Item = Frame;
|
||||
type Error = ConnectionError;
|
||||
@@ -112,8 +123,10 @@ impl<T, U> Stream for Settings<T>
|
||||
// Received new settings, queue an ACK
|
||||
self.remaining_acks += 1;
|
||||
|
||||
// Save off the settings
|
||||
self.remote = v.into_set();
|
||||
// Apply the settings before saving them.
|
||||
let settings = v.into_set();
|
||||
self.inner.apply_remote_settings(&settings)?;
|
||||
self.remote = settings;
|
||||
|
||||
let _ = try!(self.try_send_pending());
|
||||
}
|
||||
|
||||
@@ -47,8 +47,9 @@ use proto::FlowController;
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum StreamState {
|
||||
Idle,
|
||||
ReservedLocal,
|
||||
ReservedRemote,
|
||||
// TODO: these states shouldn't count against concurrency limits:
|
||||
//ReservedLocal,
|
||||
//ReservedRemote,
|
||||
Open {
|
||||
local: PeerState,
|
||||
remote: PeerState,
|
||||
@@ -65,7 +66,7 @@ impl StreamState {
|
||||
/// caller should send the the returned window size increment to the remote.
|
||||
///
|
||||
/// 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::PeerState::*;
|
||||
|
||||
@@ -75,11 +76,27 @@ impl StreamState {
|
||||
|
||||
match self {
|
||||
&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
|
||||
/// data.
|
||||
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
|
||||
/// 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::PeerState::*;
|
||||
|
||||
@@ -108,7 +125,22 @@ impl StreamState {
|
||||
|
||||
match self {
|
||||
&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.
|
||||
///
|
||||
/// Returns true if this state transition results in iniitializing the
|
||||
@@ -212,8 +204,6 @@ impl StreamState {
|
||||
Closed | HalfClosedRemote(..) => {
|
||||
Err(ProtocolError.into())
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,8 +291,6 @@ impl StreamState {
|
||||
Closed | HalfClosedLocal(..) => {
|
||||
Err(UnexpectedFrameType.into())
|
||||
}
|
||||
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +1,72 @@
|
||||
use ConnectionError;
|
||||
use frame::{self, Frame};
|
||||
use proto::{ReadySink, StreamMap, StreamTransporter, WindowSize};
|
||||
use proto::{ReadySink, StreamMap, ConnectionTransporter, StreamTransporter};
|
||||
|
||||
use futures::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StreamTracker<T> {
|
||||
inner: T,
|
||||
streams: StreamMap,
|
||||
local_max_concurrency: Option<u32>,
|
||||
remote_max_concurrency: Option<u32>,
|
||||
}
|
||||
|
||||
impl<T, U> StreamTracker<T>
|
||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>
|
||||
{
|
||||
pub fn new(inner: T) -> StreamTracker<T> {
|
||||
StreamTracker { inner }
|
||||
pub fn new(local_max_concurrency: Option<u32>,
|
||||
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> {
|
||||
fn streams(&self) -> &StreamMap {
|
||||
unimplemented!()
|
||||
&self.streams
|
||||
}
|
||||
|
||||
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