Skip to content

Commit

Permalink
Add libp2p-request-response protocol. (#1596)
Browse files Browse the repository at this point in the history
* Add the libp2p-request-response protocol.

This crate provides a generic implementation for request/response
protocols, whereby each request is sent on a new substream.

* Fix OneShotHandler usage in floodsub.

* Custom ProtocolsHandler and multiple protocols.

  1. Implement a custom ProtocolsHandler instead of using
     the OneShotHandler for better control and error handling.
     In particular, all request/response sending/receiving is
     kept in the substreams upgrades and thus the background
     task of a connection.
  2. Support multiple protocols (usually protocol versions)
     with a single `RequestResponse` instance, with
     configurable inbound/outbound support.

* Small doc clarification.

* Remove unnecessary Sync bounds.

* Remove redundant Clone constraint.

* Update protocols/request-response/Cargo.toml

Co-authored-by: Toralf Wittner <tw@dtex.org>

* Update dev-dependencies.

* Update Cargo.tomls.

* Add changelog.

* Remove Sync bound from RequestResponseCodec::Protocol.

Apparently the compiler just needs some help with the scope
of borrows, which is unfortunate.

* Try async-trait.

* Allow checking whether a ResponseChannel is still open.

Also expand the commentary on `send_response` to indicate that
responses may be discard if they come in too late.

* Add `RequestResponse::is_pending`.

As an analogue of `ResponseChannel::is_open` for outbound requests.

* Revert now unnecessary changes to the OneShotHandler.

Since `libp2p-request-response` is no longer using it.

* Update CHANGELOG for libp2p-swarm.

Co-authored-by: Toralf Wittner <tw@dtex.org>
  • Loading branch information
romanb and twittner authored Jun 29, 2020
1 parent 7270ed8 commit eb8cb43
Show file tree
Hide file tree
Showing 15 changed files with 1,481 additions and 72 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [`libp2p-ping` CHANGELOG](protocols/ping/CHANGELOG.md)
- [`libp2p-plaintext` CHANGELOG](protocols/plaintext/CHANGELOG.md)
- [`libp2p-pnet` CHANGELOG](protocols/pnet/CHANGELOG.md)
- [`libp2p-request-response` CHANGELOG](protocols/request-response/CHANGELOG.md)
- [`libp2p-secio` CHANGELOG](protocols/secio/CHANGELOG.md)
- [`libp2p-swarm` CHANGELOG](swarm/CHANGELOG.md)
- [`libp2p-tcp` CHANGELOG](transports/tcp/CHANGELOG.md)
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ default = [
"ping",
"plaintext",
"pnet",
"request-response",
"secio",
"secp256k1",
"tcp-async-std",
Expand All @@ -43,6 +44,7 @@ noise = ["libp2p-noise"]
ping = ["libp2p-ping"]
plaintext = ["libp2p-plaintext"]
pnet = ["libp2p-pnet"]
request-response = ["libp2p-request-response"]
secio = ["libp2p-secio"]
tcp-async-std = ["libp2p-tcp", "libp2p-tcp/async-std"]
tcp-tokio = ["libp2p-tcp", "libp2p-tcp/tokio"]
Expand All @@ -67,6 +69,7 @@ libp2p-noise = { version = "0.19.1", path = "protocols/noise", optional = true }
libp2p-ping = { version = "0.19.3", path = "protocols/ping", optional = true }
libp2p-plaintext = { version = "0.19.1", path = "protocols/plaintext", optional = true }
libp2p-pnet = { version = "0.19.1", path = "protocols/pnet", optional = true }
libp2p-request-response = { version = "0.1.0", path = "protocols/request-response", optional = true }
libp2p-secio = { version = "0.19.2", path = "protocols/secio", default-features = false, optional = true }
libp2p-swarm = { version = "0.19.1", path = "swarm" }
libp2p-uds = { version = "0.19.2", path = "transports/uds", optional = true }
Expand Down Expand Up @@ -107,6 +110,7 @@ members = [
"protocols/noise",
"protocols/ping",
"protocols/plaintext",
"protocols/request-response",
"protocols/secio",
"swarm",
"transports/dns",
Expand Down
13 changes: 8 additions & 5 deletions core/src/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ pub use self::{
///
/// # Context
///
/// In situations where we provide a list of protocols that we support, the elements of that list are required to
/// implement the [`ProtocolName`] trait.
/// In situations where we provide a list of protocols that we support,
/// the elements of that list are required to implement the [`ProtocolName`] trait.
///
/// Libp2p will call the [`ProtocolName::protocol_name`] trait method on each element of that list, and transmit the
/// returned value on the network. If the remote accepts a given protocol, the element serves as the return value of
/// the function that performed the negotiation.
/// Libp2p will call [`ProtocolName::protocol_name`] on each element of that list, and transmit the
/// returned value on the network. If the remote accepts a given protocol, the element
/// serves as the return value of the function that performed the negotiation.
///
/// # Example
///
Expand All @@ -118,6 +118,9 @@ pub use self::{
///
pub trait ProtocolName {
/// The protocol name as bytes. Transmitted on the network.
///
/// **Note:** Valid protocol names must start with `/` and
/// not exceed 140 bytes in length.
fn protocol_name(&self) -> &[u8];
}

Expand Down
2 changes: 1 addition & 1 deletion protocols/floodsub/src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl NetworkBehaviour for Floodsub {
_connection: ConnectionId,
event: InnerMessage,
) {
// We ignore successful sends event.
// We ignore successful sends or timeouts.
let event = match event {
InnerMessage::Rx(event) => event,
InnerMessage::Sent => return,
Expand Down
4 changes: 4 additions & 0 deletions protocols/request-response/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 0.1.0

Initial release.

25 changes: 25 additions & 0 deletions protocols/request-response/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "libp2p-request-response"
edition = "2018"
description = "Generic Request/Response Protocols"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"]

[dependencies]
async-trait = "0.1"
futures = "0.3.1"
libp2p-core = { version = "0.19.2", path = "../../core" }
libp2p-swarm = { version = "0.19.1", path = "../../swarm" }
smallvec = "1.4"
wasm-timer = "0.2"

[dev-dependencies]
async-std = "1.6.2"
libp2p-noise = { path = "../noise" }
libp2p-tcp = { path = "../../transports/tcp", features = ["async-std"] }
libp2p-yamux = { path = "../../muxers/yamux" }
rand = "0.7"
66 changes: 66 additions & 0 deletions protocols/request-response/src/codec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2020 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.

pub use libp2p_core::ProtocolName;

use async_trait::async_trait;
use futures::prelude::*;
use std::io;

/// A `RequestResponseCodec` defines the request and response types
/// for a [`RequestResponse`](crate::RequestResponse) protocol or
/// protocol family and how they are encoded / decoded on an I/O stream.
#[async_trait]
pub trait RequestResponseCodec {
/// The type of protocol(s) or protocol versions being negotiated.
type Protocol: ProtocolName + Send + Clone;
/// The type of inbound and outbound requests.
type Request: Send;
/// The type of inbound and outbound responses.
type Response: Send;

/// Reads a request from the given I/O stream according to the
/// negotiated protocol.
async fn read_request<T>(&mut self, protocol: &Self::Protocol, io: &mut T)
-> io::Result<Self::Request>
where
T: AsyncRead + Unpin + Send;

/// Reads a response from the given I/O stream according to the
/// negotiated protocol.
async fn read_response<T>(&mut self, protocol: &Self::Protocol, io: &mut T)
-> io::Result<Self::Response>
where
T: AsyncRead + Unpin + Send;

/// Writes a request to the given I/O stream according to the
/// negotiated protocol.
async fn write_request<T>(&mut self, protocol: &Self::Protocol, io: &mut T, req: Self::Request)
-> io::Result<()>
where
T: AsyncWrite + Unpin + Send;

/// Writes a response to the given I/O stream according to the
/// negotiated protocol.
async fn write_response<T>(&mut self, protocol: &Self::Protocol, io: &mut T, res: Self::Response)
-> io::Result<()>
where
T: AsyncWrite + Unpin + Send;
}
Loading

0 comments on commit eb8cb43

Please sign in to comment.