Cleaner shutdown process (#992)

* Cleaner shutdown process

* Finish

* Fix Yamux panic

* Remove irrelevant tests

* Update core/src/nodes/handled_node_tasks.rs

Co-Authored-By: tomaka <pierre.krieger1708@gmail.com>

* Fix yamux error handling

* Update yamux
This commit is contained in:
Pierre Krieger
2019-03-11 17:19:50 +01:00
committed by GitHub
parent cb93c822f1
commit 8059a693a3
32 changed files with 434 additions and 1555 deletions

View File

@ -33,7 +33,6 @@ use void::Void;
/// Implementation of `ProtocolsHandler` that doesn't handle anything.
pub struct DummyProtocolsHandler<TSubstream> {
shutting_down: bool,
marker: PhantomData<TSubstream>,
}
@ -41,7 +40,6 @@ impl<TSubstream> Default for DummyProtocolsHandler<TSubstream> {
#[inline]
fn default() -> Self {
DummyProtocolsHandler {
shutting_down: false,
marker: PhantomData,
}
}
@ -85,17 +83,9 @@ where
#[inline]
fn inject_dial_upgrade_error(&mut self, _: Self::OutboundOpenInfo, _: ProtocolsHandlerUpgrErr<<Self::OutboundProtocol as OutboundUpgrade<Self::Substream>>::Error>) {}
#[inline]
fn inject_inbound_closed(&mut self) {}
#[inline]
fn connection_keep_alive(&self) -> KeepAlive { KeepAlive::Now }
#[inline]
fn shutdown(&mut self) {
self.shutting_down = true;
}
#[inline]
fn poll(
&mut self,
@ -103,10 +93,6 @@ where
ProtocolsHandlerEvent<Self::OutboundProtocol, Self::OutboundOpenInfo, Self::OutEvent>,
Void,
> {
if self.shutting_down {
Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown))
} else {
Ok(Async::NotReady)
}
Ok(Async::NotReady)
}
}

View File

