I/O safety.
Introduce `OwnedFd` and `BorrowedFd`, and the `AsFd` trait, and implementations of `AsFd`, `From<OwnedFd>` and `From<T> for OwnedFd` for relevant types, along with Windows counterparts for handles and sockets. Tracking issue: - <https://github.com/rust-lang/rust/issues/87074> RFC: - <https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md>
This commit is contained in:
parent
2451f42c1d
commit
d15418586c
43 changed files with 2366 additions and 562 deletions
|
@ -3,6 +3,7 @@ use crate::ffi::CStr;
|
|||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::mem;
|
||||
use crate::net::{Shutdown, SocketAddr};
|
||||
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::str;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
|
||||
|
@ -74,10 +75,10 @@ impl Socket {
|
|||
// flag to atomically create the socket and set it as
|
||||
// CLOEXEC. On Linux this was added in 2.6.27.
|
||||
let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
|
||||
Ok(Socket(FileDesc::new(fd)))
|
||||
Ok(Socket(FileDesc::from_raw_fd(fd)))
|
||||
} else {
|
||||
let fd = cvt(libc::socket(fam, ty, 0))?;
|
||||
let fd = FileDesc::new(fd);
|
||||
let fd = FileDesc::from_raw_fd(fd);
|
||||
fd.set_cloexec()?;
|
||||
let socket = Socket(fd);
|
||||
|
||||
|
@ -109,11 +110,11 @@ impl Socket {
|
|||
))] {
|
||||
// Like above, set cloexec atomically
|
||||
cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
|
||||
Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))))
|
||||
Ok((Socket(FileDesc::from_raw_fd(fds[0])), Socket(FileDesc::from_raw_fd(fds[1]))))
|
||||
} else {
|
||||
cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
|
||||
let a = FileDesc::new(fds[0]);
|
||||
let b = FileDesc::new(fds[1]);
|
||||
let a = FileDesc::from_raw_fd(fds[0]);
|
||||
let b = FileDesc::from_raw_fd(fds[1]);
|
||||
a.set_cloexec()?;
|
||||
b.set_cloexec()?;
|
||||
Ok((Socket(a), Socket(b)))
|
||||
|
@ -131,7 +132,7 @@ impl Socket {
|
|||
self.set_nonblocking(true)?;
|
||||
let r = unsafe {
|
||||
let (addrp, len) = addr.into_inner();
|
||||
cvt(libc::connect(self.0.raw(), addrp, len))
|
||||
cvt(libc::connect(self.as_raw_fd(), addrp, len))
|
||||
};
|
||||
self.set_nonblocking(false)?;
|
||||
|
||||
|
@ -142,7 +143,7 @@ impl Socket {
|
|||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 };
|
||||
let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
|
||||
|
||||
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
|
||||
return Err(io::Error::new_const(
|
||||
|
@ -212,15 +213,17 @@ impl Socket {
|
|||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
))] {
|
||||
let fd = cvt_r(|| unsafe {
|
||||
libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
|
||||
})?;
|
||||
Ok(Socket(FileDesc::new(fd)))
|
||||
unsafe {
|
||||
let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?;
|
||||
Ok(Socket(FileDesc::from_raw_fd(fd)))
|
||||
}
|
||||
} else {
|
||||
let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
|
||||
let fd = FileDesc::new(fd);
|
||||
fd.set_cloexec()?;
|
||||
Ok(Socket(fd))
|
||||
unsafe {
|
||||
let fd = cvt_r(|| libc::accept(self.as_raw_fd(), storage, len))?;
|
||||
let fd = FileDesc::from_raw_fd(fd);
|
||||
fd.set_cloexec()?;
|
||||
Ok(Socket(fd))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +234,7 @@ impl Socket {
|
|||
|
||||
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
|
||||
libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
@ -263,7 +266,7 @@ impl Socket {
|
|||
|
||||
let n = cvt(unsafe {
|
||||
libc::recvfrom(
|
||||
self.0.raw(),
|
||||
self.as_raw_fd(),
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
buf.len(),
|
||||
flags,
|
||||
|
@ -288,7 +291,7 @@ impl Socket {
|
|||
target_os = "openbsd",
|
||||
))]
|
||||
pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
|
||||
let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?;
|
||||
let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
|
||||
|
@ -319,7 +322,7 @@ impl Socket {
|
|||
target_os = "openbsd",
|
||||
))]
|
||||
pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
|
||||
let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?;
|
||||
let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?;
|
||||
Ok(n as usize)
|
||||
}
|
||||
|
||||
|
@ -369,7 +372,7 @@ impl Socket {
|
|||
Shutdown::Read => libc::SHUT_RD,
|
||||
Shutdown::Both => libc::SHUT_RDWR,
|
||||
};
|
||||
cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
|
||||
cvt(unsafe { libc::shutdown(self.as_raw_fd(), how) })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -396,7 +399,7 @@ impl Socket {
|
|||
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
let mut nonblocking = nonblocking as libc::c_int;
|
||||
cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop)
|
||||
cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
|
@ -410,23 +413,52 @@ impl Socket {
|
|||
let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
|
||||
if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<c_int> for Socket {
|
||||
fn as_inner(&self) -> &c_int {
|
||||
self.0.as_inner()
|
||||
// This is used by sys_common code to abstract over Windows and Unix.
|
||||
pub fn as_raw(&self) -> RawFd {
|
||||
self.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<c_int> for Socket {
|
||||
fn from_inner(fd: c_int) -> Socket {
|
||||
Socket(FileDesc::new(fd))
|
||||
impl AsInner<FileDesc> for Socket {
|
||||
fn as_inner(&self) -> &FileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<c_int> for Socket {
|
||||
fn into_inner(self) -> c_int {
|
||||
self.0.into_raw()
|
||||
impl IntoInner<FileDesc> for Socket {
|
||||
fn into_inner(self) -> FileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<FileDesc> for Socket {
|
||||
fn from_inner(file_desc: FileDesc) -> Self {
|
||||
Self(file_desc)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for Socket {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Socket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Socket {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Socket {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
Self(FromRawFd::from_raw_fd(raw_fd))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue