extern crate libc;
use std::io;
use std::mem;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::Duration;
#[cfg(unix)]
#[path = "unix.rs"]
mod imp;
#[cfg(windows)]
#[path = "windows.rs"]
mod imp;
pub use self::imp::public::*;
pub struct FileDesc {
pub fd: CSocket,
}
impl Drop for FileDesc {
fn drop(&mut self) {
unsafe {
close(self.fd);
}
}
}
pub fn send_to(
socket: CSocket,
buffer: &[u8],
dst: *const SockAddr,
slen: SockLen,
) -> io::Result<usize> {
let send_len = imp::retry(&mut || unsafe {
imp::sendto(
socket,
buffer.as_ptr() as Buf,
buffer.len() as BufLen,
0,
dst,
slen,
)
});
if send_len < 0 {
Err(io::Error::last_os_error())
} else {
Ok(send_len as usize)
}
}
pub fn recv_from(
socket: CSocket,
buffer: &mut [u8],
caddr: *mut SockAddrStorage,
) -> io::Result<usize> {
let mut caddrlen = mem::size_of::<SockAddrStorage>() as SockLen;
let len = imp::retry(&mut || unsafe {
imp::recvfrom(
socket,
buffer.as_ptr() as MutBuf,
buffer.len() as BufLen,
0,
caddr as *mut SockAddr,
&mut caddrlen,
)
});
if len < 0 {
Err(io::Error::last_os_error())
} else {
Ok(len as usize)
}
}
#[cfg(unix)]
pub fn set_socket_receive_timeout(socket: CSocket, t: Duration) -> io::Result<()> {
let ts = duration_to_timeval(t);
let r = unsafe {
setsockopt(
socket,
SOL_SOCKET,
SO_RCVTIMEO,
(&ts as *const libc::timeval) as Buf,
mem::size_of::<libc::timeval>() as SockLen,
)
};
if r < 0 {
Err(io::Error::last_os_error())
} else if r > 0 {
Err(io::Error::new(
io::ErrorKind::Other,
format!("Unknown return value from getsockopt(): {}", r),
))
} else {
Ok(())
}
}
#[cfg(unix)]
pub fn get_socket_receive_timeout(socket: CSocket) -> io::Result<Duration> {
let ts = libc::timeval {
tv_sec: 0,
tv_usec: 0,
};
let len: SockLen = mem::size_of::<libc::timeval>() as SockLen;
let r = unsafe {
getsockopt(
socket,
SOL_SOCKET,
SO_RCVTIMEO,
(&ts as *const libc::timeval) as MutBuf,
(&len as *const SockLen) as MutSockLen,
)
};
assert_eq!(
len,
mem::size_of::<libc::timeval>() as SockLen,
"getsockopt did not set size of return value"
);
if r < 0 {
Err(io::Error::last_os_error())
} else if r > 0 {
Err(io::Error::new(
io::ErrorKind::Other,
format!("Unknown return value from getsockopt(): {}", r),
))
} else {
Ok(timeval_to_duration(ts))
}
}
fn htons(u: u16) -> u16 {
u.to_be()
}
fn ntohs(u: u16) -> u16 {
u16::from_be(u)
}
fn make_in6_addr(segments: [u16; 8]) -> In6Addr {
#[allow(deprecated)]
let mut val: In6Addr = unsafe { mem::uninitialized() };
val.s6_addr = unsafe {
mem::transmute([
htons(segments[0]),
htons(segments[1]),
htons(segments[2]),
htons(segments[3]),
htons(segments[4]),
htons(segments[5]),
htons(segments[6]),
htons(segments[7]),
])
};
val
}
pub fn addr_to_sockaddr(addr: SocketAddr, storage: &mut SockAddrStorage) -> SockLen {
unsafe {
let len = match addr {
SocketAddr::V4(sa) => {
let ip_addr = sa.ip();
let octets = ip_addr.octets();
let inaddr = imp::mk_inaddr(u32::from_be(
((octets[0] as u32) << 24)
| ((octets[1] as u32) << 16)
| ((octets[2] as u32) << 8)
| (octets[3] as u32),
));
let storage = storage as *mut _ as *mut SockAddrIn;
(*storage).sin_family = AF_INET as SockAddrFamily;
(*storage).sin_port = htons(addr.port());
(*storage).sin_addr = inaddr;
mem::size_of::<SockAddrIn>()
}
SocketAddr::V6(sa) => {
let ip_addr = sa.ip();
let segments = ip_addr.segments();
let inaddr = make_in6_addr(segments);
let storage = storage as *mut _ as *mut SockAddrIn6;
(*storage).sin6_family = AF_INET6 as SockAddrFamily6;
(*storage).sin6_port = htons(addr.port());
(*storage).sin6_addr = inaddr;
(*storage).sin6_scope_id = sa.scope_id();
mem::size_of::<SockAddrIn6>()
}
};
len as SockLen
}
}
pub fn sockaddr_to_addr(storage: &SockAddrStorage, len: usize) -> io::Result<SocketAddr> {
match storage.ss_family as libc::c_int {
AF_INET => {
assert!(len as usize >= mem::size_of::<SockAddrIn>());
let storage: &SockAddrIn = unsafe { mem::transmute(storage) };
let ip = imp::ipv4_addr(storage.sin_addr);
let a = (ip >> 24) as u8;
let b = (ip >> 16) as u8;
let c = (ip >> 8) as u8;
let d = ip as u8;
let sockaddrv4 = SocketAddrV4::new(Ipv4Addr::new(a, b, c, d), ntohs(storage.sin_port));
Ok(SocketAddr::V4(sockaddrv4))
}
AF_INET6 => {
assert!(len as usize >= mem::size_of::<SockAddrIn6>());
let storage: &SockAddrIn6 = unsafe { mem::transmute(storage) };
let arr: [u16; 8] = unsafe { mem::transmute(storage.sin6_addr.s6_addr) };
let a = ntohs(arr[0]);
let b = ntohs(arr[1]);
let c = ntohs(arr[2]);
let d = ntohs(arr[3]);
let e = ntohs(arr[4]);
let f = ntohs(arr[5]);
let g = ntohs(arr[6]);
let h = ntohs(arr[7]);
let ip = Ipv6Addr::new(a, b, c, d, e, f, g, h);
Ok(SocketAddr::V6(SocketAddrV6::new(
ip,
ntohs(storage.sin6_port),
u32::from_be(storage.sin6_flowinfo),
storage.sin6_scope_id,
)))
}
_ => Err(io::Error::new(
io::ErrorKind::InvalidData,
"expected IPv4 or IPv6 socket",
)),
}
}
#[cfg(test)]
mod tests {
use get_socket_receive_timeout;
use recv_from;
use set_socket_receive_timeout;
use std::mem;
use std::time::{Duration, Instant};
use CSocket;
use SockAddrStorage;
fn test_timeout(socket: CSocket) -> Duration {
let mut buffer = [0u8; 1024];
let mut caddr: SockAddrStorage = unsafe { mem::zeroed() };
let t0 = Instant::now();
let res = recv_from(socket, &mut buffer, &mut caddr);
assert!(!res.is_ok());
Instant::now() - t0
}
#[test]
fn test_set_socket_receive_timeout_1s() {
let socket = unsafe { libc::socket(libc::AF_INET, libc::SOCK_RAW, 1 as libc::c_int) };
let d = Duration::new(1, 0);
let res = set_socket_receive_timeout(socket, d.clone());
match res {
Err(e) => panic!("set_socket_receive_timeout reslted in error: {}", e),
_ => {}
};
let t = test_timeout(socket);
assert!(t >= Duration::new(1, 0));
assert!(t < Duration::from_millis(1100));
}
#[test]
fn test_set_socket_receive_timeout_500ms() {
let socket = unsafe { libc::socket(libc::AF_INET, libc::SOCK_RAW, 1 as libc::c_int) };
let d = Duration::from_millis(500);
let res = set_socket_receive_timeout(socket, d);
match res {
Err(e) => panic!("set_socket_receive_timeout reslted in error: {}", e),
_ => {}
};
let t = test_timeout(socket);
assert!(t >= Duration::from_millis(500));
assert!(t < Duration::from_millis(600));
}
#[test]
fn test_set_socket_receive_timeout_1500ms() {
let socket = unsafe { libc::socket(libc::AF_INET, libc::SOCK_RAW, 1 as libc::c_int) };
let d = Duration::from_millis(1500);
let res = set_socket_receive_timeout(socket, d);
match res {
Err(e) => panic!("set_socket_receive_timeout reslted in error: {}", e),
_ => {}
};
let t = test_timeout(socket);
assert!(t >= Duration::from_millis(1500));
assert!(t < Duration::from_millis(1600));
}
#[test]
fn test_get_socket_receive_timeout() {
let socket = unsafe { libc::socket(libc::AF_INET, libc::SOCK_RAW, 1 as libc::c_int) };
let s1 = Duration::new(1, 0);
set_socket_receive_timeout(socket, s1).ok();
let g1 = get_socket_receive_timeout(socket);
match g1 {
Err(e) => panic!("get_socket_receive_timeout resulted in error: {}", e),
Ok(t) => assert_eq!(s1, t, "Expected to receive 1s timeout"),
}
let s2 = Duration::from_millis(500);
set_socket_receive_timeout(socket, s2).ok();
let g2 = get_socket_receive_timeout(socket);
match g2 {
Err(e) => panic!("get_socket_receive_timeout resulted in error: {}", e),
Ok(t) => assert_eq!(s2, t, "Expected to receive 500ms timeout"),
}
}
}