wip: improve split stream tracking
This commit is contained in:
		| @@ -85,7 +85,7 @@ pub enum User { | |||||||
|     StreamReset(Reason), |     StreamReset(Reason), | ||||||
|  |  | ||||||
|     /// The application attempted to initiate too many streams to remote. |     /// The application attempted to initiate too many streams to remote. | ||||||
|     MaxConcurrencyExceeded, |     Rejected, | ||||||
|  |  | ||||||
|     // TODO: reserve additional variants |     // TODO: reserve additional variants | ||||||
| } | } | ||||||
| @@ -127,7 +127,7 @@ macro_rules! user_desc { | |||||||
|             FlowControlViolation => concat!($prefix, "flow control violation"), |             FlowControlViolation => concat!($prefix, "flow control violation"), | ||||||
|             StreamReset(_) => concat!($prefix, "frame sent on reset stream"), |             StreamReset(_) => concat!($prefix, "frame sent on reset stream"), | ||||||
|             Corrupt => concat!($prefix, "connection state corrupt"), |             Corrupt => concat!($prefix, "connection state corrupt"), | ||||||
|             MaxConcurrencyExceeded => concat!($prefix, "stream would exceed remote max concurrency"), |             Rejected => concat!($prefix, "stream would exceed remote max concurrency"), | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -87,12 +87,22 @@ impl<T> Frame<T> { | |||||||
|         match self { |         match self { | ||||||
|             &Headers(ref v) => v.is_end_stream(), |             &Headers(ref v) => v.is_end_stream(), | ||||||
|             &Data(ref v) => v.is_end_stream(), |             &Data(ref v) => v.is_end_stream(), | ||||||
|             &Reset(_) => true, |  | ||||||
|  |  | ||||||
|             &PushPromise(_) | |             &PushPromise(_) | | ||||||
|             &WindowUpdate(_) | |             &WindowUpdate(_) | | ||||||
|             &Ping(_) | |             &Ping(_) | | ||||||
|             &Settings(_) => false, |             &Settings(_) => false, | ||||||
|  |  | ||||||
|  |             &Reset(_) => true, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn is_reset(&self) -> bool { | ||||||
|  |         use self::Frame::*; | ||||||
|  |  | ||||||
|  |         match self { | ||||||
|  |             &Reset(_) => true, | ||||||
|  |             _ => false, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -344,14 +344,21 @@ impl<T: ControlStreams> ControlStreams for FlowControl<T> { | |||||||
|         T::can_create_local_stream() |         T::can_create_local_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { |     fn close_stream_local_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|         self.inner.get_reset(id) |         self.inner.close_stream_local_half(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn close_stream_remote_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.close_stream_remote_half(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { |     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||||
|         self.inner.reset_stream(id, cause) |         self.inner.reset_stream(id, cause) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||||
|  |         self.inner.get_reset(id) | ||||||
|  |     } | ||||||
|     fn is_local_active(&self, id: StreamId) -> bool { |     fn is_local_active(&self, id: StreamId) -> bool { | ||||||
|         self.inner.is_local_active(id) |         self.inner.is_local_active(id) | ||||||
|     } |     } | ||||||
| @@ -383,6 +390,14 @@ impl<T: ControlStreams> ControlStreams for FlowControl<T> { | |||||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { |     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||||
|         self.inner.remote_flow_controller(id) |         self.inner.remote_flow_controller(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.check_can_send_data(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>  { | ||||||
|  |         self.inner.check_can_recv_data(id) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: ControlPing> ControlPing for FlowControl<T> { | impl<T: ControlPing> ControlPing for FlowControl<T> { | ||||||
|   | |||||||
| @@ -112,18 +112,18 @@ fn test_with_initial_size() { | |||||||
|     assert!(fc.apply_window_update().is_none()); |     assert!(fc.apply_window_update().is_none()); | ||||||
| } | } | ||||||
|  |  | ||||||
| #[test] | // #[test] | ||||||
| fn test_with_next_update() { | // fn test_with_next_update() { | ||||||
|     let mut fc = FlowControlState::with_next_update(10); | //     let mut fc = FlowControlState::with_next_update(10); | ||||||
|  | // | ||||||
|     fc.expand_window(8); | //     fc.expand_window(8); | ||||||
|     assert_eq!(fc.window_size, 0); | //     assert_eq!(fc.window_size, 0); | ||||||
|     assert_eq!(fc.next_window_update, 18); | //     assert_eq!(fc.next_window_update, 18); | ||||||
|  | // | ||||||
|     assert_eq!(fc.apply_window_update(), Some(18)); | //     assert_eq!(fc.apply_window_update(), Some(18)); | ||||||
|     assert_eq!(fc.window_size, 18); | //     assert_eq!(fc.window_size, 18); | ||||||
|     assert_eq!(fc.next_window_update, 0); | //     assert_eq!(fc.next_window_update, 0); | ||||||
| } | // } | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| fn test_grow_accumulates() { | fn test_grow_accumulates() { | ||||||
|   | |||||||
| @@ -59,173 +59,193 @@ pub enum StreamState { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl StreamState { | impl StreamState { | ||||||
|     pub fn is_closed(&self) ->  bool { |     // /// Transition the state to represent headers being received. | ||||||
|  |     // /// | ||||||
|  |     // /// Returns true if this state transition results in iniitializing the | ||||||
|  |     // /// stream id. `Err` is returned if this is an invalid state transition. | ||||||
|  |     // pub fn recv_headers<P>(&mut self, eos: bool, initial_window_size: WindowSize) | ||||||
|  |     //     -> Result<bool, ConnectionError> | ||||||
|  |     //     where P: Peer | ||||||
|  |     // { | ||||||
|  |     //     use self::StreamState::*; | ||||||
|  |     //     use self::PeerState::*; | ||||||
|  |  | ||||||
|  |     //     match *self { | ||||||
|  |     //         Idle => { | ||||||
|  |     //             let local = Headers; | ||||||
|  |     //             if eos { | ||||||
|  |     //                 *self = HalfClosedRemote(local); | ||||||
|  |     //             } else { | ||||||
|  |     //                 let remote = Data(FlowControlState::with_initial_size(initial_window_size)); | ||||||
|  |     //                 *self = Open { local, remote }; | ||||||
|  |     //             } | ||||||
|  |     //             Ok(true) | ||||||
|  |     //         } | ||||||
|  |  | ||||||
|  |     //         Open { local, remote } => { | ||||||
|  |     //             try!(remote.check_is_headers(ProtocolError.into())); | ||||||
|  |     //             if !eos { | ||||||
|  |     //                 // Received non-trailers HEADERS on open remote. | ||||||
|  |     //                 return Err(ProtocolError.into()); | ||||||
|  |     //             } | ||||||
|  |     //             *self = HalfClosedRemote(local); | ||||||
|  |     //             Ok(false) | ||||||
|  |     //         } | ||||||
|  |  | ||||||
|  |     //         HalfClosedLocal(headers) => { | ||||||
|  |     //             try!(headers.check_is_headers(ProtocolError.into())); | ||||||
|  |     //             if eos { | ||||||
|  |     //                 *self = Closed; | ||||||
|  |     //             } else { | ||||||
|  |     //                 let remote = FlowControlState::with_initial_size(initial_window_size); | ||||||
|  |     //                 *self = HalfClosedLocal(Data(remote)); | ||||||
|  |     //             }; | ||||||
|  |     //             Ok(false) | ||||||
|  |     //         } | ||||||
|  |  | ||||||
|  |     //         Closed | HalfClosedRemote(..) => { | ||||||
|  |     //             Err(ProtocolError.into()) | ||||||
|  |     //         } | ||||||
|  |     //     } | ||||||
|  |     // } | ||||||
|  |  | ||||||
|  |     // /// Transition the state to represent headers being sent. | ||||||
|  |     // /// | ||||||
|  |     // /// Returns true if this state transition results in initializing the stream | ||||||
|  |     // /// id. `Err` is returned if this is an invalid state transition. | ||||||
|  |     // pub fn send_headers<P: Peer>(&mut self,  | ||||||
|  |     //                              eos: bool, | ||||||
|  |     //                              initial_window_size: WindowSize) | ||||||
|  |     //     -> Result<bool, ConnectionError> | ||||||
|  |     // { | ||||||
|  |     //     use self::StreamState::*; | ||||||
|  |     //     use self::PeerState::*; | ||||||
|  |  | ||||||
|  |     //     match *self { | ||||||
|  |     //         Idle => { | ||||||
|  |     //             *self = if eos { | ||||||
|  |     //                 HalfClosedLocal(Headers) | ||||||
|  |     //             } else { | ||||||
|  |     //                 Open { | ||||||
|  |     //                     local: Data(FlowControlState::with_initial_size(initial_window_size)), | ||||||
|  |     //                     remote: Headers, | ||||||
|  |     //                 } | ||||||
|  |     //             }; | ||||||
|  |  | ||||||
|  |     //             Ok(true) | ||||||
|  |     //         } | ||||||
|  |  | ||||||
|  |     //         Open { local, remote } => { | ||||||
|  |     //             try!(local.check_is_headers(UnexpectedFrameType.into())); | ||||||
|  |  | ||||||
|  |     //             *self = if eos { | ||||||
|  |     //                 HalfClosedLocal(remote) | ||||||
|  |     //             } else { | ||||||
|  |     //                 let fc = FlowControlState::with_initial_size(initial_window_size); | ||||||
|  |     //                 let local = Data(fc); | ||||||
|  |     //                 Open { local, remote } | ||||||
|  |     //             }; | ||||||
|  |  | ||||||
|  |     //             Ok(false) | ||||||
|  |     //         } | ||||||
|  |  | ||||||
|  |     //         HalfClosedRemote(local) => { | ||||||
|  |     //             try!(local.check_is_headers(UnexpectedFrameType.into())); | ||||||
|  |  | ||||||
|  |     //             *self = if eos { | ||||||
|  |     //                 Closed | ||||||
|  |     //             } else { | ||||||
|  |     //                 let fc = FlowControlState::with_initial_size(initial_window_size); | ||||||
|  |     //                 HalfClosedRemote(Data(fc)) | ||||||
|  |     //             }; | ||||||
|  |  | ||||||
|  |     //             Ok(false) | ||||||
|  |     //         } | ||||||
|  |  | ||||||
|  |     //         Closed | HalfClosedLocal(..) => { | ||||||
|  |     //             Err(UnexpectedFrameType.into()) | ||||||
|  |     //         } | ||||||
|  |     //     } | ||||||
|  |     // } | ||||||
|  |  | ||||||
|  |     pub fn check_can_send_data(&self) -> Result<(), ConnectionError> { | ||||||
|         use self::StreamState::*; |         use self::StreamState::*; | ||||||
|  |  | ||||||
|         match self { |         match self { | ||||||
|             &Closed => true, |             &Open { ref remote, .. } => { | ||||||
|             _ => false, |                 try!(remote.check_is_data(UnexpectedFrameType.into())); | ||||||
|  |                 Ok(()) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             &HalfClosedLocal(ref remote) => { | ||||||
|  |                 try!(remote.check_is_data(UnexpectedFrameType.into())); | ||||||
|  |                 Ok(()) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             &Idle | &Closed | &HalfClosedRemote(..) => { | ||||||
|  |                 Err(UnexpectedFrameType.into()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     /// Transition the state to represent headers being received. |     } | ||||||
|     /// |  | ||||||
|     /// Returns true if this state transition results in iniitializing the |     pub fn check_can_recv_data(&self) -> Result<(), ConnectionError> { | ||||||
|     /// stream id. `Err` is returned if this is an invalid state transition. |  | ||||||
|     pub fn recv_headers<P>(&mut self, eos: bool, initial_window_size: WindowSize) |  | ||||||
|         -> Result<bool, ConnectionError> |  | ||||||
|         where P: Peer |  | ||||||
|     { |  | ||||||
|         use self::StreamState::*; |         use self::StreamState::*; | ||||||
|         use self::PeerState::*; |  | ||||||
|  |  | ||||||
|         match *self { |         match self { | ||||||
|             Idle => { |             &Open { ref local, .. } => { | ||||||
|                 let local = Headers; |                 try!(local.check_is_data(ProtocolError.into())); | ||||||
|                 if eos { |                 Ok(()) | ||||||
|                     *self = HalfClosedRemote(local); |  | ||||||
|                 } else { |  | ||||||
|                     let remote = Data(FlowControlState::with_initial_size(initial_window_size)); |  | ||||||
|                     *self = Open { local, remote }; |  | ||||||
|                 } |  | ||||||
|                 Ok(true) |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Open { local, remote } => { |             &HalfClosedRemote(ref local) => { | ||||||
|                 try!(remote.check_is_headers(ProtocolError.into())); |                 try!(local.check_is_data(ProtocolError.into())); | ||||||
|                 if !eos { |                 Ok(()) | ||||||
|                     // Received non-trailers HEADERS on open remote. |  | ||||||
|                     return Err(ProtocolError.into()); |  | ||||||
|                 } |  | ||||||
|                 *self = HalfClosedRemote(local); |  | ||||||
|                 Ok(false) |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             HalfClosedLocal(headers) => { |             &Idle | &Closed | &HalfClosedLocal(..) => { | ||||||
|                 try!(headers.check_is_headers(ProtocolError.into())); |  | ||||||
|                 if eos { |  | ||||||
|                     *self = Closed; |  | ||||||
|                 } else { |  | ||||||
|                     let remote = FlowControlState::with_initial_size(initial_window_size); |  | ||||||
|                     *self = HalfClosedLocal(Data(remote)); |  | ||||||
|                 }; |  | ||||||
|                 Ok(false) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             Closed | HalfClosedRemote(..) => { |  | ||||||
|                 Err(ProtocolError.into()) |                 Err(ProtocolError.into()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn recv_data(&mut self, eos: bool) -> Result<(), ConnectionError> { |     /// Returns true iff the stream is fully closed. | ||||||
|  |     pub fn close_local(&mut self) -> Result<bool, ConnectionError> { | ||||||
|         use self::StreamState::*; |         use self::StreamState::*; | ||||||
|  |  | ||||||
|         match *self { |         match *self { | ||||||
|             Open { local, remote } => { |             Open { remote, .. } => { | ||||||
|                 try!(remote.check_is_data(ProtocolError.into())); |                 *self = HalfClosedLocal(remote); | ||||||
|                 if eos { |                 Ok(false) | ||||||
|                     *self = HalfClosedRemote(local); |  | ||||||
|                 } |  | ||||||
|                 Ok(()) |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             HalfClosedLocal(remote) => { |             HalfClosedLocal(remote) => { | ||||||
|                 try!(remote.check_is_data(ProtocolError.into())); |  | ||||||
|                 if eos { |  | ||||||
|                 *self = Closed; |                 *self = Closed; | ||||||
|                 } |  | ||||||
|                 Ok(()) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             Closed | HalfClosedRemote(..) => { |  | ||||||
|                 Err(ProtocolError.into()) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             _ => unimplemented!(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// Transition the state to represent headers being sent. |  | ||||||
|     /// |  | ||||||
|     /// Returns true if this state transition results in initializing the stream |  | ||||||
|     /// id. `Err` is returned if this is an invalid state transition. |  | ||||||
|     pub fn send_headers<P: Peer>(&mut self,  |  | ||||||
|                                  eos: bool, |  | ||||||
|                                  initial_window_size: WindowSize) |  | ||||||
|         -> Result<bool, ConnectionError> |  | ||||||
|     { |  | ||||||
|         use self::StreamState::*; |  | ||||||
|         use self::PeerState::*; |  | ||||||
|  |  | ||||||
|         match *self { |  | ||||||
|             Idle => { |  | ||||||
|                 *self = if eos { |  | ||||||
|                     HalfClosedLocal(Headers) |  | ||||||
|                 } else { |  | ||||||
|                     Open { |  | ||||||
|                         local: Data(FlowControlState::with_initial_size(initial_window_size)), |  | ||||||
|                         remote: Headers, |  | ||||||
|                     } |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 Ok(true) |                 Ok(true) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Open { local, remote } => { |             Idle | Closed | HalfClosedRemote(..) => { | ||||||
|                 try!(local.check_is_headers(UnexpectedFrameType.into())); |                 Err(ProtocolError.into()) | ||||||
|  |  | ||||||
|                 *self = if eos { |  | ||||||
|                     HalfClosedLocal(remote) |  | ||||||
|                 } else { |  | ||||||
|                     let fc = FlowControlState::with_initial_size(initial_window_size); |  | ||||||
|                     let local = Data(fc); |  | ||||||
|                     Open { local, remote } |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 Ok(false) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             HalfClosedRemote(local) => { |  | ||||||
|                 try!(local.check_is_headers(UnexpectedFrameType.into())); |  | ||||||
|  |  | ||||||
|                 *self = if eos { |  | ||||||
|                     Closed |  | ||||||
|                 } else { |  | ||||||
|                     let fc = FlowControlState::with_initial_size(initial_window_size); |  | ||||||
|                     HalfClosedRemote(Data(fc)) |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 Ok(false) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             Closed | HalfClosedLocal(..) => { |  | ||||||
|                 Err(UnexpectedFrameType.into()) |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn send_data(&mut self, eos: bool) -> Result<(), ConnectionError> { |     /// Returns true iff the stream is fully closed. | ||||||
|  |     pub fn close_remote(&mut self) -> Result<bool, ConnectionError> { | ||||||
|         use self::StreamState::*; |         use self::StreamState::*; | ||||||
|  |  | ||||||
|         match *self { |         match *self { | ||||||
|             Open { local, remote } => { |             Open { local, .. } => { | ||||||
|                 try!(local.check_is_data(UnexpectedFrameType.into())); |                 *self = HalfClosedRemote(local); | ||||||
|                 if eos { |                 Ok(false) | ||||||
|                     *self = HalfClosedLocal(remote); |  | ||||||
|                 } |  | ||||||
|                 Ok(()) |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             HalfClosedRemote(local) => { |             HalfClosedRemote(local) => { | ||||||
|                 try!(local.check_is_data(UnexpectedFrameType.into())); |  | ||||||
|                 if eos { |  | ||||||
|                 *self = Closed; |                 *self = Closed; | ||||||
|                 } |                 Ok(true) | ||||||
|                 Ok(()) |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             Idle | Closed | HalfClosedLocal(..) => { |             Idle | Closed | HalfClosedLocal(..) => { | ||||||
|                 Err(UnexpectedFrameType.into()) |                 Err(ProtocolError.into()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -79,14 +79,22 @@ impl<T: ControlStreams> ControlStreams for StreamRecvClose<T> { | |||||||
|         T::can_create_local_stream() |         T::can_create_local_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { |     fn close_stream_local_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|         self.inner.get_reset(id) |         self.inner.close_stream_local_half(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn close_stream_remote_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.close_stream_remote_half(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { |     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||||
|         self.inner.reset_stream(id, cause) |         self.inner.reset_stream(id, cause) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||||
|  |         self.inner.get_reset(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn is_local_active(&self, id: StreamId) -> bool { |     fn is_local_active(&self, id: StreamId) -> bool { | ||||||
|         self.inner.is_local_active(id) |         self.inner.is_local_active(id) | ||||||
|     } |     } | ||||||
| @@ -118,6 +126,14 @@ impl<T: ControlStreams> ControlStreams for StreamRecvClose<T> { | |||||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { |     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||||
|         self.inner.remote_flow_controller(id) |         self.inner.remote_flow_controller(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.check_can_send_data(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>  { | ||||||
|  |         self.inner.check_can_recv_data(id) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: ApplySettings> ApplySettings for StreamRecvClose<T> { | impl<T: ApplySettings> ApplySettings for StreamRecvClose<T> { | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| use ConnectionError; | use ConnectionError; | ||||||
|  | use error::Reason::{ProtocolError, RefusedStream}; | ||||||
| use frame::{Frame, StreamId}; | use frame::{Frame, StreamId}; | ||||||
| use proto::*; | use proto::*; | ||||||
|  |  | ||||||
| @@ -35,7 +36,7 @@ impl<T, U> StreamRecvOpen<T> | |||||||
|     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, |     where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>, | ||||||
|           T: ControlStreams, |           T: ControlStreams, | ||||||
| { | { | ||||||
|     fn send_refusal(&mut self, id: StreamId) -> Poll<(), ConnectionError> { |     fn send_refuse(&mut self, id: StreamId) -> Poll<(), ConnectionError> { | ||||||
|         debug_assert!(self.pending_refuse.is_none()); |         debug_assert!(self.pending_refuse.is_none()); | ||||||
|  |  | ||||||
|         let f = frame::Reset::new(id, Reason::RefusedStream); |         let f = frame::Reset::new(id, Reason::RefusedStream); | ||||||
| @@ -99,7 +100,7 @@ impl<T, U> Stream for StreamRecvOpen<T> | |||||||
|         // Since there's only one slot for pending refused streams, it must be cleared |         // Since there's only one slot for pending refused streams, it must be cleared | ||||||
|         // before polling  a frame from the transport. |         // before polling  a frame from the transport. | ||||||
|         if let Some(id) = self.pending_refuse.take() { |         if let Some(id) = self.pending_refuse.take() { | ||||||
|             try_ready!(self.send_refusal(id)); |             try_ready!(self.send_refuse(id)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         loop { |         loop { | ||||||
| @@ -115,12 +116,27 @@ impl<T, U> Stream for StreamRecvOpen<T> | |||||||
|  |  | ||||||
|             if self.inner.get_reset(id).is_some() { |             if self.inner.get_reset(id).is_some() { | ||||||
|                 // For now, just ignore frames on reset streams. |                 // For now, just ignore frames on reset streams. | ||||||
|  |                 debug!("ignoring received frame on reset stream"); | ||||||
|                 // TODO tell the remote to knock it off? |                 // TODO tell the remote to knock it off? | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if T::is_valid_remote_id(id) { |             if T::is_valid_remote_id(id) { | ||||||
|                 unimplemented!() |                 if !self.inner.is_local_active(id) { | ||||||
|  |                     if !T::can_create_remote_stream() { | ||||||
|  |                         return Err(ProtocolError.into()); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if let Some(max) = self.max_concurrency { | ||||||
|  |                         if (max as usize) < self.inner.local_active_len() { | ||||||
|  |                             return Err(RefusedStream.into()); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // If the frame ends the stream, it will be handled in | ||||||
|  |                 // StreamRecvClose. | ||||||
|  |                 return Ok(Async::Ready(Some(frame))); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -139,7 +155,7 @@ impl<T, U> Sink for StreamRecvOpen<T> | |||||||
|         // The local must complete refusing the remote stream before sending any other |         // The local must complete refusing the remote stream before sending any other | ||||||
|         // frames. |         // frames. | ||||||
|         if let Some(id) = self.pending_refuse.take() { |         if let Some(id) = self.pending_refuse.take() { | ||||||
|             if self.send_refusal(id)?.is_not_ready() { |             if self.send_refuse(id)?.is_not_ready() { | ||||||
|                 return Ok(AsyncSink::NotReady(frame)); |                 return Ok(AsyncSink::NotReady(frame)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -157,7 +173,7 @@ impl<T, U> Sink for StreamRecvOpen<T> | |||||||
|  |  | ||||||
|     fn poll_complete(&mut self) -> Poll<(), T::SinkError> { |     fn poll_complete(&mut self) -> Poll<(), T::SinkError> { | ||||||
|         if let Some(id) = self.pending_refuse.take() { |         if let Some(id) = self.pending_refuse.take() { | ||||||
|             try_ready!(self.send_refusal(id)); |             try_ready!(self.send_refuse(id)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         self.inner.poll_complete() |         self.inner.poll_complete() | ||||||
| @@ -173,7 +189,7 @@ impl<T, U> ReadySink for StreamRecvOpen<T> | |||||||
| { | { | ||||||
|     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { |     fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||||
|         if let Some(id) = self.pending_refuse.take() { |         if let Some(id) = self.pending_refuse.take() { | ||||||
|             try_ready!(self.send_refusal(id)); |             try_ready!(self.send_refuse(id)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         self.inner.poll_ready() |         self.inner.poll_ready() | ||||||
| @@ -284,7 +300,6 @@ impl<T, U> ReadySink for StreamRecvOpen<T> | |||||||
|     //     return Ok(Async::Ready(None)); |     //     return Ok(Async::Ready(None)); | ||||||
|     // } |     // } | ||||||
|  |  | ||||||
|  |  | ||||||
| impl<T: ControlStreams> ControlStreams for StreamRecvOpen<T> { | impl<T: ControlStreams> ControlStreams for StreamRecvOpen<T> { | ||||||
|     fn is_valid_local_id(id: StreamId) -> bool { |     fn is_valid_local_id(id: StreamId) -> bool { | ||||||
|         T::is_valid_local_id(id) |         T::is_valid_local_id(id) | ||||||
| @@ -298,14 +313,22 @@ impl<T: ControlStreams> ControlStreams for StreamRecvOpen<T> { | |||||||
|         T::can_create_local_stream() |         T::can_create_local_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { |     fn close_stream_local_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|         self.inner.get_reset(id) |         self.inner.close_stream_local_half(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn close_stream_remote_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.close_stream_remote_half(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { |     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||||
|         self.inner.reset_stream(id, cause) |         self.inner.reset_stream(id, cause) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||||
|  |         self.inner.get_reset(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn is_local_active(&self, id: StreamId) -> bool { |     fn is_local_active(&self, id: StreamId) -> bool { | ||||||
|         self.inner.is_local_active(id) |         self.inner.is_local_active(id) | ||||||
|     } |     } | ||||||
| @@ -337,6 +360,14 @@ impl<T: ControlStreams> ControlStreams for StreamRecvOpen<T> { | |||||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { |     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||||
|         self.inner.remote_flow_controller(id) |         self.inner.remote_flow_controller(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.check_can_send_data(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>  { | ||||||
|  |         self.inner.check_can_recv_data(id) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: ControlPing> ControlPing for StreamRecvOpen<T> { | impl<T: ControlPing> ControlPing for StreamRecvOpen<T> { | ||||||
|   | |||||||
| @@ -42,8 +42,17 @@ impl<T, U> Sink for StreamSendClose<T> | |||||||
|     type SinkItem = Frame<U>; |     type SinkItem = Frame<U>; | ||||||
|     type SinkError = ConnectionError; |     type SinkError = ConnectionError; | ||||||
|  |  | ||||||
|     fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Frame<U>, ConnectionError> { |     fn start_send(&mut self, frame: Self::SinkItem) -> StartSend<Frame<U>, ConnectionError> { | ||||||
|         self.inner.start_send(item) |         if frame.is_end_stream() { | ||||||
|  |             let id = frame.stream_id(); | ||||||
|  |             if let &Frame::Reset(ref rst) = &frame { | ||||||
|  |                 self.inner.reset_stream(id, rst.reason()); | ||||||
|  |             } else { | ||||||
|  |                 self.inner.close_stream_local_half(id)?; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self.inner.start_send(frame) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { |     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||||
| @@ -84,14 +93,22 @@ impl<T: ControlStreams> ControlStreams for StreamSendClose<T> { | |||||||
|         T::can_create_local_stream() |         T::can_create_local_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { |     fn close_stream_local_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|         self.inner.get_reset(id) |         self.inner.close_stream_local_half(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn close_stream_remote_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.close_stream_remote_half(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { |     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||||
|         self.inner.reset_stream(id, cause) |         self.inner.reset_stream(id, cause) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||||
|  |         self.inner.get_reset(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn is_local_active(&self, id: StreamId) -> bool { |     fn is_local_active(&self, id: StreamId) -> bool { | ||||||
|         self.inner.is_local_active(id) |         self.inner.is_local_active(id) | ||||||
|     } |     } | ||||||
| @@ -123,6 +140,14 @@ impl<T: ControlStreams> ControlStreams for StreamSendClose<T> { | |||||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { |     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||||
|         self.inner.remote_flow_controller(id) |         self.inner.remote_flow_controller(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.check_can_send_data(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>  { | ||||||
|  |         self.inner.check_can_recv_data(id) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: ControlPing> ControlPing for StreamSendClose<T> { | impl<T: ControlPing> ControlPing for StreamSendClose<T> { | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| use ConnectionError; | use ConnectionError; | ||||||
| use error::User::{InvalidStreamId, StreamReset}; | use error::User::{InvalidStreamId, StreamReset, Rejected}; | ||||||
| use frame::{Frame, SettingSet}; | use frame::{Frame, SettingSet}; | ||||||
| use proto::*; | use proto::*; | ||||||
|  |  | ||||||
| @@ -101,35 +101,28 @@ impl<T, U> Sink for StreamSendOpen<T> | |||||||
|  |  | ||||||
|         if T::is_valid_local_id(id) { |         if T::is_valid_local_id(id) { | ||||||
|             if self.inner.is_local_active(id) { |             if self.inner.is_local_active(id) { | ||||||
|                 // If the frame ends thestream, it will be handled in stream_recv. |             } else if T::can_create_local_stream() { | ||||||
|                 return self.inner.start_send(frame); |                 if let Some(max) = self.max_concurrency { | ||||||
|  |                     if (max as usize) < self.inner.local_active_len() { | ||||||
|  |                         return Err(Rejected.into()); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|             if T::can_create_local_stream() { |                 // TODO create that shit. | ||||||
|                 let has_capacity = match self.max_concurrency { |  | ||||||
|                     None => true, |  | ||||||
|                     Some(max) => self.inner.local_active_len() < (max as usize), |  | ||||||
|                 }; |  | ||||||
|                 if has_capacity { |  | ||||||
|                     // create that shit. |  | ||||||
|                     unimplemented!(); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             if self.inner.is_remote_active(id) { |             // If the frame was part of a remote stream, it MUST already exist. | ||||||
|                 // If the frame was part of a remote stream, it MUST already exist. If the |             if !self.inner.is_remote_active(id) && !frame.is_reset() { | ||||||
|                 // frame ends thestream, it will be handled in stream_recv. |  | ||||||
|                 return self.inner.start_send(frame); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if let Reset(rst) = frame { |  | ||||||
|                 return self.inner.start_send(Reset(rst)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Tried to send a frame on a stream |  | ||||||
|                 return Err(InvalidStreamId.into()); |                 return Err(InvalidStreamId.into()); | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if let &Data(..) = &frame { | ||||||
|  |             self.inner.check_can_send_data(id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return 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() |         self.inner.poll_complete() | ||||||
| @@ -160,14 +153,22 @@ impl<T: ControlStreams> ControlStreams for StreamSendOpen<T> { | |||||||
|         T::can_create_local_stream() |         T::can_create_local_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { |     fn close_stream_local_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|         self.inner.get_reset(id) |         self.inner.close_stream_local_half(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn close_stream_remote_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.close_stream_remote_half(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { |     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||||
|         self.inner.reset_stream(id, cause) |         self.inner.reset_stream(id, cause) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||||
|  |         self.inner.get_reset(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn is_local_active(&self, id: StreamId) -> bool { |     fn is_local_active(&self, id: StreamId) -> bool { | ||||||
|         self.inner.is_local_active(id) |         self.inner.is_local_active(id) | ||||||
|     } |     } | ||||||
| @@ -199,6 +200,14 @@ impl<T: ControlStreams> ControlStreams for StreamSendOpen<T> { | |||||||
|     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { |     fn remote_flow_controller(&mut self, id: StreamId) -> Option<&mut FlowControlState> { | ||||||
|         self.inner.remote_flow_controller(id) |         self.inner.remote_flow_controller(id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         self.inner.check_can_send_data(id) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>  { | ||||||
|  |         self.inner.check_can_recv_data(id) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: ControlFlow> ControlFlow for StreamSendOpen<T> { | impl<T: ControlFlow> ControlFlow for StreamSendOpen<T> { | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| use {ConnectionError, Peer, StreamId}; | use {ConnectionError, Peer, StreamId}; | ||||||
| use error::Reason; | use error::Reason::{NoError, ProtocolError}; | ||||||
| use proto::*; | use proto::*; | ||||||
|  |  | ||||||
| use fnv::FnvHasher; | use fnv::FnvHasher; | ||||||
| @@ -18,8 +18,10 @@ pub trait ControlStreams { | |||||||
|         !Self::can_create_local_stream() |         !Self::can_create_local_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason>; |     fn close_stream_local_half(&mut self, id: StreamId) -> Result<(), ConnectionError>; | ||||||
|  |     fn close_stream_remote_half(&mut self, id: StreamId) -> Result<(), ConnectionError>; | ||||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason); |     fn reset_stream(&mut self, id: StreamId, cause: Reason); | ||||||
|  |     fn get_reset(&self, id: StreamId) -> Option<Reason>; | ||||||
|  |  | ||||||
|     fn is_local_active(&self, id: StreamId) -> bool; |     fn is_local_active(&self, id: StreamId) -> bool; | ||||||
|     fn is_remote_active(&self, id: StreamId) -> bool; |     fn is_remote_active(&self, id: StreamId) -> bool; | ||||||
| @@ -33,13 +35,8 @@ pub trait ControlStreams { | |||||||
|     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32); |     fn local_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32); | ||||||
|     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32); |     fn remote_update_inital_window_size(&mut self, old_sz: u32, new_sz: u32); | ||||||
|  |  | ||||||
|     // fn get_active(&self, id: StreamId) -> Option<&StreamState> { |     fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError>; | ||||||
|     //     self.streams(id).get_active(id) |     fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>; | ||||||
|     // } |  | ||||||
|  |  | ||||||
|     // fn get_active_mut(&mut self, id: StreamId) -> Option<&mut StreamState>  { |  | ||||||
|     //     self.streams_mut(id).get_active_mut(id) |  | ||||||
|     // } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Holds the underlying stream state to be accessed by upper layers. | /// Holds the underlying stream state to be accessed by upper layers. | ||||||
| @@ -112,6 +109,35 @@ impl<T, P, U> ReadySink for StreamStore<T, P> | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl<T, P: Peer> StreamStore<T, P> { | ||||||
|  |     pub fn get_active(&mut self, id: StreamId) -> Option<&StreamState> { | ||||||
|  |         assert!(!id.is_zero()); | ||||||
|  |         if P::is_valid_local_stream_id(id) { | ||||||
|  |             self.local_active.get(&id) | ||||||
|  |         } else { | ||||||
|  |             self.remote_active.get(&id) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn get_active_mut(&mut self, id: StreamId) -> Option<&mut StreamState> { | ||||||
|  |         assert!(!id.is_zero()); | ||||||
|  |         if P::is_valid_local_stream_id(id) { | ||||||
|  |             self.local_active.get_mut(&id) | ||||||
|  |         } else { | ||||||
|  |             self.remote_active.get_mut(&id) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn remove_active(&mut self, id: StreamId) { | ||||||
|  |         assert!(!id.is_zero()); | ||||||
|  |         if P::is_valid_local_stream_id(id) { | ||||||
|  |             self.local_active.remove(&id); | ||||||
|  |         } else { | ||||||
|  |             self.remote_active.remove(&id); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl<T, P: Peer> ControlStreams for StreamStore<T, P> { | impl<T, P: Peer> ControlStreams for StreamStore<T, P> { | ||||||
|     fn is_valid_local_id(id: StreamId) -> bool { |     fn is_valid_local_id(id: StreamId) -> bool { | ||||||
|         P::is_valid_local_stream_id(id) |         P::is_valid_local_stream_id(id) | ||||||
| @@ -125,19 +151,39 @@ impl<T, P: Peer> ControlStreams for StreamStore<T, P> { | |||||||
|         P::can_create_local_stream() |         P::can_create_local_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_reset(&self, id: StreamId) -> Option<Reason> { |     fn close_stream_local_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|         self.reset.get(&id).map(|r| *r) |         let fully_closed = self.get_active_mut(id) | ||||||
|  |             .map(|s| s.close_local()) | ||||||
|  |             .unwrap_or_else(|| Err(ProtocolError.into()))?; | ||||||
|  |  | ||||||
|  |         if fully_closed { | ||||||
|  |             self.remove_active(id); | ||||||
|  |             self.reset.insert(id, NoError); | ||||||
|  |         } | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn close_stream_remote_half(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         let fully_closed = self.get_active_mut(id) | ||||||
|  |             .map(|s| s.close_remote()) | ||||||
|  |             .unwrap_or_else(|| Err(ProtocolError.into()))?; | ||||||
|  |  | ||||||
|  |         if fully_closed { | ||||||
|  |             self.remove_active(id); | ||||||
|  |             self.reset.insert(id, NoError); | ||||||
|  |         } | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn reset_stream(&mut self, id: StreamId, cause: Reason) { |     fn reset_stream(&mut self, id: StreamId, cause: Reason) { | ||||||
|         if P::is_valid_local_stream_id(id) { |         self.remove_active(id); | ||||||
|             self.local_active.remove(&id); |  | ||||||
|         } else { |  | ||||||
|             self.remote_active.remove(&id); |  | ||||||
|         } |  | ||||||
|         self.reset.insert(id, cause); |         self.reset.insert(id, cause); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn get_reset(&self, id: StreamId) -> Option<Reason> { | ||||||
|  |         self.reset.get(&id).map(|r| *r) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn is_local_active(&self, id: StreamId) -> bool { |     fn is_local_active(&self, id: StreamId) -> bool { | ||||||
|         self.local_active.contains_key(&id) |         self.local_active.contains_key(&id) | ||||||
|     } |     } | ||||||
| @@ -237,6 +283,20 @@ impl<T, P: Peer> ControlStreams for StreamStore<T, P> { | |||||||
|             self.remote_active.get_mut(&id).and_then(|s| s.remote_flow_controller()) |             self.remote_active.get_mut(&id).and_then(|s| s.remote_flow_controller()) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         if let Some(s) = self.get_active(id) { | ||||||
|  |             return s.check_can_send_data(); | ||||||
|  |         } | ||||||
|  |         Err(ProtocolError.into()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>  { | ||||||
|  |         if let Some(s) = self.get_active(id) { | ||||||
|  |             return s.check_can_recv_data(); | ||||||
|  |         } | ||||||
|  |         Err(ProtocolError.into()) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: ApplySettings, P> ApplySettings for StreamStore<T, P> { | impl<T: ApplySettings, P> ApplySettings for StreamStore<T, P> { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user