@ -1,205 +0,0 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use crate::{
either::EitherOutput,
protocols_handler::{KeepAlive, ProtocolsHandler, ProtocolsHandlerEvent, ProtocolsHandlerUpgrErr},
upgrade::{
DeniedUpgrade,
EitherUpgrade,
InboundUpgrade,
OutboundUpgrade,
}
};
use futures::prelude::*;
use std::mem;
/// Wrapper around a protocol handler and ignores all further method calls once it has shut down.
#[derive(Debug, Copy, Clone)]
pub struct Fuse<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> {
/// Creates a `Fuse`.
#[inline]
pub(crate) fn new(inner: TProtoHandler) -> Self {
Fuse {
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.
#[inline]
pub fn is_shutdown(&self) -> bool {
if let State::Shutdown = self.inner {
true
} else {
false
}
}
}
impl<TProtoHandler> ProtocolsHandler for Fuse<TProtoHandler>
where
TProtoHandler: ProtocolsHandler,
{
type InEvent = TProtoHandler::InEvent;
type OutEvent = TProtoHandler::OutEvent;
type Error = TProtoHandler::Error;
type Substream = TProtoHandler::Substream;
type InboundProtocol = EitherUpgrade<TProtoHandler::InboundProtocol, DeniedUpgrade>;
type OutboundProtocol = TProtoHandler::OutboundProtocol;
type OutboundOpenInfo = TProtoHandler::OutboundOpenInfo;
#[inline]
fn listen_protocol(&self) -> Self::InboundProtocol {
if let Some(inner) = self.inner.as_ref() {
EitherUpgrade::A(inner.listen_protocol())
} else {
EitherUpgrade::B(DeniedUpgrade)
}
}
#[inline]
fn inject_fully_negotiated_inbound(
&mut self,
protocol: <Self::InboundProtocol as InboundUpgrade<Self::Substream>>::Output
) {
match (protocol, self.inner.as_mut()) {
(EitherOutput::First(proto), Some(inner)) => {
inner.inject_fully_negotiated_inbound(proto)
},
(EitherOutput::Second(_), None) => {}
(EitherOutput::First(_), None) => {} // Can happen if we shut down during an upgrade.
(EitherOutput::Second(_), Some(_)) => {
panic!("Wrong API usage; an upgrade was passed to a different object that the \
one that asked for the upgrade")
},
}
}
#[inline]
fn inject_fully_negotiated_outbound(
&mut self,
protocol: <Self::OutboundProtocol as OutboundUpgrade<Self::Substream>>::Output,
info: Self::OutboundOpenInfo
) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_fully_negotiated_outbound(protocol, info)
}
}
#[inline]
fn inject_event(&mut self, event: Self::InEvent) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_event(event)
}
}
#[inline]
fn inject_dial_upgrade_error(&mut self, info: Self::OutboundOpenInfo, error: ProtocolsHandlerUpgrErr<<Self::OutboundProtocol as OutboundUpgrade<Self::Substream>>::Error>) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_dial_upgrade_error(info, error)
}
}
#[inline]
fn inject_inbound_closed(&mut self) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_inbound_closed()
}
}
#[inline]
fn connection_keep_alive(&self) -> KeepAlive {
if let Some(inner) = self.inner.as_ref() {
inner.connection_keep_alive()
} else {
KeepAlive::Now
}
}
#[inline]
fn shutdown(&mut self) {
self.inner = match mem::replace(&mut self.inner, State::Shutdown) {
State::Normal(mut inner) => {
inner.shutdown();
State::ShuttingDown(inner)
},
s @ State::ShuttingDown(_) => s,
s @ State::Shutdown => s,
};
}
#[inline]
fn poll(
&mut self,
) -> Poll<
ProtocolsHandlerEvent<Self::OutboundProtocol, Self::OutboundOpenInfo, Self::OutEvent>,
Self::Error,
> {
let poll = match self.inner.as_mut() {
Some(i) => i.poll(),
None => return Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown)),
};
if let Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown)) = poll {
self.inner = State::Shutdown;
}
poll
}
}

View File

