When Streams are dropped, close Connection (#221) (#222)

When all Streams are dropped / finished, the Connection was held
open until the peer hangs up. Instead, the Connection should hang up
once it knows that nothing more will be sent.

To fix this, we notify the Connection when a stream is no longer
referenced. On the Connection poll(), we check that there are no
active, held, reset streams or any references to the Streams
and transition to sending a GOAWAY if that is case.

The specific behavior depends on if running as a client or server.
This commit is contained in:
Darren Tsung
2018-02-15 13:14:18 -08:00
committed by Carl Lerche
parent 73b4c03b55
commit 0c59957d88
14 changed files with 193 additions and 45 deletions

View File

@@ -1,10 +1,10 @@
use super::{Buffer, Config, Counts, Prioritized, Recv, Send, Stream, StreamId};
use super::recv::RecvHeaderBlockError;
use super::store::{self, Entry, Resolve, Store};
use {client, proto, server};
use codec::{Codec, RecvError, SendError, UserError};
use frame::{self, Frame, Reason};
use proto::{peer, Peer, WindowSize};
use super::{Buffer, Config, Counts, Prioritized, Recv, Send, Stream, StreamId};
use super::recv::RecvHeaderBlockError;
use super::store::{self, Entry, Resolve, Store};
use bytes::{Buf, Bytes};
use futures::{task, Async, Poll};
@@ -520,8 +520,8 @@ where
end_of_stream: bool,
pending: Option<&store::Key>,
) -> Result<StreamRef<B>, SendError> {
use super::stream::ContentLength;
use http::Method;
use super::stream::ContentLength;
// TODO: There is a hazard with assigning a stream ID before the
// prioritize layer. If prioritization reorders new streams, this
@@ -661,6 +661,19 @@ where
me.store.num_active_streams()
}
pub fn has_streams_or_other_references(&self) -> bool {
if Arc::strong_count(&self.inner) > 1 {
return true;
}
if Arc::strong_count(&self.send_buffer) > 1 {
return true;
}
let me = self.inner.lock().unwrap();
me.counts.has_streams()
}
#[cfg(feature = "unstable")]
pub fn num_wired_streams(&self) -> usize {
let me = self.inner.lock().unwrap();
@@ -951,6 +964,16 @@ fn drop_stream_ref(inner: &Mutex<Inner>, key: store::Key) {
let actions = &mut me.actions;
// If the stream is not referenced and it is already
// closed (does not have to go through logic below
// of canceling the stream), we should notify the task
// (connection) so that it can close properly
if stream.ref_count == 0 && stream.is_closed() {
if let Some(task) = actions.task.take() {
task.notify();
}
}
me.counts.transition(stream, |counts, stream| {
maybe_cancel(stream, actions, counts);