libp2p_quic/connection/
connecting.rs

1// Copyright 2017-2020 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
21//! Future that drives a QUIC connection until is has performed its TLS handshake.
22
23use std::{
24    pin::Pin,
25    task::{Context, Poll},
26    time::Duration,
27};
28
29use futures::{
30    future::{select, Either, FutureExt, Select},
31    prelude::*,
32};
33use futures_timer::Delay;
34use libp2p_identity::PeerId;
35use quinn::rustls::pki_types::CertificateDer;
36
37use crate::{Connection, ConnectionError, Error};
38
39/// A QUIC connection currently being negotiated.
40#[derive(Debug)]
41pub struct Connecting {
42    connecting: Select<quinn::Connecting, Delay>,
43}
44
45impl Connecting {
46    pub(crate) fn new(connection: quinn::Connecting, timeout: Duration) -> Self {
47        Connecting {
48            connecting: select(connection, Delay::new(timeout)),
49        }
50    }
51}
52
53impl Connecting {
54    /// Returns the address of the node we're connected to.
55    /// Panics if the connection is still handshaking.
56    fn remote_peer_id(connection: &quinn::Connection) -> PeerId {
57        let identity = connection
58            .peer_identity()
59            .expect("connection got identity because it passed TLS handshake; qed");
60        let certificates: Box<Vec<CertificateDer>> =
61            identity.downcast().expect("we rely on rustls feature; qed");
62        let end_entity = certificates
63            .first()
64            .expect("there should be exactly one certificate; qed");
65        let p2p_cert = libp2p_tls::certificate::parse(end_entity)
66            .expect("the certificate was validated during TLS handshake; qed");
67        p2p_cert.peer_id()
68    }
69}
70
71impl Future for Connecting {
72    type Output = Result<(PeerId, Connection), Error>;
73
74    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
75        let connection = match futures::ready!(self.connecting.poll_unpin(cx)) {
76            Either::Right(_) => return Poll::Ready(Err(Error::HandshakeTimedOut)),
77            Either::Left((connection, _)) => connection.map_err(ConnectionError)?,
78        };
79
80        let peer_id = Self::remote_peer_id(&connection);
81        let muxer = Connection::new(connection);
82        Poll::Ready(Ok((peer_id, muxer)))
83    }
84}