master
cpp 595 lines 21.7 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WslCoreInstance.cpp
8
9 Abstract:
10
11 This file contains WSL Core Instance function definitions.
12
13 --*/
14
15 #include "precomp.h"
16 #include "WslCoreInstance.h"
17
18 WslCoreInstance::WslCoreInstance(
19 _In_ HANDLE UserToken,
20 _In_ wil::unique_socket& InitSocket,
21 _In_ wil::unique_socket& SystemDistroSocket,
22 _In_ const GUID& InstanceId,
23 _In_ const GUID& RuntimeId,
24 _In_ const LXSS_DISTRO_CONFIGURATION& Configuration,
25 _In_ ULONG DefaultUid,
26 _In_ ULONG64 ClientLifetimeId,
27 _In_ const std::function<LX_INIT_DRVFS_MOUNT(HANDLE)>& DrvFsCallback,
28 _In_ ULONG FeatureFlags,
29 _In_ DWORD SocketTimeout,
30 _In_ int IdleTimeout,
31 _Out_opt_ ULONG* ConnectPort,
32 _In_opt_ HANDLE JobObject) :
33 LxssRunningInstance(IdleTimeout),
34 m_featureFlags(FeatureFlags),
35 m_instanceId(InstanceId),
36 m_runtimeId(RuntimeId),
37 m_configuration(Configuration),
38 m_defaultUid(DefaultUid),
39 m_initializeDrvFs(DrvFsCallback),
40 m_ntClientLifetimeId(ClientLifetimeId),
41 m_redirectorConnectionTargets{m_configuration.Name},
42 m_socketTimeout(SocketTimeout),
43 m_jobObject(JobObject)
44 {
45 // Establish a communication channel with the init daemon.
46 m_initChannel = std::make_shared<WslCorePort>(InitSocket.release(), m_runtimeId, m_socketTimeout);
47
48 // Read a message from the init daemon. This will let us know if anything failed during startup.
49 // The watcher is disarmed as soon as the receive returns so its reported duration reflects
50 // only the wait, not the rest of the constructor.
51 gsl::span<gsl::byte> span;
52 SlowOperationWatcher slowOperation{"WaitForCreateInstanceResult"};
53 const auto& result = m_initChannel->GetChannel().ReceiveMessage<LX_MINI_INIT_CREATE_INSTANCE_RESULT>(&span, m_socketTimeout);
54 slowOperation.Reset();
55 if (result.WarningsOffset != 0)
56 {
57 for (const auto& e : wsl::shared::string::Split<char>(wsl::shared::string::FromSpan(span, result.WarningsOffset), '\n'))
58 {
59 if (!e.empty())
60 {
61 EMIT_USER_WARNING(wsl::shared::string::MultiByteToWide(e));
62 }
63 }
64 }
65
66 if (result.Result != 0)
67 {
68 // N.B. EFSBADCRC (74) or EFSCORRUPTED (117) can be returned if the disk's journal is corrupted.
69 // EIO (5) can be returned during LaunchInit if corruption is detected after the initial mount succeeds.
70 if (((result.Result == EINVAL || result.Result == 74 || result.Result == 117) && result.FailureStep == LxInitCreateInstanceStepMountDisk) ||
71 (result.Result == 5 && result.FailureStep == LxInitCreateInstanceStepLaunchInit))
72 {
73 THROW_HR(WSL_E_DISK_CORRUPTED);
74 }
75 else
76 {
77 THROW_HR_WITH_USER_ERROR(
78 E_FAIL, wsl::shared::Localization::MessageDistributionFailedToStart(result.Result, static_cast<int>(result.FailureStep)));
79 }
80 }
81
82 m_clientId = static_cast<ULONG>(result.Pid);
83 if (ConnectPort != nullptr)
84 {
85 *ConnectPort = result.ConnectPort;
86 }
87
88 // Set a flag if the rootfs folder is compressed.
89 //
90 // N.B. The system distro has an empty base path.
91 if (!m_configuration.BasePath.empty())
92 {
93 WI_SetFlagIf(m_featureFlags, LxInitFeatureRootfsCompressed, WI_IsFlagSet(GetFileAttributesW(m_configuration.BasePath.c_str()), FILE_ATTRIBUTE_COMPRESSED));
94 }
95
96 // Copy immutable distribution data into the info structure.
97 m_distributionInfo.Id = m_configuration.DistroId;
98 m_distributionInfo.Name = m_configuration.Name.c_str();
99 m_distributionInfo.PackageFamilyName = m_configuration.PackageFamilyName.c_str();
100 m_distributionInfo.InitPid = m_clientId;
101
102 // Duplicate the passed-in user token.
103 THROW_IF_WIN32_BOOL_FALSE(::DuplicateTokenEx(UserToken, MAXIMUM_ALLOWED, nullptr, SecurityImpersonation, TokenImpersonation, &m_userToken));
104
105 // If a system distro socket was provided, create a system distro for this instance.
106 if (SystemDistroSocket)
107 {
108 LXSS_DISTRO_CONFIGURATION systemDistroConfig{};
109 systemDistroConfig.DistroId = Configuration.DistroId;
110 systemDistroConfig.State = LxssDistributionStateInstalled;
111 systemDistroConfig.Version = LXSS_DISTRO_VERSION_2;
112 systemDistroConfig.Flags = (LXSS_DISTRO_FLAGS_DEFAULT | LXSS_DISTRO_FLAGS_VM_MODE);
113
114 // Allow interop requests from init (pid 1) and disable the 9p server.
115 ULONG systemDistroFeatureFlags = m_featureFlags;
116 WI_SetFlag(systemDistroFeatureFlags, LxInitFeatureDisable9pServer);
117 WI_SetFlag(systemDistroFeatureFlags, LxInitFeatureSystemDistro);
118
119 // Create an instance for the system distro, this will fail if the distro has opted-out of
120 // GUI applications via /etc/wsl.conf.
121 try
122 {
123 wil::unique_socket empty{};
124 m_systemDistro = std::make_shared<WslCoreInstance>(
125 UserToken,
126 SystemDistroSocket,
127 empty,
128 WSL2_SYSTEM_DISTRO_GUID,
129 RuntimeId,
130 systemDistroConfig,
131 LX_UID_ROOT,
132 ClientLifetimeId,
133 DrvFsCallback,
134 systemDistroFeatureFlags,
135 m_socketTimeout,
136 IdleTimeout,
137 nullptr,
138 JobObject);
139 }
140 CATCH_LOG()
141 }
142 }
143
144 WslCoreInstance::~WslCoreInstance()
145 {
146 if (m_oobeThread.joinable())
147 {
148 m_destroyingEvent.SetEvent();
149 m_oobeThread.join();
150 }
151 }
152
153 void WslCoreInstance::CreateLxProcess(
154 _In_ const CreateLxProcessData& CreateProcessData,
155 _In_ const CreateLxProcessContext& CreateProcessContext,
156 _In_ const CreateLxProcessConsoleData& ConsoleData,
157 _In_ SHORT Columns,
158 _In_ SHORT Rows,
159 _In_ PLXSS_STD_HANDLES StdHandles,
160 _Out_ GUID* InstanceId,
161 _Out_ HANDLE* ProcessHandle,
162 _Out_ HANDLE* ServerHandle,
163 _Out_ HANDLE* StandardIn,
164 _Out_ HANDLE* StandardOut,
165 _Out_ HANDLE* StandardErr,
166 _Out_ HANDLE* CommunicationChannel,
167 _Out_ HANDLE* InteropSocket)
168 {
169 LX_INIT_DRVFS_MOUNT drvfsMount = LxInitDrvfsMountNone;
170 // If drive mounting is supported, ensure that DrvFs has been initialized.
171 if (WI_IsFlagSet(m_configuration.Flags, LXSS_DISTRO_FLAGS_ENABLE_DRIVE_MOUNTING))
172 {
173 drvfsMount = m_initializeDrvFs(CreateProcessContext.UserToken.get());
174 }
175
176 // Ensure the instance is still running.
177
178 std::lock_guard lock(m_lock);
179 THROW_HR_IF(HCS_E_TERMINATED, (!m_initChannel || !m_consoleManager));
180
181 if (m_oobeCompleteEvent && !m_oobeCompleteEvent.is_signaled())
182 {
183 EMIT_USER_WARNING(wsl::shared::Localization::MessageWaitingForOobe(m_configuration.Name.c_str()));
184 m_oobeCompleteEvent.wait();
185 }
186
187 // Initialize the create process message.
188 // N.B. m_defaultUid can only be read after m_oobeCompleteEvent is signaled since OOBE can change the default UID.
189 auto messageBuffer = LxssCreateProcess::CreateMessage(LxInitMessageCreateProcessUtilityVm, CreateProcessData, m_defaultUid);
190
191 const auto messageSpan = gsl::make_span(messageBuffer);
192 const auto message = gslhelpers::get_struct<LX_INIT_CREATE_PROCESS_UTILITY_VM>(messageSpan);
193
194 // m_initializeDrvFs returns true if admin share should be used
195 if (drvfsMount == LxInitDrvfsMountElevated && !m_adminMountNamespaceCreated)
196 {
197 MountDrvfs(true);
198 m_adminMountNamespaceCreated = true;
199 }
200 else if (drvfsMount == LxInitDrvfsMountNonElevated && !m_nonAdminMountNamespaceCreated)
201 {
202 MountDrvfs(false);
203 m_nonAdminMountNamespaceCreated = true;
204 }
205
206 message->Columns = Columns;
207 message->Rows = Rows;
208 WI_SetFlagIf(message->Common.Flags, LxInitCreateProcessFlagsStdInConsole, (StdHandles->StdIn.HandleType == LxssHandleConsole));
209 WI_SetFlagIf(message->Common.Flags, LxInitCreateProcessFlagsStdOutConsole, (StdHandles->StdOut.HandleType == LxssHandleConsole));
210 WI_SetFlagIf(message->Common.Flags, LxInitCreateProcessFlagsStdErrConsole, (StdHandles->StdErr.HandleType == LxssHandleConsole));
211 WI_SetFlagIf(message->Common.Flags, LxInitCreateProcessFlagsElevated, (drvfsMount == LxInitDrvfsMountElevated));
212 WI_SetFlagIf(message->Common.Flags, LxInitCreateProcessFlagsInteropEnabled, LXSS_INTEROP_ENABLED(CreateProcessContext.Flags));
213
214 if (m_configuration.RunOOBE && CreateProcessData.Filename.empty() && CreateProcessData.CommandLine.empty())
215 {
216 WI_SetFlag(message->Common.Flags, LxInitCreateProcessFlagAllowOOBE);
217 }
218
219 // Create a session leader if needed.
220 const auto sessionLeader =
221 std::static_pointer_cast<WslCorePort>(m_consoleManager->GetSessionLeader(ConsoleData, CreateProcessContext.Elevated));
222
223 // Lock the session leader connection and send a create process message.
224 //
225 // N.B. The session leader must be locked to ensure that the create process
226 // message and response are received by the correct endpoints.
227 ULONG port;
228 {
229 auto sessionLock = sessionLeader->Lock();
230 port = sessionLeader->GetChannel().Transaction<LX_INIT_CREATE_PROCESS_UTILITY_VM>(messageSpan).Result;
231 }
232
233 // Connect to the port specified by the session leader.
234 std::vector<wil::unique_socket> sockets(LX_INIT_UTILITY_VM_CREATE_PROCESS_SOCKET_COUNT);
235 if (WI_IsFlagSet(message->Common.Flags, LxInitCreateProcessFlagAllowOOBE))
236 {
237 sockets.emplace_back();
238 }
239
240 for (auto& socket : sockets)
241 {
242 socket = wsl::windows::common::hvsocket::Connect(m_runtimeId, port);
243 }
244
245 *InstanceId = m_runtimeId;
246 *ProcessHandle = nullptr;
247 *ServerHandle = nullptr;
248 *StandardIn = reinterpret_cast<HANDLE>(sockets[0].release());
249 *StandardOut = reinterpret_cast<HANDLE>(sockets[1].release());
250 *StandardErr = reinterpret_cast<HANDLE>(sockets[2].release());
251 *CommunicationChannel = reinterpret_cast<HANDLE>(sockets[3].release());
252 *InteropSocket = reinterpret_cast<HANDLE>(sockets[4].release());
253
254 if (WI_IsFlagSet(message->Common.Flags, LxInitCreateProcessFlagAllowOOBE))
255 {
256 {
257 m_oobeCompleteEvent.create(wil::EventOptions::ManualReset);
258
259 auto impersonate = wil::CoImpersonateClient();
260 auto registration = wsl::windows::service::DistributionRegistration::Open(
261 wsl::windows::common::registry::OpenLxssUserKey().get(), m_configuration.DistroId);
262
263 // Wait for a potential previous oobe thread to complete before creating a new one.
264 if (m_oobeThread.joinable())
265 {
266 m_oobeThread.join();
267 }
268
269 m_oobeThread = std::thread([this, socket = std::move(sockets[5]), registration = std::move(registration)]() mutable {
270 try
271 {
272 ReadOOBEResult(std::move(socket), std::move(registration));
273 }
274 CATCH_LOG()
275
276 m_oobeCompleteEvent.SetEvent();
277 });
278 }
279 }
280 }
281
282 void WslCoreInstance::ReadOOBEResult(wil::unique_socket&& Socket, wsl::windows::service::DistributionRegistration&& registration)
283 {
284 wsl::shared::SocketChannel channel(std::move(Socket), "OOBE", {m_destroyingEvent.get()});
285
286 const auto* oobeResult = channel.ReceiveMessageOrClosed<LX_INIT_OOBE_RESULT>().first;
287
288 if (oobeResult == nullptr)
289 {
290 LOG_HR_MSG(E_FAIL, "OOBE channel closed");
291 return;
292 }
293
294 // Logs the result of the OOBE process
295 WSL_LOG_TELEMETRY(
296 "OOBEResult",
297 PDT_ProductAndServicePerformance,
298 TraceLoggingValue(oobeResult->Result, "Result"),
299 TraceLoggingValue(oobeResult->DefaultUid, "DefaultUid"),
300 TraceLoggingValue(m_configuration.Name.c_str(), "Name"),
301 TraceLoggingValue(2, "Version"));
302
303 if (oobeResult->Result == 0)
304 {
305 // OOBE was successful, don't run it again.
306 m_configuration.RunOOBE = false;
307 registration.Write(wsl::windows::service::Property::RunOOBE, 0);
308
309 if (oobeResult->DefaultUid != -1)
310 {
311 registration.Write(wsl::windows::service::Property::DefaultUid, static_cast<int>(oobeResult->DefaultUid));
312 m_defaultUid = static_cast<int>(oobeResult->DefaultUid);
313 }
314
315 m_redirectorConnectionTargets.UpdateUid(m_defaultUid);
316 }
317 }
318
319 ULONG WslCoreInstance::GetClientId() const
320 {
321 // Return the system distro ClientId if any so that this distribution is correctly
322 // identified if the system distro init process terminates.
323 if (m_systemDistro)
324 {
325 return m_systemDistro->GetClientId();
326 }
327
328 return m_clientId;
329 }
330
331 GUID WslCoreInstance::GetDistributionId() const
332 {
333 return m_configuration.DistroId;
334 }
335
336 std::shared_ptr<LxssPort> WslCoreInstance::GetInitPort()
337 {
338 THROW_HR_IF(HCS_E_TERMINATED, !m_initChannel);
339
340 return m_initChannel;
341 }
342
343 std::shared_ptr<LxssRunningInstance> WslCoreInstance::GetSystemDistro()
344 {
345 return m_systemDistro;
346 }
347
348 void WslCoreInstance::UpdateTimezone()
349 {
350 if (m_systemDistro)
351 {
352 m_systemDistro->UpdateTimezone();
353 }
354
355 auto message =
356 wsl::windows::common::helpers::GenerateTimezoneUpdateMessage(wsl::windows::common::helpers::GetLinuxTimezone(m_userToken.get()));
357
358 auto lock = m_initChannel->Lock();
359 auto transaction = m_initChannel->GetChannel().StartTransaction();
360 transaction.Send<LX_INIT_TIMEZONE_INFORMATION>(gsl::make_span(message));
361 }
362
363 ULONG64 WslCoreInstance::GetLifetimeManagerId() const
364 {
365 return m_ntClientLifetimeId;
366 }
367
368 void WslCoreInstance::Initialize()
369 {
370 // Check if the instance has already been initialized.
371 std::lock_guard lock(m_lock);
372 if (m_initialized)
373 {
374 return;
375 }
376
377 // If a system distro was created, initialize it first.
378 if (m_systemDistro)
379 {
380 m_systemDistro->Initialize();
381 }
382
383 LX_INIT_DRVFS_MOUNT drvfsMount = LxInitDrvfsMountNone;
384
385 // If drive mounting is supported, ensure that DrvFs has been initialized.
386 if (WI_IsFlagSet(m_configuration.Flags, LXSS_DISTRO_FLAGS_ENABLE_DRIVE_MOUNTING))
387 {
388 SlowOperationWatcher slowOperation{"WaitForDrvFsInit"};
389 drvfsMount = m_initializeDrvFs(m_userToken.get());
390 }
391
392 // Create a console manager that will be used to manage session leaders.
393 m_consoleManager = ConsoleManager::CreateConsoleManager(m_initChannel);
394
395 // Send the initial configuration information to the init daemon.
396 ULONG fixedDrives = 0;
397 if (WI_IsFlagSet(m_configuration.Flags, LXSS_DISTRO_FLAGS_ENABLE_DRIVE_MOUNTING))
398 {
399 fixedDrives = wsl::windows::common::filesystem::EnumerateFixedDrives().first;
400 }
401
402 const auto timezone = wsl::windows::common::helpers::GetLinuxTimezone();
403 auto config = wsl::windows::common::helpers::GenerateConfigurationMessage(
404 m_configuration.Name, fixedDrives, m_defaultUid, timezone, {}, m_featureFlags, drvfsMount);
405
406 auto transaction = m_initChannel->GetChannel().StartTransaction();
407 transaction.Send<LX_INIT_CONFIGURATION_INFORMATION>(gsl::span(config));
408
409 // Init replies with information about the distribution.
410 // The watcher is disarmed as soon as the receive returns so its reported duration reflects
411 // only the wait, not the subsequent interop-server launch.
412 gsl::span<gsl::byte> span;
413 SlowOperationWatcher slowOperation{"WaitForInitConfigResponse"};
414 const auto& response = transaction.Receive<LX_INIT_CONFIGURATION_INFORMATION_RESPONSE>(&span);
415 slowOperation.Reset();
416 m_defaultUid = response.DefaultUid;
417 m_plan9Port = response.Plan9Port;
418 m_distributionInfo.PidNamespace = response.PidNamespace;
419
420 if (response.VersionIndex > 0)
421 {
422 m_configuration.OsVersion = wsl::shared::string::MultiByteToWide(wsl::shared::string::FromSpan(span, response.VersionIndex));
423 m_distributionInfo.Version = m_configuration.OsVersion.c_str();
424 }
425
426 if (response.FlavorIndex > 0)
427 {
428 m_configuration.Flavor = wsl::shared::string::MultiByteToWide(wsl::shared::string::FromSpan(span, response.FlavorIndex));
429 m_distributionInfo.Flavor = m_configuration.Flavor.c_str();
430 }
431
432 // Launch the interop server with the user's token.
433 if (response.InteropPort != LX_INIT_UTILITY_VM_INVALID_PORT)
434 {
435 try
436 {
437 const wil::unique_socket socket{wsl::windows::common::hvsocket::Connect(m_runtimeId, response.InteropPort)};
438 wil::unique_handle info{wsl::windows::common::helpers::LaunchInteropServer(
439 nullptr, reinterpret_cast<HANDLE>(socket.get()), nullptr, nullptr, &m_runtimeId, m_userToken.get(), m_jobObject)};
440 }
441 CATCH_LOG()
442 }
443
444 // Initialization was successful.
445 m_initialized = true;
446
447 // The initialization message mounts the drvfs drives, so make sure we don't try it again.
448 if (drvfsMount == LxInitDrvfsMountElevated)
449 {
450 m_adminMountNamespaceCreated = true;
451 }
452 else if (drvfsMount == LxInitDrvfsMountNonElevated)
453 {
454 m_nonAdminMountNamespaceCreated = true;
455 }
456
457 WSL_LOG(
458 "WslCoreInstanceInitialize",
459 TraceLoggingValue(m_configuration.Name.c_str(), "distroName"),
460 TraceLoggingValue(LXSS_WSL_VERSION_2, "version"),
461 TraceLoggingValue(m_instanceId, "instanceId"),
462 TraceLoggingValue(m_configuration.DistroId, "distroId"),
463 TraceLoggingValue(response.DefaultUid, "defaultUid"),
464 TraceLoggingValue(response.SystemdEnabled, "systemdEnabled"));
465 }
466
467 void WslCoreInstance::MountDrvfs(bool Admin) const
468 {
469 auto [drives, nonReadableDrives] = wsl::windows::common::filesystem::EnumerateFixedDrives();
470 LX_INIT_MOUNT_DRVFS Message{{LxInitMessageRemountDrvfs, sizeof(Message)}, Admin, drives, nonReadableDrives, static_cast<int>(m_defaultUid)};
471
472 const auto& Result = m_initChannel->GetChannel().Transaction(Message, nullptr, m_socketTimeout);
473
474 LOG_HR_IF_MSG(E_UNEXPECTED, Result.Result != 0, "Failed to mount the drvfs shares, %i", Result.Result);
475 }
476
477 const WSLDistributionInformation* WslCoreInstance::DistributionInformation() const noexcept
478 {
479 return &m_distributionInfo;
480 }
481
482 bool WslCoreInstance::RequestStop(_In_ bool Force)
483 {
484 bool shutdown = true;
485 std::lock_guard lock(m_lock);
486 if (m_initChannel)
487 {
488 try
489 {
490 LX_INIT_TERMINATE_INSTANCE terminateMessage{};
491 terminateMessage.Header.MessageType = LxInitMessageTerminateInstance;
492 terminateMessage.Header.MessageSize = sizeof(terminateMessage);
493 terminateMessage.Force = Force;
494
495 auto transaction = m_initChannel->GetChannel().StartTransaction(m_socketTimeout);
496 transaction.Send(terminateMessage);
497 auto [message, span] = transaction.ReceiveOrClosed<RESULT_MESSAGE<bool>>();
498 if (message)
499 {
500 shutdown = message->Result;
501 }
502 }
503 CATCH_LOG()
504 }
505
506 return shutdown;
507 }
508
509 void WslCoreInstance::Stop()
510 {
511 std::lock_guard lock(m_lock);
512
513 WSL_LOG_TELEMETRY(
514 "StopInstance",
515 PDT_ProductAndServiceUsage,
516 TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA),
517 TraceLoggingValue(m_configuration.Name.c_str(), "distroName"),
518 TraceLoggingValue(LXSS_WSL_VERSION_2, "version"),
519 TraceLoggingValue(m_instanceId, "instanceId"),
520 TraceLoggingValue(m_configuration.DistroId, "distroId"));
521
522 m_destroyingEvent.SetEvent();
523 m_initChannel.reset();
524 m_consoleManager.reset();
525
526 // Remove the instance's Plan 9 Redirector connection targets.
527 m_redirectorConnectionTargets.RemoveAll();
528
529 // If the instance was terminated, terminate the associated system distro.
530 m_systemDistro.reset();
531
532 return;
533 }
534
535 void WslCoreInstance::RegisterPlan9ConnectionTarget(_In_ HANDLE userToken)
536 {
537 // If Plan 9 is running, add a connection target to the P9Rdr driver.
538 if (m_plan9Port != LX_INIT_UTILITY_VM_INVALID_PORT)
539 {
540 m_redirectorConnectionTargets.AddConnectionTarget(userToken, {}, m_defaultUid, {}, m_runtimeId, m_plan9Port);
541 }
542 }
543
544 wil::unique_socket WslCoreInstance::CreateLinuxProcess(_In_ LPCSTR Path, _In_ LPCSTR* Arguments)
545 {
546 std::lock_guard lock(m_lock);
547
548 return LxssCreateProcess::CreateLinuxProcess(Path, Arguments, m_runtimeId, m_initChannel->GetChannel(), nullptr, m_socketTimeout);
549 }
550
551 WslCoreInstance::WslCorePort::WslCorePort(_In_ SOCKET Socket, _In_ const GUID& RuntimeId, DWORD SocketTimeout) :
552 m_channel(wil::unique_socket{Socket}, "WslCorePort"), m_runtimeId(RuntimeId), m_socketTimeout(SocketTimeout)
553
554 {
555 // N.B. The class takes ownership of the socket.
556 }
557
558 std::shared_ptr<LxssPort> WslCoreInstance::WslCorePort::CreateSessionLeader(_In_ HANDLE)
559 {
560 // Send a create session message to the init daemon.
561 // N.B. A lock is held while this method is called.
562
563 LX_INIT_CREATE_SESSION message{{LxInitMessageCreateSession, sizeof(message)}};
564 const auto& response = m_channel.Transaction(message, nullptr, m_socketTimeout);
565
566 wil::unique_socket socket = wsl::windows::common::hvsocket::Connect(m_runtimeId, response.Port);
567 return std::make_shared<WslCorePort>(socket.release(), m_runtimeId, m_socketTimeout);
568 }
569
570 void WslCoreInstance::WslCorePort::DisconnectConsole(_In_ HANDLE)
571 {
572 }
573
574 wsl::shared::SocketChannel& WslCoreInstance::WslCorePort::GetChannel()
575 {
576 return m_channel;
577 }
578
579 wil::cs_leave_scope_exit WslCoreInstance::WslCorePort::Lock()
580 {
581 return m_lock.lock();
582 }
583
584 void WslCoreInstance::WslCorePort::Receive(_Out_writes_bytes_(Length) PVOID Buffer, _In_ ULONG Length, _In_opt_ HANDLE ClientProcess, _In_ DWORD Timeout)
585 {
586 const auto span = gsl::make_span(reinterpret_cast<gsl::byte*>(Buffer), Length);
587 const ULONG bytesRead = wsl::windows::common::socket::Receive(m_channel.Socket(), span, ClientProcess, MSG_WAITALL, Timeout);
588
589 THROW_HR_IF_MSG(E_UNEXPECTED, bytesRead < Length, "Expected %lu bytes, but received %lu", Length, bytesRead);
590 }
591
592 void WslCoreInstance::WslCorePort::Send(_In_reads_bytes_(Length) PVOID Buffer, _In_ ULONG Length)
593 {
594 wsl::windows::common::socket::Send(m_channel.Socket(), gsl::make_span(reinterpret_cast<gsl::byte*>(Buffer), Length));
595 }