diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 469bfbb0d837f..163267be1e5c1 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -159,7 +159,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_DGRAM)?; Ok(UnixDatagram(inner)) } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 27428c9eb2855..5b4659e261883 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -71,7 +71,7 @@ impl UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; #[cfg(any( target_os = "windows", @@ -136,7 +136,7 @@ impl UnixListener { #[stable(feature = "unix_socket_abstract", since = "1.70.0")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; #[cfg(target_os = "linux")] const backlog: core::ffi::c_int = -1; #[cfg(not(target_os = "linux"))] diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index ea4171a7d2877..851ff7f08795b 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -105,7 +105,7 @@ impl UnixStream { #[stable(feature = "unix_socket", since = "1.10.0")] pub fn connect>(path: P) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; cvt(libc::connect(inner.as_raw_fd(), (&raw const addr) as *const _, len))?; @@ -139,7 +139,7 @@ impl UnixStream { #[stable(feature = "unix_socket_abstract", since = "1.70.0")] pub fn connect_addr(socket_addr: &SocketAddr) -> io::Result { unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let inner = Socket::new(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::connect( inner.as_raw_fd(), (&raw const socket_addr.addr) as *const _, diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index 5200eaa5786ad..2f5c6fa31d407 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -37,15 +37,7 @@ pub fn init() {} pub struct Socket(FileDesc); impl Socket { - pub fn new(addr: &SocketAddr, ty: i32) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: i32, ty: i32) -> io::Result { + pub fn new(fam: i32, ty: i32) -> io::Result { let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?; Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) })) } @@ -242,11 +234,11 @@ impl Socket { None => netc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, netc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: i32) -> io::Result> { - let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + let raw: netc::timeval = unsafe { getsockopt(self, netc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -272,22 +264,22 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as libc::c_int, }; - setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) + unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?; + let val: netc::linger = unsafe { 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, nodelay: bool) -> io::Result<()> { let value: i32 = if nodelay { 1 } else { 0 }; - setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value) + unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value) } } pub fn nodelay(&self) -> io::Result { - let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + let raw: i32 = unsafe { getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)? }; Ok(raw != 0) } @@ -304,7 +296,7 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; + let raw: c_int = unsafe { 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))) } } diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 1dd06e97bbabd..d0a4a2fab497d 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -3,6 +3,7 @@ mod tests; use crate::ffi::{c_int, c_void}; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; +use crate::mem::MaybeUninit; use crate::net::{ Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, }; @@ -177,6 +178,18 @@ fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) { } } +fn addr_family(addr: &SocketAddr) -> c_int { + match addr { + SocketAddr::V4(..) => c::AF_INET, + SocketAddr::V6(..) => c::AF_INET6, + } +} + +/// Converts the C socket address stored in `storage` to a Rust `SocketAddr`. +/// +/// # Safety +/// * `storage` must contain a valid C socket address whose length is no larger +/// than `len`. unsafe fn socket_addr_from_c( storage: *const c::sockaddr_storage, len: usize, @@ -202,49 +215,85 @@ unsafe fn socket_addr_from_c( // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// -pub fn setsockopt( +/// Sets the value of a socket option. +/// +/// # Safety +/// `T` must be the type associated with the given socket option. +pub unsafe fn setsockopt( sock: &Socket, level: c_int, option_name: c_int, option_value: T, ) -> io::Result<()> { - unsafe { - cvt(c::setsockopt( + let option_len = size_of::() as c::socklen_t; + // SAFETY: + // * `sock` is opened for the duration of this call, as `sock` owns the socket. + // * the pointer to `option_value` is readable at a size of `size_of::` + // bytes + // * the value of `option_value` has a valid type for the given socket option + // (guaranteed by caller). + cvt(unsafe { + c::setsockopt( sock.as_raw(), level, option_name, (&raw const option_value) as *const _, - size_of::() as c::socklen_t, - ))?; - Ok(()) - } + option_len, + ) + })?; + Ok(()) } -pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> io::Result { - unsafe { - let mut option_value: T = mem::zeroed(); - let mut option_len = size_of::() as c::socklen_t; - cvt(c::getsockopt( +/// Gets the value of a socket option. +/// +/// # Safety +/// `T` must be the type associated with the given socket option. +pub unsafe fn getsockopt( + sock: &Socket, + level: c_int, + option_name: c_int, +) -> io::Result { + let mut option_value = MaybeUninit::::zeroed(); + let mut option_len = size_of::() as c::socklen_t; + + // SAFETY: + // * `sock` is opened for the duration of this call, as `sock` owns the socket. + // * the pointer to `option_value` is writable and the stack allocation has + // space for `size_of::` bytes. + cvt(unsafe { + c::getsockopt( sock.as_raw(), level, option_name, - (&raw mut option_value) as *mut _, + option_value.as_mut_ptr().cast(), &mut option_len, - ))?; - Ok(option_value) - } -} - -fn sockname(f: F) -> io::Result + ) + })?; + + // SAFETY: the `getsockopt` call succeeded and the caller guarantees that + // `T` is the type of this option, thus `option_value` must have + // been initialized by the system. + Ok(unsafe { option_value.assume_init() }) +} + +/// Wraps a call to a platform function that returns a socket address. +/// +/// # Safety +/// * if `f` returns a success (i.e. `cvt` returns `Ok` when called on the +/// return value), the buffer provided to `f` must have been initialized +/// with a valid C socket address, the length of which must be written +/// to the second argument. +unsafe fn sockname(f: F) -> io::Result where F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int, { - unsafe { - let mut storage: c::sockaddr_storage = mem::zeroed(); - let mut len = size_of_val(&storage) as c::socklen_t; - cvt(f((&raw mut storage) as *mut _, &mut len))?; - socket_addr_from_c(&storage, len as usize) - } + let mut storage = MaybeUninit::::zeroed(); + let mut len = size_of::() as c::socklen_t; + cvt(f(storage.as_mut_ptr().cast(), &mut len))?; + // SAFETY: + // The caller guarantees that the storage has been successfully initialized + // and its size written to `len` if `f` returns a success. + unsafe { socket_addr_from_c(storage.as_ptr(), len as usize) } } #[cfg(target_os = "android")] @@ -322,7 +371,7 @@ impl TcpStream { return each_addr(addr, inner); fn inner(addr: &SocketAddr) -> io::Result { - let sock = Socket::new(addr, c::SOCK_STREAM)?; + let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?; sock.connect(addr)?; Ok(TcpStream { inner: sock }) } @@ -331,7 +380,7 @@ impl TcpStream { pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { init(); - let sock = Socket::new(addr, c::SOCK_STREAM)?; + let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?; sock.connect_timeout(addr, timeout)?; Ok(TcpStream { inner: sock }) } @@ -400,11 +449,11 @@ impl TcpStream { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getpeername(self.inner.as_raw(), buf, len)) } } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) } } pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { @@ -432,11 +481,11 @@ impl TcpStream { } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) } } pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? }; Ok(raw as u32) } @@ -493,7 +542,7 @@ impl TcpListener { return each_addr(addr, inner); fn inner(addr: &SocketAddr) -> io::Result { - let sock = Socket::new(addr, c::SOCK_STREAM)?; + let sock = Socket::new(addr_family(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 @@ -503,7 +552,9 @@ impl TcpListener { // 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)?; + unsafe { + setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)? + }; // Bind our new socket let (addr, len) = socket_addr_to_c(addr); @@ -539,15 +590,15 @@ impl TcpListener { } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) } } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { // The `accept` function will fill in the storage with the address, // so we don't need to zero it here. // reference: https://linux.die.net/man/2/accept4 - let mut storage: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let mut len = size_of_val(&storage) as c::socklen_t; + let mut storage = MaybeUninit::::uninit(); + let mut len = size_of::() as c::socklen_t; let sock = self.inner.accept(storage.as_mut_ptr() as *mut _, &mut len)?; let addr = unsafe { socket_addr_from_c(storage.as_ptr(), len as usize)? }; Ok((TcpStream { inner: sock }, addr)) @@ -558,20 +609,20 @@ impl TcpListener { } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) } } pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? }; Ok(raw as u32) } pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int) } } pub fn only_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)? }; Ok(raw != 0) } @@ -617,7 +668,7 @@ impl UdpSocket { return each_addr(addr, inner); fn inner(addr: &SocketAddr) -> io::Result { - let sock = Socket::new(addr, c::SOCK_DGRAM)?; + let sock = Socket::new(addr_family(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 }) @@ -634,11 +685,11 @@ impl UdpSocket { } pub fn peer_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getpeername(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getpeername(self.inner.as_raw(), buf, len)) } } pub fn socket_addr(&self) -> io::Result { - sockname(|buf, len| unsafe { c::getsockname(self.inner.as_raw(), buf, len) }) + unsafe { sockname(|buf, len| c::getsockname(self.inner.as_raw(), buf, len)) } } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { @@ -686,48 +737,62 @@ impl UdpSocket { } pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { - setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int) + unsafe { setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int) } } pub fn broadcast(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)? }; Ok(raw != 0) } pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - setsockopt( - &self.inner, - c::IPPROTO_IP, - c::IP_MULTICAST_LOOP, - multicast_loop_v4 as IpV4MultiCastType, - ) + unsafe { + setsockopt( + &self.inner, + c::IPPROTO_IP, + c::IP_MULTICAST_LOOP, + multicast_loop_v4 as IpV4MultiCastType, + ) + } } pub fn multicast_loop_v4(&self) -> io::Result { - let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?; + let raw: IpV4MultiCastType = + unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)? }; Ok(raw != 0) } pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - setsockopt( - &self.inner, - c::IPPROTO_IP, - c::IP_MULTICAST_TTL, - multicast_ttl_v4 as IpV4MultiCastType, - ) + unsafe { + setsockopt( + &self.inner, + c::IPPROTO_IP, + c::IP_MULTICAST_TTL, + multicast_ttl_v4 as IpV4MultiCastType, + ) + } } pub fn multicast_ttl_v4(&self) -> io::Result { - let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?; + let raw: IpV4MultiCastType = + unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)? }; Ok(raw as u32) } pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int) + unsafe { + setsockopt( + &self.inner, + c::IPPROTO_IPV6, + c::IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int, + ) + } } pub fn multicast_loop_v6(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?; + let raw: c_int = + unsafe { getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)? }; Ok(raw != 0) } @@ -736,7 +801,7 @@ impl UdpSocket { imr_multiaddr: ip_v4_addr_to_c(multiaddr), imr_interface: ip_v4_addr_to_c(interface), }; - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq) } } pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { @@ -744,7 +809,7 @@ impl UdpSocket { ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr), ipv6mr_interface: to_ipv6mr_interface(interface), }; - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) } } pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { @@ -752,7 +817,7 @@ impl UdpSocket { imr_multiaddr: ip_v4_addr_to_c(multiaddr), imr_interface: ip_v4_addr_to_c(interface), }; - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq) } } pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { @@ -760,15 +825,15 @@ impl UdpSocket { ipv6mr_multiaddr: ip_v6_addr_to_c(multiaddr), ipv6mr_interface: to_ipv6mr_interface(interface), }; - setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) + unsafe { setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) } } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) + unsafe { setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int) } } pub fn ttl(&self) -> io::Result { - let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?; + let raw: c_int = unsafe { getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)? }; Ok(raw as u32) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 94bb605c1007c..14cf75adcc06f 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -115,19 +115,9 @@ pub fn init() {} pub struct Socket(OwnedFd); impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - unsafe { - let fd = cvt(netc::socket(fam, ty, 0))?; - Ok(Self::from_raw_fd(fd)) - } + pub fn new(fam: c_int, ty: c_int) -> io::Result { + let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) } pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { @@ -303,11 +293,11 @@ impl Socket { } None => netc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, netc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + let raw: netc::timeval = unsafe { getsockopt(self, netc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -333,21 +323,21 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as netc::c_int, }; - setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) + unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?; + let val: netc::linger = unsafe { 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, nodelay: bool) -> io::Result<()> { - setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) } } pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + let raw: c_int = unsafe { getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)? }; Ok(raw != 0) } @@ -360,7 +350,7 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index a191576d93b9d..559e27604a9d3 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -63,56 +63,46 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { } impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - unsafe { - cfg_select! { - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "illumos", - target_os = "hurd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "nto", - target_os = "solaris", - ) => { - // On platforms that support it we pass the SOCK_CLOEXEC - // 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))?; - let socket = Socket(FileDesc::from_raw_fd(fd)); - - // DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt` - // flag to disable `SIGPIPE` emission on socket. - #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly"))] - setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; - - Ok(socket) - } - _ => { - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::from_raw_fd(fd); - fd.set_cloexec()?; - let socket = Socket(fd); + pub fn new(family: c_int, ty: c_int) -> io::Result { + cfg_select! { + any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "illumos", + target_os = "hurd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "nto", + target_os = "solaris", + ) => { + // On platforms that support it we pass the SOCK_CLOEXEC + // flag to atomically create the socket and set it as + // CLOEXEC. On Linux this was added in 2.6.27. + let fd = cvt(unsafe { libc::socket(family, ty | libc::SOCK_CLOEXEC, 0) })?; + let socket = Socket(unsafe { FileDesc::from_raw_fd(fd) }); + + // DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly"))] + unsafe { setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)? }; + + Ok(socket) + } + _ => { + let fd = cvt(unsafe { libc::socket(family, ty, 0) })?; + let fd = unsafe { FileDesc::from_raw_fd(fd) }; + fd.set_cloexec()?; + let socket = Socket(fd); - // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` - // flag to disable `SIGPIPE` emission on socket. - #[cfg(target_vendor = "apple")] - setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(target_vendor = "apple")] + unsafe { setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)? }; - Ok(socket) - } + Ok(socket) } } } @@ -413,11 +403,11 @@ impl Socket { } None => libc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, libc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: libc::c_int) -> io::Result> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; + let raw: libc::timeval = unsafe { getsockopt(self, libc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -444,7 +434,7 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as libc::c_int, }; - setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) + unsafe { setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) } } #[cfg(target_os = "cygwin")] @@ -454,32 +444,32 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as libc::c_ushort, }; - setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) + unsafe { setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?; + let val: libc::linger = unsafe { getsockopt(self, libc::SOL_SOCKET, SO_LINGER)? }; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) + unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } } pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; + let raw: c_int = unsafe { getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)? }; Ok(raw != 0) } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn set_quickack(&self, quickack: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int) + unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int) } } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn quickack(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)?; + let raw: c_int = unsafe { getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)? }; Ok(raw != 0) } @@ -487,12 +477,12 @@ impl Socket { #[cfg(target_os = "linux")] pub fn set_deferaccept(&self, accept: Duration) -> io::Result<()> { let val = cmp::min(accept.as_secs(), c_int::MAX as u64) as c_int; - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, val) + unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, val) } } #[cfg(target_os = "linux")] pub fn deferaccept(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)?; + let raw: c_int = unsafe { getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)? }; Ok(Duration::from_secs(raw as _)) } @@ -506,21 +496,23 @@ impl Socket { } let mut arg: libc::accept_filter_arg = unsafe { mem::zeroed() }; arg.af_name = buf; - setsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER, &mut arg) + unsafe { setsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER, &mut arg) } } else { - setsockopt( - self, - libc::SOL_SOCKET, - libc::SO_ACCEPTFILTER, - core::ptr::null_mut() as *mut c_void, - ) + unsafe { + setsockopt( + self, + libc::SOL_SOCKET, + libc::SO_ACCEPTFILTER, + core::ptr::null_mut() as *mut c_void, + ) + } } } #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] pub fn acceptfilter(&self) -> io::Result<&CStr> { let arg: libc::accept_filter_arg = - getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)?; + unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)? }; let s: &[u8] = unsafe { core::slice::from_raw_parts(arg.af_name.as_ptr() as *const u8, 16) }; let name = CStr::from_bytes_with_nul(s).unwrap(); @@ -531,53 +523,57 @@ impl Socket { pub fn set_exclbind(&self, excl: bool) -> io::Result<()> { // not yet on libc crate const SO_EXCLBIND: i32 = 0x1015; - setsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND, excl) + unsafe { setsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND, excl) } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn exclbind(&self) -> io::Result { // not yet on libc crate const SO_EXCLBIND: i32 = 0x1015; - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND)?; + let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, SO_EXCLBIND)? }; Ok(raw != 0) } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { - setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) + unsafe { setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) } } #[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))] pub fn passcred(&self) -> io::Result { - let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; + let passcred: libc::c_int = + unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)? }; Ok(passcred != 0) } #[cfg(target_os = "netbsd")] pub fn set_local_creds(&self, local_creds: bool) -> io::Result<()> { - setsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS, local_creds as libc::c_int) + unsafe { setsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS, local_creds as libc::c_int) } } #[cfg(target_os = "netbsd")] pub fn local_creds(&self) -> io::Result { - let local_creds: libc::c_int = getsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS)?; + let local_creds: libc::c_int = + unsafe { getsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS)? }; Ok(local_creds != 0) } #[cfg(target_os = "freebsd")] pub fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> { - setsockopt( - self, - libc::AF_LOCAL, - libc::LOCAL_CREDS_PERSISTENT, - local_creds_persistent as libc::c_int, - ) + unsafe { + setsockopt( + self, + libc::AF_LOCAL, + libc::LOCAL_CREDS_PERSISTENT, + local_creds_persistent as libc::c_int, + ) + } } #[cfg(target_os = "freebsd")] pub fn local_creds_persistent(&self) -> io::Result { let local_creds_persistent: libc::c_int = - getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)?; + unsafe { getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)? }; Ok(local_creds_persistent != 0) } @@ -590,7 +586,7 @@ impl Socket { #[cfg(target_os = "vita")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let option = nonblocking as libc::c_int; - setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option) + unsafe { setsockopt(self, libc::SOL_SOCKET, libc::SO_NONBLOCK, option) } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] @@ -608,11 +604,11 @@ impl Socket { let option = libc::SO_USER_COOKIE; #[cfg(target_os = "openbsd")] let option = libc::SO_RTABLE; - setsockopt(self, libc::SOL_SOCKET, option, mark as libc::c_int) + unsafe { setsockopt(self, libc::SOL_SOCKET, option, mark as libc::c_int) } } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; + let raw: c_int = unsafe { 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))) } } diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index c77c50fece1a9..a1b08609eb024 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -74,16 +74,8 @@ pub struct WasiSocket(OwnedFd); pub struct Socket(WasiSocket); impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let fam = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { - let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?; + pub fn new(family: c_int, ty: c_int) -> io::Result { + let fd = cvt(unsafe { netc::socket(family, ty, 0) })?; Ok(unsafe { Self::from_raw_fd(fd) }) } @@ -270,11 +262,11 @@ impl Socket { } None => netc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, netc::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, netc::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + let raw: netc::timeval = unsafe { getsockopt(self, netc::SOL_SOCKET, kind)? }; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -303,11 +295,11 @@ impl Socket { } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + unsafe { setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) } } pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + let raw: c_int = unsafe { getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)? }; Ok(raw != 0) } @@ -317,7 +309,7 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 5b6f4cedf1b77..6dbebc5e276ec 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -111,17 +111,13 @@ pub(super) mod netc { } } -pub use crate::sys::pal::winsock::{cleanup, cvt, cvt_gai, cvt_r, startup as init}; +pub use crate::sys::pal::winsock::{cvt, cvt_gai, cvt_r, startup as init}; #[expect(missing_debug_implementations)] pub struct Socket(OwnedSocket); impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { - let family = match *addr { - SocketAddr::V4(..) => netc::AF_INET, - SocketAddr::V6(..) => netc::AF_INET6, - }; + pub fn new(family: c_int, ty: c_int) -> io::Result { let socket = unsafe { c::WSASocketW( family, @@ -384,11 +380,11 @@ impl Socket { } None => 0, }; - setsockopt(self, c::SOL_SOCKET, kind, timeout) + unsafe { setsockopt(self, c::SOL_SOCKET, kind, timeout) } } pub fn timeout(&self, kind: c_int) -> io::Result> { - let raw: u32 = getsockopt(self, c::SOL_SOCKET, kind)?; + let raw: u32 = unsafe { getsockopt(self, c::SOL_SOCKET, kind)? }; if raw == 0 { Ok(None) } else { @@ -421,26 +417,26 @@ impl Socket { l_linger: linger.unwrap_or_default().as_secs() as c_ushort, }; - setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) + unsafe { setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger) } } pub fn linger(&self) -> io::Result> { - let val: c::LINGER = getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + let val: c::LINGER = unsafe { getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)? }; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) + unsafe { setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) } } pub fn nodelay(&self) -> io::Result { - let raw: c::BOOL = getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; + let raw: c::BOOL = unsafe { getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)? }; Ok(raw != 0) } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)?; + let raw: c_int = unsafe { getsockopt(self, c::SOL_SOCKET, c::SO_ERROR)? }; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 18ab34982676c..a5f060080130f 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -58,7 +58,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { // SAFETY: must be called only once during runtime cleanup. // NOTE: this is not guaranteed to run, for example when the program aborts. pub unsafe fn cleanup() { - crate::sys::net::cleanup(); + winsock::cleanup(); } #[inline]