1use anyhow::Result;
2use async_std::io;
3use async_std::net::UdpSocket;
4use std::mem::MaybeUninit;
5use std::net::{SocketAddr, ToSocketAddrs};
6use std::time::Duration;
7use stun::agent::TransactionId;
8use stun::message::{Getter, Message, BINDING_REQUEST};
9use stun::xoraddr::XorMappedAddress;
10use thiserror::Error;
11
12#[derive(Error, Debug)]
13pub enum Error {
14 #[error("addr not exist")]
15 AddrNotExist,
16 #[error("timeout")]
17 Timeout,
18}
19
20pub async fn external_addr<T: ToSocketAddrs>(
21 udp: &UdpSocket,
22 server: T,
23 timeout: u64,
24) -> Result<SocketAddr> {
25 let mut bin = Message::new();
26 bin.build(&[
27 Box::new(TransactionId::default()),
28 Box::new(BINDING_REQUEST),
29 ])?;
30 let bin = bin.marshal_binary()?;
31 let mut li = server.to_socket_addrs()?;
32 if let Some(addr) = li.next() {
33 udp.send_to(&bin, addr).await?;
34 match io::timeout(Duration::from_secs(timeout), async move {
35 loop {
36 let mut buf: [u8; 1472] = unsafe { MaybeUninit::uninit().assume_init() };
37 if let Ok((n, peer)) = udp.recv_from(&mut buf).await {
38 if peer == addr {
39 let mut xor_addr = XorMappedAddress::default();
40 let mut msg = Message::new();
41 if msg.unmarshal_binary(&buf[..n]).is_ok() && xor_addr.get_from(&msg).is_ok() {
42 return Ok(SocketAddr::new(xor_addr.ip, xor_addr.port));
43 }
44 }
45 }
46 }
47 })
48 .await
49 {
50 Ok(r) => return Ok(r),
51 _ => return Err(Error::Timeout.into()),
52 }
53 }
54 Err(Error::AddrNotExist.into())
55}