From 4687cb65a09e4f559c517bfc3dcd5230a0235203 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 1/8] 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 529f9d4d7219995cc64f012f8e3a4f93ba3479d2 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 2/8] 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 14dbee2c2024e6551256cbd5e82a4f085f5b9624 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 3/8] 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 0c7114e7a2cc807c73fb8aaf5d5a2bf0fe569ea3 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 4/8] 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 779b07ce240a6..c569169c03157 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -131,7 +131,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 83c00d1fd4fcdccb6f8f95e2130012f835a1e2b2 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 5/8] 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 1b5fc3425e11a12c85b9791bdc1fc984b0a847d6 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 6/8] 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 82e68b24745454fef955972819a78459324ad1e4 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 7/8] 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 22c3f267785e2dc89b9969b3d38a9406109069f1 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 8/8] 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(