master
cpp 175 lines 5.25 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 Container.cpp
8
9 Abstract:
10
11 This file contains the implementation of the WinRT wrapper for the WSLC SDK Container class.
12
13 --*/
14
15 #include "precomp.h"
16 #include "Container.h"
17 #include "Microsoft.WSL.Containers.Container.g.cpp"
18 #include "ContainerSettings.h"
19 #include "Process.h"
20 #include "ProcessSettings.h"
21
22 using namespace winrt::Windows::Foundation;
23
24 namespace winrt::Microsoft::WSL::Containers::implementation {
25 Container::Container(WslcSession session, winrt::Microsoft::WSL::Containers::ContainerSettings const& settings)
26 {
27 if (settings.InitProcess())
28 {
29 m_initProcess = winrt::make_self<implementation::Process>(settings.InitProcess());
30 }
31
32 wil::unique_cotaskmem_string errorMessage;
33 auto hr = WslcCreateContainer(session, GetStructPointer(settings), m_container.put(), errorMessage.put());
34 THROW_MSG_IF_FAILED(hr, errorMessage);
35 }
36
37 Container::Container(WslcContainer handle, winrt::Microsoft::WSL::Containers::ProcessOutputMode initProcessOutputMode) :
38 m_opened(true)
39 {
40 m_container.reset(handle);
41
42 m_initProcess = winrt::make_self<implementation::Process>(initProcessOutputMode);
43
44 if (initProcessOutputMode == ProcessOutputMode::Event)
45 {
46 auto callbacks = m_initProcess->GetEventCallbacks();
47 winrt::check_hresult(WslcSetContainerInitProcessIOCallbacks(m_container.get(), &callbacks, m_initProcess.get()));
48 }
49
50 // Best-effort: attach the init process handle if one is available. The container may not
51 // have been started yet, or may not have an init process at all.
52 WslcProcess initHandle{};
53 if (SUCCEEDED(WslcGetContainerInitProcess(m_container.get(), &initHandle)) && initHandle)
54 {
55 m_initProcess->AttachHandle(initHandle);
56 }
57 }
58
59 void Container::Start()
60 {
61 auto startFlags = WSLC_CONTAINER_START_FLAG_NONE;
62 if (m_initProcess)
63 {
64 WI_SetFlagIf(
65 startFlags,
66 WSLC_CONTAINER_START_FLAG_ATTACH,
67 m_initProcess->OutputMode() == ProcessOutputMode::Event || m_initProcess->OutputMode() == ProcessOutputMode::Stream);
68 }
69
70 wil::unique_cotaskmem_string errorMessage;
71 auto hr = WslcStartContainer(ToHandle(), startFlags, errorMessage.put());
72 THROW_MSG_IF_FAILED(hr, errorMessage);
73
74 if (m_initProcess)
75 {
76 WslcProcess initHandle{};
77 hr = WslcGetContainerInitProcess(ToHandle(), &initHandle);
78 THROW_HR_IF(hr, !m_opened && FAILED(hr));
79 if (SUCCEEDED(hr) && initHandle)
80 {
81 m_initProcess->AttachHandle(initHandle);
82 }
83 }
84 }
85
86 void Container::Stop(winrt::Microsoft::WSL::Containers::Signal const& signal, TimeSpan timeout)
87 {
88 wil::unique_cotaskmem_string errorMessage;
89 auto timeoutSeconds = std::chrono::duration_cast<std::chrono::seconds>(timeout).count();
90 if (timeoutSeconds > std::numeric_limits<uint32_t>::max())
91 {
92 throw winrt::hresult_invalid_argument(L"Timeout is too large");
93 }
94
95 if (timeoutSeconds < 0)
96 {
97 throw winrt::hresult_invalid_argument(L"Timeout must be non-negative");
98 }
99
100 auto hr = WslcStopContainer(ToHandle(), static_cast<WslcSignal>(signal), static_cast<uint32_t>(timeoutSeconds), errorMessage.put());
101 THROW_MSG_IF_FAILED(hr, errorMessage);
102 }
103
104 void Container::Delete(winrt::Microsoft::WSL::Containers::DeleteContainerOption const& flags)
105 {
106 wil::unique_cotaskmem_string errorMessage;
107 auto hr = WslcDeleteContainer(ToHandle(), static_cast<WslcDeleteContainerFlags>(flags), errorMessage.put());
108 THROW_MSG_IF_FAILED(hr, errorMessage);
109 }
110
111 winrt::Microsoft::WSL::Containers::Process Container::CreateProcess(winrt::Microsoft::WSL::Containers::ProcessSettings const& newProcessSettings)
112 {
113 return *winrt::make_self<implementation::Process>(*this, newProcessSettings);
114 }
115
116 hstring Container::Inspect()
117 {
118 wil::unique_cotaskmem_ansistring inspectData;
119 winrt::check_hresult(WslcInspectContainer(ToHandle(), inspectData.put()));
120 return winrt::to_hstring(inspectData.get());
121 }
122
123 hstring Container::Id()
124 {
125 CHAR id[WSLC_CONTAINER_ID_BUFFER_SIZE];
126 winrt::check_hresult(WslcGetContainerID(ToHandle(), id));
127 return winrt::to_hstring(id);
128 }
129
130 winrt::Microsoft::WSL::Containers::Process Container::InitProcess()
131 {
132 if (!m_initProcess)
133 {
134 throw winrt::hresult_illegal_method_call(L"This container was not configured with an init process");
135 }
136
137 return *m_initProcess;
138 }
139
140 winrt::Microsoft::WSL::Containers::ContainerState Container::State()
141 {
142 WslcContainerState state;
143 winrt::check_hresult(WslcGetContainerState(ToHandle(), &state));
144 return static_cast<winrt::Microsoft::WSL::Containers::ContainerState>(state);
145 }
146
147 void Container::EnsureNotClosed() const
148 {
149 if (!m_container)
150 {
151 throw winrt::hresult_error(RO_E_CLOSED, L"Container has been closed");
152 }
153 }
154
155 WslcContainer Container::ToHandle()
156 {
157 EnsureNotClosed();
158 return m_container.get();
159 }
160
161 void Container::Close()
162 {
163 m_initProcess = nullptr;
164
165 // Methods called after Close() will fail due to EnsureNotClosed().
166 m_container.reset();
167 }
168
169 void Container::final_release(std::unique_ptr<Container> self)
170 {
171 // Ensure cleanup when refcount drops to zero even if Close() was not called explicitly.
172 self->Close();
173 }
174
175 } // namespace winrt::Microsoft::WSL::Containers::implementation