From b90dd8ee393906ac8f3d3c65bc3e200245972a99 Mon Sep 17 00:00:00 2001 From: Blue Date: Thu, 11 Jun 2026 14:07:02 -0700 Subject: [PATCH 1/6] Save state --- msipackage/package.wix.in | 64 +++ src/windows/WslcSDK/CrashDumpCallback.cpp | 2 +- src/windows/WslcSDK/CrashDumpCallback.h | 10 +- src/windows/WslcSDK/IOCallback.cpp | 15 +- src/windows/WslcSDK/IOCallback.h | 8 +- src/windows/WslcSDK/ProgressCallback.cpp | 2 +- src/windows/WslcSDK/ProgressCallback.h | 8 +- src/windows/WslcSDK/TerminationCallback.cpp | 10 +- src/windows/WslcSDK/TerminationCallback.h | 10 +- src/windows/WslcSDK/WslcsdkPrivate.h | 12 +- src/windows/WslcSDK/wslcsdk.cpp | 173 +++--- src/windows/common/WSLCSDKCallbackAdapters.h | 136 +++++ .../service/exe/WSLCSessionManager.cpp | 63 ++ src/windows/service/exe/WSLCSessionManager.h | 9 +- src/windows/service/inc/CMakeLists.txt | 2 +- src/windows/service/inc/WSLSDK.idl | 539 ++++++++++++++++++ src/windows/service/inc/wslc.idl | 5 + src/windows/service/stub/CMakeLists.txt | 2 + src/windows/wslcsession/WSLCContainer.cpp | 54 ++ src/windows/wslcsession/WSLCContainer.h | 11 +- src/windows/wslcsession/WSLCProcess.cpp | 16 +- src/windows/wslcsession/WSLCProcess.h | 7 +- src/windows/wslcsession/WSLCSession.cpp | 99 ++++ src/windows/wslcsession/WSLCSession.h | 30 +- test/windows/WslcSdkTests.cpp | 8 +- test/windows/WslcSdkWinRTTests.cpp | 4 +- 26 files changed, 1179 insertions(+), 120 deletions(-) create mode 100644 src/windows/common/WSLCSDKCallbackAdapters.h create mode 100644 src/windows/service/inc/WSLSDK.idl diff --git a/msipackage/package.wix.in b/msipackage/package.wix.in index 88dc3ea171..b3b476f801 100644 --- a/msipackage/package.wix.in +++ b/msipackage/package.wix.in @@ -386,6 +386,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/windows/WslcSDK/CrashDumpCallback.cpp b/src/windows/WslcSDK/CrashDumpCallback.cpp index 4490d710be..a157ab6b07 100644 --- a/src/windows/WslcSDK/CrashDumpCallback.cpp +++ b/src/windows/WslcSDK/CrashDumpCallback.cpp @@ -8,7 +8,7 @@ Module Name: Abstract: - Implementation of a type that implements ICrashDumpCallback. + Implementation of a type that implements IWSLCSDKCrashDumpCallback. --*/ #include "precomp.h" diff --git a/src/windows/WslcSDK/CrashDumpCallback.h b/src/windows/WslcSDK/CrashDumpCallback.h index 28014fd603..25949df4bb 100644 --- a/src/windows/WslcSDK/CrashDumpCallback.h +++ b/src/windows/WslcSDK/CrashDumpCallback.h @@ -8,21 +8,21 @@ Module Name: Abstract: - Header for a type that implements ICrashDumpCallback. Bridges the COM - ICrashDumpCallback interface back to the C-style SDK callback registered + Header for a type that implements IWSLCSDKCrashDumpCallback. Bridges the COM + IWSLCSDKCrashDumpCallback interface back to the C-style SDK callback registered via WslcRegisterSessionCrashDumpCallback. --*/ #pragma once -#include "wslc.h" +#include "WSLSDK.h" #include "wslcsdkprivate.h" #include -struct CrashDumpCallback : public winrt::implements +struct CrashDumpCallback : public winrt::implements { CrashDumpCallback(WslcSessionCrashDumpCallback callback, PVOID context); - // ICrashDumpCallback + // IWSLCSDKCrashDumpCallback HRESULT STDMETHODCALLTYPE OnCrashDump(_In_ LPCWSTR DumpPath, _In_opt_ LPCSTR ProcessName, _In_ ULONGLONG Pid, _In_ ULONG Signal, _In_ ULONGLONG Timestamp) override; private: diff --git a/src/windows/WslcSDK/IOCallback.cpp b/src/windows/WslcSDK/IOCallback.cpp index ffc1733ad1..c2283d100e 100644 --- a/src/windows/WslcSDK/IOCallback.cpp +++ b/src/windows/WslcSDK/IOCallback.cpp @@ -14,7 +14,7 @@ Module Name: #include "precomp.h" #include "WslcsdkPrivate.h" -IOCallback::IOCallback(IWSLCProcess* process, const WslcContainerProcessIOCallbackOptions& options) : +IOCallback::IOCallback(IWSLCSDKProcess* process, const WslcContainerProcessIOCallbackOptions& options) : m_process(process), m_callbackOptions(std::make_unique(options)) { using namespace wsl::windows::common::io; @@ -55,7 +55,7 @@ IOCallback::IOCallback(IWSLCProcess* process, const WslcContainerProcessIOCallba if (runResult && m_process && m_callbackOptions && m_callbackOptions->onExit) { - WSLCProcessState state{}; + WSLCSDKProcessState state{}; int exitCode = -1; // Prefer to make the callback even if we don't properly retrieve the exit code. @@ -66,7 +66,7 @@ IOCallback::IOCallback(IWSLCProcess* process, const WslcContainerProcessIOCallba } else { - WI_ASSERT(state == WslcProcessStateExited); + WI_ASSERT(state == WSLCSDKProcessStateExited); } // Regardless of our ability to get the proper exit code, inform the caller that the process @@ -119,11 +119,12 @@ bool IOCallback::HasIOCallback(const WslcContainerProcessIOCallbackOptions& opti return options.onStdOut || options.onStdErr || options.onExit; } -wil::unique_handle IOCallback::GetIOHandle(IWSLCProcess* process, WslcProcessIOHandle ioHandle) +wil::unique_handle IOCallback::GetIOHandle(IWSLCSDKProcess* process, WslcProcessIOHandle ioHandle) { - wsl::windows::common::wslutil::COMOutputHandle handle; + WSLCSDKHandle handle{}; - THROW_IF_FAILED(process->GetStdHandle(static_cast(static_cast>(ioHandle)), &handle)); + THROW_IF_FAILED(process->GetStdHandle(static_cast(static_cast>(ioHandle)), &handle)); - return handle.Release(); + // The handle value is the same regardless of the union member that was populated. + return wil::unique_handle{handle.Handle.File}; } diff --git a/src/windows/WslcSDK/IOCallback.h b/src/windows/WslcSDK/IOCallback.h index f018eb1498..b311f0186c 100644 --- a/src/windows/WslcSDK/IOCallback.h +++ b/src/windows/WslcSDK/IOCallback.h @@ -12,7 +12,7 @@ Module Name: --*/ #pragma once -#include "wslc.h" +#include "WSLSDK.h" #include "relay.hpp" #include @@ -21,7 +21,7 @@ struct WslcContainerProcessOptionsInternal; struct IOCallback { - IOCallback(IWSLCProcess* process, const WslcContainerProcessIOCallbackOptions& options); + IOCallback(IWSLCSDKProcess* process, const WslcContainerProcessIOCallbackOptions& options); ~IOCallback(); void Cancel(); @@ -32,10 +32,10 @@ struct IOCallback static bool HasIOCallback(const WslcContainerProcessOptionsInternal* options); static bool HasIOCallback(const WslcContainerProcessIOCallbackOptions& options); - static wil::unique_handle GetIOHandle(IWSLCProcess* process, WslcProcessIOHandle ioHandle); + static wil::unique_handle GetIOHandle(IWSLCSDKProcess* process, WslcProcessIOHandle ioHandle); private: - wil::com_ptr m_process; + wil::com_ptr m_process; std::unique_ptr m_callbackOptions; std::thread m_thread; wsl::windows::common::io::MultiHandleWait m_io; diff --git a/src/windows/WslcSDK/ProgressCallback.cpp b/src/windows/WslcSDK/ProgressCallback.cpp index 244480b4b9..801ff33e6d 100644 --- a/src/windows/WslcSDK/ProgressCallback.cpp +++ b/src/windows/WslcSDK/ProgressCallback.cpp @@ -8,7 +8,7 @@ Module Name: Abstract: - Implementation of a type that implements IProgressCallback. + Implementation of a type that implements IWSLCSDKProgressCallback. --*/ #include "precomp.h" diff --git a/src/windows/WslcSDK/ProgressCallback.h b/src/windows/WslcSDK/ProgressCallback.h index 8668a44cb0..9e53c156c7 100644 --- a/src/windows/WslcSDK/ProgressCallback.h +++ b/src/windows/WslcSDK/ProgressCallback.h @@ -8,19 +8,19 @@ Module Name: Abstract: - Header for a type that implements IProgressCallback. + Header for a type that implements IWSLCSDKProgressCallback. --*/ #pragma once -#include "wslc.h" +#include "WSLSDK.h" #include "wslcsdkprivate.h" #include -struct ProgressCallback : public winrt::implements +struct ProgressCallback : public winrt::implements { ProgressCallback(WslcContainerImageProgressCallback callback, PVOID context); - // IProgressCallback + // IWSLCSDKProgressCallback HRESULT STDMETHODCALLTYPE OnProgress(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total) override; // Creates a ProgressCallback if the options provides a callback. diff --git a/src/windows/WslcSDK/TerminationCallback.cpp b/src/windows/WslcSDK/TerminationCallback.cpp index bd98a59529..aa38bdfb4f 100644 --- a/src/windows/WslcSDK/TerminationCallback.cpp +++ b/src/windows/WslcSDK/TerminationCallback.cpp @@ -8,20 +8,20 @@ Module Name: Abstract: - Implementation of a type that implements ITerminationCallback. + Implementation of a type that implements IWSLCSDKTerminationCallback. --*/ #include "precomp.h" #include "TerminationCallback.h" namespace { -WslcSessionTerminationReason ConvertReason(WSLCVirtualMachineTerminationReason Reason) +WslcSessionTerminationReason ConvertReason(WSLCSDKVirtualMachineTerminationReason Reason) { switch (Reason) { - case WSLCVirtualMachineTerminationReasonShutdown: + case WSLCSDKVirtualMachineTerminationReasonShutdown: return WSLC_SESSION_TERMINATION_REASON_SHUTDOWN; - case WSLCVirtualMachineTerminationReasonCrashed: + case WSLCSDKVirtualMachineTerminationReasonCrashed: return WSLC_SESSION_TERMINATION_REASON_CRASHED; default: return WSLC_SESSION_TERMINATION_REASON_UNKNOWN; @@ -35,7 +35,7 @@ TerminationCallback::TerminationCallback(WslcSessionTerminationCallback callback } // TODO: Details from the runtime are dropped; should the SDK callback function be updated to include the reasons string? -HRESULT STDMETHODCALLTYPE TerminationCallback::OnTermination(WSLCVirtualMachineTerminationReason Reason, LPCWSTR) +HRESULT STDMETHODCALLTYPE TerminationCallback::OnTermination(WSLCSDKVirtualMachineTerminationReason Reason, LPCWSTR) { if (m_callback) { diff --git a/src/windows/WslcSDK/TerminationCallback.h b/src/windows/WslcSDK/TerminationCallback.h index afd8542bf3..dcaceff44f 100644 --- a/src/windows/WslcSDK/TerminationCallback.h +++ b/src/windows/WslcSDK/TerminationCallback.h @@ -8,20 +8,20 @@ Module Name: Abstract: - Header for a type that implements ITerminationCallback. + Header for a type that implements IWSLCSDKTerminationCallback. --*/ #pragma once -#include "wslc.h" +#include "WSLSDK.h" #include "wslcsdkprivate.h" #include -struct TerminationCallback : public winrt::implements +struct TerminationCallback : public winrt::implements { TerminationCallback(WslcSessionTerminationCallback callback, PVOID context); - // ITerminationCallback - HRESULT STDMETHODCALLTYPE OnTermination(WSLCVirtualMachineTerminationReason Reason, LPCWSTR Details) override; + // IWSLCSDKTerminationCallback + HRESULT STDMETHODCALLTYPE OnTermination(WSLCSDKVirtualMachineTerminationReason Reason, LPCWSTR Details) override; // Creates a TerminationCallback if the options provides a callback. static winrt::com_ptr CreateIf(const WslcSessionOptionsInternal* options); diff --git a/src/windows/WslcSDK/WslcsdkPrivate.h b/src/windows/WslcSDK/WslcsdkPrivate.h index 5000363abd..c12c5b82a2 100644 --- a/src/windows/WslcSDK/WslcsdkPrivate.h +++ b/src/windows/WslcSDK/WslcsdkPrivate.h @@ -14,7 +14,7 @@ Module Name: #pragma once #include #include "wslcsdk.h" -#include "wslc.h" +#include "WSLSDK.h" #include "IOCallback.h" #include #include // COM helpers @@ -106,8 +106,8 @@ const WslcContainerOptionsInternal* GetInternalType(const WslcContainerSettings* // Use to allocate the actual objects on the heap to keep it alive. struct WslcSessionImpl { - wil::com_ptr session; - wil::com_ptr terminationCallback; + wil::com_ptr session; + wil::com_ptr terminationCallback; }; WslcSessionImpl* GetInternalType(WslcSession handle); @@ -116,7 +116,7 @@ WslcSessionImpl* GetInternalType(WslcSession handle); // subscription whose release unregisters the callback. struct WslcCrashDumpSubscriptionImpl { - wil::com_ptr callback; + wil::com_ptr callback; wil::com_ptr subscription; }; @@ -124,7 +124,7 @@ WslcCrashDumpSubscriptionImpl* GetInternalType(WslcCrashDumpSubscription handle) struct WslcContainerImpl { - wil::com_ptr container; + wil::com_ptr container; WslcContainerProcessIOCallbackOptions ioCallbackOptions{}; std::atomic> ioCallbacks; }; @@ -133,7 +133,7 @@ WslcContainerImpl* GetInternalType(WslcContainer handle); struct WslcProcessImpl { - wil::com_ptr process; + wil::com_ptr process; std::shared_ptr ioCallbacks; }; diff --git a/src/windows/WslcSDK/wslcsdk.cpp b/src/windows/WslcSDK/wslcsdk.cpp index 25dcdf1426..d07904e86c 100644 --- a/src/windows/WslcSDK/wslcsdk.cpp +++ b/src/windows/WslcSDK/wslcsdk.cpp @@ -41,35 +41,35 @@ struct FlagsTraits template <> struct FlagsTraits { - using WslcType = WSLCFeatureFlags; + using WslcType = WSLCSDKFeatureFlags; constexpr static WslcSessionFeatureFlags Mask = WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU; - WSLC_FLAG_VALUE_ASSERT(WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU, WslcFeatureFlagsGPU); + WSLC_FLAG_VALUE_ASSERT(WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU, WSLCSDKFeatureFlagsGPU); }; template <> struct FlagsTraits { - using WslcType = WSLCContainerFlags; + using WslcType = WSLCSDKContainerFlags; constexpr static WslcContainerFlags Mask = WSLC_CONTAINER_FLAG_AUTO_REMOVE | WSLC_CONTAINER_FLAG_ENABLE_GPU; - WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_AUTO_REMOVE, WSLCContainerFlagsRm); - WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_ENABLE_GPU, WSLCContainerFlagsGpu); + WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_AUTO_REMOVE, WSLCSDKContainerFlagsRm); + WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_ENABLE_GPU, WSLCSDKContainerFlagsGpu); // TODO: WSLC_CONTAINER_FLAG_PRIVILEGED has no associated runtime value }; template <> struct FlagsTraits { - using WslcType = WSLCContainerStartFlags; + using WslcType = WSLCSDKContainerStartFlags; constexpr static WslcContainerStartFlags Mask = WSLC_CONTAINER_START_FLAG_ATTACH; - WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_START_FLAG_ATTACH, WSLCContainerStartFlagsAttach); + WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_START_FLAG_ATTACH, WSLCSDKContainerStartFlagsAttach); }; template <> struct FlagsTraits { - using WslcType = WSLCDeleteFlags; + using WslcType = WSLCSDKDeleteFlags; constexpr static WslcDeleteContainerFlags Mask = WSLC_DELETE_CONTAINER_FLAG_FORCE; - WSLC_FLAG_VALUE_ASSERT(WSLC_DELETE_CONTAINER_FLAG_FORCE, WSLCDeleteFlagsForce); + WSLC_FLAG_VALUE_ASSERT(WSLC_DELETE_CONTAINER_FLAG_FORCE, WSLCSDKDeleteFlagsForce); }; template @@ -79,22 +79,22 @@ typename FlagsTraits::WslcType ConvertFlags(Flags flags) return static_cast(flags & traits::Mask); } -WSLCSignal Convert(WslcSignal signal) +WSLCSDKSignal Convert(WslcSignal signal) { switch (signal) { case WSLC_SIGNAL_NONE: - return WSLCSignal::WSLCSignalNone; + return WSLCSDKSignal::WSLCSDKSignalNone; case WSLC_SIGNAL_SIGHUP: - return WSLCSignal::WSLCSignalSIGHUP; + return WSLCSDKSignal::WSLCSDKSignalSIGHUP; case WSLC_SIGNAL_SIGINT: - return WSLCSignal::WSLCSignalSIGINT; + return WSLCSDKSignal::WSLCSDKSignalSIGINT; case WSLC_SIGNAL_SIGQUIT: - return WSLCSignal::WSLCSignalSIGQUIT; + return WSLCSDKSignal::WSLCSDKSignalSIGQUIT; case WSLC_SIGNAL_SIGKILL: - return WSLCSignal::WSLCSignalSIGKILL; + return WSLCSDKSignal::WSLCSDKSignalSIGKILL; case WSLC_SIGNAL_SIGTERM: - return WSLCSignal::WSLCSignalSIGTERM; + return WSLCSDKSignal::WSLCSDKSignalSIGTERM; default: THROW_HR_MSG(E_INVALIDARG, "Invalid WslcSignal: %i", signal); } @@ -208,7 +208,7 @@ static HRESULT InetNtopToHresult(int af, const void* src, char* dst, size_t dstC return S_OK; } -bool CopyProcessSettingsToRuntime(WSLCProcessOptions& runtimeOptions, const WslcContainerProcessOptionsInternal* initProcessOptions) +bool CopyProcessSettingsToRuntime(WSLCSDKProcessOptions& runtimeOptions, const WslcContainerProcessOptionsInternal* initProcessOptions) { if (initProcessOptions) { @@ -306,13 +306,13 @@ WslRuntimeState CheckWslRuntimeState() return DoesWslRuntimeVersionSupportWslc(version) ? WslRuntimeState::InstalledWithWslcSupport : WslRuntimeState::InstalledWithoutWslcSupport; } -std::pair, HRESULT> CreateSessionManagerRaw() +std::pair, HRESULT> CreateSessionManagerRaw() { - wil::com_ptr result; + wil::com_ptr result; HRESULT hr = CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&result)); if (SUCCEEDED(hr)) { - const WSLCVersion clientVersion{WSL_PACKAGE_VERSION_MAJOR, WSL_PACKAGE_VERSION_MINOR, WSL_PACKAGE_VERSION_REVISION}; + const WSLCSDKVersion clientVersion{WSL_PACKAGE_VERSION_MAJOR, WSL_PACKAGE_VERSION_MINOR, WSL_PACKAGE_VERSION_REVISION}; BOOL isSupported = FALSE; THROW_IF_FAILED(result->IsClientVersionSupported(&clientVersion, &isSupported)); @@ -332,7 +332,7 @@ std::pair, HRESULT> CreateSessionManagerRaw() return {result, hr}; } -wil::com_ptr CreateSessionManager() +wil::com_ptr CreateSessionManager() { auto [result, hr] = CreateSessionManagerRaw(); @@ -424,29 +424,29 @@ try ErrorInfoWrapper errorInfoWrapper{errorMessage}; auto internalType = CheckAndGetInternalType(sessionSettings); - wil::com_ptr sessionManager = CreateSessionManager(); + wil::com_ptr sessionManager = CreateSessionManager(); auto result = std::make_unique(); - WSLCSessionSettings runtimeSettings{}; + WSLCSDKSessionSettings runtimeSettings{}; runtimeSettings.DisplayName = internalType->displayName; runtimeSettings.StoragePath = internalType->storagePath; runtimeSettings.MaximumStorageSizeMb = internalType->vhdRequirements.sizeBytes / _1MB; runtimeSettings.CpuCount = internalType->cpuCount; runtimeSettings.MemoryMb = internalType->memoryMb; runtimeSettings.BootTimeoutMs = internalType->timeoutMS; - runtimeSettings.NetworkingMode = WSLCNetworkingModeVirtioProxy; + runtimeSettings.NetworkingMode = WSLCSDKNetworkingModeVirtioProxy; auto terminationCallback = TerminationCallback::CreateIf(internalType); if (terminationCallback) { - result->terminationCallback.attach(terminationCallback.as().detach()); + result->terminationCallback.attach(terminationCallback.as().detach()); runtimeSettings.TerminationCallback = terminationCallback.get(); } runtimeSettings.FeatureFlags = ConvertFlags(internalType->featureFlags); - WI_SetFlag(runtimeSettings.FeatureFlags, WslcFeatureFlagsVirtioFs); - WI_SetFlag(runtimeSettings.FeatureFlags, WslcFeatureFlagsDnsTunneling); + WI_SetFlag(runtimeSettings.FeatureFlags, WSLCSDKFeatureFlagsVirtioFs); + WI_SetFlag(runtimeSettings.FeatureFlags, WSLCSDKFeatureFlagsDnsTunneling); if (SUCCEEDED(errorInfoWrapper.CaptureResult( - sessionManager->CreateSession(&runtimeSettings, WSLCSessionFlagsNone, nullptr, &result->session)))) + sessionManager->CreateSession(&runtimeSettings, WSLCSDKSessionFlagsNone, nullptr, &result->session)))) { wsl::windows::common::security::ConfigureForCOMImpersonation(result->session.get()); *session = reinterpret_cast(result.release()); @@ -506,7 +506,7 @@ try std::string uidStr; std::string gidStr; - std::vector driverOpts; + std::vector driverOpts; driverOpts.push_back({"SizeBytes", sizeStr.c_str()}); if (options->type == WSLC_VHD_TYPE_FIXED) @@ -526,13 +526,13 @@ try driverOpts.push_back({"Gid", gidStr.c_str()}); } - WSLCVolumeOptions volumeOptions{}; + WSLCSDKVolumeOptions volumeOptions{}; volumeOptions.Name = options->name; volumeOptions.Driver = "vhd"; volumeOptions.DriverOpts = driverOpts.data(); volumeOptions.DriverOptsCount = static_cast(driverOpts.size()); - WSLCVolumeInformation volumeInfo{}; + WSLCSDKVolumeInformation volumeInfo{}; return errorInfoWrapper.CaptureResult(internalType->session->CreateVolume(&volumeOptions, &volumeInfo)); } CATCH_RETURN(); @@ -675,10 +675,10 @@ try // If the container has an IO callback registered, and the container has exited, wait until the IO callback has processed all IO. try { - WSLCContainerState state{}; + WSLCSDKContainerState state{}; THROW_IF_FAILED(internalType->container->GetState(&state)); - if (state == WslcContainerStateExited || state == WslcContainerStateDeleted) + if (state == WSLCSDKContainerStateExited || state == WSLCSDKContainerStateDeleted) { ioCallback->Complete(); } @@ -710,11 +710,11 @@ try try { - WSLCProcessState state{}; + WSLCSDKProcessState state{}; int exitCode{}; THROW_IF_FAILED(internalType->process->GetState(&state, &exitCode)); - if (state == WslcProcessStateExited || state == WslcProcessStateSignalled) + if (state == WSLCSDKProcessStateExited || state == WSLCSDKProcessStateSignalled) { internalType->ioCallbacks->Complete(); } @@ -756,8 +756,8 @@ try auto result = std::make_unique(); - WSLCContainerOptions containerOptions{}; - std::unique_ptr convertedPorts; // this must stay in same scope as containerOptions since containerOptions.Ports is getting a raw pointer to the array owned by convertedPorts. + WSLCSDKContainerOptions containerOptions{}; + std::unique_ptr convertedPorts; // this must stay in same scope as containerOptions since containerOptions.Ports is getting a raw pointer to the array owned by convertedPorts. containerOptions.Image = internalContainerSettings->image; containerOptions.Name = internalContainerSettings->runtimeName; @@ -767,14 +767,14 @@ try CopyProcessSettingsToRuntime(containerOptions.InitProcessOptions, internalContainerSettings->initProcessOptions); - std::unique_ptr convertedVolumes; + std::unique_ptr convertedVolumes; if (internalContainerSettings->volumes && internalContainerSettings->volumesCount) { - convertedVolumes = std::make_unique(internalContainerSettings->volumesCount); + convertedVolumes = std::make_unique(internalContainerSettings->volumesCount); for (uint32_t i = 0; i < internalContainerSettings->volumesCount; ++i) { const WslcContainerVolume& internalVolume = internalContainerSettings->volumes[i]; - WSLCVolume& convertedVolume = convertedVolumes[i]; + WSLCSDKVolume& convertedVolume = convertedVolumes[i]; convertedVolume.HostPath = internalVolume.windowsPath; convertedVolume.ContainerPath = internalVolume.containerPath; @@ -784,14 +784,14 @@ try containerOptions.VolumesCount = static_cast(internalContainerSettings->volumesCount); } - std::unique_ptr convertedNamedVolumes; + std::unique_ptr convertedNamedVolumes; if (internalContainerSettings->namedVolumes && internalContainerSettings->namedVolumesCount) { - convertedNamedVolumes = std::make_unique(internalContainerSettings->namedVolumesCount); + convertedNamedVolumes = std::make_unique(internalContainerSettings->namedVolumesCount); for (uint32_t i = 0; i < internalContainerSettings->namedVolumesCount; ++i) { const WslcContainerNamedVolume& internalVolume = internalContainerSettings->namedVolumes[i]; - WSLCNamedVolume& convertedVolume = convertedNamedVolumes[i]; + WSLCSDKNamedVolume& convertedVolume = convertedNamedVolumes[i]; convertedVolume.Name = internalVolume.name; convertedVolume.ContainerPath = internalVolume.containerPath; @@ -803,11 +803,11 @@ try if (internalContainerSettings->ports && internalContainerSettings->portsCount) { - convertedPorts = std::make_unique(internalContainerSettings->portsCount); + convertedPorts = std::make_unique(internalContainerSettings->portsCount); for (uint32_t i = 0; i < internalContainerSettings->portsCount; ++i) { const WslcContainerPortMapping& internalPort = internalContainerSettings->ports[i]; - WSLCPortMapping& convertedPort = convertedPorts[i]; + WSLCSDKPortMapping& convertedPort = convertedPorts[i]; convertedPort.HostPort = internalPort.windowsPort; convertedPort.ContainerPort = internalPort.containerPort; @@ -904,11 +904,11 @@ try // TODO: Consider if we should just override flags when callbacks were provided instead. RETURN_HR_IF(E_INVALIDARG, WI_IsFlagClear(flags, WSLC_CONTAINER_START_FLAG_ATTACH) && hasIOCallback); - if (SUCCEEDED(errorInfoWrapper.CaptureResult(internalType->container->Start(ConvertFlags(flags), nullptr, nullptr)))) + if (SUCCEEDED(errorInfoWrapper.CaptureResult(internalType->container->Start(ConvertFlags(flags))))) { if (hasIOCallback) { - wil::com_ptr process; + wil::com_ptr process; RETURN_IF_FAILED(internalType->container->GetInitProcess(&process)); wsl::windows::common::security::ConfigureForCOMImpersonation(process.get()); internalType->ioCallbacks = std::make_shared(process.get(), internalType->ioCallbackOptions); @@ -1065,11 +1065,11 @@ try auto internalProcessSettings = CheckAndGetInternalType(newProcessSettings); RETURN_HR_IF(E_INVALIDARG, internalProcessSettings->commandLine == nullptr || internalProcessSettings->commandLineCount == 0); - WSLCProcessOptions runtimeOptions{}; + WSLCSDKProcessOptions runtimeOptions{}; CopyProcessSettingsToRuntime(runtimeOptions, internalProcessSettings); auto result = std::make_unique(); - if (SUCCEEDED(errorInfoWrapper.CaptureResult(internalContainer->container->Exec(&runtimeOptions, nullptr, &result->process)))) + if (SUCCEEDED(errorInfoWrapper.CaptureResult(internalContainer->container->Exec(&runtimeOptions, &result->process)))) { wsl::windows::common::security::ConfigureForCOMImpersonation(result->process.get()); @@ -1090,7 +1090,7 @@ CATCH_RETURN(); STDAPI WslcGetContainerID(WslcContainer container, CHAR containerID[WSLC_CONTAINER_ID_BUFFER_SIZE]) try { - static_assert(WSLC_CONTAINER_ID_BUFFER_SIZE == sizeof(WSLCContainerId), "Container ID lengths differ."); + static_assert(WSLC_CONTAINER_ID_BUFFER_SIZE == sizeof(WSLCSDKContainerId), "Container ID lengths differ."); auto internalType = CheckAndGetInternalType(container); RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->container); @@ -1144,9 +1144,9 @@ STDAPI WslcGetContainerState(_In_ WslcContainer container, _Out_ WslcContainerSt try { static_assert( - WSLC_CONTAINER_STATE_INVALID == WslcContainerStateInvalid && WSLC_CONTAINER_STATE_CREATED == WslcContainerStateCreated && - WSLC_CONTAINER_STATE_RUNNING == WslcContainerStateRunning && - WSLC_CONTAINER_STATE_EXITED == WslcContainerStateExited && WSLC_CONTAINER_STATE_DELETED == WslcContainerStateDeleted, + WSLC_CONTAINER_STATE_INVALID == WSLCSDKContainerStateInvalid && WSLC_CONTAINER_STATE_CREATED == WSLCSDKContainerStateCreated && + WSLC_CONTAINER_STATE_RUNNING == WSLCSDKContainerStateRunning && + WSLC_CONTAINER_STATE_EXITED == WSLCSDKContainerStateExited && WSLC_CONTAINER_STATE_DELETED == WSLCSDKContainerStateDeleted, "Container state enum values mismatch."); auto internalType = CheckAndGetInternalType(container); @@ -1155,7 +1155,7 @@ try *state = WSLC_CONTAINER_STATE_INVALID; - WSLCContainerState runtimeState{}; + WSLCSDKContainerState runtimeState{}; RETURN_IF_FAILED(internalType->container->GetState(&runtimeState)); *state = static_cast(runtimeState); @@ -1279,8 +1279,8 @@ STDAPI WslcGetProcessState(_In_ WslcProcess process, _Out_ WslcProcessState* sta try { static_assert( - WSLC_PROCESS_STATE_UNKNOWN == WslcProcessStateUnknown && WSLC_PROCESS_STATE_RUNNING == WslcProcessStateRunning && - WSLC_PROCESS_STATE_EXITED == WslcProcessStateExited && WSLC_PROCESS_STATE_SIGNALLED == WslcProcessStateSignalled, + WSLC_PROCESS_STATE_UNKNOWN == WSLCSDKProcessStateUnknown && WSLC_PROCESS_STATE_RUNNING == WSLCSDKProcessStateRunning && + WSLC_PROCESS_STATE_EXITED == WSLCSDKProcessStateExited && WSLC_PROCESS_STATE_SIGNALLED == WSLCSDKProcessStateSignalled, "Process state enum values mismatch."); auto internalType = CheckAndGetInternalType(process); @@ -1289,7 +1289,7 @@ try *state = WSLC_PROCESS_STATE_UNKNOWN; - WSLCProcessState runtimeState{}; + WSLCSDKProcessState runtimeState{}; int exitCode{}; RETURN_IF_FAILED(internalType->process->GetState(&runtimeState, &exitCode)); @@ -1307,9 +1307,9 @@ try *exitCode = -1; - WSLCProcessState runtimeState{}; + WSLCSDKProcessState runtimeState{}; RETURN_IF_FAILED(internalType->process->GetState(&runtimeState, exitCode)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), runtimeState != WslcProcessStateExited); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), runtimeState != WSLCSDKProcessStateExited); return S_OK; } CATCH_RETURN(); @@ -1380,13 +1380,46 @@ try } CATCH_RETURN(); +static WSLCSDKHandle ToWSLCSDKInputHandle(HANDLE Handle) +{ + const auto type = GetFileType(Handle); + if (type == FILE_TYPE_PIPE) + { + int socketType{}; + int len = sizeof(socketType); + + // N.B. FILE_TYPE_PIPE can describe a pipe, a named pipe, or a socket. + // Check for a named pipe first, since getsockopt() can return success for a named pipe. + if (GetNamedPipeInfo(Handle, nullptr, nullptr, nullptr, nullptr)) + { + return WSLCSDKHandle{.Type = WSLCSDKHandleTypePipe, .Handle = {.Pipe = Handle}}; + } + else if (getsockopt(reinterpret_cast(Handle), SOL_SOCKET, SO_TYPE, reinterpret_cast(&socketType), &len) == 0) + { + return WSLCSDKHandle{.Type = WSLCSDKHandleTypeSocket, .Handle = {.Socket = Handle}}; + } + else + { + return WSLCSDKHandle{.Type = WSLCSDKHandleTypePipe, .Handle = {.Pipe = Handle}}; + } + } + else if (type == FILE_TYPE_DISK) + { + return WSLCSDKHandle{.Type = WSLCSDKHandleTypeFile, .Handle = {.File = Handle}}; + } + else + { + THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported handle type: %d", type); + } +} + static HRESULT WslcImportSessionImageImpl( WslcSessionImpl* internalSession, PCSTR imageName, const WslcImportImageOptions* options, ErrorInfoWrapper& errorInfoWrapper, const ImageFileResolver& imageFile) { auto progressCallback = ProgressCallback::CreateIf(options); return errorInfoWrapper.CaptureResult(internalSession->session->ImportImage( - ToCOMInputHandle(imageFile.Handle()), imageName, progressCallback.get(), imageFile.Length(), nullptr)); + ToWSLCSDKInputHandle(imageFile.Handle()), imageName, progressCallback.get(), imageFile.Length(), nullptr)); } STDAPI WslcImportSessionImage( @@ -1424,7 +1457,7 @@ static HRESULT WslcLoadSessionImageImpl( auto progressCallback = ProgressCallback::CreateIf(options); return errorInfoWrapper.CaptureResult( - internalSession->session->LoadImage(ToCOMInputHandle(imageFile.Handle()), progressCallback.get(), imageFile.Length(), nullptr)); + internalSession->session->LoadImage(ToWSLCSDKInputHandle(imageFile.Handle()), progressCallback.get(), imageFile.Length(), nullptr)); } STDAPI WslcLoadSessionImage( @@ -1460,11 +1493,11 @@ try RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->session); RETURN_HR_IF_NULL(E_POINTER, nameOrID); - WSLCDeleteImageOptions options{}; + WSLCSDKDeleteImageOptions options{}; options.Image = nameOrID; // TODO: Flags? (Force and NoPrune) - wil::unique_cotaskmem_array_ptr deletedImageInformation; + wil::unique_cotaskmem_array_ptr deletedImageInformation; return errorInfoWrapper.CaptureResult( internalType->session->DeleteImage(&options, &deletedImageInformation, deletedImageInformation.size_address())); @@ -1482,7 +1515,7 @@ try RETURN_HR_IF_NULL(E_INVALIDARG, options->repo); RETURN_HR_IF_NULL(E_INVALIDARG, options->tag); - WSLCTagImageOptions runtimeOptions{}; + WSLCSDKTagImageOptions runtimeOptions{}; runtimeOptions.Image = options->image; runtimeOptions.Repo = options->repo; runtimeOptions.Tag = options->tag; @@ -1542,7 +1575,7 @@ STDAPI WslcListSessionImages(_In_ WslcSession session, _Outptr_result_buffer_(*c try { static_assert( - sizeof(decltype(WslcImageInfo::name)) == sizeof(decltype(WSLCImageInformation::Image)), "Image name size mismatch."); + sizeof(decltype(WslcImageInfo::name)) == sizeof(decltype(WSLCSDKImageInformation::Image)), "Image name size mismatch."); RETURN_HR_IF_NULL(E_POINTER, images); *images = nullptr; @@ -1553,7 +1586,7 @@ try // TODO: Many filtering options are available via WSLC_LIST_IMAGES_OPTIONS - wil::unique_cotaskmem_array_ptr imageInformation; + wil::unique_cotaskmem_array_ptr imageInformation; RETURN_IF_FAILED(internalType->session->ListImages(nullptr, &imageInformation, imageInformation.size_address())); @@ -1564,14 +1597,14 @@ try for (size_t i = 0; i < imageInformation.size(); ++i) { WslcImageInfo& currentResult = result[i]; - WSLCImageInformation& currentImage = imageInformation[i]; + WSLCSDKImageInformation& currentImage = imageInformation[i]; static_assert(std::is_trivial_v, "WslcImageInfo must be trivial."); currentResult = {}; THROW_HR_IF( E_UNEXPECTED, - memcpy_s(currentResult.name, sizeof(decltype(WslcImageInfo::name)), currentImage.Image, sizeof(decltype(WSLCImageInformation::Image))) != + memcpy_s(currentResult.name, sizeof(decltype(WslcImageInfo::name)), currentImage.Image, sizeof(decltype(WSLCSDKImageInformation::Image))) != 0); ConvertSHA256Hash(currentImage.Hash, currentResult.sha256); currentResult.sizeBytes = currentImage.Size; @@ -1629,9 +1662,9 @@ try static_assert(std::is_trivial_v, "WslcVersion must be trivial"); *version = {}; - wil::com_ptr sessionManager = CreateSessionManager(); + wil::com_ptr sessionManager = CreateSessionManager(); - WSLCVersion runtimeVersion{}; + WSLCSDKVersion runtimeVersion{}; RETURN_IF_FAILED(sessionManager->GetVersion(&runtimeVersion)); version->major = runtimeVersion.Major; diff --git a/src/windows/common/WSLCSDKCallbackAdapters.h b/src/windows/common/WSLCSDKCallbackAdapters.h new file mode 100644 index 0000000000..6b6342ee8e --- /dev/null +++ b/src/windows/common/WSLCSDKCallbackAdapters.h @@ -0,0 +1,136 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. + +// +// Adapters that bridge the SDK-facing WSLCSDK callback interfaces (declared in +// WSLSDK.idl) to the internal wslc.idl callback interfaces. The service classes +// implement the IWSLCSDK* interfaces by converting the SDK callback objects into +// these adapters and forwarding to the existing wslc.idl based implementations. +// +// The adapters are only ever invoked in-process (they wrap the SDK's marshaled +// proxy), so they do not need to be registered for marshaling. +// + +#pragma once + +#include "wslc.h" +#include "WSLSDK.h" +#include + +namespace wsl::windows::common::wslcsdk { + +class TerminationCallbackAdapter + : public Microsoft::WRL::RuntimeClass, ITerminationCallback> +{ +public: + TerminationCallbackAdapter(IWSLCSDKTerminationCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnTermination)(WSLCVirtualMachineTerminationReason Reason, LPCWSTR Details) override + { + return m_inner->OnTermination(static_cast(Reason), Details); + } + +private: + Microsoft::WRL::ComPtr m_inner; +}; + +class CrashDumpCallbackAdapter + : public Microsoft::WRL::RuntimeClass, ICrashDumpCallback> +{ +public: + CrashDumpCallbackAdapter(IWSLCSDKCrashDumpCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnCrashDump)(LPCWSTR DumpPath, LPCSTR ProcessName, ULONGLONG Pid, ULONG Signal, ULONGLONG Timestamp) override + { + return m_inner->OnCrashDump(DumpPath, ProcessName, Pid, Signal, Timestamp); + } + +private: + Microsoft::WRL::ComPtr m_inner; +}; + +class ProgressCallbackAdapter + : public Microsoft::WRL::RuntimeClass, IProgressCallback> +{ +public: + ProgressCallbackAdapter(IWSLCSDKProgressCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnProgress)(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total) override + { + return m_inner->OnProgress(Status, Id, Current, Total); + } + +private: + Microsoft::WRL::ComPtr m_inner; +}; + +class WarningCallbackAdapter + : public Microsoft::WRL::RuntimeClass, IWarningCallback> +{ +public: + WarningCallbackAdapter(IWSLCSDKWarningCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnWarning)(LPCWSTR Message) override + { + return m_inner->OnWarning(Message); + } + +private: + Microsoft::WRL::ComPtr m_inner; +}; + +// Helpers that return a wslc.idl callback wrapping the given SDK callback, or +// nullptr when the SDK callback is null. + +inline Microsoft::WRL::ComPtr WrapTerminationCallback(IWSLCSDKTerminationCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +inline Microsoft::WRL::ComPtr WrapCrashDumpCallback(IWSLCSDKCrashDumpCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +inline Microsoft::WRL::ComPtr WrapProgressCallback(IWSLCSDKProgressCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +inline Microsoft::WRL::ComPtr WrapWarningCallback(IWSLCSDKWarningCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +} // namespace wsl::windows::common::wslcsdk diff --git a/src/windows/service/exe/WSLCSessionManager.cpp b/src/windows/service/exe/WSLCSessionManager.cpp index 339f3ce6ca..fbad8e843d 100644 --- a/src/windows/service/exe/WSLCSessionManager.cpp +++ b/src/windows/service/exe/WSLCSessionManager.cpp @@ -37,6 +37,7 @@ Module Name: #include "helpers.hpp" #include "wslutil.h" #include "filesystem.hpp" +#include "WSLCSDKCallbackAdapters.h" extern wsl::windows::service::PluginManager g_pluginManager; @@ -601,6 +602,68 @@ HRESULT WSLCSessionManager::OpenSessionByName(_In_ LPCWSTR DisplayName, _Out_ IW return CallImpl(&WSLCSessionManagerImpl::OpenSessionByName, DisplayName, Session); } +HRESULT WSLCSessionManager::GetVersion(_Out_ WSLCSDKVersion* Version) +{ + static_assert(sizeof(WSLCSDKVersion) == sizeof(WSLCVersion), "WSLCSDKVersion and WSLCVersion layout mismatch"); + + return GetVersion(reinterpret_cast(Version)); +} + +HRESULT WSLCSessionManager::IsClientVersionSupported(_In_ const WSLCSDKVersion* ClientVersion, _Out_ BOOL* IsSupported) +{ + static_assert(sizeof(WSLCSDKVersion) == sizeof(WSLCVersion), "WSLCSDKVersion and WSLCVersion layout mismatch"); + + return IsClientVersionSupported(reinterpret_cast(ClientVersion), IsSupported); +} + +HRESULT WSLCSessionManager::CreateSession( + const WSLCSDKSessionSettings* Settings, WSLCSDKSessionFlags Flags, IWSLCSDKWarningCallback* WarningCallback, IWSLCSDKSession** Session) +try +{ + RETURN_HR_IF_NULL(E_POINTER, Session); + *Session = nullptr; + + const auto warning = wsl::windows::common::wslcsdk::WrapWarningCallback(WarningCallback); + + Microsoft::WRL::ComPtr session; + if (Settings == nullptr) + { + RETURN_IF_FAILED(CreateSession(static_cast(nullptr), static_cast(Flags), warning.Get(), &session)); + } + else + { + static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); + + // The TerminationCallback pointer type differs between the two settings structs, so the + // struct can't be reinterpret_cast as a whole. Field-copy it and wrap the callback. The + // factory deep-copies (AddRefs) the termination callback synchronously during CreateSession, + // so the locally-held adapter outlives the call. + const auto termination = wsl::windows::common::wslcsdk::WrapTerminationCallback(Settings->TerminationCallback); + + WSLCSessionSettings settings{}; + settings.DisplayName = Settings->DisplayName; + settings.StoragePath = Settings->StoragePath; + settings.MaximumStorageSizeMb = Settings->MaximumStorageSizeMb; + settings.CpuCount = Settings->CpuCount; + settings.MemoryMb = Settings->MemoryMb; + settings.BootTimeoutMs = Settings->BootTimeoutMs; + settings.NetworkingMode = static_cast(Settings->NetworkingMode); + settings.TerminationCallback = termination.Get(); + settings.FeatureFlags = static_cast(Settings->FeatureFlags); + memcpy(&settings.DmesgOutput, &Settings->DmesgOutput, sizeof(settings.DmesgOutput)); + settings.StorageFlags = static_cast(Settings->StorageFlags); + settings.RootVhdOverride = Settings->RootVhdOverride; + settings.RootVhdTypeOverride = Settings->RootVhdTypeOverride; + + RETURN_IF_FAILED(CreateSession(&settings, static_cast(Flags), warning.Get(), &session)); + } + + RETURN_HR_IF_NULL(E_UNEXPECTED, session); + + return session.CopyTo(Session); +} +CATCH_RETURN(); + namespace wsl::windows::service::wslc { WSLCSessionManagerImpl* WSLCSessionManagerImpl::Instance() noexcept diff --git a/src/windows/service/exe/WSLCSessionManager.h b/src/windows/service/exe/WSLCSessionManager.h index d48f52e430..4749baae3e 100644 --- a/src/windows/service/exe/WSLCSessionManager.h +++ b/src/windows/service/exe/WSLCSessionManager.h @@ -32,6 +32,7 @@ Module Name: #pragma once #include "wslc.h" +#include "WSLSDK.h" #include "COMImplClass.h" #include "wslutil.h" #include @@ -187,7 +188,7 @@ class WSLCSessionManagerImpl } // namespace wsl::windows::service::wslc class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce8f") WSLCSessionManager - : public Microsoft::WRL::RuntimeClass, IWSLCSessionManager, IFastRundown>, + : public Microsoft::WRL::RuntimeClass, IWSLCSessionManager, IWSLCSDKSessionManager, IFastRundown>, public wsl::windows::service::wslc::COMImplClass { public: @@ -204,4 +205,10 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce8f") WSLCSessionManager IFACEMETHOD(ListSessions)(_Out_ WSLCSessionListEntry** Sessions, _Out_ ULONG* SessionsCount) override; IFACEMETHOD(OpenSession)(_In_ ULONG Id, _Out_ IWSLCSession** Session) override; IFACEMETHOD(OpenSessionByName)(_In_ LPCWSTR DisplayName, _Out_ IWSLCSession** Session) override; + + // IWSLCSDKSessionManager - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. + IFACEMETHOD(GetVersion)(_Out_ WSLCSDKVersion* Version) override; + IFACEMETHOD(IsClientVersionSupported)(_In_ const WSLCSDKVersion* ClientVersion, _Out_ BOOL* IsSupported) override; + IFACEMETHOD(CreateSession)( + const WSLCSDKSessionSettings* Settings, WSLCSDKSessionFlags Flags, IWSLCSDKWarningCallback* WarningCallback, IWSLCSDKSession** Session) override; }; diff --git a/src/windows/service/inc/CMakeLists.txt b/src/windows/service/inc/CMakeLists.txt index 59888c441f..efe717c550 100644 --- a/src/windows/service/inc/CMakeLists.txt +++ b/src/windows/service/inc/CMakeLists.txt @@ -1,3 +1,3 @@ -add_idl(wslserviceidl "wslservice.idl;wslc.idl" "windowsdefs.idl") +add_idl(wslserviceidl "wslservice.idl;wslc.idl;WSLSDK.idl" "windowsdefs.idl") set_target_properties(wslserviceidl PROPERTIES FOLDER windows) diff --git a/src/windows/service/inc/WSLSDK.idl b/src/windows/service/inc/WSLSDK.idl new file mode 100644 index 0000000000..77c08b9ec0 --- /dev/null +++ b/src/windows/service/inc/WSLSDK.idl @@ -0,0 +1,539 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + WSLSDK.idl + +Abstract: + + This file contains the WSLC SDK-facing COM object definitions. + Changes in this file must maintain backwards compatibility + +--*/ + +import "unknwn.idl"; +import "wtypes.idl"; + +cpp_quote("#ifdef __cplusplus") +cpp_quote("#ifndef WSLC_SESSIONMANAGER_COCLASS_DECLARED") +cpp_quote("#define WSLC_SESSIONMANAGER_COCLASS_DECLARED") +cpp_quote("class DECLSPEC_UUID(\"a9b7a1b9-0671-405c-95f1-e0612cb4ce8f\") WSLCSessionManager;") +cpp_quote("#endif") +cpp_quote("#endif") + +#define WSLCSDK_MAX_IMAGE_NAME_LENGTH 255 +#define WSLCSDK_MAX_VOLUME_NAME_LENGTH 255 +#define WSLCSDK_MAX_VOLUME_DRIVER_LENGTH 255 +#define WSLCSDK_CONTAINER_ID_LENGTH 64 +#define WSLCSDK_MAX_BINDING_ADDRESS_LENGTH 45 + +typedef +struct _WSLCSDKVersion { + ULONG Major; + ULONG Minor; + ULONG Revision; +} WSLCSDKVersion; + +typedef enum _WSLCSDKVirtualMachineTerminationReason +{ + WSLCSDKVirtualMachineTerminationReasonUnknown, + WSLCSDKVirtualMachineTerminationReasonShutdown, + WSLCSDKVirtualMachineTerminationReasonCrashed, +} WSLCSDKVirtualMachineTerminationReason; + +typedef enum _WSLCSDKFD +{ + WSLCSDKFDStdin = 0, + WSLCSDKFDStdout = 1, + WSLCSDKFDStderr = 2, + WSLCSDKFDTty = 3, +} WSLCSDKFD; + +typedef enum _WSLCSDKSignal +{ + WSLCSDKSignalNone = 0, + WSLCSDKSignalSIGHUP = 1, + WSLCSDKSignalSIGINT = 2, + WSLCSDKSignalSIGQUIT = 3, + WSLCSDKSignalSIGILL = 4, + WSLCSDKSignalSIGTRAP = 5, + WSLCSDKSignalSIGABRT = 6, + WSLCSDKSignalSIGIOT = 6, // SIGABRT and SIGIOT are equivalent. + WSLCSDKSignalSIGBUS = 7, + WSLCSDKSignalSIGFPE = 8, + WSLCSDKSignalSIGKILL = 9, + WSLCSDKSignalSIGUSR1 = 10, + WSLCSDKSignalSIGSEGV = 11, + WSLCSDKSignalSIGUSR2 = 12, + WSLCSDKSignalSIGPIPE = 13, + WSLCSDKSignalSIGALRM = 14, + WSLCSDKSignalSIGTERM = 15, + WSLCSDKSignalSIGTKFLT = 16, + WSLCSDKSignalSIGCHLD = 17, + WSLCSDKSignalSIGCONT = 18, + WSLCSDKSignalSIGSTOP = 19, + WSLCSDKSignalSIGTSTP = 20, + WSLCSDKSignalSIGTTIN = 21, + WSLCSDKSignalSIGTTOU = 22, + WSLCSDKSignalSIGURG = 23, + WSLCSDKSignalSIGXCPU = 24, + WSLCSDKSignalSIGXFSZ = 25, + WSLCSDKSignalSIGVTALRM = 26, + WSLCSDKSignalSIGPROF = 27, + WSLCSDKSignalSIGWINCH = 28, + WSLCSDKSignalSIGIO = 29, + WSLCSDKSignalSIGPOLL = 29, // SIGIO and SIGPOLL are equivalent. + WSLCSDKSignalSIGPWR = 30, + WSLCSDKSignalSIGSYS = 31 +} WSLCSDKSignal; + +[ + uuid(86A807EA-F2A1-4382-93E5-09FB5F2F4A31), + pointer_default(unique), + object +] +interface IWSLCSDKTerminationCallback : IUnknown +{ + HRESULT OnTermination(WSLCSDKVirtualMachineTerminationReason Reason, LPCWSTR Details); +}; + +[ + uuid(EAA15E20-7FCC-485B-B798-ED4095DBACA5), + pointer_default(unique), + object +] +interface IWSLCSDKCrashDumpCallback : IUnknown +{ + HRESULT OnCrashDump( + [in, string] LPCWSTR DumpPath, + [in, unique, string] LPCSTR ProcessName, + [in] ULONGLONG Pid, + [in] ULONG Signal, + [in] ULONGLONG Timestamp); +}; + +[ + uuid(06154F2A-ACA7-461E-94FC-92781BA1F6F6), + pointer_default(unique), + object +] +interface IWSLCSDKProgressCallback : IUnknown +{ + HRESULT OnProgress(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total); +}; + +[ + uuid(290C58A1-328C-4E90-B09B-0A9D32C40074), + pointer_default(unique), + object +] +interface IWSLCSDKWarningCallback : IUnknown +{ + HRESULT OnWarning([in, string] LPCWSTR Message); +}; + +typedef struct _WSLCSDKImageInformation +{ + char Image[WSLCSDK_MAX_IMAGE_NAME_LENGTH + 1]; + char Hash[256]; + char Digest[256]; + LONGLONG Size; // Matches Docker's int64 image size + LONGLONG Created; // Unix timestamp + char ParentId[256]; +} WSLCSDKImageInformation; + +typedef enum _WSLCSDKListImagesFlags +{ + WSLCSDKListImagesFlagsNone = 0, + WSLCSDKListImagesFlagsAll = 1, // Show all images (default hides intermediate images) + WSLCSDKListImagesFlagsDigests = 2, // Include digest information +} WSLCSDKListImagesFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKListImagesFlags);") + +typedef struct _WSLCSDKKeyValuePair +{ + [string] LPCSTR Key; + [string] LPCSTR Value; +} WSLCSDKKeyValuePair; + +typedef WSLCSDKKeyValuePair WSLCSDKLabel; +typedef WSLCSDKKeyValuePair WSLCSDKDriverOption; +typedef WSLCSDKKeyValuePair WSLCSDKFilter; + +typedef struct _WSLCSDKListImagesOptions +{ + DWORD Flags; // WSLCSDKListImagesFlags (can combine with bitwise OR) + [unique, size_is(FiltersCount)] const WSLCSDKFilter* Filters; + ULONG FiltersCount; +} WSLCSDKListImagesOptions; + +typedef enum _WSLCSDKProcessFlags +{ + WSLCSDKProcessFlagsNone = 0, + WSLCSDKProcessFlagsStdin = 1, + WSLCSDKProcessFlagsTty = 2 +} WSLCSDKProcessFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKProcessFlags);") + +typedef struct _WSLCSDKStringArray +{ + [unique, size_is(Count)] LPCSTR const* Values; + ULONG Count; +} WSLCSDKStringArray; + +typedef struct _WSLCSDKProcessOptions +{ + [unique] LPCSTR CurrentDirectory; + [unique] LPCSTR User; + WSLCSDKStringArray CommandLine; + WSLCSDKStringArray Environment; + WSLCSDKProcessFlags Flags; +} WSLCSDKProcessOptions; + +typedef struct _WSLCSDKNamedVolume +{ + LPCSTR Name; + LPCSTR ContainerPath; + BOOL ReadOnly; +} WSLCSDKNamedVolume; + +typedef struct _WSLCSDKVolume +{ + LPCWSTR HostPath; + LPCSTR ContainerPath; + BOOL ReadOnly; +} WSLCSDKVolume; + +typedef struct _WSLCSDKPortMapping +{ + USHORT HostPort; + USHORT ContainerPort; + int Family; + int Protocol; + char BindingAddress[WSLCSDK_MAX_BINDING_ADDRESS_LENGTH + 1]; +} WSLCSDKPortMapping; + +typedef struct _WSLCSDKTmpfsMount +{ + LPCSTR Destination; + [unique] LPCSTR Options; +} WSLCSDKTmpfsMount; + +typedef struct _WSLCSDKUlimit +{ + [string] LPCSTR Name; + LONGLONG Soft; + LONGLONG Hard; +} WSLCSDKUlimit; + +typedef struct _WSLCSDKNetworkConnection +{ + [string] LPCSTR NetworkName; + [unique, size_is(SettingsCount)] const WSLCSDKKeyValuePair* Settings; + ULONG SettingsCount; +} WSLCSDKNetworkConnection; + +typedef struct _WSLCSDKContainerNetwork +{ + [unique, string] LPCSTR NetworkMode; + + [unique, size_is(NetworksCount)] const WSLCSDKNetworkConnection* Networks; + ULONG NetworksCount; +} WSLCSDKContainerNetwork; + +typedef enum _WSLCSDKContainerFlags +{ + WSLCSDKContainerFlagsNone = 0, + WSLCSDKContainerFlagsRm = 1, // Delete the container when it exits. + WSLCSDKContainerFlagsGpu = 2, // Enable GPU access. + WSLCSDKContainerFlagsInit = 4, // Run the container under an init process. + WSLCSDKContainerFlagsPublishAll = 8, // Publish all exposed ports. +} WSLCSDKContainerFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKContainerFlags);") + +typedef enum _WSLCSDKContainerStartFlags +{ + WSLCSDKContainerStartFlagsNone = 0, + WSLCSDKContainerStartFlagsAttach = 1, // Attach stdio handles on start. +} WSLCSDKContainerStartFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKContainerStartFlags);") + +typedef struct _WSLCSDKContainerOptions +{ + LPCSTR Image; + [unique] LPCSTR Name; + WSLCSDKStringArray Entrypoint; + WSLCSDKProcessOptions InitProcessOptions; + [unique, size_is(VolumesCount)] WSLCSDKVolume* Volumes; + ULONG VolumesCount; + [unique, size_is(PortsCount)] WSLCSDKPortMapping* Ports; + ULONG PortsCount; + [unique, size_is(LabelsCount)] const WSLCSDKLabel* Labels; + ULONG LabelsCount; + WSLCSDKContainerFlags Flags; + WSLCSDKSignal StopSignal; + [unique] LPCSTR HostName; + [unique] LPCSTR DomainName; + + WSLCSDKStringArray DnsServers; + WSLCSDKStringArray DnsSearchDomains; + WSLCSDKStringArray DnsOptions; + + LONGLONG ShmSize; + WSLCSDKContainerNetwork ContainerNetwork; + [unique, size_is(TmpfsCount)] const WSLCSDKTmpfsMount* Tmpfs; + ULONG TmpfsCount; + + [unique, size_is(NamedVolumesCount)] WSLCSDKNamedVolume* NamedVolumes; + ULONG NamedVolumesCount; + + LONGLONG MemoryBytes; + LONGLONG NanoCpus; + [unique, size_is(UlimitsCount)] const WSLCSDKUlimit* Ulimits; + ULONG UlimitsCount; +} WSLCSDKContainerOptions; + +typedef enum _WSLCSDKContainerState +{ + WSLCSDKContainerStateInvalid = 0, + WSLCSDKContainerStateCreated = 1, + WSLCSDKContainerStateRunning = 2, + WSLCSDKContainerStateExited = 3, + WSLCSDKContainerStateDeleted = 4, +} WSLCSDKContainerState; + +typedef char WSLCSDKContainerId[WSLCSDK_CONTAINER_ID_LENGTH + 1]; + +typedef [system_handle(sh_file)] HANDLE WSLCSDKFileHandle; +typedef [system_handle(sh_pipe)] HANDLE WSLCSDKPipeHandle; +typedef [system_handle(sh_socket)] HANDLE WSLCSDKSocketHandle; + +typedef enum _WSLCSDKHandleType +{ + WSLCSDKHandleTypeUnknown = 0, + WSLCSDKHandleTypeFile = 1, + WSLCSDKHandleTypePipe = 2, + WSLCSDKHandleTypeSocket = 3 +} WSLCSDKHandleType; + +typedef struct _WSLCSDKHandle +{ + WSLCSDKHandleType Type; + + [switch_type(WSLCSDKHandleType), switch_is(Type)] + union + { + [case(WSLCSDKHandleTypeFile)] + WSLCSDKFileHandle File; + [case(WSLCSDKHandleTypePipe)] + WSLCSDKPipeHandle Pipe; + [case(WSLCSDKHandleTypeSocket)] + WSLCSDKSocketHandle Socket; + [default]; + } Handle; +} WSLCSDKHandle; + +typedef enum _WSLCSDKProcessState +{ + WSLCSDKProcessStateUnknown = 0, + WSLCSDKProcessStateRunning = 1, + WSLCSDKProcessStateExited = 2, + WSLCSDKProcessStateSignalled = 3 +} WSLCSDKProcessState; + +[ + uuid(AC69DD0D-6616-4C4F-91F2-C39D6034EA82), + pointer_default(unique), + object +] +interface IWSLCSDKProcess : IUnknown +{ + HRESULT Signal([in] int Signal); + HRESULT GetExitEvent([out, system_handle(sh_event)] HANDLE* EventHandle); + HRESULT GetStdHandle([in] WSLCSDKFD Fd, [out] WSLCSDKHandle* Handle); + HRESULT GetPid([out] int* Pid); + HRESULT GetState([out] WSLCSDKProcessState* State, [out] int* Code); +} + +typedef enum _WSLCSDKNetworkingMode +{ + WSLCSDKNetworkingModeNone, + WSLCSDKNetworkingModeNAT, + WSLCSDKNetworkingModeVirtioProxy +} WSLCSDKNetworkingMode; + +typedef enum _WSLCSDKFeatureFlags +{ + WSLCSDKFeatureFlagsNone = 0, + WSLCSDKFeatureFlagsDnsTunneling = 1, + WSLCSDKFeatureFlagsEarlyBootDmesg = 2, + WSLCSDKFeatureFlagsGPU = 4, + WSLCSDKFeatureFlagsVirtioFs = 8, + WSLCSDKFeatureFlagsDebug = 16, +} WSLCSDKFeatureFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKFeatureFlags);") + +typedef enum _WSLCSDKSessionStorageFlags +{ + WSLCSDKSessionStorageFlagsNone = 0, + WSLCSDKSessionStorageFlagsNoCreate = 1, // Open an existing storage path, but don't create a new one. +} WSLCSDKSessionStorageFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKSessionStorageFlags);") + +typedef struct _WSLCSDKSessionSettings { + LPCWSTR DisplayName; + LPCWSTR StoragePath; + ULONGLONG MaximumStorageSizeMb; + ULONG CpuCount; + ULONG MemoryMb; + ULONG BootTimeoutMs; + WSLCSDKNetworkingMode NetworkingMode; + [unique] IWSLCSDKTerminationCallback* TerminationCallback; + WSLCSDKFeatureFlags FeatureFlags; + WSLCSDKHandle DmesgOutput; + WSLCSDKSessionStorageFlags StorageFlags; + + // Below options are used for debugging purposes only. + [unique] LPCWSTR RootVhdOverride; + [unique] LPCSTR RootVhdTypeOverride; +} WSLCSDKSessionSettings; + +typedef enum _WSLCSDKDeleteFlags +{ + WSLCSDKDeleteFlagsNone = 0, + WSLCSDKDeleteFlagsForce = 1, + WSLCSDKDeleteFlagsDeleteVolumes = 2, +} WSLCSDKDeleteFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKDeleteFlags);") + +[ + uuid(8C3C91FA-D550-41B9-AD9D-23DCBF96F549), + pointer_default(unique), + object +] +interface IWSLCSDKContainer : IUnknown +{ + HRESULT Stop([in] WSLCSDKSignal Signal, [in] LONG TimeoutSeconds); + HRESULT Start([in] WSLCSDKContainerStartFlags Flags); + HRESULT Delete([in] WSLCSDKDeleteFlags Flags); + HRESULT GetState([out] WSLCSDKContainerState* State); + HRESULT GetInitProcess([out] IWSLCSDKProcess** Process); + HRESULT Exec([in, ref] const WSLCSDKProcessOptions* Options, [out] IWSLCSDKProcess** Process); + HRESULT Inspect([out] LPSTR* Output); + HRESULT GetId([out, string] WSLCSDKContainerId Id); +} + +typedef enum _WSLCSDKDeletedImageType +{ + WSLCSDKDeletedImageTypeDeleted = 0, + WSLCSDKDeletedImageTypeUntagged = 1 +} WSLCSDKDeletedImageType; + +typedef struct _WSLCSDKDeletedImageInformation +{ + char Image[WSLCSDK_MAX_IMAGE_NAME_LENGTH + 1]; + WSLCSDKDeletedImageType Type; +} WSLCSDKDeletedImageInformation; + +typedef enum _WSLCSDKDeleteImageFlags +{ + WSLCSDKDeleteImageFlagsNone = 0, + WSLCSDKDeleteImageFlagsForce = 1, + WSLCSDKDeleteImageFlagsNoPrune = 2, +} WSLCSDKDeleteImageFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKDeleteImageFlags);") + +typedef struct _WSLCSDKDeleteImageOptions +{ + LPCSTR Image; // Image can be ID or Repo:Tag. + DWORD Flags; // WSLCSDKDeleteImageFlags +} WSLCSDKDeleteImageOptions; + +typedef struct _WSLCSDKTagImageOptions +{ + LPCSTR Image; // Source image name or ID. + LPCSTR Repo; // Target repository name. + LPCSTR Tag; // Target tag name. +} WSLCSDKTagImageOptions; + +typedef struct _WSLCSDKVolumeOptions +{ + [unique] LPCSTR Name; + [unique] LPCSTR Driver; + [unique, size_is(DriverOptsCount)] const WSLCSDKDriverOption* DriverOpts; + ULONG DriverOptsCount; + [unique, size_is(LabelsCount)] const WSLCSDKLabel* Labels; + ULONG LabelsCount; +} WSLCSDKVolumeOptions; + +typedef char WSLCSDKVolumeName[WSLCSDK_MAX_VOLUME_NAME_LENGTH + 1]; + +typedef struct _WSLCSDKVolumeInformation +{ + WSLCSDKVolumeName Name; + char Driver[WSLCSDK_MAX_VOLUME_DRIVER_LENGTH + 1]; +} WSLCSDKVolumeInformation; + +[ + uuid(DD7B2EF9-AA01-4F21-8A3A-29D394CBB579), + pointer_default(unique), + object +] +interface IWSLCSDKSession : IUnknown +{ + // Image management. + HRESULT PullImage([in] LPCSTR Image, [in, unique] LPCSTR RegistryAuthenticationInformation, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in, unique] IWSLCSDKWarningCallback* WarningCallback); + HRESULT LoadImage([in] WSLCSDKHandle ImageHandle, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength, [in, unique] IWSLCSDKWarningCallback* WarningCallback); + HRESULT ImportImage([in] WSLCSDKHandle ImageHandle, [in] LPCSTR ImageName, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength, [in, unique] IWSLCSDKWarningCallback* WarningCallback); + HRESULT ListImages([in, unique] const WSLCSDKListImagesOptions* Options, [out, size_is(, *Count)] WSLCSDKImageInformation** Images, [out] ULONG* Count); + HRESULT DeleteImage([in] const WSLCSDKDeleteImageOptions* Options, [out, size_is(, *Count)] WSLCSDKDeletedImageInformation** DeletedImages, [out] ULONG* Count); + HRESULT TagImage([in] const WSLCSDKTagImageOptions* Options); + + // Container management. + HRESULT CreateContainer([in] const WSLCSDKContainerOptions* Options, [in, unique] IWSLCSDKWarningCallback* WarningCallback, [out] IWSLCSDKContainer** Container); + + // Terminate the VM and containers. + HRESULT Terminate(); + + // Volume management. + HRESULT CreateVolume([in] const WSLCSDKVolumeOptions* Options, [out] WSLCSDKVolumeInformation* VolumeInfo); + HRESULT DeleteVolume([in] LPCSTR Name); + + HRESULT Authenticate([in] LPCSTR ServerAddress, [in] LPCSTR Username, [in] LPCSTR Password, [out] LPSTR* IdentityToken); + HRESULT PushImage([in] LPCSTR Image, [in] LPCSTR RegistryAuthenticationInformation, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in, unique] IWSLCSDKWarningCallback* WarningCallback); + + HRESULT RegisterCrashDumpCallback([in] IWSLCSDKCrashDumpCallback* Callback, [out] IUnknown** Subscription); +} + +typedef enum _WSLCSDKSessionFlags +{ + WSLCSDKSessionFlagsNone = 0, + WSLCSDKSessionFlagsPersistent = 1, // Session remains active after its COM reference is released. + WSLCSDKSessionFlagsOpenExisting = 2, // Open an existing session if the name is in use. +} WSLCSDKSessionFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKSessionFlags);") + +[ + uuid(279F2047-DA35-45A3-B671-AFD2302D5D16), + pointer_default(unique), + object +] +interface IWSLCSDKSessionManager : IUnknown +{ + HRESULT GetVersion([out] WSLCSDKVersion* Version); + HRESULT IsClientVersionSupported([in] const WSLCSDKVersion* ClientVersion, [out] BOOL* IsSupported); + + // Session management. + HRESULT CreateSession([in, unique] const WSLCSDKSessionSettings* Settings, WSLCSDKSessionFlags Flags, [in, unique] IWSLCSDKWarningCallback* WarningCallback, [out] IWSLCSDKSession** Session); +} diff --git a/src/windows/service/inc/wslc.idl b/src/windows/service/inc/wslc.idl index 04ff531cc1..d2283d0780 100644 --- a/src/windows/service/inc/wslc.idl +++ b/src/windows/service/inc/wslc.idl @@ -9,6 +9,8 @@ Module Name: Abstract: This file contains the WSLC-related COM object definitions. + // N.B. ABI breaking changes in this file are OK, since both client & server always ship together. + // The WSLC SDK must not use this file, and instead use WSLSDK.idl --*/ @@ -16,7 +18,10 @@ import "unknwn.idl"; import "wtypes.idl"; cpp_quote("#ifdef __cplusplus") +cpp_quote("#ifndef WSLC_SESSIONMANAGER_COCLASS_DECLARED") +cpp_quote("#define WSLC_SESSIONMANAGER_COCLASS_DECLARED") cpp_quote("class DECLSPEC_UUID(\"a9b7a1b9-0671-405c-95f1-e0612cb4ce8f\") WSLCSessionManager;") +cpp_quote("#endif") cpp_quote("class DECLSPEC_UUID(\"9FCD2067-9FC6-4EFA-9EB0-698169EBF7D3\") WSLCSessionFactory;") cpp_quote("#endif") diff --git a/src/windows/service/stub/CMakeLists.txt b/src/windows/service/stub/CMakeLists.txt index c0308d6dcd..a40c3746bd 100644 --- a/src/windows/service/stub/CMakeLists.txt +++ b/src/windows/service/stub/CMakeLists.txt @@ -3,6 +3,8 @@ set(SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslservice_p_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslc_i_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslc_p_${TARGET_PLATFORM}.c + ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WSLSDK_i_${TARGET_PLATFORM}.c + ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WSLSDK_p_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/dlldata_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_LIST_DIR}/WslServiceProxyStub.def ${CMAKE_CURRENT_LIST_DIR}/WslServiceProxyStub.rc) diff --git a/src/windows/wslcsession/WSLCContainer.cpp b/src/windows/wslcsession/WSLCContainer.cpp index 03baa3e3ab..aa3bdd0540 100644 --- a/src/windows/wslcsession/WSLCContainer.cpp +++ b/src/windows/wslcsession/WSLCContainer.cpp @@ -2459,3 +2459,57 @@ HRESULT WSLCContainer::InterfaceSupportsErrorInfo(REFIID riid) { return riid == __uuidof(IWSLCContainer) ? S_OK : S_FALSE; } + +HRESULT WSLCContainer::Stop(WSLCSDKSignal Signal, LONG TimeoutSeconds) +{ + static_assert(sizeof(WSLCSDKSignal) == sizeof(WSLCSignal), "WSLCSDKSignal and WSLCSignal size mismatch"); + + return Stop(static_cast(Signal), TimeoutSeconds); +} + +HRESULT WSLCContainer::Start(WSLCSDKContainerStartFlags Flags) +{ + return Start(static_cast(Flags), nullptr, nullptr); +} + +HRESULT WSLCContainer::Delete(WSLCSDKDeleteFlags Flags) +{ + return Delete(static_cast(Flags)); +} + +HRESULT WSLCContainer::GetState(WSLCSDKContainerState* State) +{ + static_assert(sizeof(WSLCSDKContainerState) == sizeof(WSLCContainerState), "WSLCSDKContainerState and WSLCContainerState size mismatch"); + + return GetState(reinterpret_cast(State)); +} + +HRESULT WSLCContainer::GetInitProcess(IWSLCSDKProcess** Process) +try +{ + RETURN_HR_IF_NULL(E_POINTER, Process); + *Process = nullptr; + + Microsoft::WRL::ComPtr process; + RETURN_IF_FAILED(GetInitProcess(&process)); + RETURN_HR_IF_NULL(E_UNEXPECTED, process); + + return process.CopyTo(Process); +} +CATCH_RETURN(); + +HRESULT WSLCContainer::Exec(const WSLCSDKProcessOptions* Options, IWSLCSDKProcess** Process) +try +{ + static_assert(sizeof(WSLCSDKProcessOptions) == sizeof(WSLCProcessOptions), "WSLCSDKProcessOptions and WSLCProcessOptions size mismatch"); + + RETURN_HR_IF_NULL(E_POINTER, Process); + *Process = nullptr; + + Microsoft::WRL::ComPtr process; + RETURN_IF_FAILED(Exec(reinterpret_cast(Options), nullptr, &process)); + RETURN_HR_IF_NULL(E_UNEXPECTED, process); + + return process.CopyTo(Process); +} +CATCH_RETURN(); diff --git a/src/windows/wslcsession/WSLCContainer.h b/src/windows/wslcsession/WSLCContainer.h index c3ad79288c..2ee98a1e48 100644 --- a/src/windows/wslcsession/WSLCContainer.h +++ b/src/windows/wslcsession/WSLCContainer.h @@ -22,6 +22,7 @@ Module Name: #include "IORelay.h" #include "COMImplClass.h" #include "wslc_schema.h" +#include "WSLSDK.h" #include "WSLCContainerMetadata.h" #include "WSLCNetworkMetadata.h" #include "WSLCVhdVolume.h" @@ -217,7 +218,7 @@ class WSLCContainerImpl }; class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLCContainer - : public Microsoft::WRL::RuntimeClass, IWSLCContainer, IFastRundown, ISupportErrorInfo>, + : public Microsoft::WRL::RuntimeClass, IWSLCContainer, IWSLCSDKContainer, IFastRundown, ISupportErrorInfo>, public COMImplClass { @@ -242,6 +243,14 @@ class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLCContainer IFACEMETHOD(ConnectToNetwork)(_In_ const WSLCNetworkConnectionOptions* Options) override; IFACEMETHOD(DisconnectFromNetwork)(_In_ LPCSTR NetworkName) override; + // IWSLCSDKContainer - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. + IFACEMETHOD(Stop)(_In_ WSLCSDKSignal Signal, _In_ LONG TimeoutSeconds) override; + IFACEMETHOD(Start)(_In_ WSLCSDKContainerStartFlags Flags) override; + IFACEMETHOD(Delete)(_In_ WSLCSDKDeleteFlags Flags) override; + IFACEMETHOD(GetState)(_Out_ WSLCSDKContainerState* State) override; + IFACEMETHOD(GetInitProcess)(_Out_ IWSLCSDKProcess** Process) override; + IFACEMETHOD(Exec)(_In_ const WSLCSDKProcessOptions* Options, _Out_ IWSLCSDKProcess** Process) override; + IFACEMETHOD(InterfaceSupportsErrorInfo)(REFIID riid); // Cache read-only properties so they remain accessible after the impl is disconnected. diff --git a/src/windows/wslcsession/WSLCProcess.cpp b/src/windows/wslcsession/WSLCProcess.cpp index 04decf9ec6..ec6e86c0d2 100644 --- a/src/windows/wslcsession/WSLCProcess.cpp +++ b/src/windows/wslcsession/WSLCProcess.cpp @@ -122,4 +122,18 @@ try m_control->ResizeTty(Rows, Columns); return S_OK; } -CATCH_RETURN(); \ No newline at end of file +CATCH_RETURN(); + +HRESULT WSLCProcess::GetStdHandle(WSLCSDKFD Fd, WSLCSDKHandle* Handle) +{ + static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); + + return GetStdHandle(static_cast(Fd), reinterpret_cast(Handle)); +} + +HRESULT WSLCProcess::GetState(WSLCSDKProcessState* State, int* Code) +{ + static_assert(sizeof(WSLCSDKProcessState) == sizeof(WSLCProcessState), "WSLCSDKProcessState and WSLCProcessState size mismatch"); + + return GetState(reinterpret_cast(State), Code); +} \ No newline at end of file diff --git a/src/windows/wslcsession/WSLCProcess.h b/src/windows/wslcsession/WSLCProcess.h index cce5543d91..2cc6227b1a 100644 --- a/src/windows/wslcsession/WSLCProcess.h +++ b/src/windows/wslcsession/WSLCProcess.h @@ -14,6 +14,7 @@ Module Name: #pragma once #include "wslc.h" +#include "WSLSDK.h" #include "WSLCProcessControl.h" #include "WSLCProcessIO.h" @@ -22,7 +23,7 @@ namespace wsl::windows::service::wslc { class WSLCVirtualMachine; class DECLSPEC_UUID("AFBEA6D6-D8A4-4F81-8FED-F947EB74B33B") WSLCProcess - : public Microsoft::WRL::RuntimeClass, IWSLCProcess, IFastRundown> + : public Microsoft::WRL::RuntimeClass, IWSLCProcess, IWSLCSDKProcess, IFastRundown> { public: WSLCProcess(std::shared_ptr Control, std::unique_ptr&& Io, WSLCProcessFlags Flags); @@ -37,6 +38,10 @@ class DECLSPEC_UUID("AFBEA6D6-D8A4-4F81-8FED-F947EB74B33B") WSLCProcess IFACEMETHOD(GetState)(_Out_ WSLCProcessState* State, _Out_ int* Code) override; IFACEMETHOD(ResizeTty)(_In_ ULONG Rows, _In_ ULONG Columns) override; + // IWSLCSDKProcess - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. + IFACEMETHOD(GetStdHandle)(_In_ WSLCSDKFD Fd, _Out_ WSLCSDKHandle* Handle) override; + IFACEMETHOD(GetState)(_Out_ WSLCSDKProcessState* State, _Out_ int* Code) override; + wil::unique_handle GetStdHandle(int Index); HANDLE GetExitEvent(); int GetPid() const; diff --git a/src/windows/wslcsession/WSLCSession.cpp b/src/windows/wslcsession/WSLCSession.cpp index 2be375fe99..4e9863ceab 100644 --- a/src/windows/wslcsession/WSLCSession.cpp +++ b/src/windows/wslcsession/WSLCSession.cpp @@ -21,6 +21,7 @@ Module Name: #include "ServiceProcessLauncher.h" #include "WslCoreFilesystem.h" #include "wslpolicies.h" +#include "WSLCSDKCallbackAdapters.h" using namespace wsl::windows::common; using io::MultiHandleWait; @@ -2833,6 +2834,104 @@ HRESULT WSLCSession::InterfaceSupportsErrorInfo(REFIID riid) return riid == __uuidof(IWSLCSession) ? S_OK : S_FALSE; } +HRESULT WSLCSession::PullImage(LPCSTR Image, LPCSTR RegistryAuthenticationInformation, IWSLCSDKProgressCallback* ProgressCallback, IWSLCSDKWarningCallback* WarningCallback) +{ + const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); + const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + + return PullImage(Image, RegistryAuthenticationInformation, progress.Get(), warning.Get()); +} + +HRESULT WSLCSession::LoadImage(WSLCSDKHandle ImageHandle, IWSLCSDKProgressCallback* ProgressCallback, ULONGLONG ContentLength, IWSLCSDKWarningCallback* WarningCallback) +{ + static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); + + WSLCHandle handle{}; + memcpy(&handle, &ImageHandle, sizeof(handle)); + + const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); + const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + + return LoadImage(handle, progress.Get(), ContentLength, warning.Get()); +} + +HRESULT WSLCSession::ImportImage(WSLCSDKHandle ImageHandle, LPCSTR ImageName, IWSLCSDKProgressCallback* ProgressCallback, ULONGLONG ContentLength, IWSLCSDKWarningCallback* WarningCallback) +{ + static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); + + WSLCHandle handle{}; + memcpy(&handle, &ImageHandle, sizeof(handle)); + + const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); + const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + + return ImportImage(handle, ImageName, progress.Get(), ContentLength, warning.Get()); +} + +HRESULT WSLCSession::ListImages(const WSLCSDKListImagesOptions* Options, WSLCSDKImageInformation** Images, ULONG* Count) +{ + static_assert(sizeof(WSLCSDKListImagesOptions) == sizeof(WSLCListImagesOptions), "WSLCSDKListImagesOptions and WSLCListImagesOptions layout mismatch"); + static_assert(sizeof(WSLCSDKImageInformation) == sizeof(WSLCImageInformation), "WSLCSDKImageInformation and WSLCImageInformation layout mismatch"); + + return ListImages(reinterpret_cast(Options), reinterpret_cast(Images), Count); +} + +HRESULT WSLCSession::DeleteImage(const WSLCSDKDeleteImageOptions* Options, WSLCSDKDeletedImageInformation** DeletedImages, ULONG* Count) +{ + static_assert(sizeof(WSLCSDKDeleteImageOptions) == sizeof(WSLCDeleteImageOptions), "WSLCSDKDeleteImageOptions and WSLCDeleteImageOptions layout mismatch"); + static_assert(sizeof(WSLCSDKDeletedImageInformation) == sizeof(WSLCDeletedImageInformation), "WSLCSDKDeletedImageInformation and WSLCDeletedImageInformation layout mismatch"); + + return DeleteImage(reinterpret_cast(Options), reinterpret_cast(DeletedImages), Count); +} + +HRESULT WSLCSession::TagImage(const WSLCSDKTagImageOptions* Options) +{ + static_assert(sizeof(WSLCSDKTagImageOptions) == sizeof(WSLCTagImageOptions), "WSLCSDKTagImageOptions and WSLCTagImageOptions layout mismatch"); + + return TagImage(reinterpret_cast(Options)); +} + +HRESULT WSLCSession::PushImage(LPCSTR Image, LPCSTR RegistryAuthenticationInformation, IWSLCSDKProgressCallback* ProgressCallback, IWSLCSDKWarningCallback* WarningCallback) +{ + const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); + const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + + return PushImage(Image, RegistryAuthenticationInformation, progress.Get(), warning.Get()); +} + +HRESULT WSLCSession::CreateContainer(const WSLCSDKContainerOptions* Options, IWSLCSDKWarningCallback* WarningCallback, IWSLCSDKContainer** Container) +try +{ + static_assert(sizeof(WSLCSDKContainerOptions) == sizeof(WSLCContainerOptions), "WSLCSDKContainerOptions and WSLCContainerOptions layout mismatch"); + + RETURN_HR_IF_NULL(E_POINTER, Container); + *Container = nullptr; + + const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + + Microsoft::WRL::ComPtr container; + RETURN_IF_FAILED(CreateContainer(reinterpret_cast(Options), warning.Get(), &container)); + RETURN_HR_IF_NULL(E_UNEXPECTED, container); + + return container.CopyTo(Container); +} +CATCH_RETURN(); + +HRESULT WSLCSession::CreateVolume(const WSLCSDKVolumeOptions* Options, WSLCSDKVolumeInformation* VolumeInfo) +{ + static_assert(sizeof(WSLCSDKVolumeOptions) == sizeof(WSLCVolumeOptions), "WSLCSDKVolumeOptions and WSLCVolumeOptions layout mismatch"); + static_assert(sizeof(WSLCSDKVolumeInformation) == sizeof(WSLCVolumeInformation), "WSLCSDKVolumeInformation and WSLCVolumeInformation layout mismatch"); + + return CreateVolume(reinterpret_cast(Options), reinterpret_cast(VolumeInfo)); +} + +HRESULT WSLCSession::RegisterCrashDumpCallback(IWSLCSDKCrashDumpCallback* Callback, IUnknown** Subscription) +{ + const auto callback = wslcsdk::WrapCrashDumpCallback(Callback); + + return RegisterCrashDumpCallback(callback.Get(), Subscription); +} + MultiHandleWait WSLCSession::CreateIOContext(HANDLE CancelHandle) { io::MultiHandleWait io; diff --git a/src/windows/wslcsession/WSLCSession.h b/src/windows/wslcsession/WSLCSession.h index 5c7bee2227..b0ed7914b6 100644 --- a/src/windows/wslcsession/WSLCSession.h +++ b/src/windows/wslcsession/WSLCSession.h @@ -15,6 +15,7 @@ Module Name: #pragma once #include "wslc.h" +#include "WSLSDK.h" #include "WSLCVirtualMachine.h" #include "WSLCContainer.h" #include "WSLCVolumes.h" @@ -73,7 +74,7 @@ class UserCOMCallback // The SYSTEM service creates the VM and passes IWSLCVirtualMachine to Initialize(). // class DECLSPEC_UUID("4877FEFC-4977-4929-A958-9F36AA1892A4") WSLCSession - : public Microsoft::WRL::RuntimeClass, IWSLCSession, IFastRundown, ISupportErrorInfo> + : public Microsoft::WRL::RuntimeClass, IWSLCSession, IWSLCSDKSession, IFastRundown, ISupportErrorInfo> { public: WSLCSession() = default; @@ -193,6 +194,33 @@ class DECLSPEC_UUID("4877FEFC-4977-4929-A958-9F36AA1892A4") WSLCSession IFACEMETHOD(MapVmPort)(_In_ int Family, _In_ unsigned short WindowsPort, _In_ unsigned short LinuxPort) override; IFACEMETHOD(UnmapVmPort)(_In_ int Family, _In_ unsigned short WindowsPort, _In_ unsigned short LinuxPort) override; + // IWSLCSDKSession - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. + // Methods that have an identical signature in both interfaces (Terminate, DeleteVolume, Authenticate) are + // served by the single existing override and require no additional code here. + IFACEMETHOD(PullImage)( + _In_ LPCSTR Image, + _In_opt_ LPCSTR RegistryAuthenticationInformation, + _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, + _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; + IFACEMETHOD(LoadImage)(_In_ WSLCSDKHandle ImageHandle, _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, _In_ ULONGLONG ContentLength, _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; + IFACEMETHOD(ImportImage)( + _In_ WSLCSDKHandle ImageHandle, + _In_ LPCSTR ImageName, + _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, + _In_ ULONGLONG ContentLength, + _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; + IFACEMETHOD(ListImages)(_In_opt_ const WSLCSDKListImagesOptions* Options, _Out_ WSLCSDKImageInformation** Images, _Out_ ULONG* Count) override; + IFACEMETHOD(DeleteImage)(_In_ const WSLCSDKDeleteImageOptions* Options, _Out_ WSLCSDKDeletedImageInformation** DeletedImages, _Out_ ULONG* Count) override; + IFACEMETHOD(TagImage)(_In_ const WSLCSDKTagImageOptions* Options) override; + IFACEMETHOD(PushImage)( + _In_ LPCSTR Image, + _In_ LPCSTR RegistryAuthenticationInformation, + _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, + _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; + IFACEMETHOD(CreateContainer)(_In_ const WSLCSDKContainerOptions* Options, _In_opt_ IWSLCSDKWarningCallback* WarningCallback, _Out_ IWSLCSDKContainer** Container) override; + IFACEMETHOD(CreateVolume)(_In_ const WSLCSDKVolumeOptions* Options, _Out_ WSLCSDKVolumeInformation* VolumeInfo) override; + IFACEMETHOD(RegisterCrashDumpCallback)(_In_ IWSLCSDKCrashDumpCallback* Callback, _Out_ IUnknown** Subscription) override; + common::io::MultiHandleWait CreateIOContext(HANDLE CancelHandle = nullptr); UserHandle OpenUserHandle(WSLCHandle Handle); diff --git a/test/windows/WslcSdkTests.cpp b/test/windows/WslcSdkTests.cpp index 2588a13fe2..8a569db196 100644 --- a/test/windows/WslcSdkTests.cpp +++ b/test/windows/WslcSdkTests.cpp @@ -362,10 +362,10 @@ class WslcSdkTests UniqueCrashDumpSubscription subscription; VERIFY_SUCCEEDED(WslcRegisterSessionCrashDumpCallback(session.get(), callback, &promise, &subscription, nullptr)); - auto& comSession = *reinterpret_cast(session.get())->session; + auto comSession = reinterpret_cast(session.get())->session.query(); wsl::windows::common::WSLCProcessLauncher launcher{"/bin/sh", {"/bin/sh", "-c", "kill -SEGV $$"}}; - auto process = launcher.Launch(comSession); + auto process = launcher.Launch(*comSession); auto result = process.WaitAndCaptureOutput(); VERIFY_ARE_EQUAL(result.Code, 128 + WSLCSignalSIGSEGV); @@ -2239,8 +2239,8 @@ class WslcSdkTests launcher.AddPort(port, port, AF_INET); // Get the IWSLCSession COM object from the SDK session handle. - auto& session = *reinterpret_cast(m_defaultSession)->session; - auto container = launcher.Launch(session, WSLCContainerStartFlagsNone); + auto session = reinterpret_cast(m_defaultSession)->session.query(); + auto container = launcher.Launch(*session, WSLCContainerStartFlagsNone); auto registryAddress = std::format("127.0.0.1:{}", port); diff --git a/test/windows/WslcSdkWinRTTests.cpp b/test/windows/WslcSdkWinRTTests.cpp index 5336618df4..fbcfedeaae 100644 --- a/test/windows/WslcSdkWinRTTests.cpp +++ b/test/windows/WslcSdkWinRTTests.cpp @@ -185,8 +185,8 @@ class WslcSdkWinRtTests launcher.AddPort(port, port, AF_INET); // Get the IWSLCSession COM object from the SDK session handle. - auto& comSession = *reinterpret_cast(WSLCSDK::implementation::GetHandle(m_defaultSession))->session; - auto container = launcher.Launch(comSession, WSLCContainerStartFlagsNone); + auto comSession = reinterpret_cast(WSLCSDK::implementation::GetHandle(m_defaultSession))->session.query(); + auto container = launcher.Launch(*comSession, WSLCContainerStartFlagsNone); auto registryAddress = std::format("127.0.0.1:{}", port); From 19d7e1caabe51e94b2f6421cdfb3387466764b06 Mon Sep 17 00:00:00 2001 From: Blue Date: Thu, 11 Jun 2026 15:01:25 -0700 Subject: [PATCH 2/6] Save state --- src/windows/WslcSDK/CrashDumpCallback.cpp | 2 +- src/windows/WslcSDK/CrashDumpCallback.h | 10 +- src/windows/WslcSDK/IOCallback.cpp | 12 +- src/windows/WslcSDK/IOCallback.h | 8 +- src/windows/WslcSDK/ProgressCallback.cpp | 2 +- src/windows/WslcSDK/ProgressCallback.h | 8 +- src/windows/WslcSDK/TerminationCallback.cpp | 10 +- src/windows/WslcSDK/TerminationCallback.h | 10 +- src/windows/WslcSDK/WslcsdkPrivate.h | 12 +- src/windows/WslcSDK/wslcsdk.cpp | 148 ++-- src/windows/common/APICompat.cpp | 728 ++++++++++++++++++ src/windows/common/APICompat.h | 198 +++++ src/windows/common/CMakeLists.txt | 2 + src/windows/common/WSLCSDKCallbackAdapters.h | 136 ---- .../service/exe/WSLCSessionManager.cpp | 63 +- src/windows/service/exe/WSLCSessionManager.h | 15 +- src/windows/service/inc/CMakeLists.txt | 2 +- src/windows/service/inc/WSLCCompat.idl | 539 +++++++++++++ src/windows/service/inc/WSLSDK.idl | 539 ------------- src/windows/service/inc/wslc.idl | 2 +- src/windows/service/stub/CMakeLists.txt | 4 +- src/windows/wslcsession/WSLCContainer.cpp | 64 +- src/windows/wslcsession/WSLCContainer.h | 18 +- src/windows/wslcsession/WSLCProcess.cpp | 28 +- src/windows/wslcsession/WSLCProcess.h | 10 +- src/windows/wslcsession/WSLCSession.cpp | 195 +++-- src/windows/wslcsession/WSLCSession.h | 41 +- 27 files changed, 1851 insertions(+), 955 deletions(-) create mode 100644 src/windows/common/APICompat.cpp create mode 100644 src/windows/common/APICompat.h delete mode 100644 src/windows/common/WSLCSDKCallbackAdapters.h create mode 100644 src/windows/service/inc/WSLCCompat.idl delete mode 100644 src/windows/service/inc/WSLSDK.idl diff --git a/src/windows/WslcSDK/CrashDumpCallback.cpp b/src/windows/WslcSDK/CrashDumpCallback.cpp index a157ab6b07..42d92b51b3 100644 --- a/src/windows/WslcSDK/CrashDumpCallback.cpp +++ b/src/windows/WslcSDK/CrashDumpCallback.cpp @@ -8,7 +8,7 @@ Module Name: Abstract: - Implementation of a type that implements IWSLCSDKCrashDumpCallback. + Implementation of a type that implements IWSLCCompatCrashDumpCallback. --*/ #include "precomp.h" diff --git a/src/windows/WslcSDK/CrashDumpCallback.h b/src/windows/WslcSDK/CrashDumpCallback.h index 25949df4bb..ede7bcd5a0 100644 --- a/src/windows/WslcSDK/CrashDumpCallback.h +++ b/src/windows/WslcSDK/CrashDumpCallback.h @@ -8,21 +8,21 @@ Module Name: Abstract: - Header for a type that implements IWSLCSDKCrashDumpCallback. Bridges the COM - IWSLCSDKCrashDumpCallback interface back to the C-style SDK callback registered + Header for a type that implements IWSLCCompatCrashDumpCallback. Bridges the COM + IWSLCCompatCrashDumpCallback interface back to the C-style SDK callback registered via WslcRegisterSessionCrashDumpCallback. --*/ #pragma once -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "wslcsdkprivate.h" #include -struct CrashDumpCallback : public winrt::implements +struct CrashDumpCallback : public winrt::implements { CrashDumpCallback(WslcSessionCrashDumpCallback callback, PVOID context); - // IWSLCSDKCrashDumpCallback + // IWSLCCompatCrashDumpCallback HRESULT STDMETHODCALLTYPE OnCrashDump(_In_ LPCWSTR DumpPath, _In_opt_ LPCSTR ProcessName, _In_ ULONGLONG Pid, _In_ ULONG Signal, _In_ ULONGLONG Timestamp) override; private: diff --git a/src/windows/WslcSDK/IOCallback.cpp b/src/windows/WslcSDK/IOCallback.cpp index c2283d100e..36695773a2 100644 --- a/src/windows/WslcSDK/IOCallback.cpp +++ b/src/windows/WslcSDK/IOCallback.cpp @@ -14,7 +14,7 @@ Module Name: #include "precomp.h" #include "WslcsdkPrivate.h" -IOCallback::IOCallback(IWSLCSDKProcess* process, const WslcContainerProcessIOCallbackOptions& options) : +IOCallback::IOCallback(IWSLCCompatProcess* process, const WslcContainerProcessIOCallbackOptions& options) : m_process(process), m_callbackOptions(std::make_unique(options)) { using namespace wsl::windows::common::io; @@ -55,7 +55,7 @@ IOCallback::IOCallback(IWSLCSDKProcess* process, const WslcContainerProcessIOCal if (runResult && m_process && m_callbackOptions && m_callbackOptions->onExit) { - WSLCSDKProcessState state{}; + WSLCCompatProcessState state{}; int exitCode = -1; // Prefer to make the callback even if we don't properly retrieve the exit code. @@ -66,7 +66,7 @@ IOCallback::IOCallback(IWSLCSDKProcess* process, const WslcContainerProcessIOCal } else { - WI_ASSERT(state == WSLCSDKProcessStateExited); + WI_ASSERT(state == WSLCCompatProcessStateExited); } // Regardless of our ability to get the proper exit code, inform the caller that the process @@ -119,11 +119,11 @@ bool IOCallback::HasIOCallback(const WslcContainerProcessIOCallbackOptions& opti return options.onStdOut || options.onStdErr || options.onExit; } -wil::unique_handle IOCallback::GetIOHandle(IWSLCSDKProcess* process, WslcProcessIOHandle ioHandle) +wil::unique_handle IOCallback::GetIOHandle(IWSLCCompatProcess* process, WslcProcessIOHandle ioHandle) { - WSLCSDKHandle handle{}; + WSLCCompatHandle handle{}; - THROW_IF_FAILED(process->GetStdHandle(static_cast(static_cast>(ioHandle)), &handle)); + THROW_IF_FAILED(process->GetStdHandle(static_cast(static_cast>(ioHandle)), &handle)); // The handle value is the same regardless of the union member that was populated. return wil::unique_handle{handle.Handle.File}; diff --git a/src/windows/WslcSDK/IOCallback.h b/src/windows/WslcSDK/IOCallback.h index b311f0186c..0e3a9cc0db 100644 --- a/src/windows/WslcSDK/IOCallback.h +++ b/src/windows/WslcSDK/IOCallback.h @@ -12,7 +12,7 @@ Module Name: --*/ #pragma once -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "relay.hpp" #include @@ -21,7 +21,7 @@ struct WslcContainerProcessOptionsInternal; struct IOCallback { - IOCallback(IWSLCSDKProcess* process, const WslcContainerProcessIOCallbackOptions& options); + IOCallback(IWSLCCompatProcess* process, const WslcContainerProcessIOCallbackOptions& options); ~IOCallback(); void Cancel(); @@ -32,10 +32,10 @@ struct IOCallback static bool HasIOCallback(const WslcContainerProcessOptionsInternal* options); static bool HasIOCallback(const WslcContainerProcessIOCallbackOptions& options); - static wil::unique_handle GetIOHandle(IWSLCSDKProcess* process, WslcProcessIOHandle ioHandle); + static wil::unique_handle GetIOHandle(IWSLCCompatProcess* process, WslcProcessIOHandle ioHandle); private: - wil::com_ptr m_process; + wil::com_ptr m_process; std::unique_ptr m_callbackOptions; std::thread m_thread; wsl::windows::common::io::MultiHandleWait m_io; diff --git a/src/windows/WslcSDK/ProgressCallback.cpp b/src/windows/WslcSDK/ProgressCallback.cpp index 801ff33e6d..b0aafc8e51 100644 --- a/src/windows/WslcSDK/ProgressCallback.cpp +++ b/src/windows/WslcSDK/ProgressCallback.cpp @@ -8,7 +8,7 @@ Module Name: Abstract: - Implementation of a type that implements IWSLCSDKProgressCallback. + Implementation of a type that implements IWSLCCompatProgressCallback. --*/ #include "precomp.h" diff --git a/src/windows/WslcSDK/ProgressCallback.h b/src/windows/WslcSDK/ProgressCallback.h index 9e53c156c7..6eb728717e 100644 --- a/src/windows/WslcSDK/ProgressCallback.h +++ b/src/windows/WslcSDK/ProgressCallback.h @@ -8,19 +8,19 @@ Module Name: Abstract: - Header for a type that implements IWSLCSDKProgressCallback. + Header for a type that implements IWSLCCompatProgressCallback. --*/ #pragma once -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "wslcsdkprivate.h" #include -struct ProgressCallback : public winrt::implements +struct ProgressCallback : public winrt::implements { ProgressCallback(WslcContainerImageProgressCallback callback, PVOID context); - // IWSLCSDKProgressCallback + // IWSLCCompatProgressCallback HRESULT STDMETHODCALLTYPE OnProgress(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total) override; // Creates a ProgressCallback if the options provides a callback. diff --git a/src/windows/WslcSDK/TerminationCallback.cpp b/src/windows/WslcSDK/TerminationCallback.cpp index aa38bdfb4f..c97e4343ee 100644 --- a/src/windows/WslcSDK/TerminationCallback.cpp +++ b/src/windows/WslcSDK/TerminationCallback.cpp @@ -8,20 +8,20 @@ Module Name: Abstract: - Implementation of a type that implements IWSLCSDKTerminationCallback. + Implementation of a type that implements IWSLCCompatTerminationCallback. --*/ #include "precomp.h" #include "TerminationCallback.h" namespace { -WslcSessionTerminationReason ConvertReason(WSLCSDKVirtualMachineTerminationReason Reason) +WslcSessionTerminationReason ConvertReason(WSLCCompatVirtualMachineTerminationReason Reason) { switch (Reason) { - case WSLCSDKVirtualMachineTerminationReasonShutdown: + case WSLCCompatVirtualMachineTerminationReasonShutdown: return WSLC_SESSION_TERMINATION_REASON_SHUTDOWN; - case WSLCSDKVirtualMachineTerminationReasonCrashed: + case WSLCCompatVirtualMachineTerminationReasonCrashed: return WSLC_SESSION_TERMINATION_REASON_CRASHED; default: return WSLC_SESSION_TERMINATION_REASON_UNKNOWN; @@ -35,7 +35,7 @@ TerminationCallback::TerminationCallback(WslcSessionTerminationCallback callback } // TODO: Details from the runtime are dropped; should the SDK callback function be updated to include the reasons string? -HRESULT STDMETHODCALLTYPE TerminationCallback::OnTermination(WSLCSDKVirtualMachineTerminationReason Reason, LPCWSTR) +HRESULT STDMETHODCALLTYPE TerminationCallback::OnTermination(WSLCCompatVirtualMachineTerminationReason Reason, LPCWSTR) { if (m_callback) { diff --git a/src/windows/WslcSDK/TerminationCallback.h b/src/windows/WslcSDK/TerminationCallback.h index dcaceff44f..5a75192133 100644 --- a/src/windows/WslcSDK/TerminationCallback.h +++ b/src/windows/WslcSDK/TerminationCallback.h @@ -8,20 +8,20 @@ Module Name: Abstract: - Header for a type that implements IWSLCSDKTerminationCallback. + Header for a type that implements IWSLCCompatTerminationCallback. --*/ #pragma once -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "wslcsdkprivate.h" #include -struct TerminationCallback : public winrt::implements +struct TerminationCallback : public winrt::implements { TerminationCallback(WslcSessionTerminationCallback callback, PVOID context); - // IWSLCSDKTerminationCallback - HRESULT STDMETHODCALLTYPE OnTermination(WSLCSDKVirtualMachineTerminationReason Reason, LPCWSTR Details) override; + // IWSLCCompatTerminationCallback + HRESULT STDMETHODCALLTYPE OnTermination(WSLCCompatVirtualMachineTerminationReason Reason, LPCWSTR Details) override; // Creates a TerminationCallback if the options provides a callback. static winrt::com_ptr CreateIf(const WslcSessionOptionsInternal* options); diff --git a/src/windows/WslcSDK/WslcsdkPrivate.h b/src/windows/WslcSDK/WslcsdkPrivate.h index c12c5b82a2..cd0711de83 100644 --- a/src/windows/WslcSDK/WslcsdkPrivate.h +++ b/src/windows/WslcSDK/WslcsdkPrivate.h @@ -14,7 +14,7 @@ Module Name: #pragma once #include #include "wslcsdk.h" -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "IOCallback.h" #include #include // COM helpers @@ -106,8 +106,8 @@ const WslcContainerOptionsInternal* GetInternalType(const WslcContainerSettings* // Use to allocate the actual objects on the heap to keep it alive. struct WslcSessionImpl { - wil::com_ptr session; - wil::com_ptr terminationCallback; + wil::com_ptr session; + wil::com_ptr terminationCallback; }; WslcSessionImpl* GetInternalType(WslcSession handle); @@ -116,7 +116,7 @@ WslcSessionImpl* GetInternalType(WslcSession handle); // subscription whose release unregisters the callback. struct WslcCrashDumpSubscriptionImpl { - wil::com_ptr callback; + wil::com_ptr callback; wil::com_ptr subscription; }; @@ -124,7 +124,7 @@ WslcCrashDumpSubscriptionImpl* GetInternalType(WslcCrashDumpSubscription handle) struct WslcContainerImpl { - wil::com_ptr container; + wil::com_ptr container; WslcContainerProcessIOCallbackOptions ioCallbackOptions{}; std::atomic> ioCallbacks; }; @@ -133,7 +133,7 @@ WslcContainerImpl* GetInternalType(WslcContainer handle); struct WslcProcessImpl { - wil::com_ptr process; + wil::com_ptr process; std::shared_ptr ioCallbacks; }; diff --git a/src/windows/WslcSDK/wslcsdk.cpp b/src/windows/WslcSDK/wslcsdk.cpp index d07904e86c..5ab3ce5353 100644 --- a/src/windows/WslcSDK/wslcsdk.cpp +++ b/src/windows/WslcSDK/wslcsdk.cpp @@ -41,35 +41,35 @@ struct FlagsTraits template <> struct FlagsTraits { - using WslcType = WSLCSDKFeatureFlags; + using WslcType = WSLCCompatFeatureFlags; constexpr static WslcSessionFeatureFlags Mask = WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU; - WSLC_FLAG_VALUE_ASSERT(WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU, WSLCSDKFeatureFlagsGPU); + WSLC_FLAG_VALUE_ASSERT(WSLC_SESSION_FEATURE_FLAG_ENABLE_GPU, WSLCCompatFeatureFlagsGPU); }; template <> struct FlagsTraits { - using WslcType = WSLCSDKContainerFlags; + using WslcType = WSLCCompatContainerFlags; constexpr static WslcContainerFlags Mask = WSLC_CONTAINER_FLAG_AUTO_REMOVE | WSLC_CONTAINER_FLAG_ENABLE_GPU; - WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_AUTO_REMOVE, WSLCSDKContainerFlagsRm); - WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_ENABLE_GPU, WSLCSDKContainerFlagsGpu); + WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_AUTO_REMOVE, WSLCCompatContainerFlagsRm); + WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_FLAG_ENABLE_GPU, WSLCCompatContainerFlagsGpu); // TODO: WSLC_CONTAINER_FLAG_PRIVILEGED has no associated runtime value }; template <> struct FlagsTraits { - using WslcType = WSLCSDKContainerStartFlags; + using WslcType = WSLCCompatContainerStartFlags; constexpr static WslcContainerStartFlags Mask = WSLC_CONTAINER_START_FLAG_ATTACH; - WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_START_FLAG_ATTACH, WSLCSDKContainerStartFlagsAttach); + WSLC_FLAG_VALUE_ASSERT(WSLC_CONTAINER_START_FLAG_ATTACH, WSLCCompatContainerStartFlagsAttach); }; template <> struct FlagsTraits { - using WslcType = WSLCSDKDeleteFlags; + using WslcType = WSLCCompatDeleteFlags; constexpr static WslcDeleteContainerFlags Mask = WSLC_DELETE_CONTAINER_FLAG_FORCE; - WSLC_FLAG_VALUE_ASSERT(WSLC_DELETE_CONTAINER_FLAG_FORCE, WSLCSDKDeleteFlagsForce); + WSLC_FLAG_VALUE_ASSERT(WSLC_DELETE_CONTAINER_FLAG_FORCE, WSLCCompatDeleteFlagsForce); }; template @@ -79,22 +79,22 @@ typename FlagsTraits::WslcType ConvertFlags(Flags flags) return static_cast(flags & traits::Mask); } -WSLCSDKSignal Convert(WslcSignal signal) +WSLCCompatSignal Convert(WslcSignal signal) { switch (signal) { case WSLC_SIGNAL_NONE: - return WSLCSDKSignal::WSLCSDKSignalNone; + return WSLCCompatSignal::WSLCCompatSignalNone; case WSLC_SIGNAL_SIGHUP: - return WSLCSDKSignal::WSLCSDKSignalSIGHUP; + return WSLCCompatSignal::WSLCCompatSignalSIGHUP; case WSLC_SIGNAL_SIGINT: - return WSLCSDKSignal::WSLCSDKSignalSIGINT; + return WSLCCompatSignal::WSLCCompatSignalSIGINT; case WSLC_SIGNAL_SIGQUIT: - return WSLCSDKSignal::WSLCSDKSignalSIGQUIT; + return WSLCCompatSignal::WSLCCompatSignalSIGQUIT; case WSLC_SIGNAL_SIGKILL: - return WSLCSDKSignal::WSLCSDKSignalSIGKILL; + return WSLCCompatSignal::WSLCCompatSignalSIGKILL; case WSLC_SIGNAL_SIGTERM: - return WSLCSDKSignal::WSLCSDKSignalSIGTERM; + return WSLCCompatSignal::WSLCCompatSignalSIGTERM; default: THROW_HR_MSG(E_INVALIDARG, "Invalid WslcSignal: %i", signal); } @@ -208,7 +208,7 @@ static HRESULT InetNtopToHresult(int af, const void* src, char* dst, size_t dstC return S_OK; } -bool CopyProcessSettingsToRuntime(WSLCSDKProcessOptions& runtimeOptions, const WslcContainerProcessOptionsInternal* initProcessOptions) +bool CopyProcessSettingsToRuntime(WSLCCompatProcessOptions& runtimeOptions, const WslcContainerProcessOptionsInternal* initProcessOptions) { if (initProcessOptions) { @@ -306,13 +306,13 @@ WslRuntimeState CheckWslRuntimeState() return DoesWslRuntimeVersionSupportWslc(version) ? WslRuntimeState::InstalledWithWslcSupport : WslRuntimeState::InstalledWithoutWslcSupport; } -std::pair, HRESULT> CreateSessionManagerRaw() +std::pair, HRESULT> CreateSessionManagerRaw() { - wil::com_ptr result; + wil::com_ptr result; HRESULT hr = CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&result)); if (SUCCEEDED(hr)) { - const WSLCSDKVersion clientVersion{WSL_PACKAGE_VERSION_MAJOR, WSL_PACKAGE_VERSION_MINOR, WSL_PACKAGE_VERSION_REVISION}; + const WSLCCompatVersion clientVersion{WSL_PACKAGE_VERSION_MAJOR, WSL_PACKAGE_VERSION_MINOR, WSL_PACKAGE_VERSION_REVISION}; BOOL isSupported = FALSE; THROW_IF_FAILED(result->IsClientVersionSupported(&clientVersion, &isSupported)); @@ -332,7 +332,7 @@ std::pair, HRESULT> CreateSessionManagerRaw return {result, hr}; } -wil::com_ptr CreateSessionManager() +wil::com_ptr CreateSessionManager() { auto [result, hr] = CreateSessionManagerRaw(); @@ -424,29 +424,29 @@ try ErrorInfoWrapper errorInfoWrapper{errorMessage}; auto internalType = CheckAndGetInternalType(sessionSettings); - wil::com_ptr sessionManager = CreateSessionManager(); + wil::com_ptr sessionManager = CreateSessionManager(); auto result = std::make_unique(); - WSLCSDKSessionSettings runtimeSettings{}; + WSLCCompatSessionSettings runtimeSettings{}; runtimeSettings.DisplayName = internalType->displayName; runtimeSettings.StoragePath = internalType->storagePath; runtimeSettings.MaximumStorageSizeMb = internalType->vhdRequirements.sizeBytes / _1MB; runtimeSettings.CpuCount = internalType->cpuCount; runtimeSettings.MemoryMb = internalType->memoryMb; runtimeSettings.BootTimeoutMs = internalType->timeoutMS; - runtimeSettings.NetworkingMode = WSLCSDKNetworkingModeVirtioProxy; + runtimeSettings.NetworkingMode = WSLCCompatNetworkingModeVirtioProxy; auto terminationCallback = TerminationCallback::CreateIf(internalType); if (terminationCallback) { - result->terminationCallback.attach(terminationCallback.as().detach()); + result->terminationCallback.attach(terminationCallback.as().detach()); runtimeSettings.TerminationCallback = terminationCallback.get(); } runtimeSettings.FeatureFlags = ConvertFlags(internalType->featureFlags); - WI_SetFlag(runtimeSettings.FeatureFlags, WSLCSDKFeatureFlagsVirtioFs); - WI_SetFlag(runtimeSettings.FeatureFlags, WSLCSDKFeatureFlagsDnsTunneling); + WI_SetFlag(runtimeSettings.FeatureFlags, WSLCCompatFeatureFlagsVirtioFs); + WI_SetFlag(runtimeSettings.FeatureFlags, WSLCCompatFeatureFlagsDnsTunneling); if (SUCCEEDED(errorInfoWrapper.CaptureResult( - sessionManager->CreateSession(&runtimeSettings, WSLCSDKSessionFlagsNone, nullptr, &result->session)))) + sessionManager->CreateSession(&runtimeSettings, WSLCCompatSessionFlagsNone, nullptr, &result->session)))) { wsl::windows::common::security::ConfigureForCOMImpersonation(result->session.get()); *session = reinterpret_cast(result.release()); @@ -506,7 +506,7 @@ try std::string uidStr; std::string gidStr; - std::vector driverOpts; + std::vector driverOpts; driverOpts.push_back({"SizeBytes", sizeStr.c_str()}); if (options->type == WSLC_VHD_TYPE_FIXED) @@ -526,13 +526,13 @@ try driverOpts.push_back({"Gid", gidStr.c_str()}); } - WSLCSDKVolumeOptions volumeOptions{}; + WSLCCompatVolumeOptions volumeOptions{}; volumeOptions.Name = options->name; volumeOptions.Driver = "vhd"; volumeOptions.DriverOpts = driverOpts.data(); volumeOptions.DriverOptsCount = static_cast(driverOpts.size()); - WSLCSDKVolumeInformation volumeInfo{}; + WSLCCompatVolumeInformation volumeInfo{}; return errorInfoWrapper.CaptureResult(internalType->session->CreateVolume(&volumeOptions, &volumeInfo)); } CATCH_RETURN(); @@ -675,10 +675,10 @@ try // If the container has an IO callback registered, and the container has exited, wait until the IO callback has processed all IO. try { - WSLCSDKContainerState state{}; + WSLCCompatContainerState state{}; THROW_IF_FAILED(internalType->container->GetState(&state)); - if (state == WSLCSDKContainerStateExited || state == WSLCSDKContainerStateDeleted) + if (state == WSLCCompatContainerStateExited || state == WSLCCompatContainerStateDeleted) { ioCallback->Complete(); } @@ -710,11 +710,11 @@ try try { - WSLCSDKProcessState state{}; + WSLCCompatProcessState state{}; int exitCode{}; THROW_IF_FAILED(internalType->process->GetState(&state, &exitCode)); - if (state == WSLCSDKProcessStateExited || state == WSLCSDKProcessStateSignalled) + if (state == WSLCCompatProcessStateExited || state == WSLCCompatProcessStateSignalled) { internalType->ioCallbacks->Complete(); } @@ -756,8 +756,8 @@ try auto result = std::make_unique(); - WSLCSDKContainerOptions containerOptions{}; - std::unique_ptr convertedPorts; // this must stay in same scope as containerOptions since containerOptions.Ports is getting a raw pointer to the array owned by convertedPorts. + WSLCCompatContainerOptions containerOptions{}; + std::unique_ptr convertedPorts; // this must stay in same scope as containerOptions since containerOptions.Ports is getting a raw pointer to the array owned by convertedPorts. containerOptions.Image = internalContainerSettings->image; containerOptions.Name = internalContainerSettings->runtimeName; @@ -767,14 +767,14 @@ try CopyProcessSettingsToRuntime(containerOptions.InitProcessOptions, internalContainerSettings->initProcessOptions); - std::unique_ptr convertedVolumes; + std::unique_ptr convertedVolumes; if (internalContainerSettings->volumes && internalContainerSettings->volumesCount) { - convertedVolumes = std::make_unique(internalContainerSettings->volumesCount); + convertedVolumes = std::make_unique(internalContainerSettings->volumesCount); for (uint32_t i = 0; i < internalContainerSettings->volumesCount; ++i) { const WslcContainerVolume& internalVolume = internalContainerSettings->volumes[i]; - WSLCSDKVolume& convertedVolume = convertedVolumes[i]; + WSLCCompatVolume& convertedVolume = convertedVolumes[i]; convertedVolume.HostPath = internalVolume.windowsPath; convertedVolume.ContainerPath = internalVolume.containerPath; @@ -784,14 +784,14 @@ try containerOptions.VolumesCount = static_cast(internalContainerSettings->volumesCount); } - std::unique_ptr convertedNamedVolumes; + std::unique_ptr convertedNamedVolumes; if (internalContainerSettings->namedVolumes && internalContainerSettings->namedVolumesCount) { - convertedNamedVolumes = std::make_unique(internalContainerSettings->namedVolumesCount); + convertedNamedVolumes = std::make_unique(internalContainerSettings->namedVolumesCount); for (uint32_t i = 0; i < internalContainerSettings->namedVolumesCount; ++i) { const WslcContainerNamedVolume& internalVolume = internalContainerSettings->namedVolumes[i]; - WSLCSDKNamedVolume& convertedVolume = convertedNamedVolumes[i]; + WSLCCompatNamedVolume& convertedVolume = convertedNamedVolumes[i]; convertedVolume.Name = internalVolume.name; convertedVolume.ContainerPath = internalVolume.containerPath; @@ -803,11 +803,11 @@ try if (internalContainerSettings->ports && internalContainerSettings->portsCount) { - convertedPorts = std::make_unique(internalContainerSettings->portsCount); + convertedPorts = std::make_unique(internalContainerSettings->portsCount); for (uint32_t i = 0; i < internalContainerSettings->portsCount; ++i) { const WslcContainerPortMapping& internalPort = internalContainerSettings->ports[i]; - WSLCSDKPortMapping& convertedPort = convertedPorts[i]; + WSLCCompatPortMapping& convertedPort = convertedPorts[i]; convertedPort.HostPort = internalPort.windowsPort; convertedPort.ContainerPort = internalPort.containerPort; @@ -908,7 +908,7 @@ try { if (hasIOCallback) { - wil::com_ptr process; + wil::com_ptr process; RETURN_IF_FAILED(internalType->container->GetInitProcess(&process)); wsl::windows::common::security::ConfigureForCOMImpersonation(process.get()); internalType->ioCallbacks = std::make_shared(process.get(), internalType->ioCallbackOptions); @@ -1065,7 +1065,7 @@ try auto internalProcessSettings = CheckAndGetInternalType(newProcessSettings); RETURN_HR_IF(E_INVALIDARG, internalProcessSettings->commandLine == nullptr || internalProcessSettings->commandLineCount == 0); - WSLCSDKProcessOptions runtimeOptions{}; + WSLCCompatProcessOptions runtimeOptions{}; CopyProcessSettingsToRuntime(runtimeOptions, internalProcessSettings); auto result = std::make_unique(); @@ -1090,7 +1090,7 @@ CATCH_RETURN(); STDAPI WslcGetContainerID(WslcContainer container, CHAR containerID[WSLC_CONTAINER_ID_BUFFER_SIZE]) try { - static_assert(WSLC_CONTAINER_ID_BUFFER_SIZE == sizeof(WSLCSDKContainerId), "Container ID lengths differ."); + static_assert(WSLC_CONTAINER_ID_BUFFER_SIZE == sizeof(WSLCCompatContainerId), "Container ID lengths differ."); auto internalType = CheckAndGetInternalType(container); RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->container); @@ -1144,9 +1144,9 @@ STDAPI WslcGetContainerState(_In_ WslcContainer container, _Out_ WslcContainerSt try { static_assert( - WSLC_CONTAINER_STATE_INVALID == WSLCSDKContainerStateInvalid && WSLC_CONTAINER_STATE_CREATED == WSLCSDKContainerStateCreated && - WSLC_CONTAINER_STATE_RUNNING == WSLCSDKContainerStateRunning && - WSLC_CONTAINER_STATE_EXITED == WSLCSDKContainerStateExited && WSLC_CONTAINER_STATE_DELETED == WSLCSDKContainerStateDeleted, + WSLC_CONTAINER_STATE_INVALID == WSLCCompatContainerStateInvalid && WSLC_CONTAINER_STATE_CREATED == WSLCCompatContainerStateCreated && + WSLC_CONTAINER_STATE_RUNNING == WSLCCompatContainerStateRunning && + WSLC_CONTAINER_STATE_EXITED == WSLCCompatContainerStateExited && WSLC_CONTAINER_STATE_DELETED == WSLCCompatContainerStateDeleted, "Container state enum values mismatch."); auto internalType = CheckAndGetInternalType(container); @@ -1155,7 +1155,7 @@ try *state = WSLC_CONTAINER_STATE_INVALID; - WSLCSDKContainerState runtimeState{}; + WSLCCompatContainerState runtimeState{}; RETURN_IF_FAILED(internalType->container->GetState(&runtimeState)); *state = static_cast(runtimeState); @@ -1279,8 +1279,8 @@ STDAPI WslcGetProcessState(_In_ WslcProcess process, _Out_ WslcProcessState* sta try { static_assert( - WSLC_PROCESS_STATE_UNKNOWN == WSLCSDKProcessStateUnknown && WSLC_PROCESS_STATE_RUNNING == WSLCSDKProcessStateRunning && - WSLC_PROCESS_STATE_EXITED == WSLCSDKProcessStateExited && WSLC_PROCESS_STATE_SIGNALLED == WSLCSDKProcessStateSignalled, + WSLC_PROCESS_STATE_UNKNOWN == WSLCCompatProcessStateUnknown && WSLC_PROCESS_STATE_RUNNING == WSLCCompatProcessStateRunning && + WSLC_PROCESS_STATE_EXITED == WSLCCompatProcessStateExited && WSLC_PROCESS_STATE_SIGNALLED == WSLCCompatProcessStateSignalled, "Process state enum values mismatch."); auto internalType = CheckAndGetInternalType(process); @@ -1289,7 +1289,7 @@ try *state = WSLC_PROCESS_STATE_UNKNOWN; - WSLCSDKProcessState runtimeState{}; + WSLCCompatProcessState runtimeState{}; int exitCode{}; RETURN_IF_FAILED(internalType->process->GetState(&runtimeState, &exitCode)); @@ -1307,9 +1307,9 @@ try *exitCode = -1; - WSLCSDKProcessState runtimeState{}; + WSLCCompatProcessState runtimeState{}; RETURN_IF_FAILED(internalType->process->GetState(&runtimeState, exitCode)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), runtimeState != WSLCSDKProcessStateExited); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), runtimeState != WSLCCompatProcessStateExited); return S_OK; } CATCH_RETURN(); @@ -1380,7 +1380,7 @@ try } CATCH_RETURN(); -static WSLCSDKHandle ToWSLCSDKInputHandle(HANDLE Handle) +static WSLCCompatHandle ToWSLCCompatInputHandle(HANDLE Handle) { const auto type = GetFileType(Handle); if (type == FILE_TYPE_PIPE) @@ -1392,20 +1392,20 @@ static WSLCSDKHandle ToWSLCSDKInputHandle(HANDLE Handle) // Check for a named pipe first, since getsockopt() can return success for a named pipe. if (GetNamedPipeInfo(Handle, nullptr, nullptr, nullptr, nullptr)) { - return WSLCSDKHandle{.Type = WSLCSDKHandleTypePipe, .Handle = {.Pipe = Handle}}; + return WSLCCompatHandle{.Type = WSLCCompatHandleTypePipe, .Handle = {.Pipe = Handle}}; } else if (getsockopt(reinterpret_cast(Handle), SOL_SOCKET, SO_TYPE, reinterpret_cast(&socketType), &len) == 0) { - return WSLCSDKHandle{.Type = WSLCSDKHandleTypeSocket, .Handle = {.Socket = Handle}}; + return WSLCCompatHandle{.Type = WSLCCompatHandleTypeSocket, .Handle = {.Socket = Handle}}; } else { - return WSLCSDKHandle{.Type = WSLCSDKHandleTypePipe, .Handle = {.Pipe = Handle}}; + return WSLCCompatHandle{.Type = WSLCCompatHandleTypePipe, .Handle = {.Pipe = Handle}}; } } else if (type == FILE_TYPE_DISK) { - return WSLCSDKHandle{.Type = WSLCSDKHandleTypeFile, .Handle = {.File = Handle}}; + return WSLCCompatHandle{.Type = WSLCCompatHandleTypeFile, .Handle = {.File = Handle}}; } else { @@ -1419,7 +1419,7 @@ static HRESULT WslcImportSessionImageImpl( auto progressCallback = ProgressCallback::CreateIf(options); return errorInfoWrapper.CaptureResult(internalSession->session->ImportImage( - ToWSLCSDKInputHandle(imageFile.Handle()), imageName, progressCallback.get(), imageFile.Length(), nullptr)); + ToWSLCCompatInputHandle(imageFile.Handle()), imageName, progressCallback.get(), imageFile.Length(), nullptr)); } STDAPI WslcImportSessionImage( @@ -1456,8 +1456,8 @@ static HRESULT WslcLoadSessionImageImpl( { auto progressCallback = ProgressCallback::CreateIf(options); - return errorInfoWrapper.CaptureResult( - internalSession->session->LoadImage(ToWSLCSDKInputHandle(imageFile.Handle()), progressCallback.get(), imageFile.Length(), nullptr)); + return errorInfoWrapper.CaptureResult(internalSession->session->LoadImage( + ToWSLCCompatInputHandle(imageFile.Handle()), progressCallback.get(), imageFile.Length(), nullptr)); } STDAPI WslcLoadSessionImage( @@ -1493,11 +1493,11 @@ try RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->session); RETURN_HR_IF_NULL(E_POINTER, nameOrID); - WSLCSDKDeleteImageOptions options{}; + WSLCCompatDeleteImageOptions options{}; options.Image = nameOrID; // TODO: Flags? (Force and NoPrune) - wil::unique_cotaskmem_array_ptr deletedImageInformation; + wil::unique_cotaskmem_array_ptr deletedImageInformation; return errorInfoWrapper.CaptureResult( internalType->session->DeleteImage(&options, &deletedImageInformation, deletedImageInformation.size_address())); @@ -1515,7 +1515,7 @@ try RETURN_HR_IF_NULL(E_INVALIDARG, options->repo); RETURN_HR_IF_NULL(E_INVALIDARG, options->tag); - WSLCSDKTagImageOptions runtimeOptions{}; + WSLCCompatTagImageOptions runtimeOptions{}; runtimeOptions.Image = options->image; runtimeOptions.Repo = options->repo; runtimeOptions.Tag = options->tag; @@ -1575,7 +1575,7 @@ STDAPI WslcListSessionImages(_In_ WslcSession session, _Outptr_result_buffer_(*c try { static_assert( - sizeof(decltype(WslcImageInfo::name)) == sizeof(decltype(WSLCSDKImageInformation::Image)), "Image name size mismatch."); + sizeof(decltype(WslcImageInfo::name)) == sizeof(decltype(WSLCCompatImageInformation::Image)), "Image name size mismatch."); RETURN_HR_IF_NULL(E_POINTER, images); *images = nullptr; @@ -1586,7 +1586,7 @@ try // TODO: Many filtering options are available via WSLC_LIST_IMAGES_OPTIONS - wil::unique_cotaskmem_array_ptr imageInformation; + wil::unique_cotaskmem_array_ptr imageInformation; RETURN_IF_FAILED(internalType->session->ListImages(nullptr, &imageInformation, imageInformation.size_address())); @@ -1597,14 +1597,14 @@ try for (size_t i = 0; i < imageInformation.size(); ++i) { WslcImageInfo& currentResult = result[i]; - WSLCSDKImageInformation& currentImage = imageInformation[i]; + WSLCCompatImageInformation& currentImage = imageInformation[i]; static_assert(std::is_trivial_v, "WslcImageInfo must be trivial."); currentResult = {}; THROW_HR_IF( E_UNEXPECTED, - memcpy_s(currentResult.name, sizeof(decltype(WslcImageInfo::name)), currentImage.Image, sizeof(decltype(WSLCSDKImageInformation::Image))) != + memcpy_s(currentResult.name, sizeof(decltype(WslcImageInfo::name)), currentImage.Image, sizeof(decltype(WSLCCompatImageInformation::Image))) != 0); ConvertSHA256Hash(currentImage.Hash, currentResult.sha256); currentResult.sizeBytes = currentImage.Size; @@ -1662,9 +1662,9 @@ try static_assert(std::is_trivial_v, "WslcVersion must be trivial"); *version = {}; - wil::com_ptr sessionManager = CreateSessionManager(); + wil::com_ptr sessionManager = CreateSessionManager(); - WSLCSDKVersion runtimeVersion{}; + WSLCCompatVersion runtimeVersion{}; RETURN_IF_FAILED(sessionManager->GetVersion(&runtimeVersion)); version->major = runtimeVersion.Major; diff --git a/src/windows/common/APICompat.cpp b/src/windows/common/APICompat.cpp new file mode 100644 index 0000000000..f886944b96 --- /dev/null +++ b/src/windows/common/APICompat.cpp @@ -0,0 +1,728 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. + +#include "precomp.h" +#include "APICompat.h" +#include + +namespace wsl::windows::common::apicompat { + +namespace { + + template + void CopyString(char (&Destination)[Size], const char* Source) + { + THROW_HR_IF(E_UNEXPECTED, strcpy_s(Destination, Source) != 0); + } + + // Converts an input array of WSLCCompat elements into a vector of the matching + // wslc.idl elements by converting each element individually. + template + std::vector ConvertArray(const TIn* Items, ULONG Count) + { + std::vector result; + if (Items == nullptr || Count == 0) + { + return result; + } + + result.reserve(Count); + for (ULONG index = 0; index < Count; index++) + { + result.push_back(Convert(Items[index])); + } + + return result; + } + + // + // In-process adapters that bridge the SDK-facing WSLCCompat callback interfaces to + // the internal wslc.idl callback interfaces. They wrap the SDK's marshaled proxy + // and are only ever invoked in-process, so they do not need to be registered for + // marshaling. + // + + class TerminationCallbackAdapter + : public Microsoft::WRL::RuntimeClass, ITerminationCallback> + { + public: + TerminationCallbackAdapter(IWSLCCompatTerminationCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnTermination)(WSLCVirtualMachineTerminationReason Reason, LPCWSTR Details) override + { + return m_inner->OnTermination(Convert(Reason), Details); + } + + private: + Microsoft::WRL::ComPtr m_inner; + }; + + class CrashDumpCallbackAdapter + : public Microsoft::WRL::RuntimeClass, ICrashDumpCallback> + { + public: + CrashDumpCallbackAdapter(IWSLCCompatCrashDumpCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnCrashDump)(LPCWSTR DumpPath, LPCSTR ProcessName, ULONGLONG Pid, ULONG Signal, ULONGLONG Timestamp) override + { + return m_inner->OnCrashDump(DumpPath, ProcessName, Pid, Signal, Timestamp); + } + + private: + Microsoft::WRL::ComPtr m_inner; + }; + + class ProgressCallbackAdapter + : public Microsoft::WRL::RuntimeClass, IProgressCallback> + { + public: + ProgressCallbackAdapter(IWSLCCompatProgressCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnProgress)(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total) override + { + return m_inner->OnProgress(Status, Id, Current, Total); + } + + private: + Microsoft::WRL::ComPtr m_inner; + }; + + class WarningCallbackAdapter + : public Microsoft::WRL::RuntimeClass, IWarningCallback> + { + public: + WarningCallbackAdapter(IWSLCCompatWarningCallback* Inner) : m_inner(Inner) + { + } + + IFACEMETHOD(OnWarning)(LPCWSTR Message) override + { + return m_inner->OnWarning(Message); + } + + private: + Microsoft::WRL::ComPtr m_inner; + }; + +} // namespace + +// +// Enum conversions. +// + +WSLCFD Convert(WSLCCompatFD Fd) +{ + switch (Fd) + { + case WSLCCompatFDStdin: + return WSLCFDStdin; + case WSLCCompatFDStdout: + return WSLCFDStdout; + case WSLCCompatFDStderr: + return WSLCFDStderr; + case WSLCCompatFDTty: + return WSLCFDTty; + } + + return WSLCFDStdin; +} + +WSLCSignal Convert(WSLCCompatSignal Signal) +{ + switch (Signal) + { + case WSLCCompatSignalNone: + return WSLCSignalNone; + case WSLCCompatSignalSIGHUP: + return WSLCSignalSIGHUP; + case WSLCCompatSignalSIGINT: + return WSLCSignalSIGINT; + case WSLCCompatSignalSIGQUIT: + return WSLCSignalSIGQUIT; + case WSLCCompatSignalSIGILL: + return WSLCSignalSIGILL; + case WSLCCompatSignalSIGTRAP: + return WSLCSignalSIGTRAP; + case WSLCCompatSignalSIGABRT: // Equivalent to WSLCCompatSignalSIGIOT. + return WSLCSignalSIGABRT; + case WSLCCompatSignalSIGBUS: + return WSLCSignalSIGBUS; + case WSLCCompatSignalSIGFPE: + return WSLCSignalSIGFPE; + case WSLCCompatSignalSIGKILL: + return WSLCSignalSIGKILL; + case WSLCCompatSignalSIGUSR1: + return WSLCSignalSIGUSR1; + case WSLCCompatSignalSIGSEGV: + return WSLCSignalSIGSEGV; + case WSLCCompatSignalSIGUSR2: + return WSLCSignalSIGUSR2; + case WSLCCompatSignalSIGPIPE: + return WSLCSignalSIGPIPE; + case WSLCCompatSignalSIGALRM: + return WSLCSignalSIGALRM; + case WSLCCompatSignalSIGTERM: + return WSLCSignalSIGTERM; + case WSLCCompatSignalSIGTKFLT: + return WSLCSignalSIGTKFLT; + case WSLCCompatSignalSIGCHLD: + return WSLCSignalSIGCHLD; + case WSLCCompatSignalSIGCONT: + return WSLCSignalSIGCONT; + case WSLCCompatSignalSIGSTOP: + return WSLCSignalSIGSTOP; + case WSLCCompatSignalSIGTSTP: + return WSLCSignalSIGTSTP; + case WSLCCompatSignalSIGTTIN: + return WSLCSignalSIGTTIN; + case WSLCCompatSignalSIGTTOU: + return WSLCSignalSIGTTOU; + case WSLCCompatSignalSIGURG: + return WSLCSignalSIGURG; + case WSLCCompatSignalSIGXCPU: + return WSLCSignalSIGXCPU; + case WSLCCompatSignalSIGXFSZ: + return WSLCSignalSIGXFSZ; + case WSLCCompatSignalSIGVTALRM: + return WSLCSignalSIGVTALRM; + case WSLCCompatSignalSIGPROF: + return WSLCSignalSIGPROF; + case WSLCCompatSignalSIGWINCH: + return WSLCSignalSIGWINCH; + case WSLCCompatSignalSIGIO: // Equivalent to WSLCCompatSignalSIGPOLL. + return WSLCSignalSIGIO; + case WSLCCompatSignalSIGPWR: + return WSLCSignalSIGPWR; + case WSLCCompatSignalSIGSYS: + return WSLCSignalSIGSYS; + } + + return WSLCSignalNone; +} + +WSLCProcessFlags Convert(WSLCCompatProcessFlags Flags) +{ + WSLCProcessFlags result = WSLCProcessFlagsNone; + WI_SetFlagIf(result, WSLCProcessFlagsStdin, WI_IsFlagSet(Flags, WSLCCompatProcessFlagsStdin)); + WI_SetFlagIf(result, WSLCProcessFlagsTty, WI_IsFlagSet(Flags, WSLCCompatProcessFlagsTty)); + return result; +} + +WSLCContainerFlags Convert(WSLCCompatContainerFlags Flags) +{ + WSLCContainerFlags result = WSLCContainerFlagsNone; + WI_SetFlagIf(result, WSLCContainerFlagsRm, WI_IsFlagSet(Flags, WSLCCompatContainerFlagsRm)); + WI_SetFlagIf(result, WSLCContainerFlagsGpu, WI_IsFlagSet(Flags, WSLCCompatContainerFlagsGpu)); + WI_SetFlagIf(result, WSLCContainerFlagsInit, WI_IsFlagSet(Flags, WSLCCompatContainerFlagsInit)); + WI_SetFlagIf(result, WSLCContainerFlagsPublishAll, WI_IsFlagSet(Flags, WSLCCompatContainerFlagsPublishAll)); + return result; +} + +WSLCContainerStartFlags Convert(WSLCCompatContainerStartFlags Flags) +{ + WSLCContainerStartFlags result = WSLCContainerStartFlagsNone; + WI_SetFlagIf(result, WSLCContainerStartFlagsAttach, WI_IsFlagSet(Flags, WSLCCompatContainerStartFlagsAttach)); + return result; +} + +WSLCDeleteFlags Convert(WSLCCompatDeleteFlags Flags) +{ + WSLCDeleteFlags result = WSLCDeleteFlagsNone; + WI_SetFlagIf(result, WSLCDeleteFlagsForce, WI_IsFlagSet(Flags, WSLCCompatDeleteFlagsForce)); + WI_SetFlagIf(result, WSLCDeleteFlagsDeleteVolumes, WI_IsFlagSet(Flags, WSLCCompatDeleteFlagsDeleteVolumes)); + return result; +} + +WSLCNetworkingMode Convert(WSLCCompatNetworkingMode Mode) +{ + switch (Mode) + { + case WSLCCompatNetworkingModeNone: + return WSLCNetworkingModeNone; + case WSLCCompatNetworkingModeNAT: + return WSLCNetworkingModeNAT; + case WSLCCompatNetworkingModeVirtioProxy: + return WSLCNetworkingModeVirtioProxy; + } + + return WSLCNetworkingModeNone; +} + +WSLCFeatureFlags Convert(WSLCCompatFeatureFlags Flags) +{ + WSLCFeatureFlags result = WslcFeatureFlagsNone; + WI_SetFlagIf(result, WslcFeatureFlagsDnsTunneling, WI_IsFlagSet(Flags, WSLCCompatFeatureFlagsDnsTunneling)); + WI_SetFlagIf(result, WslcFeatureFlagsEarlyBootDmesg, WI_IsFlagSet(Flags, WSLCCompatFeatureFlagsEarlyBootDmesg)); + WI_SetFlagIf(result, WslcFeatureFlagsGPU, WI_IsFlagSet(Flags, WSLCCompatFeatureFlagsGPU)); + WI_SetFlagIf(result, WslcFeatureFlagsVirtioFs, WI_IsFlagSet(Flags, WSLCCompatFeatureFlagsVirtioFs)); + WI_SetFlagIf(result, WslcFeatureFlagsDebug, WI_IsFlagSet(Flags, WSLCCompatFeatureFlagsDebug)); + return result; +} + +WSLCSessionStorageFlags Convert(WSLCCompatSessionStorageFlags Flags) +{ + WSLCSessionStorageFlags result = WSLCSessionStorageFlagsNone; + WI_SetFlagIf(result, WSLCSessionStorageFlagsNoCreate, WI_IsFlagSet(Flags, WSLCCompatSessionStorageFlagsNoCreate)); + return result; +} + +WSLCSessionFlags Convert(WSLCCompatSessionFlags Flags) +{ + WSLCSessionFlags result = WSLCSessionFlagsNone; + WI_SetFlagIf(result, WSLCSessionFlagsPersistent, WI_IsFlagSet(Flags, WSLCCompatSessionFlagsPersistent)); + WI_SetFlagIf(result, WSLCSessionFlagsOpenExisting, WI_IsFlagSet(Flags, WSLCCompatSessionFlagsOpenExisting)); + return result; +} + +WSLCHandleType Convert(WSLCCompatHandleType Type) +{ + switch (Type) + { + case WSLCCompatHandleTypeUnknown: + return WSLCHandleTypeUnknown; + case WSLCCompatHandleTypeFile: + return WSLCHandleTypeFile; + case WSLCCompatHandleTypePipe: + return WSLCHandleTypePipe; + case WSLCCompatHandleTypeSocket: + return WSLCHandleTypeSocket; + } + + return WSLCHandleTypeUnknown; +} + +WSLCCompatProcessState Convert(WSLCProcessState State) +{ + switch (State) + { + case WslcProcessStateUnknown: + return WSLCCompatProcessStateUnknown; + case WslcProcessStateRunning: + return WSLCCompatProcessStateRunning; + case WslcProcessStateExited: + return WSLCCompatProcessStateExited; + case WslcProcessStateSignalled: + return WSLCCompatProcessStateSignalled; + } + + return WSLCCompatProcessStateUnknown; +} + +WSLCCompatContainerState Convert(WSLCContainerState State) +{ + switch (State) + { + case WslcContainerStateInvalid: + return WSLCCompatContainerStateInvalid; + case WslcContainerStateCreated: + return WSLCCompatContainerStateCreated; + case WslcContainerStateRunning: + return WSLCCompatContainerStateRunning; + case WslcContainerStateExited: + return WSLCCompatContainerStateExited; + case WslcContainerStateDeleted: + return WSLCCompatContainerStateDeleted; + } + + return WSLCCompatContainerStateInvalid; +} + +WSLCCompatVirtualMachineTerminationReason Convert(WSLCVirtualMachineTerminationReason Reason) +{ + switch (Reason) + { + case WSLCVirtualMachineTerminationReasonUnknown: + return WSLCCompatVirtualMachineTerminationReasonUnknown; + case WSLCVirtualMachineTerminationReasonShutdown: + return WSLCCompatVirtualMachineTerminationReasonShutdown; + case WSLCVirtualMachineTerminationReasonCrashed: + return WSLCCompatVirtualMachineTerminationReasonCrashed; + } + + return WSLCCompatVirtualMachineTerminationReasonUnknown; +} + +WSLCCompatHandleType Convert(WSLCHandleType Type) +{ + switch (Type) + { + case WSLCHandleTypeUnknown: + return WSLCCompatHandleTypeUnknown; + case WSLCHandleTypeFile: + return WSLCCompatHandleTypeFile; + case WSLCHandleTypePipe: + return WSLCCompatHandleTypePipe; + case WSLCHandleTypeSocket: + return WSLCCompatHandleTypeSocket; + } + + return WSLCCompatHandleTypeUnknown; +} + +WSLCCompatDeletedImageType Convert(WSLCDeletedImageType Type) +{ + switch (Type) + { + case WSLCDeletedImageTypeDeleted: + return WSLCCompatDeletedImageTypeDeleted; + case WSLCDeletedImageTypeUntagged: + return WSLCCompatDeletedImageTypeUntagged; + } + + return WSLCCompatDeletedImageTypeDeleted; +} + +// +// Scalar / non-owning struct conversions. +// + +WSLCVersion Convert(const WSLCCompatVersion& Version) +{ + WSLCVersion result{}; + result.Major = Version.Major; + result.Minor = Version.Minor; + result.Revision = Version.Revision; + return result; +} + +WSLCCompatVersion Convert(const WSLCVersion& Version) +{ + WSLCCompatVersion result{}; + result.Major = Version.Major; + result.Minor = Version.Minor; + result.Revision = Version.Revision; + return result; +} + +WSLCHandle Convert(const WSLCCompatHandle& Handle) +{ + WSLCHandle result{}; + result.Type = Convert(Handle.Type); + switch (Handle.Type) + { + case WSLCCompatHandleTypeFile: + result.Handle.File = Handle.Handle.File; + break; + case WSLCCompatHandleTypePipe: + result.Handle.Pipe = Handle.Handle.Pipe; + break; + case WSLCCompatHandleTypeSocket: + result.Handle.Socket = Handle.Handle.Socket; + break; + case WSLCCompatHandleTypeUnknown: + break; + } + + return result; +} + +WSLCCompatHandle Convert(const WSLCHandle& Handle) +{ + WSLCCompatHandle result{}; + result.Type = Convert(Handle.Type); + switch (Handle.Type) + { + case WSLCHandleTypeFile: + result.Handle.File = Handle.Handle.File; + break; + case WSLCHandleTypePipe: + result.Handle.Pipe = Handle.Handle.Pipe; + break; + case WSLCHandleTypeSocket: + result.Handle.Socket = Handle.Handle.Socket; + break; + case WSLCHandleTypeUnknown: + break; + } + + return result; +} + +WSLCStringArray Convert(const WSLCCompatStringArray& Array) +{ + WSLCStringArray result{}; + result.Values = Array.Values; + result.Count = Array.Count; + return result; +} + +WSLCProcessOptions Convert(const WSLCCompatProcessOptions& Options) +{ + WSLCProcessOptions result{}; + result.CurrentDirectory = Options.CurrentDirectory; + result.User = Options.User; + result.CommandLine = Convert(Options.CommandLine); + result.Environment = Convert(Options.Environment); + result.Flags = Convert(Options.Flags); + return result; +} + +KeyValuePair Convert(const WSLCCompatKeyValuePair& Pair) +{ + KeyValuePair result{}; + result.Key = Pair.Key; + result.Value = Pair.Value; + return result; +} + +WSLCVolume Convert(const WSLCCompatVolume& Volume) +{ + WSLCVolume result{}; + result.HostPath = Volume.HostPath; + result.ContainerPath = Volume.ContainerPath; + result.ReadOnly = Volume.ReadOnly; + return result; +} + +WSLCNamedVolume Convert(const WSLCCompatNamedVolume& Volume) +{ + WSLCNamedVolume result{}; + result.Name = Volume.Name; + result.ContainerPath = Volume.ContainerPath; + result.ReadOnly = Volume.ReadOnly; + return result; +} + +WSLCPortMapping Convert(const WSLCCompatPortMapping& Port) +{ + WSLCPortMapping result{}; + result.HostPort = Port.HostPort; + result.ContainerPort = Port.ContainerPort; + result.Family = Port.Family; + result.Protocol = Port.Protocol; + CopyString(result.BindingAddress, Port.BindingAddress); + return result; +} + +WSLCTmpfsMount Convert(const WSLCCompatTmpfsMount& Mount) +{ + WSLCTmpfsMount result{}; + result.Destination = Mount.Destination; + result.Options = Mount.Options; + return result; +} + +WSLCUlimit Convert(const WSLCCompatUlimit& Ulimit) +{ + WSLCUlimit result{}; + result.Name = Ulimit.Name; + result.Soft = Ulimit.Soft; + result.Hard = Ulimit.Hard; + return result; +} + +WSLCDeleteImageOptions Convert(const WSLCCompatDeleteImageOptions& Options) +{ + WSLCDeleteImageOptions result{}; + result.Image = Options.Image; + result.Flags = Options.Flags; + return result; +} + +WSLCTagImageOptions Convert(const WSLCCompatTagImageOptions& Options) +{ + WSLCTagImageOptions result{}; + result.Image = Options.Image; + result.Repo = Options.Repo; + result.Tag = Options.Tag; + return result; +} + +WSLCCompatImageInformation Convert(const WSLCImageInformation& Image) +{ + WSLCCompatImageInformation result{}; + CopyString(result.Image, Image.Image); + CopyString(result.Hash, Image.Hash); + CopyString(result.Digest, Image.Digest); + result.Size = Image.Size; + result.Created = Image.Created; + CopyString(result.ParentId, Image.ParentId); + return result; +} + +WSLCCompatDeletedImageInformation Convert(const WSLCDeletedImageInformation& Image) +{ + WSLCCompatDeletedImageInformation result{}; + CopyString(result.Image, Image.Image); + result.Type = Convert(Image.Type); + return result; +} + +WSLCCompatVolumeInformation Convert(const WSLCVolumeInformation& Volume) +{ + WSLCCompatVolumeInformation result{}; + CopyString(result.Name, Volume.Name); + CopyString(result.Driver, Volume.Driver); + return result; +} + +// +// Composite struct conversions. +// + +ContainerOptionsConversion::ContainerOptionsConversion(const WSLCCompatContainerOptions& Options) +{ + m_value.Image = Options.Image; + m_value.Name = Options.Name; + m_value.Entrypoint = Convert(Options.Entrypoint); + m_value.InitProcessOptions = Convert(Options.InitProcessOptions); + + m_volumes = ConvertArray(Options.Volumes, Options.VolumesCount); + m_value.Volumes = m_volumes.empty() ? nullptr : m_volumes.data(); + m_value.VolumesCount = Options.VolumesCount; + + m_ports = ConvertArray(Options.Ports, Options.PortsCount); + m_value.Ports = m_ports.empty() ? nullptr : m_ports.data(); + m_value.PortsCount = Options.PortsCount; + + m_labels = ConvertArray(Options.Labels, Options.LabelsCount); + m_value.Labels = m_labels.empty() ? nullptr : m_labels.data(); + m_value.LabelsCount = Options.LabelsCount; + + m_value.Flags = Convert(Options.Flags); + m_value.StopSignal = Convert(Options.StopSignal); + m_value.HostName = Options.HostName; + m_value.DomainName = Options.DomainName; + + m_value.DnsServers = Convert(Options.DnsServers); + m_value.DnsSearchDomains = Convert(Options.DnsSearchDomains); + m_value.DnsOptions = Convert(Options.DnsOptions); + + m_value.ShmSize = Options.ShmSize; + + // Container network (nested arrays whose elements have their own arrays). + m_value.ContainerNetwork.NetworkMode = Options.ContainerNetwork.NetworkMode; + const ULONG networksCount = Options.ContainerNetwork.NetworksCount; + m_networks.reserve(networksCount); + m_networkSettings.reserve(networksCount); + for (ULONG index = 0; index < networksCount; index++) + { + const auto& sourceConnection = Options.ContainerNetwork.Networks[index]; + m_networkSettings.push_back(ConvertArray(sourceConnection.Settings, sourceConnection.SettingsCount)); + + WSLCNetworkConnection connection{}; + connection.NetworkName = sourceConnection.NetworkName; + connection.Settings = m_networkSettings.back().empty() ? nullptr : m_networkSettings.back().data(); + connection.SettingsCount = sourceConnection.SettingsCount; + m_networks.push_back(connection); + } + + m_value.ContainerNetwork.Networks = m_networks.empty() ? nullptr : m_networks.data(); + m_value.ContainerNetwork.NetworksCount = networksCount; + + m_tmpfs = ConvertArray(Options.Tmpfs, Options.TmpfsCount); + m_value.Tmpfs = m_tmpfs.empty() ? nullptr : m_tmpfs.data(); + m_value.TmpfsCount = Options.TmpfsCount; + + m_namedVolumes = ConvertArray(Options.NamedVolumes, Options.NamedVolumesCount); + m_value.NamedVolumes = m_namedVolumes.empty() ? nullptr : m_namedVolumes.data(); + m_value.NamedVolumesCount = Options.NamedVolumesCount; + + m_value.MemoryBytes = Options.MemoryBytes; + m_value.NanoCpus = Options.NanoCpus; + + m_ulimits = ConvertArray(Options.Ulimits, Options.UlimitsCount); + m_value.Ulimits = m_ulimits.empty() ? nullptr : m_ulimits.data(); + m_value.UlimitsCount = Options.UlimitsCount; +} + +ListImagesOptionsConversion::ListImagesOptionsConversion(const WSLCCompatListImagesOptions& Options) +{ + // Flags is a DWORD bitmask with identical bit meanings in both contracts. + m_value.Flags = Options.Flags; + + m_filters = ConvertArray(Options.Filters, Options.FiltersCount); + m_value.Filters = m_filters.empty() ? nullptr : m_filters.data(); + m_value.FiltersCount = Options.FiltersCount; +} + +VolumeOptionsConversion::VolumeOptionsConversion(const WSLCCompatVolumeOptions& Options) +{ + m_value.Name = Options.Name; + m_value.Driver = Options.Driver; + + m_driverOpts = ConvertArray(Options.DriverOpts, Options.DriverOptsCount); + m_value.DriverOpts = m_driverOpts.empty() ? nullptr : m_driverOpts.data(); + m_value.DriverOptsCount = Options.DriverOptsCount; + + m_labels = ConvertArray(Options.Labels, Options.LabelsCount); + m_value.Labels = m_labels.empty() ? nullptr : m_labels.data(); + m_value.LabelsCount = Options.LabelsCount; +} + +SessionSettingsConversion::SessionSettingsConversion(const WSLCCompatSessionSettings& Settings) +{ + m_value.DisplayName = Settings.DisplayName; + m_value.StoragePath = Settings.StoragePath; + m_value.MaximumStorageSizeMb = Settings.MaximumStorageSizeMb; + m_value.CpuCount = Settings.CpuCount; + m_value.MemoryMb = Settings.MemoryMb; + m_value.BootTimeoutMs = Settings.BootTimeoutMs; + m_value.NetworkingMode = Convert(Settings.NetworkingMode); + + // The factory deep-copies (AddRefs) the termination callback synchronously + // during CreateSession, so the adapter held here outlives the call. + m_terminationCallback = Convert(Settings.TerminationCallback); + m_value.TerminationCallback = m_terminationCallback.Get(); + + m_value.FeatureFlags = Convert(Settings.FeatureFlags); + m_value.DmesgOutput = Convert(Settings.DmesgOutput); + m_value.StorageFlags = Convert(Settings.StorageFlags); + m_value.RootVhdOverride = Settings.RootVhdOverride; + m_value.RootVhdTypeOverride = Settings.RootVhdTypeOverride; +} + +// +// Callback conversions. +// + +Microsoft::WRL::ComPtr Convert(IWSLCCompatTerminationCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +Microsoft::WRL::ComPtr Convert(IWSLCCompatCrashDumpCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +Microsoft::WRL::ComPtr Convert(IWSLCCompatProgressCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +Microsoft::WRL::ComPtr Convert(IWSLCCompatWarningCallback* Callback) +{ + Microsoft::WRL::ComPtr result; + if (Callback != nullptr) + { + result = Microsoft::WRL::Make(Callback); + } + + return result; +} + +} // namespace wsl::windows::common::apicompat diff --git a/src/windows/common/APICompat.h b/src/windows/common/APICompat.h new file mode 100644 index 0000000000..39012db265 --- /dev/null +++ b/src/windows/common/APICompat.h @@ -0,0 +1,198 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. + +// +// Conversion helpers that bridge the SDK-facing WSLCCompat COM contract (declared +// in WSLCCompat.idl) and the internal wslc.idl contract. +// +// The two contracts are intentionally decoupled: WSLCCompat.idl must stay +// backwards compatible, while wslc.idl can change freely. Because of that, the +// two sets of types are never assumed to share the same layout. Every +// conversion below copies field by field instead of casting between the two +// representations. +// +// The service classes (WSLCSessionManager, WSLCSession, WSLCContainer, +// WSLCProcess) implement the IWSLCCompat* interfaces by converting the WSLCCompat +// types into the wslc.idl types with the overloaded Convert() functions here +// and then forwarding to the existing wslc.idl based implementations. +// + +#pragma once + +#include +#include +#include "wslc.h" +#include "WSLCCompat.h" + +namespace wsl::windows::common::apicompat { + +// +// Enum conversions. +// + +// Forward (WSLCCompat -> wslc.idl). +WSLCFD Convert(WSLCCompatFD Fd); +WSLCSignal Convert(WSLCCompatSignal Signal); +WSLCProcessFlags Convert(WSLCCompatProcessFlags Flags); +WSLCContainerFlags Convert(WSLCCompatContainerFlags Flags); +WSLCContainerStartFlags Convert(WSLCCompatContainerStartFlags Flags); +WSLCDeleteFlags Convert(WSLCCompatDeleteFlags Flags); +WSLCNetworkingMode Convert(WSLCCompatNetworkingMode Mode); +WSLCFeatureFlags Convert(WSLCCompatFeatureFlags Flags); +WSLCSessionStorageFlags Convert(WSLCCompatSessionStorageFlags Flags); +WSLCSessionFlags Convert(WSLCCompatSessionFlags Flags); +WSLCHandleType Convert(WSLCCompatHandleType Type); + +// Reverse (wslc.idl -> WSLCCompat). +WSLCCompatProcessState Convert(WSLCProcessState State); +WSLCCompatContainerState Convert(WSLCContainerState State); +WSLCCompatVirtualMachineTerminationReason Convert(WSLCVirtualMachineTerminationReason Reason); +WSLCCompatHandleType Convert(WSLCHandleType Type); +WSLCCompatDeletedImageType Convert(WSLCDeletedImageType Type); + +// +// Scalar / non-owning struct conversions. The returned struct copies any +// pointer fields straight from the input, so it stays valid only as long as the +// input (and the buffers it points at) remain alive. They are meant to be used +// for the duration of a single forwarded call. +// + +// Forward (WSLCCompat -> wslc.idl). +WSLCVersion Convert(const WSLCCompatVersion& Version); +WSLCHandle Convert(const WSLCCompatHandle& Handle); +WSLCStringArray Convert(const WSLCCompatStringArray& Array); +WSLCProcessOptions Convert(const WSLCCompatProcessOptions& Options); +KeyValuePair Convert(const WSLCCompatKeyValuePair& Pair); +WSLCVolume Convert(const WSLCCompatVolume& Volume); +WSLCNamedVolume Convert(const WSLCCompatNamedVolume& Volume); +WSLCPortMapping Convert(const WSLCCompatPortMapping& Port); +WSLCTmpfsMount Convert(const WSLCCompatTmpfsMount& Mount); +WSLCUlimit Convert(const WSLCCompatUlimit& Ulimit); +WSLCDeleteImageOptions Convert(const WSLCCompatDeleteImageOptions& Options); +WSLCTagImageOptions Convert(const WSLCCompatTagImageOptions& Options); + +// Reverse (wslc.idl -> WSLCCompat). +WSLCCompatVersion Convert(const WSLCVersion& Version); +WSLCCompatHandle Convert(const WSLCHandle& Handle); +WSLCCompatImageInformation Convert(const WSLCImageInformation& Image); +WSLCCompatDeletedImageInformation Convert(const WSLCDeletedImageInformation& Image); +WSLCCompatVolumeInformation Convert(const WSLCVolumeInformation& Volume); + +// +// Composite struct conversions. These contain nested arrays whose element types +// differ between the two contracts, so the converted struct owns backing +// storage that must outlive the forwarded call. Construct the conversion as a +// local and pass Get() to the wslc.idl method. +// + +class ContainerOptionsConversion +{ +public: + NON_COPYABLE(ContainerOptionsConversion); + DEFAULT_MOVABLE(ContainerOptionsConversion); + + explicit ContainerOptionsConversion(const WSLCCompatContainerOptions& Options); + + const WSLCContainerOptions* Get() const noexcept + { + return &m_value; + } + +private: + WSLCContainerOptions m_value{}; + std::vector m_volumes; + std::vector m_ports; + std::vector m_labels; + std::vector m_tmpfs; + std::vector m_namedVolumes; + std::vector m_ulimits; + std::vector m_networks; + std::vector> m_networkSettings; +}; + +class ListImagesOptionsConversion +{ +public: + NON_COPYABLE(ListImagesOptionsConversion); + DEFAULT_MOVABLE(ListImagesOptionsConversion); + + explicit ListImagesOptionsConversion(const WSLCCompatListImagesOptions& Options); + + const WSLCListImagesOptions* Get() const noexcept + { + return &m_value; + } + +private: + WSLCListImagesOptions m_value{}; + std::vector m_filters; +}; + +class VolumeOptionsConversion +{ +public: + NON_COPYABLE(VolumeOptionsConversion); + DEFAULT_MOVABLE(VolumeOptionsConversion); + + explicit VolumeOptionsConversion(const WSLCCompatVolumeOptions& Options); + + const WSLCVolumeOptions* Get() const noexcept + { + return &m_value; + } + +private: + WSLCVolumeOptions m_value{}; + std::vector m_driverOpts; + std::vector m_labels; +}; + +class SessionSettingsConversion +{ +public: + NON_COPYABLE(SessionSettingsConversion); + DEFAULT_MOVABLE(SessionSettingsConversion); + + explicit SessionSettingsConversion(const WSLCCompatSessionSettings& Settings); + + const WSLCSessionSettings* Get() const noexcept + { + return &m_value; + } + +private: + WSLCSessionSettings m_value{}; + Microsoft::WRL::ComPtr m_terminationCallback; +}; + +inline ContainerOptionsConversion Convert(const WSLCCompatContainerOptions& Options) +{ + return ContainerOptionsConversion(Options); +} + +inline ListImagesOptionsConversion Convert(const WSLCCompatListImagesOptions& Options) +{ + return ListImagesOptionsConversion(Options); +} + +inline VolumeOptionsConversion Convert(const WSLCCompatVolumeOptions& Options) +{ + return VolumeOptionsConversion(Options); +} + +inline SessionSettingsConversion Convert(const WSLCCompatSessionSettings& Settings) +{ + return SessionSettingsConversion(Settings); +} + +// +// Callback conversions. Wrap the SDK callback object in an in-process adapter +// that implements the matching wslc.idl callback interface, or return a null +// ComPtr when the SDK callback is null. +// + +Microsoft::WRL::ComPtr Convert(IWSLCCompatTerminationCallback* Callback); +Microsoft::WRL::ComPtr Convert(IWSLCCompatCrashDumpCallback* Callback); +Microsoft::WRL::ComPtr Convert(IWSLCCompatProgressCallback* Callback); +Microsoft::WRL::ComPtr Convert(IWSLCCompatWarningCallback* Callback); + +} // namespace wsl::windows::common::apicompat diff --git a/src/windows/common/CMakeLists.txt b/src/windows/common/CMakeLists.txt index fafd201352..e5a5ca5207 100644 --- a/src/windows/common/CMakeLists.txt +++ b/src/windows/common/CMakeLists.txt @@ -1,4 +1,5 @@ set(SOURCES + APICompat.cpp ConsoleProgressBar.cpp ConsoleProgressIndicator.cpp ConsoleState.cpp @@ -57,6 +58,7 @@ set(SOURCES set(HEADERS ../../../generated/Localization.h + APICompat.h ../inc/docker_schema.h ../inc/wslc_schema.h ../inc/lxssbusclient.h diff --git a/src/windows/common/WSLCSDKCallbackAdapters.h b/src/windows/common/WSLCSDKCallbackAdapters.h deleted file mode 100644 index 6b6342ee8e..0000000000 --- a/src/windows/common/WSLCSDKCallbackAdapters.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (C) Microsoft Corporation. All rights reserved. - -// -// Adapters that bridge the SDK-facing WSLCSDK callback interfaces (declared in -// WSLSDK.idl) to the internal wslc.idl callback interfaces. The service classes -// implement the IWSLCSDK* interfaces by converting the SDK callback objects into -// these adapters and forwarding to the existing wslc.idl based implementations. -// -// The adapters are only ever invoked in-process (they wrap the SDK's marshaled -// proxy), so they do not need to be registered for marshaling. -// - -#pragma once - -#include "wslc.h" -#include "WSLSDK.h" -#include - -namespace wsl::windows::common::wslcsdk { - -class TerminationCallbackAdapter - : public Microsoft::WRL::RuntimeClass, ITerminationCallback> -{ -public: - TerminationCallbackAdapter(IWSLCSDKTerminationCallback* Inner) : m_inner(Inner) - { - } - - IFACEMETHOD(OnTermination)(WSLCVirtualMachineTerminationReason Reason, LPCWSTR Details) override - { - return m_inner->OnTermination(static_cast(Reason), Details); - } - -private: - Microsoft::WRL::ComPtr m_inner; -}; - -class CrashDumpCallbackAdapter - : public Microsoft::WRL::RuntimeClass, ICrashDumpCallback> -{ -public: - CrashDumpCallbackAdapter(IWSLCSDKCrashDumpCallback* Inner) : m_inner(Inner) - { - } - - IFACEMETHOD(OnCrashDump)(LPCWSTR DumpPath, LPCSTR ProcessName, ULONGLONG Pid, ULONG Signal, ULONGLONG Timestamp) override - { - return m_inner->OnCrashDump(DumpPath, ProcessName, Pid, Signal, Timestamp); - } - -private: - Microsoft::WRL::ComPtr m_inner; -}; - -class ProgressCallbackAdapter - : public Microsoft::WRL::RuntimeClass, IProgressCallback> -{ -public: - ProgressCallbackAdapter(IWSLCSDKProgressCallback* Inner) : m_inner(Inner) - { - } - - IFACEMETHOD(OnProgress)(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total) override - { - return m_inner->OnProgress(Status, Id, Current, Total); - } - -private: - Microsoft::WRL::ComPtr m_inner; -}; - -class WarningCallbackAdapter - : public Microsoft::WRL::RuntimeClass, IWarningCallback> -{ -public: - WarningCallbackAdapter(IWSLCSDKWarningCallback* Inner) : m_inner(Inner) - { - } - - IFACEMETHOD(OnWarning)(LPCWSTR Message) override - { - return m_inner->OnWarning(Message); - } - -private: - Microsoft::WRL::ComPtr m_inner; -}; - -// Helpers that return a wslc.idl callback wrapping the given SDK callback, or -// nullptr when the SDK callback is null. - -inline Microsoft::WRL::ComPtr WrapTerminationCallback(IWSLCSDKTerminationCallback* Callback) -{ - Microsoft::WRL::ComPtr result; - if (Callback != nullptr) - { - result = Microsoft::WRL::Make(Callback); - } - - return result; -} - -inline Microsoft::WRL::ComPtr WrapCrashDumpCallback(IWSLCSDKCrashDumpCallback* Callback) -{ - Microsoft::WRL::ComPtr result; - if (Callback != nullptr) - { - result = Microsoft::WRL::Make(Callback); - } - - return result; -} - -inline Microsoft::WRL::ComPtr WrapProgressCallback(IWSLCSDKProgressCallback* Callback) -{ - Microsoft::WRL::ComPtr result; - if (Callback != nullptr) - { - result = Microsoft::WRL::Make(Callback); - } - - return result; -} - -inline Microsoft::WRL::ComPtr WrapWarningCallback(IWSLCSDKWarningCallback* Callback) -{ - Microsoft::WRL::ComPtr result; - if (Callback != nullptr) - { - result = Microsoft::WRL::Make(Callback); - } - - return result; -} - -} // namespace wsl::windows::common::wslcsdk diff --git a/src/windows/service/exe/WSLCSessionManager.cpp b/src/windows/service/exe/WSLCSessionManager.cpp index fbad8e843d..31dfddee44 100644 --- a/src/windows/service/exe/WSLCSessionManager.cpp +++ b/src/windows/service/exe/WSLCSessionManager.cpp @@ -37,7 +37,7 @@ Module Name: #include "helpers.hpp" #include "wslutil.h" #include "filesystem.hpp" -#include "WSLCSDKCallbackAdapters.h" +#include "APICompat.h" extern wsl::windows::service::PluginManager g_pluginManager; @@ -48,6 +48,7 @@ using wsl::windows::service::wslc::WSLCPluginNotifier; using wsl::windows::service::wslc::WSLCSessionManagerImpl; using wsl::windows::service::wslc::WSLCVirtualMachineFactory; namespace wslutil = wsl::windows::common::wslutil; +namespace apicompat = wsl::windows::common::apicompat; namespace settings = wsl::windows::wslc::settings; namespace { @@ -285,8 +286,9 @@ void WSLCSessionManagerImpl::CreateSession( THROW_IF_FAILED(factory->CreateSession(&sessionSettings, vmFactory.Get(), notifier.Get(), WarningCallback, &session, &serviceRef)); // Track the session via its service ref, along with metadata and security info. - m_sessions.push_back(SessionEntry{ - std::move(serviceRef), sessionId, creatorPid, resolvedDisplayName, std::move(tokenInfo), notifier, false, sharedToken, std::move(storedSid), std::move(sessionJob)}); + m_sessions.push_back( + SessionEntry{ + std::move(serviceRef), sessionId, creatorPid, resolvedDisplayName, std::move(tokenInfo), notifier, false, sharedToken, std::move(storedSid), std::move(sessionJob)}); // For persistent sessions, also hold a strong reference to keep them alive. const bool persistent = WI_IsFlagSet(Flags, WSLCSessionFlagsPersistent); @@ -602,60 +604,49 @@ HRESULT WSLCSessionManager::OpenSessionByName(_In_ LPCWSTR DisplayName, _Out_ IW return CallImpl(&WSLCSessionManagerImpl::OpenSessionByName, DisplayName, Session); } -HRESULT WSLCSessionManager::GetVersion(_Out_ WSLCSDKVersion* Version) +HRESULT WSLCSessionManager::GetVersion(_Out_ WSLCCompatVersion* Version) +try { - static_assert(sizeof(WSLCSDKVersion) == sizeof(WSLCVersion), "WSLCSDKVersion and WSLCVersion layout mismatch"); + RETURN_HR_IF_NULL(E_POINTER, Version); + + WSLCVersion version{}; + RETURN_IF_FAILED(GetVersion(&version)); - return GetVersion(reinterpret_cast(Version)); + *Version = apicompat::Convert(version); + return S_OK; } +CATCH_RETURN(); -HRESULT WSLCSessionManager::IsClientVersionSupported(_In_ const WSLCSDKVersion* ClientVersion, _Out_ BOOL* IsSupported) +HRESULT WSLCSessionManager::IsClientVersionSupported(_In_ const WSLCCompatVersion* ClientVersion, _Out_ BOOL* IsSupported) +try { - static_assert(sizeof(WSLCSDKVersion) == sizeof(WSLCVersion), "WSLCSDKVersion and WSLCVersion layout mismatch"); + RETURN_HR_IF_NULL(E_POINTER, ClientVersion); - return IsClientVersionSupported(reinterpret_cast(ClientVersion), IsSupported); + const auto clientVersion = apicompat::Convert(*ClientVersion); + return IsClientVersionSupported(&clientVersion, IsSupported); } +CATCH_RETURN(); HRESULT WSLCSessionManager::CreateSession( - const WSLCSDKSessionSettings* Settings, WSLCSDKSessionFlags Flags, IWSLCSDKWarningCallback* WarningCallback, IWSLCSDKSession** Session) + const WSLCCompatSessionSettings* Settings, WSLCCompatSessionFlags Flags, IWSLCCompatWarningCallback* WarningCallback, IWSLCCompatSession** Session) try { RETURN_HR_IF_NULL(E_POINTER, Session); *Session = nullptr; - const auto warning = wsl::windows::common::wslcsdk::WrapWarningCallback(WarningCallback); + const auto warning = apicompat::Convert(WarningCallback); Microsoft::WRL::ComPtr session; if (Settings == nullptr) { - RETURN_IF_FAILED(CreateSession(static_cast(nullptr), static_cast(Flags), warning.Get(), &session)); + RETURN_IF_FAILED(CreateSession(static_cast(nullptr), apicompat::Convert(Flags), warning.Get(), &session)); } else { - static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); - - // The TerminationCallback pointer type differs between the two settings structs, so the - // struct can't be reinterpret_cast as a whole. Field-copy it and wrap the callback. The - // factory deep-copies (AddRefs) the termination callback synchronously during CreateSession, - // so the locally-held adapter outlives the call. - const auto termination = wsl::windows::common::wslcsdk::WrapTerminationCallback(Settings->TerminationCallback); - - WSLCSessionSettings settings{}; - settings.DisplayName = Settings->DisplayName; - settings.StoragePath = Settings->StoragePath; - settings.MaximumStorageSizeMb = Settings->MaximumStorageSizeMb; - settings.CpuCount = Settings->CpuCount; - settings.MemoryMb = Settings->MemoryMb; - settings.BootTimeoutMs = Settings->BootTimeoutMs; - settings.NetworkingMode = static_cast(Settings->NetworkingMode); - settings.TerminationCallback = termination.Get(); - settings.FeatureFlags = static_cast(Settings->FeatureFlags); - memcpy(&settings.DmesgOutput, &Settings->DmesgOutput, sizeof(settings.DmesgOutput)); - settings.StorageFlags = static_cast(Settings->StorageFlags); - settings.RootVhdOverride = Settings->RootVhdOverride; - settings.RootVhdTypeOverride = Settings->RootVhdTypeOverride; - - RETURN_IF_FAILED(CreateSession(&settings, static_cast(Flags), warning.Get(), &session)); + // The conversion holds the wrapped termination callback so it outlives the call. The factory + // deep-copies (AddRefs) the termination callback synchronously during CreateSession. + const auto settings = apicompat::Convert(*Settings); + RETURN_IF_FAILED(CreateSession(settings.Get(), apicompat::Convert(Flags), warning.Get(), &session)); } RETURN_HR_IF_NULL(E_UNEXPECTED, session); diff --git a/src/windows/service/exe/WSLCSessionManager.h b/src/windows/service/exe/WSLCSessionManager.h index 4749baae3e..ecb049999f 100644 --- a/src/windows/service/exe/WSLCSessionManager.h +++ b/src/windows/service/exe/WSLCSessionManager.h @@ -32,7 +32,7 @@ Module Name: #pragma once #include "wslc.h" -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "COMImplClass.h" #include "wslutil.h" #include @@ -188,7 +188,7 @@ class WSLCSessionManagerImpl } // namespace wsl::windows::service::wslc class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce8f") WSLCSessionManager - : public Microsoft::WRL::RuntimeClass, IWSLCSessionManager, IWSLCSDKSessionManager, IFastRundown>, + : public Microsoft::WRL::RuntimeClass, IWSLCSessionManager, IWSLCCompatSessionManager, IFastRundown>, public wsl::windows::service::wslc::COMImplClass { public: @@ -206,9 +206,12 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce8f") WSLCSessionManager IFACEMETHOD(OpenSession)(_In_ ULONG Id, _Out_ IWSLCSession** Session) override; IFACEMETHOD(OpenSessionByName)(_In_ LPCWSTR DisplayName, _Out_ IWSLCSession** Session) override; - // IWSLCSDKSessionManager - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. - IFACEMETHOD(GetVersion)(_Out_ WSLCSDKVersion* Version) override; - IFACEMETHOD(IsClientVersionSupported)(_In_ const WSLCSDKVersion* ClientVersion, _Out_ BOOL* IsSupported) override; + // IWSLCCompatSessionManager - converts the WSLCCompat types to the wslc.idl types and forwards to the methods above. + IFACEMETHOD(GetVersion)(_Out_ WSLCCompatVersion* Version) override; + IFACEMETHOD(IsClientVersionSupported)(_In_ const WSLCCompatVersion* ClientVersion, _Out_ BOOL* IsSupported) override; IFACEMETHOD(CreateSession)( - const WSLCSDKSessionSettings* Settings, WSLCSDKSessionFlags Flags, IWSLCSDKWarningCallback* WarningCallback, IWSLCSDKSession** Session) override; + const WSLCCompatSessionSettings* Settings, + WSLCCompatSessionFlags Flags, + IWSLCCompatWarningCallback* WarningCallback, + IWSLCCompatSession** Session) override; }; diff --git a/src/windows/service/inc/CMakeLists.txt b/src/windows/service/inc/CMakeLists.txt index efe717c550..6a552cf06d 100644 --- a/src/windows/service/inc/CMakeLists.txt +++ b/src/windows/service/inc/CMakeLists.txt @@ -1,3 +1,3 @@ -add_idl(wslserviceidl "wslservice.idl;wslc.idl;WSLSDK.idl" "windowsdefs.idl") +add_idl(wslserviceidl "wslservice.idl;wslc.idl;WSLCCompat.idl" "windowsdefs.idl") set_target_properties(wslserviceidl PROPERTIES FOLDER windows) diff --git a/src/windows/service/inc/WSLCCompat.idl b/src/windows/service/inc/WSLCCompat.idl new file mode 100644 index 0000000000..d9937e5b6d --- /dev/null +++ b/src/windows/service/inc/WSLCCompat.idl @@ -0,0 +1,539 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + WSLCCompat.idl + +Abstract: + + This file contains the WSLC SDK-facing COM object definitions. + Changes in this file must maintain backwards compatibility + +--*/ + +import "unknwn.idl"; +import "wtypes.idl"; + +cpp_quote("#ifdef __cplusplus") +cpp_quote("#ifndef WSLC_SESSIONMANAGER_COCLASS_DECLARED") +cpp_quote("#define WSLC_SESSIONMANAGER_COCLASS_DECLARED") +cpp_quote("class DECLSPEC_UUID(\"a9b7a1b9-0671-405c-95f1-e0612cb4ce8f\") WSLCSessionManager;") +cpp_quote("#endif") +cpp_quote("#endif") + +#define WSLCCompat_MAX_IMAGE_NAME_LENGTH 255 +#define WSLCCompat_MAX_VOLUME_NAME_LENGTH 255 +#define WSLCCompat_MAX_VOLUME_DRIVER_LENGTH 255 +#define WSLCCompat_CONTAINER_ID_LENGTH 64 +#define WSLCCompat_MAX_BINDING_ADDRESS_LENGTH 45 + +typedef +struct _WSLCCompatVersion { + ULONG Major; + ULONG Minor; + ULONG Revision; +} WSLCCompatVersion; + +typedef enum _WSLCCompatVirtualMachineTerminationReason +{ + WSLCCompatVirtualMachineTerminationReasonUnknown, + WSLCCompatVirtualMachineTerminationReasonShutdown, + WSLCCompatVirtualMachineTerminationReasonCrashed, +} WSLCCompatVirtualMachineTerminationReason; + +typedef enum _WSLCCompatFD +{ + WSLCCompatFDStdin = 0, + WSLCCompatFDStdout = 1, + WSLCCompatFDStderr = 2, + WSLCCompatFDTty = 3, +} WSLCCompatFD; + +typedef enum _WSLCCompatSignal +{ + WSLCCompatSignalNone = 0, + WSLCCompatSignalSIGHUP = 1, + WSLCCompatSignalSIGINT = 2, + WSLCCompatSignalSIGQUIT = 3, + WSLCCompatSignalSIGILL = 4, + WSLCCompatSignalSIGTRAP = 5, + WSLCCompatSignalSIGABRT = 6, + WSLCCompatSignalSIGIOT = 6, // SIGABRT and SIGIOT are equivalent. + WSLCCompatSignalSIGBUS = 7, + WSLCCompatSignalSIGFPE = 8, + WSLCCompatSignalSIGKILL = 9, + WSLCCompatSignalSIGUSR1 = 10, + WSLCCompatSignalSIGSEGV = 11, + WSLCCompatSignalSIGUSR2 = 12, + WSLCCompatSignalSIGPIPE = 13, + WSLCCompatSignalSIGALRM = 14, + WSLCCompatSignalSIGTERM = 15, + WSLCCompatSignalSIGTKFLT = 16, + WSLCCompatSignalSIGCHLD = 17, + WSLCCompatSignalSIGCONT = 18, + WSLCCompatSignalSIGSTOP = 19, + WSLCCompatSignalSIGTSTP = 20, + WSLCCompatSignalSIGTTIN = 21, + WSLCCompatSignalSIGTTOU = 22, + WSLCCompatSignalSIGURG = 23, + WSLCCompatSignalSIGXCPU = 24, + WSLCCompatSignalSIGXFSZ = 25, + WSLCCompatSignalSIGVTALRM = 26, + WSLCCompatSignalSIGPROF = 27, + WSLCCompatSignalSIGWINCH = 28, + WSLCCompatSignalSIGIO = 29, + WSLCCompatSignalSIGPOLL = 29, // SIGIO and SIGPOLL are equivalent. + WSLCCompatSignalSIGPWR = 30, + WSLCCompatSignalSIGSYS = 31 +} WSLCCompatSignal; + +[ + uuid(86A807EA-F2A1-4382-93E5-09FB5F2F4A31), + pointer_default(unique), + object +] +interface IWSLCCompatTerminationCallback : IUnknown +{ + HRESULT OnTermination(WSLCCompatVirtualMachineTerminationReason Reason, LPCWSTR Details); +}; + +[ + uuid(EAA15E20-7FCC-485B-B798-ED4095DBACA5), + pointer_default(unique), + object +] +interface IWSLCCompatCrashDumpCallback : IUnknown +{ + HRESULT OnCrashDump( + [in, string] LPCWSTR DumpPath, + [in, unique, string] LPCSTR ProcessName, + [in] ULONGLONG Pid, + [in] ULONG Signal, + [in] ULONGLONG Timestamp); +}; + +[ + uuid(06154F2A-ACA7-461E-94FC-92781BA1F6F6), + pointer_default(unique), + object +] +interface IWSLCCompatProgressCallback : IUnknown +{ + HRESULT OnProgress(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total); +}; + +[ + uuid(290C58A1-328C-4E90-B09B-0A9D32C40074), + pointer_default(unique), + object +] +interface IWSLCCompatWarningCallback : IUnknown +{ + HRESULT OnWarning([in, string] LPCWSTR Message); +}; + +typedef struct _WSLCCompatImageInformation +{ + char Image[WSLCCompat_MAX_IMAGE_NAME_LENGTH + 1]; + char Hash[256]; + char Digest[256]; + LONGLONG Size; // Matches Docker's int64 image size + LONGLONG Created; // Unix timestamp + char ParentId[256]; +} WSLCCompatImageInformation; + +typedef enum _WSLCCompatListImagesFlags +{ + WSLCCompatListImagesFlagsNone = 0, + WSLCCompatListImagesFlagsAll = 1, // Show all images (default hides intermediate images) + WSLCCompatListImagesFlagsDigests = 2, // Include digest information +} WSLCCompatListImagesFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatListImagesFlags);") + +typedef struct _WSLCCompatKeyValuePair +{ + [string] LPCSTR Key; + [string] LPCSTR Value; +} WSLCCompatKeyValuePair; + +typedef WSLCCompatKeyValuePair WSLCCompatLabel; +typedef WSLCCompatKeyValuePair WSLCCompatDriverOption; +typedef WSLCCompatKeyValuePair WSLCCompatFilter; + +typedef struct _WSLCCompatListImagesOptions +{ + DWORD Flags; // WSLCCompatListImagesFlags (can combine with bitwise OR) + [unique, size_is(FiltersCount)] const WSLCCompatFilter* Filters; + ULONG FiltersCount; +} WSLCCompatListImagesOptions; + +typedef enum _WSLCCompatProcessFlags +{ + WSLCCompatProcessFlagsNone = 0, + WSLCCompatProcessFlagsStdin = 1, + WSLCCompatProcessFlagsTty = 2 +} WSLCCompatProcessFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatProcessFlags);") + +typedef struct _WSLCCompatStringArray +{ + [unique, size_is(Count)] LPCSTR const* Values; + ULONG Count; +} WSLCCompatStringArray; + +typedef struct _WSLCCompatProcessOptions +{ + [unique] LPCSTR CurrentDirectory; + [unique] LPCSTR User; + WSLCCompatStringArray CommandLine; + WSLCCompatStringArray Environment; + WSLCCompatProcessFlags Flags; +} WSLCCompatProcessOptions; + +typedef struct _WSLCCompatNamedVolume +{ + LPCSTR Name; + LPCSTR ContainerPath; + BOOL ReadOnly; +} WSLCCompatNamedVolume; + +typedef struct _WSLCCompatVolume +{ + LPCWSTR HostPath; + LPCSTR ContainerPath; + BOOL ReadOnly; +} WSLCCompatVolume; + +typedef struct _WSLCCompatPortMapping +{ + USHORT HostPort; + USHORT ContainerPort; + int Family; + int Protocol; + char BindingAddress[WSLCCompat_MAX_BINDING_ADDRESS_LENGTH + 1]; +} WSLCCompatPortMapping; + +typedef struct _WSLCCompatTmpfsMount +{ + LPCSTR Destination; + [unique] LPCSTR Options; +} WSLCCompatTmpfsMount; + +typedef struct _WSLCCompatUlimit +{ + [string] LPCSTR Name; + LONGLONG Soft; + LONGLONG Hard; +} WSLCCompatUlimit; + +typedef struct _WSLCCompatNetworkConnection +{ + [string] LPCSTR NetworkName; + [unique, size_is(SettingsCount)] const WSLCCompatKeyValuePair* Settings; + ULONG SettingsCount; +} WSLCCompatNetworkConnection; + +typedef struct _WSLCCompatContainerNetwork +{ + [unique, string] LPCSTR NetworkMode; + + [unique, size_is(NetworksCount)] const WSLCCompatNetworkConnection* Networks; + ULONG NetworksCount; +} WSLCCompatContainerNetwork; + +typedef enum _WSLCCompatContainerFlags +{ + WSLCCompatContainerFlagsNone = 0, + WSLCCompatContainerFlagsRm = 1, // Delete the container when it exits. + WSLCCompatContainerFlagsGpu = 2, // Enable GPU access. + WSLCCompatContainerFlagsInit = 4, // Run the container under an init process. + WSLCCompatContainerFlagsPublishAll = 8, // Publish all exposed ports. +} WSLCCompatContainerFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatContainerFlags);") + +typedef enum _WSLCCompatContainerStartFlags +{ + WSLCCompatContainerStartFlagsNone = 0, + WSLCCompatContainerStartFlagsAttach = 1, // Attach stdio handles on start. +} WSLCCompatContainerStartFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatContainerStartFlags);") + +typedef struct _WSLCCompatContainerOptions +{ + LPCSTR Image; + [unique] LPCSTR Name; + WSLCCompatStringArray Entrypoint; + WSLCCompatProcessOptions InitProcessOptions; + [unique, size_is(VolumesCount)] WSLCCompatVolume* Volumes; + ULONG VolumesCount; + [unique, size_is(PortsCount)] WSLCCompatPortMapping* Ports; + ULONG PortsCount; + [unique, size_is(LabelsCount)] const WSLCCompatLabel* Labels; + ULONG LabelsCount; + WSLCCompatContainerFlags Flags; + WSLCCompatSignal StopSignal; + [unique] LPCSTR HostName; + [unique] LPCSTR DomainName; + + WSLCCompatStringArray DnsServers; + WSLCCompatStringArray DnsSearchDomains; + WSLCCompatStringArray DnsOptions; + + LONGLONG ShmSize; + WSLCCompatContainerNetwork ContainerNetwork; + [unique, size_is(TmpfsCount)] const WSLCCompatTmpfsMount* Tmpfs; + ULONG TmpfsCount; + + [unique, size_is(NamedVolumesCount)] WSLCCompatNamedVolume* NamedVolumes; + ULONG NamedVolumesCount; + + LONGLONG MemoryBytes; + LONGLONG NanoCpus; + [unique, size_is(UlimitsCount)] const WSLCCompatUlimit* Ulimits; + ULONG UlimitsCount; +} WSLCCompatContainerOptions; + +typedef enum _WSLCCompatContainerState +{ + WSLCCompatContainerStateInvalid = 0, + WSLCCompatContainerStateCreated = 1, + WSLCCompatContainerStateRunning = 2, + WSLCCompatContainerStateExited = 3, + WSLCCompatContainerStateDeleted = 4, +} WSLCCompatContainerState; + +typedef char WSLCCompatContainerId[WSLCCompat_CONTAINER_ID_LENGTH + 1]; + +typedef [system_handle(sh_file)] HANDLE WSLCCompatFileHandle; +typedef [system_handle(sh_pipe)] HANDLE WSLCCompatPipeHandle; +typedef [system_handle(sh_socket)] HANDLE WSLCCompatSocketHandle; + +typedef enum _WSLCCompatHandleType +{ + WSLCCompatHandleTypeUnknown = 0, + WSLCCompatHandleTypeFile = 1, + WSLCCompatHandleTypePipe = 2, + WSLCCompatHandleTypeSocket = 3 +} WSLCCompatHandleType; + +typedef struct _WSLCCompatHandle +{ + WSLCCompatHandleType Type; + + [switch_type(WSLCCompatHandleType), switch_is(Type)] + union + { + [case(WSLCCompatHandleTypeFile)] + WSLCCompatFileHandle File; + [case(WSLCCompatHandleTypePipe)] + WSLCCompatPipeHandle Pipe; + [case(WSLCCompatHandleTypeSocket)] + WSLCCompatSocketHandle Socket; + [default]; + } Handle; +} WSLCCompatHandle; + +typedef enum _WSLCCompatProcessState +{ + WSLCCompatProcessStateUnknown = 0, + WSLCCompatProcessStateRunning = 1, + WSLCCompatProcessStateExited = 2, + WSLCCompatProcessStateSignalled = 3 +} WSLCCompatProcessState; + +[ + uuid(AC69DD0D-6616-4C4F-91F2-C39D6034EA82), + pointer_default(unique), + object +] +interface IWSLCCompatProcess : IUnknown +{ + HRESULT Signal([in] int Signal); + HRESULT GetExitEvent([out, system_handle(sh_event)] HANDLE* EventHandle); + HRESULT GetStdHandle([in] WSLCCompatFD Fd, [out] WSLCCompatHandle* Handle); + HRESULT GetPid([out] int* Pid); + HRESULT GetState([out] WSLCCompatProcessState* State, [out] int* Code); +} + +typedef enum _WSLCCompatNetworkingMode +{ + WSLCCompatNetworkingModeNone, + WSLCCompatNetworkingModeNAT, + WSLCCompatNetworkingModeVirtioProxy +} WSLCCompatNetworkingMode; + +typedef enum _WSLCCompatFeatureFlags +{ + WSLCCompatFeatureFlagsNone = 0, + WSLCCompatFeatureFlagsDnsTunneling = 1, + WSLCCompatFeatureFlagsEarlyBootDmesg = 2, + WSLCCompatFeatureFlagsGPU = 4, + WSLCCompatFeatureFlagsVirtioFs = 8, + WSLCCompatFeatureFlagsDebug = 16, +} WSLCCompatFeatureFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatFeatureFlags);") + +typedef enum _WSLCCompatSessionStorageFlags +{ + WSLCCompatSessionStorageFlagsNone = 0, + WSLCCompatSessionStorageFlagsNoCreate = 1, // Open an existing storage path, but don't create a new one. +} WSLCCompatSessionStorageFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatSessionStorageFlags);") + +typedef struct _WSLCCompatSessionSettings { + LPCWSTR DisplayName; + LPCWSTR StoragePath; + ULONGLONG MaximumStorageSizeMb; + ULONG CpuCount; + ULONG MemoryMb; + ULONG BootTimeoutMs; + WSLCCompatNetworkingMode NetworkingMode; + [unique] IWSLCCompatTerminationCallback* TerminationCallback; + WSLCCompatFeatureFlags FeatureFlags; + WSLCCompatHandle DmesgOutput; + WSLCCompatSessionStorageFlags StorageFlags; + + // Below options are used for debugging purposes only. + [unique] LPCWSTR RootVhdOverride; + [unique] LPCSTR RootVhdTypeOverride; +} WSLCCompatSessionSettings; + +typedef enum _WSLCCompatDeleteFlags +{ + WSLCCompatDeleteFlagsNone = 0, + WSLCCompatDeleteFlagsForce = 1, + WSLCCompatDeleteFlagsDeleteVolumes = 2, +} WSLCCompatDeleteFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatDeleteFlags);") + +[ + uuid(8C3C91FA-D550-41B9-AD9D-23DCBF96F549), + pointer_default(unique), + object +] +interface IWSLCCompatContainer : IUnknown +{ + HRESULT Stop([in] WSLCCompatSignal Signal, [in] LONG TimeoutSeconds); + HRESULT Start([in] WSLCCompatContainerStartFlags Flags); + HRESULT Delete([in] WSLCCompatDeleteFlags Flags); + HRESULT GetState([out] WSLCCompatContainerState* State); + HRESULT GetInitProcess([out] IWSLCCompatProcess** Process); + HRESULT Exec([in, ref] const WSLCCompatProcessOptions* Options, [out] IWSLCCompatProcess** Process); + HRESULT Inspect([out] LPSTR* Output); + HRESULT GetId([out, string] WSLCCompatContainerId Id); +} + +typedef enum _WSLCCompatDeletedImageType +{ + WSLCCompatDeletedImageTypeDeleted = 0, + WSLCCompatDeletedImageTypeUntagged = 1 +} WSLCCompatDeletedImageType; + +typedef struct _WSLCCompatDeletedImageInformation +{ + char Image[WSLCCompat_MAX_IMAGE_NAME_LENGTH + 1]; + WSLCCompatDeletedImageType Type; +} WSLCCompatDeletedImageInformation; + +typedef enum _WSLCCompatDeleteImageFlags +{ + WSLCCompatDeleteImageFlagsNone = 0, + WSLCCompatDeleteImageFlagsForce = 1, + WSLCCompatDeleteImageFlagsNoPrune = 2, +} WSLCCompatDeleteImageFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatDeleteImageFlags);") + +typedef struct _WSLCCompatDeleteImageOptions +{ + LPCSTR Image; // Image can be ID or Repo:Tag. + DWORD Flags; // WSLCCompatDeleteImageFlags +} WSLCCompatDeleteImageOptions; + +typedef struct _WSLCCompatTagImageOptions +{ + LPCSTR Image; // Source image name or ID. + LPCSTR Repo; // Target repository name. + LPCSTR Tag; // Target tag name. +} WSLCCompatTagImageOptions; + +typedef struct _WSLCCompatVolumeOptions +{ + [unique] LPCSTR Name; + [unique] LPCSTR Driver; + [unique, size_is(DriverOptsCount)] const WSLCCompatDriverOption* DriverOpts; + ULONG DriverOptsCount; + [unique, size_is(LabelsCount)] const WSLCCompatLabel* Labels; + ULONG LabelsCount; +} WSLCCompatVolumeOptions; + +typedef char WSLCCompatVolumeName[WSLCCompat_MAX_VOLUME_NAME_LENGTH + 1]; + +typedef struct _WSLCCompatVolumeInformation +{ + WSLCCompatVolumeName Name; + char Driver[WSLCCompat_MAX_VOLUME_DRIVER_LENGTH + 1]; +} WSLCCompatVolumeInformation; + +[ + uuid(DD7B2EF9-AA01-4F21-8A3A-29D394CBB579), + pointer_default(unique), + object +] +interface IWSLCCompatSession : IUnknown +{ + // Image management. + HRESULT PullImage([in] LPCSTR Image, [in, unique] LPCSTR RegistryAuthenticationInformation, [in, unique] IWSLCCompatProgressCallback* ProgressCallback, [in, unique] IWSLCCompatWarningCallback* WarningCallback); + HRESULT LoadImage([in] WSLCCompatHandle ImageHandle, [in, unique] IWSLCCompatProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength, [in, unique] IWSLCCompatWarningCallback* WarningCallback); + HRESULT ImportImage([in] WSLCCompatHandle ImageHandle, [in] LPCSTR ImageName, [in, unique] IWSLCCompatProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength, [in, unique] IWSLCCompatWarningCallback* WarningCallback); + HRESULT ListImages([in, unique] const WSLCCompatListImagesOptions* Options, [out, size_is(, *Count)] WSLCCompatImageInformation** Images, [out] ULONG* Count); + HRESULT DeleteImage([in] const WSLCCompatDeleteImageOptions* Options, [out, size_is(, *Count)] WSLCCompatDeletedImageInformation** DeletedImages, [out] ULONG* Count); + HRESULT TagImage([in] const WSLCCompatTagImageOptions* Options); + + // Container management. + HRESULT CreateContainer([in] const WSLCCompatContainerOptions* Options, [in, unique] IWSLCCompatWarningCallback* WarningCallback, [out] IWSLCCompatContainer** Container); + + // Terminate the VM and containers. + HRESULT Terminate(); + + // Volume management. + HRESULT CreateVolume([in] const WSLCCompatVolumeOptions* Options, [out] WSLCCompatVolumeInformation* VolumeInfo); + HRESULT DeleteVolume([in] LPCSTR Name); + + HRESULT Authenticate([in] LPCSTR ServerAddress, [in] LPCSTR Username, [in] LPCSTR Password, [out] LPSTR* IdentityToken); + HRESULT PushImage([in] LPCSTR Image, [in] LPCSTR RegistryAuthenticationInformation, [in, unique] IWSLCCompatProgressCallback* ProgressCallback, [in, unique] IWSLCCompatWarningCallback* WarningCallback); + + HRESULT RegisterCrashDumpCallback([in] IWSLCCompatCrashDumpCallback* Callback, [out] IUnknown** Subscription); +} + +typedef enum _WSLCCompatSessionFlags +{ + WSLCCompatSessionFlagsNone = 0, + WSLCCompatSessionFlagsPersistent = 1, // Session remains active after its COM reference is released. + WSLCCompatSessionFlagsOpenExisting = 2, // Open an existing session if the name is in use. +} WSLCCompatSessionFlags; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCCompatSessionFlags);") + +[ + uuid(279F2047-DA35-45A3-B671-AFD2302D5D16), + pointer_default(unique), + object +] +interface IWSLCCompatSessionManager : IUnknown +{ + HRESULT GetVersion([out] WSLCCompatVersion* Version); + HRESULT IsClientVersionSupported([in] const WSLCCompatVersion* ClientVersion, [out] BOOL* IsSupported); + + // Session management. + HRESULT CreateSession([in, unique] const WSLCCompatSessionSettings* Settings, WSLCCompatSessionFlags Flags, [in, unique] IWSLCCompatWarningCallback* WarningCallback, [out] IWSLCCompatSession** Session); +} diff --git a/src/windows/service/inc/WSLSDK.idl b/src/windows/service/inc/WSLSDK.idl deleted file mode 100644 index 77c08b9ec0..0000000000 --- a/src/windows/service/inc/WSLSDK.idl +++ /dev/null @@ -1,539 +0,0 @@ -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - WSLSDK.idl - -Abstract: - - This file contains the WSLC SDK-facing COM object definitions. - Changes in this file must maintain backwards compatibility - ---*/ - -import "unknwn.idl"; -import "wtypes.idl"; - -cpp_quote("#ifdef __cplusplus") -cpp_quote("#ifndef WSLC_SESSIONMANAGER_COCLASS_DECLARED") -cpp_quote("#define WSLC_SESSIONMANAGER_COCLASS_DECLARED") -cpp_quote("class DECLSPEC_UUID(\"a9b7a1b9-0671-405c-95f1-e0612cb4ce8f\") WSLCSessionManager;") -cpp_quote("#endif") -cpp_quote("#endif") - -#define WSLCSDK_MAX_IMAGE_NAME_LENGTH 255 -#define WSLCSDK_MAX_VOLUME_NAME_LENGTH 255 -#define WSLCSDK_MAX_VOLUME_DRIVER_LENGTH 255 -#define WSLCSDK_CONTAINER_ID_LENGTH 64 -#define WSLCSDK_MAX_BINDING_ADDRESS_LENGTH 45 - -typedef -struct _WSLCSDKVersion { - ULONG Major; - ULONG Minor; - ULONG Revision; -} WSLCSDKVersion; - -typedef enum _WSLCSDKVirtualMachineTerminationReason -{ - WSLCSDKVirtualMachineTerminationReasonUnknown, - WSLCSDKVirtualMachineTerminationReasonShutdown, - WSLCSDKVirtualMachineTerminationReasonCrashed, -} WSLCSDKVirtualMachineTerminationReason; - -typedef enum _WSLCSDKFD -{ - WSLCSDKFDStdin = 0, - WSLCSDKFDStdout = 1, - WSLCSDKFDStderr = 2, - WSLCSDKFDTty = 3, -} WSLCSDKFD; - -typedef enum _WSLCSDKSignal -{ - WSLCSDKSignalNone = 0, - WSLCSDKSignalSIGHUP = 1, - WSLCSDKSignalSIGINT = 2, - WSLCSDKSignalSIGQUIT = 3, - WSLCSDKSignalSIGILL = 4, - WSLCSDKSignalSIGTRAP = 5, - WSLCSDKSignalSIGABRT = 6, - WSLCSDKSignalSIGIOT = 6, // SIGABRT and SIGIOT are equivalent. - WSLCSDKSignalSIGBUS = 7, - WSLCSDKSignalSIGFPE = 8, - WSLCSDKSignalSIGKILL = 9, - WSLCSDKSignalSIGUSR1 = 10, - WSLCSDKSignalSIGSEGV = 11, - WSLCSDKSignalSIGUSR2 = 12, - WSLCSDKSignalSIGPIPE = 13, - WSLCSDKSignalSIGALRM = 14, - WSLCSDKSignalSIGTERM = 15, - WSLCSDKSignalSIGTKFLT = 16, - WSLCSDKSignalSIGCHLD = 17, - WSLCSDKSignalSIGCONT = 18, - WSLCSDKSignalSIGSTOP = 19, - WSLCSDKSignalSIGTSTP = 20, - WSLCSDKSignalSIGTTIN = 21, - WSLCSDKSignalSIGTTOU = 22, - WSLCSDKSignalSIGURG = 23, - WSLCSDKSignalSIGXCPU = 24, - WSLCSDKSignalSIGXFSZ = 25, - WSLCSDKSignalSIGVTALRM = 26, - WSLCSDKSignalSIGPROF = 27, - WSLCSDKSignalSIGWINCH = 28, - WSLCSDKSignalSIGIO = 29, - WSLCSDKSignalSIGPOLL = 29, // SIGIO and SIGPOLL are equivalent. - WSLCSDKSignalSIGPWR = 30, - WSLCSDKSignalSIGSYS = 31 -} WSLCSDKSignal; - -[ - uuid(86A807EA-F2A1-4382-93E5-09FB5F2F4A31), - pointer_default(unique), - object -] -interface IWSLCSDKTerminationCallback : IUnknown -{ - HRESULT OnTermination(WSLCSDKVirtualMachineTerminationReason Reason, LPCWSTR Details); -}; - -[ - uuid(EAA15E20-7FCC-485B-B798-ED4095DBACA5), - pointer_default(unique), - object -] -interface IWSLCSDKCrashDumpCallback : IUnknown -{ - HRESULT OnCrashDump( - [in, string] LPCWSTR DumpPath, - [in, unique, string] LPCSTR ProcessName, - [in] ULONGLONG Pid, - [in] ULONG Signal, - [in] ULONGLONG Timestamp); -}; - -[ - uuid(06154F2A-ACA7-461E-94FC-92781BA1F6F6), - pointer_default(unique), - object -] -interface IWSLCSDKProgressCallback : IUnknown -{ - HRESULT OnProgress(LPCSTR Status, LPCSTR Id, ULONGLONG Current, ULONGLONG Total); -}; - -[ - uuid(290C58A1-328C-4E90-B09B-0A9D32C40074), - pointer_default(unique), - object -] -interface IWSLCSDKWarningCallback : IUnknown -{ - HRESULT OnWarning([in, string] LPCWSTR Message); -}; - -typedef struct _WSLCSDKImageInformation -{ - char Image[WSLCSDK_MAX_IMAGE_NAME_LENGTH + 1]; - char Hash[256]; - char Digest[256]; - LONGLONG Size; // Matches Docker's int64 image size - LONGLONG Created; // Unix timestamp - char ParentId[256]; -} WSLCSDKImageInformation; - -typedef enum _WSLCSDKListImagesFlags -{ - WSLCSDKListImagesFlagsNone = 0, - WSLCSDKListImagesFlagsAll = 1, // Show all images (default hides intermediate images) - WSLCSDKListImagesFlagsDigests = 2, // Include digest information -} WSLCSDKListImagesFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKListImagesFlags);") - -typedef struct _WSLCSDKKeyValuePair -{ - [string] LPCSTR Key; - [string] LPCSTR Value; -} WSLCSDKKeyValuePair; - -typedef WSLCSDKKeyValuePair WSLCSDKLabel; -typedef WSLCSDKKeyValuePair WSLCSDKDriverOption; -typedef WSLCSDKKeyValuePair WSLCSDKFilter; - -typedef struct _WSLCSDKListImagesOptions -{ - DWORD Flags; // WSLCSDKListImagesFlags (can combine with bitwise OR) - [unique, size_is(FiltersCount)] const WSLCSDKFilter* Filters; - ULONG FiltersCount; -} WSLCSDKListImagesOptions; - -typedef enum _WSLCSDKProcessFlags -{ - WSLCSDKProcessFlagsNone = 0, - WSLCSDKProcessFlagsStdin = 1, - WSLCSDKProcessFlagsTty = 2 -} WSLCSDKProcessFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKProcessFlags);") - -typedef struct _WSLCSDKStringArray -{ - [unique, size_is(Count)] LPCSTR const* Values; - ULONG Count; -} WSLCSDKStringArray; - -typedef struct _WSLCSDKProcessOptions -{ - [unique] LPCSTR CurrentDirectory; - [unique] LPCSTR User; - WSLCSDKStringArray CommandLine; - WSLCSDKStringArray Environment; - WSLCSDKProcessFlags Flags; -} WSLCSDKProcessOptions; - -typedef struct _WSLCSDKNamedVolume -{ - LPCSTR Name; - LPCSTR ContainerPath; - BOOL ReadOnly; -} WSLCSDKNamedVolume; - -typedef struct _WSLCSDKVolume -{ - LPCWSTR HostPath; - LPCSTR ContainerPath; - BOOL ReadOnly; -} WSLCSDKVolume; - -typedef struct _WSLCSDKPortMapping -{ - USHORT HostPort; - USHORT ContainerPort; - int Family; - int Protocol; - char BindingAddress[WSLCSDK_MAX_BINDING_ADDRESS_LENGTH + 1]; -} WSLCSDKPortMapping; - -typedef struct _WSLCSDKTmpfsMount -{ - LPCSTR Destination; - [unique] LPCSTR Options; -} WSLCSDKTmpfsMount; - -typedef struct _WSLCSDKUlimit -{ - [string] LPCSTR Name; - LONGLONG Soft; - LONGLONG Hard; -} WSLCSDKUlimit; - -typedef struct _WSLCSDKNetworkConnection -{ - [string] LPCSTR NetworkName; - [unique, size_is(SettingsCount)] const WSLCSDKKeyValuePair* Settings; - ULONG SettingsCount; -} WSLCSDKNetworkConnection; - -typedef struct _WSLCSDKContainerNetwork -{ - [unique, string] LPCSTR NetworkMode; - - [unique, size_is(NetworksCount)] const WSLCSDKNetworkConnection* Networks; - ULONG NetworksCount; -} WSLCSDKContainerNetwork; - -typedef enum _WSLCSDKContainerFlags -{ - WSLCSDKContainerFlagsNone = 0, - WSLCSDKContainerFlagsRm = 1, // Delete the container when it exits. - WSLCSDKContainerFlagsGpu = 2, // Enable GPU access. - WSLCSDKContainerFlagsInit = 4, // Run the container under an init process. - WSLCSDKContainerFlagsPublishAll = 8, // Publish all exposed ports. -} WSLCSDKContainerFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKContainerFlags);") - -typedef enum _WSLCSDKContainerStartFlags -{ - WSLCSDKContainerStartFlagsNone = 0, - WSLCSDKContainerStartFlagsAttach = 1, // Attach stdio handles on start. -} WSLCSDKContainerStartFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKContainerStartFlags);") - -typedef struct _WSLCSDKContainerOptions -{ - LPCSTR Image; - [unique] LPCSTR Name; - WSLCSDKStringArray Entrypoint; - WSLCSDKProcessOptions InitProcessOptions; - [unique, size_is(VolumesCount)] WSLCSDKVolume* Volumes; - ULONG VolumesCount; - [unique, size_is(PortsCount)] WSLCSDKPortMapping* Ports; - ULONG PortsCount; - [unique, size_is(LabelsCount)] const WSLCSDKLabel* Labels; - ULONG LabelsCount; - WSLCSDKContainerFlags Flags; - WSLCSDKSignal StopSignal; - [unique] LPCSTR HostName; - [unique] LPCSTR DomainName; - - WSLCSDKStringArray DnsServers; - WSLCSDKStringArray DnsSearchDomains; - WSLCSDKStringArray DnsOptions; - - LONGLONG ShmSize; - WSLCSDKContainerNetwork ContainerNetwork; - [unique, size_is(TmpfsCount)] const WSLCSDKTmpfsMount* Tmpfs; - ULONG TmpfsCount; - - [unique, size_is(NamedVolumesCount)] WSLCSDKNamedVolume* NamedVolumes; - ULONG NamedVolumesCount; - - LONGLONG MemoryBytes; - LONGLONG NanoCpus; - [unique, size_is(UlimitsCount)] const WSLCSDKUlimit* Ulimits; - ULONG UlimitsCount; -} WSLCSDKContainerOptions; - -typedef enum _WSLCSDKContainerState -{ - WSLCSDKContainerStateInvalid = 0, - WSLCSDKContainerStateCreated = 1, - WSLCSDKContainerStateRunning = 2, - WSLCSDKContainerStateExited = 3, - WSLCSDKContainerStateDeleted = 4, -} WSLCSDKContainerState; - -typedef char WSLCSDKContainerId[WSLCSDK_CONTAINER_ID_LENGTH + 1]; - -typedef [system_handle(sh_file)] HANDLE WSLCSDKFileHandle; -typedef [system_handle(sh_pipe)] HANDLE WSLCSDKPipeHandle; -typedef [system_handle(sh_socket)] HANDLE WSLCSDKSocketHandle; - -typedef enum _WSLCSDKHandleType -{ - WSLCSDKHandleTypeUnknown = 0, - WSLCSDKHandleTypeFile = 1, - WSLCSDKHandleTypePipe = 2, - WSLCSDKHandleTypeSocket = 3 -} WSLCSDKHandleType; - -typedef struct _WSLCSDKHandle -{ - WSLCSDKHandleType Type; - - [switch_type(WSLCSDKHandleType), switch_is(Type)] - union - { - [case(WSLCSDKHandleTypeFile)] - WSLCSDKFileHandle File; - [case(WSLCSDKHandleTypePipe)] - WSLCSDKPipeHandle Pipe; - [case(WSLCSDKHandleTypeSocket)] - WSLCSDKSocketHandle Socket; - [default]; - } Handle; -} WSLCSDKHandle; - -typedef enum _WSLCSDKProcessState -{ - WSLCSDKProcessStateUnknown = 0, - WSLCSDKProcessStateRunning = 1, - WSLCSDKProcessStateExited = 2, - WSLCSDKProcessStateSignalled = 3 -} WSLCSDKProcessState; - -[ - uuid(AC69DD0D-6616-4C4F-91F2-C39D6034EA82), - pointer_default(unique), - object -] -interface IWSLCSDKProcess : IUnknown -{ - HRESULT Signal([in] int Signal); - HRESULT GetExitEvent([out, system_handle(sh_event)] HANDLE* EventHandle); - HRESULT GetStdHandle([in] WSLCSDKFD Fd, [out] WSLCSDKHandle* Handle); - HRESULT GetPid([out] int* Pid); - HRESULT GetState([out] WSLCSDKProcessState* State, [out] int* Code); -} - -typedef enum _WSLCSDKNetworkingMode -{ - WSLCSDKNetworkingModeNone, - WSLCSDKNetworkingModeNAT, - WSLCSDKNetworkingModeVirtioProxy -} WSLCSDKNetworkingMode; - -typedef enum _WSLCSDKFeatureFlags -{ - WSLCSDKFeatureFlagsNone = 0, - WSLCSDKFeatureFlagsDnsTunneling = 1, - WSLCSDKFeatureFlagsEarlyBootDmesg = 2, - WSLCSDKFeatureFlagsGPU = 4, - WSLCSDKFeatureFlagsVirtioFs = 8, - WSLCSDKFeatureFlagsDebug = 16, -} WSLCSDKFeatureFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKFeatureFlags);") - -typedef enum _WSLCSDKSessionStorageFlags -{ - WSLCSDKSessionStorageFlagsNone = 0, - WSLCSDKSessionStorageFlagsNoCreate = 1, // Open an existing storage path, but don't create a new one. -} WSLCSDKSessionStorageFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKSessionStorageFlags);") - -typedef struct _WSLCSDKSessionSettings { - LPCWSTR DisplayName; - LPCWSTR StoragePath; - ULONGLONG MaximumStorageSizeMb; - ULONG CpuCount; - ULONG MemoryMb; - ULONG BootTimeoutMs; - WSLCSDKNetworkingMode NetworkingMode; - [unique] IWSLCSDKTerminationCallback* TerminationCallback; - WSLCSDKFeatureFlags FeatureFlags; - WSLCSDKHandle DmesgOutput; - WSLCSDKSessionStorageFlags StorageFlags; - - // Below options are used for debugging purposes only. - [unique] LPCWSTR RootVhdOverride; - [unique] LPCSTR RootVhdTypeOverride; -} WSLCSDKSessionSettings; - -typedef enum _WSLCSDKDeleteFlags -{ - WSLCSDKDeleteFlagsNone = 0, - WSLCSDKDeleteFlagsForce = 1, - WSLCSDKDeleteFlagsDeleteVolumes = 2, -} WSLCSDKDeleteFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKDeleteFlags);") - -[ - uuid(8C3C91FA-D550-41B9-AD9D-23DCBF96F549), - pointer_default(unique), - object -] -interface IWSLCSDKContainer : IUnknown -{ - HRESULT Stop([in] WSLCSDKSignal Signal, [in] LONG TimeoutSeconds); - HRESULT Start([in] WSLCSDKContainerStartFlags Flags); - HRESULT Delete([in] WSLCSDKDeleteFlags Flags); - HRESULT GetState([out] WSLCSDKContainerState* State); - HRESULT GetInitProcess([out] IWSLCSDKProcess** Process); - HRESULT Exec([in, ref] const WSLCSDKProcessOptions* Options, [out] IWSLCSDKProcess** Process); - HRESULT Inspect([out] LPSTR* Output); - HRESULT GetId([out, string] WSLCSDKContainerId Id); -} - -typedef enum _WSLCSDKDeletedImageType -{ - WSLCSDKDeletedImageTypeDeleted = 0, - WSLCSDKDeletedImageTypeUntagged = 1 -} WSLCSDKDeletedImageType; - -typedef struct _WSLCSDKDeletedImageInformation -{ - char Image[WSLCSDK_MAX_IMAGE_NAME_LENGTH + 1]; - WSLCSDKDeletedImageType Type; -} WSLCSDKDeletedImageInformation; - -typedef enum _WSLCSDKDeleteImageFlags -{ - WSLCSDKDeleteImageFlagsNone = 0, - WSLCSDKDeleteImageFlagsForce = 1, - WSLCSDKDeleteImageFlagsNoPrune = 2, -} WSLCSDKDeleteImageFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKDeleteImageFlags);") - -typedef struct _WSLCSDKDeleteImageOptions -{ - LPCSTR Image; // Image can be ID or Repo:Tag. - DWORD Flags; // WSLCSDKDeleteImageFlags -} WSLCSDKDeleteImageOptions; - -typedef struct _WSLCSDKTagImageOptions -{ - LPCSTR Image; // Source image name or ID. - LPCSTR Repo; // Target repository name. - LPCSTR Tag; // Target tag name. -} WSLCSDKTagImageOptions; - -typedef struct _WSLCSDKVolumeOptions -{ - [unique] LPCSTR Name; - [unique] LPCSTR Driver; - [unique, size_is(DriverOptsCount)] const WSLCSDKDriverOption* DriverOpts; - ULONG DriverOptsCount; - [unique, size_is(LabelsCount)] const WSLCSDKLabel* Labels; - ULONG LabelsCount; -} WSLCSDKVolumeOptions; - -typedef char WSLCSDKVolumeName[WSLCSDK_MAX_VOLUME_NAME_LENGTH + 1]; - -typedef struct _WSLCSDKVolumeInformation -{ - WSLCSDKVolumeName Name; - char Driver[WSLCSDK_MAX_VOLUME_DRIVER_LENGTH + 1]; -} WSLCSDKVolumeInformation; - -[ - uuid(DD7B2EF9-AA01-4F21-8A3A-29D394CBB579), - pointer_default(unique), - object -] -interface IWSLCSDKSession : IUnknown -{ - // Image management. - HRESULT PullImage([in] LPCSTR Image, [in, unique] LPCSTR RegistryAuthenticationInformation, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in, unique] IWSLCSDKWarningCallback* WarningCallback); - HRESULT LoadImage([in] WSLCSDKHandle ImageHandle, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength, [in, unique] IWSLCSDKWarningCallback* WarningCallback); - HRESULT ImportImage([in] WSLCSDKHandle ImageHandle, [in] LPCSTR ImageName, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength, [in, unique] IWSLCSDKWarningCallback* WarningCallback); - HRESULT ListImages([in, unique] const WSLCSDKListImagesOptions* Options, [out, size_is(, *Count)] WSLCSDKImageInformation** Images, [out] ULONG* Count); - HRESULT DeleteImage([in] const WSLCSDKDeleteImageOptions* Options, [out, size_is(, *Count)] WSLCSDKDeletedImageInformation** DeletedImages, [out] ULONG* Count); - HRESULT TagImage([in] const WSLCSDKTagImageOptions* Options); - - // Container management. - HRESULT CreateContainer([in] const WSLCSDKContainerOptions* Options, [in, unique] IWSLCSDKWarningCallback* WarningCallback, [out] IWSLCSDKContainer** Container); - - // Terminate the VM and containers. - HRESULT Terminate(); - - // Volume management. - HRESULT CreateVolume([in] const WSLCSDKVolumeOptions* Options, [out] WSLCSDKVolumeInformation* VolumeInfo); - HRESULT DeleteVolume([in] LPCSTR Name); - - HRESULT Authenticate([in] LPCSTR ServerAddress, [in] LPCSTR Username, [in] LPCSTR Password, [out] LPSTR* IdentityToken); - HRESULT PushImage([in] LPCSTR Image, [in] LPCSTR RegistryAuthenticationInformation, [in, unique] IWSLCSDKProgressCallback* ProgressCallback, [in, unique] IWSLCSDKWarningCallback* WarningCallback); - - HRESULT RegisterCrashDumpCallback([in] IWSLCSDKCrashDumpCallback* Callback, [out] IUnknown** Subscription); -} - -typedef enum _WSLCSDKSessionFlags -{ - WSLCSDKSessionFlagsNone = 0, - WSLCSDKSessionFlagsPersistent = 1, // Session remains active after its COM reference is released. - WSLCSDKSessionFlagsOpenExisting = 2, // Open an existing session if the name is in use. -} WSLCSDKSessionFlags; - -cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSDKSessionFlags);") - -[ - uuid(279F2047-DA35-45A3-B671-AFD2302D5D16), - pointer_default(unique), - object -] -interface IWSLCSDKSessionManager : IUnknown -{ - HRESULT GetVersion([out] WSLCSDKVersion* Version); - HRESULT IsClientVersionSupported([in] const WSLCSDKVersion* ClientVersion, [out] BOOL* IsSupported); - - // Session management. - HRESULT CreateSession([in, unique] const WSLCSDKSessionSettings* Settings, WSLCSDKSessionFlags Flags, [in, unique] IWSLCSDKWarningCallback* WarningCallback, [out] IWSLCSDKSession** Session); -} diff --git a/src/windows/service/inc/wslc.idl b/src/windows/service/inc/wslc.idl index d2283d0780..f7e8e8fffc 100644 --- a/src/windows/service/inc/wslc.idl +++ b/src/windows/service/inc/wslc.idl @@ -10,7 +10,7 @@ Abstract: This file contains the WSLC-related COM object definitions. // N.B. ABI breaking changes in this file are OK, since both client & server always ship together. - // The WSLC SDK must not use this file, and instead use WSLSDK.idl + // The WSLC SDK must not use this file, and instead use WSLCCompat.idl --*/ diff --git a/src/windows/service/stub/CMakeLists.txt b/src/windows/service/stub/CMakeLists.txt index a40c3746bd..d6dfc408ef 100644 --- a/src/windows/service/stub/CMakeLists.txt +++ b/src/windows/service/stub/CMakeLists.txt @@ -3,8 +3,8 @@ set(SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslservice_p_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslc_i_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/wslc_p_${TARGET_PLATFORM}.c - ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WSLSDK_i_${TARGET_PLATFORM}.c - ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WSLSDK_p_${TARGET_PLATFORM}.c + ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WSLCCompat_i_${TARGET_PLATFORM}.c + ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/WSLCCompat_p_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_BINARY_DIR}/../inc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}/dlldata_${TARGET_PLATFORM}.c ${CMAKE_CURRENT_LIST_DIR}/WslServiceProxyStub.def ${CMAKE_CURRENT_LIST_DIR}/WslServiceProxyStub.rc) diff --git a/src/windows/wslcsession/WSLCContainer.cpp b/src/windows/wslcsession/WSLCContainer.cpp index aa3bdd0540..c309e87ba2 100644 --- a/src/windows/wslcsession/WSLCContainer.cpp +++ b/src/windows/wslcsession/WSLCContainer.cpp @@ -23,6 +23,9 @@ Module Name: #include "WSLCProcess.h" #include "WSLCProcessIO.h" #include "WSLCVolumes.h" +#include "APICompat.h" + +namespace apicompat = wsl::windows::common::apicompat; using wsl::windows::common::COMServiceExecutionContext; using wsl::windows::common::docker_schema::ErrorResponse; @@ -292,8 +295,9 @@ void UnmountVolumes(std::vector& volumes, WSLCVirtualMachine& p else { LOG_HR(result); - EMIT_USER_WARNING(wsl::shared::Localization::MessageWslcVolumeUnmountFailed( - volume.HostPath, wsl::windows::common::wslutil::GetErrorString(result))); + EMIT_USER_WARNING( + wsl::shared::Localization::MessageWslcVolumeUnmountFailed( + volume.HostPath, wsl::windows::common::wslutil::GetErrorString(result))); } } } @@ -678,8 +682,9 @@ void WSLCContainerImpl::Attach(LPCSTR DetachKeys, WSLCHandle* Stdin, WSLCHandle* handles.emplace_back( std::make_unique>(HandleWrapper{std::move(stdinRead), std::move(onInputComplete)}, ioHandle.get())); - handles.emplace_back(std::make_unique( - std::move(ioHandle), std::move(stdoutWrite), std::move(stderrWrite), DockerIORelayHandle::Format::Raw)); + handles.emplace_back( + std::make_unique( + std::move(ioHandle), std::move(stdoutWrite), std::move(stderrWrite), DockerIORelayHandle::Format::Raw)); m_ioRelay.AddHandles(std::move(handles)); @@ -793,8 +798,8 @@ void WSLCContainerImpl::Start(WSLCContainerStartFlags Flags, const WSLCProcessSt catch (...) { LOG_CAUGHT_EXCEPTION(); - EMIT_USER_WARNING(wsl::shared::Localization::MessageWslcContainerStopAfterPluginRejectionFailed( - wsl::shared::string::MultiByteToWide(m_id))); + EMIT_USER_WARNING( + wsl::shared::Localization::MessageWslcContainerStopAfterPluginRejectionFailed(wsl::shared::string::MultiByteToWide(m_id))); } if (comError.has_value() && comError->Message) @@ -1812,8 +1817,9 @@ std::unique_ptr WSLCContainerImpl::Open( catch (...) { LOG_CAUGHT_EXCEPTION(); - EMIT_USER_WARNING(wsl::shared::Localization::MessageWslcContainerTimestampRecoveryFailed( - wsl::shared::string::MultiByteToWide(dockerContainer.Id))); + EMIT_USER_WARNING( + wsl::shared::Localization::MessageWslcContainerTimestampRecoveryFailed( + wsl::shared::string::MultiByteToWide(dockerContainer.Id))); } return container; @@ -1934,8 +1940,9 @@ std::unique_ptr WSLCContainerImpl::CreateRelayedProcessIO(wil: fds.emplace(WSLCFDStdout, TypedHandle{wil::unique_handle{stdoutRead.release()}, WSLCHandleTypePipe}); fds.emplace(WSLCFDStderr, TypedHandle{wil::unique_handle{stderrRead.release()}, WSLCHandleTypePipe}); - ioHandles.emplace_back(std::make_unique( - std::move(stream), std::move(stdoutWrite), std::move(stderrWrite), common::io::DockerIORelayHandle::Format::Raw)); + ioHandles.emplace_back( + std::make_unique( + std::move(stream), std::move(stdoutWrite), std::move(stderrWrite), common::io::DockerIORelayHandle::Format::Raw)); m_ioRelay.AddHandles(std::move(ioHandles)); @@ -2460,31 +2467,35 @@ HRESULT WSLCContainer::InterfaceSupportsErrorInfo(REFIID riid) return riid == __uuidof(IWSLCContainer) ? S_OK : S_FALSE; } -HRESULT WSLCContainer::Stop(WSLCSDKSignal Signal, LONG TimeoutSeconds) +HRESULT WSLCContainer::Stop(WSLCCompatSignal Signal, LONG TimeoutSeconds) { - static_assert(sizeof(WSLCSDKSignal) == sizeof(WSLCSignal), "WSLCSDKSignal and WSLCSignal size mismatch"); - - return Stop(static_cast(Signal), TimeoutSeconds); + return Stop(apicompat::Convert(Signal), TimeoutSeconds); } -HRESULT WSLCContainer::Start(WSLCSDKContainerStartFlags Flags) +HRESULT WSLCContainer::Start(WSLCCompatContainerStartFlags Flags) { - return Start(static_cast(Flags), nullptr, nullptr); + return Start(apicompat::Convert(Flags), nullptr, nullptr); } -HRESULT WSLCContainer::Delete(WSLCSDKDeleteFlags Flags) +HRESULT WSLCContainer::Delete(WSLCCompatDeleteFlags Flags) { - return Delete(static_cast(Flags)); + return Delete(apicompat::Convert(Flags)); } -HRESULT WSLCContainer::GetState(WSLCSDKContainerState* State) +HRESULT WSLCContainer::GetState(WSLCCompatContainerState* State) +try { - static_assert(sizeof(WSLCSDKContainerState) == sizeof(WSLCContainerState), "WSLCSDKContainerState and WSLCContainerState size mismatch"); + RETURN_HR_IF_NULL(E_POINTER, State); + + WSLCContainerState state{}; + RETURN_IF_FAILED(GetState(&state)); - return GetState(reinterpret_cast(State)); + *State = apicompat::Convert(state); + return S_OK; } +CATCH_RETURN(); -HRESULT WSLCContainer::GetInitProcess(IWSLCSDKProcess** Process) +HRESULT WSLCContainer::GetInitProcess(IWSLCCompatProcess** Process) try { RETURN_HR_IF_NULL(E_POINTER, Process); @@ -2498,16 +2509,17 @@ try } CATCH_RETURN(); -HRESULT WSLCContainer::Exec(const WSLCSDKProcessOptions* Options, IWSLCSDKProcess** Process) +HRESULT WSLCContainer::Exec(const WSLCCompatProcessOptions* Options, IWSLCCompatProcess** Process) try { - static_assert(sizeof(WSLCSDKProcessOptions) == sizeof(WSLCProcessOptions), "WSLCSDKProcessOptions and WSLCProcessOptions size mismatch"); - + RETURN_HR_IF_NULL(E_POINTER, Options); RETURN_HR_IF_NULL(E_POINTER, Process); *Process = nullptr; + const auto options = apicompat::Convert(*Options); + Microsoft::WRL::ComPtr process; - RETURN_IF_FAILED(Exec(reinterpret_cast(Options), nullptr, &process)); + RETURN_IF_FAILED(Exec(&options, nullptr, &process)); RETURN_HR_IF_NULL(E_UNEXPECTED, process); return process.CopyTo(Process); diff --git a/src/windows/wslcsession/WSLCContainer.h b/src/windows/wslcsession/WSLCContainer.h index 2ee98a1e48..6baee4cc7e 100644 --- a/src/windows/wslcsession/WSLCContainer.h +++ b/src/windows/wslcsession/WSLCContainer.h @@ -22,7 +22,7 @@ Module Name: #include "IORelay.h" #include "COMImplClass.h" #include "wslc_schema.h" -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "WSLCContainerMetadata.h" #include "WSLCNetworkMetadata.h" #include "WSLCVhdVolume.h" @@ -218,7 +218,7 @@ class WSLCContainerImpl }; class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLCContainer - : public Microsoft::WRL::RuntimeClass, IWSLCContainer, IWSLCSDKContainer, IFastRundown, ISupportErrorInfo>, + : public Microsoft::WRL::RuntimeClass, IWSLCContainer, IWSLCCompatContainer, IFastRundown, ISupportErrorInfo>, public COMImplClass { @@ -243,13 +243,13 @@ class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLCContainer IFACEMETHOD(ConnectToNetwork)(_In_ const WSLCNetworkConnectionOptions* Options) override; IFACEMETHOD(DisconnectFromNetwork)(_In_ LPCSTR NetworkName) override; - // IWSLCSDKContainer - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. - IFACEMETHOD(Stop)(_In_ WSLCSDKSignal Signal, _In_ LONG TimeoutSeconds) override; - IFACEMETHOD(Start)(_In_ WSLCSDKContainerStartFlags Flags) override; - IFACEMETHOD(Delete)(_In_ WSLCSDKDeleteFlags Flags) override; - IFACEMETHOD(GetState)(_Out_ WSLCSDKContainerState* State) override; - IFACEMETHOD(GetInitProcess)(_Out_ IWSLCSDKProcess** Process) override; - IFACEMETHOD(Exec)(_In_ const WSLCSDKProcessOptions* Options, _Out_ IWSLCSDKProcess** Process) override; + // IWSLCCompatContainer - converts the WSLCCompat types to the wslc.idl types and forwards to the methods above. + IFACEMETHOD(Stop)(_In_ WSLCCompatSignal Signal, _In_ LONG TimeoutSeconds) override; + IFACEMETHOD(Start)(_In_ WSLCCompatContainerStartFlags Flags) override; + IFACEMETHOD(Delete)(_In_ WSLCCompatDeleteFlags Flags) override; + IFACEMETHOD(GetState)(_Out_ WSLCCompatContainerState* State) override; + IFACEMETHOD(GetInitProcess)(_Out_ IWSLCCompatProcess** Process) override; + IFACEMETHOD(Exec)(_In_ const WSLCCompatProcessOptions* Options, _Out_ IWSLCCompatProcess** Process) override; IFACEMETHOD(InterfaceSupportsErrorInfo)(REFIID riid); diff --git a/src/windows/wslcsession/WSLCProcess.cpp b/src/windows/wslcsession/WSLCProcess.cpp index ec6e86c0d2..268a3caf1b 100644 --- a/src/windows/wslcsession/WSLCProcess.cpp +++ b/src/windows/wslcsession/WSLCProcess.cpp @@ -15,8 +15,10 @@ Module Name: #include "precomp.h" #include "WSLCProcess.h" #include "WSLCVirtualMachine.h" +#include "APICompat.h" using wsl::windows::service::wslc::WSLCProcess; +namespace apicompat = wsl::windows::common::apicompat; WSLCProcess::WSLCProcess(std::shared_ptr Control, std::unique_ptr&& Io, WSLCProcessFlags Flags) : m_control(std::move(Control)), m_io(std::move(Io)), m_flags(Flags) @@ -124,16 +126,28 @@ try } CATCH_RETURN(); -HRESULT WSLCProcess::GetStdHandle(WSLCSDKFD Fd, WSLCSDKHandle* Handle) +HRESULT WSLCProcess::GetStdHandle(WSLCCompatFD Fd, WSLCCompatHandle* Handle) +try { - static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); + RETURN_HR_IF_NULL(E_POINTER, Handle); + + WSLCHandle handle{}; + RETURN_IF_FAILED(GetStdHandle(apicompat::Convert(Fd), &handle)); - return GetStdHandle(static_cast(Fd), reinterpret_cast(Handle)); + *Handle = apicompat::Convert(handle); + return S_OK; } +CATCH_RETURN(); -HRESULT WSLCProcess::GetState(WSLCSDKProcessState* State, int* Code) +HRESULT WSLCProcess::GetState(WSLCCompatProcessState* State, int* Code) +try { - static_assert(sizeof(WSLCSDKProcessState) == sizeof(WSLCProcessState), "WSLCSDKProcessState and WSLCProcessState size mismatch"); + RETURN_HR_IF_NULL(E_POINTER, State); + + WSLCProcessState state{}; + RETURN_IF_FAILED(GetState(&state, Code)); - return GetState(reinterpret_cast(State), Code); -} \ No newline at end of file + *State = apicompat::Convert(state); + return S_OK; +} +CATCH_RETURN(); \ No newline at end of file diff --git a/src/windows/wslcsession/WSLCProcess.h b/src/windows/wslcsession/WSLCProcess.h index 2cc6227b1a..da981ff52c 100644 --- a/src/windows/wslcsession/WSLCProcess.h +++ b/src/windows/wslcsession/WSLCProcess.h @@ -14,7 +14,7 @@ Module Name: #pragma once #include "wslc.h" -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "WSLCProcessControl.h" #include "WSLCProcessIO.h" @@ -23,7 +23,7 @@ namespace wsl::windows::service::wslc { class WSLCVirtualMachine; class DECLSPEC_UUID("AFBEA6D6-D8A4-4F81-8FED-F947EB74B33B") WSLCProcess - : public Microsoft::WRL::RuntimeClass, IWSLCProcess, IWSLCSDKProcess, IFastRundown> + : public Microsoft::WRL::RuntimeClass, IWSLCProcess, IWSLCCompatProcess, IFastRundown> { public: WSLCProcess(std::shared_ptr Control, std::unique_ptr&& Io, WSLCProcessFlags Flags); @@ -38,9 +38,9 @@ class DECLSPEC_UUID("AFBEA6D6-D8A4-4F81-8FED-F947EB74B33B") WSLCProcess IFACEMETHOD(GetState)(_Out_ WSLCProcessState* State, _Out_ int* Code) override; IFACEMETHOD(ResizeTty)(_In_ ULONG Rows, _In_ ULONG Columns) override; - // IWSLCSDKProcess - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. - IFACEMETHOD(GetStdHandle)(_In_ WSLCSDKFD Fd, _Out_ WSLCSDKHandle* Handle) override; - IFACEMETHOD(GetState)(_Out_ WSLCSDKProcessState* State, _Out_ int* Code) override; + // IWSLCCompatProcess - converts the WSLCCompat types to the wslc.idl types and forwards to the methods above. + IFACEMETHOD(GetStdHandle)(_In_ WSLCCompatFD Fd, _Out_ WSLCCompatHandle* Handle) override; + IFACEMETHOD(GetState)(_Out_ WSLCCompatProcessState* State, _Out_ int* Code) override; wil::unique_handle GetStdHandle(int Index); HANDLE GetExitEvent(); diff --git a/src/windows/wslcsession/WSLCSession.cpp b/src/windows/wslcsession/WSLCSession.cpp index 4e9863ceab..602ed43ffd 100644 --- a/src/windows/wslcsession/WSLCSession.cpp +++ b/src/windows/wslcsession/WSLCSession.cpp @@ -21,7 +21,7 @@ Module Name: #include "ServiceProcessLauncher.h" #include "WslCoreFilesystem.h" #include "wslpolicies.h" -#include "WSLCSDKCallbackAdapters.h" +#include "APICompat.h" using namespace wsl::windows::common; using io::MultiHandleWait; @@ -555,11 +555,13 @@ ServiceRunningProcess WSLCSession::StartProcess( auto process = launcher.Launch(*m_virtualMachine); - m_ioRelay.AddHandle(std::make_unique( - process.GetStdHandle(1), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); + m_ioRelay.AddHandle( + std::make_unique( + process.GetStdHandle(1), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); - m_ioRelay.AddHandle(std::make_unique( - process.GetStdHandle(2), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); + m_ioRelay.AddHandle( + std::make_unique( + process.GetStdHandle(2), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); m_ioRelay.AddHandle(std::make_unique(process.GetExitEvent(), std::move(ExitCallback))); @@ -669,8 +671,9 @@ void WSLCSession::StreamImageOperation(DockerHTTPClient::HTTPRequestContext& req auto onCompleted = [&]() { io.Cancel(); }; - io.AddHandle(std::make_unique( - requestContext, std::move(onHttpResponse), std::move(onChunk), std::move(onCompleted))); + io.AddHandle( + std::make_unique( + requestContext, std::move(onHttpResponse), std::move(onChunk), std::move(onCompleted))); io.Run({}); @@ -842,8 +845,9 @@ try auto io = CreateIOContext(); - io.AddHandle(std::make_unique>( - buildFileHandle.Get(), common::io::HandleWrapper{buildProcess.GetStdHandle(WSLCFDStdin)})); + io.AddHandle( + std::make_unique>( + buildFileHandle.Get(), common::io::HandleWrapper{buildProcess.GetStdHandle(WSLCFDStdin)})); bool verbose = WI_IsFlagSet(Options->Flags, WSLCBuildImageFlagsVerbose); std::string allOutput; @@ -1212,8 +1216,10 @@ void WSLCSession::ImportImageImpl(DockerHTTPClient::HTTPRequestContext& Request, LOG_LAST_ERROR_IF(shutdown(socket, SD_SEND) == SOCKET_ERROR); }; - io.AddHandle(std::make_unique>( - common::io::HandleWrapper{userHandle.Get(), std::move(onInputComplete)}, common::io::HandleWrapper{Request.stream.native_handle()})); + io.AddHandle( + std::make_unique>( + common::io::HandleWrapper{userHandle.Get(), std::move(onInputComplete)}, + common::io::HandleWrapper{Request.stream.native_handle()})); io.AddHandle( std::make_unique(Request, std::move(onHttpResponse), std::move(onProgress)), @@ -2834,100 +2840,169 @@ HRESULT WSLCSession::InterfaceSupportsErrorInfo(REFIID riid) return riid == __uuidof(IWSLCSession) ? S_OK : S_FALSE; } -HRESULT WSLCSession::PullImage(LPCSTR Image, LPCSTR RegistryAuthenticationInformation, IWSLCSDKProgressCallback* ProgressCallback, IWSLCSDKWarningCallback* WarningCallback) +HRESULT WSLCSession::PullImage(LPCSTR Image, LPCSTR RegistryAuthenticationInformation, IWSLCCompatProgressCallback* ProgressCallback, IWSLCCompatWarningCallback* WarningCallback) { - const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); - const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + const auto progress = apicompat::Convert(ProgressCallback); + const auto warning = apicompat::Convert(WarningCallback); return PullImage(Image, RegistryAuthenticationInformation, progress.Get(), warning.Get()); } -HRESULT WSLCSession::LoadImage(WSLCSDKHandle ImageHandle, IWSLCSDKProgressCallback* ProgressCallback, ULONGLONG ContentLength, IWSLCSDKWarningCallback* WarningCallback) +HRESULT WSLCSession::LoadImage(WSLCCompatHandle ImageHandle, IWSLCCompatProgressCallback* ProgressCallback, ULONGLONG ContentLength, IWSLCCompatWarningCallback* WarningCallback) { - static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); - - WSLCHandle handle{}; - memcpy(&handle, &ImageHandle, sizeof(handle)); - - const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); - const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + const auto handle = apicompat::Convert(ImageHandle); + const auto progress = apicompat::Convert(ProgressCallback); + const auto warning = apicompat::Convert(WarningCallback); return LoadImage(handle, progress.Get(), ContentLength, warning.Get()); } -HRESULT WSLCSession::ImportImage(WSLCSDKHandle ImageHandle, LPCSTR ImageName, IWSLCSDKProgressCallback* ProgressCallback, ULONGLONG ContentLength, IWSLCSDKWarningCallback* WarningCallback) +HRESULT WSLCSession::ImportImage( + WSLCCompatHandle ImageHandle, LPCSTR ImageName, IWSLCCompatProgressCallback* ProgressCallback, ULONGLONG ContentLength, IWSLCCompatWarningCallback* WarningCallback) { - static_assert(sizeof(WSLCSDKHandle) == sizeof(WSLCHandle), "WSLCSDKHandle and WSLCHandle layout mismatch"); - - WSLCHandle handle{}; - memcpy(&handle, &ImageHandle, sizeof(handle)); - - const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); - const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + const auto handle = apicompat::Convert(ImageHandle); + const auto progress = apicompat::Convert(ProgressCallback); + const auto warning = apicompat::Convert(WarningCallback); return ImportImage(handle, ImageName, progress.Get(), ContentLength, warning.Get()); } -HRESULT WSLCSession::ListImages(const WSLCSDKListImagesOptions* Options, WSLCSDKImageInformation** Images, ULONG* Count) +HRESULT WSLCSession::ListImages(const WSLCCompatListImagesOptions* Options, WSLCCompatImageInformation** Images, ULONG* Count) +try { - static_assert(sizeof(WSLCSDKListImagesOptions) == sizeof(WSLCListImagesOptions), "WSLCSDKListImagesOptions and WSLCListImagesOptions layout mismatch"); - static_assert(sizeof(WSLCSDKImageInformation) == sizeof(WSLCImageInformation), "WSLCSDKImageInformation and WSLCImageInformation layout mismatch"); + RETURN_HR_IF_NULL(E_POINTER, Images); + RETURN_HR_IF_NULL(E_POINTER, Count); + + *Images = nullptr; + *Count = 0; - return ListImages(reinterpret_cast(Options), reinterpret_cast(Images), Count); + WSLCImageInformation* internalImages = nullptr; + ULONG count = 0; + if (Options == nullptr) + { + RETURN_IF_FAILED(ListImages(static_cast(nullptr), &internalImages, &count)); + } + else + { + const auto options = apicompat::Convert(*Options); + RETURN_IF_FAILED(ListImages(options.Get(), &internalImages, &count)); + } + + auto freeInternal = wil::scope_exit([&] { CoTaskMemFree(internalImages); }); + + if (count > 0) + { + auto converted = wil::make_unique_cotaskmem_nothrow(count); + RETURN_IF_NULL_ALLOC(converted); + + for (ULONG index = 0; index < count; index++) + { + converted[index] = apicompat::Convert(internalImages[index]); + } + + *Images = converted.release(); + } + + *Count = count; + return S_OK; } +CATCH_RETURN(); -HRESULT WSLCSession::DeleteImage(const WSLCSDKDeleteImageOptions* Options, WSLCSDKDeletedImageInformation** DeletedImages, ULONG* Count) +HRESULT WSLCSession::DeleteImage(const WSLCCompatDeleteImageOptions* Options, WSLCCompatDeletedImageInformation** DeletedImages, ULONG* Count) +try { - static_assert(sizeof(WSLCSDKDeleteImageOptions) == sizeof(WSLCDeleteImageOptions), "WSLCSDKDeleteImageOptions and WSLCDeleteImageOptions layout mismatch"); - static_assert(sizeof(WSLCSDKDeletedImageInformation) == sizeof(WSLCDeletedImageInformation), "WSLCSDKDeletedImageInformation and WSLCDeletedImageInformation layout mismatch"); + RETURN_HR_IF_NULL(E_POINTER, Options); + RETURN_HR_IF_NULL(E_POINTER, DeletedImages); + RETURN_HR_IF_NULL(E_POINTER, Count); + + *DeletedImages = nullptr; + *Count = 0; + + const auto options = apicompat::Convert(*Options); + + WSLCDeletedImageInformation* internalImages = nullptr; + ULONG count = 0; + RETURN_IF_FAILED(DeleteImage(&options, &internalImages, &count)); + + auto freeInternal = wil::scope_exit([&] { CoTaskMemFree(internalImages); }); - return DeleteImage(reinterpret_cast(Options), reinterpret_cast(DeletedImages), Count); + if (count > 0) + { + auto converted = wil::make_unique_cotaskmem_nothrow(count); + RETURN_IF_NULL_ALLOC(converted); + + for (ULONG index = 0; index < count; index++) + { + converted[index] = apicompat::Convert(internalImages[index]); + } + + *DeletedImages = converted.release(); + } + + *Count = count; + return S_OK; } +CATCH_RETURN(); -HRESULT WSLCSession::TagImage(const WSLCSDKTagImageOptions* Options) +HRESULT WSLCSession::TagImage(const WSLCCompatTagImageOptions* Options) +try { - static_assert(sizeof(WSLCSDKTagImageOptions) == sizeof(WSLCTagImageOptions), "WSLCSDKTagImageOptions and WSLCTagImageOptions layout mismatch"); + RETURN_HR_IF_NULL(E_POINTER, Options); - return TagImage(reinterpret_cast(Options)); + const auto options = apicompat::Convert(*Options); + return TagImage(&options); } +CATCH_RETURN(); -HRESULT WSLCSession::PushImage(LPCSTR Image, LPCSTR RegistryAuthenticationInformation, IWSLCSDKProgressCallback* ProgressCallback, IWSLCSDKWarningCallback* WarningCallback) +HRESULT WSLCSession::PushImage(LPCSTR Image, LPCSTR RegistryAuthenticationInformation, IWSLCCompatProgressCallback* ProgressCallback, IWSLCCompatWarningCallback* WarningCallback) { - const auto progress = wslcsdk::WrapProgressCallback(ProgressCallback); - const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + const auto progress = apicompat::Convert(ProgressCallback); + const auto warning = apicompat::Convert(WarningCallback); return PushImage(Image, RegistryAuthenticationInformation, progress.Get(), warning.Get()); } -HRESULT WSLCSession::CreateContainer(const WSLCSDKContainerOptions* Options, IWSLCSDKWarningCallback* WarningCallback, IWSLCSDKContainer** Container) +HRESULT WSLCSession::CreateContainer(const WSLCCompatContainerOptions* Options, IWSLCCompatWarningCallback* WarningCallback, IWSLCCompatContainer** Container) try { - static_assert(sizeof(WSLCSDKContainerOptions) == sizeof(WSLCContainerOptions), "WSLCSDKContainerOptions and WSLCContainerOptions layout mismatch"); - + RETURN_HR_IF_NULL(E_POINTER, Options); RETURN_HR_IF_NULL(E_POINTER, Container); *Container = nullptr; - const auto warning = wslcsdk::WrapWarningCallback(WarningCallback); + const auto warning = apicompat::Convert(WarningCallback); + const auto options = apicompat::Convert(*Options); Microsoft::WRL::ComPtr container; - RETURN_IF_FAILED(CreateContainer(reinterpret_cast(Options), warning.Get(), &container)); + RETURN_IF_FAILED(CreateContainer(options.Get(), warning.Get(), &container)); RETURN_HR_IF_NULL(E_UNEXPECTED, container); return container.CopyTo(Container); } CATCH_RETURN(); -HRESULT WSLCSession::CreateVolume(const WSLCSDKVolumeOptions* Options, WSLCSDKVolumeInformation* VolumeInfo) +HRESULT WSLCSession::CreateVolume(const WSLCCompatVolumeOptions* Options, WSLCCompatVolumeInformation* VolumeInfo) +try { - static_assert(sizeof(WSLCSDKVolumeOptions) == sizeof(WSLCVolumeOptions), "WSLCSDKVolumeOptions and WSLCVolumeOptions layout mismatch"); - static_assert(sizeof(WSLCSDKVolumeInformation) == sizeof(WSLCVolumeInformation), "WSLCSDKVolumeInformation and WSLCVolumeInformation layout mismatch"); + RETURN_HR_IF_NULL(E_POINTER, Options); - return CreateVolume(reinterpret_cast(Options), reinterpret_cast(VolumeInfo)); + const auto options = apicompat::Convert(*Options); + + WSLCVolumeInformation info{}; + WSLCVolumeInformation* internalInfo = (VolumeInfo != nullptr) ? &info : nullptr; + RETURN_IF_FAILED(CreateVolume(options.Get(), internalInfo)); + + if (VolumeInfo != nullptr) + { + *VolumeInfo = apicompat::Convert(info); + } + + return S_OK; } +CATCH_RETURN(); -HRESULT WSLCSession::RegisterCrashDumpCallback(IWSLCSDKCrashDumpCallback* Callback, IUnknown** Subscription) +HRESULT WSLCSession::RegisterCrashDumpCallback(IWSLCCompatCrashDumpCallback* Callback, IUnknown** Subscription) { - const auto callback = wslcsdk::WrapCrashDumpCallback(Callback); + const auto callback = apicompat::Convert(Callback); return RegisterCrashDumpCallback(callback.Get(), Subscription); } @@ -2937,12 +3012,14 @@ MultiHandleWait WSLCSession::CreateIOContext(HANDLE CancelHandle) io::MultiHandleWait io; // Cancel with E_ABORT if the session is terminating. - io.AddHandle(std::make_unique( - m_sessionTerminatingEvent.get(), [this]() { THROW_HR_MSG(E_ABORT, "Session %lu is terminating", m_id); })); + io.AddHandle(std::make_unique(m_sessionTerminatingEvent.get(), [this]() { + THROW_HR_MSG(E_ABORT, "Session %lu is terminating", m_id); + })); // Cancel with E_ABORT if the client process exits. - io.AddHandle(std::make_unique( - wslutil::OpenCallingProcess(SYNCHRONIZE), [this]() { THROW_HR_MSG(E_ABORT, "Client process has exited"); })); + io.AddHandle(std::make_unique(wslutil::OpenCallingProcess(SYNCHRONIZE), [this]() { + THROW_HR_MSG(E_ABORT, "Client process has exited"); + })); if (CancelHandle != nullptr) { diff --git a/src/windows/wslcsession/WSLCSession.h b/src/windows/wslcsession/WSLCSession.h index b0ed7914b6..e196eb61e7 100644 --- a/src/windows/wslcsession/WSLCSession.h +++ b/src/windows/wslcsession/WSLCSession.h @@ -15,7 +15,7 @@ Module Name: #pragma once #include "wslc.h" -#include "WSLSDK.h" +#include "WSLCCompat.h" #include "WSLCVirtualMachine.h" #include "WSLCContainer.h" #include "WSLCVolumes.h" @@ -74,7 +74,7 @@ class UserCOMCallback // The SYSTEM service creates the VM and passes IWSLCVirtualMachine to Initialize(). // class DECLSPEC_UUID("4877FEFC-4977-4929-A958-9F36AA1892A4") WSLCSession - : public Microsoft::WRL::RuntimeClass, IWSLCSession, IWSLCSDKSession, IFastRundown, ISupportErrorInfo> + : public Microsoft::WRL::RuntimeClass, IWSLCSession, IWSLCCompatSession, IFastRundown, ISupportErrorInfo> { public: WSLCSession() = default; @@ -194,32 +194,39 @@ class DECLSPEC_UUID("4877FEFC-4977-4929-A958-9F36AA1892A4") WSLCSession IFACEMETHOD(MapVmPort)(_In_ int Family, _In_ unsigned short WindowsPort, _In_ unsigned short LinuxPort) override; IFACEMETHOD(UnmapVmPort)(_In_ int Family, _In_ unsigned short WindowsPort, _In_ unsigned short LinuxPort) override; - // IWSLCSDKSession - converts the WSLCSDK types to the wslc.idl types and forwards to the methods above. + // IWSLCCompatSession - converts the WSLCCompat types to the wslc.idl types and forwards to the methods above. // Methods that have an identical signature in both interfaces (Terminate, DeleteVolume, Authenticate) are // served by the single existing override and require no additional code here. IFACEMETHOD(PullImage)( _In_ LPCSTR Image, _In_opt_ LPCSTR RegistryAuthenticationInformation, - _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, - _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; - IFACEMETHOD(LoadImage)(_In_ WSLCSDKHandle ImageHandle, _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, _In_ ULONGLONG ContentLength, _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; + _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, + _In_opt_ IWSLCCompatWarningCallback* WarningCallback) override; + IFACEMETHOD(LoadImage)( + _In_ WSLCCompatHandle ImageHandle, + _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, + _In_ ULONGLONG ContentLength, + _In_opt_ IWSLCCompatWarningCallback* WarningCallback) override; IFACEMETHOD(ImportImage)( - _In_ WSLCSDKHandle ImageHandle, + _In_ WSLCCompatHandle ImageHandle, _In_ LPCSTR ImageName, - _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, + _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, _In_ ULONGLONG ContentLength, - _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; - IFACEMETHOD(ListImages)(_In_opt_ const WSLCSDKListImagesOptions* Options, _Out_ WSLCSDKImageInformation** Images, _Out_ ULONG* Count) override; - IFACEMETHOD(DeleteImage)(_In_ const WSLCSDKDeleteImageOptions* Options, _Out_ WSLCSDKDeletedImageInformation** DeletedImages, _Out_ ULONG* Count) override; - IFACEMETHOD(TagImage)(_In_ const WSLCSDKTagImageOptions* Options) override; + _In_opt_ IWSLCCompatWarningCallback* WarningCallback) override; + IFACEMETHOD(ListImages)(_In_opt_ const WSLCCompatListImagesOptions* Options, _Out_ WSLCCompatImageInformation** Images, _Out_ ULONG* Count) override; + IFACEMETHOD(DeleteImage)(_In_ const WSLCCompatDeleteImageOptions* Options, _Out_ WSLCCompatDeletedImageInformation** DeletedImages, _Out_ ULONG* Count) override; + IFACEMETHOD(TagImage)(_In_ const WSLCCompatTagImageOptions* Options) override; IFACEMETHOD(PushImage)( _In_ LPCSTR Image, _In_ LPCSTR RegistryAuthenticationInformation, - _In_opt_ IWSLCSDKProgressCallback* ProgressCallback, - _In_opt_ IWSLCSDKWarningCallback* WarningCallback) override; - IFACEMETHOD(CreateContainer)(_In_ const WSLCSDKContainerOptions* Options, _In_opt_ IWSLCSDKWarningCallback* WarningCallback, _Out_ IWSLCSDKContainer** Container) override; - IFACEMETHOD(CreateVolume)(_In_ const WSLCSDKVolumeOptions* Options, _Out_ WSLCSDKVolumeInformation* VolumeInfo) override; - IFACEMETHOD(RegisterCrashDumpCallback)(_In_ IWSLCSDKCrashDumpCallback* Callback, _Out_ IUnknown** Subscription) override; + _In_opt_ IWSLCCompatProgressCallback* ProgressCallback, + _In_opt_ IWSLCCompatWarningCallback* WarningCallback) override; + IFACEMETHOD(CreateContainer)( + _In_ const WSLCCompatContainerOptions* Options, + _In_opt_ IWSLCCompatWarningCallback* WarningCallback, + _Out_ IWSLCCompatContainer** Container) override; + IFACEMETHOD(CreateVolume)(_In_ const WSLCCompatVolumeOptions* Options, _Out_ WSLCCompatVolumeInformation* VolumeInfo) override; + IFACEMETHOD(RegisterCrashDumpCallback)(_In_ IWSLCCompatCrashDumpCallback* Callback, _Out_ IUnknown** Subscription) override; common::io::MultiHandleWait CreateIOContext(HANDLE CancelHandle = nullptr); From 171e71df512bd1d4f5a1fc786b99d382f399cfbf Mon Sep 17 00:00:00 2001 From: Blue Date: Thu, 11 Jun 2026 15:35:25 -0700 Subject: [PATCH 3/6] Save state --- src/windows/common/APICompat.cpp | 69 ++++++++++++++++++++++---------- src/windows/common/APICompat.h | 40 ++++++------------ 2 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/windows/common/APICompat.cpp b/src/windows/common/APICompat.cpp index f886944b96..21876e4210 100644 --- a/src/windows/common/APICompat.cpp +++ b/src/windows/common/APICompat.cpp @@ -14,8 +14,15 @@ namespace { THROW_HR_IF(E_UNEXPECTED, strcpy_s(Destination, Source) != 0); } - // Converts an input array of WSLCCompat elements into a vector of the matching - // wslc.idl elements by converting each element individually. + // Throws E_INVALIDARG if Value contains any bit outside of KnownMask. + template + void ThrowIfUnknownFlags(TValue Value, TMask KnownMask, PCSTR Name) + { + const auto value = static_cast(Value); + const auto mask = static_cast(KnownMask); + THROW_HR_IF_MSG(E_INVALIDARG, (value & ~mask) != 0, "Invalid %hs value: 0x%llx", Name, value); + } + template std::vector ConvertArray(const TIn* Items, ULONG Count) { @@ -34,13 +41,6 @@ namespace { return result; } - // - // In-process adapters that bridge the SDK-facing WSLCCompat callback interfaces to - // the internal wslc.idl callback interfaces. They wrap the SDK's marshaled proxy - // and are only ever invoked in-process, so they do not need to be registered for - // marshaling. - // - class TerminationCallbackAdapter : public Microsoft::WRL::RuntimeClass, ITerminationCallback> { @@ -129,7 +129,7 @@ WSLCFD Convert(WSLCCompatFD Fd) return WSLCFDTty; } - return WSLCFDStdin; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCCompatFD value: %i", static_cast(Fd)); } WSLCSignal Convert(WSLCCompatSignal Signal) @@ -148,7 +148,7 @@ WSLCSignal Convert(WSLCCompatSignal Signal) return WSLCSignalSIGILL; case WSLCCompatSignalSIGTRAP: return WSLCSignalSIGTRAP; - case WSLCCompatSignalSIGABRT: // Equivalent to WSLCCompatSignalSIGIOT. + case WSLCCompatSignalSIGABRT: return WSLCSignalSIGABRT; case WSLCCompatSignalSIGBUS: return WSLCSignalSIGBUS; @@ -194,7 +194,7 @@ WSLCSignal Convert(WSLCCompatSignal Signal) return WSLCSignalSIGPROF; case WSLCCompatSignalSIGWINCH: return WSLCSignalSIGWINCH; - case WSLCCompatSignalSIGIO: // Equivalent to WSLCCompatSignalSIGPOLL. + case WSLCCompatSignalSIGIO: return WSLCSignalSIGIO; case WSLCCompatSignalSIGPWR: return WSLCSignalSIGPWR; @@ -202,11 +202,13 @@ WSLCSignal Convert(WSLCCompatSignal Signal) return WSLCSignalSIGSYS; } - return WSLCSignalNone; + THROW_HR_MSG(E_INVALIDARG, "Invalid Signal value: %i", static_cast(Signal)); } WSLCProcessFlags Convert(WSLCCompatProcessFlags Flags) { + ThrowIfUnknownFlags(Flags, WSLCCompatProcessFlagsStdin | WSLCCompatProcessFlagsTty, "WSLCCompatProcessFlags"); + WSLCProcessFlags result = WSLCProcessFlagsNone; WI_SetFlagIf(result, WSLCProcessFlagsStdin, WI_IsFlagSet(Flags, WSLCCompatProcessFlagsStdin)); WI_SetFlagIf(result, WSLCProcessFlagsTty, WI_IsFlagSet(Flags, WSLCCompatProcessFlagsTty)); @@ -215,6 +217,11 @@ WSLCProcessFlags Convert(WSLCCompatProcessFlags Flags) WSLCContainerFlags Convert(WSLCCompatContainerFlags Flags) { + ThrowIfUnknownFlags( + Flags, + WSLCCompatContainerFlagsRm | WSLCCompatContainerFlagsGpu | WSLCCompatContainerFlagsInit | WSLCCompatContainerFlagsPublishAll, + "WSLCCompatContainerFlags"); + WSLCContainerFlags result = WSLCContainerFlagsNone; WI_SetFlagIf(result, WSLCContainerFlagsRm, WI_IsFlagSet(Flags, WSLCCompatContainerFlagsRm)); WI_SetFlagIf(result, WSLCContainerFlagsGpu, WI_IsFlagSet(Flags, WSLCCompatContainerFlagsGpu)); @@ -225,6 +232,8 @@ WSLCContainerFlags Convert(WSLCCompatContainerFlags Flags) WSLCContainerStartFlags Convert(WSLCCompatContainerStartFlags Flags) { + ThrowIfUnknownFlags(Flags, WSLCCompatContainerStartFlagsAttach, "WSLCCompatContainerStartFlags"); + WSLCContainerStartFlags result = WSLCContainerStartFlagsNone; WI_SetFlagIf(result, WSLCContainerStartFlagsAttach, WI_IsFlagSet(Flags, WSLCCompatContainerStartFlagsAttach)); return result; @@ -232,6 +241,8 @@ WSLCContainerStartFlags Convert(WSLCCompatContainerStartFlags Flags) WSLCDeleteFlags Convert(WSLCCompatDeleteFlags Flags) { + ThrowIfUnknownFlags(Flags, WSLCCompatDeleteFlagsForce | WSLCCompatDeleteFlagsDeleteVolumes, "WSLCCompatDeleteFlags"); + WSLCDeleteFlags result = WSLCDeleteFlagsNone; WI_SetFlagIf(result, WSLCDeleteFlagsForce, WI_IsFlagSet(Flags, WSLCCompatDeleteFlagsForce)); WI_SetFlagIf(result, WSLCDeleteFlagsDeleteVolumes, WI_IsFlagSet(Flags, WSLCCompatDeleteFlagsDeleteVolumes)); @@ -250,11 +261,17 @@ WSLCNetworkingMode Convert(WSLCCompatNetworkingMode Mode) return WSLCNetworkingModeVirtioProxy; } - return WSLCNetworkingModeNone; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCCompatNetworkingMode value: %i", static_cast(Mode)); } WSLCFeatureFlags Convert(WSLCCompatFeatureFlags Flags) { + ThrowIfUnknownFlags( + Flags, + WSLCCompatFeatureFlagsDnsTunneling | WSLCCompatFeatureFlagsEarlyBootDmesg | WSLCCompatFeatureFlagsGPU | + WSLCCompatFeatureFlagsVirtioFs | WSLCCompatFeatureFlagsDebug, + "WSLCCompatFeatureFlags"); + WSLCFeatureFlags result = WslcFeatureFlagsNone; WI_SetFlagIf(result, WslcFeatureFlagsDnsTunneling, WI_IsFlagSet(Flags, WSLCCompatFeatureFlagsDnsTunneling)); WI_SetFlagIf(result, WslcFeatureFlagsEarlyBootDmesg, WI_IsFlagSet(Flags, WSLCCompatFeatureFlagsEarlyBootDmesg)); @@ -266,6 +283,8 @@ WSLCFeatureFlags Convert(WSLCCompatFeatureFlags Flags) WSLCSessionStorageFlags Convert(WSLCCompatSessionStorageFlags Flags) { + ThrowIfUnknownFlags(Flags, WSLCCompatSessionStorageFlagsNoCreate, "WSLCCompatSessionStorageFlags"); + WSLCSessionStorageFlags result = WSLCSessionStorageFlagsNone; WI_SetFlagIf(result, WSLCSessionStorageFlagsNoCreate, WI_IsFlagSet(Flags, WSLCCompatSessionStorageFlagsNoCreate)); return result; @@ -273,6 +292,8 @@ WSLCSessionStorageFlags Convert(WSLCCompatSessionStorageFlags Flags) WSLCSessionFlags Convert(WSLCCompatSessionFlags Flags) { + ThrowIfUnknownFlags(Flags, WSLCCompatSessionFlagsPersistent | WSLCCompatSessionFlagsOpenExisting, "WSLCCompatSessionFlags"); + WSLCSessionFlags result = WSLCSessionFlagsNone; WI_SetFlagIf(result, WSLCSessionFlagsPersistent, WI_IsFlagSet(Flags, WSLCCompatSessionFlagsPersistent)); WI_SetFlagIf(result, WSLCSessionFlagsOpenExisting, WI_IsFlagSet(Flags, WSLCCompatSessionFlagsOpenExisting)); @@ -293,7 +314,7 @@ WSLCHandleType Convert(WSLCCompatHandleType Type) return WSLCHandleTypeSocket; } - return WSLCHandleTypeUnknown; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCCompatHandleType value: %i", static_cast(Type)); } WSLCCompatProcessState Convert(WSLCProcessState State) @@ -310,7 +331,7 @@ WSLCCompatProcessState Convert(WSLCProcessState State) return WSLCCompatProcessStateSignalled; } - return WSLCCompatProcessStateUnknown; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCProcessState value: %i", static_cast(State)); } WSLCCompatContainerState Convert(WSLCContainerState State) @@ -329,7 +350,7 @@ WSLCCompatContainerState Convert(WSLCContainerState State) return WSLCCompatContainerStateDeleted; } - return WSLCCompatContainerStateInvalid; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCContainerState value: %i", static_cast(State)); } WSLCCompatVirtualMachineTerminationReason Convert(WSLCVirtualMachineTerminationReason Reason) @@ -344,7 +365,7 @@ WSLCCompatVirtualMachineTerminationReason Convert(WSLCVirtualMachineTerminationR return WSLCCompatVirtualMachineTerminationReasonCrashed; } - return WSLCCompatVirtualMachineTerminationReasonUnknown; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCVirtualMachineTerminationReason value: %i", static_cast(Reason)); } WSLCCompatHandleType Convert(WSLCHandleType Type) @@ -361,7 +382,7 @@ WSLCCompatHandleType Convert(WSLCHandleType Type) return WSLCCompatHandleTypeSocket; } - return WSLCCompatHandleTypeUnknown; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCHandleType value: %i", static_cast(Type)); } WSLCCompatDeletedImageType Convert(WSLCDeletedImageType Type) @@ -374,7 +395,7 @@ WSLCCompatDeletedImageType Convert(WSLCDeletedImageType Type) return WSLCCompatDeletedImageTypeUntagged; } - return WSLCCompatDeletedImageTypeDeleted; + THROW_HR_MSG(E_INVALIDARG, "Invalid WSLCDeletedImageType value: %i", static_cast(Type)); } // @@ -518,6 +539,9 @@ WSLCUlimit Convert(const WSLCCompatUlimit& Ulimit) WSLCDeleteImageOptions Convert(const WSLCCompatDeleteImageOptions& Options) { + ThrowIfUnknownFlags( + Options.Flags, WSLCCompatDeleteImageFlagsForce | WSLCCompatDeleteImageFlagsNoPrune, "WSLCCompatDeleteImageFlags"); + WSLCDeleteImageOptions result{}; result.Image = Options.Image; result.Flags = Options.Flags; @@ -633,6 +657,9 @@ ContainerOptionsConversion::ContainerOptionsConversion(const WSLCCompatContainer ListImagesOptionsConversion::ListImagesOptionsConversion(const WSLCCompatListImagesOptions& Options) { + ThrowIfUnknownFlags( + Options.Flags, WSLCCompatListImagesFlagsAll | WSLCCompatListImagesFlagsDigests, "WSLCCompatListImagesFlags"); + // Flags is a DWORD bitmask with identical bit meanings in both contracts. m_value.Flags = Options.Flags; @@ -665,8 +692,6 @@ SessionSettingsConversion::SessionSettingsConversion(const WSLCCompatSessionSett m_value.BootTimeoutMs = Settings.BootTimeoutMs; m_value.NetworkingMode = Convert(Settings.NetworkingMode); - // The factory deep-copies (AddRefs) the termination callback synchronously - // during CreateSession, so the adapter held here outlives the call. m_terminationCallback = Convert(Settings.TerminationCallback); m_value.TerminationCallback = m_terminationCallback.Get(); diff --git a/src/windows/common/APICompat.h b/src/windows/common/APICompat.h index 39012db265..cb6bf9f737 100644 --- a/src/windows/common/APICompat.h +++ b/src/windows/common/APICompat.h @@ -1,20 +1,16 @@ -// Copyright (C) Microsoft Corporation. All rights reserved. +/*++ -// -// Conversion helpers that bridge the SDK-facing WSLCCompat COM contract (declared -// in WSLCCompat.idl) and the internal wslc.idl contract. -// -// The two contracts are intentionally decoupled: WSLCCompat.idl must stay -// backwards compatible, while wslc.idl can change freely. Because of that, the -// two sets of types are never assumed to share the same layout. Every -// conversion below copies field by field instead of casting between the two -// representations. -// -// The service classes (WSLCSessionManager, WSLCSession, WSLCContainer, -// WSLCProcess) implement the IWSLCCompat* interfaces by converting the WSLCCompat -// types into the wslc.idl types with the overloaded Convert() functions here -// and then forwarding to the existing wslc.idl based implementations. -// +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + APICompat.h + +Abstract: + + API compatibility layer between the wslc.idl and wslccompat.idl. + +--*/ #pragma once @@ -49,13 +45,6 @@ WSLCCompatVirtualMachineTerminationReason Convert(WSLCVirtualMachineTerminationR WSLCCompatHandleType Convert(WSLCHandleType Type); WSLCCompatDeletedImageType Convert(WSLCDeletedImageType Type); -// -// Scalar / non-owning struct conversions. The returned struct copies any -// pointer fields straight from the input, so it stays valid only as long as the -// input (and the buffers it points at) remain alive. They are meant to be used -// for the duration of a single forwarded call. -// - // Forward (WSLCCompat -> wslc.idl). WSLCVersion Convert(const WSLCCompatVersion& Version); WSLCHandle Convert(const WSLCCompatHandle& Handle); @@ -185,10 +174,7 @@ inline SessionSettingsConversion Convert(const WSLCCompatSessionSettings& Settin } // -// Callback conversions. Wrap the SDK callback object in an in-process adapter -// that implements the matching wslc.idl callback interface, or return a null -// ComPtr when the SDK callback is null. -// +// Callback conversions. Microsoft::WRL::ComPtr Convert(IWSLCCompatTerminationCallback* Callback); Microsoft::WRL::ComPtr Convert(IWSLCCompatCrashDumpCallback* Callback); From ce4c538e1185422726edfdc2fb49add3255e1d98 Mon Sep 17 00:00:00 2001 From: Blue Date: Thu, 11 Jun 2026 17:06:24 -0700 Subject: [PATCH 4/6] Cleanup --- src/windows/common/APICompat.cpp | 43 +++++++++++++------ src/windows/common/APICompat.h | 8 ++-- .../service/exe/WSLCSessionManager.cpp | 17 ++------ src/windows/service/exe/WSLCSessionManager.h | 1 - src/windows/service/inc/wslc.idl | 2 - src/windows/wslcsession/WSLCContainer.cpp | 26 +++++------ src/windows/wslcsession/WSLCSession.cpp | 38 +++++++--------- test/windows/WSLCTests.cpp | 11 ++--- test/windows/WslcSdkWinRTTests.cpp | 3 +- 9 files changed, 71 insertions(+), 78 deletions(-) diff --git a/src/windows/common/APICompat.cpp b/src/windows/common/APICompat.cpp index 21876e4210..c83c26a6b4 100644 --- a/src/windows/common/APICompat.cpp +++ b/src/windows/common/APICompat.cpp @@ -300,6 +300,26 @@ WSLCSessionFlags Convert(WSLCCompatSessionFlags Flags) return result; } +WSLCListImagesFlags Convert(WSLCCompatListImagesFlags Flags) +{ + ThrowIfUnknownFlags(Flags, WSLCCompatListImagesFlagsAll | WSLCCompatListImagesFlagsDigests, "WSLCCompatListImagesFlags"); + + WSLCListImagesFlags result = WSLCListImagesFlagsNone; + WI_SetFlagIf(result, WSLCListImagesFlagsAll, WI_IsFlagSet(Flags, WSLCCompatListImagesFlagsAll)); + WI_SetFlagIf(result, WSLCListImagesFlagsDigests, WI_IsFlagSet(Flags, WSLCCompatListImagesFlagsDigests)); + return result; +} + +WSLCDeleteImageFlags Convert(WSLCCompatDeleteImageFlags Flags) +{ + ThrowIfUnknownFlags(Flags, WSLCCompatDeleteImageFlagsForce | WSLCCompatDeleteImageFlagsNoPrune, "WSLCCompatDeleteImageFlags"); + + WSLCDeleteImageFlags result = WSLCDeleteImageFlagsNone; + WI_SetFlagIf(result, WSLCDeleteImageFlagsForce, WI_IsFlagSet(Flags, WSLCCompatDeleteImageFlagsForce)); + WI_SetFlagIf(result, WSLCDeleteImageFlagsNoPrune, WI_IsFlagSet(Flags, WSLCCompatDeleteImageFlagsNoPrune)); + return result; +} + WSLCHandleType Convert(WSLCCompatHandleType Type) { switch (Type) @@ -539,12 +559,9 @@ WSLCUlimit Convert(const WSLCCompatUlimit& Ulimit) WSLCDeleteImageOptions Convert(const WSLCCompatDeleteImageOptions& Options) { - ThrowIfUnknownFlags( - Options.Flags, WSLCCompatDeleteImageFlagsForce | WSLCCompatDeleteImageFlagsNoPrune, "WSLCCompatDeleteImageFlags"); - WSLCDeleteImageOptions result{}; result.Image = Options.Image; - result.Flags = Options.Flags; + result.Flags = static_cast(Convert(static_cast(Options.Flags))); return result; } @@ -622,17 +639,21 @@ ContainerOptionsConversion::ContainerOptionsConversion(const WSLCCompatContainer // Container network (nested arrays whose elements have their own arrays). m_value.ContainerNetwork.NetworkMode = Options.ContainerNetwork.NetworkMode; const ULONG networksCount = Options.ContainerNetwork.NetworksCount; + THROW_HR_IF(E_INVALIDARG, networksCount > 0 && Options.ContainerNetwork.Networks == nullptr); + m_networks.reserve(networksCount); m_networkSettings.reserve(networksCount); for (ULONG index = 0; index < networksCount; index++) { - const auto& sourceConnection = Options.ContainerNetwork.Networks[index]; - m_networkSettings.push_back(ConvertArray(sourceConnection.Settings, sourceConnection.SettingsCount)); + const auto& network = Options.ContainerNetwork.Networks[index]; + THROW_HR_IF(E_INVALIDARG, network.SettingsCount > 0 && network.Settings == nullptr); + + m_networkSettings.push_back(ConvertArray(network.Settings, network.SettingsCount)); WSLCNetworkConnection connection{}; - connection.NetworkName = sourceConnection.NetworkName; + connection.NetworkName = network.NetworkName; connection.Settings = m_networkSettings.back().empty() ? nullptr : m_networkSettings.back().data(); - connection.SettingsCount = sourceConnection.SettingsCount; + connection.SettingsCount = network.SettingsCount; m_networks.push_back(connection); } @@ -657,11 +678,7 @@ ContainerOptionsConversion::ContainerOptionsConversion(const WSLCCompatContainer ListImagesOptionsConversion::ListImagesOptionsConversion(const WSLCCompatListImagesOptions& Options) { - ThrowIfUnknownFlags( - Options.Flags, WSLCCompatListImagesFlagsAll | WSLCCompatListImagesFlagsDigests, "WSLCCompatListImagesFlags"); - - // Flags is a DWORD bitmask with identical bit meanings in both contracts. - m_value.Flags = Options.Flags; + m_value.Flags = static_cast(Convert(static_cast(Options.Flags))); m_filters = ConvertArray(Options.Filters, Options.FiltersCount); m_value.Filters = m_filters.empty() ? nullptr : m_filters.data(); diff --git a/src/windows/common/APICompat.h b/src/windows/common/APICompat.h index cb6bf9f737..c3811652fa 100644 --- a/src/windows/common/APICompat.h +++ b/src/windows/common/APICompat.h @@ -36,6 +36,8 @@ WSLCNetworkingMode Convert(WSLCCompatNetworkingMode Mode); WSLCFeatureFlags Convert(WSLCCompatFeatureFlags Flags); WSLCSessionStorageFlags Convert(WSLCCompatSessionStorageFlags Flags); WSLCSessionFlags Convert(WSLCCompatSessionFlags Flags); +WSLCListImagesFlags Convert(WSLCCompatListImagesFlags Flags); +WSLCDeleteImageFlags Convert(WSLCCompatDeleteImageFlags Flags); WSLCHandleType Convert(WSLCCompatHandleType Type); // Reverse (wslc.idl -> WSLCCompat). @@ -67,10 +69,7 @@ WSLCCompatDeletedImageInformation Convert(const WSLCDeletedImageInformation& Ima WSLCCompatVolumeInformation Convert(const WSLCVolumeInformation& Volume); // -// Composite struct conversions. These contain nested arrays whose element types -// differ between the two contracts, so the converted struct owns backing -// storage that must outlive the forwarded call. Construct the conversion as a -// local and pass Get() to the wslc.idl method. +// Composite struct conversions. // class ContainerOptionsConversion @@ -175,6 +174,7 @@ inline SessionSettingsConversion Convert(const WSLCCompatSessionSettings& Settin // // Callback conversions. +// Microsoft::WRL::ComPtr Convert(IWSLCCompatTerminationCallback* Callback); Microsoft::WRL::ComPtr Convert(IWSLCCompatCrashDumpCallback* Callback); diff --git a/src/windows/service/exe/WSLCSessionManager.cpp b/src/windows/service/exe/WSLCSessionManager.cpp index 31dfddee44..5d275217ab 100644 --- a/src/windows/service/exe/WSLCSessionManager.cpp +++ b/src/windows/service/exe/WSLCSessionManager.cpp @@ -286,9 +286,8 @@ void WSLCSessionManagerImpl::CreateSession( THROW_IF_FAILED(factory->CreateSession(&sessionSettings, vmFactory.Get(), notifier.Get(), WarningCallback, &session, &serviceRef)); // Track the session via its service ref, along with metadata and security info. - m_sessions.push_back( - SessionEntry{ - std::move(serviceRef), sessionId, creatorPid, resolvedDisplayName, std::move(tokenInfo), notifier, false, sharedToken, std::move(storedSid), std::move(sessionJob)}); + m_sessions.push_back(SessionEntry{ + std::move(serviceRef), sessionId, creatorPid, resolvedDisplayName, std::move(tokenInfo), notifier, false, sharedToken, std::move(storedSid), std::move(sessionJob)}); // For persistent sessions, also hold a strong reference to keep them alive. const bool persistent = WI_IsFlagSet(Flags, WSLCSessionFlagsPersistent); @@ -544,7 +543,7 @@ try } CATCH_RETURN(); -HRESULT WSLCSessionManager::IsClientVersionSupported(_In_ const WSLCVersion* ClientVersion, _Out_ BOOL* IsSupported) +HRESULT WSLCSessionManager::IsClientVersionSupported(_In_ const WSLCCompatVersion* ClientVersion, _Out_ BOOL* IsSupported) try { RETURN_HR_IF(E_POINTER, ClientVersion == nullptr || IsSupported == nullptr); @@ -617,16 +616,6 @@ try } CATCH_RETURN(); -HRESULT WSLCSessionManager::IsClientVersionSupported(_In_ const WSLCCompatVersion* ClientVersion, _Out_ BOOL* IsSupported) -try -{ - RETURN_HR_IF_NULL(E_POINTER, ClientVersion); - - const auto clientVersion = apicompat::Convert(*ClientVersion); - return IsClientVersionSupported(&clientVersion, IsSupported); -} -CATCH_RETURN(); - HRESULT WSLCSessionManager::CreateSession( const WSLCCompatSessionSettings* Settings, WSLCCompatSessionFlags Flags, IWSLCCompatWarningCallback* WarningCallback, IWSLCCompatSession** Session) try diff --git a/src/windows/service/exe/WSLCSessionManager.h b/src/windows/service/exe/WSLCSessionManager.h index ecb049999f..cd2c2afe18 100644 --- a/src/windows/service/exe/WSLCSessionManager.h +++ b/src/windows/service/exe/WSLCSessionManager.h @@ -198,7 +198,6 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce8f") WSLCSessionManager WSLCSessionManager(wsl::windows::service::wslc::WSLCSessionManagerImpl* Impl); IFACEMETHOD(GetVersion)(_Out_ WSLCVersion* Version) override; - IFACEMETHOD(IsClientVersionSupported)(_In_ const WSLCVersion* ClientVersion, _Out_ BOOL* IsSupported) override; IFACEMETHOD(CreateSession)( const WSLCSessionSettings* WslcSessionSettings, WSLCSessionFlags Flags, IWarningCallback* WarningCallback, IWSLCSession** WslcSession) override; IFACEMETHOD(EnterSession)(_In_ LPCWSTR DisplayName, _In_ LPCWSTR StoragePath, IWarningCallback* WarningCallback, IWSLCSession** WslcSession) override; diff --git a/src/windows/service/inc/wslc.idl b/src/windows/service/inc/wslc.idl index f7e8e8fffc..425ee07467 100644 --- a/src/windows/service/inc/wslc.idl +++ b/src/windows/service/inc/wslc.idl @@ -924,8 +924,6 @@ cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(WSLCSessionFlags);") interface IWSLCSessionManager : IUnknown { HRESULT GetVersion([out] WSLCVersion* Version); - HRESULT IsClientVersionSupported([in] const WSLCVersion* ClientVersion, [out] BOOL* IsSupported); - // Session management. HRESULT CreateSession([in, unique] const WSLCSessionSettings* Settings, WSLCSessionFlags Flags, [in, unique] IWarningCallback* WarningCallback, [out] IWSLCSession** Session); HRESULT EnterSession([in, ref] LPCWSTR DisplayName, [in, ref] LPCWSTR StoragePath, [in, unique] IWarningCallback* WarningCallback, [out] IWSLCSession** Session); diff --git a/src/windows/wslcsession/WSLCContainer.cpp b/src/windows/wslcsession/WSLCContainer.cpp index c309e87ba2..91814e6ef1 100644 --- a/src/windows/wslcsession/WSLCContainer.cpp +++ b/src/windows/wslcsession/WSLCContainer.cpp @@ -295,9 +295,8 @@ void UnmountVolumes(std::vector& volumes, WSLCVirtualMachine& p else { LOG_HR(result); - EMIT_USER_WARNING( - wsl::shared::Localization::MessageWslcVolumeUnmountFailed( - volume.HostPath, wsl::windows::common::wslutil::GetErrorString(result))); + EMIT_USER_WARNING(wsl::shared::Localization::MessageWslcVolumeUnmountFailed( + volume.HostPath, wsl::windows::common::wslutil::GetErrorString(result))); } } } @@ -682,9 +681,8 @@ void WSLCContainerImpl::Attach(LPCSTR DetachKeys, WSLCHandle* Stdin, WSLCHandle* handles.emplace_back( std::make_unique>(HandleWrapper{std::move(stdinRead), std::move(onInputComplete)}, ioHandle.get())); - handles.emplace_back( - std::make_unique( - std::move(ioHandle), std::move(stdoutWrite), std::move(stderrWrite), DockerIORelayHandle::Format::Raw)); + handles.emplace_back(std::make_unique( + std::move(ioHandle), std::move(stdoutWrite), std::move(stderrWrite), DockerIORelayHandle::Format::Raw)); m_ioRelay.AddHandles(std::move(handles)); @@ -798,8 +796,8 @@ void WSLCContainerImpl::Start(WSLCContainerStartFlags Flags, const WSLCProcessSt catch (...) { LOG_CAUGHT_EXCEPTION(); - EMIT_USER_WARNING( - wsl::shared::Localization::MessageWslcContainerStopAfterPluginRejectionFailed(wsl::shared::string::MultiByteToWide(m_id))); + EMIT_USER_WARNING(wsl::shared::Localization::MessageWslcContainerStopAfterPluginRejectionFailed( + wsl::shared::string::MultiByteToWide(m_id))); } if (comError.has_value() && comError->Message) @@ -1817,9 +1815,8 @@ std::unique_ptr WSLCContainerImpl::Open( catch (...) { LOG_CAUGHT_EXCEPTION(); - EMIT_USER_WARNING( - wsl::shared::Localization::MessageWslcContainerTimestampRecoveryFailed( - wsl::shared::string::MultiByteToWide(dockerContainer.Id))); + EMIT_USER_WARNING(wsl::shared::Localization::MessageWslcContainerTimestampRecoveryFailed( + wsl::shared::string::MultiByteToWide(dockerContainer.Id))); } return container; @@ -1940,9 +1937,8 @@ std::unique_ptr WSLCContainerImpl::CreateRelayedProcessIO(wil: fds.emplace(WSLCFDStdout, TypedHandle{wil::unique_handle{stdoutRead.release()}, WSLCHandleTypePipe}); fds.emplace(WSLCFDStderr, TypedHandle{wil::unique_handle{stderrRead.release()}, WSLCHandleTypePipe}); - ioHandles.emplace_back( - std::make_unique( - std::move(stream), std::move(stdoutWrite), std::move(stderrWrite), common::io::DockerIORelayHandle::Format::Raw)); + ioHandles.emplace_back(std::make_unique( + std::move(stream), std::move(stdoutWrite), std::move(stderrWrite), common::io::DockerIORelayHandle::Format::Raw)); m_ioRelay.AddHandles(std::move(ioHandles)); @@ -2464,7 +2460,7 @@ CATCH_RETURN(); HRESULT WSLCContainer::InterfaceSupportsErrorInfo(REFIID riid) { - return riid == __uuidof(IWSLCContainer) ? S_OK : S_FALSE; + return riid == __uuidof(IWSLCContainer) || riid == __uuidof(IWSLCCompatContainer) ? S_OK : S_FALSE; } HRESULT WSLCContainer::Stop(WSLCCompatSignal Signal, LONG TimeoutSeconds) diff --git a/src/windows/wslcsession/WSLCSession.cpp b/src/windows/wslcsession/WSLCSession.cpp index 602ed43ffd..4493b5e8ca 100644 --- a/src/windows/wslcsession/WSLCSession.cpp +++ b/src/windows/wslcsession/WSLCSession.cpp @@ -555,13 +555,11 @@ ServiceRunningProcess WSLCSession::StartProcess( auto process = launcher.Launch(*m_virtualMachine); - m_ioRelay.AddHandle( - std::make_unique( - process.GetStdHandle(1), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); + m_ioRelay.AddHandle(std::make_unique( + process.GetStdHandle(1), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); - m_ioRelay.AddHandle( - std::make_unique( - process.GetStdHandle(2), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); + m_ioRelay.AddHandle(std::make_unique( + process.GetStdHandle(2), [this, LogSource](const auto& data) { OnProcessLog(data, LogSource); }, false)); m_ioRelay.AddHandle(std::make_unique(process.GetExitEvent(), std::move(ExitCallback))); @@ -671,9 +669,8 @@ void WSLCSession::StreamImageOperation(DockerHTTPClient::HTTPRequestContext& req auto onCompleted = [&]() { io.Cancel(); }; - io.AddHandle( - std::make_unique( - requestContext, std::move(onHttpResponse), std::move(onChunk), std::move(onCompleted))); + io.AddHandle(std::make_unique( + requestContext, std::move(onHttpResponse), std::move(onChunk), std::move(onCompleted))); io.Run({}); @@ -845,9 +842,8 @@ try auto io = CreateIOContext(); - io.AddHandle( - std::make_unique>( - buildFileHandle.Get(), common::io::HandleWrapper{buildProcess.GetStdHandle(WSLCFDStdin)})); + io.AddHandle(std::make_unique>( + buildFileHandle.Get(), common::io::HandleWrapper{buildProcess.GetStdHandle(WSLCFDStdin)})); bool verbose = WI_IsFlagSet(Options->Flags, WSLCBuildImageFlagsVerbose); std::string allOutput; @@ -1216,10 +1212,8 @@ void WSLCSession::ImportImageImpl(DockerHTTPClient::HTTPRequestContext& Request, LOG_LAST_ERROR_IF(shutdown(socket, SD_SEND) == SOCKET_ERROR); }; - io.AddHandle( - std::make_unique>( - common::io::HandleWrapper{userHandle.Get(), std::move(onInputComplete)}, - common::io::HandleWrapper{Request.stream.native_handle()})); + io.AddHandle(std::make_unique>( + common::io::HandleWrapper{userHandle.Get(), std::move(onInputComplete)}, common::io::HandleWrapper{Request.stream.native_handle()})); io.AddHandle( std::make_unique(Request, std::move(onHttpResponse), std::move(onProgress)), @@ -2837,7 +2831,7 @@ CATCH_RETURN(); HRESULT WSLCSession::InterfaceSupportsErrorInfo(REFIID riid) { - return riid == __uuidof(IWSLCSession) ? S_OK : S_FALSE; + return riid == __uuidof(IWSLCSession) || riid == __uuidof(IWSLCCompatSession) ? S_OK : S_FALSE; } HRESULT WSLCSession::PullImage(LPCSTR Image, LPCSTR RegistryAuthenticationInformation, IWSLCCompatProgressCallback* ProgressCallback, IWSLCCompatWarningCallback* WarningCallback) @@ -3012,14 +3006,12 @@ MultiHandleWait WSLCSession::CreateIOContext(HANDLE CancelHandle) io::MultiHandleWait io; // Cancel with E_ABORT if the session is terminating. - io.AddHandle(std::make_unique(m_sessionTerminatingEvent.get(), [this]() { - THROW_HR_MSG(E_ABORT, "Session %lu is terminating", m_id); - })); + io.AddHandle(std::make_unique( + m_sessionTerminatingEvent.get(), [this]() { THROW_HR_MSG(E_ABORT, "Session %lu is terminating", m_id); })); // Cancel with E_ABORT if the client process exits. - io.AddHandle(std::make_unique(wslutil::OpenCallingProcess(SYNCHRONIZE), [this]() { - THROW_HR_MSG(E_ABORT, "Client process has exited"); - })); + io.AddHandle(std::make_unique( + wslutil::OpenCallingProcess(SYNCHRONIZE), [this]() { THROW_HR_MSG(E_ABORT, "Client process has exited"); })); if (CancelHandle != nullptr) { diff --git a/test/windows/WSLCTests.cpp b/test/windows/WSLCTests.cpp index 1bbe99f07d..5c36c1ac48 100644 --- a/test/windows/WSLCTests.cpp +++ b/test/windows/WSLCTests.cpp @@ -15,6 +15,7 @@ Module Name: #include "precomp.h" #include "Common.h" #include "wslc.h" +#include "wslccompat.h" #include "WSLCProcessLauncher.h" #include "WSLCContainerLauncher.h" #include "WslCoreFilesystem.h" @@ -235,23 +236,23 @@ class WSLCTests WSLC_TEST_METHOD(IsClientVersionSupported) { - wil::com_ptr sessionManager; - VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager))); + wil::com_ptr sessionManager; + VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(IWSLCCompatSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager))); BOOL isSupported = FALSE; // The current version should always be supported. - const WSLCVersion currentVersion{WSL_PACKAGE_VERSION_MAJOR, WSL_PACKAGE_VERSION_MINOR, WSL_PACKAGE_VERSION_REVISION}; + const WSLCCompatVersion currentVersion{WSL_PACKAGE_VERSION_MAJOR, WSL_PACKAGE_VERSION_MINOR, WSL_PACKAGE_VERSION_REVISION}; VERIFY_SUCCEEDED(sessionManager->IsClientVersionSupported(¤tVersion, &isSupported)); VERIFY_IS_TRUE(isSupported); // A very old version should not be supported. - const WSLCVersion oldVersion{1, 0, 0}; + const WSLCCompatVersion oldVersion{1, 0, 0}; VERIFY_SUCCEEDED(sessionManager->IsClientVersionSupported(&oldVersion, &isSupported)); VERIFY_IS_FALSE(isSupported); // A very high version should be supported. - const WSLCVersion futureVersion{99, 0, 0}; + const WSLCCompatVersion futureVersion{99, 0, 0}; VERIFY_SUCCEEDED(sessionManager->IsClientVersionSupported(&futureVersion, &isSupported)); VERIFY_IS_TRUE(isSupported); } diff --git a/test/windows/WslcSdkWinRTTests.cpp b/test/windows/WslcSdkWinRTTests.cpp index fbcfedeaae..496ba25d6f 100644 --- a/test/windows/WslcSdkWinRTTests.cpp +++ b/test/windows/WslcSdkWinRTTests.cpp @@ -185,7 +185,8 @@ class WslcSdkWinRtTests launcher.AddPort(port, port, AF_INET); // Get the IWSLCSession COM object from the SDK session handle. - auto comSession = reinterpret_cast(WSLCSDK::implementation::GetHandle(m_defaultSession))->session.query(); + auto comSession = + reinterpret_cast(WSLCSDK::implementation::GetHandle(m_defaultSession))->session.query(); auto container = launcher.Launch(*comSession, WSLCContainerStartFlagsNone); auto registryAddress = std::format("127.0.0.1:{}", port); From f526dff12804ccb0f6426deda33a7c16664daa55 Mon Sep 17 00:00:00 2001 From: Blue Date: Thu, 11 Jun 2026 17:13:36 -0700 Subject: [PATCH 5/6] Cleanup --- src/windows/service/inc/WSLCCompat.idl | 6 ++---- src/windows/service/inc/wslc.idl | 5 +---- test/windows/WSLCTests.cpp | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/windows/service/inc/WSLCCompat.idl b/src/windows/service/inc/WSLCCompat.idl index d9937e5b6d..075b6c5855 100644 --- a/src/windows/service/inc/WSLCCompat.idl +++ b/src/windows/service/inc/WSLCCompat.idl @@ -17,10 +17,8 @@ import "unknwn.idl"; import "wtypes.idl"; cpp_quote("#ifdef __cplusplus") -cpp_quote("#ifndef WSLC_SESSIONMANAGER_COCLASS_DECLARED") -cpp_quote("#define WSLC_SESSIONMANAGER_COCLASS_DECLARED") -cpp_quote("class DECLSPEC_UUID(\"a9b7a1b9-0671-405c-95f1-e0612cb4ce8f\") WSLCSessionManager;") -cpp_quote("#endif") +cpp_quote("class DECLSPEC_UUID(\"a9b7a1b9-0671-405c-95f1-e0612cb4ce8f\") WSLCCompatSessionManager;") +cpp_quote("class DECLSPEC_UUID(\"9fcd2067-9fc6-4efa-9eb0-698169ebf7d3\") WSLCCompatSessionManagerFactory;") cpp_quote("#endif") #define WSLCCompat_MAX_IMAGE_NAME_LENGTH 255 diff --git a/src/windows/service/inc/wslc.idl b/src/windows/service/inc/wslc.idl index 425ee07467..ba3073372a 100644 --- a/src/windows/service/inc/wslc.idl +++ b/src/windows/service/inc/wslc.idl @@ -18,11 +18,8 @@ import "unknwn.idl"; import "wtypes.idl"; cpp_quote("#ifdef __cplusplus") -cpp_quote("#ifndef WSLC_SESSIONMANAGER_COCLASS_DECLARED") -cpp_quote("#define WSLC_SESSIONMANAGER_COCLASS_DECLARED") cpp_quote("class DECLSPEC_UUID(\"a9b7a1b9-0671-405c-95f1-e0612cb4ce8f\") WSLCSessionManager;") -cpp_quote("#endif") -cpp_quote("class DECLSPEC_UUID(\"9FCD2067-9FC6-4EFA-9EB0-698169EBF7D3\") WSLCSessionFactory;") +cpp_quote("class DECLSPEC_UUID(\"9fcd2067-9fc6-4efa-9eb0-698169ebf7d3\") WSLCSessionFactory;") cpp_quote("#endif") #define WSLC_MAX_CONTAINER_NAME_LENGTH 255 diff --git a/test/windows/WSLCTests.cpp b/test/windows/WSLCTests.cpp index 5c36c1ac48..0b45bec465 100644 --- a/test/windows/WSLCTests.cpp +++ b/test/windows/WSLCTests.cpp @@ -237,7 +237,7 @@ class WSLCTests WSLC_TEST_METHOD(IsClientVersionSupported) { wil::com_ptr sessionManager; - VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(IWSLCCompatSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager))); + VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager))); BOOL isSupported = FALSE; From 4106df98dbc5fdf3e0d3897a8eca0697bba688f3 Mon Sep 17 00:00:00 2001 From: Blue Date: Thu, 11 Jun 2026 17:24:08 -0700 Subject: [PATCH 6/6] Cleanup --- src/windows/WslcSDK/wslcsdk.cpp | 42 ++++--------------- .../service/exe/WSLCSessionManager.cpp | 2 - src/windows/service/exe/WSLCSessionManager.h | 2 +- src/windows/wslcsession/WSLCContainer.h | 2 +- src/windows/wslcsession/WSLCSession.cpp | 20 ++++----- 5 files changed, 18 insertions(+), 50 deletions(-) diff --git a/src/windows/WslcSDK/wslcsdk.cpp b/src/windows/WslcSDK/wslcsdk.cpp index 5ab3ce5353..6299426e32 100644 --- a/src/windows/WslcSDK/wslcsdk.cpp +++ b/src/windows/WslcSDK/wslcsdk.cpp @@ -22,6 +22,7 @@ Module Name: #include "Localization.h" #include "WslInstall.h" #include "wslutil.h" +#include "APICompat.h" #include "WindowsUpdateIntegration.h" using namespace std::string_view_literals; @@ -1380,46 +1381,17 @@ try } CATCH_RETURN(); -static WSLCCompatHandle ToWSLCCompatInputHandle(HANDLE Handle) -{ - const auto type = GetFileType(Handle); - if (type == FILE_TYPE_PIPE) - { - int socketType{}; - int len = sizeof(socketType); - - // N.B. FILE_TYPE_PIPE can describe a pipe, a named pipe, or a socket. - // Check for a named pipe first, since getsockopt() can return success for a named pipe. - if (GetNamedPipeInfo(Handle, nullptr, nullptr, nullptr, nullptr)) - { - return WSLCCompatHandle{.Type = WSLCCompatHandleTypePipe, .Handle = {.Pipe = Handle}}; - } - else if (getsockopt(reinterpret_cast(Handle), SOL_SOCKET, SO_TYPE, reinterpret_cast(&socketType), &len) == 0) - { - return WSLCCompatHandle{.Type = WSLCCompatHandleTypeSocket, .Handle = {.Socket = Handle}}; - } - else - { - return WSLCCompatHandle{.Type = WSLCCompatHandleTypePipe, .Handle = {.Pipe = Handle}}; - } - } - else if (type == FILE_TYPE_DISK) - { - return WSLCCompatHandle{.Type = WSLCCompatHandleTypeFile, .Handle = {.File = Handle}}; - } - else - { - THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported handle type: %d", type); - } -} - static HRESULT WslcImportSessionImageImpl( WslcSessionImpl* internalSession, PCSTR imageName, const WslcImportImageOptions* options, ErrorInfoWrapper& errorInfoWrapper, const ImageFileResolver& imageFile) { auto progressCallback = ProgressCallback::CreateIf(options); return errorInfoWrapper.CaptureResult(internalSession->session->ImportImage( - ToWSLCCompatInputHandle(imageFile.Handle()), imageName, progressCallback.get(), imageFile.Length(), nullptr)); + wsl::windows::common::apicompat::Convert(ToCOMInputHandle(imageFile.Handle())), + imageName, + progressCallback.get(), + imageFile.Length(), + nullptr)); } STDAPI WslcImportSessionImage( @@ -1457,7 +1429,7 @@ static HRESULT WslcLoadSessionImageImpl( auto progressCallback = ProgressCallback::CreateIf(options); return errorInfoWrapper.CaptureResult(internalSession->session->LoadImage( - ToWSLCCompatInputHandle(imageFile.Handle()), progressCallback.get(), imageFile.Length(), nullptr)); + wsl::windows::common::apicompat::Convert(ToCOMInputHandle(imageFile.Handle())), progressCallback.get(), imageFile.Length(), nullptr)); } STDAPI WslcLoadSessionImage( diff --git a/src/windows/service/exe/WSLCSessionManager.cpp b/src/windows/service/exe/WSLCSessionManager.cpp index 5d275217ab..05a2569692 100644 --- a/src/windows/service/exe/WSLCSessionManager.cpp +++ b/src/windows/service/exe/WSLCSessionManager.cpp @@ -632,8 +632,6 @@ try } else { - // The conversion holds the wrapped termination callback so it outlives the call. The factory - // deep-copies (AddRefs) the termination callback synchronously during CreateSession. const auto settings = apicompat::Convert(*Settings); RETURN_IF_FAILED(CreateSession(settings.Get(), apicompat::Convert(Flags), warning.Get(), &session)); } diff --git a/src/windows/service/exe/WSLCSessionManager.h b/src/windows/service/exe/WSLCSessionManager.h index cd2c2afe18..f0735aa067 100644 --- a/src/windows/service/exe/WSLCSessionManager.h +++ b/src/windows/service/exe/WSLCSessionManager.h @@ -205,7 +205,7 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce8f") WSLCSessionManager IFACEMETHOD(OpenSession)(_In_ ULONG Id, _Out_ IWSLCSession** Session) override; IFACEMETHOD(OpenSessionByName)(_In_ LPCWSTR DisplayName, _Out_ IWSLCSession** Session) override; - // IWSLCCompatSessionManager - converts the WSLCCompat types to the wslc.idl types and forwards to the methods above. + // IWSLCCompatSessionManager. IFACEMETHOD(GetVersion)(_Out_ WSLCCompatVersion* Version) override; IFACEMETHOD(IsClientVersionSupported)(_In_ const WSLCCompatVersion* ClientVersion, _Out_ BOOL* IsSupported) override; IFACEMETHOD(CreateSession)( diff --git a/src/windows/wslcsession/WSLCContainer.h b/src/windows/wslcsession/WSLCContainer.h index 6baee4cc7e..59516685c1 100644 --- a/src/windows/wslcsession/WSLCContainer.h +++ b/src/windows/wslcsession/WSLCContainer.h @@ -243,7 +243,7 @@ class DECLSPEC_UUID("B1F1C4E3-C225-4CAE-AD8A-34C004DE1AE4") WSLCContainer IFACEMETHOD(ConnectToNetwork)(_In_ const WSLCNetworkConnectionOptions* Options) override; IFACEMETHOD(DisconnectFromNetwork)(_In_ LPCSTR NetworkName) override; - // IWSLCCompatContainer - converts the WSLCCompat types to the wslc.idl types and forwards to the methods above. + // IWSLCCompatContainer. IFACEMETHOD(Stop)(_In_ WSLCCompatSignal Signal, _In_ LONG TimeoutSeconds) override; IFACEMETHOD(Start)(_In_ WSLCCompatContainerStartFlags Flags) override; IFACEMETHOD(Delete)(_In_ WSLCCompatDeleteFlags Flags) override; diff --git a/src/windows/wslcsession/WSLCSession.cpp b/src/windows/wslcsession/WSLCSession.cpp index 4493b5e8ca..c31dbd49d1 100644 --- a/src/windows/wslcsession/WSLCSession.cpp +++ b/src/windows/wslcsession/WSLCSession.cpp @@ -2870,20 +2870,19 @@ try *Images = nullptr; *Count = 0; - WSLCImageInformation* internalImages = nullptr; + wil::unique_cotaskmem_array_ptr imagesImpl; + ULONG count = 0; if (Options == nullptr) { - RETURN_IF_FAILED(ListImages(static_cast(nullptr), &internalImages, &count)); + RETURN_IF_FAILED(ListImages(static_cast(nullptr), &imagesImpl, &count)); } else { const auto options = apicompat::Convert(*Options); - RETURN_IF_FAILED(ListImages(options.Get(), &internalImages, &count)); + RETURN_IF_FAILED(ListImages(options.Get(), &imagesImpl, &count)); } - auto freeInternal = wil::scope_exit([&] { CoTaskMemFree(internalImages); }); - if (count > 0) { auto converted = wil::make_unique_cotaskmem_nothrow(count); @@ -2891,7 +2890,7 @@ try for (ULONG index = 0; index < count; index++) { - converted[index] = apicompat::Convert(internalImages[index]); + converted[index] = apicompat::Convert(imagesImpl[index]); } *Images = converted.release(); @@ -2914,11 +2913,10 @@ try const auto options = apicompat::Convert(*Options); - WSLCDeletedImageInformation* internalImages = nullptr; - ULONG count = 0; - RETURN_IF_FAILED(DeleteImage(&options, &internalImages, &count)); + wil::unique_cotaskmem_array_ptr imagesImpl; - auto freeInternal = wil::scope_exit([&] { CoTaskMemFree(internalImages); }); + ULONG count = 0; + RETURN_IF_FAILED(DeleteImage(&options, &imagesImpl, &count)); if (count > 0) { @@ -2927,7 +2925,7 @@ try for (ULONG index = 0; index < count; index++) { - converted[index] = apicompat::Convert(internalImages[index]); + converted[index] = apicompat::Convert(imagesImpl[index]); } *DeletedImages = converted.release();