use local_ip_address::{local_ip, local_ipv6};
use std::net::IpAddr;
#[cfg(target_os = "linux")]
use std::{io, mem, os::unix::io::RawFd};
pub fn format_socket_addr(ip: IpAddr, port: u16) -> String {
match ip {
IpAddr::V4(v4) => format!("{}:{}", v4, port),
IpAddr::V6(v6) => format!("[{}]:{}", v6, port),
}
}
pub fn format_url(scheme: &str, ip: IpAddr, port: u16) -> String {
format!("{}://{}", scheme, format_socket_addr(ip, port))
}
pub fn preferred_local_ip() -> Option<IpAddr> {
local_ip().ok().or_else(|| local_ipv6().ok())
}
#[cfg(target_os = "linux")]
pub fn set_tcp_fastopen_connect(fd: RawFd) -> io::Result<()> {
let enable: libc::c_int = 1;
unsafe {
let ret = libc::setsockopt(
fd,
libc::IPPROTO_TCP,
libc::TCP_FASTOPEN_CONNECT,
&enable as *const _ as *const libc::c_void,
mem::size_of_val(&enable) as libc::socklen_t,
);
if ret != 0 {
let err = std::io::Error::last_os_error();
return Err(err);
}
}
Ok(())
}
#[cfg(target_os = "linux")]
pub fn set_tcp_fastopen(fd: RawFd) -> io::Result<()> {
let queue: libc::c_int = 1024;
unsafe {
let ret = libc::setsockopt(
fd,
libc::IPPROTO_TCP,
libc::TCP_FASTOPEN,
&queue as *const _ as *const libc::c_void,
mem::size_of_val(&queue) as libc::socklen_t,
);
if ret != 0 {
let err = std::io::Error::last_os_error();
return Err(err);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn test_format_socket_addr_ipv4() {
assert_eq!(
format_socket_addr(IpAddr::from_str("127.0.0.1").unwrap(), 80),
"127.0.0.1:80"
);
assert_eq!(
format_socket_addr(IpAddr::from_str("192.168.1.1").unwrap(), 8080),
"192.168.1.1:8080"
);
}
#[test]
fn test_format_socket_addr_ipv6() {
assert_eq!(
format_socket_addr(IpAddr::from_str("::1").unwrap(), 80),
"[::1]:80"
);
assert_eq!(
format_socket_addr(IpAddr::from_str("2001:db8::1").unwrap(), 8080),
"[2001:db8::1]:8080"
);
}
#[test]
fn test_format_url_ipv4() {
assert_eq!(
format_url("http", IpAddr::from_str("127.0.0.1").unwrap(), 80),
"http://127.0.0.1:80"
);
assert_eq!(
format_url("https", IpAddr::from_str("192.168.1.1").unwrap(), 443),
"https://192.168.1.1:443"
);
}
#[test]
fn test_format_url_ipv6() {
assert_eq!(
format_url("http", IpAddr::from_str("::1").unwrap(), 80),
"http://[::1]:80"
);
assert_eq!(
format_url("https", IpAddr::from_str("2001:db8::1").unwrap(), 443),
"https://[2001:db8::1]:443"
);
}
#[test]
fn test_preferred_local_ip() {
let ip = preferred_local_ip();
assert!(ip.is_some());
}
}