libp2p_quic/
hole_punching.rs

1use std::{
2    convert::Infallible,
3    net::{SocketAddr, UdpSocket},
4    time::Duration,
5};
6
7use futures::future::Either;
8use rand::{distributions, Rng};
9
10use crate::{provider::Provider, Error};
11
12pub(crate) async fn hole_puncher<P: Provider>(
13    socket: UdpSocket,
14    remote_addr: SocketAddr,
15    timeout_duration: Duration,
16) -> Error {
17    let punch_holes_future = punch_holes::<P>(socket, remote_addr);
18    futures::pin_mut!(punch_holes_future);
19    match futures::future::select(P::sleep(timeout_duration), punch_holes_future).await {
20        Either::Left(_) => Error::HandshakeTimedOut,
21        Either::Right((Err(hole_punch_err), _)) => hole_punch_err,
22        Either::Right((Ok(never), _)) => match never {},
23    }
24}
25
26async fn punch_holes<P: Provider>(
27    socket: UdpSocket,
28    remote_addr: SocketAddr,
29) -> Result<Infallible, Error> {
30    loop {
31        let contents: Vec<u8> = rand::thread_rng()
32            .sample_iter(distributions::Standard)
33            .take(64)
34            .collect();
35
36        tracing::trace!("Sending random UDP packet to {remote_addr}");
37
38        P::send_to(&socket, &contents, remote_addr).await?;
39
40        let sleep_duration = Duration::from_millis(rand::thread_rng().gen_range(10..=200));
41        P::sleep(sleep_duration).await;
42    }
43}