use async_std::net::{SocketAddr, TcpListener, UdpSocket};
use std::net::IpAddr;
use std::sync::Arc;
use futures::prelude::*;
use futures::StreamExt;
use get_if_addrs::get_if_addrs;
use crate::agent::AgentError;
use crate::candidate::TransportType;
use crate::socket::UdpSocketChannel;
#[derive(Debug, Clone)]
pub enum GatherSocket {
Udp(UdpSocketChannel),
Tcp(Arc<TcpListener>),
}
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 fn iface_sockets(
) -> Result<impl Stream<Item = Result<GatherSocket, std::io::Error>>, AgentError> {
let mut ifaces = 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());
}) {}
Ok(futures::stream::iter(ifaces.clone())
.then(|iface| async move {
Ok(GatherSocket::Udp(UdpSocketChannel::new(
UdpSocket::bind(SocketAddr::new(iface.clone().ip(), 0)).await?,
)))
})
.chain(futures::stream::iter(ifaces).then(|iface| async move {
Ok(GatherSocket::Tcp(Arc::new(
TcpListener::bind(SocketAddr::new(iface.clone().ip(), 0)).await?,
)))
})))
}