From 18c14add399c35153883f8b84a2e11a7c22f6721 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 14:05:10 -0700 Subject: [PATCH 1/6] Add a `try_clone()` function to `OwnedFd`. As suggested in #88564. This adds a `try_clone()` to `OwnedFd` by refactoring the code out of the existing `File`/`Socket` code. --- library/std/src/os/fd/owned.rs | 23 +++++++++++ library/std/src/os/windows/io/handle.rs | 33 +++++++++++++++ library/std/src/os/windows/io/socket.rs | 54 +++++++++++++++++++++++++ library/std/src/sys/unix/fd.rs | 17 +------- library/std/src/sys/windows/fs.rs | 2 +- library/std/src/sys/windows/handle.rs | 15 +------ library/std/src/sys/windows/net.rs | 47 +-------------------- 7 files changed, 115 insertions(+), 76 deletions(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 52d7d4690d39f..597e050b00d5a 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,6 +8,7 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed file descriptor. @@ -67,6 +68,28 @@ impl BorrowedFd<'_> { } } +impl OwnedFd { + /// Creates a new `OwnedFd` instance that shares the same underlying file handle + /// as the existing `OwnedFd` instance. + pub fn try_clone(&self) -> crate::io::Result { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // is a POSIX flag that was added to Linux in 2.6.24. + #[cfg(not(target_os = "espidf"))] + let cmd = libc::F_DUPFD_CLOEXEC; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let cmd = libc::F_DUPFD; + + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) + } +} + #[unstable(feature = "io_safety", issue = "87074")] impl AsRawFd for BorrowedFd<'_> { #[inline] diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 72a17adb3b470..64c3761511425 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -11,6 +11,7 @@ use crate::marker::PhantomData; use crate::mem::forget; use crate::ptr::NonNull; use crate::sys::c; +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed handle. @@ -110,6 +111,38 @@ impl BorrowedHandle<'_> { } } +impl OwnedHandle { + /// Creates a new `OwnedHandle` instance that shares the same underlying file handle + /// as the existing `OwnedHandle` instance. + pub fn try_clone(&self) -> crate::io::Result { + let handle = self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?; + + Ok(unsafe { OwnedHandle::from_raw_handle(handle) }) + } + + pub(crate) fn duplicate( + &self, + access: c::DWORD, + inherit: bool, + options: c::DWORD, + ) -> io::Result { + let mut ret = 0 as c::HANDLE; + cvt(unsafe { + let cur_proc = c::GetCurrentProcess(); + c::DuplicateHandle( + cur_proc, + self.as_raw_handle(), + cur_proc, + &mut ret, + access, + inherit as c::BOOL, + options, + ) + })?; + unsafe { Ok(Self::from_raw_handle(ret)) } + } +} + impl TryFrom for OwnedHandle { type Error = (); diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 23db66df09f7a..9e27ead90fb56 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -7,6 +7,7 @@ use crate::fmt; use crate::marker::PhantomData; use crate::mem::forget; use crate::sys::c; +use crate::sys::cvt; /// A borrowed socket. /// @@ -69,6 +70,59 @@ impl BorrowedSocket<'_> { } } +impl OwnedSocket { + /// Creates a new `OwnedSocket` instance that shares the same underlying socket + /// as the existing `OwnedSocket` instance. + pub fn try_clone(&self) -> io::Result { + let mut info = unsafe { mem::zeroed::() }; + let result = unsafe { + c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) + }; + cvt(result)?; + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, + ) + }; + + if socket != c::INVALID_SOCKET { + unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } + } else { + let error = unsafe { c::WSAGetLastError() }; + + if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == c::INVALID_SOCKET { + return Err(last_error()); + } + + unsafe { + let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); + socket.set_no_inherit()?; + Ok(socket) + } + } + } +} + impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 0956726084e02..3c2b36fe691bc 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -266,22 +266,9 @@ impl FileDesc { } } + #[inline] pub fn duplicate(&self) -> io::Result { - // We want to atomically duplicate this file descriptor and set the - // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // is a POSIX flag that was added to Linux in 2.6.24. - #[cfg(not(target_os = "espidf"))] - let cmd = libc::F_DUPFD_CLOEXEC; - - // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics - // will never be supported, as this is a bare metal framework with - // no capabilities for multi-process execution. While F_DUPFD is also - // not supported yet, it might be (currently it returns ENOSYS). - #[cfg(target_os = "espidf")] - let cmd = libc::F_DUPFD; - - let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; - Ok(unsafe { FileDesc::from_raw_fd(fd) }) + Ok(Self(self.0.try_clone()?)) } } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 0c1a50e231cd4..08ff35361f4b6 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -455,7 +455,7 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? }) + Ok(Self(self.0.try_clone()?)) } fn reparse_point<'a>( diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 21d86b002264a..8de5729daa38d 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -235,20 +235,7 @@ impl Handle { inherit: bool, options: c::DWORD, ) -> io::Result { - let mut ret = 0 as c::HANDLE; - cvt(unsafe { - let cur_proc = c::GetCurrentProcess(); - c::DuplicateHandle( - cur_proc, - self.as_raw_handle(), - cur_proc, - &mut ret, - access, - inherit as c::BOOL, - options, - ) - })?; - unsafe { Ok(Handle::from_raw_handle(ret)) } + Ok(Self(self.0.duplicate(access, inherit, options)?)) } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 33152cc97abc0..681875985bdc9 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -208,52 +208,7 @@ impl Socket { } pub fn duplicate(&self) -> io::Result { - let mut info = unsafe { mem::zeroed::() }; - let result = unsafe { - c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) - }; - cvt(result)?; - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) - }; - - if socket != c::INVALID_SOCKET { - unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } - } else { - let error = unsafe { c::WSAGetLastError() }; - - if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { - return Err(io::Error::from_raw_os_error(error)); - } - - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED, - ) - }; - - if socket == c::INVALID_SOCKET { - return Err(last_error()); - } - - unsafe { - let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); - socket.set_no_inherit()?; - Ok(socket) - } - } + Ok(Self(self.0.duplicate()?)) } fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { From 622dfcceb9328b359e28adaec8192390e494ca1e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 14:44:54 -0700 Subject: [PATCH 2/6] Fix Windows compilation errors. --- library/std/src/os/windows/io/handle.rs | 3 ++- library/std/src/os/windows/io/socket.rs | 11 +++++++++-- library/std/src/sys/windows/fs.rs | 2 +- library/std/src/sys/windows/net.rs | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 64c3761511425..92c5f49e58a00 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -7,6 +7,7 @@ use crate::convert::TryFrom; use crate::ffi::c_void; use crate::fmt; use crate::fs; +use crate::io; use crate::marker::PhantomData; use crate::mem::forget; use crate::ptr::NonNull; @@ -114,7 +115,7 @@ impl BorrowedHandle<'_> { impl OwnedHandle { /// Creates a new `OwnedHandle` instance that shares the same underlying file handle /// as the existing `OwnedHandle` instance. - pub fn try_clone(&self) -> crate::io::Result { + pub fn try_clone(&self) -> crate::io::Result { let handle = self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?; Ok(unsafe { OwnedHandle::from_raw_handle(handle) }) diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 9e27ead90fb56..0d77643404742 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -4,7 +4,9 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::fmt; +use crate::io; use crate::marker::PhantomData; +use crate::mem; use crate::mem::forget; use crate::sys::c; use crate::sys::cvt; @@ -91,7 +93,7 @@ impl OwnedSocket { }; if socket != c::INVALID_SOCKET { - unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } + unsafe { Ok(Self(OwnedSocket::from_raw_socket(socket))) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -115,7 +117,7 @@ impl OwnedSocket { } unsafe { - let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); + let socket = Self(OwnedSocket::from_raw_socket(socket)); socket.set_no_inherit()?; Ok(socket) } @@ -123,6 +125,11 @@ impl OwnedSocket { } } +/// Returns the last error from the Windows socket interface. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) +} + impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 08ff35361f4b6..34455b7e3161a 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -455,7 +455,7 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Ok(Self(self.0.try_clone()?)) + Ok(Self { handle: self.handle.try_clone()? }) } fn reparse_point<'a>( diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 681875985bdc9..39417baebd44c 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -208,7 +208,7 @@ impl Socket { } pub fn duplicate(&self) -> io::Result { - Ok(Self(self.0.duplicate()?)) + Ok(Self(self.0.try_clone()?)) } fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { From c986c6b4ffec634d3c0ecbc3867a818bc41a59be Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 15:30:17 -0700 Subject: [PATCH 3/6] Fix more Windows compilation errors. --- library/std/src/os/windows/io/handle.rs | 4 +--- library/std/src/os/windows/io/socket.rs | 17 +++++++++++++++-- library/std/src/sys/windows/handle.rs | 6 +++++- library/std/src/sys/windows/net.rs | 15 +-------------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 92c5f49e58a00..9522a05495c6f 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -116,9 +116,7 @@ impl OwnedHandle { /// Creates a new `OwnedHandle` instance that shares the same underlying file handle /// as the existing `OwnedHandle` instance. pub fn try_clone(&self) -> crate::io::Result { - let handle = self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?; - - Ok(unsafe { OwnedHandle::from_raw_handle(handle) }) + self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS) } pub(crate) fn duplicate( diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 0d77643404742..7acd0af88b39a 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -93,7 +93,7 @@ impl OwnedSocket { }; if socket != c::INVALID_SOCKET { - unsafe { Ok(Self(OwnedSocket::from_raw_socket(socket))) } + unsafe { Ok(OwnedSocket::from_raw_socket(socket)) } } else { let error = unsafe { c::WSAGetLastError() }; @@ -117,12 +117,25 @@ impl OwnedSocket { } unsafe { - let socket = Self(OwnedSocket::from_raw_socket(socket)); + let socket = OwnedSocket::from_raw_socket(socket); socket.set_no_inherit()?; Ok(socket) } } } + + #[cfg(not(target_vendor = "uwp"))] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + sys::cvt(unsafe { + c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) + }) + .map(drop) + } + + #[cfg(target_vendor = "uwp")] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) + } } /// Returns the last error from the Windows socket interface. diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index 8de5729daa38d..76a97e89be194 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -229,12 +229,16 @@ impl Handle { Ok(written as usize) } + pub fn try_clone(&self) -> io::Result { + Ok(Self(self.0.try_clone()?)) + } + pub fn duplicate( &self, access: c::DWORD, inherit: bool, options: c::DWORD, - ) -> io::Result { + ) -> io::Result { Ok(Self(self.0.duplicate(access, inherit, options)?)) } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 39417baebd44c..75d4b3bd76862 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -129,7 +129,7 @@ impl Socket { unsafe { let socket = Self::from_raw_socket(socket); - socket.set_no_inherit()?; + socket.0.set_no_inherit()?; Ok(socket) } } @@ -371,19 +371,6 @@ impl Socket { } } - #[cfg(not(target_vendor = "uwp"))] - fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { - c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) - }) - .map(drop) - } - - #[cfg(target_vendor = "uwp")] - fn set_no_inherit(&self) -> io::Result<()> { - Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) - } - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { Shutdown::Write => c::SD_SEND, From 2d6a4c85ca037ac07cac6029c2b174678c39a40d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 9 Sep 2021 15:37:43 -0700 Subject: [PATCH 4/6] Fix another Windows compilation error. --- library/std/src/os/windows/io/socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 7acd0af88b39a..e0af4f1f6cb16 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -126,7 +126,7 @@ impl OwnedSocket { #[cfg(not(target_vendor = "uwp"))] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { + cvt(unsafe { c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) }) .map(drop) From 53e072f2207747e8b60dcbb77b763c1598cfb192 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 5 Oct 2021 14:11:49 -0700 Subject: [PATCH 5/6] Fix compilation on WASI, which doesn't yet support `dup`. --- library/std/src/os/fd/owned.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 597e050b00d5a..0b6588db92c83 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,6 +8,7 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; +#[cfg(not(target_os = "wasi"))] use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -71,6 +72,7 @@ impl BorrowedFd<'_> { impl OwnedFd { /// Creates a new `OwnedFd` instance that shares the same underlying file handle /// as the existing `OwnedFd` instance. + #[cfg(not(target_os = "wasi"))] pub fn try_clone(&self) -> crate::io::Result { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This @@ -88,6 +90,14 @@ impl OwnedFd { let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; Ok(unsafe { Self::from_raw_fd(fd) }) } + + #[cfg(target_os = "wasi")] + pub fn try_clone(&self) -> crate::io::Result { + Err(crate::io::Error::new_const( + crate::io::ErrorKind::Unsupported, + &"operation not supported on WASI yet", + )) + } } #[unstable(feature = "io_safety", issue = "87074")] From 83aebf8f7bb6d766f6b68accdc44acb9cea3d57e Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 12 Jan 2022 11:41:48 -0800 Subject: [PATCH 6/6] Use the correct `cvt` for converting socket errors on Windows. `WSADuplicateSocketW` returns 0 on success, which differs from handle-oriented functions which return 0 on error. Use `sys::net::cvt` to handle its return value, which handles the socket convention of returning 0 on success, rather than `sys::cvt`, which handles the handle-oriented convention of returning 0 on failure. --- library/std/src/os/windows/io/socket.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index e0af4f1f6cb16..26b569bcdd362 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -8,6 +8,7 @@ use crate::io; use crate::marker::PhantomData; use crate::mem; use crate::mem::forget; +use crate::sys; use crate::sys::c; use crate::sys::cvt; @@ -80,7 +81,7 @@ impl OwnedSocket { let result = unsafe { c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) }; - cvt(result)?; + sys::net::cvt(result)?; let socket = unsafe { c::WSASocketW( info.iAddressFamily,