use std::net::{SocketAddr, UdpSocket};
use tracing::info;
use std::net::IpAddr;
use std::sync::Arc;
use crate::agent::AgentError;
use crate::candidate::TransportType;
use crate::runtime::{AsyncTcpListener, Runtime};
use crate::socket::UdpSocketChannel;
#[derive(Debug, Clone)]
pub enum GatherSocket {
Udp(UdpSocketChannel),
Tcp(Arc<dyn AsyncTcpListener>),
}
impl GatherSocket {
pub fn transport(&self) -> TransportType {
match self {
GatherSocket::Udp(_) => TransportType::Udp,
GatherSocket::Tcp(_) => TransportType::Tcp,
}
}
pub fn local_addr(&self) -> SocketAddr {
match self {
GatherSocket::Udp(s) => s.local_addr().unwrap(),
GatherSocket::Tcp(s) => s.local_addr().unwrap(),
}
}
}
fn address_is_ignorable(ip: IpAddr) -> bool {
if ip.is_loopback() || ip.is_unspecified() || ip.is_multicast() {
return true;
}
match ip {
IpAddr::V4(ipv4) => ipv4.is_broadcast() || ipv4.is_link_local(),
IpAddr::V6(_ipv6) => false,
}
}
pub async fn iface_sockets(
runtime: Arc<dyn Runtime>,
) -> Result<Vec<Result<GatherSocket, std::io::Error>>, AgentError> {
let mut ifaces = if_addrs::get_if_addrs()?;
ifaces.retain(|e| !address_is_ignorable(e.ip()));
for _f in ifaces.iter().inspect(|iface| {
info!("Found interface {} address {:?}", iface.name, iface.ip());
}) {}
let mut ret = vec![];
for iface in ifaces {
ret.push(
UdpSocket::bind(SocketAddr::new(iface.clone().ip(), 0)).and_then(|udp| {
runtime
.wrap_udp_socket(udp)
.map(|udp| GatherSocket::Udp(UdpSocketChannel::new(udp)))
}),
);
ret.push(
runtime
.new_tcp_listener(SocketAddr::new(iface.clone().ip(), 0))
.await
.map(GatherSocket::Tcp),
);
}
Ok(ret)
}