Auto merge of #107405 - hermitcore:bsd, r=bjorn3

add support of RustyHermit's BSD socket layer

RustyHermit is a tier 3 platform and publishes a new kernel interface. The new version supports a common BSD socket layer. By supporting this interface, the implementation of `std` can be harmonized to other operating systems. In `sys_common/mod.rs` we remove only a special case for RustyHermit. All changes are done in the RustyHermit specific directories.

To realize this socket layer, the handling of file descriptors is also harmonized to other operating systems.
This commit is contained in:
bors 2023-02-25 19:43:00 +00:00
commit 34e6673a04
16 changed files with 600 additions and 484 deletions

View File

@ -1927,8 +1927,16 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"compiler_builtins",
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
@ -5294,7 +5302,7 @@ dependencies = [
"dlmalloc",
"fortanix-sgx-abi",
"hashbrown 0.12.3",
"hermit-abi 0.2.6",
"hermit-abi 0.3.0",
"libc",
"miniz_oxide",
"object 0.29.0",

View File

@ -43,7 +43,7 @@ dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
[target.'cfg(target_os = "hermit")'.dependencies]
hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] }
hermit-abi = { version = "0.3.0", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }

View File

@ -9,7 +9,7 @@ use crate::fs;
use crate::io;
use crate::marker::PhantomData;
use crate::mem::forget;
#[cfg(not(any(target_arch = "wasm32", target_env = "sgx")))]
#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))]
use crate::sys::cvt;
use crate::sys_common::{AsInner, FromInner, IntoInner};
@ -89,7 +89,7 @@ impl OwnedFd {
impl BorrowedFd<'_> {
/// Creates a new `OwnedFd` instance that shares the same underlying file
/// description as the existing `BorrowedFd` instance.
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))]
#[stable(feature = "io_safety", since = "1.63.0")]
pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
// We want to atomically duplicate this file descriptor and set the
@ -112,7 +112,7 @@ impl BorrowedFd<'_> {
/// Creates a new `OwnedFd` instance that shares the same underlying file
/// description as the existing `BorrowedFd` instance.
#[cfg(target_arch = "wasm32")]
#[cfg(any(target_arch = "wasm32", target_os = "hermit"))]
#[stable(feature = "io_safety", since = "1.63.0")]
pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
Err(crate::io::const_io_error!(
@ -174,7 +174,10 @@ impl Drop for OwnedFd {
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// opened after we closed ours.
#[cfg(not(target_os = "hermit"))]
let _ = libc::close(self.fd);
#[cfg(target_os = "hermit")]
let _ = hermit_abi::close(self.fd);
}
}
}

View File

@ -4,6 +4,9 @@
use crate::fs;
use crate::io;
#[cfg(target_os = "hermit")]
use crate::os::hermit::io::OwnedFd;
#[cfg(not(target_os = "hermit"))]
use crate::os::raw;
#[cfg(all(doc, not(target_arch = "wasm32")))]
use crate::os::unix::io::AsFd;
@ -12,11 +15,18 @@ use crate::os::unix::io::OwnedFd;
#[cfg(target_os = "wasi")]
use crate::os::wasi::io::OwnedFd;
use crate::sys_common::{AsInner, IntoInner};
#[cfg(target_os = "hermit")]
use hermit_abi as libc;
/// Raw file descriptors.
#[rustc_allowed_through_unstable_modules]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(target_os = "hermit"))]
pub type RawFd = raw::c_int;
#[rustc_allowed_through_unstable_modules]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(target_os = "hermit")]
pub type RawFd = i32;
/// A trait to extract the raw file descriptor from an underlying object.
///

View File

@ -0,0 +1,13 @@
#![stable(feature = "os_fd", since = "1.66.0")]
mod net;
#[path = "../../fd/owned.rs"]
mod owned;
#[path = "../../fd/raw.rs"]
mod raw;
// Export the types and traits for the public API.
#[stable(feature = "os_fd", since = "1.66.0")]
pub use owned::*;
#[stable(feature = "os_fd", since = "1.66.0")]
pub use raw::*;

