hook/unix/
common.rs

1extern "C" {
2    #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
3    #[cfg_attr(
4        any(
5            target_os = "linux",
6            target_os = "emscripten",
7            target_os = "fuchsia",
8            target_os = "l4re"
9        ),
10        link_name = "__errno_location"
11    )]
12    #[cfg_attr(
13        any(
14            target_os = "netbsd",
15            target_os = "openbsd",
16            target_os = "android",
17            target_os = "redox",
18            target_env = "newlib"
19        ),
20        link_name = "__errno"
21    )]
22    #[cfg_attr(
23        any(target_os = "solaris", target_os = "illumos"),
24        link_name = "___errno"
25    )]
26    #[cfg_attr(
27        any(
28            target_os = "macos",
29            target_os = "ios",
30            target_os = "freebsd",
31            target_os = "watchos"
32        ),
33        link_name = "__error"
34    )]
35    #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
36    fn errno_location() -> *mut libc::c_int;
37}
38
39pub extern "C" fn reset_errno() {
40    set_errno(0)
41}
42
43pub extern "C" fn set_errno(errno: libc::c_int) {
44    unsafe { errno_location().write(errno) }
45}
46
47pub extern "C" fn set_non_blocking(socket: libc::c_int, on: bool) -> bool {
48    unsafe {
49        let flags = libc::fcntl(socket, libc::F_GETFL);
50        if flags < 0 {
51            return false;
52        }
53        libc::fcntl(
54            socket,
55            libc::F_SETFL,
56            if on {
57                flags | libc::O_NONBLOCK
58            } else {
59                flags & !libc::O_NONBLOCK
60            },
61        ) == 0
62    }
63}
64
65pub extern "C" fn is_blocking(socket: libc::c_int) -> bool {
66    !is_non_blocking(socket)
67}
68
69pub extern "C" fn is_non_blocking(socket: libc::c_int) -> bool {
70    unsafe {
71        let flags = libc::fcntl(socket, libc::F_GETFL);
72        if flags < 0 {
73            return false;
74        }
75        (flags & libc::O_NONBLOCK) != 0
76    }
77}
78
79/// check https://www.rustwiki.org.cn/en/reference/introduction.html for help information
80#[macro_export]
81macro_rules! init_hook {
82    ( $symbol:literal ) => {{
83        once_cell::sync::Lazy::new(|| unsafe {
84            let symbol = std::ffi::CString::new(String::from($symbol)).expect(&String::from(
85                "can not transfer \"".to_owned() + $symbol + "\" to CString",
86            ));
87            let ptr = libc::dlsym(libc::RTLD_NEXT, symbol.as_ptr());
88            if ptr.is_null() {
89                panic!("system {} not found !", $symbol);
90            }
91            std::mem::transmute(ptr)
92        })
93    }};
94}
95
96#[macro_export]
97macro_rules! impl_simple_hook {
98    ( ($fn: expr) ( $socket:expr, $($arg: expr),* $(,)* ), $timeout:expr) => {{
99        let ns_time = ($timeout as Option<std::time::Duration>).map(|d|d.as_nanos() as u64).unwrap_or(u64::MAX);
100        let timeout_time = timer_utils::add_timeout_time(ns_time);
101        let _ = base_coroutine::EventLoop::round_robin_timeout_schedule(timeout_time);
102        unsafe {
103            let mut set: libc::sigset_t = std::mem::zeroed();
104            libc::sigaddset(&mut set, libc::SIGURG);
105            let mut oldset: libc::sigset_t = std::mem::zeroed();
106            libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
107            let r = $fn($socket ,$($arg, )*);
108            libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
109            r
110        }
111    }};
112}
113
114//todo try to replace with impl_expected_read_hook
115#[macro_export]
116macro_rules! impl_read_hook {
117    ( ($fn: expr) ( $socket:expr, $($arg: expr),* $(,)* ), $timeout:expr) => {{
118        let socket = $socket;
119        let blocking = $crate::unix::common::is_blocking(socket);
120        if blocking {
121            $crate::unix::common::set_non_blocking(socket, true);
122        }
123        let event_loop = base_coroutine::EventLoop::next();
124        let mut r;
125        loop {
126            unsafe {
127                let mut set: libc::sigset_t = std::mem::zeroed();
128                libc::sigaddset(&mut set, libc::SIGURG);
129                let mut oldset: libc::sigset_t = std::mem::zeroed();
130                libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
131                r = $fn($socket ,$($arg, )*);
132                libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
133            }
134            if r != -1 {
135                $crate::unix::common::reset_errno();
136                break;
137            }
138            let error_kind = std::io::Error::last_os_error().kind();
139            if error_kind == std::io::ErrorKind::WouldBlock {
140                //等待读事件
141                if let Err(e) = event_loop.wait_read_event(socket, $timeout) {
142                    match e.kind() {
143                        //maybe invoke by Monitor::signal(), just ignore this
144                        std::io::ErrorKind::Interrupted => $crate::unix::common::reset_errno(),
145                        _ => break,
146                    }
147                }
148            } else if error_kind != std::io::ErrorKind::Interrupted {
149                break;
150            }
151        }
152        if blocking {
153            $crate::unix::common::set_non_blocking(socket, false);
154        }
155        r
156    }};
157}
158
159#[macro_export]
160macro_rules! impl_expected_read_hook {
161    ( ($fn: expr) ( $socket:expr, $buffer:expr, $length:expr ), $timeout:expr) => {{
162        let socket = $socket;
163        let blocking = $crate::unix::common::is_blocking(socket);
164        if blocking {
165            $crate::unix::common::set_non_blocking(socket, true);
166        }
167        let event_loop = base_coroutine::EventLoop::next();
168        let mut received = 0;
169        let mut r = 0;
170        while received < $length {
171            unsafe {
172                let mut set: libc::sigset_t = std::mem::zeroed();
173                libc::sigaddset(&mut set, libc::SIGURG);
174                let mut oldset: libc::sigset_t = std::mem::zeroed();
175                libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
176                r = $fn(
177                    $socket,
178                    ($buffer as usize + received) as *mut libc::c_void,
179                    $length - received
180                );
181                libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
182            }
183            if r != -1 {
184                $crate::unix::common::reset_errno();
185                received += r as libc::size_t;
186                if received >= $length {
187                    r = received as libc::ssize_t;
188                    break;
189                }
190                if r == 0 {
191                    break;
192                }
193            }
194            let error_kind = std::io::Error::last_os_error().kind();
195            if error_kind == std::io::ErrorKind::WouldBlock {
196                //等待读事件
197                if let Err(e) = event_loop.wait_read_event(socket, $timeout) {
198                    match e.kind() {
199                        //maybe invoke by Monitor::signal(), just ignore this
200                        std::io::ErrorKind::Interrupted => $crate::unix::common::reset_errno(),
201                        _ => break,
202                    }
203                }
204            } else if error_kind != std::io::ErrorKind::Interrupted {
205                break;
206            }
207        }
208        if blocking {
209            $crate::unix::common::set_non_blocking(socket, false);
210        }
211        r
212    }};
213    ( ($fn: expr) ( $socket:expr, $buffer:expr, $length:expr, $($arg: expr),* $(,)* ), $timeout:expr) => {{
214        let socket = $socket;
215        let blocking = $crate::unix::common::is_blocking(socket);
216        if blocking {
217            $crate::unix::common::set_non_blocking(socket, true);
218        }
219        let event_loop = base_coroutine::EventLoop::next();
220        let mut received = 0;
221        let mut r = 0;
222        while received < $length {
223            unsafe {
224                let mut set: libc::sigset_t = std::mem::zeroed();
225                libc::sigaddset(&mut set, libc::SIGURG);
226                let mut oldset: libc::sigset_t = std::mem::zeroed();
227                libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
228                r = $fn(
229                    $socket,
230                    ($buffer as usize + received) as *mut libc::c_void,
231                    $length - received,
232                    $($arg, )*
233                );
234                libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
235            }
236            if r != -1 {
237                $crate::unix::common::reset_errno();
238                received += r as libc::size_t;
239                if received >= $length {
240                    r = received as libc::ssize_t;
241                    break;
242                }
243                if r == 0 {
244                    break;
245                }
246            }
247            let error_kind = std::io::Error::last_os_error().kind();
248            if error_kind == std::io::ErrorKind::WouldBlock {
249                //等待读事件
250                if let Err(e) = event_loop.wait_read_event(socket, $timeout) {
251                    match e.kind() {
252                        //maybe invoke by Monitor::signal(), just ignore this
253                        std::io::ErrorKind::Interrupted => $crate::unix::common::reset_errno(),
254                        _ => break,
255                    }
256                }
257            } else if error_kind != std::io::ErrorKind::Interrupted {
258                break;
259            }
260        }
261        if blocking {
262            $crate::unix::common::set_non_blocking(socket, false);
263        }
264        r
265    }};
266}
267
268//todo try to replace with impl_expected_write_hook
269#[macro_export]
270macro_rules! impl_write_hook {
271    ( ($fn: expr) ( $socket:expr, $($arg: expr),* $(,)* ), $timeout:expr ) => {{
272        let socket = $socket;
273        let blocking = $crate::unix::common::is_blocking(socket);
274        if blocking {
275            $crate::unix::common::set_non_blocking(socket, true);
276        }
277        let event_loop = base_coroutine::EventLoop::next();
278        let mut r;
279        loop {
280            unsafe {
281                let mut set: libc::sigset_t = std::mem::zeroed();
282                libc::sigaddset(&mut set, libc::SIGURG);
283                let mut oldset: libc::sigset_t = std::mem::zeroed();
284                libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
285                r = $fn($socket, $($arg, )*);
286                libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
287            }
288            if r != -1 {
289                $crate::unix::common::reset_errno();
290                break;
291            }
292            let error_kind = std::io::Error::last_os_error().kind();
293            if error_kind == std::io::ErrorKind::WouldBlock {
294                //等待写事件
295                if let Err(e) = event_loop.wait_write_event(socket, $timeout) {
296                    match e.kind() {
297                        //maybe invoke by Monitor::signal(), just ignore this
298                        std::io::ErrorKind::Interrupted => $crate::unix::common::reset_errno(),
299                        _ => break,
300                    }
301                }
302            } else if error_kind != std::io::ErrorKind::Interrupted {
303                break;
304            }
305        }
306        if blocking {
307            $crate::unix::common::set_non_blocking(socket, false);
308        }
309        r
310    }};
311}
312
313#[macro_export]
314macro_rules! impl_expected_write_hook {
315    ( ($fn: expr) ( $socket:expr, $buffer:expr, $length:expr), $timeout:expr) => {{
316        let socket = $socket;
317        let blocking = $crate::unix::common::is_blocking(socket);
318        if blocking {
319            $crate::unix::common::set_non_blocking(socket, true);
320        }
321        let event_loop = base_coroutine::EventLoop::next();
322        let mut sent = 0;
323        let mut r = 0;
324        while sent < $length {
325            unsafe {
326                let mut set: libc::sigset_t = std::mem::zeroed();
327                libc::sigaddset(&mut set, libc::SIGURG);
328                let mut oldset: libc::sigset_t = std::mem::zeroed();
329                libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
330                r = $fn(
331                    $socket,
332                    ($buffer as usize + sent) as *const libc::c_void,
333                    $length - sent
334                );
335                libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
336            }
337            if r != -1 {
338                $crate::unix::common::reset_errno();
339                sent += r as libc::size_t;
340                if sent >= $length {
341                    r = sent as libc::ssize_t;
342                    break;
343                }
344                if r == 0 {
345                    break;
346                }
347            }
348            let error_kind = std::io::Error::last_os_error().kind();
349            if error_kind == std::io::ErrorKind::WouldBlock {
350                //等待写事件
351                if let Err(e) = event_loop.wait_write_event(socket, $timeout) {
352                    match e.kind() {
353                        //maybe invoke by Monitor::signal(), just ignore this
354                        std::io::ErrorKind::Interrupted => $crate::unix::common::reset_errno(),
355                        _ => break,
356                    }
357                }
358            } else if error_kind != std::io::ErrorKind::Interrupted {
359                break;
360            }
361        }
362        if blocking {
363            $crate::unix::common::set_non_blocking(socket, false);
364        }
365        r
366    }};
367    ( ($fn: expr) ( $socket:expr, $buffer:expr, $length:expr, $($arg: expr),* $(,)* ), $timeout:expr) => {{
368        let socket = $socket;
369        let blocking = $crate::unix::common::is_blocking(socket);
370        if blocking {
371            $crate::unix::common::set_non_blocking(socket, true);
372        }
373        let event_loop = base_coroutine::EventLoop::next();
374        let mut sent = 0;
375        let mut r = 0;
376        while sent < $length {
377            unsafe {
378                let mut set: libc::sigset_t = std::mem::zeroed();
379                libc::sigaddset(&mut set, libc::SIGURG);
380                let mut oldset: libc::sigset_t = std::mem::zeroed();
381                libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
382                r = $fn(
383                    $socket,
384                    ($buffer as usize + sent) as *const libc::c_void,
385                    $length - sent,
386                    $($arg, )*
387                );
388                libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
389            }
390            if r != -1 {
391                $crate::unix::common::reset_errno();
392                sent += r as libc::size_t;
393                if sent >= $length {
394                    r = sent as libc::ssize_t;
395                    break;
396                }
397                if r == 0 {
398                    break;
399                }
400            }
401            let error_kind = std::io::Error::last_os_error().kind();
402            if error_kind == std::io::ErrorKind::WouldBlock {
403                //等待写事件
404                if let Err(e) = event_loop.wait_write_event(socket, $timeout) {
405                    match e.kind() {
406                        //maybe invoke by Monitor::signal(), just ignore this
407                        std::io::ErrorKind::Interrupted => $crate::unix::common::reset_errno(),
408                        _ => break,
409                    }
410                }
411            } else if error_kind != std::io::ErrorKind::Interrupted {
412                break;
413            }
414        }
415        if blocking {
416            $crate::unix::common::set_non_blocking(socket, false);
417        }
418        r
419    }};
420}