-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
UnixStream/UnixListener on Windows #150428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kouhe3
wants to merge
2
commits into
rust-lang:main
Choose a base branch
from
kouhe3:win-af-unix-2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,003
−0
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| use crate::bstr::ByteStr; | ||
| use crate::ffi::OsStr; | ||
| use crate::path::Path; | ||
| #[cfg(not(doc))] | ||
| use crate::sys::c::{AF_UNIX, SOCKADDR, SOCKADDR_UN}; | ||
| use crate::sys::cvt_nz; | ||
| use crate::{fmt, io, mem, ptr}; | ||
|
|
||
| #[cfg(not(doc))] | ||
| pub fn sockaddr_un(path: &Path) -> io::Result<(SOCKADDR_UN, usize)> { | ||
| // SAFETY: All zeros is a valid representation for `sockaddr_un`. | ||
| let mut addr: SOCKADDR_UN = unsafe { mem::zeroed() }; | ||
| addr.sun_family = AF_UNIX; | ||
|
|
||
| // path to UTF-8 bytes | ||
| let bytes = path | ||
| .to_str() | ||
| .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "path must be valid UTF-8"))? | ||
| .as_bytes(); | ||
| if bytes.len() >= addr.sun_path.len() { | ||
| return Err(io::const_error!(io::ErrorKind::InvalidInput, "path too long")); | ||
| } | ||
| // SAFETY: `bytes` and `addr.sun_path` are not overlapping and | ||
| // both point to valid memory. | ||
| // NOTE: We zeroed the memory above, so the path is already null | ||
| // terminated. | ||
| unsafe { | ||
| ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len()) | ||
| }; | ||
|
|
||
| let len = SUN_PATH_OFFSET + bytes.len() + 1; | ||
| Ok((addr, len)) | ||
| } | ||
| #[cfg(not(doc))] | ||
| const SUN_PATH_OFFSET: usize = mem::offset_of!(SOCKADDR_UN, sun_path); | ||
| pub struct SocketAddr { | ||
kouhe3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| #[cfg(not(doc))] | ||
| pub(super) addr: SOCKADDR_UN, | ||
| pub(super) len: u32, // Use u32 here as same as libc::socklen_t | ||
| } | ||
| impl fmt::Debug for SocketAddr { | ||
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| match self.address() { | ||
| AddressKind::Unnamed => write!(fmt, "(unnamed)"), | ||
| AddressKind::Abstract(name) => write!(fmt, "{name:?} (abstract)"), | ||
| AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl SocketAddr { | ||
| #[cfg(not(doc))] | ||
| pub(super) fn new<F>(f: F) -> io::Result<SocketAddr> | ||
| where | ||
| F: FnOnce(*mut SOCKADDR, *mut i32) -> i32, | ||
| { | ||
| unsafe { | ||
| let mut addr: SOCKADDR_UN = mem::zeroed(); | ||
| let mut len = mem::size_of::<SOCKADDR_UN>() as i32; | ||
| cvt_nz(f(&raw mut addr as *mut _, &mut len))?; | ||
| SocketAddr::from_parts(addr, len) | ||
| } | ||
| } | ||
| #[cfg(not(doc))] | ||
| pub(super) fn from_parts(addr: SOCKADDR_UN, len: i32) -> io::Result<SocketAddr> { | ||
| if addr.sun_family != AF_UNIX { | ||
| Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid address family")) | ||
| } else if len < SUN_PATH_OFFSET as _ || len > mem::size_of::<SOCKADDR_UN>() as _ { | ||
| Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid address length")) | ||
| } else { | ||
| Ok(SocketAddr { addr, len: len as _ }) | ||
| } | ||
| } | ||
|
|
||
| /// Returns the contents of this address if it is a `pathname` address. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// With a pathname: | ||
| /// | ||
| /// ```no_run | ||
| /// use std::os::windows::net::UnixListener; | ||
| /// use std::path::Path; | ||
| /// | ||
| /// fn main() -> std::io::Result<()> { | ||
| /// let socket = UnixListener::bind("/tmp/sock")?; | ||
| /// let addr = socket.local_addr().expect("Couldn't get local address"); | ||
| /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); | ||
| /// Ok(()) | ||
| /// } | ||
| /// ``` | ||
| pub fn as_pathname(&self) -> Option<&Path> { | ||
| if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } | ||
| } | ||
|
|
||
| /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns an error if the path is longer than `SUN_LEN` or if it contains | ||
| /// NULL bytes. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ``` | ||
| /// use std::os::windows::net::SocketAddr; | ||
| /// use std::path::Path; | ||
| /// | ||
| /// # fn main() -> std::io::Result<()> { | ||
| /// let address = SocketAddr::from_pathname("/path/to/socket")?; | ||
| /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); | ||
| /// # Ok(()) | ||
| /// # } | ||
| /// ``` | ||
| /// | ||
| /// Creating a `SocketAddr` with a NULL byte results in an error. | ||
| /// | ||
| /// ``` | ||
| /// use std::os::windows::net::SocketAddr; | ||
| /// | ||
| /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err()); | ||
| /// ``` | ||
| pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr> | ||
| where | ||
| P: AsRef<Path>, | ||
| { | ||
| sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len: len as _ }) | ||
| } | ||
| fn address(&self) -> AddressKind<'_> { | ||
| let len = self.len as usize - SUN_PATH_OFFSET; | ||
| let path = unsafe { mem::transmute::<&[i8], &[u8]>(&self.addr.sun_path) }; | ||
|
|
||
| if len == 0 { | ||
| AddressKind::Unnamed | ||
| } else if self.addr.sun_path[0] == 0 { | ||
| AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) | ||
| } else { | ||
| AddressKind::Pathname(unsafe { | ||
| OsStr::from_encoded_bytes_unchecked(&path[..len - 1]).as_ref() | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| /// Returns `true` if the address is unnamed. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// A named address: | ||
| /// | ||
| /// ```no_run | ||
| /// use std::os::windows::net::UnixListener; | ||
| /// | ||
| /// fn main() -> std::io::Result<()> { | ||
| /// let socket = UnixListener::bind("/tmp/sock")?; | ||
| /// let addr = socket.local_addr().expect("Couldn't get local address"); | ||
| /// assert_eq!(addr.is_unnamed(), false); | ||
| /// Ok(()) | ||
| /// } | ||
| /// ``` | ||
| pub fn is_unnamed(&self) -> bool { | ||
| matches!(self.address(), AddressKind::Unnamed) | ||
| } | ||
| } | ||
| enum AddressKind<'a> { | ||
| Unnamed, | ||
| Pathname(&'a Path), | ||
| Abstract(&'a ByteStr), | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/, it looks to me like abstract and unnamed sockets should both be supported by Windows as well. Presumably the implementation should as such more closely mirror library/std/src/os/unix/net/addr.rs?
That would also fix the problem in fmt::Debug, where you bail if it's not a path socket incorrectly; it would make more sense for me if it used the same strategy as the unix impl.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe abstract sockets not support by Windows. Set first byte of sun_path to zero cause
code: 10022when connectThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add an unresolved question to the tracking issue about that? It doesn't seem expected to me given:
Maybe something is wrong with our setup or the blog post is stale...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Mark-Simulacrum seems like microsoft not impl full AF_UNIX yet. I will add this ref to tracking issue.
I suggest specifying in the documentation that only AF_UNIX SOCK_STREAM with TRUE paths is supported