• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 use rustix::fs::{cwd, unlinkat, AtFlags};
17 use rustix::io::{read, write};
18 use rustix::net::{
19     accept, bind_unix, connect_unix, listen, socket, AddressFamily, Protocol, SocketAddrUnix,
20     SocketType,
21 };
22 use rustix::path::DecInt;
23 use std::path::Path;
24 use std::str::FromStr;
25 use std::sync::{Arc, Condvar, Mutex};
26 use std::thread;
27 
28 const BUFFER_SIZE: usize = 20;
29 
server(ready: Arc<(Mutex<bool>, Condvar)>, path: &Path)30 fn 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 
client(ready: Arc<(Mutex<bool>, Condvar)>, path: &Path, runs: &[(&[&str], i32)])72 fn 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]
test_unix()116 fn 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