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