master
cpp 149 lines 4.55 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 main.cpp
8
9 Abstract:
10
11 This file contains the entrypoint for wslrelay.
12
13 --*/
14
15 #include "precomp.h"
16 #include "localhost.h"
17 #include "CommandLine.h"
18
19 using namespace wsl::windows::common;
20 using namespace wsl::shared;
21
22 int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
23 try
24 {
25 wsl::windows::common::wslutil::ConfigureCrt();
26 wsl::windows::common::wslutil::InitializeWil();
27
28 // Initialize COM.
29 auto coInit = wil::CoInitializeEx(COINIT_MULTITHREADED);
30 wsl::windows::common::wslutil::CoInitializeSecurity();
31
32 // Initialize winsock.
33 WSADATA data;
34 THROW_IF_WIN32_ERROR(WSAStartup(MAKEWORD(2, 2), &data));
35
36 // Parse arguments.
37 wil::unique_handle handle{};
38 wslrelay::RelayMode mode{wslrelay::RelayMode::Invalid};
39 wil::unique_handle pipe{};
40 wil::unique_handle exitEvent{};
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);
48 parser.AddArgument(Handle{handle}, wslrelay::handle_option);
49 parser.AddArgument(vmId, wslrelay::vm_id_option);
50 parser.AddArgument(Handle{pipe}, wslrelay::pipe_option);
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:
77 {
78 // If not relaying to a file, create a console window.
79 if (!handle)
80 {
81 wsl::windows::common::helpers::CreateConsole(L"WSL Debug Console");
82 }
83
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
87 // Print a message that the VM has exited and prompt the user for input.
88 wsl::windows::common::wslutil::PrintSystemError(HCS_E_CONNECTION_CLOSED);
89 if (!handle)
90 {
91 getwchar();
92 }
93
94 break;
95 }
96
97 case wslrelay::RelayMode::PortRelay:
98 {
99 wsl::shared::SocketChannel channel{wil::unique_socket{reinterpret_cast<SOCKET>(handle.release())}, "PortRelay"};
100 wsl::windows::wslrelay::localhost::RelayWorker(channel, vmId);
101 break;
102 }
103
104 case wslrelay::RelayMode::WSLCPortRelay:
105 {
106 wsl::windows::wslrelay::localhost::RunWSLCPortRelay(vmId, port, exitEvent.get());
107 break;
108 }
109
110 case wslrelay::RelayMode::KdRelay:
111 {
112 THROW_HR_IF(E_INVALIDARG, port == 0);
113
114 // Bind, listen, and accept a connection on the specified port.
115 const wil::unique_socket listenSocket(WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED));
116 THROW_LAST_ERROR_IF(!listenSocket);
117
118 sockaddr_in address{};
119 address.sin_family = AF_INET;
120 address.sin_port = htons(port);
121 address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
122 THROW_LAST_ERROR_IF(bind(listenSocket.get(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == SOCKET_ERROR);
123
124 THROW_LAST_ERROR_IF(listen(listenSocket.get(), 1) == SOCKET_ERROR);
125
126 auto socket = wsl::windows::common::socket::CancellableAccept(listenSocket.get(), INFINITE, exitEvent.get());
127 if (!socket)
128 {
129 return 1;
130 }
131
132 // Begin the relay.
133 wsl::windows::common::relay::BidirectionalRelay(
134 reinterpret_cast<HANDLE>(socket->get()), pipe.get(), 0x1000, wsl::windows::common::relay::RelayFlags::LeftIsSocket);
135
136 break;
137 }
138
139 default:
140 THROW_HR_MSG(E_INVALIDARG, "Invalid relay mode %d specified.", static_cast<int>(mode));
141 }
142
143 return 0;
144 }
145 catch (...)
146 {
147 LOG_CAUGHT_EXCEPTION();
148 return 1;
149 }