@ -94,21 +94,11 @@ where
self.inner.inject_dial_upgrade_error(info, error)
}
#[inline]
fn inject_inbound_closed(&mut self) {
self.inner.inject_inbound_closed()
}
#[inline]
fn connection_keep_alive(&self) -> KeepAlive {
self.inner.connection_keep_alive()
}
#[inline]
fn shutdown(&mut self) {
self.inner.shutdown()
}
#[inline]
fn poll(
&mut self,

View File

@ -89,21 +89,11 @@ where
self.inner.inject_dial_upgrade_error(info, error)
}
#[inline]
fn inject_inbound_closed(&mut self) {
self.inner.inject_inbound_closed()
}
#[inline]
fn connection_keep_alive(&self) -> KeepAlive {
self.inner.connection_keep_alive()
}
#[inline]
fn shutdown(&mut self) {
self.inner.shutdown()
}
#[inline]
fn poll(
&mut self,
@ -114,7 +104,6 @@ where
Ok(self.inner.poll()?.map(|ev| {
match ev {
ProtocolsHandlerEvent::Custom(ev) => ProtocolsHandlerEvent::Custom((self.map)(ev)),
ProtocolsHandlerEvent::Shutdown => ProtocolsHandlerEvent::Shutdown,
ProtocolsHandlerEvent::OutboundSubstreamRequest { upgrade, info } => {
ProtocolsHandlerEvent::OutboundSubstreamRequest { upgrade, info }
}

View File

@ -44,15 +44,13 @@ use std::{cmp::Ordering, error, fmt, time::Duration, time::Instant};
use tokio_io::{AsyncRead, AsyncWrite};
pub use self::dummy::DummyProtocolsHandler;
pub use self::fuse::Fuse;
pub use self::map_in::MapInEvent;
pub use self::map_out::MapOutEvent;
pub use self::node_handler::{NodeHandlerWrapper, NodeHandlerWrapperBuilder};
pub use self::node_handler::{NodeHandlerWrapper, NodeHandlerWrapperBuilder, NodeHandlerWrapperError};
pub use self::one_shot::OneShotHandler;
pub use self::select::{IntoProtocolsHandlerSelect, ProtocolsHandlerSelect};
mod dummy;
mod fuse;
mod map_in;
mod map_out;
mod node_handler;
@ -138,10 +136,6 @@ pub trait ProtocolsHandler {
/// Indicates to the handler that upgrading a substream to the given protocol has failed.
fn inject_dial_upgrade_error(&mut self, info: Self::OutboundOpenInfo, error: ProtocolsHandlerUpgrErr<<Self::OutboundProtocol as OutboundUpgrade<Self::Substream>>::Error>);
/// Indicates to the handler that the inbound part of the muxer has been closed, and that
/// therefore no more inbound substreams will be produced.
fn inject_inbound_closed(&mut self);
/// Returns until when the connection should be kept alive.
///
/// If returns `Until`, that indicates that this connection may invoke `shutdown()` after the
@ -160,20 +154,9 @@ pub trait ProtocolsHandler {
/// After `shutdown()` is called, the result of this method doesn't matter anymore.
fn connection_keep_alive(&self) -> KeepAlive;
/// Indicates to the node that it should shut down. After that, it is expected that `poll()`
/// returns `Ready(ProtocolsHandlerEvent::Shutdown)` as soon as possible.
/// Should behave like `Stream::poll()`.
///
/// This method allows an implementation to perform a graceful shutdown of the substreams, and
/// send back various events.
fn shutdown(&mut self);
/// Should behave like `Stream::poll()`. Should close if no more event can be produced and the
/// node should be closed.
///
/// > **Note**: If this handler is combined with other handlers, as soon as `poll()` returns
/// > `Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown))`, all the other handlers
/// > will receive a call to `shutdown()` and will eventually be closed and
/// > destroyed.
/// Returning an error will close the connection to the remote.
fn poll(&mut self) -> Poll<ProtocolsHandlerEvent<Self::OutboundProtocol, Self::OutboundOpenInfo, Self::OutEvent>, Self::Error>;
/// Adds a closure that turns the input event into something else.
@ -196,16 +179,6 @@ pub trait ProtocolsHandler {
MapOutEvent::new(self, map)
}
/// Wraps around `self`. When `poll()` returns `Shutdown`, any further call to any method will
/// be ignored.
#[inline]
fn fuse(self) -> Fuse<Self>
where
Self: Sized,
{
Fuse::new(self)
}
/// Builds an implementation of `ProtocolsHandler` that handles both this protocol and the
/// other one together.
#[inline]
@ -251,11 +224,6 @@ pub enum ProtocolsHandlerEvent<TConnectionUpgrade, TOutboundOpenInfo, TCustom> {
info: TOutboundOpenInfo,
},
/// Perform a graceful shutdown of the connection to the remote.
///
/// Should be returned after `shutdown()` has been called.
Shutdown,
/// Other event.
Custom(TCustom),
}
@ -280,7 +248,6 @@ impl<TConnectionUpgrade, TOutboundOpenInfo, TCustom>
info: map(info),
}
}
ProtocolsHandlerEvent::Shutdown => ProtocolsHandlerEvent::Shutdown,
ProtocolsHandlerEvent::Custom(val) => ProtocolsHandlerEvent::Custom(val),
}
}
@ -301,7 +268,6 @@ impl<TConnectionUpgrade, TOutboundOpenInfo, TCustom>
info,
}
}
ProtocolsHandlerEvent::Shutdown => ProtocolsHandlerEvent::Shutdown,
ProtocolsHandlerEvent::Custom(val) => ProtocolsHandlerEvent::Custom(val),
}
}
@ -319,7 +285,6 @@ impl<TConnectionUpgrade, TOutboundOpenInfo, TCustom>
ProtocolsHandlerEvent::OutboundSubstreamRequest { upgrade, info } => {
ProtocolsHandlerEvent::OutboundSubstreamRequest { upgrade, info }
}
ProtocolsHandlerEvent::Shutdown => ProtocolsHandlerEvent::Shutdown,
ProtocolsHandlerEvent::Custom(val) => ProtocolsHandlerEvent::Custom(map(val)),
}
}

