1 #![allow(unsafe_code)]
2
3 use crate::time::Duration;
4 use std::os::unix::io::RawFd;
5 use std::{io, mem, ptr};
6
7 #[cfg(any(target_os = "linux", target_os = "android"))]
8 #[path = "linux.rs"]
9 mod imp;
10
11 #[cfg(all(
12 feature = "phy-raw_socket",
13 not(any(target_os = "linux", target_os = "android")),
14 unix
15 ))]
16 pub mod bpf;
17 #[cfg(all(
18 feature = "phy-raw_socket",
19 any(target_os = "linux", target_os = "android")
20 ))]
21 pub mod raw_socket;
22 #[cfg(all(
23 feature = "phy-tuntap_interface",
24 any(target_os = "linux", target_os = "android")
25 ))]
26 pub mod tuntap_interface;
27
28 #[cfg(all(
29 feature = "phy-raw_socket",
30 not(any(target_os = "linux", target_os = "android")),
31 unix
32 ))]
33 pub use self::bpf::BpfDevice as RawSocketDesc;
34 #[cfg(all(
35 feature = "phy-raw_socket",
36 any(target_os = "linux", target_os = "android")
37 ))]
38 pub use self::raw_socket::RawSocketDesc;
39 #[cfg(all(
40 feature = "phy-tuntap_interface",
41 any(target_os = "linux", target_os = "android")
42 ))]
43 pub use self::tuntap_interface::TunTapInterfaceDesc;
44
45 /// Wait until given file descriptor becomes readable, but no longer than given timeout.
wait(fd: RawFd, duration: Option<Duration>) -> io::Result<()>46 pub fn wait(fd: RawFd, duration: Option<Duration>) -> io::Result<()> {
47 unsafe {
48 let mut readfds = {
49 let mut readfds = mem::MaybeUninit::<libc::fd_set>::uninit();
50 libc::FD_ZERO(readfds.as_mut_ptr());
51 libc::FD_SET(fd, readfds.as_mut_ptr());
52 readfds.assume_init()
53 };
54
55 let mut writefds = {
56 let mut writefds = mem::MaybeUninit::<libc::fd_set>::uninit();
57 libc::FD_ZERO(writefds.as_mut_ptr());
58 writefds.assume_init()
59 };
60
61 let mut exceptfds = {
62 let mut exceptfds = mem::MaybeUninit::<libc::fd_set>::uninit();
63 libc::FD_ZERO(exceptfds.as_mut_ptr());
64 exceptfds.assume_init()
65 };
66
67 let mut timeout = libc::timeval {
68 tv_sec: 0,
69 tv_usec: 0,
70 };
71 let timeout_ptr = if let Some(duration) = duration {
72 timeout.tv_sec = duration.secs() as libc::time_t;
73 timeout.tv_usec = (duration.millis() * 1_000) as libc::suseconds_t;
74 &mut timeout as *mut _
75 } else {
76 ptr::null_mut()
77 };
78
79 let res = libc::select(
80 fd + 1,
81 &mut readfds,
82 &mut writefds,
83 &mut exceptfds,
84 timeout_ptr,
85 );
86 if res == -1 {
87 return Err(io::Error::last_os_error());
88 }
89 Ok(())
90 }
91 }
92
93 #[cfg(all(
94 any(feature = "phy-tuntap_interface", feature = "phy-raw_socket"),
95 unix
96 ))]
97 #[repr(C)]
98 #[derive(Debug)]
99 struct ifreq {
100 ifr_name: [libc::c_char; libc::IF_NAMESIZE],
101 ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
102 }
103
104 #[cfg(all(
105 any(feature = "phy-tuntap_interface", feature = "phy-raw_socket"),
106 unix
107 ))]
ifreq_for(name: &str) -> ifreq108 fn ifreq_for(name: &str) -> ifreq {
109 let mut ifreq = ifreq {
110 ifr_name: [0; libc::IF_NAMESIZE],
111 ifr_data: 0,
112 };
113 for (i, byte) in name.as_bytes().iter().enumerate() {
114 ifreq.ifr_name[i] = *byte as libc::c_char
115 }
116 ifreq
117 }
118
119 #[cfg(all(
120 any(target_os = "linux", target_os = "android"),
121 any(feature = "phy-tuntap_interface", feature = "phy-raw_socket")
122 ))]
ifreq_ioctl( lower: libc::c_int, ifreq: &mut ifreq, cmd: libc::c_ulong, ) -> io::Result<libc::c_int>123 fn ifreq_ioctl(
124 lower: libc::c_int,
125 ifreq: &mut ifreq,
126 cmd: libc::c_ulong,
127 ) -> io::Result<libc::c_int> {
128 unsafe {
129 let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
130 if res == -1 {
131 return Err(io::Error::last_os_error());
132 }
133 }
134
135 Ok(ifreq.ifr_data)
136 }
137