1use std::io;
2use std::mem;
3use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
4use std::time::Duration;
5
6pub type CSocket = libc::c_int;
7pub type Buf = *const libc::c_void;
8pub type MutBuf = *mut libc::c_void;
9pub type BufLen = libc::size_t;
10pub type CouldFail = libc::ssize_t;
11pub type SockLen = libc::socklen_t;
12pub type MutSockLen = *mut libc::socklen_t;
13pub type SockAddr = libc::sockaddr;
14pub type SockAddrIn = libc::sockaddr_in;
15pub type SockAddrIn6 = libc::sockaddr_in6;
16pub type SockAddrStorage = libc::sockaddr_storage;
17pub type SockAddrFamily = libc::sa_family_t;
18pub type SockAddrFamily6 = libc::sa_family_t;
19pub type InAddr = libc::in_addr;
20pub type In6Addr = libc::in6_addr;
21
22#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "netbsd")))]
23pub type TvUsecType = libc::c_long;
24#[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
25pub type TvUsecType = libc::c_int;
26
27pub const AF_INET: libc::c_int = libc::AF_INET;
28pub const AF_INET6: libc::c_int = libc::AF_INET6;
29
30pub use libc::{IFF_BROADCAST, IFF_LOOPBACK, IFF_MULTICAST, IFF_POINTOPOINT, IFF_UP};
31
32pub unsafe fn close(sock: CSocket) {
33 unsafe {
34 let _ = libc::close(sock);
35 }
36}
37
38fn ntohs(u: u16) -> u16 {
39 u16::from_be(u)
40}
41
42pub fn sockaddr_to_addr(storage: &SockAddrStorage, len: usize) -> io::Result<SocketAddr> {
43 match storage.ss_family as libc::c_int {
44 AF_INET => {
45 assert!(len as usize >= mem::size_of::<SockAddrIn>());
46 let storage: &SockAddrIn = unsafe { mem::transmute(storage) };
47 let ip = ipv4_addr_int(storage.sin_addr);
48 let o1 = (ip >> 24) as u8;
50 let o2 = (ip >> 16) as u8;
51 let o3 = (ip >> 8) as u8;
52 let o4 = ip as u8;
53 let sockaddrv4 =
54 SocketAddrV4::new(Ipv4Addr::new(o1, o2, o3, o4), ntohs(storage.sin_port));
55 Ok(SocketAddr::V4(sockaddrv4))
56 }
57 AF_INET6 => {
58 assert!(len as usize >= mem::size_of::<SockAddrIn6>());
59 let storage: &SockAddrIn6 = unsafe { mem::transmute(storage) };
60 let arr: [u16; 8] = unsafe { mem::transmute(storage.sin6_addr.s6_addr) };
61 let h1 = ntohs(arr[0]);
63 let h2 = ntohs(arr[1]);
64 let h3 = ntohs(arr[2]);
65 let h4 = ntohs(arr[3]);
66 let h5 = ntohs(arr[4]);
67 let h6 = ntohs(arr[5]);
68 let h7 = ntohs(arr[6]);
69 let h8 = ntohs(arr[7]);
70 let ip = Ipv6Addr::new(h1, h2, h3, h4, h5, h6, h7, h8);
71 Ok(SocketAddr::V6(SocketAddrV6::new(
72 ip,
73 ntohs(storage.sin6_port),
74 u32::from_be(storage.sin6_flowinfo),
75 storage.sin6_scope_id,
76 )))
77 }
78 _ => Err(io::Error::new(io::ErrorKind::InvalidData, "Not supported")),
79 }
80}
81
82#[inline(always)]
83pub fn ipv4_addr_int(addr: InAddr) -> u32 {
84 (addr.s_addr as u32).to_be()
85}
86
87pub fn timeval_to_duration(tv: libc::timeval) -> Duration {
89 Duration::new(tv.tv_sec as u64, (tv.tv_usec as u32) * 1000)
90}
91
92pub fn duration_to_timeval(dur: Duration) -> libc::timeval {
94 libc::timeval {
95 tv_sec: dur.as_secs() as libc::time_t,
96 tv_usec: dur.subsec_micros() as TvUsecType,
97 }
98}
99
100pub fn timespec_to_duration(ts: libc::timespec) -> Duration {
102 Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
103}
104
105pub fn duration_to_timespec(dur: Duration) -> libc::timespec {
107 libc::timespec {
108 tv_sec: dur.as_secs() as libc::time_t,
109 tv_nsec: (dur.subsec_nanos() as TvUsecType).into(),
110 }
111}
112
113pub unsafe fn sendto(
114 socket: CSocket,
115 buf: Buf,
116 len: BufLen,
117 flags: libc::c_int,
118 addr: *const SockAddr,
119 addrlen: SockLen,
120) -> CouldFail {
121 unsafe { libc::sendto(socket, buf, len, flags, addr, addrlen) }
122}
123
124pub unsafe fn recvfrom(
125 socket: CSocket,
126 buf: MutBuf,
127 len: BufLen,
128 flags: libc::c_int,
129 addr: *mut SockAddr,
130 addrlen: *mut SockLen,
131) -> CouldFail {
132 unsafe { libc::recvfrom(socket, buf, len, flags, addr, addrlen) }
133}
134
135#[inline]
136pub fn retry<F>(f: &mut F) -> libc::ssize_t
137where
138 F: FnMut() -> libc::ssize_t,
139{
140 loop {
141 let ret = f();
142 if ret != -1 || errno() as isize != libc::EINTR as isize {
143 return ret;
144 }
145 }
146}
147
148fn errno() -> i32 {
149 io::Error::last_os_error().raw_os_error().unwrap()
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 use std::time::Duration;
156
157 #[test]
158 fn test_timeval_round_trip() {
159 let dur = Duration::new(1, 500_000_000);
160 let tv = duration_to_timeval(dur);
161 assert_eq!(timeval_to_duration(tv), dur);
162 }
163
164 #[test]
165 fn test_timespec_round_trip() {
166 let dur = Duration::new(2, 123_456_789);
167 let ts = duration_to_timespec(dur);
168 assert_eq!(timespec_to_duration(ts), dur);
169 }
170
171 #[test]
172 fn test_ipv4_addr_int() {
173 let addr = InAddr {
174 s_addr: u32::from_be(0x7f000001),
175 };
176 assert_eq!(ipv4_addr_int(addr), 0x7f000001);
177 }
178}