#![allow(unused)]
use crate::error::{Error, Result};
use log::{debug, info, warn};
use std::net::{IpAddr, SocketAddr, SocketAddrV4};
use std::time::Duration;
use tokio::time::{self, Instant};
pub const DEFAULT_UPNP_LEASE_DURATION_SEC: u32 = 120;
pub const UPNP_RESPONSE_TIMEOUT_MSEC: u64 = 3_000;
pub async fn forward_port(local_addr: SocketAddr, lease_duration: u32) -> Result<SocketAddrV4> {
let igd_res = add_port(local_addr, lease_duration).await;
if let Ok(ref ext_sock_addr) = igd_res {
let ext_port = ext_sock_addr.port();
let lease_interval = Duration::from_secs(lease_duration.into());
let _ = tokio::spawn(async move {
let mut timer = time::interval_at(Instant::now() + lease_interval, lease_interval);
loop {
let _ = timer.tick().await;
debug!("Renewing IGD lease for port {}", local_addr);
let renew_res = renew_port(local_addr, ext_port, lease_duration).await;
match renew_res {
Ok(()) => {}
Err(e) => {
warn!("Failed to renew IGD lease: {} - {:?}", e, e);
}
}
}
});
}
igd_res
}
pub(crate) async fn add_port(local_addr: SocketAddr, lease_duration: u32) -> Result<SocketAddrV4> {
let gateway = igd::aio::search_gateway(Default::default()).await?;
debug!("Found IGD gateway: {:?}", gateway);
if let SocketAddr::V4(socket_addr) = local_addr {
let ext_addr = gateway
.get_any_address(
igd::PortMappingProtocol::UDP,
socket_addr,
lease_duration,
"MaidSafe.net",
)
.await?;
debug!("Our external port no. is {:?}", ext_addr.port());
Ok(ext_addr)
} else {
info!("IPv6 for IGD is not supported");
Err(Error::IgdNotSupported)
}
}
pub(crate) async fn renew_port(
local_addr: SocketAddr,
ext_port: u16,
lease_duration: u32,
) -> Result<()> {
let gateway = igd::aio::search_gateway(Default::default()).await?;
if let SocketAddr::V4(socket_addr) = local_addr {
gateway
.add_port(
igd::PortMappingProtocol::UDP,
ext_port,
socket_addr,
lease_duration,
"MaidSafe.net",
)
.await
.map_err(Error::IgdRenewPort)?;
debug!("Successfully renewed the port mapping");
Ok(())
} else {
info!("IPv6 for IGD is not supported");
Err(Error::IgdNotSupported)
}
}
pub(crate) fn get_local_ip() -> Result<IpAddr> {
debug!("Attempting to realise local IP address with IGD...");
let gateway = igd::search_gateway(Default::default())?;
let gateway_conn = std::net::TcpStream::connect(gateway.addr)?;
let local_sa = gateway_conn.local_addr()?;
info!("Fetched IP address from IGD gateway: {:?}", &local_sa.ip());
Ok(local_sa.ip())
}