Rethink the Accept() logic to differentiate between errors and cancellation (#14156)
* Bring relay changes * Redesign Accept() logic to differenciate between cancellation and errors * Prepare for PR * Apply PR feedback
Blue committed
Feb 4, 2026 at 19:02 UTC
1897d055ddf6afa05f148c0a5b80090e7b55ac3c
10 files changed
+439
-35
src/shared/inc/defs.h
+12
@@ -22,6 +22,18 @@ Abstract:
22
#define _wcsicmp wcscasecmp
23
#endif
24
25
+#define NON_COPYABLE(Type) \
26
+ Type(const Type&) = delete; \
27
+ Type& operator=(const Type&) = delete;
28
+
29
+#define NON_MOVABLE(Type) \
30
+ Type(Type&&) = delete; \
31
+ Type& operator=(Type&&) = delete;
32
+
33
+#define DEFAULT_MOVABLE(Type) \
34
+ Type(Type&&) = default; \
35
+ Type& operator=(Type&&) = default;
36
+
37
namespace wsl::shared {
38
39
inline constexpr std::uint32_t VersionMajor = WSL_PACKAGE_VERSION_MAJOR;
src/windows/common/hvsocket.cpp
+6
-3
@@ -39,11 +39,14 @@ void InitializeWildcardSocketAddress(_Out_ PSOCKADDR_HV Address)
39
}
40
} // namespace
41
42
-wil::unique_socket wsl::windows::common::hvsocket::Accept(
43
- _In_ SOCKET ListenSocket, _In_ int Timeout, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
42
+std::optional<wil::unique_socket> wsl::windows::common::hvsocket::CancellableAccept(
43
+ _In_ SOCKET ListenSocket, _In_ DWORD Timeout, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
44
{
45
wil::unique_socket Socket = Create();
46
- wsl::windows::common::socket::Accept(ListenSocket, Socket.get(), Timeout, ExitHandle, Location);
46
+ if (!socket::CancellableAccept(ListenSocket, Socket.get(), Timeout, ExitHandle, Location))
47
+ {
48
+ return {};
49
+ }
50
51
return Socket;
52
}
src/windows/common/hvsocket.hpp
+2
-2
@@ -19,9 +19,9 @@ Abstract:
19
20
namespace wsl::windows::common::hvsocket {
21
22
-wil::unique_socket Accept(
22
+std::optional<wil::unique_socket> CancellableAccept(
23
_In_ SOCKET ListenSocket,
24
- _In_ int Timeout,
24
+ _In_ DWORD Timeout,
25
_In_opt_ HANDLE ExitHandle = nullptr,
26
const std::source_location& Location = std::source_location::current());
27
src/windows/common/relay.cpp
+219
-2
@@ -16,8 +16,14 @@ Abstract:
16
#include "relay.hpp"
17
#pragma hdrstop
18
19
+using wsl::windows::common::relay::EventHandle;
20
+using wsl::windows::common::relay::HandleWrapper;
21
+using wsl::windows::common::relay::IOHandleStatus;
22
+using wsl::windows::common::relay::MultiHandleWait;
23
+using wsl::windows::common::relay::OverlappedIOHandle;
24
using wsl::windows::common::relay::ScopedMultiRelay;
25
using wsl::windows::common::relay::ScopedRelay;
26
+using wsl::windows::common::relay::SingleAcceptHandle;
27
28
namespace {
29
@@ -108,7 +114,7 @@ wsl::windows::common::relay::InterruptableRead(
114
return 0;
115
}
116
111
- THROW_LAST_ERROR_IF(lastError != ERROR_IO_PENDING);
117
+ THROW_LAST_ERROR_IF_MSG(lastError != ERROR_IO_PENDING, "Handle: 0x%p", (void*)InputHandle);
118
119
auto cancelRead = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] {
120
CancelIoEx(InputHandle, Overlapped);
@@ -569,4 +575,215 @@ try
575
}
576
}
577
}
572
-CATCH_LOG()
\ No newline at end of file
578
+CATCH_LOG()
579
+
580
+void MultiHandleWait::AddHandle(std::unique_ptr<OverlappedIOHandle>&& handle, Flags flags)
581
+{
582
+ m_handles.emplace_back(flags, std::move(handle));
583
+}
584
+
585
+void MultiHandleWait::Cancel()
586
+{
587
+ m_cancel = true;
588
+}
589
+bool MultiHandleWait::Run(std::optional<std::chrono::milliseconds> Timeout)
590
+{
591
+ m_cancel = false; // Run may be called multiple times.
592
+
593
+ std::optional<std::chrono::steady_clock::time_point> deadline;
594
+
595
+ if (Timeout.has_value())
596
+ {
597
+ deadline = std::chrono::steady_clock::now() + Timeout.value();
598
+ }
599
+
600
+ // Run until all handles are completed.
601
+
602
+ while (!m_handles.empty() && !m_cancel)
603
+ {
604
+ // Schedule IO on each handle until all are either pending, or completed.
605
+ for (size_t i = 0; i < m_handles.size(); i++)
606
+ {
607
+ while (m_handles[i].second->GetState() == IOHandleStatus::Standby)
608
+ {
609
+ try
610
+ {
611
+ m_handles[i].second->Schedule();
612
+ }
613
+ catch (...)
614
+ {
615
+ if (WI_IsFlagSet(m_handles[i].first, Flags::IgnoreErrors))
616
+ {
617
+ m_handles[i].second.reset(); // Reset the handle so it can be deleted.
618
+ }
619
+ else
620
+ {
621
+ throw;
622
+ }
623
+ }
624
+ }
625
+ }
626
+
627
+ // Remove completed handles from m_handles.
628
+ for (auto it = m_handles.begin(); it != m_handles.end();)
629
+ {
630
+ if (!it->second)
631
+ {
632
+ it = m_handles.erase(it);
633
+ }
634
+ else if (it->second->GetState() == IOHandleStatus::Completed)
635
+ {
636
+ if (WI_IsFlagSet(it->first, Flags::CancelOnCompleted))
637
+ {
638
+ m_cancel = true; // Cancel the IO if a handle with CancelOnCompleted is in the completed state.
639
+ }
640
+
641
+ it = m_handles.erase(it);
642
+ }
643
+ else
644
+ {
645
+ ++it;
646
+ }
647
+ }
648
+
649
+ if (m_handles.empty() || m_cancel)
650
+ {
651
+ break;
652
+ }
653
+
654
+ // Wait for the next operation to complete.
655
+ std::vector<HANDLE> waitHandles;
656
+ for (const auto& e : m_handles)
657
+ {
658
+ waitHandles.emplace_back(e.second->GetHandle());
659
+ }
660
+
661
+ DWORD waitTimeout = INFINITE;
662
+ if (deadline.has_value())
663
+ {
664
+ auto miliseconds =
665
+ std::chrono::duration_cast<std::chrono::milliseconds>(deadline.value() - std::chrono::steady_clock::now()).count();
666
+
667
+ waitTimeout = static_cast<DWORD>(std::max(0LL, miliseconds));
668
+ }
669
+
670
+ auto result = WaitForMultipleObjects(static_cast<DWORD>(waitHandles.size()), waitHandles.data(), false, waitTimeout);
671
+ if (result == WAIT_TIMEOUT)
672
+ {
673
+ THROW_WIN32(ERROR_TIMEOUT);
674
+ }
675
+ else if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size())
676
+ {
677
+ auto index = result - WAIT_OBJECT_0;
678
+
679
+ try
680
+ {
681
+ m_handles[index].second->Collect();
682
+ }
683
+ catch (...)
684
+ {
685
+ if (WI_IsFlagSet(m_handles[index].first, Flags::IgnoreErrors))
686
+ {
687
+ m_handles.erase(m_handles.begin() + index);
688
+ }
689
+ else
690
+ {
691
+ throw;
692
+ }
693
+ }
694
+ }
695
+ else
696
+ {
697
+ THROW_LAST_ERROR_MSG("Timeout: %lu, Count: %llu", waitTimeout, waitHandles.size());
698
+ }
699
+ }
700
+
701
+ return !m_cancel;
702
+}
703
+
704
+IOHandleStatus OverlappedIOHandle::GetState() const
705
+{
706
+ return State;
707
+}
708
+
709
+EventHandle::EventHandle(HandleWrapper&& Handle, std::function<void()>&& OnSignalled) :
710
+ Handle(std::move(Handle)), OnSignalled(std::move(OnSignalled))
711
+{
712
+}
713
+
714
+void EventHandle::Schedule()
715
+{
716
+ State = IOHandleStatus::Pending;
717
+}
718
+
719
+void EventHandle::Collect()
720
+{
721
+ State = IOHandleStatus::Completed;
722
+ OnSignalled();
723
+}
724
+
725
+HANDLE EventHandle::GetHandle() const
726
+{
727
+ return Handle.Get();
728
+}
729
+
730
+SingleAcceptHandle::SingleAcceptHandle(HandleWrapper&& ListenSocket, HandleWrapper&& AcceptedSocket, std::function<void()>&& OnAccepted) :
731
+ ListenSocket(std::move(ListenSocket)), AcceptedSocket(std::move(AcceptedSocket)), OnAccepted(std::move(OnAccepted))
732
+{
733
+ Overlapped.hEvent = Event.get();
734
+}
735
+
736
+SingleAcceptHandle::~SingleAcceptHandle()
737
+{
738
+ if (State == IOHandleStatus::Pending)
739
+ {
740
+ LOG_IF_WIN32_BOOL_FALSE(CancelIoEx(ListenSocket.Get(), &Overlapped));
741
+
742
+ DWORD bytesProcessed{};
743
+ DWORD flagsReturned{};
744
+ if (!WSAGetOverlappedResult((SOCKET)ListenSocket.Get(), &Overlapped, &bytesProcessed, TRUE, &flagsReturned))
745
+ {
746
+ auto error = GetLastError();
747
+ LOG_LAST_ERROR_IF(error != ERROR_CONNECTION_ABORTED && error != ERROR_OPERATION_ABORTED);
748
+ }
749
+ }
750
+}
751
+
752
+void SingleAcceptHandle::Schedule()
753
+{
754
+ WI_ASSERT(State == IOHandleStatus::Standby);
755
+
756
+ // Schedule the accept.
757
+ DWORD bytesReturned{};
758
+ if (AcceptEx((SOCKET)ListenSocket.Get(), (SOCKET)AcceptedSocket.Get(), &AcceptBuffer, 0, sizeof(SOCKADDR_STORAGE), sizeof(SOCKADDR_STORAGE), &bytesReturned, &Overlapped))
759
+ {
760
+ // Accept completed immediately.
761
+ State = IOHandleStatus::Completed;
762
+ OnAccepted();
763
+ }
764
+ else
765
+ {
766
+ auto error = WSAGetLastError();
767
+ THROW_HR_IF_MSG(HRESULT_FROM_WIN32(error), error != ERROR_IO_PENDING, "Handle: 0x%p", (void*)ListenSocket.Get());
768
+
769
+ State = IOHandleStatus::Pending;
770
+ }
771
+}
772
+
773
+void SingleAcceptHandle::Collect()
774
+{
775
+ WI_ASSERT(State == IOHandleStatus::Pending);
776
+
777
+ DWORD bytesReceived{};
778
+ DWORD flagsReturned{};
779
+
780
+ THROW_IF_WIN32_BOOL_FALSE(WSAGetOverlappedResult((SOCKET)ListenSocket.Get(), &Overlapped, &bytesReceived, false, &flagsReturned));
781
+
782
+ State = IOHandleStatus::Completed;
783
+ OnAccepted();
784
+}
785
+
786
+HANDLE SingleAcceptHandle::GetHandle() const
787
+{
788
+ return Event.get();
789
+}
\ No newline at end of file
src/windows/common/relay.hpp
+152
@@ -150,4 +150,156 @@ private:
150
std::function<void()> m_onDestroy;
151
};
152
153
+enum class IOHandleStatus
154
+{
155
+ Standby,
156
+ Pending,
157
+ Completed
158
+};
159
+
160
+struct HandleWrapper
161
+{
162
+ DEFAULT_MOVABLE(HandleWrapper);
163
+ NON_COPYABLE(HandleWrapper)
164
+
165
+ HandleWrapper(
166
+ wil::unique_handle&& handle, std::function<void()>&& OnClose = []() {}) :
167
+ Handle(handle.get()), OwnedHandle(std::move(handle)), OnClose(std::move(OnClose))
168
+ {
169
+ }
170
+
171
+ HandleWrapper(
172
+ wil::unique_socket&& handle, std::function<void()>&& OnClose = []() {}) :
173
+ Handle((HANDLE)handle.get()), OwnedHandle(wil::unique_socket{handle.release()}), OnClose(std::move(OnClose))
174
+ {
175
+ }
176
+
177
+ HandleWrapper(
178
+ wil::unique_event&& handle, std::function<void()>&& OnClose = []() {}) :
179
+ Handle(handle.get()), OwnedHandle(wil::unique_handle{handle.release()}), OnClose(std::move(OnClose))
180
+ {
181
+ }
182
+
183
+ HandleWrapper(
184
+ SOCKET handle, std::function<void()>&& OnClose = []() {}) :
185
+ Handle(reinterpret_cast<HANDLE>(handle)), OnClose(std::move(OnClose))
186
+ {
187
+ }
188
+
189
+ HandleWrapper(HANDLE handle, std::function<void()>&& OnClose = []() {}) : Handle(handle), OnClose(std::move(OnClose))
190
+ {
191
+ }
192
+
193
+ HandleWrapper(
194
+ wil::unique_hfile&& handle, std::function<void()>&& OnClose = []() {}) :
195
+ Handle(handle.get()), OwnedHandle(wil::unique_handle{handle.release()}), OnClose(std::move(OnClose))
196
+ {
197
+ }
198
+
199
+ ~HandleWrapper()
200
+ {
201
+ Reset();
202
+ }
203
+
204
+ HANDLE Get() const
205
+ {
206
+ return Handle;
207
+ }
208
+
209
+ void Reset()
210
+ {
211
+ if (OnClose != nullptr)
212
+ {
213
+ OnClose();
214
+ OnClose = nullptr;
215
+ }
216
+
217
+ OwnedHandle = {};
218
+ Handle = nullptr;
219
+ }
220
+
221
+private:
222
+ HANDLE Handle{};
223
+ std::variant<wil::unique_handle, wil::unique_socket> OwnedHandle;
224
+ std::function<void()> OnClose;
225
+};
226
+
227
+class OverlappedIOHandle
228
+{
229
+public:
230
+ NON_COPYABLE(OverlappedIOHandle)
231
+ NON_MOVABLE(OverlappedIOHandle)
232
+
233
+ OverlappedIOHandle() = default;
234
+ virtual ~OverlappedIOHandle() = default;
235
+ virtual void Schedule() = 0;
236
+ virtual void Collect() = 0;
237
+ virtual HANDLE GetHandle() const = 0;
238
+ IOHandleStatus GetState() const;
239
+
240
+protected:
241
+ IOHandleStatus State = IOHandleStatus::Standby;
242
+};
243
+
244
+class EventHandle : public OverlappedIOHandle
245
+{
246
+public:
247
+ NON_COPYABLE(EventHandle)
248
+ NON_MOVABLE(EventHandle)
249
+
250
+ EventHandle(HandleWrapper&& Handle, std::function<void()>&& OnSignalled = []() {});
251
+ void Schedule() override;
252
+ void Collect() override;
253
+ HANDLE GetHandle() const override;
254
+
255
+private:
256
+ HandleWrapper Handle;
257
+ std::function<void()> OnSignalled;
258
+};
259
+
260
+class SingleAcceptHandle : public OverlappedIOHandle
261
+{
262
+public:
263
+ NON_COPYABLE(SingleAcceptHandle)
264
+ NON_MOVABLE(SingleAcceptHandle)
265
+
266
+ SingleAcceptHandle(HandleWrapper&& ListenSocket, HandleWrapper&& AcceptedSocket, std::function<void()>&& OnAccepted);
267
+ ~SingleAcceptHandle();
268
+
269
+ void Schedule() override;
270
+ void Collect() override;
271
+ HANDLE GetHandle() const override;
272
+
273
+private:
274
+ HandleWrapper ListenSocket;
275
+ HandleWrapper AcceptedSocket;
276
+ wil::unique_event Event{wil::EventOptions::ManualReset};
277
+ OVERLAPPED Overlapped{};
278
+ std::function<void()> OnAccepted;
279
+ char AcceptBuffer[2 * sizeof(SOCKADDR_STORAGE)];
280
+};
281
+
282
+class MultiHandleWait
283
+{
284
+public:
285
+ enum Flags
286
+ {
287
+ None = 0,
288
+ CancelOnCompleted = 1,
289
+ IgnoreErrors = 2
290
+ };
291
+
292
+ MultiHandleWait() = default;
293
+
294
+ void AddHandle(std::unique_ptr<OverlappedIOHandle>&& handle, Flags flags = Flags::None);
295
+ bool Run(std::optional<std::chrono::milliseconds> Timeout);
296
+ void Cancel();
297
+
298
+private:
299
+ std::vector<std::pair<Flags, std::unique_ptr<OverlappedIOHandle>>> m_handles;
300
+ bool m_cancel = false;
301
+};
302
+
303
+DEFINE_ENUM_FLAG_OPERATORS(MultiHandleWait::Flags);
304
+
305
} // namespace wsl::windows::common::relay
src/windows/common/socket.cpp
+17
-12
@@ -17,20 +17,25 @@ Abstract:
17
#include "socket.hpp"
18
#pragma hdrstop
19
20
-void wsl::windows::common::socket::Accept(
21
- _In_ SOCKET ListenSocket, _In_ SOCKET Socket, _In_ int Timeout, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
20
+bool wsl::windows::common::socket::CancellableAccept(
21
+ _In_ SOCKET ListenSocket, _In_ SOCKET Socket, _In_ DWORD Timeout, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
22
{
23
- CHAR AcceptBuffer[2 * sizeof(SOCKADDR_STORAGE)]{};
24
- DWORD BytesReturned;
25
- OVERLAPPED Overlapped{};
26
- const wil::unique_event OverlappedEvent(wil::EventOptions::ManualReset);
27
- Overlapped.hEvent = OverlappedEvent.get();
28
- const BOOL Success =
29
- AcceptEx(ListenSocket, Socket, AcceptBuffer, 0, sizeof(SOCKADDR_STORAGE), sizeof(SOCKADDR_STORAGE), &BytesReturned, &Overlapped);
23
+ relay::MultiHandleWait io;
24
+
25
+ bool accepted = false;
26
+
27
+ io.AddHandle(std::make_unique<relay::SingleAcceptHandle>(ListenSocket, Socket, [&]() { accepted = true; }), relay::MultiHandleWait::CancelOnCompleted);
28
+
29
+ if (ExitHandle != nullptr)
30
+ {
31
+ io.AddHandle(std::make_unique<relay::EventHandle>(ExitHandle), relay::MultiHandleWait::CancelOnCompleted);
32
+ }
33
+
34
+ io.Run(std::chrono::milliseconds(Timeout));
35
31
- if (!Success)
36
+ if (!accepted)
37
{
33
- GetResult(ListenSocket, Overlapped, Timeout, ExitHandle, Location);
38
+ return false; // Accept was cancelled by the exit event.
39
}
40
41
// Set the accept context to mark the socket as connected.
@@ -39,7 +44,7 @@ void wsl::windows::common::socket::Accept(
44
"From: %hs",
45
std::format("{}", Location).c_str());
46
42
- return;
47
+ return true;
48
}
49
50
std::pair<DWORD, DWORD> wsl::windows::common::socket::GetResult(
src/windows/common/socket.hpp
+2
-2
@@ -18,10 +18,10 @@ Abstract:
18
19
namespace wsl::windows::common::socket {
20
21
-void Accept(
21
+bool CancellableAccept(
22
_In_ SOCKET ListenSocket,
23
_In_ SOCKET Socket,
24
- _In_ int Timeout,
24
+ _In_ DWORD Timeout,
25
_In_opt_ HANDLE ExitHandle,
26
_In_ const std::source_location& Location = std::source_location::current());
27
src/windows/service/exe/WslCoreVm.cpp
+20
-12
@@ -823,14 +823,15 @@ WslCoreVm::~WslCoreVm() noexcept
823
824
wil::unique_socket WslCoreVm::AcceptConnection(_In_ DWORD ReceiveTimeout, _In_ const std::source_location& Location) const
825
{
826
- auto socket =
827
- wsl::windows::common::hvsocket::Accept(m_listenSocket.get(), m_vmConfig.KernelBootTimeout, m_terminatingEvent.get(), Location);
826
+ auto socket = hvsocket::CancellableAccept(m_listenSocket.get(), m_vmConfig.KernelBootTimeout, m_terminatingEvent.get(), Location);
827
+ THROW_HR_IF(E_ABORT, !socket.has_value());
828
+
829
if (ReceiveTimeout != 0)
830
{
830
- THROW_LAST_ERROR_IF(setsockopt(socket.get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&ReceiveTimeout, sizeof(ReceiveTimeout)) == SOCKET_ERROR);
831
+ THROW_LAST_ERROR_IF(setsockopt(socket->get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&ReceiveTimeout, sizeof(ReceiveTimeout)) == SOCKET_ERROR);
832
}
833
833
- return socket;
834
+ return std::move(socket.value());
835
}
836
837
_Requires_lock_held_(m_guestDeviceLock)
@@ -1084,13 +1085,16 @@ void WslCoreVm::CollectCrashDumps(wil::unique_socket&& listenSocket) const
1085
{
1086
try
1087
{
1087
- auto socket = wsl::windows::common::hvsocket::Accept(listenSocket.get(), INFINITE, m_terminatingEvent.get());
1088
+ auto socket = hvsocket::CancellableAccept(listenSocket.get(), INFINITE, m_terminatingEvent.get());
1089
+ if (!socket.has_value())
1090
+ {
1091
+ break; // VM is exiting.
1092
+ }
1093
1094
DWORD receiveTimeout = m_vmConfig.KernelBootTimeout;
1090
- THROW_LAST_ERROR_IF(
1091
- setsockopt(listenSocket.get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&receiveTimeout, sizeof(receiveTimeout)) == SOCKET_ERROR);
1095
+ THROW_LAST_ERROR_IF(setsockopt(socket->get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&receiveTimeout, sizeof(receiveTimeout)) == SOCKET_ERROR);
1096
1093
- auto channel = wsl::shared::SocketChannel{std::move(socket), "crash_dump", m_terminatingEvent.get()};
1097
+ auto channel = wsl::shared::SocketChannel{std::move(socket.value()), "crash_dump", m_terminatingEvent.get()};
1098
1099
const auto& message = channel.ReceiveMessage<LX_PROCESS_CRASH>();
1100
const char* process = reinterpret_cast<const char*>(&message.Buffer);
@@ -2554,10 +2558,14 @@ try
2558
for (;;)
2559
{
2560
// Create a worker thread to handle each request.
2557
- wsl::shared::SocketChannel channel{
2558
- wsl::windows::common::hvsocket::Accept(listenSocket.get(), INFINITE, m_terminatingEvent.get()),
2559
- "VirtioFs",
2560
- m_terminatingEvent.get()};
2561
+
2562
+ auto socket = hvsocket::CancellableAccept(listenSocket.get(), INFINITE, m_terminatingEvent.get());
2563
+ if (!socket.has_value())
2564
+ {
2565
+ break;
2566
+ }
2567
+
2568
+ wsl::shared::SocketChannel channel{std::move(socket.value()), "VirtioFs", m_terminatingEvent.get()};
2569
std::thread([this, channel = std::move(channel)]() mutable {
2570
try
2571
{
src/windows/wslrelay/localhost.cpp
+5
-1
@@ -297,7 +297,11 @@ try
297
wil::unique_socket InetSocket(WSASocket(AddressFamily, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED));
298
THROW_LAST_ERROR_IF(!InetSocket);
299
300
- wsl::windows::common::socket::Accept(Arguments->ListenSocket.get(), InetSocket.get(), INFINITE, Arguments->ExitEvent.get());
300
+ if (!wsl::windows::common::socket::CancellableAccept(
301
+ Arguments->ListenSocket.get(), InetSocket.get(), INFINITE, Arguments->ExitEvent.get()))
302
+ {
303
+ break; // Exit event was signaled, exit.
304
+ }
305
306
// Establish a relay thread.
307
src/windows/wslrelay/main.cpp
+4
-1
@@ -120,7 +120,10 @@ try
120
const wil::unique_socket socket(WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED));
121
THROW_LAST_ERROR_IF(!socket);
122
123
- wsl::windows::common::socket::Accept(listenSocket.get(), socket.get(), INFINITE, exitEvent.get());
123
+ if (!wsl::windows::common::socket::CancellableAccept(listenSocket.get(), socket.get(), INFINITE, exitEvent.get()))
124
+ {
125
+ return 1;
126
+ }
127
128
// Begin the relay.
129
wsl::windows::common::relay::BidirectionalRelay(