View File

@ -31,7 +31,7 @@ use crate::{
}
};
use futures::prelude::*;
use std::time::{Duration, Instant};
use std::{error, fmt, time::Duration, time::Instant};
use tokio_timer::{Delay, Timeout};
/// Prototype for a `NodeHandlerWrapper`.
@ -145,6 +145,46 @@ where
connection_shutdown: Option<Delay>,
}
/// Error generated by the `NodeHandlerWrapper`.
#[derive(Debug)]
pub enum NodeHandlerWrapperError<TErr> {
/// Error generated by the handler.
Handler(TErr),
/// The connection has been deemed useless and has been closed.
UselessTimeout,
}
impl<TErr> From<TErr> for NodeHandlerWrapperError<TErr> {
fn from(err: TErr) -> NodeHandlerWrapperError<TErr> {
NodeHandlerWrapperError::Handler(err)
}
}
impl<TErr> fmt::Display for NodeHandlerWrapperError<TErr>
where
TErr: fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NodeHandlerWrapperError::Handler(err) => write!(f, "{}", err),
NodeHandlerWrapperError::UselessTimeout =>
write!(f, "Node has been closed due to inactivity"),
}
}
}
impl<TErr> error::Error for NodeHandlerWrapperError<TErr>
where
TErr: error::Error + 'static
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
NodeHandlerWrapperError::Handler(err) => Some(err),
NodeHandlerWrapperError::UselessTimeout => None,
}
}
}
impl<TProtoHandler> NodeHandler for NodeHandlerWrapper<TProtoHandler>
where
TProtoHandler: ProtocolsHandler,
@ -153,7 +193,7 @@ where
{
type InEvent = TProtoHandler::InEvent;
type OutEvent = TProtoHandler::OutEvent;
type Error = TProtoHandler::Error;
type Error = NodeHandlerWrapperError<TProtoHandler::Error>;
type Substream = TProtoHandler::Substream;
// The first element of the tuple is the unique upgrade identifier
// (see `unique_dial_upgrade_id`).
@ -192,42 +232,11 @@ where
}
}
#[inline]
fn inject_inbound_closed(&mut self) {
self.handler.inject_inbound_closed();
}
fn inject_outbound_closed(&mut self, user_data: Self::OutboundOpenInfo) {
let pos = match self
.queued_dial_upgrades
.iter()
.position(|(id, _)| id == &user_data.0)
{
Some(p) => p,
None => {
debug_assert!(
false,
"Received an outbound closed error with an invalid upgrade ID"
);
return;
}
};
self.queued_dial_upgrades.remove(pos);
self.handler
.inject_dial_upgrade_error(user_data.1, ProtocolsHandlerUpgrErr::MuxerDeniedSubstream);
}
#[inline]
fn inject_event(&mut self, event: Self::InEvent) {
self.handler.inject_event(event);
}
#[inline]
fn shutdown(&mut self) {
self.handler.shutdown();
}
fn poll(&mut self) -> Poll<NodeHandlerEvent<Self::OutboundOpenInfo, Self::OutEvent>, Self::Error> {
// Continue negotiation of newly-opened substreams on the listening side.
// We remove each element from `negotiating_in` one by one and add them back if not ready.
@ -273,55 +282,47 @@ where
// Poll the handler at the end so that we see the consequences of the method calls on
// `self.handler`.
loop {
let poll_result = self.handler.poll()?;
let poll_result = self.handler.poll()?;
self.connection_shutdown = match self.handler.connection_keep_alive() {
KeepAlive::Until(expiration) => Some(Delay::new(expiration)),
KeepAlive::Now => Some(Delay::new(Instant::now())),
KeepAlive::Forever => None,
};
self.connection_shutdown = match self.handler.connection_keep_alive() {
KeepAlive::Until(expiration) => Some(Delay::new(expiration)),
KeepAlive::Now => Some(Delay::new(Instant::now())),
KeepAlive::Forever => None,
};
match poll_result {
Async::Ready(ProtocolsHandlerEvent::Custom(event)) => {
return Ok(Async::Ready(NodeHandlerEvent::Custom(event)));
}
Async::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
upgrade,
info,
}) => {
let id = self.unique_dial_upgrade_id;
self.unique_dial_upgrade_id += 1;
self.queued_dial_upgrades.push((id, upgrade));
return Ok(Async::Ready(
NodeHandlerEvent::OutboundSubstreamRequest((id, info)),
));
}
Async::Ready(ProtocolsHandlerEvent::Shutdown) => {
return Ok(Async::Ready(NodeHandlerEvent::Shutdown))
},
Async::NotReady => (),
};
// Check the `connection_shutdown`.
if let Some(mut connection_shutdown) = self.connection_shutdown.take() {
// If we're negotiating substreams, let's delay the closing.
if self.negotiating_in.is_empty() && self.negotiating_out.is_empty() {
match connection_shutdown.poll() {
Ok(Async::Ready(_)) | Err(_) => {
self.shutdown();
continue; // We need to poll the handler again.
},
Ok(Async::NotReady) => {
self.connection_shutdown = Some(connection_shutdown);
}
}
} else {
self.connection_shutdown = Some(connection_shutdown);
}
match poll_result {
Async::Ready(ProtocolsHandlerEvent::Custom(event)) => {
return Ok(Async::Ready(NodeHandlerEvent::Custom(event)));
}
Async::Ready(ProtocolsHandlerEvent::OutboundSubstreamRequest {
upgrade,
info,
}) => {
let id = self.unique_dial_upgrade_id;
self.unique_dial_upgrade_id += 1;
self.queued_dial_upgrades.push((id, upgrade));
return Ok(Async::Ready(
NodeHandlerEvent::OutboundSubstreamRequest((id, info)),
));
}
Async::NotReady => (),
};
break;
// Check the `connection_shutdown`.
if let Some(mut connection_shutdown) = self.connection_shutdown.take() {
// If we're negotiating substreams, let's delay the closing.
if self.negotiating_in.is_empty() && self.negotiating_out.is_empty() {
match connection_shutdown.poll() {
Ok(Async::Ready(_)) | Err(_) => {
return Err(NodeHandlerWrapperError::UselessTimeout);
},
Ok(Async::NotReady) => {
self.connection_shutdown = Some(connection_shutdown);
}
}
} else {
self.connection_shutdown = Some(connection_shutdown);
}
}
Ok(Async::NotReady)

View File

@ -188,20 +188,12 @@ where
self.pending_error = Some(error);
}
}
#[inline]
fn inject_inbound_closed(&mut self) {}
#[inline]
fn connection_keep_alive(&self) -> KeepAlive {
self.keep_alive
}
#[inline]
fn shutdown(&mut self) {
self.shutting_down = true;
}
fn poll(&mut self) -> Poll<ProtocolsHandlerEvent<Self::OutboundProtocol, Self::OutboundOpenInfo, Self::OutEvent>, Self::Error> {
if let Some(err) = self.pending_error.take() {
return Err(err);
@ -213,10 +205,6 @@ where
self.events_out.shrink_to_fit();
}
if self.shutting_down && self.dial_negotiated == 0 {
return Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown));
}
if !self.dial_queue.is_empty() {
if !self.shutting_down && self.dial_negotiated < self.max_dial_negotiated {
self.dial_negotiated += 1;

View File

@ -24,7 +24,6 @@ use crate::{
either::EitherOutput,
protocols_handler::{
KeepAlive,
Fuse,
IntoProtocolsHandler,
ProtocolsHandler,
ProtocolsHandlerEvent,
@ -78,8 +77,8 @@ where
fn into_handler(self, remote_peer_id: &PeerId) -> Self::Handler {
ProtocolsHandlerSelect {
proto1: self.proto1.into_handler(remote_peer_id).fuse(),
proto2: self.proto2.into_handler(remote_peer_id).fuse(),
proto1: self.proto1.into_handler(remote_peer_id),
proto2: self.proto2.into_handler(remote_peer_id),
}
}
}
@ -88,9 +87,9 @@ where
#[derive(Debug, Clone)]
pub struct ProtocolsHandlerSelect<TProto1, TProto2> {
/// The first protocol.
proto1: Fuse<TProto1>,
proto1: TProto1,
/// The second protocol.
proto2: Fuse<TProto2>,
proto2: TProto2,
}
impl<TProto1, TProto2> ProtocolsHandlerSelect<TProto1, TProto2> {
@ -98,8 +97,8 @@ impl<TProto1, TProto2> ProtocolsHandlerSelect<TProto1, TProto2> {
#[inline]
pub(crate) fn new(proto1: TProto1, proto2: TProto2) -> Self {
ProtocolsHandlerSelect {
proto1: Fuse::new(proto1),
proto2: Fuse::new(proto2),
proto1,
proto2,
}
}
}
@ -119,7 +118,7 @@ where
type OutEvent = EitherOutput<TProto1::OutEvent, TProto2::OutEvent>;
type Error = EitherError<TProto1::Error, TProto2::Error>;
type Substream = TSubstream;
type InboundProtocol = SelectUpgrade<<Fuse<TProto1> as ProtocolsHandler>::InboundProtocol, <Fuse<TProto2> as ProtocolsHandler>::InboundProtocol>;
type InboundProtocol = SelectUpgrade<<TProto1 as ProtocolsHandler>::InboundProtocol, <TProto2 as ProtocolsHandler>::InboundProtocol>;
type OutboundProtocol = EitherUpgrade<TProto1::OutboundProtocol, TProto2::OutboundProtocol>;
type OutboundOpenInfo = EitherOutput<TProto1::OutboundOpenInfo, TProto2::OutboundOpenInfo>;
@ -160,12 +159,6 @@ where
}
}
#[inline]
fn inject_inbound_closed(&mut self) {
self.proto1.inject_inbound_closed();
self.proto2.inject_inbound_closed();
}
#[inline]
fn inject_dial_upgrade_error(&mut self, info: Self::OutboundOpenInfo, error: ProtocolsHandlerUpgrErr<<Self::OutboundProtocol as OutboundUpgrade<Self::Substream>>::Error>) {
match (info, error) {
@ -213,12 +206,6 @@ where
cmp::max(self.proto1.connection_keep_alive(), self.proto2.connection_keep_alive())
}
#[inline]
fn shutdown(&mut self) {
self.proto1.shutdown();
self.proto2.shutdown();
}
fn poll(&mut self) -> Poll<ProtocolsHandlerEvent<Self::OutboundProtocol, Self::OutboundOpenInfo, Self::OutEvent>, Self::Error> {
loop {
match self.proto1.poll().map_err(EitherError::A)? {
@ -231,9 +218,6 @@ where
info: EitherOutput::First(info),
}));
},
Async::Ready(ProtocolsHandlerEvent::Shutdown) => {
self.proto2.shutdown();
},
Async::NotReady => ()
};
@ -247,22 +231,12 @@ where
info: EitherOutput::Second(info),
}));
},
Async::Ready(ProtocolsHandlerEvent::Shutdown) => {
if !self.proto1.is_shutting_down_or_shutdown() {
self.proto1.shutdown();
continue;
}
},
Async::NotReady => ()
};
break;
}
if self.proto1.is_shutdown() && self.proto2.is_shutdown() {
Ok(Async::Ready(ProtocolsHandlerEvent::Shutdown))
} else {
Ok(Async::NotReady)
}
Ok(Async::NotReady)
}
}