1b8a62b91Sopenharmony_ci//! Test a simple Unix-domain socket server and client.
2b8a62b91Sopenharmony_ci//!
3b8a62b91Sopenharmony_ci//! The client sends lists of integers and the server sends back sums.
4b8a62b91Sopenharmony_ci
5b8a62b91Sopenharmony_ci// This test uses `AF_UNIX` with `SOCK_SEQPACKET` which is unsupported on macOS.
6b8a62b91Sopenharmony_ci#![cfg(not(any(
7b8a62b91Sopenharmony_ci    target_os = "ios",
8b8a62b91Sopenharmony_ci    target_os = "macos",
9b8a62b91Sopenharmony_ci    target_os = "redox",
10b8a62b91Sopenharmony_ci    target_os = "wasi",
11b8a62b91Sopenharmony_ci)))]
12b8a62b91Sopenharmony_ci// This test uses `DecInt`.
13b8a62b91Sopenharmony_ci#![cfg(feature = "itoa")]
14b8a62b91Sopenharmony_ci#![cfg(feature = "fs")]
15b8a62b91Sopenharmony_ci
16b8a62b91Sopenharmony_ciuse rustix::fs::{cwd, unlinkat, AtFlags};
17b8a62b91Sopenharmony_ciuse rustix::io::{read, write};
18b8a62b91Sopenharmony_ciuse rustix::net::{
19b8a62b91Sopenharmony_ci    accept, bind_unix, connect_unix, listen, socket, AddressFamily, Protocol, SocketAddrUnix,
20b8a62b91Sopenharmony_ci    SocketType,
21b8a62b91Sopenharmony_ci};
22b8a62b91Sopenharmony_ciuse rustix::path::DecInt;
23b8a62b91Sopenharmony_ciuse std::path::Path;
24b8a62b91Sopenharmony_ciuse std::str::FromStr;
25b8a62b91Sopenharmony_ciuse std::sync::{Arc, Condvar, Mutex};
26b8a62b91Sopenharmony_ciuse std::thread;
27b8a62b91Sopenharmony_ci
28b8a62b91Sopenharmony_ciconst BUFFER_SIZE: usize = 20;
29b8a62b91Sopenharmony_ci
30b8a62b91Sopenharmony_cifn server(ready: Arc<(Mutex<bool>, Condvar)>, path: &Path) {
31b8a62b91Sopenharmony_ci    let connection_socket = socket(
32b8a62b91Sopenharmony_ci        AddressFamily::UNIX,
33b8a62b91Sopenharmony_ci        SocketType::SEQPACKET,
34b8a62b91Sopenharmony_ci        Protocol::default(),
35b8a62b91Sopenharmony_ci    )
36b8a62b91Sopenharmony_ci    .unwrap();
37b8a62b91Sopenharmony_ci
38b8a62b91Sopenharmony_ci    let name = SocketAddrUnix::new(path).unwrap();
39b8a62b91Sopenharmony_ci    bind_unix(&connection_socket, &name).unwrap();
40b8a62b91Sopenharmony_ci    listen(&connection_socket, 1).unwrap();
41b8a62b91Sopenharmony_ci
42b8a62b91Sopenharmony_ci    {
43b8a62b91Sopenharmony_ci        let (lock, cvar) = &*ready;
44b8a62b91Sopenharmony_ci        let mut started = lock.lock().unwrap();
45b8a62b91Sopenharmony_ci        *started = true;
46b8a62b91Sopenharmony_ci        cvar.notify_all();
47b8a62b91Sopenharmony_ci    }
48b8a62b91Sopenharmony_ci
49b8a62b91Sopenharmony_ci    let mut buffer = vec![0; BUFFER_SIZE];
50b8a62b91Sopenharmony_ci    'exit: loop {
51b8a62b91Sopenharmony_ci        let data_socket = accept(&connection_socket).unwrap();
52b8a62b91Sopenharmony_ci        let mut sum = 0;
53b8a62b91Sopenharmony_ci        loop {
54b8a62b91Sopenharmony_ci            let nread = read(&data_socket, &mut buffer).unwrap();
55b8a62b91Sopenharmony_ci
56b8a62b91Sopenharmony_ci            if &buffer[..nread] == b"exit" {
57b8a62b91Sopenharmony_ci                break 'exit;
58b8a62b91Sopenharmony_ci            }
59b8a62b91Sopenharmony_ci            if &buffer[..nread] == b"sum" {
60b8a62b91Sopenharmony_ci                break;
61b8a62b91Sopenharmony_ci            }
62b8a62b91Sopenharmony_ci
63b8a62b91Sopenharmony_ci            sum += i32::from_str(&String::from_utf8_lossy(&buffer[..nread])).unwrap();
64b8a62b91Sopenharmony_ci        }
65b8a62b91Sopenharmony_ci
66b8a62b91Sopenharmony_ci        write(&data_socket, DecInt::new(sum).as_bytes()).unwrap();
67b8a62b91Sopenharmony_ci    }
68b8a62b91Sopenharmony_ci
69b8a62b91Sopenharmony_ci    unlinkat(cwd(), path, AtFlags::empty()).unwrap();
70b8a62b91Sopenharmony_ci}
71b8a62b91Sopenharmony_ci
72b8a62b91Sopenharmony_cifn client(ready: Arc<(Mutex<bool>, Condvar)>, path: &Path, runs: &[(&[&str], i32)]) {
73b8a62b91Sopenharmony_ci    {
74b8a62b91Sopenharmony_ci        let (lock, cvar) = &*ready;
75b8a62b91Sopenharmony_ci        let mut started = lock.lock().unwrap();
76b8a62b91Sopenharmony_ci        while !*started {
77b8a62b91Sopenharmony_ci            started = cvar.wait(started).unwrap();
78b8a62b91Sopenharmony_ci        }
79b8a62b91Sopenharmony_ci    }
80b8a62b91Sopenharmony_ci
81b8a62b91Sopenharmony_ci    let addr = SocketAddrUnix::new(path).unwrap();
82b8a62b91Sopenharmony_ci    let mut buffer = vec![0; BUFFER_SIZE];
83b8a62b91Sopenharmony_ci
84b8a62b91Sopenharmony_ci    for (args, sum) in runs {
85b8a62b91Sopenharmony_ci        let data_socket = socket(
86b8a62b91Sopenharmony_ci            AddressFamily::UNIX,
87b8a62b91Sopenharmony_ci            SocketType::SEQPACKET,
88b8a62b91Sopenharmony_ci            Protocol::default(),
89b8a62b91Sopenharmony_ci        )
90b8a62b91Sopenharmony_ci        .unwrap();
91b8a62b91Sopenharmony_ci        connect_unix(&data_socket, &addr).unwrap();
92b8a62b91Sopenharmony_ci
93b8a62b91Sopenharmony_ci        for arg in *args {
94b8a62b91Sopenharmony_ci            write(&data_socket, arg.as_bytes()).unwrap();
95b8a62b91Sopenharmony_ci        }
96b8a62b91Sopenharmony_ci        write(&data_socket, b"sum").unwrap();
97b8a62b91Sopenharmony_ci
98b8a62b91Sopenharmony_ci        let nread = read(&data_socket, &mut buffer).unwrap();
99b8a62b91Sopenharmony_ci        assert_eq!(
100b8a62b91Sopenharmony_ci            i32::from_str(&String::from_utf8_lossy(&buffer[..nread])).unwrap(),
101b8a62b91Sopenharmony_ci            *sum
102b8a62b91Sopenharmony_ci        );
103b8a62b91Sopenharmony_ci    }
104b8a62b91Sopenharmony_ci
105b8a62b91Sopenharmony_ci    let data_socket = socket(
106b8a62b91Sopenharmony_ci        AddressFamily::UNIX,
107b8a62b91Sopenharmony_ci        SocketType::SEQPACKET,
108b8a62b91Sopenharmony_ci        Protocol::default(),
109b8a62b91Sopenharmony_ci    )
110b8a62b91Sopenharmony_ci    .unwrap();
111b8a62b91Sopenharmony_ci    connect_unix(&data_socket, &addr).unwrap();
112b8a62b91Sopenharmony_ci    write(&data_socket, b"exit").unwrap();
113b8a62b91Sopenharmony_ci}
114b8a62b91Sopenharmony_ci
115b8a62b91Sopenharmony_ci#[test]
116b8a62b91Sopenharmony_cifn test_unix() {
117b8a62b91Sopenharmony_ci    let ready = Arc::new((Mutex::new(false), Condvar::new()));
118b8a62b91Sopenharmony_ci    let ready_clone = Arc::clone(&ready);
119b8a62b91Sopenharmony_ci
120b8a62b91Sopenharmony_ci    let tmp = tempfile::tempdir().unwrap();
121b8a62b91Sopenharmony_ci    let path = tmp.path().join("soccer");
122b8a62b91Sopenharmony_ci    let send_path = path.to_owned();
123b8a62b91Sopenharmony_ci    let server = thread::Builder::new()
124b8a62b91Sopenharmony_ci        .name("server".to_string())
125b8a62b91Sopenharmony_ci        .spawn(move || {
126b8a62b91Sopenharmony_ci            server(ready, &send_path);
127b8a62b91Sopenharmony_ci        })
128b8a62b91Sopenharmony_ci        .unwrap();
129b8a62b91Sopenharmony_ci    let send_path = path.to_owned();
130b8a62b91Sopenharmony_ci    let client = thread::Builder::new()
131b8a62b91Sopenharmony_ci        .name("client".to_string())
132b8a62b91Sopenharmony_ci        .spawn(move || {
133b8a62b91Sopenharmony_ci            client(
134b8a62b91Sopenharmony_ci                ready_clone,
135b8a62b91Sopenharmony_ci                &send_path,
136b8a62b91Sopenharmony_ci                &[
137b8a62b91Sopenharmony_ci                    (&["1", "2"], 3),
138b8a62b91Sopenharmony_ci                    (&["4", "77", "103"], 184),
139b8a62b91Sopenharmony_ci                    (&["5", "78", "104"], 187),
140b8a62b91Sopenharmony_ci                    (&[], 0),
141b8a62b91Sopenharmony_ci                ],
142b8a62b91Sopenharmony_ci            );
143b8a62b91Sopenharmony_ci        })
144b8a62b91Sopenharmony_ci        .unwrap();
145b8a62b91Sopenharmony_ci    client.join().unwrap();
146b8a62b91Sopenharmony_ci    server.join().unwrap();
147b8a62b91Sopenharmony_ci}
148