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