use std::{
net::{Ipv4Addr, TcpListener, TcpStream, UdpSocket},
str::FromStr,
};
pub fn udp_is_available(host: &str, port: u16) -> bool {
Ipv4Addr::from_str(host)
.map(|addr| UdpSocket::bind((addr, port)).is_ok())
.unwrap_or(false)
}
pub fn tcp_is_available(host: &str, port: u16) -> bool {
Ipv4Addr::from_str(host)
.map(|addr| TcpListener::bind((addr, port)).is_ok())
.unwrap_or(false)
}
pub fn tcp_can_connect(host: &str, port: u16) -> bool {
TcpStream::connect((host, port)).is_ok()
}
pub fn port_is_available(host: &str, port: u16) -> bool {
if !tcp_is_available(host, port) {
return false;
}
udp_is_available(host, port) && !tcp_can_connect(host, port)
}
pub fn find_port(host: &str, port: u16) -> Option<u16> {
(port..=u16::MAX).find(|&p| port_is_available(host, p))
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_find_port() {
let port = find_port("127.0.0.1", 8080).unwrap();
assert_eq!(port, 8080);
}
#[test]
fn test_port_is_available() {
assert!(port_is_available("127.0.0.1", 0));
}
#[test]
fn test_invalid_host() {
assert!(!udp_is_available("invalid", 8080));
assert!(!tcp_is_available("invalid", 8080));
}
}