libp2p_plaintext/
lib.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use crate::error::PlainTextError;
22
23use bytes::Bytes;
24use futures::future::{self, Ready};
25use futures::prelude::*;
26use futures::future::BoxFuture;
27use libp2p_core::{
28    identity,
29    InboundUpgrade,
30    OutboundUpgrade,
31    UpgradeInfo,
32    PeerId,
33    PublicKey,
34};
35use log::debug;
36use std::{io, iter, pin::Pin, task::{Context, Poll}};
37use void::Void;
38
39mod error;
40mod handshake;
41mod structs_proto {
42    include!(concat!(env!("OUT_DIR"), "/structs.rs"));
43}
44
45
46/// `PlainText1Config` is an insecure connection handshake for testing purposes only.
47///
48/// > **Note**: Given that `PlainText1Config` has no notion of exchanging peer identity information it is not compatible
49/// > with the `libp2p_core::transport::upgrade::Builder` pattern. See
50/// > [`PlainText2Config`](struct.PlainText2Config.html) if compatibility is needed. Even though not compatible with the
51/// > Builder pattern one can still do an upgrade *manually*:
52///
53/// ```
54/// # use libp2p_core::transport::{ Transport, memory::MemoryTransport };
55/// # use libp2p_plaintext::PlainText1Config;
56/// #
57/// MemoryTransport::default()
58///   .and_then(move |io, endpoint| {
59///     libp2p_core::upgrade::apply(
60///       io,
61///       PlainText1Config{},
62///       endpoint,
63///       libp2p_core::transport::upgrade::Version::V1,
64///     )
65///   })
66///   .map(|plaintext, _endpoint| {
67///     unimplemented!();
68///     // let peer_id = somehow_derive_peer_id();
69///     // return (peer_id, plaintext);
70///   });
71/// ```
72#[derive(Debug, Copy, Clone)]
73pub struct PlainText1Config;
74
75impl UpgradeInfo for PlainText1Config {
76    type Info = &'static [u8];
77    type InfoIter = iter::Once<Self::Info>;
78
79    fn protocol_info(&self) -> Self::InfoIter {
80        iter::once(b"/plaintext/1.0.0")
81    }
82}
83
84impl<C> InboundUpgrade<C> for PlainText1Config {
85    type Output = C;
86    type Error = Void;
87    type Future = Ready<Result<C, Self::Error>>;
88
89    fn upgrade_inbound(self, i: C, _: Self::Info) -> Self::Future {
90        future::ready(Ok(i))
91    }
92}
93
94impl<C> OutboundUpgrade<C> for PlainText1Config {
95    type Output = C;
96    type Error = Void;
97    type Future = Ready<Result<C, Self::Error>>;
98
99    fn upgrade_outbound(self, i: C, _: Self::Info) -> Self::Future {
100        future::ready(Ok(i))
101    }
102}
103
104/// `PlainText2Config` is an insecure connection handshake for testing purposes only, implementing
105/// the libp2p plaintext connection handshake specification.
106#[derive(Clone)]
107pub struct PlainText2Config {
108    pub local_public_key: identity::PublicKey,
109}
110
111impl UpgradeInfo for PlainText2Config {
112    type Info = &'static [u8];
113    type InfoIter = iter::Once<Self::Info>;
114
115    fn protocol_info(&self) -> Self::InfoIter {
116        iter::once(b"/plaintext/2.0.0")
117    }
118}
119
120impl<C> InboundUpgrade<C> for PlainText2Config
121where
122    C: AsyncRead + AsyncWrite + Send + Unpin + 'static
123{
124    type Output = (PeerId, PlainTextOutput<C>);
125    type Error = PlainTextError;
126    type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
127
128    fn upgrade_inbound(self, socket: C, _: Self::Info) -> Self::Future {
129        Box::pin(self.handshake(socket))
130    }
131}
132
133impl<C> OutboundUpgrade<C> for PlainText2Config
134where
135    C: AsyncRead + AsyncWrite + Send + Unpin + 'static
136{
137    type Output = (PeerId, PlainTextOutput<C>);
138    type Error = PlainTextError;
139    type Future = BoxFuture<'static, Result<Self::Output, Self::Error>>;
140
141    fn upgrade_outbound(self, socket: C, _: Self::Info) -> Self::Future {
142        Box::pin(self.handshake(socket))
143    }
144}
145
146impl PlainText2Config {
147    async fn handshake<T>(self, socket: T) -> Result<(PeerId, PlainTextOutput<T>), PlainTextError>
148    where
149        T: AsyncRead + AsyncWrite + Send + Unpin + 'static
150    {
151        debug!("Starting plaintext handshake.");
152        let (socket, remote, read_buffer) = handshake::handshake(socket, self).await?;
153        debug!("Finished plaintext handshake.");
154
155        Ok((
156            remote.peer_id,
157            PlainTextOutput {
158                socket,
159                remote_key: remote.public_key,
160                read_buffer,
161            }
162        ))
163    }
164}
165
166/// Output of the plaintext protocol.
167pub struct PlainTextOutput<S>
168where
169    S: AsyncRead + AsyncWrite + Unpin,
170{
171    /// The plaintext stream.
172    pub socket: S,
173    /// The public key of the remote.
174    pub remote_key: PublicKey,
175    /// Remaining bytes that have been already buffered
176    /// during the handshake but are not part of the
177    /// handshake. These must be consumed first by `poll_read`.
178    read_buffer: Bytes,
179}
180
181impl<S: AsyncRead + AsyncWrite + Unpin> AsyncRead for PlainTextOutput<S> {
182    fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8])
183        -> Poll<Result<usize, io::Error>>
184    {
185        if !self.read_buffer.is_empty() {
186            let n = std::cmp::min(buf.len(), self.read_buffer.len());
187            let b = self.read_buffer.split_to(n);
188            buf[..n].copy_from_slice(&b[..]);
189            return Poll::Ready(Ok(n))
190        }
191        AsyncRead::poll_read(Pin::new(&mut self.socket), cx, buf)
192    }
193}
194
195impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for PlainTextOutput<S> {
196    fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8])
197        -> Poll<Result<usize, io::Error>>
198    {
199        AsyncWrite::poll_write(Pin::new(&mut self.socket), cx, buf)
200    }
201
202    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>)
203        -> Poll<Result<(), io::Error>>
204    {
205        AsyncWrite::poll_flush(Pin::new(&mut self.socket), cx)
206    }
207
208    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>)
209        -> Poll<Result<(), io::Error>>
210    {
211        AsyncWrite::poll_close(Pin::new(&mut self.socket), cx)
212    }
213}