| 1 | /*++ |
| 2 | |
| 3 | Copyright (c) Microsoft. All rights reserved. |
| 4 | |
| 5 | Module Name: |
| 6 | |
| 7 | WSLCSession.h |
| 8 | |
| 9 | Abstract: |
| 10 | |
| 11 | TODO |
| 12 | |
| 13 | --*/ |
| 14 | |
| 15 | #pragma once |
| 16 | |
| 17 | #include "wslc.h" |
| 18 | #include "WSLCCompat.h" |
| 19 | #include "WSLCVirtualMachine.h" |
| 20 | #include "WSLCContainer.h" |
| 21 | #include "WSLCIdleState.h" |
| 22 | #include "WSLCVolumes.h" |
| 23 | #include "WSLCSessionRuntime.h" |
| 24 | #include "WSLCNetworkMetadata.h" |
| 25 | #include "DockerEventTracker.h" |
| 26 | #include "DockerHTTPClient.h" |
| 27 | #include "EventStore.h" |
| 28 | #include "IORelay.h" |
| 29 | #include <atomic> |
| 30 | #include <list> |
| 31 | #include <optional> |
| 32 | #include <unordered_map> |
| 33 | |
| 34 | namespace wsl::windows::service::wslc { |
| 35 | |
| 36 | class WSLCSession; |
| 37 | |
| 38 | class UserHandle |
| 39 | { |
| 40 | NON_COPYABLE(UserHandle); |
| 41 | |
| 42 | public: |
| 43 | UserHandle(WSLCSession& Session, HANDLE handle); |
| 44 | UserHandle(UserHandle&& Other); |
| 45 | |
| 46 | ~UserHandle(); |
| 47 | |
| 48 | UserHandle& operator=(UserHandle&& Other); |
| 49 | |
| 50 | HANDLE Get() const noexcept; |
| 51 | void Reset(); |
| 52 | |
| 53 | private: |
| 54 | WSLCSession* m_session{}; |
| 55 | HANDLE m_handle{}; |
| 56 | }; |
| 57 | |
| 58 | class UserCOMCallback |
| 59 | { |
| 60 | NON_COPYABLE(UserCOMCallback); |
| 61 | |
| 62 | public: |
| 63 | UserCOMCallback(WSLCSession& Session) noexcept; |
| 64 | UserCOMCallback(UserCOMCallback&& Other) noexcept; |
| 65 | |
| 66 | ~UserCOMCallback() noexcept; |
| 67 | |
| 68 | UserCOMCallback& operator=(UserCOMCallback&& Other) noexcept; |
| 69 | void Reset() noexcept; |
| 70 | |
| 71 | private: |
| 72 | WSLCSession* m_session{}; |
| 73 | DWORD m_threadId{}; |
| 74 | }; |
| 75 | |
| 76 | // |
| 77 | // WSLCSession - Implements IWSLCSession for container management. |
| 78 | // Runs in a per-user COM server process for security isolation. |
| 79 | // The SYSTEM service passes an IWSLCVirtualMachineFactory to Initialize(); the VM is created |
| 80 | // lazily on first use and may be torn down when idle and recreated on demand. |
| 81 | // |
| 82 | class DECLSPEC_UUID("4877FEFC-4977-4929-A958-9F36AA1892A4") WSLCSession |
| 83 | : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>, IWSLCSession, IWSLCCompatSession, IFastRundown, ISupportErrorInfo> |
| 84 | { |
| 85 | // WSLCContainer::Delete acquires a VmLease to keep the VM alive (and block idle |
| 86 | // teardown) for the duration of a container deletion. |
| 87 | friend class WSLCContainer; |
| 88 | |
| 89 | public: |
| 90 | WSLCSession() : m_runtime(*this) |
| 91 | { |
| 92 | } |
| 93 | |
| 94 | ~WSLCSession(); |
| 95 | |
| 96 | // Sets a callback invoked when this object is destroyed. |
| 97 | // Used by the COM server host to signal process exit. |
| 98 | void SetDestructionCallback(std::function<void()>&& callback); |
| 99 | |
| 100 | // Type of m_crashDumpCallbacks. Exposed so CrashDumpSubscription can hold an iterator into |
| 101 | // it as an O(1) registration handle. |
| 102 | using CrashDumpCallbackList = std::list<wil::com_ptr<ICrashDumpCallback>>; |
| 103 | |
| 104 | // IWSLCSession - initialization methods |
| 105 | IFACEMETHOD(GetProcessHandle)(_Out_ HANDLE* ProcessHandle) override; |
| 106 | IFACEMETHOD(Initialize)( |
| 107 | _In_ const WSLCSessionInitSettings* Settings, |
| 108 | _In_ IWSLCVirtualMachineFactory* VmFactory, |
| 109 | _In_ IWSLCPluginNotifier* PluginNotifier, |
| 110 | _In_opt_ IWarningCallback* WarningCallback) override; |
| 111 | |
| 112 | IFACEMETHOD(GetId)(_Out_ ULONG* Id) override; |
| 113 | IFACEMETHOD(GetDisplayName)(_Out_ LPWSTR* DisplayName) override; |
| 114 | IFACEMETHOD(GetState)(_Out_ WSLCSessionState* State) override; |
| 115 | IFACEMETHOD(GetTerminationEvent)(_Out_ HANDLE* Event) override; |
| 116 | IFACEMETHOD(GetTerminationReason)(_Out_ WSLCVirtualMachineTerminationReason* Reason, _Out_ LPWSTR* Details) override; |
| 117 | |
| 118 | // Event streaming. Opens a stream object that yields matching events one at a time via |
| 119 | // IWSLCEventStream::GetNext. |
| 120 | IFACEMETHOD(GetEvents)( |
| 121 | _In_ LONGLONG SinceTime, |
| 122 | _In_ LONGLONG UntilTime, |
| 123 | _In_reads_opt_(FiltersCount) const WSLCFilter* Filters, |
| 124 | _In_ ULONG FiltersCount, |
| 125 | _Outptr_ IWSLCEventStream** Stream) override; |
| 126 | |
| 127 | // Image management. |
| 128 | IFACEMETHOD(PullImage)( |
| 129 | _In_ LPCSTR Image, |
| 130 | _In_opt_ LPCSTR RegistryAuthenticationInformation, |
| 131 | _In_opt_ IProgressCallback* ProgressCallback, |
| 132 | _In_opt_ IWarningCallback* WarningCallback) override; |
| 133 | IFACEMETHOD(BuildImage)(_In_ const WSLCBuildImageOptions* Options, _In_opt_ IProgressCallback* ProgressCallback, _In_opt_ HANDLE CancelEvent) override; |
| 134 | IFACEMETHOD(LoadImage)( |
| 135 | _In_ const WSLCHandle ImageHandle, |
| 136 | _In_ ULONGLONG ContentLength, |
| 137 | _In_opt_ IWarningCallback* WarningCallback, |
| 138 | _In_opt_ IImageLoadCallback* LoadCallback) override; |
| 139 | IFACEMETHOD(ImportImage)( |
| 140 | _In_ const WSLCHandle ImageHandle, |
| 141 | _In_opt_ LPCSTR ImageName, |
| 142 | _In_ ULONGLONG ContentLength, |
| 143 | _In_opt_ IWarningCallback* WarningCallback, |
| 144 | _Out_ LPSTR* ImageId) override; |
| 145 | IFACEMETHOD(SaveImage)(_In_ WSLCHandle OutputHandle, _In_ LPCSTR ImageNameOrID, _In_ IProgressCallback* ProgressCallback, _In_opt_ HANDLE CancelEvent) override; |
| 146 | IFACEMETHOD(SaveImages)(_In_ WSLCHandle OutputHandle, _In_ const WSLCStringArray* ImageNames, _In_ IProgressCallback* ProgressCallback, _In_opt_ HANDLE CancelEvent) override; |
| 147 | IFACEMETHOD(ListImages)(_In_opt_ const WSLCListImagesOptions* Options, _Out_ WSLCImageInformation** Images, _Out_ ULONG* Count) override; |
| 148 | IFACEMETHOD(DeleteImage)(_In_ const WSLCDeleteImageOptions* Options, _Out_ WSLCDeletedImageInformation** DeletedImages, _Out_ ULONG* Count) override; |
| 149 | IFACEMETHOD(TagImage)(_In_ const WSLCTagImageOptions* Options) override; |
| 150 | IFACEMETHOD(PushImage)( |
| 151 | _In_ LPCSTR Image, |
| 152 | _In_ LPCSTR RegistryAuthenticationInformation, |
| 153 | _In_opt_ IProgressCallback* ProgressCallback, |
| 154 | _In_opt_ IWarningCallback* WarningCallback) override; |
| 155 | IFACEMETHOD(InspectImage)(_In_ LPCSTR ImageNameOrId, _Out_ LPSTR* Output) override; |
| 156 | IFACEMETHOD(Authenticate)(_In_ LPCSTR ServerAddress, _In_ LPCSTR Username, _In_ LPCSTR Password, _Out_ LPSTR* IdentityToken) override; |
| 157 | IFACEMETHOD(PruneImages)( |
| 158 | _In_opt_ const WSLCFilter* Filters, |
| 159 | _In_ ULONG FiltersCount, |
| 160 | _Out_ WSLCDeletedImageInformation** DeletedImages, |
| 161 | _Out_ ULONG* DeletedImagesCount, |
| 162 | _Out_ ULONGLONG* SpaceReclaimed) override; |
| 163 | |
| 164 | // Container management. |
| 165 | IFACEMETHOD(CreateContainer)(_In_ const WSLCContainerOptions* Options, _In_opt_ IWarningCallback* WarningCallback, _Out_ IWSLCContainer** Container) override; |
| 166 | IFACEMETHOD(OpenContainer)(_In_ LPCSTR Id, _In_ IWSLCContainer** Container) override; |
| 167 | IFACEMETHOD(BeginContainerOperation)(_Outptr_ IUnknown** Operation) override; |
| 168 | IFACEMETHOD(ListContainers)( |
| 169 | _In_opt_ const WSLCListContainersOptions* Options, |
| 170 | _Out_ WSLCContainerEntry** Containers, |
| 171 | _Out_ ULONG* Count, |
| 172 | _Out_ WSLCContainerPortMapping** Ports, |
| 173 | _Out_ ULONG* PortsCount) override; |
| 174 | IFACEMETHOD(PruneContainers)(_In_opt_ const WSLCFilter* Filters, _In_ ULONG FiltersCount, _Out_ WSLCPruneContainersResults* Result) override; |
| 175 | |
| 176 | // VM management. |
| 177 | IFACEMETHOD(CreateRootNamespaceProcess)( |
| 178 | _In_ LPCSTR Executable, |
| 179 | _In_ const WSLCProcessOptions* Options, |
| 180 | _In_ ULONG TtyRows, |
| 181 | _In_ ULONG TtyColumns, |
| 182 | _In_ BOOL AcquireVmLease, |
| 183 | _Out_ IWSLCProcess** VirtualMachine, |
| 184 | _Out_ int* Errno) override; |
| 185 | |
| 186 | // Disk management. |
| 187 | IFACEMETHOD(FormatVirtualDisk)(_In_ LPCWSTR Path) override; |
| 188 | |
| 189 | // Volume management. |
| 190 | IFACEMETHOD(CreateVolume)(_In_ const WSLCVolumeOptions* Options, _Out_ WSLCVolumeInformation* VolumeInfo) override; |
| 191 | IFACEMETHOD(DeleteVolume)(_In_ LPCSTR Name) override; |
| 192 | IFACEMETHOD(ListVolumes) |
| 193 | (_In_reads_opt_(FiltersCount) const WSLCFilter* Filters, _In_ ULONG FiltersCount, _Out_ LPSTR* Output) override; |
| 194 | IFACEMETHOD(InspectVolume)(_In_ LPCSTR Name, _Out_ LPSTR* Output) override; |
| 195 | IFACEMETHOD(PruneVolumes) |
| 196 | (_In_reads_opt_(FiltersCount) const WSLCFilter* Filters, |
| 197 | _In_ ULONG FiltersCount, |
| 198 | _In_opt_ IWarningCallback* WarningCallback, |
| 199 | _Out_ WSLCVolumeName** Volumes, |
| 200 | _Out_ ULONG* VolumesCount, |
| 201 | _Out_ ULONGLONG* SpaceReclaimed) override; |
| 202 | |
| 203 | // Network management. |
| 204 | IFACEMETHOD(CreateNetwork)(_In_ const WSLCNetworkOptions* Options, _In_opt_ IWarningCallback* WarningCallback) override; |
| 205 | IFACEMETHOD(DeleteNetwork)(_In_ LPCSTR Name) override; |
| 206 | IFACEMETHOD(ListNetworks) |
| 207 | (_In_reads_opt_(FiltersCount) const WSLCFilter* Filters, _In_ ULONG FiltersCount, _Out_ LPSTR* Output) override; |
| 208 | IFACEMETHOD(InspectNetwork)(_In_ LPCSTR Name, _Out_ LPSTR* Output) override; |
| 209 | IFACEMETHOD(PruneNetworks) |
| 210 | (_In_reads_opt_(FiltersCount) const WSLCFilter* Filters, _In_ ULONG FiltersCount, _Out_ WSLCNetworkName** Networks, _Out_ ULONG* NetworksCount) |
| 211 | override; |
| 212 | |
| 213 | IFACEMETHOD(Terminate()) override; |
| 214 | |
| 215 | IFACEMETHOD(RegisterCrashDumpCallback)(_In_ ICrashDumpCallback* Callback, _Out_ IUnknown** Subscription) override; |
| 216 | |
| 217 | // Called by CrashDumpSubscription when its last reference is released. The iterator must |
| 218 | // have been returned by RegisterCrashDumpCallback against this session. |
| 219 | void RemoveCrashDumpCallback(CrashDumpCallbackList::iterator It) noexcept; |
| 220 | |
| 221 | // ISupportErrorInfo |
| 222 | IFACEMETHOD(InterfaceSupportsErrorInfo)(_In_ REFIID riid) override; |
| 223 | |
| 224 | // Testing. |
| 225 | IFACEMETHOD(MountWindowsFolder)(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ BOOL AcquireVmLease) override; |
| 226 | IFACEMETHOD(UnmountWindowsFolder)(_In_ LPCSTR LinuxPath, _In_ BOOL AcquireVmLease) override; |
| 227 | IFACEMETHOD(MapVmPort)(_In_ int Family, _In_ unsigned short WindowsPort, _In_ unsigned short LinuxPort) override; |
| 228 | IFACEMETHOD(UnmapVmPort)(_In_ int Family, _In_ unsigned short WindowsPort, _In_ unsigned short LinuxPort) override; |
| 229 | IFACEMETHOD(TriggerIdleTermination)(_Out_ BOOL* WasAlreadyIdle) override; |
| 230 | |
| 231 | // IWSLCCompatSession - converts the WSLCCompat types to the wslc.idl types and forwards to the methods above. |
| 232 | // Methods that have an identical signature in both interfaces (Terminate, DeleteVolume, Authenticate, |
| 233 | // GetTerminationReason) are served by the single existing override and require no additional code here. |
| 234 | IFACEMETHOD(PullImage)( |
| 235 | _In_ LPCSTR Image, |
| 236 | _In_opt_ LPCSTR RegistryAuthenticationInformation, |
| 237 | _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, |
| 238 | _In_opt_ IWSLCCompatWarningCallback* WarningCallback) override; |
| 239 | IFACEMETHOD(LoadImage)( |
| 240 | _In_ WSLCCompatHandle ImageHandle, |
| 241 | _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, |
| 242 | _In_ ULONGLONG ContentLength, |
| 243 | _In_opt_ IWSLCCompatWarningCallback* WarningCallback) override; |
| 244 | IFACEMETHOD(ImportImage)( |
| 245 | _In_ WSLCCompatHandle ImageHandle, |
| 246 | _In_opt_ LPCSTR ImageName, |
| 247 | _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, |
| 248 | _In_ ULONGLONG ContentLength, |
| 249 | _In_opt_ IWSLCCompatWarningCallback* WarningCallback, |
| 250 | _Out_ LPSTR* ImageId) override; |
| 251 | IFACEMETHOD(ListImages)(_In_opt_ const WSLCCompatListImagesOptions* Options, _Out_ WSLCCompatImageInformation** Images, _Out_ ULONG* Count) override; |
| 252 | IFACEMETHOD(DeleteImage)(_In_ const WSLCCompatDeleteImageOptions* Options, _Out_ WSLCCompatDeletedImageInformation** DeletedImages, _Out_ ULONG* Count) override; |
| 253 | IFACEMETHOD(TagImage)(_In_ const WSLCCompatTagImageOptions* Options) override; |
| 254 | IFACEMETHOD(PushImage)( |
| 255 | _In_ LPCSTR Image, |
| 256 | _In_ LPCSTR RegistryAuthenticationInformation, |
| 257 | _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, |
| 258 | _In_opt_ IWSLCCompatWarningCallback* WarningCallback) override; |
| 259 | IFACEMETHOD(CreateContainer)( |
| 260 | _In_ const WSLCCompatContainerOptions* Options, |
| 261 | _In_opt_ IWSLCCompatWarningCallback* WarningCallback, |
| 262 | _Out_ IWSLCCompatContainer** Container) override; |
| 263 | IFACEMETHOD(OpenContainer)(_In_ LPCSTR NameOrId, _Out_ IWSLCCompatContainer** Container) override; |
| 264 | IFACEMETHOD(CreateVolume)(_In_ const WSLCCompatVolumeOptions* Options, _Out_ WSLCCompatVolumeInformation* VolumeInfo) override; |
| 265 | IFACEMETHOD(RegisterCrashDumpCallback)(_In_ IWSLCCompatCrashDumpCallback* Callback, _Out_ IUnknown** Subscription) override; |
| 266 | |
| 267 | common::io::MultiHandleWait CreateIOContext(HANDLE CancelHandle = nullptr); |
| 268 | |
| 269 | UserHandle OpenUserHandle(WSLCHandle Handle); |
| 270 | void ReleaseUserHandle(HANDLE Handle); |
| 271 | |
| 272 | UserCOMCallback RegisterUserCOMCallback(); |
| 273 | void UnregisterUserCOMCallback(DWORD ThreadId); |
| 274 | |
| 275 | ULONG Id() const noexcept |
| 276 | { |
| 277 | return m_id; |
| 278 | } |
| 279 | |
| 280 | bool WaitForEventOrSessionTerminating(HANDLE Event, std::chrono::milliseconds Timeout) const; |
| 281 | |
| 282 | // Shared idle-termination state. Exposed so VM-scoped objects (e.g. running containers via |
| 283 | // WSLCContainerImpl's ActivityRef) can hold an activity reference for their lifetime without |
| 284 | // keeping the session object itself alive. |
| 285 | std::shared_ptr<IdleState> IdleStateShared() const noexcept |
| 286 | { |
| 287 | return m_runtime.IdleStateShared(); |
| 288 | } |
| 289 | |
| 290 | WSLCSessionRuntime& Runtime() noexcept |
| 291 | { |
| 292 | return m_runtime; |
| 293 | } |
| 294 | |
| 295 | const WSLCSessionRuntime& Runtime() const noexcept |
| 296 | { |
| 297 | return m_runtime; |
| 298 | } |
| 299 | |
| 300 | // Creates an opaque activity token that holds a reference on this session's activity count for |
| 301 | // its lifetime, deferring idle teardown of the VM until every outstanding token is released. |
| 302 | // Used both for transient client operations (BeginContainerOperation) and to keep the VM alive |
| 303 | // for the lifetime of a process whose wrapper a client may keep (root-namespace and exec'd |
| 304 | // processes). |
| 305 | Microsoft::WRL::ComPtr<IUnknown> CreateActivityToken(); |
| 306 | |
| 307 | private: |
| 308 | ULONG m_id = 0; |
| 309 | void PersistSettings(const WSLCSessionInitSettings& Settings, PSID UserSid); |
| 310 | |
| 311 | using VmLease = WSLCSessionRuntime::VmLease; |
| 312 | [[nodiscard]] VmLease AcquireLease(WSLCSessionRuntime::VmLeasePolicy Policy = WSLCSessionRuntime::VmLeasePolicy::Acquire); |
| 313 | |
| 314 | // Maps the AcquireVmLease flag that plugin-reachable methods carry onto the lease policy. The |
| 315 | // service passes FALSE for every plugin-originated call: a plugin is never a reason to create a |
| 316 | // VM, so it is served by the running one -- including one committed to stopping -- or rejected. |
| 317 | [[nodiscard]] static constexpr WSLCSessionRuntime::VmLeasePolicy LeasePolicyFor(BOOL AcquireVmLease) noexcept |
| 318 | { |
| 319 | return AcquireVmLease ? WSLCSessionRuntime::VmLeasePolicy::Acquire : WSLCSessionRuntime::VmLeasePolicy::ExistingOnly; |
| 320 | } |
| 321 | |
| 322 | __requires_lock_held(m_userHandlesLock) void CancelUserHandleIO(); |
| 323 | __requires_lock_held(m_userCOMCallbacksLock) void CancelUserCOMCallbacks(); |
| 324 | |
| 325 | void CreateContainerImpl(const WSLCContainerOptions* Options, IWSLCContainer** Container); |
| 326 | |
| 327 | // A create RPC hands the container off to the Docker event stream thread here and waits, so the |
| 328 | // container is committed and its create event recorded from that thread. Recording it from the RPC |
| 329 | // thread instead would let another container's event be recorded first and regress the event |
| 330 | // stream's timestamps. |
| 331 | struct PendingContainerCreate |
| 332 | { |
| 333 | wil::unique_event Completed{wil::EventOptions::ManualReset}; |
| 334 | std::shared_ptr<WSLCContainerImpl> Container; |
| 335 | std::exception_ptr Exception; |
| 336 | }; |
| 337 | |
| 338 | __requires_lock_held(m_containersLock) std::shared_ptr<PendingContainerCreate> StartPendingCreate(std::shared_ptr<WSLCContainerImpl> Container); |
| 339 | |
| 340 | __requires_lock_held(m_containersLock) void CompletePendingCreate( |
| 341 | const std::shared_ptr<PendingContainerCreate>& PendingCreate, std::exception_ptr Exception) noexcept; |
| 342 | |
| 343 | void WaitForPendingCreateCompletion(const std::shared_ptr<PendingContainerCreate>& PendingCreate); |
| 344 | |
| 345 | // Returns with the lock held once no create is in flight. Only one fits: the slot is unkeyed, |
| 346 | // because the container ID isn't known until Docker assigns it. |
| 347 | void WaitForConflictingCreateToComplete(std::unique_lock<std::mutex>& ContainersLock); |
| 348 | |
| 349 | void OnContainerCreated(const std::string& ContainerId, std::int64_t Time) noexcept; |
| 350 | |
| 351 | void ConfigureStorage(const WSLCSessionInitSettings& Settings, PSID UserSid); |
| 352 | |
| 353 | void Ext4Format(const std::string& Device); |
| 354 | std::string InspectImageLockHeld(const std::string& Id); |
| 355 | void OnContainerDeleted(const WSLCContainerImpl* Container); |
| 356 | |
| 357 | void OnCrashDumpWritten(const std::wstring& DumpPath, const std::string& ProcessName, ULONG Pid, ULONG Signal, ULONGLONG Timestamp); |
| 358 | |
| 359 | void OnImageCreated(const std::string& ImageNameOrId) noexcept; |
| 360 | |
| 361 | void OnImageDeleted(const std::string& ImageId) noexcept; |
| 362 | |
| 363 | void OnContainerdExited(); |
| 364 | void OnDockerdExited(); |
| 365 | ServiceRunningProcess StartProcess( |
| 366 | const std::string& Executable, const std::vector<std::string>& Args, PCSTR LogSource, std::function<void()>&& ExitCallback); |
| 367 | void InstallTrustedRootCertificates(); |
| 368 | void StartContainerd(); |
| 369 | void StartDockerd(); |
| 370 | int StopProcess(ServiceRunningProcess& Process, DWORD TerminateTimeoutMs, DWORD KillTimeoutMs); |
| 371 | std::optional<std::string> ImportImageImpl( |
| 372 | DockerHTTPClient::HTTPRequestContext& Request, const WSLCHandle ImageHandle, IImageLoadCallback* LoadCallback = nullptr); |
| 373 | void RecoverExistingContainers(); |
| 374 | void RecoverExistingNetworks(); |
| 375 | |
| 376 | void SaveImageImpl(std::pair<uint32_t, wil::unique_socket>& RequestCodePair, WSLCHandle OutputHandle, HANDLE CancelEvent); |
| 377 | void StreamImageOperation(DockerHTTPClient::HTTPRequestContext& requestContext, LPCSTR Image, LPCSTR OperationName, IProgressCallback* ProgressCallback); |
| 378 | |
| 379 | // The VM factory is a cross-process proxy supplied by the SYSTEM service at Initialize() time |
| 380 | // but first used later (on demand) from a different thread/apartment. A directly stored proxy |
| 381 | // would fail with RPC_E_WRONG_THREAD, so it is parked in the process Global Interface Table and |
| 382 | // re-fetched (re-marshalled into the calling apartment) each time a VM is created. |
| 383 | wil::com_ptr<IGlobalInterfaceTable> m_git; |
| 384 | DWORD m_vmFactoryGitCookie{}; |
| 385 | |
| 386 | WSLCSessionRuntime m_runtime; |
| 387 | std::wstring m_displayName; |
| 388 | std::wstring m_creatorProcessName; |
| 389 | std::filesystem::path m_storageVhdPath; |
| 390 | |
| 391 | // N.B. The runtime lock must be acquired before acquiring m_containersLock or m_networksLock. |
| 392 | // These locks protect m_containers without requiring an exclusive hold on the runtime lock. |
| 393 | // This allows independent operations to proceed while container bookkeeping remains synchronized. |
| 394 | // WSLCVolumes has its own internal srwlock and does not require the runtime lock. |
| 395 | std::mutex m_containersLock; |
| 396 | std::unordered_map<std::string, std::shared_ptr<WSLCContainerImpl>> m_containers; |
| 397 | std::mutex m_networksLock; |
| 398 | std::unordered_map<std::string, NetworkEntry> m_networks; |
| 399 | wil::shared_event m_sessionTerminatingEvent{wil::EventOptions::ManualReset}; |
| 400 | wil::shared_event m_sessionTerminatedEvent{wil::EventOptions::ManualReset}; |
| 401 | |
| 402 | WSLCVirtualMachineTerminationReason m_terminationReason{WSLCVirtualMachineTerminationReasonUnknown}; |
| 403 | std::wstring m_terminationDetails; |
| 404 | |
| 405 | // Persisted settings required to (re)create the VM on demand. The string fields point |
| 406 | // into the owned storage members below (or m_displayName) so they remain valid for the |
| 407 | // lifetime of the session. |
| 408 | WSLCSessionInitSettings m_settings{}; |
| 409 | std::optional<std::wstring> m_settingsCreatorProcessName; |
| 410 | std::optional<std::wstring> m_settingsStoragePath; |
| 411 | std::optional<std::string> m_settingsRootVhdTypeOverride; |
| 412 | std::vector<BYTE> m_userSid; |
| 413 | |
| 414 | WSLCFeatureFlags m_featureFlags{}; |
| 415 | std::function<void()> m_destructionCallback; |
| 416 | std::atomic<bool> m_terminating{false}; |
| 417 | |
| 418 | wil::com_ptr<IWSLCPluginNotifier> m_pluginNotifier; |
| 419 | |
| 420 | // Bounded in-memory ring of recent lifecycle events, shared by all event-stream subscribers. |
| 421 | EventStore m_eventStore; |
| 422 | |
| 423 | __guarded_by(m_containersLock) std::shared_ptr<PendingContainerCreate> m_pendingCreate; |
| 424 | |
| 425 | // N.B. Declared after everything OnContainerCreated() touches so the callback is unregistered first. |
| 426 | DockerEventTracker::EventTrackingReference m_containerEventTracking; |
| 427 | |
| 428 | // User-provided handles that the session is currently doing IO on. |
| 429 | std::mutex m_userHandlesLock; |
| 430 | __guarded_by(m_userHandlesLock) std::vector<HANDLE> m_userHandles; |
| 431 | |
| 432 | // Threads currently inside an outgoing COM callback (e.g. IProgressCallback::OnProgress). |
| 433 | std::recursive_mutex m_userCOMCallbacksLock; |
| 434 | __guarded_by(m_userCOMCallbacksLock) std::map<DWORD, int> m_userCOMCallbackThreads; |
| 435 | |
| 436 | // Callbacks registered via RegisterCrashDumpCallback. std::list gives stable iterators that |
| 437 | // survive insertions and unrelated erasures, so each CrashDumpSubscription stashes its own |
| 438 | // iterator and uses it as an O(1) removal handle when the last reference is released. |
| 439 | // The session's lifetime extends past Terminate() (the COM object outlives the VM), so this |
| 440 | // list may outlive the runtime VM instance; that's fine because dispatch only runs while the VM |
| 441 | // thread is alive. |
| 442 | mutable wil::srwlock m_crashDumpLock; |
| 443 | _Guarded_by_(m_crashDumpLock) CrashDumpCallbackList m_crashDumpCallbacks; |
| 444 | |
| 445 | friend class WSLCSessionRuntime; |
| 446 | }; |
| 447 | |
| 448 | } // namespace wsl::windows::service::wslc |