cleanup: refactor wslrelay and other minor cleanup (#14099)

* cleanup: refactor wslrelay and other minor cleanup * pr feedback --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

Ben Hillis committed Jan 23, 2026 at 13:33 UTC d8cd707384ddf3d7d7877911ccae355740a3127f
6 files changed +32 -23
src/windows/common/CMakeLists.txt
+2 -2
@@ -1,6 +1,7 @@
1 set(SOURCES
2 ConsoleProgressBar.cpp
3 ConsoleProgressIndicator.cpp
4 + ConsoleState.cpp
5 DeviceHostProxy.cpp
6 disk.cpp
7 Distribution.cpp
@@ -32,7 +33,6 @@ set(SOURCES
33 string.cpp
34 SubProcess.cpp
35 svccomm.cpp
35 - ConsoleState.cpp
36 WslClient.cpp
37 WslCoreConfig.cpp
38 WslCoreFilesystem.cpp
@@ -74,6 +74,7 @@ set(HEADERS
74 ../inc/wslrelay.h
75 ConsoleProgressBar.h
76 ConsoleProgressIndicator.h
77 + ConsoleState.h
78 DeviceHostProxy.h
79 disk.hpp
80 Distribution.h
@@ -107,7 +108,6 @@ set(HEADERS
108 Stringify.h
109 SubProcess.h
110 svccomm.hpp
110 - ConsoleState.h
111 WslClient.h
112 WslCoreConfig.h
113 WslCoreFilesystem.h
src/windows/common/ConsoleState.cpp
+1
@@ -9,6 +9,7 @@ Module Name:
9 Abstract:
10
11 This file contains function definitions for the ConsoleState helper class.
12 +
13 --*/
14
15 #include "precomp.h"
src/windows/common/helpers.cpp
+10 -7
@@ -178,6 +178,11 @@ private:
178 launcher.AddOption(wslrelay::disable_telemetry_option);
179 }
180
181 + if (WI_IsFlagSet(Flags, LaunchWslRelayFlags::ConnectPipe))
182 + {
183 + launcher.AddOption(wslrelay::connect_pipe_option);
184 + }
185 +
186 return launcher.Launch(UserToken, WI_IsFlagSet(Flags, LaunchWslRelayFlags::HideWindow));
187 }
188 } // namespace
@@ -501,11 +506,10 @@ bool wsl::windows::common::helpers::IsWslSupportInterfacePresent()
506 void wsl::windows::common::helpers::LaunchDebugConsole(
507 _In_ LPCWSTR PipeName, _In_ bool ConnectExistingPipe, _In_ HANDLE UserToken, _In_opt_ HANDLE LogFile, _In_ bool DisableTelemetry)
508 {
504 - wslrelay::RelayMode relayMode;
509 + LaunchWslRelayFlags flags{};
510 wil::unique_hfile pipe;
511 if (ConnectExistingPipe)
512 {
508 - relayMode = wslrelay::RelayMode::DebugConsoleRelay;
513 // Connect to an existing pipe. The connection should be:
514 // Asynchronous (FILE_FLAG_OVERLAPPED)
515 // Anonymous (SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS)
@@ -515,21 +519,20 @@ void wsl::windows::common::helpers::LaunchDebugConsole(
519 }
520 else
521 {
518 - relayMode = wslrelay::RelayMode::DebugConsole;
519 - // Create a new pipe server. The pipe should be:
522 + // Create a new pipe server the child process will connect to. The pipe should be:
523 // Bi-directional: PIPE_ACCESS_DUPLEX
524 // Asynchronous: FILE_FLAG_OVERLAPPED
525 // Raw: PIPE_TYPE_BYTE | PIPE_READMODE_BYTE
526 // Blocking: PIPE_WAIT
527 + WI_SetFlag(flags, LaunchWslRelayFlags::ConnectPipe);
528 pipe.reset(CreateNamedPipeW(
529 PipeName, (PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED), (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT), 1, LX_RELAY_BUFFER_SIZE, LX_RELAY_BUFFER_SIZE, 0, nullptr));
530 }
531
532 THROW_LAST_ERROR_IF(!pipe);
533
530 - LaunchWslRelayFlags flags{};
534 WI_SetFlagIf(flags, LaunchWslRelayFlags::DisableTelemetry, DisableTelemetry);
532 - wil::unique_handle info{LaunchWslRelay(relayMode, LogFile, nullptr, pipe.get(), {}, nullptr, UserToken, flags)};
535 + wil::unique_handle info{LaunchWslRelay(wslrelay::RelayMode::DebugConsole, LogFile, nullptr, pipe.get(), {}, nullptr, UserToken, flags)};
536 }
537
538 [[nodiscard]] wil::unique_handle wsl::windows::common::helpers::LaunchInteropServer(
@@ -550,7 +553,7 @@ void wsl::windows::common::helpers::LaunchKdRelay(_In_ LPCWSTR PipeName, _In_ HA
553
554 THROW_LAST_ERROR_IF(!pipe);
555
553 - LaunchWslRelayFlags flags{};
556 + LaunchWslRelayFlags flags = LaunchWslRelayFlags::ConnectPipe;
557 WI_SetFlagIf(flags, LaunchWslRelayFlags::DisableTelemetry, DisableTelemetry);
558 wil::unique_handle info{LaunchWslRelay(wslrelay::RelayMode::KdRelay, nullptr, nullptr, pipe.get(), Port, ExitEvent, UserToken, flags)};
559 }
src/windows/common/helpers.hpp
+2 -1
@@ -62,7 +62,8 @@ enum class LaunchWslRelayFlags
62 {
63 None = 0,
64 DisableTelemetry = 1,
65 - HideWindow = 2
65 + HideWindow = 2,
66 + ConnectPipe = 4
67 };
68
69 DEFINE_ENUM_FLAG_OPERATORS(LaunchWslRelayFlags);
src/windows/inc/wslrelay.h
+1 -1
@@ -19,7 +19,6 @@ enum RelayMode
19 {
20 Invalid = -1,
21 DebugConsole,
22 - DebugConsoleRelay,
22 PortRelay,
23 KdRelay
24 };
@@ -32,4 +31,5 @@ LPCWSTR const pipe_option = L"--pipe";
31 LPCWSTR const exit_event_option = L"--exit-event";
32 LPCWSTR const port_option = L"--port";
33 LPCWSTR const disable_telemetry_option = L"--disable-telemetry";
34 +LPCWSTR const connect_pipe_option = L"--connect-pipe";
35 } // namespace wslrelay
\ No newline at end of file
src/windows/wslrelay/main.cpp
+16 -12
@@ -38,9 +38,10 @@ try
38 wslrelay::RelayMode mode{wslrelay::RelayMode::Invalid};
39 wil::unique_handle pipe{};
40 wil::unique_handle exitEvent{};
41 - int port{};
41 + uint32_t port{};
42 GUID vmId{};
43 bool disableTelemetry = !wsl::shared::OfficialBuild;
44 + bool connectPipe = false;
45
46 ArgumentParser parser(GetCommandLineW(), wslrelay::binary_name);
47 parser.AddArgument(Integer(reinterpret_cast<int&>(mode)), wslrelay::mode_option);
@@ -50,17 +51,29 @@ try
51 parser.AddArgument(Handle{exitEvent}, wslrelay::exit_event_option);
52 parser.AddArgument(Integer{port}, wslrelay::port_option);
53 parser.AddArgument(disableTelemetry, wslrelay::disable_telemetry_option);
54 + parser.AddArgument(connectPipe, wslrelay::connect_pipe_option);
55 parser.Parse();
56
57 // Initialize logging.
58 WslTraceLoggingInitialize(LxssTelemetryProvider, disableTelemetry);
59 auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [] { WslTraceLoggingUninitialize(); });
60
61 + // Ensure that the other end of the pipe has connected if required.
62 + if (connectPipe)
63 + {
64 + std::vector<HANDLE> exitEvents;
65 + if (exitEvent)
66 + {
67 + exitEvents.push_back(exitEvent.get());
68 + }
69 +
70 + wsl::windows::common::helpers::ConnectPipe(pipe.get(), (15 * 1000), exitEvents);
71 + }
72 +
73 // Perform the requested operation.
74 switch (mode)
75 {
76 case wslrelay::RelayMode::DebugConsole:
63 - case wslrelay::RelayMode::DebugConsoleRelay:
77 {
78 // If not relaying to a file, create a console window.
79 if (!handle)
@@ -68,12 +81,6 @@ try
81 wsl::windows::common::helpers::CreateConsole(L"WSL Debug Console");
82 }
83
71 - if (mode == wslrelay::RelayMode::DebugConsole)
72 - {
73 - // Ensure that the other end of the pipe has connected.
74 - wsl::windows::common::helpers::ConnectPipe(pipe.get(), (15 * 1000));
75 - }
76 -
84 // Relay the contents of the pipe to the output handle.
85 wsl::windows::common::relay::InterruptableRelay(pipe.get(), handle ? handle.get() : GetStdHandle(STD_OUTPUT_HANDLE));
86
@@ -98,9 +105,6 @@ try
105 {
106 THROW_HR_IF(E_INVALIDARG, port == 0);
107
101 - // Ensure that the other end of the pipe has connected.
102 - wsl::windows::common::helpers::ConnectPipe(pipe.get(), (15 * 1000), {exitEvent.get()});
103 -
108 // Bind, listen, and accept a connection on the specified port.
109 const wil::unique_socket listenSocket(WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED));
110 THROW_LAST_ERROR_IF(!listenSocket);
@@ -126,7 +130,7 @@ try
130 }
131
132 default:
129 - THROW_HR(E_INVALIDARG);
133 + THROW_HR_MSG(E_INVALIDARG, "Invalid relay mode %d specified.", static_cast<int>(mode));
134 }
135
136 return 0;