rmw_stun/
lib.rs

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}