Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions library/std/src/os/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
81 changes: 81 additions & 0 deletions library/std/src/os/windows/net/addr.rs
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)
}
98 changes: 98 additions & 0 deletions library/std/src/os/windows/net/listener.rs
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()
}
}
8 changes: 8 additions & 0 deletions library/std/src/os/windows/net/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#![unstable(feature = "windows_unix_domain_sockets", issue = "56533")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of the code was transplanted from https://github.com/Azure/mio-uds-windows

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

Except as otherwise noted, Rust is licensed under the Apache License, Version
2.0 <LICENSE-APACHE> or <http://www.apache.org/licenses/LICENSE-2.0> or the MIT
license <LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option.

We cannot legally take MIT-only code and unilaterally relicense it to Apache 2.0. One of the following needs to happen:

  1. The upstream code needs to be relicensed.

  2. The upstream copyright holder needs to grant Rust the right to take the code under a different license.

  3. 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".

  4. The contribution needs to be rewritten by somebody else without reference to copyrighted material from the original implementation.

#![doc(cfg(windows))]
mod addr;
mod listener;
mod stream;
pub use addr::*;
pub use listener::*;
pub use stream::*;
118 changes: 118 additions & 0 deletions library/std/src/os/windows/net/stream.rs
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
}
}
10 changes: 9 additions & 1 deletion library/std/src/sys/pal/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading