From 7ab73dc939b1bde96e6742daabb1b38883e94c0c Mon Sep 17 00:00:00 2001 From: Jake Correnti Date: Fri, 29 Aug 2025 21:25:00 -0400 Subject: [PATCH] unixgram: Make fd non-blocking When creating unixgram backend from existing fd we need to make it non-blocking so the user does not have to care about this implementation detail. Disabling SIGPIPE is needed on the existing fd for the same reason. Fix by moving these steps from open() to new(). Authored-by: Nir Soffer Signed-off-by: Nir Soffer Signed-off-by: Jake Correnti Signed-off-by: Sergio Lopez --- src/devices/src/virtio/net/unixgram.rs | 57 +++++++++++++------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/devices/src/virtio/net/unixgram.rs b/src/devices/src/virtio/net/unixgram.rs index 78955d202..21f70a405 100644 --- a/src/devices/src/virtio/net/unixgram.rs +++ b/src/devices/src/virtio/net/unixgram.rs @@ -19,11 +19,40 @@ pub struct Unixgram { impl Unixgram { /// Create the backend with a pre-established connection to the userspace network proxy. pub fn new(fd: RawFd) -> Self { + // Ensure the socket is in non-blocking mode. + match fcntl(fd, FcntlArg::F_GETFL) { + Ok(flags) => match OFlag::from_bits(flags) { + Some(flags) => { + if let Err(e) = fcntl(fd, FcntlArg::F_SETFL(flags | OFlag::O_NONBLOCK)) { + warn!("error switching to non-blocking: id={fd}, err={e}"); + } + } + None => error!("invalid fd flags id={fd}"), + }, + Err(e) => error!("couldn't obtain fd flags id={fd}, err={e}"), + }; + + #[cfg(target_os = "macos")] + { + // nix doesn't provide an abstraction for SO_NOSIGPIPE, fall back to libc. + let option_value: libc::c_int = 1; + unsafe { + libc::setsockopt( + fd, + libc::SOL_SOCKET, + libc::SO_NOSIGPIPE, + &option_value as *const _ as *const libc::c_void, + std::mem::size_of_val(&option_value) as libc::socklen_t, + ) + }; + } + Self { fd } } /// Create the backend opening a connection to the userspace network proxy. pub fn open(path: PathBuf, send_vfkit_magic: bool) -> Result { + // We cannot create a non-blocking socket on macOS here. This is done later in new(). let fd = socket( AddressFamily::Unix, SockType::Datagram, @@ -47,34 +76,6 @@ impl Unixgram { send(fd, &VFKIT_MAGIC, MsgFlags::empty()).map_err(ConnectError::SendingMagic)?; } - // macOS forces us to do this here instead of just using SockFlag::SOCK_NONBLOCK above. - match fcntl(fd, FcntlArg::F_GETFL) { - Ok(flags) => match OFlag::from_bits(flags) { - Some(flags) => { - if let Err(e) = fcntl(fd, FcntlArg::F_SETFL(flags | OFlag::O_NONBLOCK)) { - warn!("error switching to non-blocking: id={fd}, err={e}"); - } - } - None => error!("invalid fd flags id={fd}"), - }, - Err(e) => error!("couldn't obtain fd flags id={fd}, err={e}"), - }; - - #[cfg(target_os = "macos")] - { - // nix doesn't provide an abstraction for SO_NOSIGPIPE, fall back to libc. - let option_value: libc::c_int = 1; - unsafe { - libc::setsockopt( - fd, - libc::SOL_SOCKET, - libc::SO_NOSIGPIPE, - &option_value as *const _ as *const libc::c_void, - std::mem::size_of_val(&option_value) as libc::socklen_t, - ) - }; - } - if let Err(e) = setsockopt(fd, sockopt::SndBuf, &(7 * 1024 * 1024)) { log::warn!("Failed to increase SO_SNDBUF (performance may be decreased): {e}"); }