use std::net::{IpAddr, SocketAddr};
pub(crate) fn reachable_ip(local: SocketAddr, peer: IpAddr) -> IpAddr {
if !local.ip().is_unspecified() {
return local.ip();
}
if peer.is_loopback() {
return "127.0.0.1".parse().unwrap_or(peer);
}
local_address_towards(peer)
}
fn local_address_towards(peer: IpAddr) -> IpAddr {
std::net::UdpSocket::bind("0.0.0.0:0")
.and_then(|socket| {
socket.connect(std::net::SocketAddr::new(peer, 9))?;
socket.local_addr()
})
.map_or_else(|_| "127.0.0.1".parse().unwrap_or(peer), |addr| addr.ip())
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn an_explicit_bind_address_is_advertised_as_given() {
let local: SocketAddr = "192.0.2.10:5060".parse().unwrap();
let peer: IpAddr = "203.0.113.1".parse().unwrap();
assert_eq!(reachable_ip(local, peer), local.ip());
}
#[test]
fn a_loopback_peer_is_faced_from_loopback() {
let local: SocketAddr = "0.0.0.0:0".parse().unwrap();
let peer: IpAddr = "127.0.0.1".parse().unwrap();
assert_eq!(reachable_ip(local, peer), peer);
}
#[test]
fn the_advertised_address_is_never_the_peers_or_unspecified() {
let local: SocketAddr = "0.0.0.0:0".parse().unwrap();
let peer: IpAddr = "192.0.2.1".parse().unwrap();
let advertised = reachable_ip(local, peer);
assert_ne!(advertised, peer, "the peer's address is somebody else's");
assert!(!advertised.is_unspecified());
}
}