Skip to content

Commit a526413

Browse files
committed
windows uds
1 parent 227ac7c commit a526413

File tree

8 files changed

+394
-1
lines changed

8 files changed

+394
-1
lines changed

library/std/src/os/windows/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
pub mod ffi;
3030
pub mod fs;
3131
pub mod io;
32+
pub mod net;
3233
pub mod process;
3334
pub mod raw;
3435
pub mod thread;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")]
2+
3+
use crate::os::raw::{c_char, c_int};
4+
use crate::path::Path;
5+
use crate::sys::c::{self, SOCKADDR};
6+
use crate::sys::cvt;
7+
use crate::{io, mem};
8+
pub fn sockaddr_un(path: &Path) -> io::Result<(c::sockaddr_un, c_int)> {
9+
let mut addr: c::sockaddr_un = unsafe { mem::zeroed() };
10+
addr.sun_family = c::AF_UNIX;
11+
// Winsock2 expects 'sun_path' to be a Win32 UTF-8 file system path
12+
let bytes = path
13+
.to_str()
14+
.map(|s| s.as_bytes())
15+
.ok_or(io::Error::new(io::ErrorKind::InvalidInput, "path contains invalid characters"))?;
16+
17+
if bytes.contains(&0) {
18+
return Err(io::Error::new(
19+
io::ErrorKind::InvalidInput,
20+
"paths may not contain interior null bytes",
21+
));
22+
}
23+
24+
if bytes.len() >= addr.sun_path.len() {
25+
return Err(io::Error::new(
26+
io::ErrorKind::InvalidInput,
27+
"path must be shorter than SUN_LEN",
28+
));
29+
}
30+
for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
31+
*dst = *src as c_char;
32+
}
33+
// null byte for pathname addresses is already there because we zeroed the
34+
// struct
35+
36+
let mut len = sun_path_offset(&addr) + bytes.len();
37+
match bytes.first() {
38+
Some(&0) | None => {}
39+
Some(_) => len += 1,
40+
}
41+
Ok((addr, len as _))
42+
}
43+
fn sun_path_offset(addr: &c::sockaddr_un) -> usize {
44+
// Work with an actual instance of the type since using a null pointer is UB
45+
let base = addr as *const _ as usize;
46+
let path = &addr.sun_path as *const _ as usize;
47+
path - base
48+
}
49+
#[allow(dead_code)]
50+
pub struct SocketAddr {
51+
addr: c::sockaddr_un,
52+
len: c_int,
53+
}
54+
impl SocketAddr {
55+
pub fn new<F>(f: F) -> io::Result<SocketAddr>
56+
where
57+
F: FnOnce(*mut SOCKADDR, *mut c_int) -> c_int,
58+
{
59+
unsafe {
60+
let mut addr: c::sockaddr_un = mem::zeroed();
61+
let mut len = mem::size_of::<c::sockaddr_un>() as c_int;
62+
cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
63+
SocketAddr::from_parts(addr, len)
64+
}
65+
}
66+
fn from_parts(addr: c::sockaddr_un, mut len: c_int) -> io::Result<SocketAddr> {
67+
if len == 0 {
68+
// When there is a datagram from unnamed unix socket
69+
// linux returns zero bytes of address
70+
len = sun_path_offset(&addr) as c_int; // i.e. zero-length address
71+
} else if addr.sun_family != c::AF_UNIX {
72+
return Err(io::Error::new(
73+
io::ErrorKind::InvalidInput,
74+
"file descriptor did not correspond to a Unix socket",
75+
));
76+
}
77+
78+
Ok(SocketAddr { addr, len })
79+
}
80+
}
81+
pub fn from_sockaddr_un(addr: c::sockaddr_un, len: c_int) -> io::Result<SocketAddr> {
82+
SocketAddr::from_parts(addr, len)
83+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")]
2+
3+
use core::mem;
4+
5+
use super::sockaddr_un;
6+
use crate::io;
7+
use crate::os::raw::c_int;
8+
use crate::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
9+
use crate::os::windows::net::{SocketAddr, UnixStream, from_sockaddr_un};
10+
use crate::path::Path;
11+
use crate::sys::c::{self, bind, getsockname, listen};
12+
use crate::sys::cvt;
13+
use crate::sys::net::Socket;
14+
15+
pub struct UnixListener(Socket);
16+
17+
impl UnixListener {
18+
pub fn bind<P: AsRef<Path>>(path: &Path) -> io::Result<UnixListener> {
19+
unsafe {
20+
let inner = Socket::new_unix()?;
21+
let (addr, len) = sockaddr_un(path)?;
22+
cvt(bind(inner.as_raw(), &addr as *const _ as *const _, len))?;
23+
cvt(listen(inner.as_raw(), 128))?;
24+
Ok(UnixListener(inner))
25+
}
26+
}
27+
pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
28+
let mut storage: c::sockaddr_un = unsafe { mem::zeroed() };
29+
let mut len = mem::size_of_val(&storage) as c_int;
30+
let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
31+
let addr = from_sockaddr_un(storage, len)?;
32+
Ok((UnixStream(sock), addr))
33+
}
34+
pub fn incoming(&self) -> Incoming<'_> {
35+
Incoming { listener: self }
36+
}
37+
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
38+
self.0.take_error()
39+
}
40+
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
41+
self.0.set_nonblocking(nonblocking)
42+
}
43+
pub fn local_addr(&self) -> io::Result<SocketAddr> {
44+
SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw() as _, addr, len) })
45+
}
46+
pub fn try_clone(&self) -> io::Result<UnixListener> {
47+
self.0.duplicate().map(UnixListener)
48+
}
49+
}
50+
51+
pub struct Incoming<'a> {
52+
listener: &'a UnixListener,
53+
}
54+
55+
impl<'a> Iterator for Incoming<'a> {
56+
type Item = io::Result<UnixStream>;
57+
58+
fn next(&mut self) -> Option<io::Result<UnixStream>> {
59+
Some(self.listener.accept().map(|s| s.0))
60+
}
61+
62+
fn size_hint(&self) -> (usize, Option<usize>) {
63+
(usize::MAX, None)
64+
}
65+
}
66+
67+
impl AsRawSocket for UnixListener {
68+
fn as_raw_socket(&self) -> RawSocket {
69+
self.0.as_raw_socket()
70+
}
71+
}
72+
73+
impl FromRawSocket for UnixListener {
74+
unsafe fn from_raw_socket(sock: RawSocket) -> Self {
75+
UnixListener(unsafe { Socket::from_raw_socket(sock) })
76+
}
77+
}
78+
79+
impl IntoRawSocket for UnixListener {
80+
fn into_raw_socket(self) -> RawSocket {
81+
let ret = self.0.as_raw_socket();
82+
mem::forget(self);
83+
ret
84+
}
85+
}
86+
87+
impl<'a> IntoIterator for &'a UnixListener {
88+
type Item = io::Result<UnixStream>;
89+
type IntoIter = Incoming<'a>;
90+
91+
fn into_iter(self) -> Incoming<'a> {
92+
self.incoming()
93+
}
94+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")]
2+
3+
mod addr;
4+
mod listener;
5+
mod stream;
6+
pub use addr::*;
7+
pub use listener::*;
8+
pub use stream::*;
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")]
2+
3+
use core::mem;
4+
use core::time::Duration;
5+
6+
use crate::io::{self, IoSlice};
7+
use crate::net::Shutdown;
8+
use crate::os::windows::io::{
9+
AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, RawSocket,
10+
};
11+
use crate::os::windows::net::{SocketAddr, sockaddr_un};
12+
use crate::path::Path;
13+
use crate::sys::c::{SO_RCVTIMEO, SO_SNDTIMEO, connect, getpeername, getsockname};
14+
use crate::sys::cvt;
15+
use crate::sys::net::Socket;
16+
17+
pub struct UnixStream(pub Socket);
18+
impl UnixStream {
19+
pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
20+
unsafe {
21+
let inner = Socket::new_unix()?;
22+
let (addr, len) = sockaddr_un(path.as_ref())?;
23+
cvt(connect(inner.as_raw() as _, &addr as *const _ as *const _, len))?;
24+
Ok(UnixStream(inner))
25+
}
26+
}
27+
pub fn local_addr(&self) -> io::Result<SocketAddr> {
28+
SocketAddr::new(|addr, len| unsafe { getsockname(self.0.as_raw() as _, addr, len) })
29+
}
30+
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
31+
SocketAddr::new(|addr, len| unsafe { getpeername(self.0.as_raw() as _, addr, len) })
32+
}
33+
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
34+
self.0.timeout(SO_RCVTIMEO)
35+
}
36+
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
37+
self.0.set_nonblocking(nonblocking)
38+
}
39+
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
40+
self.0.set_timeout(dur, SO_RCVTIMEO)
41+
}
42+
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
43+
self.0.set_timeout(dur, SO_SNDTIMEO)
44+
}
45+
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
46+
self.0.shutdown(how)
47+
}
48+
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
49+
self.0.take_error()
50+
}
51+
pub fn try_clone(&self) -> io::Result<UnixStream> {
52+
self.0.duplicate().map(UnixStream)
53+
}
54+
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
55+
self.0.timeout(SO_SNDTIMEO)
56+
}
57+
}
58+
59+
impl io::Read for UnixStream {
60+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
61+
io::Read::read(&mut &*self, buf)
62+
}
63+
}
64+
65+
impl<'a> io::Read for &'a UnixStream {
66+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
67+
self.0.read(buf)
68+
}
69+
}
70+
71+
impl io::Write for UnixStream {
72+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
73+
io::Write::write(&mut &*self, buf)
74+
}
75+
76+
fn flush(&mut self) -> io::Result<()> {
77+
io::Write::flush(&mut &*self)
78+
}
79+
}
80+
impl<'a> io::Write for &'a UnixStream {
81+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
82+
self.0.write_vectored(&[IoSlice::new(buf)])
83+
}
84+
85+
fn flush(&mut self) -> io::Result<()> {
86+
Ok(())
87+
}
88+
}
89+
90+
impl AsSocket for UnixStream {
91+
fn as_socket(&self) -> BorrowedSocket<'_> {
92+
self.0.as_socket()
93+
}
94+
}
95+
96+
impl AsRawSocket for UnixStream {
97+
fn as_raw_socket(&self) -> RawSocket {
98+
self.0.as_raw_socket()
99+
}
100+
}
101+
102+
impl FromRawSocket for UnixStream {
103+
unsafe fn from_raw_socket(sock: RawSocket) -> Self {
104+
unsafe { UnixStream(Socket::from_raw_socket(sock)) }
105+
}
106+
}
107+
108+
impl IntoRawSocket for UnixStream {
109+
fn into_raw_socket(self) -> RawSocket {
110+
let ret = self.0.as_raw_socket();
111+
mem::forget(self);
112+
ret
113+
}
114+
}

