@samitouri / QOSAMI-WSL / commits / c7aad616

Improve logging when socket operations fail (#13579)

* Don't throw when processing an empty argument * Cleanup diff

Blue committed Oct 8, 2025 at 18:24 UTC c7aad6161166d330099cc48ceab7ee158b8225a2
9 files changed +109 -44
src/linux/init/util.cpp
+8 -6
@@ -537,7 +537,7 @@ Return Value:
537 return Socket;
538 }
539
540 -wil::unique_fd UtilConnectVsock(unsigned int Port, bool CloseOnExec, std::optional<int> SocketBuffer) noexcept
540 +wil::unique_fd UtilConnectVsock(unsigned int Port, bool CloseOnExec, std::optional<int> SocketBuffer, const std::source_location& Source) noexcept
541
542 /*++
543
@@ -553,6 +553,8 @@ Arguments:
553
554 SocketBuffer - Optionally supplies the size to use for the socket send and receive buffers.
555
556 + Source - Supplies the caller location.
557 +
558 Return Value:
559
560 A file descriptor representing the connected socket, -1 on failure.
@@ -565,7 +567,7 @@ Return Value:
567 wil::unique_fd SocketFd{socket(AF_VSOCK, Type, 0)};
568 if (!SocketFd)
569 {
568 - LOG_ERROR("socket failed {}", errno);
570 + LOG_ERROR("socket failed {} (from: {})", errno, Source);
571 return {};
572 }
573
@@ -577,7 +579,7 @@ Return Value:
579 Timeout.tv_sec = LX_INIT_HVSOCKET_TIMEOUT_SECONDS;
580 if (setsockopt(SocketFd.get(), AF_VSOCK, SO_VM_SOCKETS_CONNECT_TIMEOUT, &Timeout, sizeof(Timeout)) < 0)
581 {
580 - LOG_ERROR("setsockopt SO_VM_SOCKETS_CONNECT_TIMEOUT failed {}", errno);
582 + LOG_ERROR("setsockopt SO_VM_SOCKETS_CONNECT_TIMEOUT failed {}, (from: {})", errno, Source);
583 return {};
584 }
585
@@ -586,13 +588,13 @@ Return Value:
588 int BufferSize = *SocketBuffer;
589 if (setsockopt(SocketFd.get(), SOL_SOCKET, SO_SNDBUF, &BufferSize, sizeof(BufferSize)) < 0)
590 {
589 - LOG_ERROR("setsockopt(SO_SNDBUF, {}) failed {}", BufferSize, errno);
591 + LOG_ERROR("setsockopt(SO_SNDBUF, {}) failed {}, (from: {})", BufferSize, errno, Source);
592 return {};
593 }
594
595 if (setsockopt(SocketFd.get(), SOL_SOCKET, SO_RCVBUF, &BufferSize, sizeof(BufferSize)) < 0)
596 {
595 - LOG_ERROR("setsockopt(SO_RCVBUF, {}) failed {}", BufferSize, errno);
597 + LOG_ERROR("setsockopt(SO_RCVBUF, {}) failed {}, (from: {})", BufferSize, errno, Source);
598 return {};
599 }
600 }
@@ -603,7 +605,7 @@ Return Value:
605 SocketAddress.svm_port = Port;
606 if (connect(SocketFd.get(), (const struct sockaddr*)&SocketAddress, sizeof(SocketAddress)) < 0)
607 {
606 - LOG_ERROR("connect port {} failed {}", Port, errno);
608 + LOG_ERROR("connect port {} failed {} (from: {})", Port, errno, Source);
609 return {};
610 }
611
src/linux/init/util.h
+3 -1
@@ -28,6 +28,7 @@ Abstract:
28 #include <future>
29 #include <filesystem>
30 #include <vector>
31 +#include <source_location>
32 #include "lxinitshared.h"
33 #include "lxdef.h"
34 #include "common.h"
@@ -128,7 +129,8 @@ wil::unique_fd UtilConnectToInteropServer(std::optional<pid_t> Pid = {});
129
130 wil::unique_fd UtilConnectUnix(const char* Path);
131
131 -wil::unique_fd UtilConnectVsock(unsigned int Port, bool CloseOnExec, std::optional<int> SocketBuffer = {}) noexcept;
132 +wil::unique_fd UtilConnectVsock(
133 + unsigned int Port, bool CloseOnExec, std::optional<int> SocketBuffer = {}, const std::source_location& Source = std::source_location::current()) noexcept;
134
135 // Needs to be declared before UtilCreateChildProcess().
136 void UtilSetThreadName(const char* Name);
src/shared/inc/stringshared.h
+17
@@ -20,6 +20,7 @@ Abstract:
20 #include <fstream>
21 #include <gsl/gsl>
22 #include <format>
23 +#include <source_location>
24
25 #ifndef WIN32
26 #include <string.h>
@@ -834,6 +835,22 @@ struct std::formatter<wchar_t[N], char>
835 }
836 };
837
838 +template <>
839 +struct std::formatter<std::source_location, char>
840 +{
841 + template <typename TCtx>
842 + static constexpr auto parse(TCtx& ctx)
843 + {
844 + return ctx.begin();
845 + }
846 +
847 + template <typename TCtx>
848 + auto format(const std::source_location& location, TCtx& ctx) const
849 + {
850 + return std::format_to(ctx.out(), "{}[{}:{}]", location.function_name(), location.file_name(), location.line());
851 + }
852 +};
853 +
854 template <>
855 struct std::formatter<char*, wchar_t>
856 {
src/windows/common/hvsocket.cpp
+7 -5
@@ -39,15 +39,17 @@ void InitializeWildcardSocketAddress(_Out_ PSOCKADDR_HV Address)
39 }
40 } // namespace
41
42 -wil::unique_socket wsl::windows::common::hvsocket::Accept(_In_ SOCKET ListenSocket, _In_ int Timeout, _In_opt_ HANDLE ExitHandle)
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)
44 {
45 wil::unique_socket Socket = Create();
45 - wsl::windows::common::socket::Accept(ListenSocket, Socket.get(), Timeout, ExitHandle);
46 + wsl::windows::common::socket::Accept(ListenSocket, Socket.get(), Timeout, ExitHandle, Location);
47
48 return Socket;
49 }
50
50 -wil::unique_socket wsl::windows::common::hvsocket::Connect(_In_ const GUID& VmId, _In_ unsigned long Port, _In_opt_ HANDLE ExitHandle)
51 +wil::unique_socket wsl::windows::common::hvsocket::Connect(
52 + _In_ const GUID& VmId, _In_ unsigned long Port, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
53 {
54 OVERLAPPED Overlapped{};
55 const wil::unique_event OverlappedEvent(wil::EventOptions::ManualReset);
@@ -71,7 +73,7 @@ wil::unique_socket wsl::windows::common::hvsocket::Connect(_In_ const GUID& VmId
73
74 if (Result != 0)
75 {
74 - socket::GetResult(Socket.get(), Overlapped, INFINITE, ExitHandle);
76 + socket::GetResult(Socket.get(), Overlapped, INFINITE, ExitHandle, Location);
77 }
78
79 ULONG Timeout = CONNECT_TIMEOUT;
@@ -86,7 +88,7 @@ wil::unique_socket wsl::windows::common::hvsocket::Connect(_In_ const GUID& VmId
88 const BOOL Success = ConnectFn(Socket.get(), reinterpret_cast<sockaddr*>(&Addr), sizeof(Addr), nullptr, 0, nullptr, &Overlapped);
89 if (Success == FALSE)
90 {
89 - socket::GetResult(Socket.get(), Overlapped, INFINITE, ExitHandle);
91 + socket::GetResult(Socket.get(), Overlapped, INFINITE, ExitHandle, Location);
92 }
93
94 return Socket;
src/windows/common/hvsocket.hpp
+11 -3
@@ -19,9 +19,17 @@ Abstract:
19
20 namespace wsl::windows::common::hvsocket {
21
22 -wil::unique_socket Accept(_In_ SOCKET ListenSocket, _In_ int Timeout, _In_opt_ HANDLE ExitHandle = nullptr);
23 -
24 -wil::unique_socket Connect(_In_ const GUID& VmId, _In_ unsigned long Port, _In_opt_ HANDLE ExitHandle = nullptr);
22 +wil::unique_socket Accept(
23 + _In_ SOCKET ListenSocket,
24 + _In_ int Timeout,
25 + _In_opt_ HANDLE ExitHandle = nullptr,
26 + const std::source_location& Location = std::source_location::current());
27 +
28 +wil::unique_socket Connect(
29 + _In_ const GUID& VmId,
30 + _In_ unsigned long Port,
31 + _In_opt_ HANDLE ExitHandle = nullptr,
32 + const std::source_location& Location = std::source_location::current());
33
34 wil::unique_socket Create();
35
src/windows/common/socket.cpp
+22 -15
@@ -17,7 +17,8 @@ Abstract:
17 #include "socket.hpp"
18 #pragma hdrstop
19
20 -void wsl::windows::common::socket::Accept(_In_ SOCKET ListenSocket, _In_ SOCKET Socket, _In_ int Timeout, _In_opt_ HANDLE ExitHandle)
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)
22 {
23 CHAR AcceptBuffer[2 * sizeof(SOCKADDR_STORAGE)]{};
24 DWORD BytesReturned;
@@ -29,17 +30,20 @@ void wsl::windows::common::socket::Accept(_In_ SOCKET ListenSocket, _In_ SOCKET
30
31 if (!Success)
32 {
32 - GetResult(ListenSocket, Overlapped, Timeout, ExitHandle);
33 + GetResult(ListenSocket, Overlapped, Timeout, ExitHandle, Location);
34 }
35
36 // Set the accept context to mark the socket as connected.
36 - THROW_LAST_ERROR_IF(
37 - setsockopt(Socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast<char*>(&ListenSocket), sizeof(ListenSocket)) == SOCKET_ERROR);
37 + THROW_LAST_ERROR_IF_MSG(
38 + setsockopt(Socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast<char*>(&ListenSocket), sizeof(ListenSocket)) == SOCKET_ERROR,
39 + "From: %hs",
40 + std::format("{}", Location).c_str());
41
42 return;
43 }
44
42 -std::pair<DWORD, DWORD> wsl::windows::common::socket::GetResult(_In_ SOCKET Socket, _In_ OVERLAPPED& Overlapped, _In_ DWORD Timeout, _In_ HANDLE ExitHandle)
45 +std::pair<DWORD, DWORD> wsl::windows::common::socket::GetResult(
46 + _In_ SOCKET Socket, _In_ OVERLAPPED& Overlapped, _In_ DWORD Timeout, _In_ HANDLE ExitHandle, _In_ const std::source_location& Location)
47 {
48 const int error = WSAGetLastError();
49 THROW_HR_IF(HRESULT_FROM_WIN32(error), error != WSA_IO_PENDING);
@@ -64,7 +68,7 @@ std::pair<DWORD, DWORD> wsl::windows::common::socket::GetResult(_In_ SOCKET Sock
68 return {0, 0};
69 }
70
67 - THROW_HR_IF(HCS_E_CONNECTION_TIMEOUT, (waitStatus != WAIT_OBJECT_0));
71 + THROW_HR_IF_MSG(HCS_E_CONNECTION_TIMEOUT, (waitStatus != WAIT_OBJECT_0), "From: %hs", std::format("{}", Location).c_str());
72
73 cancelFunction.release();
74 const bool result = WSAGetOverlappedResult(Socket, &Overlapped, &bytesProcessed, FALSE, &flagsReturned);
@@ -83,16 +87,17 @@ std::pair<DWORD, DWORD> wsl::windows::common::socket::GetResult(_In_ SOCKET Sock
87 return {bytesProcessed, flagsReturned};
88 }
89
86 -int wsl::windows::common::socket::Receive(_In_ SOCKET Socket, _In_ gsl::span<gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle, _In_ DWORD Flags, _In_ DWORD Timeout)
90 +int wsl::windows::common::socket::Receive(
91 + _In_ SOCKET Socket, _In_ gsl::span<gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle, _In_ DWORD Flags, _In_ DWORD Timeout, _In_ const std::source_location& Location)
92 {
88 - const int BytesRead = ReceiveNoThrow(Socket, Buffer, ExitHandle, Flags, Timeout);
93 + const int BytesRead = ReceiveNoThrow(Socket, Buffer, ExitHandle, Flags, Timeout, Location);
94 THROW_LAST_ERROR_IF(BytesRead == SOCKET_ERROR);
95
96 return BytesRead;
97 }
98
99 int wsl::windows::common::socket::ReceiveNoThrow(
95 - _In_ SOCKET Socket, _In_ gsl::span<gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle, _In_ DWORD Flags, _In_ DWORD Timeout)
100 + _In_ SOCKET Socket, _In_ gsl::span<gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle, _In_ DWORD Flags, _In_ DWORD Timeout, _In_ const std::source_location& Location)
101 {
102 OVERLAPPED Overlapped{};
103 const wil::unique_event OverlappedEvent(wil::EventOptions::ManualReset);
@@ -103,7 +108,7 @@ int wsl::windows::common::socket::ReceiveNoThrow(
108 try
109 {
110 BytesReturned = SOCKET_ERROR;
106 - auto [innerBytes, Flags] = GetResult(Socket, Overlapped, Timeout, ExitHandle);
111 + auto [innerBytes, Flags] = GetResult(Socket, Overlapped, Timeout, ExitHandle, Location);
112 BytesReturned = innerBytes;
113 }
114 catch (...)
@@ -116,20 +121,22 @@ int wsl::windows::common::socket::ReceiveNoThrow(
121 return BytesReturned;
122 }
123
119 -std::vector<gsl::byte> wsl::windows::common::socket::Receive(_In_ SOCKET Socket, _In_opt_ HANDLE ExitHandle, _In_ DWORD Timeout)
124 +std::vector<gsl::byte> wsl::windows::common::socket::Receive(
125 + _In_ SOCKET Socket, _In_opt_ HANDLE ExitHandle, _In_ DWORD Timeout, _In_ const std::source_location& Location)
126 {
121 - Receive(Socket, {}, ExitHandle, MSG_PEEK);
127 + Receive(Socket, {}, ExitHandle, MSG_PEEK, Timeout, Location);
128
129 ULONG Size = 0;
130 THROW_LAST_ERROR_IF(ioctlsocket(Socket, FIONREAD, &Size) == SOCKET_ERROR);
131
132 std::vector<gsl::byte> Buffer(Size);
127 - WI_VERIFY(Receive(Socket, gsl::make_span(Buffer), ExitHandle, Timeout) == static_cast<int>(Size));
133 + WI_VERIFY(Receive(Socket, gsl::make_span(Buffer), ExitHandle, MSG_WAITALL, Timeout, Location) == static_cast<int>(Size));
134
135 return Buffer;
136 }
137
132 -int wsl::windows::common::socket::Send(_In_ SOCKET Socket, _In_ gsl::span<const gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle)
138 +int wsl::windows::common::socket::Send(
139 + _In_ SOCKET Socket, _In_ gsl::span<const gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle, _In_ const std::source_location& Location)
140 {
141 OVERLAPPED Overlapped{};
142 const wil::unique_event OverlappedEvent(wil::EventOptions::ManualReset);
@@ -139,7 +146,7 @@ int wsl::windows::common::socket::Send(_In_ SOCKET Socket, _In_ gsl::span<const
146 if (WSASend(Socket, &VectorBuffer, 1, &BytesWritten, 0, &Overlapped, nullptr) != 0)
147 {
148 DWORD Flags;
142 - std::tie(BytesWritten, Flags) = GetResult(Socket, Overlapped, INFINITE, ExitHandle);
149 + std::tie(BytesWritten, Flags) = GetResult(Socket, Overlapped, INFINITE, ExitHandle, Location);
150 }
151
152 WI_ASSERT(BytesWritten == gsl::narrow_cast<DWORD>(Buffer.size()));
src/windows/common/socket.hpp
+37 -11
@@ -18,16 +18,42 @@ Abstract:
18
19 namespace wsl::windows::common::socket {
20
21 -void Accept(_In_ SOCKET ListenSocket, _In_ SOCKET Socket, _In_ int Timeout, _In_opt_ HANDLE ExitHandle);
22 -
23 -std::pair<DWORD, DWORD> GetResult(_In_ SOCKET Socket, _In_ OVERLAPPED& Overlapped, _In_ DWORD Timeout, _In_ HANDLE ExitHandle);
24 -
25 -int Receive(_In_ SOCKET Socket, _In_ gsl::span<gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle = nullptr, _In_ DWORD Flags = MSG_WAITALL, _In_ DWORD Timeout = INFINITE);
26 -
27 -std::vector<gsl::byte> Receive(_In_ SOCKET Socket, _In_opt_ HANDLE ExitHandle = nullptr, _In_ DWORD Timeout = INFINITE);
28 -
29 -int ReceiveNoThrow(_In_ SOCKET Socket, _In_ gsl::span<gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle = nullptr, _In_ DWORD Flags = MSG_WAITALL, _In_ DWORD Timeout = INFINITE);
30 -
31 -int Send(_In_ SOCKET Socket, _In_ gsl::span<const gsl::byte> Buffer, _In_opt_ HANDLE ExitHandle = nullptr);
21 +void Accept(
22 + _In_ SOCKET ListenSocket,
23 + _In_ SOCKET Socket,
24 + _In_ int Timeout,
25 + _In_opt_ HANDLE ExitHandle,
26 + _In_ const std::source_location& Location = std::source_location::current());
27 +
28 +std::pair<DWORD, DWORD> GetResult(
29 + _In_ SOCKET Socket, _In_ OVERLAPPED& Overlapped, _In_ DWORD Timeout, _In_ HANDLE ExitHandle, _In_ const std::source_location& Location);
30 +
31 +int Receive(
32 + _In_ SOCKET Socket,
33 + _In_ gsl::span<gsl::byte> Buffer,
34 + _In_opt_ HANDLE ExitHandle = nullptr,
35 + _In_ DWORD Flags = MSG_WAITALL,
36 + _In_ DWORD Timeout = INFINITE,
37 + _In_ const std::source_location& Location = std::source_location::current());
38 +
39 +std::vector<gsl::byte> Receive(
40 + _In_ SOCKET Socket,
41 + _In_opt_ HANDLE ExitHandle = nullptr,
42 + _In_ DWORD Timeout = INFINITE,
43 + _In_ const std::source_location& Location = std::source_location::current());
44 +
45 +int ReceiveNoThrow(
46 + _In_ SOCKET Socket,
47 + _In_ gsl::span<gsl::byte> Buffer,
48 + _In_opt_ HANDLE ExitHandle = nullptr,
49 + _In_ DWORD Flags = MSG_WAITALL,
50 + _In_ DWORD Timeout = INFINITE,
51 + _In_ const std::source_location& Location = std::source_location::current());
52 +
53 +int Send(
54 + _In_ SOCKET Socket,
55 + _In_ gsl::span<const gsl::byte> Buffer,
56 + _In_opt_ HANDLE ExitHandle = nullptr,
57 + _In_ const std::source_location& Location = std::source_location::current());
58
59 } // namespace wsl::windows::common::socket
src/windows/service/exe/WslCoreVm.cpp
+3 -2
@@ -879,9 +879,10 @@ WslCoreVm::~WslCoreVm() noexcept
879 WSL_LOG("TerminateVmStop");
880 }
881
882 -wil::unique_socket WslCoreVm::AcceptConnection(_In_ DWORD ReceiveTimeout) const
882 +wil::unique_socket WslCoreVm::AcceptConnection(_In_ DWORD ReceiveTimeout, _In_ const std::source_location& Location) const
883 {
884 - auto socket = wsl::windows::common::hvsocket::Accept(m_listenSocket.get(), m_vmConfig.KernelBootTimeout, m_terminatingEvent.get());
884 + auto socket =
885 + wsl::windows::common::hvsocket::Accept(m_listenSocket.get(), m_vmConfig.KernelBootTimeout, m_terminatingEvent.get(), Location);
886 if (ReceiveTimeout != 0)
887 {
888 THROW_LAST_ERROR_IF(setsockopt(socket.get(), SOL_SOCKET, SO_RCVTIMEO, (const char*)&ReceiveTimeout, sizeof(ReceiveTimeout)) == SOCKET_ERROR);
src/windows/service/exe/WslCoreVm.h
+1 -1
@@ -61,7 +61,7 @@ public:
61
62 ~WslCoreVm() noexcept;
63
64 - wil::unique_socket AcceptConnection(_In_ DWORD ReceiveTimeout = 0) const;
64 + wil::unique_socket AcceptConnection(_In_ DWORD ReceiveTimeout = 0, _In_ const std::source_location& Location = std::source_location::current()) const;
65
66 enum class DiskType
67 {