Expand description
A convenience crate for optionally supporting systemd socket activation.
§About
Important: because of various reasons it is recommended to call the init
function at
the start of your program!
The goal of this crate is to make socket activation with systemd in your project trivial.
It provides a replacement for std::net::SocketAddr
that allows parsing the bind address from string just like the one from std
but on top of that also allows systemd://socket_name
format that tells it to use systemd activation with given socket name.
Then it provides a method to bind the address which will return the socket from systemd if available.
The provided type supports conversions from various types of strings and also serde
and parse_arg
via feature flag.
Thanks to this the change to your code should be minimal - parsing will continue to work, it’ll just allow a new format.
You only need to change the code to use SocketAddr::bind()
instead of TcpListener::bind()
for binding.
You also don’t need to worry about conditional compilation to ensure OS compatibility. This crate handles that for you by disabling systemd on non-linux systems.
Further, the crate also provides methods for binding tokio
1.0, 0.2, 0.3, and async_std
sockets if the appropriate features are
activated.
§Example
use systemd_socket::SocketAddr;
use std::convert::TryFrom;
use std::io::Write;
systemd_socket::init().expect("Failed to initialize systemd sockets");
let mut args = std::env::args_os();
let program_name = args.next().expect("unknown program name");
let socket_addr = args.next().expect("missing socket address");
let socket_addr = SocketAddr::try_from(socket_addr).expect("failed to parse socket address");
let socket = socket_addr.bind().expect("failed to bind socket");
loop {
let _ = socket
.accept()
.expect("failed to accept connection")
.0
.write_all(b"Hello world!")
.map_err(|err| eprintln!("Failed to send {}", err));
}
§Features
enable_systemd
- on by default, the existence of this feature can allow your users to turn off systemd support if they don’t need it. Note that it’s already disabled on non-linux systems, so you don’t need to care about that.serde
- implementsserde::Deserialize
forSocketAddr
parse_arg
- implementsparse_arg::ParseArg
forSocketAddr
tokio
- addsbind_tokio
method toSocketAddr
(tokio 1.0)tokio_0_2
- addsbind_tokio_0_2
method toSocketAddr
tokio_0_3
- addsbind_tokio_0_3
method toSocketAddr
async_std
- addsbind_async_std
method toSocketAddr
§Soundness
The systemd file descriptors are transferred using environment variables and since they are file descriptors, they should have move semantics. However environment variables in Rust do not have move semantics and even modifying them is very dangerous.
Because of this, the crate only allows initialization when there’s only one thread running. However that still doesn’t prevent all possible problems: if some other code closes file descriptors stored in those environment variables you can get an invalid socket.
This situation is obviously ridiculous because there shouldn’t be a reason to use another library to do the same thing. It could also be argued that whichever code doesn’t clear the evironment variable is broken (even though understandably) and it’s not a fault of this library.
§MSRV
This crate must always compile with the latest Rust available in the latest Debian stable. That is currently Rust 1.48.0. (Debian 11 - Bullseye)
Modules§
- error
- Error types that can occur when dealing with
SocketAddr
Structs§
- Socket
Addr - Socket address that can be an ordinary address or a systemd socket
Functions§
- init
- Initializes the library while there’s only a single thread.
- init_
unprotected ⚠ - Initializes the library without protection against double close.