library/std/src/sys/net/connection/socket/windows.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::os::windows::io::{
99
AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
1010
};
1111
use crate::sys::c;
12+
use crate::sys::c::{AF_UNIX, INVALID_SOCKET, SOCK_STREAM, WSA_FLAG_OVERLAPPED, WSASocketW};
1213
use crate::sys::pal::winsock::last_error;
1314
use crate::sys_common::{AsInner, FromInner, IntoInner};
1415
use crate::time::Duration;
@@ -117,6 +118,23 @@ pub use crate::sys::pal::winsock::{cvt, cvt_gai, cvt_r, startup as init};
117118
pub struct Socket(OwnedSocket);
118119

119120
impl Socket {
121+
pub fn new_unix() -> io::Result<Socket> {
122+
let socket = unsafe {
123+
match WSASocketW(
124+
AF_UNIX as i32,
125+
SOCK_STREAM,
126+
0,
127+
ptr::null_mut(),
128+
0,
129+
WSA_FLAG_OVERLAPPED,
130+
) {
131+
INVALID_SOCKET => Err(last_error()),
132+
n => Ok(Socket::from_raw(n)),
133+
}
134+
}?;
135+
socket.0.set_no_inherit()?;
136+
Ok(socket)
137+
}
120138
pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> {
121139
let socket = unsafe {
122140
c::WSASocketW(

library/std/src/sys/pal/windows/c.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,16 @@ use core::ptr;
1111
mod windows_sys;
1212
pub use windows_sys::*;
1313

14-
pub type WCHAR = u16;
14+
use crate::os::raw::c_char;
1515

16+
pub type WCHAR = u16;
17+
pub const AF_UNIX: ADDRESS_FAMILY = 1;
18+
#[derive(Clone, Copy)]
19+
#[repr(C)]
20+
pub struct sockaddr_un {
21+
pub sun_family: ADDRESS_FAMILY,
22+
pub sun_path: [c_char; 108],
23+
}
1624
pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _);
1725

1826
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170

0 commit comments

Comments
 (0)