Compare commits

...

6 commits

Author SHA1 Message Date
Mathieu Trossevin 099a22fb98
Merge branch 'main' into notify_barrier 2024-01-11 14:44:10 +01:00
Mathieu Trossevin 10c4028f49
Merge branch 'doc-rs' 2024-01-09 10:39:01 +01:00
Mathieu Trossevin c25149382b
Merge branch 'log' 2024-01-09 10:37:12 +01:00
Mathieu Trossevin f61df0da1b
listen: Make one of the closure into a function
This make it a bit easier to debug any problems with it.
2024-01-09 10:35:48 +01:00
Mathieu Trossevin 42aa8b285a
Replace logging crate with log 2024-01-09 10:34:26 +01:00
Mathieu Trossevin 0ce9662f52
Better documentation 2024-01-08 11:25:17 +01:00
4 changed files with 49 additions and 45 deletions

View file

@ -17,5 +17,18 @@ notify = ["dep:libc", "dep:rustix", "rustix/pipe", "rustix/event"]
[dependencies] [dependencies]
libc = { version = "0.2.150", optional = true } libc = { version = "0.2.150", optional = true }
log = "0.4.20"
rustix = { version = "0.38.26", optional = true, features = ["net"] } rustix = { version = "0.38.26", optional = true, features = ["net"] }
tracing = { version = "0.1.40", default-features = false, features = ["std", "log"] }
[package.metadata.docs.rs]
features = ["listenfd", "notify"]
rustdoc-args = ["--cfg", "doc_cfg"]
targets = [
"x86_64-unknown-linux-gnu",
"i686-unknown-linux-gnu",
"x86_64-apple-darwin",
"x86_64-unknown-freebsd",
"x86_64-unknown-openbsd",
"x86_64-unknown-netbsd",
"wasm32-unknown-emscripten"
]

View file

@ -1,4 +1,10 @@
//! A library permitting interaction with the LISTEN_FDS and NOTIFY_SOCKET protocol.
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#[cfg(feature = "listenfd")] #[cfg(feature = "listenfd")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "listenfd")))]
pub mod listen; pub mod listen;
#[cfg(feature = "notify")] #[cfg(feature = "notify")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "notify")))]
pub mod notify; pub mod notify;

View file

