1b8a62b91Sopenharmony_ci#![cfg(any(target_os = "android", target_os = "linux"))]
2b8a62b91Sopenharmony_ci
3b8a62b91Sopenharmony_ciuse rustix::fd::{AsFd, OwnedFd};
4b8a62b91Sopenharmony_ciuse rustix::io::epoll::{self, Epoll};
5b8a62b91Sopenharmony_ciuse rustix::io::{ioctl_fionbio, read, write};
6b8a62b91Sopenharmony_ciuse rustix::net::{
7b8a62b91Sopenharmony_ci    accept, bind_v4, connect_v4, getsockname, listen, socket, AddressFamily, Ipv4Addr, Protocol,
8b8a62b91Sopenharmony_ci    SocketAddrAny, SocketAddrV4, SocketType,
9b8a62b91Sopenharmony_ci};
10b8a62b91Sopenharmony_ciuse std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
11b8a62b91Sopenharmony_ciuse std::sync::{Arc, Condvar, Mutex};
12b8a62b91Sopenharmony_ciuse std::thread;
13b8a62b91Sopenharmony_ci
14b8a62b91Sopenharmony_ciconst BUFFER_SIZE: usize = 20;
15b8a62b91Sopenharmony_ci
16b8a62b91Sopenharmony_cifn server(ready: Arc<(Mutex<u16>, Condvar)>) {
17b8a62b91Sopenharmony_ci    let listen_sock = socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap();
18b8a62b91Sopenharmony_ci    bind_v4(&listen_sock, &SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0)).unwrap();
19b8a62b91Sopenharmony_ci    listen(&listen_sock, 1).unwrap();
20b8a62b91Sopenharmony_ci
21b8a62b91Sopenharmony_ci    let who = match getsockname(&listen_sock).unwrap() {
22b8a62b91Sopenharmony_ci        SocketAddrAny::V4(addr) => addr,
23b8a62b91Sopenharmony_ci        _ => panic!(),
24b8a62b91Sopenharmony_ci    };
25b8a62b91Sopenharmony_ci
26b8a62b91Sopenharmony_ci    {
27b8a62b91Sopenharmony_ci        let (lock, cvar) = &*ready;
28b8a62b91Sopenharmony_ci        let mut port = lock.lock().unwrap();
29b8a62b91Sopenharmony_ci        *port = who.port();
30b8a62b91Sopenharmony_ci        cvar.notify_all();
31b8a62b91Sopenharmony_ci    }
32b8a62b91Sopenharmony_ci
33b8a62b91Sopenharmony_ci    let epoll = Epoll::new(epoll::CreateFlags::CLOEXEC, epoll::Owning::<OwnedFd>::new()).unwrap();
34b8a62b91Sopenharmony_ci
35b8a62b91Sopenharmony_ci    // Test into conversions.
36b8a62b91Sopenharmony_ci    let fd: OwnedFd = epoll.into();
37b8a62b91Sopenharmony_ci    let epoll: Epoll<epoll::Owning<OwnedFd>> = fd.into();
38b8a62b91Sopenharmony_ci    let fd: RawFd = epoll.into_raw_fd();
39b8a62b91Sopenharmony_ci    let epoll = unsafe { Epoll::<epoll::Owning<OwnedFd>>::from_raw_fd(fd) };
40b8a62b91Sopenharmony_ci
41b8a62b91Sopenharmony_ci    let raw_listen_sock = listen_sock.as_fd().as_raw_fd();
42b8a62b91Sopenharmony_ci    epoll.add(listen_sock, epoll::EventFlags::IN).unwrap();
43b8a62b91Sopenharmony_ci
44b8a62b91Sopenharmony_ci    let mut event_list = epoll::EventVec::with_capacity(4);
45b8a62b91Sopenharmony_ci    loop {
46b8a62b91Sopenharmony_ci        epoll.wait(&mut event_list, -1).unwrap();
47b8a62b91Sopenharmony_ci        for (_event_flags, target) in &event_list {
48b8a62b91Sopenharmony_ci            if target.as_raw_fd() == raw_listen_sock {
49b8a62b91Sopenharmony_ci                let conn_sock = accept(&*target).unwrap();
50b8a62b91Sopenharmony_ci                ioctl_fionbio(&conn_sock, true).unwrap();
51b8a62b91Sopenharmony_ci                epoll
52b8a62b91Sopenharmony_ci                    .add(conn_sock, epoll::EventFlags::OUT | epoll::EventFlags::ET)
53b8a62b91Sopenharmony_ci                    .unwrap();
54b8a62b91Sopenharmony_ci            } else {
55b8a62b91Sopenharmony_ci                write(&*target, b"hello\n").unwrap();
56b8a62b91Sopenharmony_ci                let _ = epoll.del(target).unwrap();
57b8a62b91Sopenharmony_ci            }
58b8a62b91Sopenharmony_ci        }
59b8a62b91Sopenharmony_ci    }
60b8a62b91Sopenharmony_ci}
61b8a62b91Sopenharmony_ci
62b8a62b91Sopenharmony_cifn client(ready: Arc<(Mutex<u16>, Condvar)>) {
63b8a62b91Sopenharmony_ci    let port = {
64b8a62b91Sopenharmony_ci        let (lock, cvar) = &*ready;
65b8a62b91Sopenharmony_ci        let mut port = lock.lock().unwrap();
66b8a62b91Sopenharmony_ci        while *port == 0 {
67b8a62b91Sopenharmony_ci            port = cvar.wait(port).unwrap();
68b8a62b91Sopenharmony_ci        }
69b8a62b91Sopenharmony_ci        *port
70b8a62b91Sopenharmony_ci    };
71b8a62b91Sopenharmony_ci
72b8a62b91Sopenharmony_ci    let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port);
73b8a62b91Sopenharmony_ci    let mut buffer = vec![0; BUFFER_SIZE];
74b8a62b91Sopenharmony_ci
75b8a62b91Sopenharmony_ci    for _ in 0..16 {
76b8a62b91Sopenharmony_ci        let data_socket =
77b8a62b91Sopenharmony_ci            socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap();
78b8a62b91Sopenharmony_ci        connect_v4(&data_socket, &addr).unwrap();
79b8a62b91Sopenharmony_ci
80b8a62b91Sopenharmony_ci        let nread = read(&data_socket, &mut buffer).unwrap();
81b8a62b91Sopenharmony_ci        assert_eq!(String::from_utf8_lossy(&buffer[..nread]), "hello\n");
82b8a62b91Sopenharmony_ci    }
83b8a62b91Sopenharmony_ci}
84b8a62b91Sopenharmony_ci
85b8a62b91Sopenharmony_ci#[test]
86b8a62b91Sopenharmony_cifn test_epoll() {
87b8a62b91Sopenharmony_ci    let ready = Arc::new((Mutex::new(0_u16), Condvar::new()));
88b8a62b91Sopenharmony_ci    let ready_clone = Arc::clone(&ready);
89b8a62b91Sopenharmony_ci
90b8a62b91Sopenharmony_ci    let _server = thread::Builder::new()
91b8a62b91Sopenharmony_ci        .name("server".to_string())
92b8a62b91Sopenharmony_ci        .spawn(move || {
93b8a62b91Sopenharmony_ci            server(ready);
94b8a62b91Sopenharmony_ci        })
95b8a62b91Sopenharmony_ci        .unwrap();
96b8a62b91Sopenharmony_ci    let client = thread::Builder::new()
97b8a62b91Sopenharmony_ci        .name("client".to_string())
98b8a62b91Sopenharmony_ci        .spawn(move || {
99b8a62b91Sopenharmony_ci            client(ready_clone);
100b8a62b91Sopenharmony_ci        })
101b8a62b91Sopenharmony_ci        .unwrap();
102b8a62b91Sopenharmony_ci    client.join().unwrap();
103b8a62b91Sopenharmony_ci}
104