View File

@ -0,0 +1,46 @@
use crate::os::hermit::io::OwnedFd;
use crate::os::hermit::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::{net, sys};
macro_rules! impl_as_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::$t {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.as_inner().socket().as_raw_fd()
}
}
)*};
}
impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
macro_rules! impl_from_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::$t {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
unsafe {
let socket = sys::net::Socket::from_inner(FromInner::from_inner(OwnedFd::from_raw_fd(fd)));
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
}
}
}
)*};
}
impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
macro_rules! impl_into_raw_fd {
($($t:ident)*) => {$(
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::$t {
#[inline]
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_socket().into_inner().into_inner().into_raw_fd()
}
}
)*};
}
impl_into_raw_fd! { TcpStream TcpListener UdpSocket }

View File

@ -1,6 +1,11 @@
#![stable(feature = "rust1", since = "1.0.0")]
#[allow(unused_extern_crates)]
#[stable(feature = "rust1", since = "1.0.0")]
pub extern crate hermit_abi as abi;
pub mod ffi;
pub mod io;
/// A prelude for conveniently writing platform-specific code.
///

View File

@ -60,16 +60,6 @@ pub mod windows {}
all(target_vendor = "fortanix", target_env = "sgx")
)
)))]
#[cfg(target_os = "hermit")]
#[path = "hermit/mod.rs"]
pub mod unix;
#[cfg(not(all(
doc,
any(
all(target_arch = "wasm32", not(target_os = "wasi")),
all(target_vendor = "fortanix", target_env = "sgx")
)
)))]
#[cfg(all(not(target_os = "hermit"), any(unix, doc)))]
pub mod unix;
@ -123,6 +113,8 @@ pub mod freebsd;
pub mod fuchsia;
#[cfg(target_os = "haiku")]
pub mod haiku;
#[cfg(target_os = "hermit")]
pub mod hermit;
#[cfg(target_os = "horizon")]
pub mod horizon;
#[cfg(target_os = "illumos")]

View File

