diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 5acd96c0cb..5a969b785f 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -79,8 +79,7 @@ semver-parser = "0.9.0" uuid = { version = "0.8.1", features = ["v4"] } [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.9", features = ["knownfolders", "objbase", "shlobj", -"winbase", "winerror", "tlhelp32"] } +winapi = { version = "0.3.9", features = ["knownfolders", "mswsock", "objbase", "shlobj", "tlhelp32", "winbase", "winerror", "winsock2"] } fwdansi = "1.1.0" [target.'cfg(unix)'.dependencies] diff --git a/cli/inspector.rs b/cli/inspector.rs index baaa96ec90..dbab615e5e 100644 --- a/cli/inspector.rs +++ b/cli/inspector.rs @@ -137,9 +137,27 @@ async fn server( host: SocketAddr, register_inspector_rx: UnboundedReceiver, ) { - // TODO: `inspector_map` in an Rc> instead. This is currently not - // possible because warp requires all filters to implement Send, which should - // not be necessary because we are using a single-threaded runtime. + // When the main thread shuts down, The Rust stdlib will call `WSACleanup()`, + // which shuts down the network stack. This thread will still be + // running at that time (because it never exits), but all attempts at network + // I/O will fail with a `WSANOTINITIALIZED` error, which causes a panic. + // To prevent this from happening, Winsock is initialized another time here; + // this increases Winsock's internal reference count, so it won't shut + // itself down when the main thread calls `WSACleanup()` upon exit. + // TODO: When the last `Inspector` instance is dropped, make it signal the + // server thread so it exits cleanly, then join it with the main thread. + #[cfg(windows)] + unsafe { + use winapi::um::winsock2::{WSAStartup, WSADATA}; + let mut wsa_data = MaybeUninit::::zeroed(); + let r = WSAStartup(0x202 /* Winsock 2.2 */, wsa_data.as_mut_ptr()); + assert_eq!(r, 0); + } + + // TODO: put the `inspector_map` in an `Rc>` instead. This is + // currently not possible because warp requires all filters to implement + // `Send`, which should not be necessary because we are using the + // single-threaded Tokio runtime. let inspector_map = HashMap::::new(); let inspector_map = Arc::new(Mutex::new(inspector_map));