@ -104,13 +104,11 @@ impl FileDescriptor {
/// ///
/// # Errors /// # Errors
/// ///
/// This function will fail if no file descriptor colud be received which might not actually be an error. See [`ReceiveError`] for details. /// This function will fail if no file descriptor could be received which might not actually be an error. See [`ReceiveError`] for details.
pub fn receive( pub fn receive(
unset_env: bool, unset_env: bool,
) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, ReceiveError> { ) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, ReceiveError> {
let span = tracing::info_span!("receive", f_unset_env = ?unset_env); log::trace!("Receiving file descriptors.");
let _enter = span.enter();
let fds = Self::inner_receive(unset_env)?; let fds = Self::inner_receive(unset_env)?;
match Self::from_fds(fds) { match Self::from_fds(fds) {
@ -127,7 +125,7 @@ impl FileDescriptor {
/// ///
/// # Errors /// # Errors
/// ///
/// This function will fail if no file descriptor colud be received which might not actually be an error. See [`ReceiveError`] for details. /// This function will fail if no file descriptor could be received which might not actually be an error. See [`ReceiveError`] for details.
/// ///
/// # Safety /// # Safety
/// ///
@ -135,9 +133,7 @@ impl FileDescriptor {
/// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)). /// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)).
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors. /// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
pub unsafe fn receive_no_dup() -> Result<impl IntoIterator<Item = Self>, ReceiveError> { pub unsafe fn receive_no_dup() -> Result<impl IntoIterator<Item = Self>, ReceiveError> {
let span = tracing::info_span!("receive_no_dup"); log::trace!("Receiving file descriptors without duplication.");
let _enter = span.enter();
let fds = Self::inner_receive(true)?; let fds = Self::inner_receive(true)?;
Self::from_fds_no_dup(fds).map_err(ReceiveError::GetFds) Self::from_fds_no_dup(fds).map_err(ReceiveError::GetFds)
@ -146,7 +142,7 @@ impl FileDescriptor {
fn inner_receive(unset_env: bool) -> Result<usize, ReceiveError> { fn inner_receive(unset_env: bool) -> Result<usize, ReceiveError> {
let pid = env::var_os(PID_VAR).ok_or(ReceiveError::NoListenPID)?; let pid = env::var_os(PID_VAR).ok_or(ReceiveError::NoListenPID)?;
let fds = env::var_os(FD_NUMBER_VAR).ok_or(ReceiveError::NoListenFD)?; let fds = env::var_os(FD_NUMBER_VAR).ok_or(ReceiveError::NoListenFD)?;
tracing::trace!("{PID_VAR} = {pid:?}; {FD_NUMBER_VAR} = {fds:?}"); log::trace!("{PID_VAR} = {pid:?}; {FD_NUMBER_VAR} = {fds:?}");
if unset_env { if unset_env {
env::remove_var(PID_VAR); env::remove_var(PID_VAR);
@ -189,8 +185,6 @@ impl FileDescriptor {
unset_env: bool, unset_env: bool,
) -> Result<impl IntoIterator<Item = (OsString, Result<Self, DupError>)>, ReceiveNameError> ) -> Result<impl IntoIterator<Item = (OsString, Result<Self, DupError>)>, ReceiveNameError>
{ {
let span = tracing::info_span!("receive_with_names", f_unset_env = ?unset_env);
let _enter = span.enter();
let ret = Self::get_names()? let ret = Self::get_names()?
.into_iter() .into_iter()
.zip(Self::receive(unset_env)?); .zip(Self::receive(unset_env)?);
@ -214,15 +208,13 @@ impl FileDescriptor {
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors. /// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
pub unsafe fn receive_with_names_no_dup( pub unsafe fn receive_with_names_no_dup(
) -> Result<impl IntoIterator<Item = (OsString, Self)>, ReceiveNameError> { ) -> Result<impl IntoIterator<Item = (OsString, Self)>, ReceiveNameError> {
let span = tracing::info_span!("receive_with_names_no_dups");
let _enter = span.enter();
let ret = Self::get_names()?.into_iter().zip(Self::receive_no_dup()?); let ret = Self::get_names()?.into_iter().zip(Self::receive_no_dup()?);
Ok(ret) Ok(ret)
} }
fn get_names() -> Result<impl IntoIterator<Item = OsString>, ReceiveNameError> { fn get_names() -> Result<impl IntoIterator<Item = OsString>, ReceiveNameError> {
let fd_names = env::var_os(FD_NAMES_VAR).ok_or(ReceiveNameError::NoListenFDName)?; let fd_names = env::var_os(FD_NAMES_VAR).ok_or(ReceiveNameError::NoListenFDName)?;
tracing::trace!("{FD_NAMES_VAR} = {fd_names:?}"); log::trace!("{FD_NAMES_VAR} = {fd_names:?}");
Ok(fd_names Ok(fd_names
.as_encoded_bytes() .as_encoded_bytes()
.split(|b| *b == b':') .split(|b| *b == b':')
@ -236,6 +228,18 @@ impl FileDescriptor {
.collect::<Vec<_>>()) .collect::<Vec<_>>())
} }
fn from_fd_offset(fd_offset: usize) -> Result<Self, DupError> {
SD_LISTEN_FDS_START
.checked_add(fd_offset as RawFd)
.map(|fd| {
// SAFETY: The file descriptor won't be closed by the time we duplicate it.
let fd = unsafe { BorrowedFd::borrow_raw(fd) };
rustix::fs::fcntl_dupfd_cloexec(fd, 0).map_err(DupError::from)
})
.expect("Already checked against overflow.")
.map(Self::from_fd)
}
fn from_fds( fn from_fds(
num_fds: usize, num_fds: usize,
) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, GetFdsError> { ) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, GetFdsError> {
@ -243,17 +247,7 @@ impl FileDescriptor {
return Err(GetFdsError::TooManyFDs(num_fds)); return Err(GetFdsError::TooManyFDs(num_fds));
} }
let ret = (0..num_fds).map(|fd_offset| { let ret = (0..num_fds).map(Self::from_fd_offset);
SD_LISTEN_FDS_START
.checked_add(fd_offset as RawFd)
.map(|fd| {
// SAFETY: The file descriptor won't be closed by the time we duplicate it.
let fd = unsafe { BorrowedFd::borrow_raw(fd) };
rustix::fs::fcntl_dupfd_cloexec(fd, 0).map_err(DupError::from)
})
.expect("Already checked against overflow.")
.map(Self::from_fd)
});
Ok(ret) Ok(ret)
} }

View file

@ -48,18 +48,15 @@ impl Notifier {
/// ///
/// This function error out if the socket couldn't be opened. /// This function error out if the socket couldn't be opened.
pub fn new(unset_env: bool) -> Result<Option<Self>, NewNotifierError> { pub fn new(unset_env: bool) -> Result<Option<Self>, NewNotifierError> {
let span = tracing::info_span!("new", f_unset_env = ?unset_env); log::info!("Opening NOTIFY_SOCKET if available.");
let _enter = span.enter();
tracing::info!("Opening NOTIFY_SOCKET if available.");
let env_sock = match env::var_os("NOTIFY_SOCKET") { let env_sock = match env::var_os("NOTIFY_SOCKET") {
None => return Ok(None), None => return Ok(None),
Some(v) => v, Some(v) => v,
}; };
tracing::debug!("NOTIFY_SOCKET = {env_sock:?}"); log::debug!("NOTIFY_SOCKET = {env_sock:?}");
if unset_env { if unset_env {
tracing::trace!("Removing NOTIFY_SOCKET from environment."); log::trace!("Removing NOTIFY_SOCKET from environment.");
env::remove_var("NOTIFY_SOCKET"); env::remove_var("NOTIFY_SOCKET");
} }
@ -73,12 +70,12 @@ impl Notifier {
unsafe { OsString::from_encoded_bytes_unchecked(v.to_vec()) } unsafe { OsString::from_encoded_bytes_unchecked(v.to_vec()) }
}) { }) {
Some(stripped_addr) => { Some(stripped_addr) => {
tracing::trace!("Opening abstract socket {stripped_addr:?}."); log::trace!("Opening abstract socket {stripped_addr:?}.");
rustix::net::SocketAddrUnix::new_abstract_name(stripped_addr.as_encoded_bytes()) rustix::net::SocketAddrUnix::new_abstract_name(stripped_addr.as_encoded_bytes())
.map_err(NewNotifierError::InvalidAbstractSocket)? .map_err(NewNotifierError::InvalidAbstractSocket)?
} }
None => { None => {
tracing::trace!("Opening named socket {env_sock:?}."); log::trace!("Opening named socket {env_sock:?}.");
rustix::net::SocketAddrUnix::new(env_sock) rustix::net::SocketAddrUnix::new(env_sock)
.map_err(NewNotifierError::InvalidSocketPath)? .map_err(NewNotifierError::InvalidSocketPath)?
} }
@ -104,10 +101,6 @@ impl Notifier {
state: &[NotifyState<'_>], state: &[NotifyState<'_>],
fds: &[BorrowedFd], fds: &[BorrowedFd],
) -> Result<(), NotifyError> { ) -> Result<(), NotifyError> {
let span =
tracing::info_span!("notify_with_fds", f_self = ?self, f_state = ?state, f_fds = ?fds);
let _enter = span.enter();
let msg = state let msg = state
.iter() .iter()
.fold(String::new(), |acc, state| format!("{acc}{state}\n")) .fold(String::new(), |acc, state| format!("{acc}{state}\n"))
@ -116,10 +109,10 @@ impl Notifier {
let msg_iov = IoSlice::new(&msg); let msg_iov = IoSlice::new(&msg);
let mut ancillary = if fds.is_empty() { let mut ancillary = if fds.is_empty() {
tracing::trace!("No file descriptors provided, not sending ancillary messages."); log::trace!("No file descriptors provided, not sending ancillary messages.");
rustix::net::SendAncillaryBuffer::default() rustix::net::SendAncillaryBuffer::default()
} else { } else {
tracing::trace!( log::trace!(
"{} file descriptors provided, sending through ancillary messages", "{} file descriptors provided, sending through ancillary messages",
fds.len() fds.len()
); );
@ -131,8 +124,7 @@ impl Notifier {
ancillary ancillary
}; };
span.record("expected_length", msg_len); log::debug!("Sending notification messages.");
tracing::debug!("Sending notification messages.");
let sent_len = rustix::net::sendmsg_unix( let sent_len = rustix::net::sendmsg_unix(
self.socket.as_fd(), self.socket.as_fd(),
&self.sock_addr, &self.sock_addr,
@ -141,11 +133,10 @@ impl Notifier {
rustix::net::SendFlags::empty(), rustix::net::SendFlags::empty(),
) )
.map_err(NotifyError::SendMsg)?; .map_err(NotifyError::SendMsg)?;
span.record("sent_length", sent_len); log::debug!("Notification message sent. {sent_len} bytes sent.");
tracing::debug!("Notification message sent. {sent_len} bytes sent.");
if sent_len != msg_len { if sent_len != msg_len {
tracing::error!("The notification message couldn't be completely sent!"); log::error!("The notification message couldn't be completely sent!");
return Err(NotifyError::PartialSend); return Err(NotifyError::PartialSend);
} }