You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ahcodedthat opened this issue
Sep 8, 2023
· 1 comment
Labels
A-ioArea: std::io, std::fs, std::net and std::pathC-bugCategory: This is a bug.O-windowsOperating system: WindowsT-libsRelevant to the library team, which will review and decide on the PR/issue.
I was working on some code in which a socket is inherited by a child process from its parent, much like how BSD inetd works. This works without incident on Unix-like platforms.
Windows also supports socket inheritance, but there's a catch: even though the socket already exists from the moment the process starts, WSAStartup must still be called before using it.
The issue is that the standard library's implementations of FromRawSocket::from_raw_socket do not trigger a call to WSAStartup. The standard library does call WSAStartup as soon as it's used to create a socket (e.g. with TcpListener::bind), but not when bringing in an existing, inherited socket.
Please consider calling WSAStartup from from_raw_socket as well. Note, though, that it would no longer be zero-cost. This is acceptable to me, but I don't know if others would have a problem with that.
Here's a pair of example programs that demonstrate socket inheritance on Windows.
# Cargo.toml
[package]
name = "socket-inheritance-example"version = "0.1.0"edition = "2021"
[dependencies]
windows-sys = { version = "0.48.0", features = ["Win32_Foundation"] }
// src/bin/parent.rsuse std::{
env,
io::{self,Read},
net::{Ipv4Addr,TcpListener,TcpStream},
os::windows::io::{AsRawSocket,OwnedSocket},
process::Command,};use windows_sys::Win32::Foundation::{SetHandleInformation,HANDLE_FLAG_INHERIT};fnmain(){// Get the child program's name from the command line.let inheritor_program = env::args().skip(1).next().unwrap();// Open a TCP listening socket.let listener = TcpListener::bind((Ipv4Addr::LOCALHOST,0u16)).unwrap();let address = listener.local_addr().unwrap();let listener:OwnedSocket = listener.into();// Make the TCP listening socket inheritable.let made_inheritable = unsafe{SetHandleInformation(
listener.as_raw_socket()as_,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT,)};if made_inheritable == 0{panic!("{}", io::Error::last_os_error());}// Start the child process.Command::new(inheritor_program).arg(format!("{}", listener.as_raw_socket())).spawn().unwrap();// Connect to the child process and read some bytes.letmut message = Vec::<u8>::new();{letmut connection = TcpStream::connect(address).unwrap();
connection.read_to_end(&mut message).unwrap();}// Write them to standard output.let message = String::from_utf8(message).unwrap();print!("{message}");}
To try it, run cargo build --bins, then run target\debug\parent target\debug\child.
Unless that first drop statement is uncommented, the child process will panic with the error message “Either the application has not called WSAStartup, or WSAStartup failed.”
thread 'main' panicked at src\bin\inheritor.rs:13:47:
called `Result::unwrap()` on an `Err` value: Os { code: 10093, kind: Uncategorized, message: "Either the applicat
ion has not called WSAStartup, or WSAStartup failed." }
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/1e746d7741d44551e9378daf13b8797322aa0b74/library\std\src\panicking.rs:619
1: core::panicking::panic_fmt
at /rustc/1e746d7741d44551e9378daf13b8797322aa0b74/library\core\src\panicking.rs:72
2: core::result::unwrap_failed
at /rustc/1e746d7741d44551e9378daf13b8797322aa0b74/library\core\src\result.rs:1652
3: enum2$<core::result::Result<tuple$<std::net::tcp::TcpStream,enum2$<core::net::socket_addr::SocketAddr> >,st
d::io::error::Error> >::unwrap<tuple$<std::net::tcp::TcpStream,enum2$<core::net::socket_addr::SocketAddr> >,std::
io::error::Error>
at /rustc/1e746d7741d44551e9378daf13b8797322aa0b74\library\core\src\result.rs:1077
4: inheritor::main
at C:\Users\ahcodedthat\Desktop\socket-inheritance-example\src\bin\inheritor.rs:13
5: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/1e746d7741d44551e9378daf13b8797322aa0b74\library\core\src\ops\function.rs:250
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
The text was updated successfully, but these errors were encountered:
ChrisDenton
added
O-windows
Operating system: Windows
T-libs
Relevant to the library team, which will review and decide on the PR/issue.
A-io
Area: std::io, std::fs, std::net and std::path
and removed
needs-triage
This issue may need triage. Remove it if it has been sufficiently triaged.
labels
Sep 9, 2023
I guess the alternative would be to ensure WSAStartup is called before any socket using function. Maybe by wrapping the socket API so it can't be forgotten.
A-ioArea: std::io, std::fs, std::net and std::pathC-bugCategory: This is a bug.O-windowsOperating system: WindowsT-libsRelevant to the library team, which will review and decide on the PR/issue.
I was working on some code in which a socket is inherited by a child process from its parent, much like how BSD
inetd
works. This works without incident on Unix-like platforms.Windows also supports socket inheritance, but there's a catch: even though the socket already exists from the moment the process starts,
WSAStartup
must still be called before using it.The issue is that the standard library's implementations of
FromRawSocket::from_raw_socket
do not trigger a call toWSAStartup
. The standard library does callWSAStartup
as soon as it's used to create a socket (e.g. withTcpListener::bind
), but not when bringing in an existing, inherited socket.Please consider calling
WSAStartup
fromfrom_raw_socket
as well. Note, though, that it would no longer be zero-cost. This is acceptable to me, but I don't know if others would have a problem with that.Here's a pair of example programs that demonstrate socket inheritance on Windows.
To try it, run
cargo build --bins
, then runtarget\debug\parent target\debug\child
.Unless that first
drop
statement is uncommented, the child process will panic with the error message “Either the application has not called WSAStartup, or WSAStartup failed.”Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: