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