-
Notifications
You must be signed in to change notification settings - Fork 14k
std::os::windows::net: add Unix-domain socket support (AF_UNIX on Windows) #147335
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
Closed
Closed
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
9ac52d5
windows uds
kouhe3 e73728c
cfg windows
kouhe3 9abface
move file
kouhe3 a649265
fix wrong generic
kouhe3 852a4ce
fix as ref
kouhe3 1eaacdc
finish test
kouhe3 3966e45
echo test
kouhe3 d069ed4
remove new_unix
kouhe3 febd55a
use offset_of
kouhe3 74c1f0b
remove useless
kouhe3 84b38dd
fix ci
kouhe3 92d448c
fix ci
kouhe3 e7df166
fix ci
kouhe3 21048a5
fix ci
kouhe3 87fcb27
fix ci
kouhe3 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,81 @@ | ||
| #![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}; | ||
| 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() + bytes.len(); | ||
| match bytes.first() { | ||
| Some(&0) | None => {} | ||
| Some(_) => len += 1, | ||
| } | ||
| Ok((addr, len as _)) | ||
| } | ||
| fn sun_path_offset() -> usize { | ||
| offset_of!(c::sockaddr_un, sun_path) | ||
| } | ||
| #[allow(dead_code)] | ||
| pub struct SocketAddr { | ||
| addr: c::sockaddr_un, | ||
| len: c_int, | ||
| } | ||
| impl SocketAddr { | ||
| pub fn new<F>(f: F) -> io::Result<SocketAddr> | ||
| 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::<c::sockaddr_un>() 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<SocketAddr> { | ||
| if len == 0 { | ||
| // When there is a datagram from unnamed unix socket | ||
| // linux returns zero bytes of 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, | ||
| "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> { | ||
| SocketAddr::from_parts(addr, len) | ||
| } |
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,98 @@ | ||
| #![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, AF_UNIX, SOCK_STREAM, bind, getsockname, listen}; | ||
| use crate::sys::net::Socket; | ||
| use crate::sys::winsock::startup; | ||
| pub struct UnixListener(Socket); | ||
|
|
||
| impl UnixListener { | ||
| pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> { | ||
| unsafe { | ||
| startup(); | ||
| 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()) | ||
| } | ||
| if listen(inner.as_raw(), 128) != 0 { | ||
| panic!("err: {}", io::Error::last_os_error()) | ||
| } | ||
| 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<Option<io::Error>> { | ||
| 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> { | ||
| SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw() as _, addr, len) }) | ||
| } | ||
| pub fn try_clone(&self) -> io::Result<UnixListener> { | ||
| self.0.duplicate().map(UnixListener) | ||
| } | ||
| } | ||
|
|
||
| pub struct Incoming<'a> { | ||
| listener: &'a UnixListener, | ||
| } | ||
|
|
||
| impl<'a> Iterator for Incoming<'a> { | ||
| type Item = io::Result<UnixStream>; | ||
|
|
||
| fn next(&mut self) -> Option<io::Result<UnixStream>> { | ||
| Some(self.listener.accept().map(|s| s.0)) | ||
| } | ||
|
|
||
| fn size_hint(&self) -> (usize, Option<usize>) { | ||
| (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<UnixStream>; | ||
| type IntoIter = Incoming<'a>; | ||
|
|
||
| fn into_iter(self) -> Incoming<'a> { | ||
| self.incoming() | ||
| } | ||
| } |
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,8 @@ | ||
| #![unstable(feature = "windows_unix_domain_sockets", issue = "56533")] | ||
| #![doc(cfg(windows))] | ||
| mod addr; | ||
| mod listener; | ||
| mod stream; | ||
| pub use addr::*; | ||
| pub use listener::*; | ||
| pub use stream::*; | ||
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,118 @@ | ||
| #![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::{ | ||
| 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); | ||
| impl UnixStream { | ||
| pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> { | ||
| unsafe { | ||
| startup(); | ||
| 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()) | ||
| } | ||
| Ok(UnixStream(inner)) | ||
| } | ||
| } | ||
| pub fn local_addr(&self) -> io::Result<SocketAddr> { | ||
| SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw() as _, addr, len) }) | ||
| } | ||
| pub fn peer_addr(&self) -> io::Result<SocketAddr> { | ||
| SocketAddr::new(|addr, len| unsafe { getpeername(self.0.as_raw() as _, addr, len) }) | ||
| } | ||
| pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | ||
| 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<Duration>) -> io::Result<()> { | ||
| self.0.set_timeout(dur, SO_RCVTIMEO) | ||
| } | ||
| pub fn set_write_timeout(&self, dur: Option<Duration>) -> 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<Option<io::Error>> { | ||
| self.0.take_error() | ||
| } | ||
| pub fn try_clone(&self) -> io::Result<UnixStream> { | ||
| self.0.duplicate().map(UnixStream) | ||
| } | ||
| pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | ||
| self.0.timeout(SO_SNDTIMEO) | ||
| } | ||
| } | ||
|
|
||
| impl io::Read for UnixStream { | ||
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
| io::Read::read(&mut &*self, buf) | ||
| } | ||
| } | ||
|
|
||
| impl<'a> io::Read for &'a UnixStream { | ||
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | ||
| self.0.read(buf) | ||
| } | ||
| } | ||
|
|
||
| impl io::Write for UnixStream { | ||
| fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | ||
| 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<usize> { | ||
| 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 | ||
| } | ||
| } |
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
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.
I am not sure that's going to be allowed. The mio-uds-windows repo is MIT licensed only whereas the standard library is dual licensed.
rust/COPYRIGHT
Lines 17 to 19 in 20383c9
We cannot legally take MIT-only code and unilaterally relicense it to Apache 2.0. One of the following needs to happen:
The upstream code needs to be relicensed.
The upstream copyright holder needs to grant Rust the right to take the code under a different license.
The actual license of the domain socket code for Windows needs to be explained in the standard library source code sufficiently clearly to fall under "as otherwise noted".
The contribution needs to be rewritten by somebody else without reference to copyrighted material from the original implementation.