Fix an infinite loop in ProtocolsHandlerSelect (#961)

This commit is contained in:
Pierre Krieger
2019-02-20 15:06:49 +01:00
committed by GitHub
parent e92c6a219b
commit e1ad88f757
2 changed files with 53 additions and 8 deletions

View File

@ -29,11 +29,37 @@ use crate::{
} }
}; };
use futures::prelude::*; use futures::prelude::*;
use std::mem;
/// Wrapper around a protocol handler and ignores all further method calls once it has shut down. /// Wrapper around a protocol handler and ignores all further method calls once it has shut down.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Fuse<TProtoHandler> { pub struct Fuse<TProtoHandler> {
inner: Option<TProtoHandler>, inner: State<TProtoHandler>,
}
#[derive(Debug, Copy, Clone)]
enum State<TProtoHandler> {
Normal(TProtoHandler),
ShuttingDown(TProtoHandler),
Shutdown,
}
impl<TProtoHandler> State<TProtoHandler> {
fn as_ref(&self) -> Option<&TProtoHandler> {
match self {
State::Normal(h) => Some(h),
State::ShuttingDown(h) => Some(h),
State::Shutdown => None,
}
}
fn as_mut(&mut self) -> Option<&mut TProtoHandler> {
match self {
State::Normal(h) => Some(h),
State::ShuttingDown(h) => Some(h),
State::Shutdown => None,
}
}
} }
impl<TProtoHandler> Fuse<TProtoHandler> { impl<TProtoHandler> Fuse<TProtoHandler> {
@ -41,14 +67,28 @@ impl<TProtoHandler> Fuse<TProtoHandler> {
#[inline] #[inline]
pub(crate) fn new(inner: TProtoHandler) -> Self { pub(crate) fn new(inner: TProtoHandler) -> Self {
Fuse { Fuse {
inner: Some(inner), inner: State::Normal(inner),
}
}
/// Returns true if `shutdown()` has been called in the past, or if polling has returned
/// `Shutdown` in the past.
pub fn is_shutting_down_or_shutdown(&self) -> bool {
match self.inner {
State::Normal(_) => false,
State::ShuttingDown(_) => true,
State::Shutdown => true,
} }
} }
/// Returns true if polling has returned `Shutdown` in the past. /// Returns true if polling has returned `Shutdown` in the past.
#[inline] #[inline]
pub fn is_shutdown(&self) -> bool { pub fn is_shutdown(&self) -> bool {
self.inner.is_none() if let State::Shutdown = self.inner {
true
} else {
false
}
} }
} }
@ -134,9 +174,14 @@ where
#[inline] #[inline]
fn shutdown(&mut self) { fn shutdown(&mut self) {
if let Some(inner) = self.inner.as_mut() { self.inner = match mem::replace(&mut self.inner, State::Shutdown) {
inner.shutdown() State::Normal(mut inner) => {
} inner.shutdown();
State::ShuttingDown(inner)
},
s @ State::ShuttingDown(_) => s,
s @ State::Shutdown => s,
};
} }
#[inline] #[inline]
@ -152,7 +197,7 @@ where
}; };
if let Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown)) = poll { if let Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown)) = poll {
self.inner = None; self.inner = State::Shutdown;
} }
poll poll

View File

@ -248,7 +248,7 @@ where
})); }));
}, },
Async::Ready(ProtocolsHandlerEvent::Shutdown) => { Async::Ready(ProtocolsHandlerEvent::Shutdown) => {
if !self.proto1.is_shutdown() { if !self.proto1.is_shutting_down_or_shutdown() {
self.proto1.shutdown(); self.proto1.shutdown();
continue; continue;
} }