Mercurial > crates > systemd-socket
view tests/comm.rs @ 25:8e20daee41ed
Set CLOEXEC flag on the descriptors
The received systemd descriptors don't have `O_CLOEXEC` set because they
are received over `exec`. Thus if the process executes a child the child
gets polluted with the descriptors.
To prevent this, we set `O_CLOEXEC` during initialization. However this
also required restructuring of the code because `libsystemd` doesn't
provide temporary access to the descriptors - only permanent one. Thus
we have to "validate" the descriptors eagerly. We still store the
invalid ones as errors to make sure the errors get reported accurately.
author | Martin Habovstiak <martin.habovstiak@gmail.com> |
---|---|
date | Fri, 28 Feb 2025 21:11:19 +0100 |
parents | 1941e9d9819c |
children | cfef4593e207 |
line wrap: on
line source
use std::process::Child; use std::ffi::OsStr; use std::io::{self, Read, Write}; pub trait Test { const SOCKET_ADDR: &'static str; fn spawn_slave(program_name: &OsStr) -> io::Result<Child>; } const REQUEST: &[u8] = b"orange coin"; const RESPONSE: &[u8] = b"good"; fn main_master(slave: io::Result<Child>) { let mut slave = slave.expect("failed to run a child"); // give slave some time to bind the socket just to be sure std::thread::sleep(std::time::Duration::from_secs(5)); if let Some(exited) = slave.try_wait().expect("failed to check if the child exited") { panic!("child exited unexpectedly: {}", exited); } let mut client_socket = std::net::TcpStream::connect("localhost:4242").expect("Failed to connect to 127.0.0.1:4242"); client_socket.write_all(REQUEST).expect("failed to send data"); let mut buf = [0u8; RESPONSE.len()]; client_socket.read_exact(&mut buf).expect("failed to read response"); assert_eq!(buf, RESPONSE); let status = slave.wait().expect("faild to wait for slave"); if !status.success() { panic!("slave did not exit with succcess, status: {}", status); } } fn main_slave(addr: &str) { use systemd_socket::SocketAddr; // SAFETY: this is the only thread that's going to mess with systemd sockets. unsafe { systemd_socket::init_unprotected().unwrap(); } let socket = addr .parse::<SocketAddr>() .expect("failed to parse socket") .bind() .expect("failed to bind"); let (mut client_socket, _) = socket.accept().expect("failed to accept"); let mut buf = [0u8; REQUEST.len()]; client_socket.read_exact(&mut buf).expect("failed to read response"); assert_eq!(buf, REQUEST); client_socket.write_all(RESPONSE).expect("failed to send data"); } pub fn main<T: Test>() { let mut args = std::env::args_os(); let program_name = args.next().expect("missing program name"); match std::env::var_os("SYSTEMD_SOCKET_INTEGRATION_TEST") { None => main_master(T::spawn_slave(&program_name)), Some(arg) if arg == "slave" => main_slave(T::SOCKET_ADDR), Some(arg) => panic!("Unknown argument '{:?}'", arg), } }