extern crate libc;
use std::io;
use std::mem;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use internal::CSocket;
#[cfg(windows)]
pub unsafe fn close(sock: CSocket) {
let _ = libc::closesocket(sock);
}
#[cfg(unix)]
pub unsafe fn close(sock: CSocket) {
let _ = libc::close(sock);
}
fn errno() -> i32 {
io::Error::last_os_error().raw_os_error().unwrap()
}
#[cfg(windows)]
#[inline]
pub fn retry<F>(f: &mut F) -> libc::c_int
where F: FnMut() -> libc::c_int
{
loop {
let minus1 = -1;
let ret = f();
if ret != minus1 || errno() as isize != libc::WSAEINTR as isize {
return ret;
}
}
}
#[cfg(unix)]
#[inline]
pub fn retry<F>(f: &mut F) -> libc::ssize_t
where F: FnMut() -> libc::ssize_t
{
loop {
let minus1 = -1;
let ret = f();
if ret != minus1 || errno() as isize != libc::EINTR as isize {
return ret;
}
}
}
fn htons(u: u16) -> u16 {
u.to_be()
}
fn ntohs(u: u16) -> u16 {
u16::from_be(u)
}
pub fn addr_to_sockaddr(addr: SocketAddr, storage: &mut libc::sockaddr_storage) -> libc::socklen_t {
unsafe {
let len = match addr {
SocketAddr::V4(sa) => {
let ip_addr = sa.ip();
let [a, b, c, d] = ip_addr.octets();
let inaddr = libc::in_addr {
s_addr: u32::from_be(((a as u32) << 24) | ((b as u32) << 16) |
((c as u32) << 8) |
(d as u32)),
};
let storage = storage as *mut _ as *mut libc::sockaddr_in;
(*storage).sin_family = libc::AF_INET as libc::sa_family_t;
(*storage).sin_port = htons(addr.port());
(*storage).sin_addr = inaddr;
mem::size_of::<libc::sockaddr_in>()
}
SocketAddr::V6(sa) => {
let ip_addr = sa.ip();
let [a, b, c, d, e, f, g, h] = ip_addr.segments();
let inaddr = libc::in6_addr {
s6_addr: [htons(a), htons(b), htons(c), htons(d), htons(e), htons(f), htons(g),
htons(h)],
};
let storage = storage as *mut _ as *mut libc::sockaddr_in6;
(*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t;
(*storage).sin6_port = htons(addr.port());
(*storage).sin6_addr = inaddr;
mem::size_of::<libc::sockaddr_in6>()
}
};
len as libc::socklen_t
}
}
pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: usize) -> io::Result<SocketAddr> {
match storage.ss_family as libc::c_int {
libc::AF_INET => {
assert!(len as usize >= mem::size_of::<libc::sockaddr_in>());
let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) };
let ip = (storage.sin_addr.s_addr as u32).to_be();
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))
}
libc::AF_INET6 => {
assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>());
let storage: &libc::sockaddr_in6 = unsafe { mem::transmute(storage) };
let a = ntohs(storage.sin6_addr.s6_addr[0]);
let b = ntohs(storage.sin6_addr.s6_addr[1]);
let c = ntohs(storage.sin6_addr.s6_addr[2]);
let d = ntohs(storage.sin6_addr.s6_addr[3]);
let e = ntohs(storage.sin6_addr.s6_addr[4]);
let f = ntohs(storage.sin6_addr.s6_addr[5]);
let g = ntohs(storage.sin6_addr.s6_addr[6]);
let h = ntohs(storage.sin6_addr.s6_addr[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),
u32::from_be(storage.sin6_scope_id))))
}
_ => {
#[cfg(unix)]
use libc::EINVAL as ERROR;
#[cfg(windows)]
use libc::WSAEINVAL as ERROR;
Err(io::Error::from_raw_os_error(ERROR))
}
}
}