@ -1,6 +1,6 @@
use crate::ffi::{c_char, CStr, OsString};
use crate::fmt;
use crate::os::unix::ffi::OsStringExt;
use crate::os::hermit::ffi::OsStringExt;
use crate::ptr;
use crate::sync::atomic::{
AtomicIsize, AtomicPtr,

View File

@ -1,36 +1,23 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")]
use crate::io::{self, Read};
use crate::mem;
use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd};
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::unsupported;
use crate::sys_common::AsInner;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::os::hermit::io::*;
#[derive(Debug)]
pub struct FileDesc {
fd: i32,
fd: OwnedFd,
}
impl FileDesc {
pub fn new(fd: i32) -> FileDesc {
FileDesc { fd }
}
pub fn raw(&self) -> i32 {
self.fd
}
/// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> i32 {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let result = unsafe { abi::read(self.fd, buf.as_mut_ptr(), buf.len()) };
cvt(result as i32)
let result = cvt(unsafe { abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
Ok(result as usize)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
@ -39,8 +26,8 @@ impl FileDesc {
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let result = unsafe { abi::write(self.fd, buf.as_ptr(), buf.len()) };
cvt(result as i32)
let result = cvt(unsafe { abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
Ok(result as usize)
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
@ -69,19 +56,45 @@ impl<'a> Read for &'a FileDesc {
}
}
impl AsInner<i32> for FileDesc {
fn as_inner(&self) -> &i32 {
impl IntoInner<OwnedFd> for FileDesc {
fn into_inner(self) -> OwnedFd {
self.fd
}
}
impl FromInner<OwnedFd> for FileDesc {
fn from_inner(owned_fd: OwnedFd) -> Self {
Self { fd: owned_fd }
}
}
impl FromRawFd for FileDesc {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self { fd: FromRawFd::from_raw_fd(raw_fd) }
}
}
impl AsInner<OwnedFd> for FileDesc {
fn as_inner(&self) -> &OwnedFd {
&self.fd
}
}
impl Drop for FileDesc {
fn drop(&mut self) {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// (opened after we closed ours.
let _ = unsafe { abi::close(self.fd) };
impl AsFd for FileDesc {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}
impl AsRawFd for FileDesc {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}
impl IntoRawFd for FileDesc {
fn into_raw_fd(self) -> RawFd {
self.fd.into_raw_fd()
}
}

View File

@ -3,14 +3,17 @@ use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, Error, ErrorKind};
use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::{Path, PathBuf};
use crate::sys::common::small_c_string::run_path_with_cstr;
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::{O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY};
use crate::sys::hermit::abi::{
self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY,
};
use crate::sys::hermit::fd::FileDesc;
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
pub use crate::sys_common::fs::{copy, try_exists};
//pub use crate::sys_common::fs::remove_dir_all;
@ -283,7 +286,7 @@ impl File {
}
let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
Ok(File(FileDesc::new(fd as i32)))
Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) }))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
@ -363,6 +366,54 @@ impl DirBuilder {
}
}
impl AsInner<FileDesc> for File {
fn as_inner(&self) -> &FileDesc {
&self.0
}
}
impl AsInnerMut<FileDesc> for File {
fn as_inner_mut(&mut self) -> &mut FileDesc {
&mut self.0
}
}
impl IntoInner<FileDesc> for File {
fn into_inner(self) -> FileDesc {
self.0
}
}
impl FromInner<FileDesc> for File {
fn from_inner(file_desc: FileDesc) -> Self {
Self(file_desc)
}
}
impl AsFd for File {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl IntoRawFd for File {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
impl FromRawFd for File {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self(FromRawFd::from_raw_fd(raw_fd))
}
}
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
unsupported()
}

View File

@ -13,7 +13,7 @@
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!
#![allow(unsafe_op_in_unsafe_fn)]
#![allow(missing_docs, nonstandard_style, unsafe_op_in_unsafe_fn)]
use crate::intrinsics;
use crate::os::raw::c_char;
@ -57,9 +57,7 @@ pub mod locks {
}
use crate::io::ErrorKind;
#[allow(unused_extern_crates)]
pub extern crate hermit_abi as abi;
use crate::os::hermit::abi;
pub fn unsupported<T>() -> crate::io::Result<T> {
Err(unsupported_err())
@ -126,25 +124,72 @@ pub unsafe extern "C" fn runtime_entry(
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno {
x if x == 13 as i32 => ErrorKind::PermissionDenied,
x if x == 98 as i32 => ErrorKind::AddrInUse,
x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
x if x == 11 as i32 => ErrorKind::WouldBlock,
x if x == 103 as i32 => ErrorKind::ConnectionAborted,
x if x == 111 as i32 => ErrorKind::ConnectionRefused,
x if x == 104 as i32 => ErrorKind::ConnectionReset,
x if x == 17 as i32 => ErrorKind::AlreadyExists,
x if x == 4 as i32 => ErrorKind::Interrupted,
x if x == 22 as i32 => ErrorKind::InvalidInput,
x if x == 2 as i32 => ErrorKind::NotFound,
x if x == 107 as i32 => ErrorKind::NotConnected,
x if x == 1 as i32 => ErrorKind::PermissionDenied,
x if x == 32 as i32 => ErrorKind::BrokenPipe,
x if x == 110 as i32 => ErrorKind::TimedOut,
abi::errno::EACCES => ErrorKind::PermissionDenied,
abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
abi::errno::EAGAIN => ErrorKind::WouldBlock,
abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
abi::errno::EEXIST => ErrorKind::AlreadyExists,
abi::errno::EINTR => ErrorKind::Interrupted,
abi::errno::EINVAL => ErrorKind::InvalidInput,
abi::errno::ENOENT => ErrorKind::NotFound,
abi::errno::ENOTCONN => ErrorKind::NotConnected,
abi::errno::EPERM => ErrorKind::PermissionDenied,
abi::errno::EPIPE => ErrorKind::BrokenPipe,
abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
_ => ErrorKind::Uncategorized,
}
}
pub fn cvt(result: i32) -> crate::io::Result<usize> {
if result < 0 { Err(crate::io::Error::from_raw_os_error(-result)) } else { Ok(result as usize) }
#[doc(hidden)]
pub trait IsNegative {
fn is_negative(&self) -> bool;
fn negate(&self) -> i32;
}
macro_rules! impl_is_negative {
($($t:ident)*) => ($(impl IsNegative for $t {
fn is_negative(&self) -> bool {
*self < 0
}
fn negate(&self) -> i32 {
i32::try_from(-(*self)).unwrap()
}
})*)
}
impl IsNegative for i32 {
fn is_negative(&self) -> bool {
*self < 0
}
fn negate(&self) -> i32 {
-(*self)
}
}
impl_is_negative! { i8 i16 i64 isize }
pub fn cvt<T: IsNegative>(t: T) -> crate::io::Result<T> {
if t.is_negative() {
let e = decode_error_kind(t.negate());
Err(crate::io::Error::from(e))
} else {
Ok(t)
}
}
pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
where
T: IsNegative,
F: FnMut() -> T,
{
loop {
match cvt(f()) {
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
other => return other,
}
}
}

View File

@ -1,129 +1,178 @@
use crate::fmt;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::str;
use crate::sync::Arc;
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::IpAddress::{Ipv4, Ipv6};
use crate::sys::unsupported;
use crate::sys_common::AsInner;
#![allow(dead_code)]
use crate::cmp;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::mem;
use crate::net::{Shutdown, SocketAddr};
use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
use crate::sys::hermit::fd::FileDesc;
use crate::sys::time::Instant;
use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
use core::ffi::c_int;
#[allow(unused_extern_crates)]
pub extern crate hermit_abi as netc;
pub use crate::sys::{cvt, cvt_r};
pub type wrlen_t = usize;
pub fn cvt_gai(err: i32) -> io::Result<()> {
if err == 0 {
return Ok(());
}
let detail = "";
Err(io::Error::new(
io::ErrorKind::Uncategorized,
&format!("failed to lookup address information: {detail}")[..],
))
}
/// Checks whether the HermitCore's socket interface has been started already, and
/// if not, starts it.
pub fn init() -> io::Result<()> {
if abi::network_init() < 0 {
return Err(io::const_io_error!(
ErrorKind::Uncategorized,
"Unable to initialize network interface",
));
}
Ok(())
}
#[derive(Debug, Clone)]
pub struct Socket(abi::Handle);
impl AsInner<abi::Handle> for Socket {
fn as_inner(&self) -> &abi::Handle {
&self.0
pub fn init() {
if unsafe { netc::network_init() } < 0 {
panic!("Unable to initialize network interface");
}
}
impl Drop for Socket {
fn drop(&mut self) {
let _ = abi::tcpstream::close(self.0);
#[derive(Debug)]
pub struct Socket(FileDesc);
impl Socket {
pub fn new(addr: &SocketAddr, ty: i32) -> io::Result<Socket> {
let fam = match *addr {
SocketAddr::V4(..) => netc::AF_INET,
SocketAddr::V6(..) => netc::AF_INET6,
};
Socket::new_raw(fam, ty)
}
}
// Arc is used to count the number of used sockets.
// Only if all sockets are released, the drop
// method will close the socket.
#[derive(Clone)]
pub struct TcpStream(Arc<Socket>);
pub fn new_raw(fam: i32, ty: i32) -> io::Result<Socket> {
let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
impl TcpStream {
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let addr = addr?;
pub fn new_pair(_fam: i32, _ty: i32) -> io::Result<(Socket, Socket)> {
unimplemented!()
}
match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
_ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
"Unable to initiate a connection on a socket",
)),
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?;
let r = unsafe {
let (addr, len) = addr.into_inner();
cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len))
};
self.set_nonblocking(false)?;
match r {
Ok(_) => return Ok(()),
// there's no ErrorKind for EINPROGRESS :(
Err(ref e) if e.raw_os_error() == Some(netc::errno::EINPROGRESS) => {}
Err(e) => return Err(e),
}
let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout",
));
}
let start = Instant::now();
loop {
let elapsed = start.elapsed();
if elapsed >= timeout {
return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
}
let timeout = timeout - elapsed;
let mut timeout = timeout
.as_secs()
.saturating_mul(1_000)
.saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
if timeout == 0 {
timeout = 1;
}
let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
-1 => {
let err = io::Error::last_os_error();
if err.kind() != io::ErrorKind::Interrupted {
return Err(err);
}
}
0 => {}
_ => {
// linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
// for POLLHUP rather than read readiness
if pollfd.revents & netc::POLLHUP != 0 {
let e = self.take_error()?.unwrap_or_else(|| {
io::const_io_error!(
io::ErrorKind::Uncategorized,
"no error set after POLLHUP",
)
});
return Err(e);
}
return Ok(());
}
}
}
}
pub fn connect_timeout(saddr: &SocketAddr, duration: Duration) -> io::Result<TcpStream> {
match abi::tcpstream::connect(
saddr.ip().to_string().as_bytes(),
saddr.port(),
Some(duration.as_millis() as u64),
) {
Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
_ => Err(io::const_io_error!(
ErrorKind::Uncategorized,
"Unable to initiate a connection on a socket",
)),
}
pub fn accept(
&self,
storage: *mut netc::sockaddr,
len: *mut netc::socklen_t,
) -> io::Result<Socket> {
let fd = cvt(unsafe { netc::accept(self.0.as_raw_fd(), storage, len) })?;
Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
.map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
})
pub fn duplicate(&self) -> io::Result<Socket> {
let fd = cvt(unsafe { netc::dup(self.0.as_raw_fd()) })?;
Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
abi::tcpstream::set_write_timeout(
*self.0.as_inner(),
duration.map(|d| d.as_millis() as u64),
)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
let ret =
cvt(unsafe { netc::recv(self.0.as_raw_fd(), buf.as_mut_ptr(), buf.len(), flags) })?;
Ok(ret as usize)
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
})?;
Ok(duration.map(|d| Duration::from_millis(d)))
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.recv_with_flags(buf, 0)
}
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
abi::tcpstream::peek(*self.0.as_inner(), buf)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
self.recv_with_flags(buf, netc::MSG_PEEK)
}
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
self.read_vectored(&mut [IoSliceMut::new(buffer)])
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut size: isize = 0;
pub fn read_vectored(&self, ioslice: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let mut size: usize = 0;
for i in ioslice.iter_mut() {
let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
})?;
for i in bufs.iter_mut() {
let ret: isize =
cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
if ret != 0 {
size += ret;
}
}
Ok(size)
Ok(size.try_into().unwrap())
}
#[inline]
@ -131,360 +180,174 @@ impl TcpStream {
true
}
pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
self.write_vectored(&[IoSlice::new(buffer)])
fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
let n = cvt(unsafe {
netc::recvfrom(
self.as_raw_fd(),
buf.as_mut_ptr(),
buf.len(),
flags,
&mut storage as *mut _ as *mut _,
&mut addrlen,
)
})?;
Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
}
pub fn write_vectored(&self, ioslice: &[IoSlice<'_>]) -> io::Result<usize> {
let mut size: usize = 0;
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.recv_from_with_flags(buf, 0)
}
for i in ioslice.iter() {
size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
})?;
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.recv_from_with_flags(buf, netc::MSG_PEEK)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let sz = cvt(unsafe { netc::write(self.0.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
Ok(sz.try_into().unwrap())
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut size: isize = 0;
for i in bufs.iter() {
size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
}
Ok(size)
Ok(size.try_into().unwrap())
}
#[inline]
pub fn is_write_vectored(&self) -> bool {
true
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
let timeout = match dur {
Some(dur) => {
if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout",
));
}
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
let secs = if dur.as_secs() > netc::time_t::MAX as u64 {
netc::time_t::MAX
} else {
dur.as_secs() as netc::time_t
};
let mut timeout = netc::timeval {
tv_sec: secs,
tv_usec: dur.subsec_micros() as netc::suseconds_t,
};
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
timeout.tv_usec = 1;
}
timeout
}
None => netc::timeval { tv_sec: 0, tv_usec: 0 },
};
Ok(saddr)
setsockopt(self, netc::SOL_SOCKET, kind, timeout)
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unsupported()
pub fn timeout(&self, kind: i32) -> io::Result<Option<Duration>> {
let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
if raw.tv_sec == 0 && raw.tv_usec == 0 {
Ok(None)
} else {
let sec = raw.tv_sec as u64;
let nsec = (raw.tv_usec as u32) * 1000;
Ok(Some(Duration::new(sec, nsec)))
}
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
let how = match how {
Shutdown::Write => netc::SHUT_WR,
Shutdown::Read => netc::SHUT_RD,
Shutdown::Both => netc::SHUT_RDWR,
};
cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?;
Ok(())
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
Ok(self.clone())
}
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
let linger = netc::linger {
l_onoff: linger.is_some() as i32,
l_linger: linger.unwrap_or_default().as_secs() as libc::c_int,
};
pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
unsupported()
setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
unsupported()
let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
}
pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
let value: i32 = if nodelay { 1 } else { 0 };
setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value)
}
pub fn nodelay(&self) -> io::Result<bool> {
abi::tcpstream::nodelay(*self.0.as_inner())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
Ok(raw != 0)
}
pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
abi::tcpstream::set_tll(*self.0.as_inner(), tll)
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
}
pub fn ttl(&self) -> io::Result<u32> {
abi::tcpstream::get_tll(*self.0.as_inner())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unsupported()
}
pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking: i32 = if nonblocking { 1 } else { 0 };
cvt(unsafe {
netc::ioctl(
self.as_raw_fd(),
netc::FIONBIO,
&mut nonblocking as *mut _ as *mut core::ffi::c_void,
)
})
}
}
impl fmt::Debug for TcpStream {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
#[derive(Clone)]
pub struct TcpListener(SocketAddr);
impl TcpListener {
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
let addr = addr?;
Ok(TcpListener(*addr))
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
Ok(self.0)
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
.map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
let saddr = match ipaddr {
Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
_ => {
return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
}
};
Ok((TcpStream(Arc::new(Socket(handle))), saddr))
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
Ok(self.clone())
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
unsupported()
}
pub fn ttl(&self) -> io::Result<u32> {
unsupported()
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn only_v6(&self) -> io::Result<bool> {
unsupported()
.map(drop)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unsupported()
unimplemented!()
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unsupported()
// This is used by sys_common code to abstract over Windows and Unix.
pub fn as_raw(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
impl AsInner<FileDesc> for Socket {
fn as_inner(&self) -> &FileDesc {
&self.0
}
}
pub struct UdpSocket(abi::Handle);
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
unsupported()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
unsupported()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unsupported()
}
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unsupported()
}
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unsupported()
}
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
unsupported()
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
unsupported()
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unsupported()
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unsupported()
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
unsupported()
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
unsupported()
}
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn broadcast(&self) -> io::Result<bool> {
unsupported()
}
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
unsupported()
}
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
unsupported()
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
unsupported()
}
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
unsupported()
}
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
unsupported()
}
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
unsupported()
}
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
unsupported()
}
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
unsupported()
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
unsupported()
}
pub fn ttl(&self) -> io::Result<u32> {
unsupported()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unsupported()
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unsupported()
}
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
unsupported()
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
unsupported()
}
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
unsupported()
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
unsupported()
}
}
impl fmt::Debug for UdpSocket {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
pub struct LookupHost(!);
impl LookupHost {
pub fn port(&self) -> u16 {
impl IntoInner<FileDesc> for Socket {
fn into_inner(self) -> FileDesc {
self.0
}
}
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
self.0
impl FromInner<FileDesc> for Socket {
fn from_inner(file_desc: FileDesc) -> Self {
Self(file_desc)
}
}
impl TryFrom<&str> for LookupHost {
type Error = io::Error;
fn try_from(_v: &str) -> io::Result<LookupHost> {
unsupported()
impl AsFd for Socket {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;
fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
unsupported()
impl AsRawFd for Socket {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[allow(nonstandard_style)]
pub mod netc {
pub const AF_INET: u8 = 0;
pub const AF_INET6: u8 = 1;
pub type sa_family_t = u8;
#[derive(Copy, Clone)]
pub struct in_addr {
pub s_addr: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: u16,
pub sin_addr: in_addr,
}
#[derive(Copy, Clone)]
pub struct in6_addr {
pub s6_addr: [u8; 16],
}
#[derive(Copy, Clone)]
pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: u16,
pub sin6_addr: in6_addr,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {}
}

View File

@ -4,7 +4,7 @@ use crate::ffi::{CStr, OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
use crate::os::unix::ffi::OsStringExt;
use crate::os::hermit::ffi::OsStringExt;
use crate::path::{self, PathBuf};
use crate::str;
use crate::sync::Mutex;

View File

@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::cmp::Ordering;
use crate::ops::{Add, AddAssign, Sub, SubAssign};
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::timespec;
use crate::sys::hermit::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
@ -102,55 +103,122 @@ impl Hash for Timespec {
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: Timespec,
}
pub struct Instant(Timespec);
impl Instant {
pub fn now() -> Instant {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
Instant { t: time }
Instant(time)
}
#[stable(feature = "time2", since = "1.8.0")]
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
}
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
self.checked_sub_instant(&earlier)
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
self.0.sub_timespec(&other.0).ok()
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_add_duration(other)? })
Some(Instant(self.0.checked_add_duration(other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_sub_duration(other)? })
Some(Instant(self.0.checked_sub_duration(other)?))
}
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
self.0.checked_add_duration(&duration).map(Instant)
}
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
self.0.checked_sub_duration(&duration).map(Instant)
}
}
impl Add<Duration> for Instant {
type Output = Instant;
/// # Panics
///
/// This function may panic if the resulting point in time cannot be represented by the
/// underlying data structure. See [`Instant::checked_add`] for a version without panic.
fn add(self, other: Duration) -> Instant {
self.checked_add(other).expect("overflow when adding duration to instant")
}
}
impl AddAssign<Duration> for Instant {
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
impl Sub<Duration> for Instant {
type Output = Instant;
fn sub(self, other: Duration) -> Instant {
self.checked_sub(other).expect("overflow when subtracting duration from instant")
}
}
impl SubAssign<Duration> for Instant {
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
/// Returns the amount of time elapsed from another instant to this one,
/// or zero duration if that instant is later than this one.
///
/// # Panics
///
/// Previous rust versions panicked when `other` was later than `self`. Currently this
/// method saturates. Future versions may reintroduce the panic in some circumstances.
/// See [Monotonicity].
///
/// [Monotonicity]: Instant#monotonicity
fn sub(self, other: Instant) -> Duration {
self.duration_since(other)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct SystemTime {
t: Timespec,
}
pub struct SystemTime(Timespec);
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
impl SystemTime {
pub fn now() -> SystemTime {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
SystemTime { t: time }
SystemTime(time)
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
self.0.sub_timespec(&other.0)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_add_duration(other)? })
Some(SystemTime(self.0.checked_add_duration(other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
Some(SystemTime(self.0.checked_sub_duration(other)?))
}
}

View File

@ -44,7 +44,6 @@ cfg_if::cfg_if! {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "l4re",
target_os = "hermit",
feature = "restricted-std",
all(target_family = "wasm", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")))] {