diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 562fdbf4ff76d..0633a5d73da45 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -95,6 +95,9 @@ impl Error { pub(crate) const ZERO_TIMEOUT: Self = const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); + + pub(crate) const NO_ADDRESSES: Self = + const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses"); } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index ddd3b68dd2d63..40f1a93e39ded 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -34,7 +34,6 @@ pub use self::tcp::IntoIncoming; pub use self::tcp::{Incoming, TcpListener, TcpStream}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::udp::UdpSocket; -use crate::io::{self, ErrorKind}; mod ip_addr; mod socket_addr; @@ -67,23 +66,3 @@ pub enum Shutdown { #[stable(feature = "rust1", since = "1.0.0")] Both, } - -fn each_addr(addr: A, mut f: F) -> io::Result -where - F: FnMut(io::Result<&SocketAddr>) -> io::Result, -{ - let addrs = match addr.to_socket_addrs() { - Ok(addrs) => addrs, - Err(e) => return f(Err(e)), - }; - let mut last_err = None; - for addr in addrs { - match f(Ok(&addr)) { - Ok(l) => return Ok(l), - Err(e) => last_err = Some(e), - } - } - Err(last_err.unwrap_or_else(|| { - io::const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses") - })) -} diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 10685b4931949..ae50f531a7162 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -167,7 +167,7 @@ impl TcpStream { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn connect(addr: A) -> io::Result { - super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) + net_imp::TcpStream::connect(addr).map(TcpStream) } /// Opens a TCP connection to a remote host with a timeout. @@ -782,7 +782,7 @@ impl TcpListener { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind(addr: A) -> io::Result { - super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) + net_imp::TcpListener::bind(addr).map(TcpListener) } /// Returns the local socket address of this listener. diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 03003037b295c..7c7ef7b2f7018 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -1,5 +1,5 @@ use crate::io::prelude::*; -use crate::io::{BorrowedBuf, IoSlice, IoSliceMut}; +use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut}; use crate::mem::MaybeUninit; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index a97b3299774bb..72e292e3d157c 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -120,7 +120,7 @@ impl UdpSocket { /// [`Ipv4Addr::UNSPECIFIED`] or [`Ipv6Addr::UNSPECIFIED`]. #[stable(feature = "rust1", since = "1.0.0")] pub fn bind(addr: A) -> io::Result { - super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) + net_imp::UdpSocket::bind(addr).map(UdpSocket) } /// Receives a single datagram message on the socket. On success, returns the number @@ -677,7 +677,7 @@ impl UdpSocket { /// on the platform. #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn connect(&self, addr: A) -> io::Result<()> { - super::each_addr(addr, |addr| self.0.connect(addr)) + self.0.connect(addr) } /// Sends data on the socket to the remote address to which it is connected. diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 91da3135f97c6..0638b36c54f9d 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -1,3 +1,4 @@ +use crate::io::ErrorKind; use crate::net::test::{compare_ignore_zoneid, next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs new file mode 100644 index 0000000000000..082644f470a17 --- /dev/null +++ b/library/std/src/sys/net/connection/mod.rs @@ -0,0 +1,52 @@ +cfg_if::cfg_if! { + if #[cfg(any( + all(target_family = "unix", not(target_os = "l4re")), + target_os = "windows", + target_os = "hermit", + all(target_os = "wasi", target_env = "p2"), + target_os = "solid_asp3", + ))] { + mod socket; + pub use socket::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(all(target_os = "wasi", target_env = "p1"))] { + mod wasip1; + pub use wasip1::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} + +#[cfg_attr( + // Make sure that this is used on some platforms at least. + not(any(target_os = "linux", target_os = "windows")), + allow(dead_code) +)] +fn each_addr(addr: A, mut f: F) -> crate::io::Result +where + F: FnMut(&crate::net::SocketAddr) -> crate::io::Result, +{ + use crate::io::Error; + + let mut last_err = None; + for addr in addr.to_socket_addrs()? { + match f(&addr) { + Ok(l) => return Ok(l), + Err(e) => last_err = Some(e), + } + } + + match last_err { + Some(err) => Err(err), + None => Err(Error::NO_ADDRESSES), + } +} diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 242df10bc3270..cef4a08f457ec 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -1,3 +1,5 @@ +use crate::error; +use crate::fmt::{self, Write}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::Arc; @@ -5,7 +7,6 @@ use crate::sys::abi::usercalls; use crate::sys::fd::FileDesc; use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported}; use crate::time::Duration; -use crate::{error, fmt}; const DEFAULT_FAKE_TTL: u32 = 64; @@ -63,18 +64,51 @@ impl fmt::Debug for TcpStream { } } -fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result { - match result { - Ok(saddr) => Ok(saddr.to_string()), - // need to downcast twice because io::Error::into_inner doesn't return the original - // value if the conversion fails - Err(e) => { - if e.get_ref().and_then(|e| e.downcast_ref::()).is_some() { - Ok(e.into_inner().unwrap().downcast::().unwrap().host) - } else { - Err(e) +/// Converts each address in `addr` into a hostname. +/// +/// SGX doesn't support DNS resolution but rather accepts hostnames in +/// the same place as socket addresses. So, to make e.g. +/// ```rust +/// TcpStream::connect("example.com:80")` +/// ``` +/// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead, +/// which contains the hostname being looked up. When `.to_socket_addrs()` +/// fails, we inspect the error and try recover the hostname from it. If that +/// succeeds, we thus continue with the hostname. +/// +/// This is a terrible hack and leads to buggy code. For instance, when users +/// use the result of `.to_socket_addrs()` in their own `ToSocketAddrs` +/// implementation to select from a list of possible URLs, the only URL used +/// will be that of the last item tried. +// FIXME: This is a terrible, terrible hack. +fn each_addr(addr: A, mut f: F) -> io::Result +where + F: FnMut(&str) -> io::Result, +{ + match addr.to_socket_addrs() { + Ok(addrs) => { + let mut last_err = None; + let mut encoded = String::new(); + for addr in addrs { + write!(encoded, "{}", &addr).unwrap(); + match f(&encoded) { + Ok(val) => return Ok(val), + Err(err) => { + last_err = Some(err); + encoded.clear(); + } + } + } + + match last_err { + Some(err) => Err(err), + None => Err(io::Error::NO_ADDRESSES), } } + Err(err) => match err.get_ref().and_then(|e| e.downcast_ref::()) { + Some(NonIpSockAddr { host }) => f(host), + None => Err(err), + }, } } @@ -86,17 +120,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result { } impl TcpStream { - pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { - let addr = io_err_to_addr(addr)?; - let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?; - Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) }) + pub fn connect(addr: A) -> io::Result { + each_addr(addr, |addr| { + let (fd, local_addr, peer_addr) = usercalls::connect_stream(addr)?; + Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) }) + }) } pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result { if dur == Duration::default() { return Err(io::Error::ZERO_TIMEOUT); } - Self::connect(Ok(addr)) // FIXME: ignoring timeout + Self::connect(addr) // FIXME: ignoring timeout } pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { @@ -247,10 +282,11 @@ impl fmt::Debug for TcpListener { } impl TcpListener { - pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result { - let addr = io_err_to_addr(addr)?; - let (fd, local_addr) = usercalls::bind_stream(&addr)?; - Ok(TcpListener { inner: Socket::new(fd, local_addr) }) + pub fn bind(addr: A) -> io::Result { + each_addr(addr, |addr| { + let (fd, local_addr) = usercalls::bind_stream(addr)?; + Ok(TcpListener { inner: Socket::new(fd, local_addr) }) + }) } pub fn socket_addr(&self) -> io::Result { @@ -316,7 +352,7 @@ impl FromInner for TcpListener { pub struct UdpSocket(!); impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + pub fn bind(_: A) -> io::Result { unsupported() } @@ -436,7 +472,7 @@ impl UdpSocket { self.0 } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect(&self, _: A) -> io::Result<()> { self.0 } } diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket/mod.rs similarity index 87% rename from library/std/src/sys/net/connection/socket.rs rename to library/std/src/sys/net/connection/socket/mod.rs index 7301bde6881a3..c8b667aa9c5c9 100644 --- a/library/std/src/sys/net/connection/socket.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -3,8 +3,11 @@ mod tests; use crate::ffi::{c_int, c_void}; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::net::{ + Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, +}; use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::net::connection::each_addr; use crate::sys_common::{AsInner, FromInner}; use crate::time::Duration; use crate::{cmp, fmt, mem, ptr}; @@ -332,14 +335,15 @@ pub struct TcpStream { } impl TcpStream { - pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { - let addr = addr?; - + pub fn connect(addr: A) -> io::Result { init(); + return each_addr(addr, inner); - let sock = Socket::new(addr, c::SOCK_STREAM)?; - sock.connect(addr)?; - Ok(TcpStream { inner: sock }) + fn inner(addr: &SocketAddr) -> io::Result { + let sock = Socket::new(addr, c::SOCK_STREAM)?; + sock.connect(addr)?; + Ok(TcpStream { inner: sock }) + } } pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { @@ -502,46 +506,47 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result { - let addr = addr?; - + pub fn bind(addr: A) -> io::Result { init(); - - let sock = Socket::new(addr, c::SOCK_STREAM)?; - - // On platforms with Berkeley-derived sockets, this allows to quickly - // rebind a socket, without needing to wait for the OS to clean up the - // previous one. - // - // On Windows, this allows rebinding sockets which are actively in use, - // which allows “socket hijacking”, so we explicitly don't set it here. - // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse - #[cfg(not(windows))] - setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; - - // Bind our new socket - let (addr, len) = socket_addr_to_c(addr); - cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; - - cfg_if::cfg_if! { - if #[cfg(target_os = "horizon")] { - // The 3DS doesn't support a big connection backlog. Sometimes - // it allows up to about 37, but other times it doesn't even - // accept 32. There may be a global limitation causing this. - let backlog = 20; - } else if #[cfg(target_os = "haiku")] { - // Haiku does not support a queue length > 32 - // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81 - let backlog = 32; - } else { - // The default for all other platforms - let backlog = 128; + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result { + let sock = Socket::new(addr, c::SOCK_STREAM)?; + + // On platforms with Berkeley-derived sockets, this allows to quickly + // rebind a socket, without needing to wait for the OS to clean up the + // previous one. + // + // On Windows, this allows rebinding sockets which are actively in use, + // which allows “socket hijacking”, so we explicitly don't set it here. + // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse + #[cfg(not(windows))] + setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; + + // Bind our new socket + let (addr, len) = socket_addr_to_c(addr); + cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; + + cfg_if::cfg_if! { + if #[cfg(target_os = "horizon")] { + // The 3DS doesn't support a big connection backlog. Sometimes + // it allows up to about 37, but other times it doesn't even + // accept 32. There may be a global limitation causing this. + let backlog = 20; + } else if #[cfg(target_os = "haiku")] { + // Haiku does not support a queue length > 32 + // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81 + let backlog = 32; + } else { + // The default for all other platforms + let backlog = 128; + } } - } - // Start listening - cvt(unsafe { c::listen(sock.as_raw(), backlog) })?; - Ok(TcpListener { inner: sock }) + // Start listening + cvt(unsafe { c::listen(sock.as_raw(), backlog) })?; + Ok(TcpListener { inner: sock }) + } } #[inline] @@ -627,15 +632,16 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result { - let addr = addr?; - + pub fn bind(addr: A) -> io::Result { init(); + return each_addr(addr, inner); - let sock = Socket::new(addr, c::SOCK_DGRAM)?; - let (addr, len) = socket_addr_to_c(addr); - cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; - Ok(UdpSocket { inner: sock }) + fn inner(addr: &SocketAddr) -> io::Result { + let sock = Socket::new(addr, c::SOCK_DGRAM)?; + let (addr, len) = socket_addr_to_c(addr); + cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; + Ok(UdpSocket { inner: sock }) + } } #[inline] @@ -810,9 +816,13 @@ impl UdpSocket { Ok(ret as usize) } - pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { - let (addr, len) = socket_addr_to_c(addr?); - cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop) + pub fn connect(&self, addr: A) -> io::Result<()> { + return each_addr(addr, |addr| inner(self, addr)); + + fn inner(this: &UdpSocket, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = socket_addr_to_c(addr); + cvt_r(|| unsafe { c::connect(this.inner.as_raw(), addr.as_ptr(), len) }).map(drop) + } } } diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 16e3487a1747f..0036804287352 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -1,6 +1,7 @@ +use super::each_addr; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::{Arc, Mutex}; use crate::sys::unsupported; use crate::time::Duration; @@ -15,13 +16,17 @@ pub struct TcpStream { } impl TcpStream { - pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { - let inner = tcp::Tcp::connect(addr?, None)?; - Ok(Self { - inner, - read_timeout: Arc::new(Mutex::new(None)), - write_timeout: Arc::new(Mutex::new(None)), - }) + pub fn connect(addr: A) -> io::Result { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result { + let inner = tcp::Tcp::connect(addr, None)?; + Ok(TcpStream { + inner, + read_timeout: Arc::new(Mutex::new(None)), + write_timeout: Arc::new(Mutex::new(None)), + }) + } } pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { @@ -145,7 +150,7 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + pub fn bind(_: A) -> io::Result { unsupported() } @@ -195,7 +200,7 @@ impl fmt::Debug for TcpListener { pub struct UdpSocket(!); impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + pub fn bind(_: A) -> io::Result { unsupported() } @@ -315,7 +320,7 @@ impl UdpSocket { self.0 } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect(&self, _: A) -> io::Result<()> { self.0 } } diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index da2174396266f..fbc86343272fc 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -1,13 +1,13 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sys::unsupported; use crate::time::Duration; pub struct TcpStream(!); impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { + pub fn connect(_: A) -> io::Result { unsupported() } @@ -121,7 +121,7 @@ impl fmt::Debug for TcpStream { pub struct TcpListener(!); impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + pub fn bind(_: A) -> io::Result { unsupported() } @@ -171,7 +171,7 @@ impl fmt::Debug for TcpListener { pub struct UdpSocket(!); impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + pub fn bind(_: A) -> io::Result { unsupported() } @@ -291,7 +291,7 @@ impl UdpSocket { self.0 } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect(&self, _: A) -> io::Result<()> { self.0 } } diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index 951dc65e5b47d..cdfa25c8a4407 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -2,7 +2,7 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::WasiFd; use crate::sys::{err2io, unsupported}; @@ -60,7 +60,7 @@ impl FromRawFd for Socket { } impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result { + pub fn connect(_: A) -> io::Result { unsupported() } @@ -212,7 +212,7 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + pub fn bind(_: A) -> io::Result { unsupported() } @@ -316,7 +316,7 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result { + pub fn bind(_: A) -> io::Result { unsupported() } @@ -436,7 +436,7 @@ impl UdpSocket { unsupported() } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect(&self, _: A) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/net/connection/xous/tcplistener.rs b/library/std/src/sys/net/connection/xous/tcplistener.rs index bdf1fcd9302b7..8818ef2ca9a9b 100644 --- a/library/std/src/sys/net/connection/xous/tcplistener.rs +++ b/library/std/src/sys/net/connection/xous/tcplistener.rs @@ -2,9 +2,10 @@ use core::convert::TryInto; use core::sync::atomic::{Atomic, AtomicBool, AtomicU16, AtomicUsize, Ordering}; use super::*; -use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; use crate::os::xous::services; use crate::sync::Arc; +use crate::sys::net::connection::each_addr; use crate::{fmt, io}; macro_rules! unimpl { @@ -25,16 +26,19 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result { - let mut addr = *socketaddr?; - - let fd = TcpListener::bind_inner(&mut addr)?; - return Ok(TcpListener { - fd: Arc::new(AtomicU16::new(fd)), - local: addr, - handle_count: Arc::new(AtomicUsize::new(1)), - nonblocking: Arc::new(AtomicBool::new(false)), - }); + pub fn bind(addr: A) -> io::Result { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result { + let mut addr = *addr; + let fd = TcpListener::bind_inner(&mut addr)?; + Ok(TcpListener { + fd: Arc::new(AtomicU16::new(fd)), + local: addr, + handle_count: Arc::new(AtomicUsize::new(1)), + nonblocking: Arc::new(AtomicBool::new(false)), + }) + } } /// This returns the raw fd of a Listener, so that it can also be used by the diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 5452476745265..4df75453d1f45 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -3,9 +3,12 @@ use core::sync::atomic::{Atomic, AtomicBool, AtomicU32, AtomicUsize, Ordering}; use super::*; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::net::{ + IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, +}; use crate::os::xous::services; use crate::sync::Arc; +use crate::sys::net::connection::each_addr; use crate::time::Duration; macro_rules! unimpl { @@ -79,8 +82,8 @@ impl TcpStream { } } - pub fn connect(socketaddr: io::Result<&SocketAddr>) -> io::Result { - Self::connect_timeout(socketaddr?, Duration::ZERO) + pub fn connect(addr: A) -> io::Result { + each_addr(addr, |addr| Self::connect_timeout(addr, Duration::ZERO)) } pub fn connect_timeout(addr: &SocketAddr, duration: Duration) -> io::Result { diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs index 2127d3267ed47..ce54ea3b79ef8 100644 --- a/library/std/src/sys/net/connection/xous/udp.rs +++ b/library/std/src/sys/net/connection/xous/udp.rs @@ -3,9 +3,10 @@ use core::sync::atomic::{Atomic, AtomicUsize, Ordering}; use super::*; use crate::cell::Cell; -use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; use crate::os::xous::services; use crate::sync::Arc; +use crate::sys::net::connection::each_addr; use crate::time::Duration; use crate::{fmt, io}; @@ -32,40 +33,45 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result { - let addr = socketaddr?; - // Construct the request - let mut connect_request = ConnectRequest { raw: [0u8; 4096] }; - - // Serialize the StdUdpBind structure. This is done "manually" because we don't want to - // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous. - let port_bytes = addr.port().to_le_bytes(); - connect_request.raw[0] = port_bytes[0]; - connect_request.raw[1] = port_bytes[1]; - match addr.ip() { - IpAddr::V4(addr) => { - connect_request.raw[2] = 4; - for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { - *dest = src; + pub fn bind(addr: A) -> io::Result { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result { + // Construct the request + let mut connect_request = ConnectRequest { raw: [0u8; 4096] }; + + // Serialize the StdUdpBind structure. This is done "manually" because we don't want to + // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous. + let port_bytes = addr.port().to_le_bytes(); + connect_request.raw[0] = port_bytes[0]; + connect_request.raw[1] = port_bytes[1]; + match addr.ip() { + IpAddr::V4(addr) => { + connect_request.raw[2] = 4; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } } - } - IpAddr::V6(addr) => { - connect_request.raw[2] = 6; - for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { - *dest = src; + IpAddr::V6(addr) => { + connect_request.raw[2] = 6; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } } } - } - let response = crate::os::xous::ffi::lend_mut( - services::net_server(), - services::NetLendMut::StdUdpBind.into(), - &mut connect_request.raw, - 0, - 4096, - ); + let response = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdUdpBind.into(), + &mut connect_request.raw, + 0, + 4096, + ); + + let Ok((_, valid)) = response else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response")); + }; - if let Ok((_, valid)) = response { // The first four bytes should be zero upon success, and will be nonzero // for an error. let response = connect_request.raw; @@ -87,8 +93,9 @@ impl UdpSocket { )); } } + let fd = response[1] as u16; - return Ok(UdpSocket { + Ok(UdpSocket { fd, local: *addr, remote: Cell::new(None), @@ -96,9 +103,8 @@ impl UdpSocket { write_timeout: Cell::new(0), handle_count: Arc::new(AtomicUsize::new(1)), nonblocking: Cell::new(false), - }); + }) } - Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response")) } pub fn peer_addr(&self) -> io::Result { @@ -198,10 +204,11 @@ impl UdpSocket { self.peek_from(buf).map(|(len, _addr)| len) } - pub fn connect(&self, maybe_addr: io::Result<&SocketAddr>) -> io::Result<()> { - let addr = maybe_addr?; - self.remote.set(Some(*addr)); - Ok(()) + pub fn connect(&self, addr: A) -> io::Result<()> { + each_addr(addr, |addr| { + self.remote.set(Some(*addr)); + Ok(()) + }) } pub fn send(&self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs index 646679a1cc8b9..0b0387e57928f 100644 --- a/library/std/src/sys/net/mod.rs +++ b/library/std/src/sys/net/mod.rs @@ -1,41 +1,2 @@ -cfg_if::cfg_if! { - if #[cfg(any( - all(target_family = "unix", not(target_os = "l4re")), - target_os = "windows", - target_os = "hermit", - all(target_os = "wasi", target_env = "p2"), - target_os = "solid_asp3", - ))] { - mod connection { - mod socket; - pub use socket::*; - } - } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { - mod connection { - mod sgx; - pub use sgx::*; - } - } else if #[cfg(all(target_os = "wasi", target_env = "p1"))] { - mod connection { - mod wasip1; - pub use wasip1::*; - } - } else if #[cfg(target_os = "xous")] { - mod connection { - mod xous; - pub use xous::*; - } - } else if #[cfg(target_os = "uefi")] { - mod connection { - mod uefi; - pub use uefi::*; - } - } else { - mod connection { - mod unsupported; - pub use unsupported::*; - } - } -} - +mod connection; pub use connection::*;