Remove legacy network protocol (#8296)

This commit is contained in:
Pierre Krieger
2021-03-11 14:57:06 +01:00
committed by GitHub
parent 8f2517b06e
commit 5f004b4428
6 changed files with 47 additions and 617 deletions
@@ -16,10 +16,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::config::ProtocolId;
use crate::protocol::generic_proto::{
handler::{NotificationsSink, NotifsHandlerProto, NotifsHandlerOut, NotifsHandlerIn},
upgrade::RegisteredProtocol
handler::{NotificationsSink, NotifsHandlerProto, NotifsHandlerOut, NotifsHandlerIn}
};
use bytes::BytesMut;
@@ -97,9 +95,6 @@ use wasm_timer::Instant;
/// accommodates for any number of connections.
///
pub struct GenericProto {
/// Legacy protocol to open with peers. Never modified.
legacy_protocol: RegisteredProtocol,
/// Notification protocols. Entries are only ever added and not removed.
/// Contains, for each protocol, the protocol name and the message to send as part of the
/// initial handshake.
@@ -346,14 +341,6 @@ pub enum GenericProtoOut {
set_id: sc_peerset::SetId,
},
/// Receives a message on the legacy substream.
LegacyMessage {
/// Id of the peer the message came from.
peer_id: PeerId,
/// Message that has been received.
message: BytesMut,
},
/// Receives a message on a custom protocol substream.
///
/// Also concerns received notifications for the notifications API.
@@ -370,9 +357,6 @@ pub enum GenericProtoOut {
impl GenericProto {
/// Creates a `CustomProtos`.
pub fn new(
protocol: impl Into<ProtocolId>,
versions: &[u8],
handshake_message: Vec<u8>,
peerset: sc_peerset::Peerset,
notif_protocols: impl Iterator<Item = (Cow<'static, str>, Vec<u8>, u64)>,
) -> Self {
@@ -382,11 +366,7 @@ impl GenericProto {
assert!(!notif_protocols.is_empty());
let legacy_handshake_message = Arc::new(RwLock::new(handshake_message));
let legacy_protocol = RegisteredProtocol::new(protocol, versions, legacy_handshake_message);
GenericProto {
legacy_protocol,
notif_protocols,
peerset,
peers: FnvHashMap::default(),
@@ -412,14 +392,6 @@ impl GenericProto {
}
}
/// Modifies the handshake of the legacy protocol.
pub fn set_legacy_handshake_message(
&mut self,
handshake_message: impl Into<Vec<u8>>
) {
*self.legacy_protocol.handshake_message().write() = handshake_message.into();
}
/// Returns the number of discovered nodes that we keep in memory.
pub fn num_discovered_peers(&self) -> usize {
self.peerset.num_discovered_peers()
@@ -1046,10 +1018,7 @@ impl NetworkBehaviour for GenericProto {
type OutEvent = GenericProtoOut;
fn new_handler(&mut self) -> Self::ProtocolsHandler {
NotifsHandlerProto::new(
self.legacy_protocol.clone(),
self.notif_protocols.clone(),
)
NotifsHandlerProto::new(self.notif_protocols.clone())
}
fn addresses_of_peer(&mut self, _: &PeerId) -> Vec<Multiaddr> {
@@ -1900,25 +1869,6 @@ impl NetworkBehaviour for GenericProto {
};
}
NotifsHandlerOut::CustomMessage { message } => {
if self.is_open(&source, sc_peerset::SetId::from(0)) { // TODO: using set 0 here is hacky
trace!(target: "sub-libp2p", "Handler({:?}) => Message", source);
trace!(target: "sub-libp2p", "External API <= Message({:?})", source);
let event = GenericProtoOut::LegacyMessage {
peer_id: source,
message,
};
self.events.push_back(NetworkBehaviourAction::GenerateEvent(event));
} else {
trace!(
target: "sub-libp2p",
"Handler({:?}) => Post-close message. Dropping message.",
source,
);
}
}
NotifsHandlerOut::Notification { protocol_index, message } => {
let set_id = sc_peerset::SetId::from(protocol_index);
if self.is_open(&source, set_id) {
@@ -60,14 +60,12 @@
use crate::protocol::generic_proto::{
upgrade::{
NotificationsIn, NotificationsOut, NotificationsInSubstream, NotificationsOutSubstream,
NotificationsHandshakeError, RegisteredProtocol, RegisteredProtocolSubstream,
RegisteredProtocolEvent, UpgradeCollec
NotificationsHandshakeError, UpgradeCollec
},
};
use bytes::BytesMut;
use libp2p::core::{either::EitherOutput, ConnectedPoint, PeerId};
use libp2p::core::upgrade::{SelectUpgrade, InboundUpgrade, OutboundUpgrade};
use libp2p::core::{ConnectedPoint, PeerId, upgrade::{InboundUpgrade, OutboundUpgrade}};
use libp2p::swarm::{
ProtocolsHandler, ProtocolsHandlerEvent,
IntoProtocolsHandler,
@@ -83,7 +81,6 @@ use futures::{
};
use log::error;
use parking_lot::{Mutex, RwLock};
use smallvec::SmallVec;
use std::{borrow::Cow, collections::VecDeque, mem, pin::Pin, str, sync::Arc, task::{Context, Poll}, time::Duration};
use wasm_timer::Instant;
@@ -114,9 +111,6 @@ pub struct NotifsHandlerProto {
/// Name of protocols, prototypes for upgrades for inbound substreams, and the message we
/// send or respond with in the handshake.
protocols: Vec<(Cow<'static, str>, NotificationsIn, Arc<RwLock<Vec<u8>>>, u64)>,
/// Configuration for the legacy protocol upgrade.
legacy_protocol: RegisteredProtocol,
}
/// The actual handler once the connection has been established.
@@ -135,15 +129,6 @@ pub struct NotifsHandler {
/// Remote we are connected to.
peer_id: PeerId,
/// Configuration for the legacy protocol upgrade.
legacy_protocol: RegisteredProtocol,
/// The substreams where bidirectional communications happen.
legacy_substreams: SmallVec<[RegisteredProtocolSubstream<NegotiatedSubstream>; 4]>,
/// Contains substreams which are being shut down.
legacy_shutdown: SmallVec<[RegisteredProtocolSubstream<NegotiatedSubstream>; 4]>,
/// Events to return in priority from `poll`.
events_queue: VecDeque<
ProtocolsHandlerEvent<NotificationsOut, usize, NotifsHandlerOut, NotifsHandlerError>
@@ -227,12 +212,10 @@ enum State {
impl IntoProtocolsHandler for NotifsHandlerProto {
type Handler = NotifsHandler;
fn inbound_protocol(&self) -> SelectUpgrade<UpgradeCollec<NotificationsIn>, RegisteredProtocol> {
let protocols = self.protocols.iter()
fn inbound_protocol(&self) -> UpgradeCollec<NotificationsIn> {
self.protocols.iter()
.map(|(_, p, _, _)| p.clone())
.collect::<UpgradeCollec<_>>();
SelectUpgrade::new(protocols, self.legacy_protocol.clone())
.collect::<UpgradeCollec<_>>()
}
fn into_handler(self, peer_id: &PeerId, connected_point: &ConnectedPoint) -> Self::Handler {
@@ -251,9 +234,6 @@ impl IntoProtocolsHandler for NotifsHandlerProto {
peer_id: peer_id.clone(),
endpoint: connected_point.clone(),
when_connection_open: Instant::now(),
legacy_protocol: self.legacy_protocol,
legacy_substreams: SmallVec::new(),
legacy_shutdown: SmallVec::new(),
events_queue: VecDeque::with_capacity(16),
}
}
@@ -332,17 +312,6 @@ pub enum NotifsHandlerOut {
protocol_index: usize,
},
/// Received a non-gossiping message on the legacy substream.
///
/// Can only happen when the handler is in the open state.
CustomMessage {
/// Message that has been received.
///
/// Keep in mind that this can be a `ConsensusMessage` message, which then contains a
/// notification.
message: BytesMut,
},
/// Received a message on a custom protocol substream.
///
/// Can only happen when the handler is in the open state.
@@ -476,7 +445,6 @@ impl NotifsHandlerProto {
/// is always the same whether we open a substream ourselves or respond to handshake from
/// the remote.
pub fn new(
legacy_protocol: RegisteredProtocol,
list: impl Into<Vec<(Cow<'static, str>, Arc<RwLock<Vec<u8>>>, u64)>>,
) -> Self {
let protocols = list
@@ -489,7 +457,6 @@ impl NotifsHandlerProto {
NotifsHandlerProto {
protocols,
legacy_protocol,
}
}
}
@@ -498,7 +465,7 @@ impl ProtocolsHandler for NotifsHandler {
type InEvent = NotifsHandlerIn;
type OutEvent = NotifsHandlerOut;
type Error = NotifsHandlerError;
type InboundProtocol = SelectUpgrade<UpgradeCollec<NotificationsIn>, RegisteredProtocol>;
type InboundProtocol = UpgradeCollec<NotificationsIn>;
type OutboundProtocol = NotificationsOut;
// Index within the `out_protocols`.
type OutboundOpenInfo = usize;
@@ -509,69 +476,51 @@ impl ProtocolsHandler for NotifsHandler {
.map(|p| p.in_upgrade.clone())
.collect::<UpgradeCollec<_>>();
let with_legacy = SelectUpgrade::new(protocols, self.legacy_protocol.clone());
SubstreamProtocol::new(with_legacy, ())
SubstreamProtocol::new(protocols, ())
}
fn inject_fully_negotiated_inbound(
&mut self,
out: <Self::InboundProtocol as InboundUpgrade<NegotiatedSubstream>>::Output,
((_remote_handshake, mut new_substream), protocol_index):
<Self::InboundProtocol as InboundUpgrade<NegotiatedSubstream>>::Output,
(): ()
) {
match out {
// Received notifications substream.
EitherOutput::First(((_remote_handshake, mut new_substream), protocol_index)) => {
let mut protocol_info = &mut self.protocols[protocol_index];
match protocol_info.state {
State::Closed { pending_opening } => {
self.events_queue.push_back(ProtocolsHandlerEvent::Custom(
NotifsHandlerOut::OpenDesiredByRemote {
protocol_index,
}
));
let mut protocol_info = &mut self.protocols[protocol_index];
match protocol_info.state {
State::Closed { pending_opening } => {
self.events_queue.push_back(ProtocolsHandlerEvent::Custom(
NotifsHandlerOut::OpenDesiredByRemote {
protocol_index,
}
));
protocol_info.state = State::OpenDesiredByRemote {
in_substream: new_substream,
pending_opening,
};
},
State::OpenDesiredByRemote { .. } => {
// If a substream already exists, silently drop the new one.
// Note that we drop the substream, which will send an equivalent to a
// TCP "RST" to the remote and force-close the substream. It might
// seem like an unclean way to get rid of a substream. However, keep
// in mind that it is invalid for the remote to open multiple such
// substreams, and therefore sending a "RST" is the most correct thing
// to do.
return;
},
State::Opening { ref mut in_substream, .. } |
State::Open { ref mut in_substream, .. } => {
if in_substream.is_some() {
// Same remark as above.
return;
}
// Create `handshake_message` on a separate line to be sure that the
// lock is released as soon as possible.
let handshake_message = protocol_info.handshake.read().clone();
new_substream.send_handshake(handshake_message);
*in_substream = Some(new_substream);
},
protocol_info.state = State::OpenDesiredByRemote {
in_substream: new_substream,
pending_opening,
};
}
// Received legacy substream.
EitherOutput::Second((substream, _handshake)) => {
// Note: while we awknowledge legacy substreams and handle incoming messages,
// it doesn't trigger any `OpenDesiredByRemote` event as a way to simplify the
// logic of this code.
// Since mid-2019, legacy substreams are supposed to be used at the same time as
// notifications substreams, and not in isolation. Nodes that open legacy
// substreams in isolation are considered deprecated.
if self.legacy_substreams.len() <= 4 {
self.legacy_substreams.push(substream);
},
State::OpenDesiredByRemote { .. } => {
// If a substream already exists, silently drop the new one.
// Note that we drop the substream, which will send an equivalent to a
// TCP "RST" to the remote and force-close the substream. It might
// seem like an unclean way to get rid of a substream. However, keep
// in mind that it is invalid for the remote to open multiple such
// substreams, and therefore sending a "RST" is the most correct thing
// to do.
return;
},
State::Opening { ref mut in_substream, .. } |
State::Open { ref mut in_substream, .. } => {
if in_substream.is_some() {
// Same remark as above.
return;
}
// Create `handshake_message` on a separate line to be sure that the
// lock is released as soon as possible.
let handshake_message = protocol_info.handshake.read().clone();
new_substream.send_handshake(handshake_message);
*in_substream = Some(new_substream);
},
}
}
@@ -683,11 +632,6 @@ impl ProtocolsHandler for NotifsHandler {
},
NotifsHandlerIn::Close { protocol_index } => {
for mut substream in self.legacy_substreams.drain(..) {
substream.shutdown();
self.legacy_shutdown.push(substream);
}
match self.protocols[protocol_index].state {
State::Open { .. } => {
self.protocols[protocol_index].state = State::Closed {
@@ -752,10 +696,6 @@ impl ProtocolsHandler for NotifsHandler {
}
fn connection_keep_alive(&self) -> KeepAlive {
if !self.legacy_substreams.is_empty() {
return KeepAlive::Yes;
}
// `Yes` if any protocol has some activity.
if self.protocols.iter().any(|p| !matches!(p.state, State::Closed { .. })) {
return KeepAlive::Yes;
@@ -883,68 +823,8 @@ impl ProtocolsHandler for NotifsHandler {
}
}
}
// The legacy substreams are polled only if the state is `Open`. Otherwise, it would be
// possible to receive notifications that would need to get silently discarded.
if matches!(self.protocols[0].state, State::Open { .. }) {
for n in (0..self.legacy_substreams.len()).rev() {
let mut substream = self.legacy_substreams.swap_remove(n);
let poll_outcome = Pin::new(&mut substream).poll_next(cx);
match poll_outcome {
Poll::Pending => self.legacy_substreams.push(substream),
Poll::Ready(Some(Ok(RegisteredProtocolEvent::Message(message)))) => {
self.legacy_substreams.push(substream);
return Poll::Ready(ProtocolsHandlerEvent::Custom(
NotifsHandlerOut::CustomMessage { message }
))
},
Poll::Ready(Some(Ok(RegisteredProtocolEvent::Clogged))) => {
return Poll::Ready(ProtocolsHandlerEvent::Close(
NotifsHandlerError::SyncNotificationsClogged
))
}
Poll::Ready(None) | Poll::Ready(Some(Err(_))) => {
if matches!(poll_outcome, Poll::Ready(None)) {
self.legacy_shutdown.push(substream);
}
if let State::Open { out_substream, .. } = &mut self.protocols[0].state {
if !out_substream.is_some() {
*out_substream = None;
return Poll::Ready(ProtocolsHandlerEvent::Custom(
NotifsHandlerOut::CloseDesired {
protocol_index: 0,
}
))
}
}
}
}
}
}
}
shutdown_list(&mut self.legacy_shutdown, cx);
Poll::Pending
}
}
/// Given a list of substreams, tries to shut them down. The substreams that have been successfully
/// shut down are removed from the list.
fn shutdown_list
(list: &mut SmallVec<impl smallvec::Array<Item = RegisteredProtocolSubstream<NegotiatedSubstream>>>,
cx: &mut Context)
{
'outer: for n in (0..list.len()).rev() {
let mut substream = list.swap_remove(n);
loop {
match substream.poll_next_unpin(cx) {
Poll::Ready(Some(Ok(_))) => {}
Poll::Pending => break,
Poll::Ready(Some(Err(_))) | Poll::Ready(None) => continue 'outer,
}
}
list.push(substream);
}
}
@@ -80,10 +80,7 @@ fn build_nodes() -> (Swarm<CustomProtoWithAddr>, Swarm<CustomProtoWithAddr>) {
});
let behaviour = CustomProtoWithAddr {
inner: GenericProto::new(
"test", &[1], vec![], peerset,
iter::once(("/foo".into(), Vec::new(), 1024 * 1024))
),
inner: GenericProto::new(peerset, iter::once(("/foo".into(), Vec::new(), 1024 * 1024))),
addrs: addrs
.iter()
.enumerate()
@@ -15,13 +15,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pub use self::collec::UpgradeCollec;
pub use self::legacy::{
RegisteredProtocol,
RegisteredProtocolEvent,
RegisteredProtocolName,
RegisteredProtocolSubstream
};
pub use self::notifications::{
NotificationsIn,
NotificationsInSubstream,
@@ -32,5 +27,4 @@ pub use self::notifications::{
};
mod collec;
mod legacy;
mod notifications;
@@ -1,293 +0,0 @@
// This file is part of Substrate.
// Copyright (C) 2018-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::config::ProtocolId;
use bytes::BytesMut;
use futures::prelude::*;
use asynchronous_codec::Framed;
use libp2p::core::{UpgradeInfo, InboundUpgrade, OutboundUpgrade, upgrade::ProtocolName};
use parking_lot::RwLock;
use std::{collections::VecDeque, io, pin::Pin, sync::Arc, vec::IntoIter as VecIntoIter};
use std::task::{Context, Poll};
use unsigned_varint::codec::UviBytes;
/// Connection upgrade for a single protocol.
///
/// Note that "a single protocol" here refers to `par` for example. However
/// each protocol can have multiple different versions for networking purposes.
pub struct RegisteredProtocol {
/// Id of the protocol for API purposes.
id: ProtocolId,
/// Base name of the protocol as advertised on the network.
/// Ends with `/` so that we can append a version number behind.
base_name: Vec<u8>,
/// List of protocol versions that we support.
/// Ordered in descending order so that the best comes first.
supported_versions: Vec<u8>,
/// Handshake to send after the substream is open.
handshake_message: Arc<RwLock<Vec<u8>>>,
}
impl RegisteredProtocol {
/// Creates a new `RegisteredProtocol`.
pub fn new(protocol: impl Into<ProtocolId>, versions: &[u8], handshake_message: Arc<RwLock<Vec<u8>>>)
-> Self {
let protocol = protocol.into();
let mut base_name = b"/substrate/".to_vec();
base_name.extend_from_slice(protocol.as_ref().as_bytes());
base_name.extend_from_slice(b"/");
RegisteredProtocol {
base_name,
id: protocol,
supported_versions: {
let mut tmp = versions.to_vec();
tmp.sort_by(|a, b| b.cmp(&a));
tmp
},
handshake_message,
}
}
/// Returns the `Arc` to the handshake message that was passed at initialization.
pub fn handshake_message(&self) -> &Arc<RwLock<Vec<u8>>> {
&self.handshake_message
}
}
impl Clone for RegisteredProtocol {
fn clone(&self) -> Self {
RegisteredProtocol {
id: self.id.clone(),
base_name: self.base_name.clone(),
supported_versions: self.supported_versions.clone(),
handshake_message: self.handshake_message.clone(),
}
}
}
/// Output of a `RegisteredProtocol` upgrade.
pub struct RegisteredProtocolSubstream<TSubstream> {
/// If true, we are in the process of closing the sink.
is_closing: bool,
/// Buffer of packets to send.
send_queue: VecDeque<BytesMut>,
/// If true, we should call `poll_complete` on the inner sink.
requires_poll_flush: bool,
/// The underlying substream.
inner: stream::Fuse<Framed<TSubstream, UviBytes<BytesMut>>>,
/// If true, we have sent a "remote is clogged" event recently and shouldn't send another one
/// unless the buffer empties then fills itself again.
clogged_fuse: bool,
}
impl<TSubstream> RegisteredProtocolSubstream<TSubstream> {
/// Starts a graceful shutdown process on this substream.
///
/// Note that "graceful" means that we sent a closing message. We don't wait for any
/// confirmation from the remote.
///
/// After calling this, the stream is guaranteed to finish soon-ish.
pub fn shutdown(&mut self) {
self.is_closing = true;
self.send_queue.clear();
}
}
/// Event produced by the `RegisteredProtocolSubstream`.
#[derive(Debug, Clone)]
pub enum RegisteredProtocolEvent {
/// Received a message from the remote.
Message(BytesMut),
/// Diagnostic event indicating that the connection is clogged and we should avoid sending too
/// many messages to it.
Clogged,
}
impl<TSubstream> Stream for RegisteredProtocolSubstream<TSubstream>
where TSubstream: AsyncRead + AsyncWrite + Unpin {
type Item = Result<RegisteredProtocolEvent, io::Error>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
// Flushing the local queue.
while !self.send_queue.is_empty() {
match Pin::new(&mut self.inner).poll_ready(cx) {
Poll::Ready(Ok(())) => {},
Poll::Ready(Err(err)) => return Poll::Ready(Some(Err(err))),
Poll::Pending => break,
}
if let Some(packet) = self.send_queue.pop_front() {
Pin::new(&mut self.inner).start_send(packet)?;
self.requires_poll_flush = true;
}
}
// If we are closing, close as soon as the Sink is closed.
if self.is_closing {
return match Pin::new(&mut self.inner).poll_close(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(Ok(_)) => Poll::Ready(None),
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
}
}
// Indicating that the remote is clogged if that's the case.
if self.send_queue.len() >= 1536 {
if !self.clogged_fuse {
// Note: this fuse is important not just for preventing us from flooding the logs;
// if you remove the fuse, then we will always return early from this function and
// thus never read any message from the network.
self.clogged_fuse = true;
return Poll::Ready(Some(Ok(RegisteredProtocolEvent::Clogged)))
}
} else {
self.clogged_fuse = false;
}
// Flushing if necessary.
if self.requires_poll_flush {
if let Poll::Ready(()) = Pin::new(&mut self.inner).poll_flush(cx)? {
self.requires_poll_flush = false;
}
}
// Receiving incoming packets.
// Note that `inner` is wrapped in a `Fuse`, therefore we can poll it forever.
match Pin::new(&mut self.inner).poll_next(cx)? {
Poll::Ready(Some(data)) => {
Poll::Ready(Some(Ok(RegisteredProtocolEvent::Message(data))))
}
Poll::Ready(None) =>
if !self.requires_poll_flush && self.send_queue.is_empty() {
Poll::Ready(None)
} else {
Poll::Pending
}
Poll::Pending => Poll::Pending,
}
}
}
impl UpgradeInfo for RegisteredProtocol {
type Info = RegisteredProtocolName;
type InfoIter = VecIntoIter<Self::Info>;
#[inline]
fn protocol_info(&self) -> Self::InfoIter {
// Report each version as an individual protocol.
self.supported_versions.iter().map(|&version| {
let num = version.to_string();
let mut name = self.base_name.clone();
name.extend_from_slice(num.as_bytes());
RegisteredProtocolName {
name,
version,
}
}).collect::<Vec<_>>().into_iter()
}
}
/// Implementation of `ProtocolName` for a custom protocol.
#[derive(Debug, Clone)]
pub struct RegisteredProtocolName {
/// Protocol name, as advertised on the wire.
name: Vec<u8>,
/// Version number. Stored in string form in `name`, but duplicated here for easier retrieval.
version: u8,
}
impl ProtocolName for RegisteredProtocolName {
fn protocol_name(&self) -> &[u8] {
&self.name
}
}
impl<TSubstream> InboundUpgrade<TSubstream> for RegisteredProtocol
where TSubstream: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
type Output = (RegisteredProtocolSubstream<TSubstream>, Vec<u8>);
type Future = Pin<Box<dyn Future<Output = Result<Self::Output, io::Error>> + Send>>;
type Error = io::Error;
fn upgrade_inbound(
self,
socket: TSubstream,
_: Self::Info,
) -> Self::Future {
Box::pin(async move {
let mut framed = {
let mut codec = UviBytes::default();
codec.set_max_len(16 * 1024 * 1024); // 16 MiB hard limit for packets.
Framed::new(socket, codec)
};
let handshake = BytesMut::from(&self.handshake_message.read()[..]);
framed.send(handshake).await?;
let received_handshake = framed.next().await
.ok_or_else(|| io::ErrorKind::UnexpectedEof)??;
Ok((RegisteredProtocolSubstream {
is_closing: false,
send_queue: VecDeque::new(),
requires_poll_flush: false,
inner: framed.fuse(),
clogged_fuse: false,
}, received_handshake.to_vec()))
})
}
}
impl<TSubstream> OutboundUpgrade<TSubstream> for RegisteredProtocol
where TSubstream: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
type Output = <Self as InboundUpgrade<TSubstream>>::Output;
type Future = <Self as InboundUpgrade<TSubstream>>::Future;
type Error = <Self as InboundUpgrade<TSubstream>>::Error;
fn upgrade_outbound(
self,
socket: TSubstream,
_: Self::Info,
) -> Self::Future {
Box::pin(async move {
let mut framed = {
let mut codec = UviBytes::default();
codec.set_max_len(16 * 1024 * 1024); // 16 MiB hard limit for packets.
Framed::new(socket, codec)
};
let handshake = BytesMut::from(&self.handshake_message.read()[..]);
framed.send(handshake).await?;
let received_handshake = framed.next().await
.ok_or_else(|| {
io::Error::new(io::ErrorKind::UnexpectedEof, "Failed to receive handshake")
})??;
Ok((RegisteredProtocolSubstream {
is_closing: false,
send_queue: VecDeque::new(),
requires_poll_flush: false,
inner: framed.fuse(),
clogged_fuse: false,
}, received_handshake.to_vec()))
})
}
}