libp2p_plaintext/
handshake.rs1use crate::PlainText2Config;
22use crate::error::PlainTextError;
23use crate::structs_proto::Exchange;
24
25use bytes::{Bytes, BytesMut};
26use futures::prelude::*;
27use asynchronous_codec::{Framed, FramedParts};
28use libp2p_core::{PublicKey, PeerId};
29use log::{debug, trace};
30use prost::Message;
31use std::io::{Error as IoError, ErrorKind as IoErrorKind};
32use unsigned_varint::codec::UviBytes;
33
34struct HandshakeContext<T> {
35 config: PlainText2Config,
36 state: T
37}
38
39struct Local {
41 exchange_bytes: Vec<u8>,
43}
44
45pub struct Remote {
47 pub peer_id: PeerId,
49 pub public_key: PublicKey,
51}
52
53impl HandshakeContext<Local> {
54 fn new(config: PlainText2Config) -> Result<Self, PlainTextError> {
55 let exchange = Exchange {
56 id: Some(config.local_public_key.clone().into_peer_id().to_bytes()),
57 pubkey: Some(config.local_public_key.clone().into_protobuf_encoding())
58 };
59 let mut buf = Vec::with_capacity(exchange.encoded_len());
60 exchange.encode(&mut buf).expect("Vec<u8> provides capacity as needed");
61
62 Ok(Self {
63 config,
64 state: Local {
65 exchange_bytes: buf
66 }
67 })
68 }
69
70 fn with_remote(self, exchange_bytes: BytesMut)
71 -> Result<HandshakeContext<Remote>, PlainTextError>
72 {
73 let prop = match Exchange::decode(exchange_bytes) {
74 Ok(prop) => prop,
75 Err(e) => {
76 debug!("failed to parse remote's exchange protobuf message");
77 return Err(PlainTextError::InvalidPayload(Some(e)));
78 },
79 };
80
81 let pb_pubkey = prop.pubkey.unwrap_or_default();
82 let public_key = match PublicKey::from_protobuf_encoding(pb_pubkey.as_slice()) {
83 Ok(p) => p,
84 Err(_) => {
85 debug!("failed to parse remote's exchange's pubkey protobuf");
86 return Err(PlainTextError::InvalidPayload(None));
87 },
88 };
89 let peer_id = match PeerId::from_bytes(&prop.id.unwrap_or_default()) {
90 Ok(p) => p,
91 Err(_) => {
92 debug!("failed to parse remote's exchange's id protobuf");
93 return Err(PlainTextError::InvalidPayload(None));
94 },
95 };
96
97 if peer_id != public_key.clone().into_peer_id() {
99 debug!("the remote's `PeerId` isn't consistent with the remote's public key");
100 return Err(PlainTextError::InvalidPeerId)
101 }
102
103 Ok(HandshakeContext {
104 config: self.config,
105 state: Remote {
106 peer_id,
107 public_key,
108 }
109 })
110 }
111}
112
113pub async fn handshake<S>(socket: S, config: PlainText2Config)
114 -> Result<(S, Remote, Bytes), PlainTextError>
115where
116 S: AsyncRead + AsyncWrite + Send + Unpin,
117{
118 let mut framed_socket = Framed::new(socket, UviBytes::default());
120
121 trace!("starting handshake");
122 let context = HandshakeContext::new(config)?;
123
124 trace!("sending exchange to remote");
125 framed_socket.send(BytesMut::from(&context.state.exchange_bytes[..])).await?;
126
127 trace!("receiving the remote's exchange");
128 let context = match framed_socket.next().await {
129 Some(p) => context.with_remote(p?)?,
130 None => {
131 debug!("unexpected eof while waiting for remote's exchange");
132 let err = IoError::new(IoErrorKind::BrokenPipe, "unexpected eof");
133 return Err(err.into());
134 }
135 };
136
137 trace!("received exchange from remote; pubkey = {:?}", context.state.public_key);
138
139 let FramedParts { io, read_buffer, write_buffer, .. } = framed_socket.into_parts();
140 assert!(write_buffer.is_empty());
141 Ok((io, context.state, read_buffer.freeze()))
142}