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