Repository: rust
Issue: `from_raw_socket` does not call `WSAStartup`
Labels: O-windows,C-bug,T-libs,A-io

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.

```toml
# Cargo.toml

[package]
name = "socket-inheritance-example"
version = "0.1.0"
edition = "2021"

[dependencies]
windows-sys = { version = "0.48.0", features = ["Win32_Foundation"] }
```

```rust
// src/bin/parent.rs

use 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};

fn main() {
	// 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.
	let mut message = Vec::<u8>::new();
	{
		let mut 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}");
}
```

```rust
// src/bin/child.rs

use std::{
	env,
	io::Write,
	net::{Ipv4Addr, TcpListener},
	os::windows::io::{FromRawSocket, RawSocket},
};

fn main() {
	// drop(TcpListener::bind((Ipv4Addr::LOCALHOST, 0u16)));

	let socket_handle: RawSocket = env::args().skip(1).next().unwrap().parse().unwrap();
	let socket = unsafe { TcpListener::from_raw_socket(socket_handle) };
	let (mut connection, _) = socket.accept().unwrap();
	connection.write_all(b"Hello, world!\n").unwrap();
	connection.flush().unwrap();
}
```

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.”

### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->

`rustc --version --verbose`:
```
rustc 1.74.0-nightly (1e746d774 2023-09-07)
binary: rustc
commit-hash: 1e746d7741d44551e9378daf13b8797322aa0b74
commit-date: 2023-09-07
host: x86_64-pc-windows-msvc
release: 1.74.0-nightly
LLVM version: 17.0.0
```

<!--
Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
environment. E.g. `RUST_BACKTRACE=1 cargo build`.
-->
<details><summary>Backtrace</summary>
<p>

```
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.
```

</p>
</details>