libp2p_quic/
hole_punching.rs1use 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}