Skip to content

Commit

Permalink
[plaintext] Retain remaining read buffer after handshake. (#1831)
Browse files Browse the repository at this point in the history
* Retain remaining read buffer.

When the plaintext protocol handshake finishes and
the `Framed` I/O is discarded in favour of the underlying
I/O stream, the remaining read buffer of `Framed` must
be retained, as it may have buffered data beyond the
end of the handshake.

* Update versions and changelogs.
  • Loading branch information
romanb authored Nov 11, 2020
1 parent fabb00c commit f771bcc
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
- [`parity-multiaddr` CHANGELOG](misc/multiaddr/CHANGELOG.md)
- [`libp2p-core-derive` CHANGELOG](misc/core-derive/CHANGELOG.md)

# Version 0.30.1 [unreleased]

- Update `libp2p-plaintext`.

# Version 0.30.0 [2020-11-09]

- Update `libp2p-mdns`, `libp2p-tcp` and `libp2p-uds` as well as `libp2p-core`
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "libp2p"
edition = "2018"
description = "Peer-to-peer networking library"
version = "0.30.0"
version = "0.30.1"
authors = ["Parity Technologies <[email protected]>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand Down Expand Up @@ -71,7 +71,7 @@ libp2p-kad = { version = "0.25.0", path = "protocols/kad", optional = true }
libp2p-mplex = { version = "0.24.0", path = "muxers/mplex", optional = true }
libp2p-noise = { version = "0.26.0", path = "protocols/noise", optional = true }
libp2p-ping = { version = "0.24.0", path = "protocols/ping", optional = true }
libp2p-plaintext = { version = "0.24.0", path = "protocols/plaintext", optional = true }
libp2p-plaintext = { version = "0.24.1", path = "protocols/plaintext", optional = true }
libp2p-pnet = { version = "0.19.2", path = "protocols/pnet", optional = true }
libp2p-request-response = { version = "0.5.0", path = "protocols/request-response", optional = true }
libp2p-swarm = { version = "0.24.0", path = "swarm" }
Expand Down
6 changes: 6 additions & 0 deletions protocols/plaintext/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 0.24.1 [unreleased]

- Ensure that no follow-up protocol data is dropped at the end of the
plaintext protocol handshake.
[PR 1831](https://github.com/libp2p/rust-libp2p/pull/1831).

# 0.24.0 [2020-11-09]

- Update dependencies.
Expand Down
2 changes: 1 addition & 1 deletion protocols/plaintext/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "libp2p-plaintext"
edition = "2018"
description = "Plaintext encryption dummy protocol for libp2p"
version = "0.24.0"
version = "0.24.1"
authors = ["Parity Technologies <[email protected]>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand Down
12 changes: 9 additions & 3 deletions protocols/plaintext/src/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::PlainText2Config;
use crate::error::PlainTextError;
use crate::structs_proto::Exchange;

use bytes::BytesMut;
use bytes::{Bytes, BytesMut};
use futures::prelude::*;
use futures_codec::Framed;
use libp2p_core::{PublicKey, PeerId};
Expand Down Expand Up @@ -111,7 +111,7 @@ impl HandshakeContext<Local> {
}

pub async fn handshake<S>(socket: S, config: PlainText2Config)
-> Result<(S, Remote), PlainTextError>
-> Result<(S, Remote, Bytes), PlainTextError>
where
S: AsyncRead + AsyncWrite + Send + Unpin,
{
Expand All @@ -134,6 +134,12 @@ where
}
};

// The `Framed` wrapper may have buffered additional data that
// was already received but is no longer part of the plaintext
// handshake. We need to capture that data before dropping
// the `Framed` wrapper via `Framed::into_inner()`.
let read_buffer = framed_socket.read_buffer().clone().freeze();

trace!("received exchange from remote; pubkey = {:?}", context.state.public_key);
Ok((framed_socket.into_inner(), context.state))
Ok((framed_socket.into_inner(), context.state, read_buffer))
}
14 changes: 13 additions & 1 deletion protocols/plaintext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

use crate::error::PlainTextError;

use bytes::Bytes;
use futures::future::{self, Ready};
use futures::prelude::*;
use futures::future::BoxFuture;
Expand Down Expand Up @@ -148,14 +149,15 @@ impl PlainText2Config {
T: AsyncRead + AsyncWrite + Send + Unpin + 'static
{
debug!("Starting plaintext handshake.");
let (socket, remote) = handshake::handshake(socket, self).await?;
let (socket, remote, read_buffer) = handshake::handshake(socket, self).await?;
debug!("Finished plaintext handshake.");

Ok((
remote.peer_id,
PlainTextOutput {
socket,
remote_key: remote.public_key,
read_buffer,
}
))
}
Expand All @@ -170,12 +172,22 @@ where
pub socket: S,
/// The public key of the remote.
pub remote_key: PublicKey,
/// Remaining bytes that have been already buffered
/// during the handshake but are not part of the
/// handshake. These must be consumed first by `poll_read`.
read_buffer: Bytes,
}

impl<S: AsyncRead + AsyncWrite + Unpin> AsyncRead for PlainTextOutput<S> {
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8])
-> Poll<Result<usize, io::Error>>
{
if !self.read_buffer.is_empty() {
let n = std::cmp::min(buf.len(), self.read_buffer.len());
let b = self.read_buffer.split_to(n);
buf[..n].copy_from_slice(&b[..]);
return Poll::Ready(Ok(n))
}
AsyncRead::poll_read(Pin::new(&mut self.socket), cx, buf)
}
}
Expand Down

0 comments on commit f771bcc

Please sign in to comment.