From 9ac52d577763cc7a10cccec5d93f8a6fd50071af Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:47:53 +0800 Subject: [PATCH 01/15] windows uds --- library/std/src/os/windows/mod.rs | 1 + library/std/src/os/windows/net/addr.rs | 83 +++++++++++++ library/std/src/os/windows/net/listener.rs | 94 +++++++++++++++ library/std/src/os/windows/net/mod.rs | 8 ++ library/std/src/os/windows/net/stream.rs | 114 ++++++++++++++++++ .../src/sys/net/connection/socket/windows.rs | 18 +++ library/std/src/sys/pal/windows/c.rs | 10 +- library/std/tests/net/windows_unix_socket.rs | 67 ++++++++++ 8 files changed, 394 insertions(+), 1 deletion(-) create mode 100644 library/std/src/os/windows/net/addr.rs create mode 100644 library/std/src/os/windows/net/listener.rs create mode 100644 library/std/src/os/windows/net/mod.rs create mode 100644 library/std/src/os/windows/net/stream.rs create mode 100644 library/std/tests/net/windows_unix_socket.rs diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs index f452403ee8426..5740f65bacef1 100644 --- a/library/std/src/os/windows/mod.rs +++ b/library/std/src/os/windows/mod.rs @@ -29,6 +29,7 @@ pub mod ffi; pub mod fs; pub mod io; +pub mod net; pub mod process; pub mod raw; pub mod thread; diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs new file mode 100644 index 0000000000000..1289aedcc547d --- /dev/null +++ b/library/std/src/os/windows/net/addr.rs @@ -0,0 +1,83 @@ +#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")] + +use crate::os::raw::{c_char, c_int}; +use crate::path::Path; +use crate::sys::c::{self, SOCKADDR}; +use crate::sys::cvt; +use crate::{io, mem}; +pub fn sockaddr_un(path: &Path) -> io::Result<(c::sockaddr_un, c_int)> { + let mut addr: c::sockaddr_un = unsafe { mem::zeroed() }; + addr.sun_family = c::AF_UNIX; + // Winsock2 expects 'sun_path' to be a Win32 UTF-8 file system path + let bytes = path + .to_str() + .map(|s| s.as_bytes()) + .ok_or(io::Error::new(io::ErrorKind::InvalidInput, "path contains invalid characters"))?; + + if bytes.contains(&0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "paths may not contain interior null bytes", + )); + } + + if bytes.len() >= addr.sun_path.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { + *dst = *src as c_char; + } + // null byte for pathname addresses is already there because we zeroed the + // struct + + let mut len = sun_path_offset(&addr) + bytes.len(); + match bytes.first() { + Some(&0) | None => {} + Some(_) => len += 1, + } + Ok((addr, len as _)) +} +fn sun_path_offset(addr: &c::sockaddr_un) -> usize { + // Work with an actual instance of the type since using a null pointer is UB + let base = addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base +} +#[allow(dead_code)] +pub struct SocketAddr { + addr: c::sockaddr_un, + len: c_int, +} +impl SocketAddr { + pub fn new(f: F) -> io::Result + where + F: FnOnce(*mut SOCKADDR, *mut c_int) -> c_int, + { + unsafe { + let mut addr: c::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as c_int; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + fn from_parts(addr: c::sockaddr_un, mut len: c_int) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset(&addr) as c_int; // i.e. zero-length address + } else if addr.sun_family != c::AF_UNIX { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket", + )); + } + + Ok(SocketAddr { addr, len }) + } +} +pub fn from_sockaddr_un(addr: c::sockaddr_un, len: c_int) -> io::Result { + SocketAddr::from_parts(addr, len) +} diff --git a/library/std/src/os/windows/net/listener.rs b/library/std/src/os/windows/net/listener.rs new file mode 100644 index 0000000000000..815c798bddfa9 --- /dev/null +++ b/library/std/src/os/windows/net/listener.rs @@ -0,0 +1,94 @@ +#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")] + +use core::mem; + +use super::sockaddr_un; +use crate::io; +use crate::os::raw::c_int; +use crate::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; +use crate::os::windows::net::{SocketAddr, UnixStream, from_sockaddr_un}; +use crate::path::Path; +use crate::sys::c::{self, bind, getsockname, listen}; +use crate::sys::cvt; +use crate::sys::net::Socket; + +pub struct UnixListener(Socket); + +impl UnixListener { + pub fn bind>(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_unix()?; + let (addr, len) = sockaddr_un(path)?; + cvt(bind(inner.as_raw(), &addr as *const _ as *const _, len))?; + cvt(listen(inner.as_raw(), 128))?; + Ok(UnixListener(inner)) + } + } + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: c::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as c_int; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = from_sockaddr_un(storage, len)?; + Ok((UnixStream(sock), addr)) + } + pub fn incoming(&self) -> Incoming<'_> { + Incoming { listener: self } + } + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw() as _, addr, len) }) + } + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } +} + +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} + +impl AsRawSocket for UnixListener { + fn as_raw_socket(&self) -> RawSocket { + self.0.as_raw_socket() + } +} + +impl FromRawSocket for UnixListener { + unsafe fn from_raw_socket(sock: RawSocket) -> Self { + UnixListener(unsafe { Socket::from_raw_socket(sock) }) + } +} + +impl IntoRawSocket for UnixListener { + fn into_raw_socket(self) -> RawSocket { + let ret = self.0.as_raw_socket(); + mem::forget(self); + ret + } +} + +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} diff --git a/library/std/src/os/windows/net/mod.rs b/library/std/src/os/windows/net/mod.rs new file mode 100644 index 0000000000000..fe7ec8885907c --- /dev/null +++ b/library/std/src/os/windows/net/mod.rs @@ -0,0 +1,8 @@ +#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")] + +mod addr; +mod listener; +mod stream; +pub use addr::*; +pub use listener::*; +pub use stream::*; diff --git a/library/std/src/os/windows/net/stream.rs b/library/std/src/os/windows/net/stream.rs new file mode 100644 index 0000000000000..b618123d4f633 --- /dev/null +++ b/library/std/src/os/windows/net/stream.rs @@ -0,0 +1,114 @@ +#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")] + +use core::mem; +use core::time::Duration; + +use crate::io::{self, IoSlice}; +use crate::net::Shutdown; +use crate::os::windows::io::{ + AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, RawSocket, +}; +use crate::os::windows::net::{SocketAddr, sockaddr_un}; +use crate::path::Path; +use crate::sys::c::{SO_RCVTIMEO, SO_SNDTIMEO, connect, getpeername, getsockname}; +use crate::sys::cvt; +use crate::sys::net::Socket; + +pub struct UnixStream(pub Socket); +impl UnixStream { + pub fn connect>(path: P) -> io::Result { + unsafe { + let inner = Socket::new_unix()?; + let (addr, len) = sockaddr_un(path.as_ref())?; + cvt(connect(inner.as_raw() as _, &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw() as _, addr, len) }) + } + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { getpeername(self.0.as_raw() as _, addr, len) }) + } + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(SO_RCVTIMEO) + } + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { + self.0.set_timeout(dur, SO_RCVTIMEO) + } + pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { + self.0.set_timeout(dur, SO_SNDTIMEO) + } + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(SO_SNDTIMEO) + } +} + +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } +} + +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } +} + +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write_vectored(&[IoSlice::new(buf)]) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl AsSocket for UnixStream { + fn as_socket(&self) -> BorrowedSocket<'_> { + self.0.as_socket() + } +} + +impl AsRawSocket for UnixStream { + fn as_raw_socket(&self) -> RawSocket { + self.0.as_raw_socket() + } +} + +impl FromRawSocket for UnixStream { + unsafe fn from_raw_socket(sock: RawSocket) -> Self { + unsafe { UnixStream(Socket::from_raw_socket(sock)) } + } +} + +impl IntoRawSocket for UnixStream { + fn into_raw_socket(self) -> RawSocket { + let ret = self.0.as_raw_socket(); + mem::forget(self); + ret + } +} diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 6dbebc5e276ec..3ec4b16ec620c 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -9,6 +9,7 @@ use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; use crate::sys::c; +use crate::sys::c::{AF_UNIX, INVALID_SOCKET, SOCK_STREAM, WSA_FLAG_OVERLAPPED, WSASocketW}; use crate::sys::pal::winsock::last_error; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; @@ -117,6 +118,23 @@ pub use crate::sys::pal::winsock::{cvt, cvt_gai, cvt_r, startup as init}; pub struct Socket(OwnedSocket); impl Socket { + pub fn new_unix() -> io::Result { + let socket = unsafe { + match WSASocketW( + AF_UNIX as i32, + SOCK_STREAM, + 0, + ptr::null_mut(), + 0, + WSA_FLAG_OVERLAPPED, + ) { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket::from_raw(n)), + } + }?; + socket.0.set_no_inherit()?; + Ok(socket) + } pub fn new(family: c_int, ty: c_int) -> io::Result { let socket = unsafe { c::WSASocketW( diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 25c1a82cc426a..9dec28a88886c 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -11,8 +11,16 @@ use core::ptr; mod windows_sys; pub use windows_sys::*; -pub type WCHAR = u16; +use crate::os::raw::c_char; +pub type WCHAR = u16; +pub const AF_UNIX: ADDRESS_FAMILY = 1; +#[derive(Clone, Copy)] +#[repr(C)] +pub struct sockaddr_un { + pub sun_family: ADDRESS_FAMILY, + pub sun_path: [c_char; 108], +} pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _); // https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170 diff --git a/library/std/tests/net/windows_unix_socket.rs b/library/std/tests/net/windows_unix_socket.rs new file mode 100644 index 0000000000000..51bddf0b18ba3 --- /dev/null +++ b/library/std/tests/net/windows_unix_socket.rs @@ -0,0 +1,67 @@ +#![cfg(all(windows, feature = "windows_unix_domain_sockets"))] +#![unstable(feature = "windows_unix_domain_sockets", issue = "none")] + +use std::io::{Read, Write}; +use std::os::windows::net::{UnixListener, UnixStream}; +use std::path::Path; +use std::thread; + +#[test] +fn smoke_bind_connect() { + let tmp = std::env::temp_dir(); + let sock_path = tmp.join("rust-test-uds.sock"); + + let listener = UnixListener::bind(&sock_path).expect("bind failed"); + + let tx = thread::spawn(move || { + let mut stream = UnixStream::connect(&sock_path).expect("connect failed"); + stream.write_all(b"hello").expect("write failed"); + }); + + let (mut stream, _) = listener.accept().expect("accept failed"); + let mut buf = [0; 5]; + stream.read_exact(&mut buf).expect("read failed"); + assert_eq!(&buf, b"hello"); + + tx.join().unwrap; + + drop(listener); + let _ = std::fs::remove_file(&sock_path); +} + +#[test] +fn echo() { + let tmp = std::env::temp_dir(); + let sock_path = tmp.join("rust-test-uds-echo.sock"); + + let listener = UnixListener::bind(&sock_path).unwrap(); + + let tx = thread::spawn(move || { + let (mut stream, _) = listener.accept().unwrap; + let mut buf = [0; 1024]; + loop { + let n = match stream.read(&mut buf) { + Ok(0) => return, + Ok(n) => n, + Err(e) => panic!("read error: {}", e), + }; + stream.write_all(&buf[..n]).unwrap; + } + }); + + let mut client = UnixStream::connect(&sock_path).unwrap; + client.write_all(b"echo").unwrap; + let mut buf = [0; 4]; + client.read_exact(&mut buf).unwrap; + assert_eq!(&buf, b"echo"); + + drop(client); + tx.join().unwrap; + let _ = std::fs::remove_file(&sock_path); +} + +#[test] +fn path_too_long() { + let long = "\\\\?\\".to_string() + &"a".repeat(300); + assert!(UnixListener::bind(long).is_err()); +} From e73728c941beed312817c89560b4cf6780a00e92 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Sat, 4 Oct 2025 21:25:35 +0800 Subject: [PATCH 02/15] cfg windows --- library/std/src/os/windows/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs index 5740f65bacef1..9e078e3364093 100644 --- a/library/std/src/os/windows/mod.rs +++ b/library/std/src/os/windows/mod.rs @@ -29,6 +29,7 @@ pub mod ffi; pub mod fs; pub mod io; +#[cfg(windows)] pub mod net; pub mod process; pub mod raw; From 9abface8bc5eef9a36ba0d0e689f1db10e78677e Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Wed, 8 Oct 2025 10:51:37 +0800 Subject: [PATCH 03/15] move file --- library/std/tests/{net => }/windows_unix_socket.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename library/std/tests/{net => }/windows_unix_socket.rs (100%) diff --git a/library/std/tests/net/windows_unix_socket.rs b/library/std/tests/windows_unix_socket.rs similarity index 100% rename from library/std/tests/net/windows_unix_socket.rs rename to library/std/tests/windows_unix_socket.rs From a6492658f15f868655f7e511982cf6b9626a7b68 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Wed, 8 Oct 2025 11:31:49 +0800 Subject: [PATCH 04/15] fix wrong generic --- library/std/Cargo.toml | 2 +- library/std/src/os/windows/net/listener.rs | 2 +- library/std/tests/windows_unix_socket.rs | 46 ++-------------------- 3 files changed, 6 insertions(+), 44 deletions(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 685c2cf162abd..f4f377c884978 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -134,7 +134,7 @@ std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] # Enable using raw-dylib for Windows imports. # This will eventually be the default. windows_raw_dylib = ["windows-targets/windows_raw_dylib"] - +windows_unix_domain_sockets = [] [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing threads = 125 diff --git a/library/std/src/os/windows/net/listener.rs b/library/std/src/os/windows/net/listener.rs index 815c798bddfa9..d317358016258 100644 --- a/library/std/src/os/windows/net/listener.rs +++ b/library/std/src/os/windows/net/listener.rs @@ -15,7 +15,7 @@ use crate::sys::net::Socket; pub struct UnixListener(Socket); impl UnixListener { - pub fn bind>(path: &Path) -> io::Result { + pub fn bind>(path: P) -> io::Result { unsafe { let inner = Socket::new_unix()?; let (addr, len) = sockaddr_un(path)?; diff --git a/library/std/tests/windows_unix_socket.rs b/library/std/tests/windows_unix_socket.rs index 51bddf0b18ba3..b1830dc74c4c1 100644 --- a/library/std/tests/windows_unix_socket.rs +++ b/library/std/tests/windows_unix_socket.rs @@ -1,9 +1,8 @@ -#![cfg(all(windows, feature = "windows_unix_domain_sockets"))] -#![unstable(feature = "windows_unix_domain_sockets", issue = "none")] +#![cfg(windows)] +#![feature(windows_unix_domain_sockets)] use std::io::{Read, Write}; use std::os::windows::net::{UnixListener, UnixStream}; -use std::path::Path; use std::thread; #[test] @@ -11,7 +10,7 @@ fn smoke_bind_connect() { let tmp = std::env::temp_dir(); let sock_path = tmp.join("rust-test-uds.sock"); - let listener = UnixListener::bind(&sock_path).expect("bind failed"); + let listener = UnixListener::bind(sock_path.as_path()).expect("bind failed"); let tx = thread::spawn(move || { let mut stream = UnixStream::connect(&sock_path).expect("connect failed"); @@ -23,45 +22,8 @@ fn smoke_bind_connect() { stream.read_exact(&mut buf).expect("read failed"); assert_eq!(&buf, b"hello"); - tx.join().unwrap; + tx.join().unwrap(); drop(listener); let _ = std::fs::remove_file(&sock_path); } - -#[test] -fn echo() { - let tmp = std::env::temp_dir(); - let sock_path = tmp.join("rust-test-uds-echo.sock"); - - let listener = UnixListener::bind(&sock_path).unwrap(); - - let tx = thread::spawn(move || { - let (mut stream, _) = listener.accept().unwrap; - let mut buf = [0; 1024]; - loop { - let n = match stream.read(&mut buf) { - Ok(0) => return, - Ok(n) => n, - Err(e) => panic!("read error: {}", e), - }; - stream.write_all(&buf[..n]).unwrap; - } - }); - - let mut client = UnixStream::connect(&sock_path).unwrap; - client.write_all(b"echo").unwrap; - let mut buf = [0; 4]; - client.read_exact(&mut buf).unwrap; - assert_eq!(&buf, b"echo"); - - drop(client); - tx.join().unwrap; - let _ = std::fs::remove_file(&sock_path); -} - -#[test] -fn path_too_long() { - let long = "\\\\?\\".to_string() + &"a".repeat(300); - assert!(UnixListener::bind(long).is_err()); -} From 852a4ce425635668d98fc7210d800ca61de9f693 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Wed, 8 Oct 2025 11:38:52 +0800 Subject: [PATCH 05/15] fix as ref --- library/std/src/os/windows/net/listener.rs | 2 +- library/std/tests/windows_unix_socket.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/library/std/src/os/windows/net/listener.rs b/library/std/src/os/windows/net/listener.rs index d317358016258..b76a360fe245d 100644 --- a/library/std/src/os/windows/net/listener.rs +++ b/library/std/src/os/windows/net/listener.rs @@ -18,7 +18,7 @@ impl UnixListener { pub fn bind>(path: P) -> io::Result { unsafe { let inner = Socket::new_unix()?; - let (addr, len) = sockaddr_un(path)?; + let (addr, len) = sockaddr_un(path.as_ref())?; cvt(bind(inner.as_raw(), &addr as *const _ as *const _, len))?; cvt(listen(inner.as_raw(), 128))?; Ok(UnixListener(inner)) diff --git a/library/std/tests/windows_unix_socket.rs b/library/std/tests/windows_unix_socket.rs index b1830dc74c4c1..261f64fd12f75 100644 --- a/library/std/tests/windows_unix_socket.rs +++ b/library/std/tests/windows_unix_socket.rs @@ -9,11 +9,10 @@ use std::thread; fn smoke_bind_connect() { let tmp = std::env::temp_dir(); let sock_path = tmp.join("rust-test-uds.sock"); - - let listener = UnixListener::bind(sock_path.as_path()).expect("bind failed"); - + let listener = UnixListener::bind(&sock_path).expect("bind failed"); + let sock_path_clone = sock_path.clone(); let tx = thread::spawn(move || { - let mut stream = UnixStream::connect(&sock_path).expect("connect failed"); + let mut stream = UnixStream::connect(&sock_path_clone).expect("connect failed"); stream.write_all(b"hello").expect("write failed"); }); From 1eaacdc98d76fe5be65d661f2bfd2290cf2dad50 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Wed, 8 Oct 2025 12:10:38 +0800 Subject: [PATCH 06/15] finish test --- library/std/src/os/windows/net/listener.rs | 12 ++++++++---- library/std/src/os/windows/net/stream.rs | 8 +++++--- library/std/tests/windows_unix_socket.rs | 3 ++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/library/std/src/os/windows/net/listener.rs b/library/std/src/os/windows/net/listener.rs index b76a360fe245d..dd9db80464e99 100644 --- a/library/std/src/os/windows/net/listener.rs +++ b/library/std/src/os/windows/net/listener.rs @@ -9,18 +9,22 @@ use crate::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocke use crate::os::windows::net::{SocketAddr, UnixStream, from_sockaddr_un}; use crate::path::Path; use crate::sys::c::{self, bind, getsockname, listen}; -use crate::sys::cvt; use crate::sys::net::Socket; - +use crate::sys::winsock::startup; pub struct UnixListener(Socket); impl UnixListener { pub fn bind>(path: P) -> io::Result { unsafe { + startup(); let inner = Socket::new_unix()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(bind(inner.as_raw(), &addr as *const _ as *const _, len))?; - cvt(listen(inner.as_raw(), 128))?; + if bind(inner.as_raw(), &addr as *const _ as *const _, len) != 0 { + panic!("err: {}", io::Error::last_os_error()) + } + if listen(inner.as_raw(), 128) != 0 { + panic!("err: {}", io::Error::last_os_error()) + } Ok(UnixListener(inner)) } } diff --git a/library/std/src/os/windows/net/stream.rs b/library/std/src/os/windows/net/stream.rs index b618123d4f633..4536352ff2560 100644 --- a/library/std/src/os/windows/net/stream.rs +++ b/library/std/src/os/windows/net/stream.rs @@ -11,16 +11,18 @@ use crate::os::windows::io::{ use crate::os::windows::net::{SocketAddr, sockaddr_un}; use crate::path::Path; use crate::sys::c::{SO_RCVTIMEO, SO_SNDTIMEO, connect, getpeername, getsockname}; -use crate::sys::cvt; use crate::sys::net::Socket; - +use crate::sys::winsock::startup; pub struct UnixStream(pub Socket); impl UnixStream { pub fn connect>(path: P) -> io::Result { unsafe { + startup(); let inner = Socket::new_unix()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(connect(inner.as_raw() as _, &addr as *const _ as *const _, len))?; + if connect(inner.as_raw() as _, &addr as *const _ as *const _, len) != 0 { + panic!("err: {}", io::Error::last_os_error()) + } Ok(UnixStream(inner)) } } diff --git a/library/std/tests/windows_unix_socket.rs b/library/std/tests/windows_unix_socket.rs index 261f64fd12f75..99ab5af839070 100644 --- a/library/std/tests/windows_unix_socket.rs +++ b/library/std/tests/windows_unix_socket.rs @@ -9,8 +9,9 @@ use std::thread; fn smoke_bind_connect() { let tmp = std::env::temp_dir(); let sock_path = tmp.join("rust-test-uds.sock"); + let _ = std::fs::remove_file(&sock_path); let listener = UnixListener::bind(&sock_path).expect("bind failed"); - let sock_path_clone = sock_path.clone(); + let sock_path_clone = sock_path.clone(); let tx = thread::spawn(move || { let mut stream = UnixStream::connect(&sock_path_clone).expect("connect failed"); stream.write_all(b"hello").expect("write failed"); From 3966e45eb18abff5800b350f5e797121394222f0 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Wed, 8 Oct 2025 12:15:49 +0800 Subject: [PATCH 07/15] echo test --- library/std/tests/windows_unix_socket.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/library/std/tests/windows_unix_socket.rs b/library/std/tests/windows_unix_socket.rs index 99ab5af839070..07bc85d2b583d 100644 --- a/library/std/tests/windows_unix_socket.rs +++ b/library/std/tests/windows_unix_socket.rs @@ -27,3 +27,39 @@ fn smoke_bind_connect() { drop(listener); let _ = std::fs::remove_file(&sock_path); } + +#[test] +fn win_uds_echo() { + let tmp = std::env::temp_dir(); + let sock_path = tmp.join("rust-test-uds-echo.sock"); + let _ = std::fs::remove_file(&sock_path); + + let listener = UnixListener::bind(&sock_path).expect("bind failed"); + let srv = thread::spawn(move || { + let (mut stream, _) = listener.accept().expect("accept failed"); + let mut buf = [0u8; 128]; + loop { + let n = match stream.read(&mut buf) { + Ok(0) => break, // 对端关闭 + Ok(n) => n, + Err(e) => panic!("read error: {}", e), + }; + stream.write_all(&buf[..n]).expect("write_all failed"); + } + }); + + let sock_path_clone = sock_path.clone(); + let cli = thread::spawn(move || { + let mut stream = UnixStream::connect(&sock_path_clone).expect("connect failed"); + let req = b"hello windows uds"; + stream.write_all(req).expect("write failed"); + let mut resp = vec![0u8; req.len()]; + stream.read_exact(&mut resp).expect("read failed"); + assert_eq!(resp, req); + }); + + cli.join().unwrap(); + srv.join().unwrap(); + + let _ = std::fs::remove_file(&sock_path); +} From d069ed4ae73a639979c748442ce6262e3a54d8d1 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Wed, 8 Oct 2025 12:49:46 +0800 Subject: [PATCH 08/15] remove new_unix --- library/std/src/os/windows/net/listener.rs | 4 ++-- library/std/src/os/windows/net/stream.rs | 6 ++++-- .../src/sys/net/connection/socket/windows.rs | 18 ------------------ 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/library/std/src/os/windows/net/listener.rs b/library/std/src/os/windows/net/listener.rs index dd9db80464e99..3fc5aff7f7afd 100644 --- a/library/std/src/os/windows/net/listener.rs +++ b/library/std/src/os/windows/net/listener.rs @@ -8,7 +8,7 @@ use crate::os::raw::c_int; use crate::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::os::windows::net::{SocketAddr, UnixStream, from_sockaddr_un}; use crate::path::Path; -use crate::sys::c::{self, bind, getsockname, listen}; +use crate::sys::c::{self, AF_UNIX, SOCK_STREAM, bind, getsockname, listen}; use crate::sys::net::Socket; use crate::sys::winsock::startup; pub struct UnixListener(Socket); @@ -17,7 +17,7 @@ impl UnixListener { pub fn bind>(path: P) -> io::Result { unsafe { startup(); - let inner = Socket::new_unix()?; + let inner = Socket::new(AF_UNIX as i32, SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; if bind(inner.as_raw(), &addr as *const _ as *const _, len) != 0 { panic!("err: {}", io::Error::last_os_error()) diff --git a/library/std/src/os/windows/net/stream.rs b/library/std/src/os/windows/net/stream.rs index 4536352ff2560..2717e88f4caa7 100644 --- a/library/std/src/os/windows/net/stream.rs +++ b/library/std/src/os/windows/net/stream.rs @@ -10,7 +10,9 @@ use crate::os::windows::io::{ }; use crate::os::windows::net::{SocketAddr, sockaddr_un}; use crate::path::Path; -use crate::sys::c::{SO_RCVTIMEO, SO_SNDTIMEO, connect, getpeername, getsockname}; +use crate::sys::c::{ + AF_UNIX, SO_RCVTIMEO, SO_SNDTIMEO, SOCK_STREAM, connect, getpeername, getsockname, +}; use crate::sys::net::Socket; use crate::sys::winsock::startup; pub struct UnixStream(pub Socket); @@ -18,7 +20,7 @@ impl UnixStream { pub fn connect>(path: P) -> io::Result { unsafe { startup(); - let inner = Socket::new_unix()?; + let inner = Socket::new(AF_UNIX as i32, SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; if connect(inner.as_raw() as _, &addr as *const _ as *const _, len) != 0 { panic!("err: {}", io::Error::last_os_error()) diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 3ec4b16ec620c..6dbebc5e276ec 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -9,7 +9,6 @@ use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; use crate::sys::c; -use crate::sys::c::{AF_UNIX, INVALID_SOCKET, SOCK_STREAM, WSA_FLAG_OVERLAPPED, WSASocketW}; use crate::sys::pal::winsock::last_error; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; @@ -118,23 +117,6 @@ pub use crate::sys::pal::winsock::{cvt, cvt_gai, cvt_r, startup as init}; pub struct Socket(OwnedSocket); impl Socket { - pub fn new_unix() -> io::Result { - let socket = unsafe { - match WSASocketW( - AF_UNIX as i32, - SOCK_STREAM, - 0, - ptr::null_mut(), - 0, - WSA_FLAG_OVERLAPPED, - ) { - INVALID_SOCKET => Err(last_error()), - n => Ok(Socket::from_raw(n)), - } - }?; - socket.0.set_no_inherit()?; - Ok(socket) - } pub fn new(family: c_int, ty: c_int) -> io::Result { let socket = unsafe { c::WSASocketW( From febd55a2a10305bc963bcd937786dd416961318c Mon Sep 17 00:00:00 2001 From: kouhe3 <25522053+kouhe3@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:11:11 +0800 Subject: [PATCH 09/15] use offset_of Co-authored-by: David Tolnay --- library/std/src/os/windows/net/addr.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs index 1289aedcc547d..16641f8a4cafa 100644 --- a/library/std/src/os/windows/net/addr.rs +++ b/library/std/src/os/windows/net/addr.rs @@ -41,10 +41,7 @@ pub fn sockaddr_un(path: &Path) -> io::Result<(c::sockaddr_un, c_int)> { Ok((addr, len as _)) } fn sun_path_offset(addr: &c::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base + offset_of!(c::sockaddr_un, sun_path) } #[allow(dead_code)] pub struct SocketAddr { From 74c1f0bd6d495e245064c2e542cbe50c3e2ccbf0 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:31:40 +0800 Subject: [PATCH 10/15] remove useless --- library/std/Cargo.toml | 2 +- library/std/src/os/windows/mod.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index f4f377c884978..685c2cf162abd 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -134,7 +134,7 @@ std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] # Enable using raw-dylib for Windows imports. # This will eventually be the default. windows_raw_dylib = ["windows-targets/windows_raw_dylib"] -windows_unix_domain_sockets = [] + [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing threads = 125 diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs index 9e078e3364093..5740f65bacef1 100644 --- a/library/std/src/os/windows/mod.rs +++ b/library/std/src/os/windows/mod.rs @@ -29,7 +29,6 @@ pub mod ffi; pub mod fs; pub mod io; -#[cfg(windows)] pub mod net; pub mod process; pub mod raw; From 84b38ddfdd11f6126587e4f2309697b163272677 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:08:46 +0800 Subject: [PATCH 11/15] fix ci --- library/std/src/os/windows/net/addr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs index 16641f8a4cafa..4e4530302b760 100644 --- a/library/std/src/os/windows/net/addr.rs +++ b/library/std/src/os/windows/net/addr.rs @@ -1,5 +1,6 @@ #![unstable(feature = "windows_unix_domain_sockets", issue = "56533")] +use crate::mem::offset_of; use crate::os::raw::{c_char, c_int}; use crate::path::Path; use crate::sys::c::{self, SOCKADDR}; From 92d448c8d7fa16f42a869327dcd301f4f39a29bc Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:53:05 +0800 Subject: [PATCH 12/15] fix ci --- library/std/src/os/windows/net/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs index 4e4530302b760..c6f43f0e5c5b6 100644 --- a/library/std/src/os/windows/net/addr.rs +++ b/library/std/src/os/windows/net/addr.rs @@ -42,7 +42,7 @@ pub fn sockaddr_un(path: &Path) -> io::Result<(c::sockaddr_un, c_int)> { Ok((addr, len as _)) } fn sun_path_offset(addr: &c::sockaddr_un) -> usize { - offset_of!(c::sockaddr_un, sun_path) + offset_of!(c::sockaddr_un, addr.sun_path) } #[allow(dead_code)] pub struct SocketAddr { From e7df166313c014cdad62b68e66de1498f5335779 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:44:02 +0800 Subject: [PATCH 13/15] fix ci --- library/std/src/os/windows/net/addr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs index c6f43f0e5c5b6..4e4530302b760 100644 --- a/library/std/src/os/windows/net/addr.rs +++ b/library/std/src/os/windows/net/addr.rs @@ -42,7 +42,7 @@ pub fn sockaddr_un(path: &Path) -> io::Result<(c::sockaddr_un, c_int)> { Ok((addr, len as _)) } fn sun_path_offset(addr: &c::sockaddr_un) -> usize { - offset_of!(c::sockaddr_un, addr.sun_path) + offset_of!(c::sockaddr_un, sun_path) } #[allow(dead_code)] pub struct SocketAddr { From 21048a58cef071851315845511747b14928d6bc0 Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Tue, 4 Nov 2025 15:50:47 +0800 Subject: [PATCH 14/15] fix ci --- library/std/src/os/windows/net/addr.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/os/windows/net/addr.rs b/library/std/src/os/windows/net/addr.rs index 4e4530302b760..6424bf55e8169 100644 --- a/library/std/src/os/windows/net/addr.rs +++ b/library/std/src/os/windows/net/addr.rs @@ -34,14 +34,14 @@ pub fn sockaddr_un(path: &Path) -> io::Result<(c::sockaddr_un, c_int)> { // null byte for pathname addresses is already there because we zeroed the // struct - let mut len = sun_path_offset(&addr) + bytes.len(); + let mut len = sun_path_offset() + bytes.len(); match bytes.first() { Some(&0) | None => {} Some(_) => len += 1, } Ok((addr, len as _)) } -fn sun_path_offset(addr: &c::sockaddr_un) -> usize { +fn sun_path_offset() -> usize { offset_of!(c::sockaddr_un, sun_path) } #[allow(dead_code)] @@ -65,7 +65,7 @@ impl SocketAddr { if len == 0 { // When there is a datagram from unnamed unix socket // linux returns zero bytes of address - len = sun_path_offset(&addr) as c_int; // i.e. zero-length address + len = sun_path_offset() as c_int; // i.e. zero-length address } else if addr.sun_family != c::AF_UNIX { return Err(io::Error::new( io::ErrorKind::InvalidInput, From 87fcb27a9cac3acba13a2e2f49d8f0b63ee9e3fa Mon Sep 17 00:00:00 2001 From: kouhe <25522053+kouhe3@users.noreply.github.com> Date: Tue, 4 Nov 2025 16:54:51 +0800 Subject: [PATCH 15/15] fix ci --- library/std/src/os/windows/net/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/windows/net/mod.rs b/library/std/src/os/windows/net/mod.rs index fe7ec8885907c..ec2bdaec59690 100644 --- a/library/std/src/os/windows/net/mod.rs +++ b/library/std/src/os/windows/net/mod.rs @@ -1,5 +1,5 @@ #![unstable(feature = "windows_unix_domain_sockets", issue = "56533")] - +#![doc(cfg(windows))] mod addr; mod listener; mod stream;