use async_std::io;
use async_std::net::UdpSocket;
use std::net::{SocketAddr, ToSocketAddrs};
use std::time::Duration;
use stun::agent::TransactionId;
use stun::message::{Getter, Message, BINDING_REQUEST};
use stun::xoraddr::XorMappedAddress;
pub async fn external_addr<T: ToSocketAddrs>(
udp: &UdpSocket,
server: T,
timeout: u64,
) -> Option<SocketAddr> {
let mut bin = Message::new();
bin
.build(&[
Box::new(TransactionId::default()),
Box::new(BINDING_REQUEST),
])
.unwrap();
let bin = bin.marshal_binary().unwrap();
if let Ok(mut li) = server.to_socket_addrs() {
if let Some(addr) = li.next() {
udp.send_to(&bin, addr).await.unwrap();
match io::timeout(Duration::from_secs(timeout), async move {
loop {
let mut buf = vec![0u8; 1472];
if let Ok((n, peer)) = udp.recv_from(&mut buf).await {
if peer == addr {
let mut xor_addr = XorMappedAddress::default();
let mut msg = Message::new();
if msg.unmarshal_binary(&buf[..n]).is_ok() && xor_addr.get_from(&msg).is_ok() {
return Ok(SocketAddr::new(xor_addr.ip, xor_addr.port));
}
}
}
}
})
.await
{
Ok(r) => return Some(r),
_ => return None,
}
}
}
None
}