use std::io;
use std::net::{TcpStream, UdpSocket, IpAddr, Ipv4Addr, Ipv6Addr};
use std::net;
use std::time::Instant;
#[cfg(target_family = "windows")]
use std::mem;
use socket_addr::SocketAddr;
use std::io::ErrorKind;
use net2;
pub trait RecvUntil {
fn recv_until(&self,
buf: &mut [u8],
deadline: Instant)
-> io::Result<Option<(usize, SocketAddr)>>;
}
impl RecvUntil for UdpSocket {
fn recv_until(&self,
buf: &mut [u8],
deadline: Instant)
-> io::Result<Option<(usize, SocketAddr)>> {
let old_timeout = try!(self.read_timeout());
loop {
let current_time = Instant::now();
if current_time >= deadline {
try!(self.set_read_timeout(old_timeout));
return Ok(None);
}
{
let timeout = deadline - current_time;
try!(self.set_read_timeout(Some(timeout)));
}
match self.recv_from(buf) {
Ok((bytes_len, addr)) => {
try!(self.set_read_timeout(old_timeout));
return Ok(Some((bytes_len, SocketAddr(addr))));
},
Err(e) => {
match e.kind() {
ErrorKind::TimedOut | ErrorKind::WouldBlock => {
try!(self.set_read_timeout(old_timeout));
return Ok(None);
},
ErrorKind::Interrupted => (),
ErrorKind::ConnectionReset => (),
_ => {
try!(self.set_read_timeout(old_timeout));
return Err(e);
},
}
}
}
}
}
}
pub fn ipv4_is_unspecified(addr: &Ipv4Addr) -> bool {
addr.octets() == [0, 0, 0, 0]
}
pub fn ipv6_is_unspecified(addr: &Ipv6Addr) -> bool {
addr.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
}
pub fn ipv4_unspecified_to_loopback(addr: Ipv4Addr) -> Ipv4Addr {
if ipv4_is_unspecified(&addr) {
Ipv4Addr::new(127, 0, 0, 1)
}
else {
addr
}
}
pub fn ipv6_unspecified_to_loopback(addr: Ipv6Addr) -> Ipv6Addr {
if ipv6_is_unspecified(&addr) {
Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)
}
else {
addr
}
}
pub fn ip_unspecified_to_loopback(addr: IpAddr) -> IpAddr {
match addr {
IpAddr::V4(addr_v4) => IpAddr::V4(ipv4_unspecified_to_loopback(addr_v4)),
IpAddr::V6(addr_v6) => IpAddr::V6(ipv6_unspecified_to_loopback(addr_v6)),
}
}
pub fn ipv4_is_loopback(addr: &Ipv4Addr) -> bool {
addr.octets()[0] == 127
}
pub fn ipv6_is_loopback(addr: &Ipv6Addr) -> bool {
addr.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
}
pub fn is_loopback(addr: &IpAddr) -> bool {
match *addr {
IpAddr::V4(ref addr_v4) => ipv4_is_loopback(addr_v4),
IpAddr::V6(ref addr_v6) => ipv6_is_loopback(addr_v6),
}
}
#[cfg(target_family = "unix")]
pub fn enable_so_reuseport(sock: &net2::TcpBuilder) -> io::Result<()> {
use net2::unix::UnixTcpBuilderExt;
let _ = try!(sock.reuse_port(true));
Ok(())
}
#[cfg(target_family = "windows")]
pub fn enable_so_reuseport(_sock: &net2::TcpBuilder) -> io::Result<()> {
Ok(())
}
#[cfg(target_family = "unix")]
#[allow(unsafe_code)]
pub fn tcp_builder_local_addr(sock: &net2::TcpBuilder) -> io::Result<net::SocketAddr> {
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
let fd = sock.as_raw_fd();
let stream = unsafe { TcpStream::from_raw_fd(fd) };
let ret = stream.local_addr();
let _ = stream.into_raw_fd();
ret
}
#[cfg(target_family = "windows")]
#[allow(unsafe_code)]
pub fn tcp_builder_local_addr(sock: &net2::TcpBuilder) -> io::Result<net::SocketAddr> {
use std::os::windows::io::{AsRawSocket, FromRawSocket};
let fd = sock.as_raw_socket();
let stream = unsafe { TcpStream::from_raw_socket(fd) };
let ret = stream.local_addr();
mem::forget(stream); ret
}