1use crate::unix::common::*;
6use once_cell::sync::Lazy;
7use std::ffi::c_void;
8
9#[macro_use]
10mod common;
11
12#[cfg(any(
13 target_os = "macos",
14 target_os = "ios",
15 target_os = "tvos",
16 target_os = "watchos",
17 target_os = "freebsd",
18 target_os = "dragonfly",
19 target_os = "openbsd",
20 target_os = "netbsd"
21))]
22mod bsd;
23
24#[cfg(any(
25 target_os = "linux",
26 target_os = "l4re",
27 target_os = "android",
28 target_os = "emscripten"
29))]
30mod linux_like;
31
32#[no_mangle]
34pub extern "C" fn sleep(secs: libc::c_uint) -> libc::c_uint {
35 let rqtp = libc::timespec {
36 tv_sec: secs as i64,
37 tv_nsec: 0,
38 };
39 let mut rmtp = libc::timespec {
40 tv_sec: 0,
41 tv_nsec: 0,
42 };
43 nanosleep(&rqtp, &mut rmtp);
44 rmtp.tv_sec as u32
45}
46
47#[no_mangle]
48pub extern "C" fn usleep(secs: libc::c_uint) -> libc::c_int {
49 let secs = secs as i64;
50 let sec = secs / 1_000_000;
51 let nsec = (secs % 1_000_000) * 1000;
52 let rqtp = libc::timespec {
53 tv_sec: sec,
54 tv_nsec: nsec,
55 };
56 let mut rmtp = libc::timespec {
57 tv_sec: 0,
58 tv_nsec: 0,
59 };
60 nanosleep(&rqtp, &mut rmtp)
61}
62
63static NANOSLEEP: Lazy<extern "C" fn(*const libc::timespec, *mut libc::timespec) -> libc::c_int> =
64 init_hook!("nanosleep");
65
66#[no_mangle]
67pub extern "C" fn nanosleep(rqtp: *const libc::timespec, rmtp: *mut libc::timespec) -> libc::c_int {
68 let mut rqtp = unsafe { *rqtp };
70 if rqtp.tv_sec < 0 || rqtp.tv_nsec < 0 {
71 return -1;
72 }
73 let nanos_time = match (rqtp.tv_sec as u64).checked_mul(1_000_000_000) {
74 Some(v) => v.checked_add(rqtp.tv_nsec as u64).unwrap_or(u64::MAX),
75 None => u64::MAX,
76 };
77 let timeout_time = timer_utils::add_timeout_time(nanos_time);
78 loop {
79 let _ = base_coroutine::EventLoop::round_robin_timeout_schedule(timeout_time);
80 let schedule_finished_time = timer_utils::now();
82 let left_time = match timeout_time.checked_sub(schedule_finished_time) {
83 Some(v) => v,
84 None => {
85 if !rmtp.is_null() {
86 unsafe {
87 (*rmtp).tv_sec = 0;
88 (*rmtp).tv_nsec = 0;
89 }
90 }
91 return 0;
92 }
93 } as i64;
94 let sec = left_time / 1_000_000_000;
95 let nsec = left_time % 1_000_000_000;
96 rqtp = libc::timespec {
97 tv_sec: sec,
98 tv_nsec: nsec,
99 };
100 if (Lazy::force(&NANOSLEEP))(&rqtp, rmtp) == 0 {
103 reset_errno();
104 return 0;
105 }
106 }
107}
108
109static CONNECT: Lazy<
111 extern "C" fn(libc::c_int, *const libc::sockaddr, libc::socklen_t) -> libc::c_int,
112> = init_hook!("connect");
113
114#[no_mangle]
115pub extern "C" fn connect(
116 socket: libc::c_int,
117 address: *const libc::sockaddr,
118 len: libc::socklen_t,
119) -> libc::c_int {
120 let blocking = is_blocking(socket);
121 if blocking {
123 set_non_blocking(socket, true);
124 }
125 let event_loop = base_coroutine::EventLoop::next();
126 let mut r;
127 loop {
128 r = (Lazy::force(&CONNECT))(socket, address, len);
129 if r == 0 {
130 reset_errno();
131 break;
132 }
133 let errno = std::io::Error::last_os_error().raw_os_error();
134 if errno == Some(libc::EINPROGRESS) {
135 if let Err(e) =
137 event_loop.wait_write_event(socket, Some(std::time::Duration::from_secs(1)))
138 {
139 match e.kind() {
140 std::io::ErrorKind::Interrupted => reset_errno(),
142 _ => {
143 r = -1;
144 break;
145 }
146 }
147 }
148 unsafe {
149 let mut len: libc::socklen_t = std::mem::zeroed();
150 let mut err: libc::c_int = 0;
151 r = libc::getsockopt(
152 socket,
153 libc::SOL_SOCKET,
154 libc::SO_ERROR,
155 &mut err as *mut _ as *mut c_void,
156 &mut len,
157 );
158 if r != 0 {
159 break;
160 }
161 if err == 0 {
162 reset_errno();
163 r = 0;
164 break;
165 };
166 set_errno(err);
167 }
168 r = -1;
169 break;
170 } else if errno != Some(libc::EINTR) {
171 r = -1;
172 break;
173 }
174 }
175 if blocking {
176 set_non_blocking(socket, false);
177 }
178 r
179}
180
181static LISTEN: Lazy<extern "C" fn(libc::c_int, libc::c_int) -> libc::c_int> = init_hook!("listen");
182
183#[no_mangle]
184pub extern "C" fn listen(socket: libc::c_int, backlog: libc::c_int) -> libc::c_int {
185 let _ = base_coroutine::EventLoop::round_robin_schedule();
186 (Lazy::force(&LISTEN))(socket, backlog)
188}
189
190static ACCEPT: Lazy<
191 extern "C" fn(libc::c_int, *mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
192> = init_hook!("accept");
193
194#[no_mangle]
195pub extern "C" fn accept(
196 socket: libc::c_int,
197 address: *mut libc::sockaddr,
198 address_len: *mut libc::socklen_t,
199) -> libc::c_int {
200 impl_read_hook!(
201 (Lazy::force(&ACCEPT))(socket, address, address_len),
202 Some(std::time::Duration::from_secs(1))
203 )
204}
205
206static SHUTDOWN: Lazy<extern "C" fn(libc::c_int, libc::c_int) -> libc::c_int> =
207 init_hook!("shutdown");
208
209#[no_mangle]
210pub extern "C" fn shutdown(socket: libc::c_int, how: libc::c_int) -> libc::c_int {
211 let _ = base_coroutine::EventLoop::round_robin_schedule();
212 match how {
214 libc::SHUT_RD => base_coroutine::EventLoop::round_robin_del_read_event(socket),
215 libc::SHUT_WR => base_coroutine::EventLoop::round_robin_del_write_event(socket),
216 libc::SHUT_RDWR => base_coroutine::EventLoop::round_robin_del_event(socket),
217 _ => {
218 crate::unix::common::set_errno(libc::EINVAL);
219 return -1;
220 }
221 }
222 (Lazy::force(&SHUTDOWN))(socket, how)
223}
224
225static POLL: Lazy<extern "C" fn(*mut libc::pollfd, libc::nfds_t, libc::c_int) -> libc::c_int> =
226 init_hook!("poll");
227
228#[no_mangle]
229pub extern "C" fn poll(
230 fds: *mut libc::pollfd,
231 nfds: libc::nfds_t,
232 timeout: libc::c_int,
233) -> libc::c_int {
234 let mut t = if timeout < 0 {
235 libc::c_int::MAX
236 } else {
237 timeout
238 };
239 let mut x = 1;
240 let mut r;
241 loop {
243 unsafe {
244 let mut set: libc::sigset_t = std::mem::zeroed();
245 libc::sigaddset(&mut set, libc::SIGURG);
246 let mut oldset: libc::sigset_t = std::mem::zeroed();
247 libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
248 r = (Lazy::force(&POLL))(fds, nfds, 0);
249 libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
250 }
251 if r != 0 || t == 0 {
252 break;
253 }
254 usleep((t.min(x) * 1000) as libc::c_uint);
255 if t != libc::c_int::MAX {
256 t = if t > x { t - x } else { 0 };
257 }
258 if x < 16 {
259 x <<= 1;
260 }
261 }
262 r
263}
264
265static SELECT: Lazy<
266 extern "C" fn(
267 libc::c_int,
268 *mut libc::fd_set,
269 *mut libc::fd_set,
270 *mut libc::fd_set,
271 *mut libc::timeval,
272 ) -> libc::c_int,
273> = init_hook!("select");
274
275#[no_mangle]
276pub extern "C" fn select(
277 nfds: libc::c_int,
278 readfds: *mut libc::fd_set,
279 writefds: *mut libc::fd_set,
280 errorfds: *mut libc::fd_set,
281 timeout: *mut libc::timeval,
282) -> libc::c_int {
283 let mut t = if timeout.is_null() {
284 libc::c_uint::MAX
285 } else {
286 unsafe {
287 ((*timeout).tv_sec as libc::c_uint) * 1_000_000 + (*timeout).tv_usec as libc::c_uint
288 }
289 };
290 let mut o = libc::timeval {
291 tv_sec: 0,
292 tv_usec: 0,
293 };
294 let mut s: [libc::fd_set; 3] = unsafe { std::mem::zeroed() };
295 unsafe {
296 if !readfds.is_null() {
297 s[0] = *readfds;
298 }
299 if !writefds.is_null() {
300 s[1] = *writefds;
301 }
302 if !errorfds.is_null() {
303 s[2] = *errorfds;
304 }
305 }
306 let mut x = 1;
307 let mut r;
308 loop {
310 unsafe {
311 let mut set: libc::sigset_t = std::mem::zeroed();
312 libc::sigaddset(&mut set, libc::SIGURG);
313 let mut oldset: libc::sigset_t = std::mem::zeroed();
314 libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut oldset);
315 r = (Lazy::force(&SELECT))(nfds, readfds, writefds, errorfds, &mut o);
316 libc::pthread_sigmask(libc::SIG_SETMASK, &oldset, std::ptr::null_mut());
317 }
318 if r != 0 || t == 0 {
319 break;
320 }
321 usleep(t.min(x) * 1000);
322 if t != libc::c_uint::MAX {
323 t = if t > x { t - x } else { 0 };
324 }
325 if x < 16 {
326 x <<= 1;
327 }
328 unsafe {
329 if !readfds.is_null() {
330 *readfds = s[0];
331 }
332 if !writefds.is_null() {
333 *writefds = s[1];
334 }
335 if !errorfds.is_null() {
336 *errorfds = s[2];
337 }
338 }
339 o.tv_sec = 0;
340 o.tv_usec = 0;
341 }
342 r
343}
344
345static SEND: Lazy<
347 extern "C" fn(libc::c_int, *const libc::c_void, libc::size_t, libc::c_int) -> libc::ssize_t,
348> = init_hook!("send");
349
350#[no_mangle]
351pub extern "C" fn send(
352 socket: libc::c_int,
353 buf: *const libc::c_void,
354 len: libc::size_t,
355 flags: libc::c_int,
356) -> libc::ssize_t {
357 impl_expected_write_hook!(
358 (Lazy::force(&SEND))(socket, buf, len, flags),
359 Some(std::time::Duration::from_secs(1))
360 )
361}
362
363static WRITE: Lazy<extern "C" fn(libc::c_int, *const libc::c_void, libc::size_t) -> libc::ssize_t> =
364 init_hook!("write");
365
366#[no_mangle]
367pub extern "C" fn write(
368 fd: libc::c_int,
369 buf: *const libc::c_void,
370 count: libc::size_t,
371) -> libc::ssize_t {
372 impl_expected_write_hook!(
373 (Lazy::force(&WRITE))(fd, buf, count),
374 Some(std::time::Duration::from_secs(1))
375 )
376}
377
378static WRITEV: Lazy<extern "C" fn(libc::c_int, *const libc::iovec, libc::c_int) -> libc::ssize_t> =
379 init_hook!("writev");
380
381#[no_mangle]
382pub extern "C" fn writev(
383 fd: libc::c_int,
384 iov: *const libc::iovec,
385 iovcnt: libc::c_int,
386) -> libc::ssize_t {
387 impl_write_hook!(
388 (Lazy::force(&WRITEV))(fd, iov, iovcnt),
389 Some(std::time::Duration::from_secs(1))
390 )
391}
392
393static SENDTO: Lazy<
394 extern "C" fn(
395 libc::c_int,
396 *const libc::c_void,
397 libc::size_t,
398 libc::c_int,
399 *const libc::sockaddr,
400 libc::socklen_t,
401 ) -> libc::ssize_t,
402> = init_hook!("sendto");
403
404#[no_mangle]
405pub extern "C" fn sendto(
406 socket: libc::c_int,
407 buf: *const libc::c_void,
408 len: libc::size_t,
409 flags: libc::c_int,
410 addr: *const libc::sockaddr,
411 addrlen: libc::socklen_t,
412) -> libc::ssize_t {
413 impl_expected_write_hook!(
414 (Lazy::force(&SENDTO))(socket, buf, len, flags, addr, addrlen),
415 Some(std::time::Duration::from_secs(1))
416 )
417}
418
419static SENDMSG: Lazy<
420 extern "C" fn(libc::c_int, *const libc::msghdr, libc::c_int) -> libc::ssize_t,
421> = init_hook!("sendmsg");
422
423#[no_mangle]
424pub extern "C" fn sendmsg(
425 fd: libc::c_int,
426 msg: *const libc::msghdr,
427 flags: libc::c_int,
428) -> libc::ssize_t {
429 impl_write_hook!(
430 (Lazy::force(&SENDMSG))(fd, msg, flags),
431 Some(std::time::Duration::from_secs(1))
432 )
433}
434
435static PWRITE: Lazy<
436 extern "C" fn(libc::c_int, *const libc::c_void, libc::size_t, libc::off_t) -> libc::ssize_t,
437> = init_hook!("pwrite");
438
439#[no_mangle]
440pub extern "C" fn pwrite(
441 fd: libc::c_int,
442 buf: *const libc::c_void,
443 count: libc::size_t,
444 offset: libc::off_t,
445) -> libc::ssize_t {
446 impl_expected_write_hook!(
447 (Lazy::force(&PWRITE))(fd, buf, count, offset),
448 Some(std::time::Duration::from_secs(1))
449 )
450}
451
452static PWRITEV: Lazy<
453 extern "C" fn(libc::c_int, *const libc::iovec, libc::c_int, libc::off_t) -> libc::ssize_t,
454> = init_hook!("pwritev");
455
456#[no_mangle]
457pub extern "C" fn pwritev(
458 fd: libc::c_int,
459 iov: *const libc::iovec,
460 iovcnt: libc::c_int,
461 offset: libc::off_t,
462) -> libc::ssize_t {
463 impl_write_hook!(
464 (Lazy::force(&PWRITEV))(fd, iov, iovcnt, offset),
465 Some(std::time::Duration::from_secs(1))
466 )
467}
468
469static RECV: Lazy<
471 extern "C" fn(libc::c_int, *mut libc::c_void, libc::size_t, libc::c_int) -> libc::ssize_t,
472> = init_hook!("recv");
473
474#[no_mangle]
475pub extern "C" fn recv(
476 socket: libc::c_int,
477 buf: *mut libc::c_void,
478 len: libc::size_t,
479 flags: libc::c_int,
480) -> libc::ssize_t {
481 impl_expected_read_hook!(
482 (Lazy::force(&RECV))(socket, buf, len, flags),
483 Some(std::time::Duration::from_secs(1))
484 )
485}
486
487static READV: Lazy<extern "C" fn(libc::c_int, *const libc::iovec, libc::c_int) -> libc::ssize_t> =
488 init_hook!("readv");
489
490#[no_mangle]
491pub extern "C" fn readv(
492 fd: libc::c_int,
493 iov: *const libc::iovec,
494 iovcnt: libc::c_int,
495) -> libc::ssize_t {
496 impl_read_hook!(
497 (Lazy::force(&READV))(fd, iov, iovcnt),
498 Some(std::time::Duration::from_secs(1))
499 )
500}
501
502static PREAD: Lazy<
503 extern "C" fn(libc::c_int, *mut libc::c_void, libc::size_t, libc::off_t) -> libc::ssize_t,
504> = init_hook!("pread");
505
506#[no_mangle]
507pub extern "C" fn pread(
508 fd: libc::c_int,
509 buf: *mut libc::c_void,
510 count: libc::size_t,
511 offset: libc::off_t,
512) -> libc::ssize_t {
513 impl_expected_read_hook!(
514 (Lazy::force(&PREAD))(fd, buf, count, offset),
515 Some(std::time::Duration::from_secs(1))
516 )
517}
518
519static PREADV: Lazy<
520 extern "C" fn(libc::c_int, *const libc::iovec, libc::c_int, libc::off_t) -> libc::ssize_t,
521> = init_hook!("preadv");
522
523#[no_mangle]
524pub extern "C" fn preadv(
525 fd: libc::c_int,
526 iov: *const libc::iovec,
527 iovcnt: libc::c_int,
528 offset: libc::off_t,
529) -> libc::ssize_t {
530 impl_read_hook!(
531 (Lazy::force(&PREADV))(fd, iov, iovcnt, offset),
532 Some(std::time::Duration::from_secs(1))
533 )
534}
535
536static RECVFROM: Lazy<
537 extern "C" fn(
538 libc::c_int,
539 *mut libc::c_void,
540 libc::size_t,
541 libc::c_int,
542 *mut libc::sockaddr,
543 *mut libc::socklen_t,
544 ) -> libc::ssize_t,
545> = init_hook!("recvfrom");
546
547#[no_mangle]
548pub extern "C" fn recvfrom(
549 socket: libc::c_int,
550 buf: *mut libc::c_void,
551 len: libc::size_t,
552 flags: libc::c_int,
553 addr: *mut libc::sockaddr,
554 addrlen: *mut libc::socklen_t,
555) -> libc::ssize_t {
556 impl_expected_read_hook!(
557 (Lazy::force(&RECVFROM))(socket, buf, len, flags, addr, addrlen),
558 Some(std::time::Duration::from_secs(1))
559 )
560}
561
562static RECVMSG: Lazy<extern "C" fn(libc::c_int, *mut libc::msghdr, libc::c_int) -> libc::ssize_t> =
563 init_hook!("recvmsg");
564
565#[no_mangle]
566pub extern "C" fn recvmsg(
567 fd: libc::c_int,
568 msg: *mut libc::msghdr,
569 flags: libc::c_int,
570) -> libc::ssize_t {
571 impl_read_hook!(
572 (Lazy::force(&RECVMSG))(fd, msg, flags),
573 Some(std::time::Duration::from_secs(1))
574 )
575}