Fix broken WSLCorePort channel after receive timeout (#14455)
Refactor the socket channel to resolve the broken state after a timeout: * Replace the sequence number with transaction id. And add transaction step in the message header. * The transaction and non-transaction messages are differentiated by the transaction step. * The old sequence number logic stays the same for non-transaction messages. * For transaction messages. The reply side will reply with the same id in the incoming transaction request. * For transaction messages. The receive loop will discard stale messages based on the transaction id.
Feng Wang committed
Apr 21, 2026 at 10:14 UTC
f05690c3fd254d7f949e04e8ecabd2ddc0132200
20 files changed
+517
-162
src/linux/init/GnsEngine.cpp
+8
-6
@@ -25,12 +25,13 @@ constexpr auto c_ipStrings = {"ip", "ip6"};
25
const char* c_loopbackInterfaceName = "lo";
26
27
GnsEngine::GnsEngine(
28
+ wsl::shared::SocketChannel& channel,
29
const NotificationRoutine& notificationRoutine,
30
const StatusRoutine& statusRoutine,
31
NetworkManager& manager,
32
std::optional<int> dnsTunnelingFd,
33
const std::string& dnsTunnelingIpAddress) :
33
- notificationRoutine(notificationRoutine), statusRoutine(statusRoutine), manager(manager)
34
+ channel(channel), notificationRoutine(notificationRoutine), statusRoutine(statusRoutine), manager(manager)
35
{
36
if (dnsTunnelingFd.has_value())
37
{
@@ -363,11 +364,11 @@ void GnsEngine::ProcessLinkChange(Interface& interface, const wsl::shared::hns::
364
}
365
}
366
366
-std::tuple<bool, int> GnsEngine::ProcessNextMessage()
367
+std::tuple<bool, int> GnsEngine::ProcessNextMessage(wsl::shared::Transaction& transaction)
368
{
369
int return_value = 0;
370
370
- auto payload = notificationRoutine();
371
+ auto payload = notificationRoutine(transaction);
372
if (!payload.has_value())
373
{
374
GNS_LOG_ERROR("Received empty message, exiting");
@@ -723,22 +724,23 @@ void GnsEngine::run()
724
725
while (true)
726
{
727
+ auto transaction = channel.ReceiveTransaction();
728
try
729
{
730
GNS_LOG_INFO("Processing Next Message");
729
- auto [should_continue, return_value] = ProcessNextMessage();
731
+ auto [should_continue, return_value] = ProcessNextMessage(transaction);
732
if (!should_continue)
733
{
734
break;
735
}
736
737
GNS_LOG_INFO("Processing Next Message Successful ({:#x})", return_value);
736
- statusRoutine(return_value, "");
738
+ statusRoutine(return_value, "", transaction);
739
}
740
catch (const std::exception& e)
741
{
742
GNS_LOG_ERROR("Error while processing message: {}", e.what());
741
- statusRoutine(-1, e.what());
743
+ statusRoutine(-1, e.what(), transaction);
744
}
745
}
746
src/linux/init/GnsEngine.h
+5
-3
@@ -21,10 +21,11 @@ public:
21
std::optional<GUID> AdapterId;
22
};
23
24
- using NotificationRoutine = std::function<std::optional<Message>()>;
25
- using StatusRoutine = std::function<void(int, const std::string&)>;
24
+ using NotificationRoutine = std::function<std::optional<Message>(wsl::shared::Transaction&)>;
25
+ using StatusRoutine = std::function<void(int, const std::string&, wsl::shared::Transaction&)>;
26
27
GnsEngine(
28
+ wsl::shared::SocketChannel& channel,
29
const NotificationRoutine& notificationRoutine,
30
const StatusRoutine& statusRoutine,
31
NetworkManager& manager,
@@ -36,7 +37,7 @@ public:
37
void run();
38
39
private:
39
- std::tuple<bool, int> ProcessNextMessage();
40
+ std::tuple<bool, int> ProcessNextMessage(wsl::shared::Transaction& transaction);
41
42
void ProcessNotification(const nlohmann::json& payload, Interface& interface);
43
@@ -69,6 +70,7 @@ private:
70
void ProcessNotificationImpl(
71
Interface& interface, const nlohmann::json& payload, void (GnsEngine::*routine)(Interface&, const T&, wsl::shared::hns::ModifyRequestType));
72
73
+ wsl::shared::SocketChannel& channel;
74
const NotificationRoutine& notificationRoutine;
75
const StatusRoutine& statusRoutine;
76
NetworkManager& manager;
src/linux/init/binfmt.cpp
+2
-1
@@ -174,7 +174,8 @@ try
174
// Send the create process message to the interop server.
175
//
176
177
- channel.SendMessage<LX_INIT_CREATE_NT_PROCESS_UTILITY_VM>(Span);
177
+ auto transaction = channel.StartTransaction();
178
+ transaction.Send<LX_INIT_CREATE_NT_PROCESS_UTILITY_VM>(Span);
179
180
//
181
// Accept connections from the interop server.
src/linux/init/config.cpp
+16
-15
@@ -334,7 +334,7 @@ try
334
CATCH_LOG()
335
336
void ConfigHandleInteropMessage(
337
- wsl::shared::SocketChannel& ResponseChannel,
337
+ wsl::shared::Transaction& Transaction,
338
wsl::shared::SocketChannel& InteropChannel,
339
bool Elevated,
340
gsl::span<gsl::byte> Message,
@@ -350,7 +350,7 @@ Routine Description:
350
351
Arguments:
352
353
- ResponseChannel - Supplies channel used to send responses.
353
+ Transaction - Supplies transaction used to send responses.
354
355
InteropChannel - Supplies a channel to the host to be used for create
356
process requests.
@@ -381,7 +381,7 @@ try
381
382
case LxInitMessageQueryDrvfsElevated:
383
{
384
- ResponseChannel.SendResultMessage<bool>(Elevated);
384
+ Transaction.SendResultMessage<bool>(Elevated);
385
break;
386
}
387
@@ -397,7 +397,7 @@ try
397
auto Value = UtilGetEnvironmentVariable(Query->Buffer);
398
wsl::shared::MessageWriter<LX_INIT_QUERY_ENVIRONMENT_VARIABLE> Response(LxInitMessageQueryEnvironmentVariable);
399
Response.WriteString(Value);
400
- ResponseChannel.SendMessage<LX_INIT_QUERY_ENVIRONMENT_VARIABLE>(Response.Span());
400
+ Transaction.Send<LX_INIT_QUERY_ENVIRONMENT_VARIABLE>(Response.Span());
401
}
402
403
break;
@@ -405,7 +405,7 @@ try
405
case LxInitMessageQueryFeatureFlags:
406
{
407
assert(Config.FeatureFlags.has_value());
408
- ResponseChannel.SendResultMessage<int32_t>(Config.FeatureFlags.value());
408
+ Transaction.SendResultMessage<int32_t>(Config.FeatureFlags.value());
409
break;
410
}
411
@@ -419,7 +419,7 @@ try
419
}
420
421
bool success = false;
422
- auto sendResponse = wil::scope_exit([&]() { ResponseChannel.SendResultMessage<bool>(success); });
422
+ auto sendResponse = wil::scope_exit([&]() { Transaction.SendResultMessage<bool>(success); });
423
424
if (!Config.BootInit || Config.InitPid.value_or(0) != getpid())
425
{
@@ -435,7 +435,7 @@ try
435
436
case LxInitMessageQueryNetworkingMode:
437
assert(Config.NetworkingMode.has_value());
438
- ResponseChannel.SendResultMessage<uint8_t>(static_cast<uint8_t>(Config.NetworkingMode.value()));
438
+ Transaction.SendResultMessage<uint8_t>(static_cast<uint8_t>(Config.NetworkingMode.value()));
439
break;
440
441
case LxInitMessageQueryVmId:
@@ -446,7 +446,7 @@ try
446
Response.WriteString(Config.VmId.value());
447
}
448
449
- ResponseChannel.SendMessage<LX_INIT_QUERY_VM_ID>(Response.Span());
449
+ Transaction.Send<LX_INIT_QUERY_VM_ID>(Response.Span());
450
break;
451
}
452
@@ -618,7 +618,7 @@ try
618
}
619
CATCH_LOG()
620
621
-int ConfigInitializeInstance(wsl::shared::SocketChannel& Channel, gsl::span<gsl::byte> Buffer, wsl::linux::WslDistributionConfig& Config)
621
+int ConfigInitializeInstance(const std::function<void(const gsl::span<gsl::byte>&)>& SendResponse, gsl::span<gsl::byte> Buffer, wsl::linux::WslDistributionConfig& Config)
622
623
/*++
624
@@ -632,7 +632,7 @@ Routine Description:
632
633
Arguments:
634
635
- MessageFd - Supplies a file descriptor to send the response message.
635
+ SendResponse - Supplies a function to send the response message.
636
637
Buffer - Supplies the message buffer.
638
@@ -923,7 +923,7 @@ try
923
Response.WriteString(Response->VersionIndex, Version->c_str());
924
}
925
926
- Channel.SendMessage<LX_INIT_CONFIGURATION_INFORMATION_RESPONSE>(Response.Span());
926
+ SendResponse(Response.Span());
927
928
//
929
// Accept the interop connection.
@@ -973,13 +973,14 @@ try
973
continue;
974
}
975
976
- auto [Message, Span] = ClientChannel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
976
+ auto transaction = ClientChannel.ReceiveTransaction();
977
+ auto [Message, Span] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
978
if (Message == nullptr)
979
{
980
continue;
981
}
982
982
- ConfigHandleInteropMessage(ClientChannel, InteropChannel, Elevated, Span, Message, Config);
983
+ ConfigHandleInteropMessage(transaction, InteropChannel, Elevated, Span, Message, Config);
984
}
985
});
986
@@ -2186,7 +2187,7 @@ Return Value:
2187
return Result;
2188
}
2189
2189
-int ConfigRemountDrvFs(gsl::span<gsl::byte> Buffer, wsl::shared::SocketChannel& Channel, const wsl::linux::WslDistributionConfig& Config)
2190
+int ConfigRemountDrvFs(gsl::span<gsl::byte> Buffer, wsl::shared::Transaction& Transaction, const wsl::linux::WslDistributionConfig& Config)
2191
2192
/*++
2193
@@ -2207,7 +2208,7 @@ Return Value:
2208
2209
--*/
2210
{
2210
- Channel.SendResultMessage<int32_t>(ConfigRemountDrvFsImpl(Buffer, Config));
2211
+ Transaction.SendResultMessage<int32_t>(ConfigRemountDrvFsImpl(Buffer, Config));
2212
2213
return 0;
2214
}
src/linux/init/config.h
+4
-3
@@ -20,6 +20,7 @@ Abstract:
20
#include <set>
21
#include <string_view>
22
#include <optional>
23
+#include <functional>
24
#include "SocketChannel.h"
25
#include "WslDistributionConfig.h"
26
@@ -399,7 +400,7 @@ std::set<std::pair<unsigned int, std::string>> ConfigGetMountedDrvFsVolumes(void
400
std::vector<std::pair<std::string, std::string>> ConfigGetWslgEnvironmentVariables(const wsl::linux::WslDistributionConfig& Config);
401
402
void ConfigHandleInteropMessage(
402
- wsl::shared::SocketChannel& ResponseChannel,
403
+ wsl::shared::Transaction& Transaction,
404
wsl::shared::SocketChannel& InteropChannel,
405
bool Elevated,
406
gsl::span<gsl::byte> Message,
@@ -408,7 +409,7 @@ void ConfigHandleInteropMessage(
409
410
void ConfigInitializeCgroups(wsl::linux::WslDistributionConfig& Config);
411
411
-int ConfigInitializeInstance(wsl::shared::SocketChannel& Channel, gsl::span<gsl::byte> Buffer, wsl::linux::WslDistributionConfig& Config);
412
+int ConfigInitializeInstance(const std::function<void(const gsl::span<gsl::byte>&)>& SendResponse, gsl::span<gsl::byte> Buffer, wsl::linux::WslDistributionConfig& Config);
413
414
void ConfigMountDrvFsVolumes(unsigned int DrvFsVolumes, uid_t OwnerUid, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config);
415
@@ -420,7 +421,7 @@ int ConfigRegisterBinfmtInterpreter(void);
421
422
int ConfigSetMountNamespace(bool Elevated);
423
423
-int ConfigRemountDrvFs(gsl::span<gsl::byte> Buffer, wsl::shared::SocketChannel& Channel, const wsl::linux::WslDistributionConfig& Config);
424
+int ConfigRemountDrvFs(gsl::span<gsl::byte> Buffer, wsl::shared::Transaction& Transaction, const wsl::linux::WslDistributionConfig& Config);
425
426
int ConfigRemountDrvFsImpl(gsl::span<gsl::byte> Buffer, const wsl::linux::WslDistributionConfig& Config);
427
src/linux/init/drvfs.cpp
+3
-2
@@ -209,8 +209,9 @@ Return Value:
209
QueryPortMessage.MessageType = LxInitMessageQueryDrvfsElevated;
210
QueryPortMessage.MessageSize = sizeof(QueryPortMessage);
211
212
- channel.SendMessage(QueryPortMessage);
213
- return channel.ReceiveMessage<RESULT_MESSAGE<bool>>().Result;
212
+ auto transaction = channel.StartTransaction();
213
+ transaction.Send(QueryPortMessage);
214
+ return transaction.Receive<RESULT_MESSAGE<bool>>().Result;
215
}
216
217
int MountFilesystem(const char* FsType, const char* Source, const char* Target, const char* Options, int* ExitCode)
src/linux/init/init.cpp
+71
-38
@@ -116,10 +116,15 @@ int InitConnectToServer(int LxBusFd, bool WaitForServer);
116
int InitCreateProcessUtilityVm(
117
gsl::span<gsl::byte> Message,
118
const LX_INIT_CREATE_PROCESS_UTILITY_VM& Header,
119
- wsl::shared::SocketChannel& MessageFd,
119
+ wsl::shared::Transaction& Transaction,
120
const wsl::linux::WslDistributionConfig& Config);
121
122
-int InitCreateSessionLeader(gsl::span<gsl::byte> Buffer, wsl::shared::SocketChannel& Channel, int LxBusFd, wsl::linux::WslDistributionConfig& Config);
122
+int InitCreateSessionLeader(
123
+ gsl::span<gsl::byte> Buffer,
124
+ wsl::shared::SocketChannel& Channel,
125
+ const std::function<void(LX_INIT_CREATE_SESSION_RESPONSE&)>& SendResponse,
126
+ int LxBusFd,
127
+ wsl::linux::WslDistributionConfig& Config);
128
129
void InitEntry(int Argc, char* Argv[]);
130
@@ -127,7 +132,7 @@ void InitEntryWsl(wsl::linux::WslDistributionConfig& Config);
132
133
void InitEntryUtilityVm(wsl::linux::WslDistributionConfig& Config);
134
130
-void InitTerminateInstance(gsl::span<gsl::byte> Buffer, wsl::shared::SocketChannel& Channel, wsl::linux::WslDistributionConfig& Config);
135
+void InitTerminateInstance(gsl::span<gsl::byte> Buffer, const std::function<void(bool)>& SendResult, wsl::linux::WslDistributionConfig& Config);
136
137
void InitTerminateInstanceInternal(const wsl::linux::WslDistributionConfig& Config);
138
@@ -1111,7 +1116,12 @@ Return Value:
1116
return 0;
1117
}
1118
1114
-int InitCreateSessionLeader(gsl::span<gsl::byte> Buffer, wsl::shared::SocketChannel& Channel, int LxBusFd, wsl::linux::WslDistributionConfig& Config)
1119
+int InitCreateSessionLeader(
1120
+ gsl::span<gsl::byte> Buffer,
1121
+ wsl::shared::SocketChannel& Channel,
1122
+ const std::function<void(LX_INIT_CREATE_SESSION_RESPONSE&)>& SendResponse,
1123
+ int LxBusFd,
1124
+ wsl::linux::WslDistributionConfig& Config)
1125
1126
/*++
1127
@@ -1228,7 +1238,7 @@ try
1238
Response.Header.MessageType = LxInitMessageCreateSessionResponse;
1239
Response.Header.MessageSize = sizeof(Response);
1240
Response.Port = SocketAddress.svm_port;
1231
- Channel.SendMessage(Response);
1241
+ SendResponse(Response);
1242
1243
if (!ListenSocket)
1244
{
@@ -1329,7 +1339,7 @@ Return Value:
1339
int InitCreateProcessUtilityVm(
1340
gsl::span<gsl::byte> Span,
1341
const LX_INIT_CREATE_PROCESS_UTILITY_VM& CreateProcess,
1332
- wsl::shared::SocketChannel& Channel,
1342
+ wsl::shared::Transaction& Transaction,
1343
const wsl::linux::WslDistributionConfig& Config)
1344
1345
/*++
@@ -1414,7 +1424,7 @@ Return Value:
1424
// Tell the service which sockets ports to connect to.
1425
//
1426
1417
- Channel.SendResultMessage<uint32_t>(SocketAddress.svm_port);
1427
+ Transaction.SendResultMessage<uint32_t>(SocketAddress.svm_port);
1428
1429
//
1430
// Exit if creating the listening socket failed.
@@ -1978,13 +1988,14 @@ Return Value:
1988
continue;
1989
}
1990
1981
- auto [Header, Span] = channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
1991
+ auto transaction = channel.ReceiveTransaction();
1992
+ auto [Header, Span] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
1993
if (Header != nullptr)
1994
{
1995
try
1996
{
1997
ConfigHandleInteropMessage(
1987
- channel, ControlChannel, WI_IsFlagSet(CreateProcess.Common.Flags, LxInitCreateProcessFlagsElevated), Span, Header, Config);
1998
+ transaction, ControlChannel, WI_IsFlagSet(CreateProcess.Common.Flags, LxInitCreateProcessFlagsElevated), Span, Header, Config);
1999
}
2000
CATCH_LOG();
2001
}
@@ -2455,7 +2466,8 @@ Return Value:
2466
}
2467
else if (PollDescriptors[0].revents & POLLIN)
2468
{
2458
- auto [Header, Span] = channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
2469
+ auto transaction = channel.ReceiveTransaction();
2470
+ auto [Header, Span] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
2471
if (Header == nullptr)
2472
{
2473
break;
@@ -2464,16 +2476,23 @@ Return Value:
2476
switch (Header->MessageType)
2477
{
2478
case LxInitMessageCreateSession:
2467
- if (InitCreateSessionLeader(Span, channel, -1, Config) < 0)
2479
+ {
2480
+ auto SendResponse = [&](LX_INIT_CREATE_SESSION_RESPONSE& response) { transaction.Send(response); };
2481
+ if (InitCreateSessionLeader(Span, channel, SendResponse, -1, Config) < 0)
2482
{
2483
FATAL_ERROR("InitCreateSessionLeader failed");
2484
}
2471
-
2472
- break;
2485
+ }
2486
+ break;
2487
2488
case LxInitMessageInitialize:
2475
- ConfigInitializeInstance(channel, Span, Config);
2476
- break;
2489
+ {
2490
+ auto SendResponse = [&](const gsl::span<gsl::byte>& span) {
2491
+ transaction.Send<LX_INIT_CONFIGURATION_INFORMATION_RESPONSE>(span);
2492
+ };
2493
+ ConfigInitializeInstance(SendResponse, Span, Config);
2494
+ }
2495
+ break;
2496
2497
case LxInitMessageTimezoneInformation:
2498
UpdateTimezone(Span, Config);
@@ -2489,15 +2508,18 @@ Return Value:
2508
//
2509
2510
WaitForBootProcess(Config);
2492
- ConfigRemountDrvFs(Span, channel, Config);
2511
+ ConfigRemountDrvFs(Span, transaction, Config);
2512
break;
2513
2514
case LxInitMessageTerminateInstance:
2496
- InitTerminateInstance(Span, channel, Config);
2497
- break;
2515
+ {
2516
+ auto SendResult = [&](bool result) { transaction.SendResultMessage<bool>(result); };
2517
+ InitTerminateInstance(Span, SendResult, Config);
2518
+ }
2519
+ break;
2520
2521
case LxInitCreateProcess:
2500
- ProcessCreateProcessMessage(channel, Span);
2522
+ ProcessCreateProcessMessage(transaction, Span);
2523
break;
2524
2525
default:
@@ -2612,7 +2634,9 @@ Return Value:
2634
switch (Header->MessageType)
2635
{
2636
case LxInitMessageCreateSession:
2615
- if (InitCreateSessionLeader(Message, Channel, LxBusFd.get(), Config) < 0)
2637
+ {
2638
+ auto SendResponse = [&](LX_INIT_CREATE_SESSION_RESPONSE& response) { Channel.SendMessage(response); };
2639
+ if (InitCreateSessionLeader(Message, Channel, SendResponse, LxBusFd.get(), Config) < 0)
2640
{
2641
//
2642
// If this distro has no children, exit on failure.
@@ -2626,24 +2650,32 @@ Return Value:
2650
2651
LOG_ERROR("InitCreateSessionLeader failed");
2652
}
2629
-
2630
- break;
2653
+ }
2654
+ break;
2655
2656
case LxInitMessageNetworkInformation:
2657
ConfigUpdateNetworkInformation(Message, Config);
2658
break;
2659
2660
case LxInitMessageInitialize:
2637
- ConfigInitializeInstance(Channel, Message, Config);
2638
- break;
2661
+ {
2662
+ auto SendResponse = [&](const gsl::span<gsl::byte>& span) {
2663
+ Channel.SendMessage<LX_INIT_CONFIGURATION_INFORMATION_RESPONSE>(span);
2664
+ };
2665
+ ConfigInitializeInstance(SendResponse, Message, Config);
2666
+ }
2667
+ break;
2668
2669
case LxInitMessageTimezoneInformation:
2670
UpdateTimezone(Message, Config);
2671
break;
2672
2673
case LxInitMessageTerminateInstance:
2645
- InitTerminateInstance(Message, Channel, Config);
2646
- break;
2674
+ {
2675
+ auto SendResult = [&](bool result) { Channel.SendResultMessage<bool>(result); };
2676
+ InitTerminateInstance(Message, SendResult, Config);
2677
+ }
2678
+ break;
2679
2680
default:
2681
FATAL_ERROR("Unexpected message {}", Header->MessageType);
@@ -2653,7 +2685,7 @@ Return Value:
2685
return;
2686
}
2687
2656
-void InitTerminateInstance(gsl::span<gsl::byte> Buffer, wsl::shared::SocketChannel& Channel, wsl::linux::WslDistributionConfig& Config)
2688
+void InitTerminateInstance(gsl::span<gsl::byte> Buffer, const std::function<void(bool)>& SendResult, wsl::linux::WslDistributionConfig& Config)
2689
2690
/*++
2691
@@ -2665,7 +2697,7 @@ Arguments:
2697
2698
Buffer - Supplies the message buffer.
2699
2668
- Channel - Supplies a channel to send the response.
2700
+ SendResult - Supplies a function to send the response.
2701
2702
Config - Supplies the distribution config.
2703
@@ -2690,7 +2722,7 @@ try
2722
2723
if (!StopPlan9Server(Message->Force, Config))
2724
{
2693
- Channel.SendResultMessage<bool>(false);
2725
+ SendResult(false);
2726
return;
2727
}
2728
@@ -3036,7 +3068,8 @@ Return Value:
3068
3069
for (;;)
3070
{
3039
- auto [Message, Span] = channel.ReceiveMessageOrClosed<LX_INIT_CREATE_PROCESS_UTILITY_VM>();
3071
+ auto transaction = channel.ReceiveTransaction();
3072
+ auto [Message, Span] = transaction.ReceiveOrClosed<LX_INIT_CREATE_PROCESS_UTILITY_VM>();
3073
if (Message == nullptr)
3074
{
3075
_exit(0);
@@ -3045,7 +3078,7 @@ Return Value:
3078
switch (Message->Header.MessageType)
3079
{
3080
case LxInitMessageCreateProcessUtilityVm:
3048
- if (InitCreateProcessUtilityVm(Span, *Message, channel, Config) < 0)
3081
+ if (InitCreateProcessUtilityVm(Span, *Message, transaction, Config) < 0)
3082
{
3083
FATAL_ERROR("InitCreateProcessUtilityVm failed");
3084
}
@@ -3294,7 +3327,7 @@ unsigned int StartGns(int Argc, char** Argv)
3327
3328
if (channel.Socket() == -1)
3329
{
3297
- readNotification = [&]() -> std::optional<GnsEngine::Message> {
3330
+ readNotification = [&](wsl::shared::Transaction&) -> std::optional<GnsEngine::Message> {
3331
std::string content{std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>()};
3332
if (content.empty())
3333
{
@@ -3308,7 +3341,7 @@ unsigned int StartGns(int Argc, char** Argv)
3341
return {{AdapterId.has_value() ? LxGnsMessageNotification : LxGnsMessageInterfaceConfiguration, content, AdapterId}};
3342
};
3343
3311
- returnStatus = [&](int Result, const std::string& Error) {
3344
+ returnStatus = [&](int Result, const std::string& Error, wsl::shared::Transaction&) {
3345
GNS_LOG_INFO("Returning LxGnsMessageResult (no output fd) [{} - {}]", Result, Error.c_str());
3346
// exitCode keeps the most recent error in the test path
3347
if (Result != 0)
@@ -3320,9 +3353,9 @@ unsigned int StartGns(int Argc, char** Argv)
3353
}
3354
else
3355
{
3323
- readNotification = [&]() -> std::optional<GnsEngine::Message> {
3356
+ readNotification = [&](wsl::shared::Transaction& transaction) -> std::optional<GnsEngine::Message> {
3357
std::vector<gsl::byte> Buffer;
3325
- auto [Message, Span] = channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
3358
+ auto [Message, Span] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
3359
if (Message == nullptr)
3360
{
3361
return {};
@@ -3385,7 +3418,7 @@ unsigned int StartGns(int Argc, char** Argv)
3418
}
3419
};
3420
3388
- returnStatus = [&](int Result, const std::string& Error) {
3421
+ returnStatus = [&](int Result, const std::string& Error, wsl::shared::Transaction& transaction) {
3422
std::vector<gsl::byte> Buffer(sizeof(LX_GNS_RESULT) + Error.size() + 1);
3423
3424
GNS_LOG_INFO("Returning LxGnsMessageResult [{} - {}]", Result, Error.c_str());
@@ -3397,13 +3430,13 @@ unsigned int StartGns(int Argc, char** Argv)
3430
response.WriteString(Error);
3431
}
3432
3400
- return channel.SendMessage<LX_GNS_RESULT>(response.Span());
3433
+ return transaction.Send<LX_GNS_RESULT>(response.Span());
3434
};
3435
}
3436
3437
RoutingTable routingTable(RT_TABLE_MAIN);
3438
NetworkManager manager(routingTable);
3406
- GnsEngine engine(readNotification, returnStatus, manager, DnsFd, DnsTunnelingIp);
3439
+ GnsEngine engine(channel, readNotification, returnStatus, manager, DnsFd, DnsTunnelingIp);
3440
3441
engine.run();
3442
src/linux/init/localhost.cpp
+4
-2
@@ -246,7 +246,8 @@ try
246
{
247
auto message = SockToRelayMessage(sock);
248
message.Header.MessageType = LxGnsMessagePortListenerRelayStart;
249
- channel.SendMessage(message);
249
+ auto transaction = channel.StartTransaction();
250
+ transaction.Send(message);
251
252
return 0;
253
}
@@ -257,7 +258,8 @@ try
258
{
259
auto message = SockToRelayMessage(sock);
260
message.Header.MessageType = LxGnsMessagePortListenerRelayStop;
260
- channel.SendMessage(message);
261
+ auto transaction = channel.StartTransaction();
262
+ transaction.Send(message);
263
264
return 0;
265
}
src/linux/init/main.cpp
+11
-12
@@ -193,7 +193,7 @@ int MountInit(const char* Target);
193
194
int MountPlan9(const char* Name, const char* Target, bool ReadOnly, std::optional<int> BufferSize = {});
195
196
-int ProcessMessage(wsl::shared::SocketChannel& channel, LX_MESSAGE_TYPE Type, gsl::span<gsl::byte> Buffer, VmConfiguration& Config);
196
+int ProcessMessage(wsl::shared::Transaction& Transaction, LX_MESSAGE_TYPE Type, gsl::span<gsl::byte> Buffer, VmConfiguration& Config);
197
198
wil::unique_fd RegisterSeccompHook();
199
@@ -2808,7 +2808,7 @@ void ProcessImportExportMessage(gsl::span<gsl::byte> Buffer, wsl::shared::Socket
2808
}
2809
}
2810
2811
-int ProcessMountFolderMessage(wsl::shared::SocketChannel& Channel, gsl::span<gsl::byte> Buffer)
2811
+int ProcessMountFolderMessage(wsl::shared::Transaction& Transaction, gsl::span<gsl::byte> Buffer)
2812
2813
/*++
2814
@@ -2844,7 +2844,7 @@ Return Value:
2844
}
2845
2846
int Result = MountPlan9(Name, Target, Message->ReadOnly);
2847
- Channel.SendResultMessage<int32_t>(Result);
2847
+ Transaction.SendResultMessage<int32_t>(Result);
2848
return 0;
2849
}
2850
@@ -3163,7 +3163,7 @@ try
3163
}
3164
CATCH_RETURN_ERRNO();
3165
3166
-int ProcessMessage(wsl::shared::SocketChannel& Channel, LX_MESSAGE_TYPE Type, gsl::span<gsl::byte> Buffer, VmConfiguration& Config)
3166
+int ProcessMessage(wsl::shared::Transaction& Transaction, LX_MESSAGE_TYPE Type, gsl::span<gsl::byte> Buffer, VmConfiguration& Config)
3167
3168
/*++
3169
@@ -3173,9 +3173,7 @@ Routine Description:
3173
3174
Arguments:
3175
3176
- MessageFd - Supplies a file descriptor to the socket on which the message was
3177
- received. This is used for operations that require responses, for example a
3178
- VHD eject request.
3176
+ Transaction - Supplies the transaction for replying to the message.
3177
3178
Buffer - Supplies the message.
3179
@@ -3259,7 +3257,7 @@ try
3257
return -1;
3258
}
3259
3262
- Channel.SendResultMessage(EjectScsi(EjectMessage->Lun));
3260
+ Transaction.SendResultMessage(EjectScsi(EjectMessage->Lun));
3261
return 0;
3262
}
3263
@@ -3495,10 +3493,10 @@ try
3493
return 0;
3494
3495
case LxMiniInitMountFolder:
3498
- return ProcessMountFolderMessage(Channel, Buffer);
3496
+ return ProcessMountFolderMessage(Transaction, Buffer);
3497
3498
case LxInitCreateProcess:
3501
- return ProcessCreateProcessMessage(Channel, Buffer);
3499
+ return ProcessCreateProcessMessage(Transaction, Buffer);
3500
3501
case LxMiniInitMessageWaitForPmemDevice:
3502
{
@@ -4175,13 +4173,14 @@ int main(int Argc, char* Argv[])
4173
}
4174
else if (PollDescriptors[0].revents & POLLIN)
4175
{
4178
- auto [Message, Range] = channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
4176
+ auto transaction = channel.ReceiveTransaction();
4177
+ auto [Message, Range] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
4178
if (Message == nullptr)
4179
{
4180
break; // Socket was closed, exit
4181
}
4182
4184
- Result = ProcessMessage(channel, Message->MessageType, Range, Config);
4183
+ Result = ProcessMessage(transaction, Message->MessageType, Range, Config);
4184
if (Result < 0)
4185
{
4186
goto ErrorExit;
src/linux/init/plan9.cpp
+3
-2
@@ -157,13 +157,14 @@ try
157
std::vector<gsl::byte> Buffer;
158
for (;;)
159
{
160
- auto [Message, _] = channel.ReceiveMessageOrClosed<LX_INIT_STOP_PLAN9_SERVER>();
160
+ auto transaction = channel.ReceiveTransaction();
161
+ auto [Message, _] = transaction.ReceiveOrClosed<LX_INIT_STOP_PLAN9_SERVER>();
162
if (Message == nullptr)
163
{
164
_exit(0);
165
}
166
166
- channel.SendResultMessage<bool>(StopPlan9Server(fileSystem, Message->Force));
167
+ transaction.SendResultMessage<bool>(StopPlan9Server(fileSystem, Message->Force));
168
}
169
}
170
CATCH_LOG();
src/linux/init/util.cpp
+14
-10
@@ -1110,13 +1110,14 @@ try
1110
wsl::shared::MessageWriter<LX_INIT_QUERY_ENVIRONMENT_VARIABLE> Message(LxInitMessageQueryEnvironmentVariable);
1111
Message.WriteString(Name);
1112
1113
- channel.SendMessage<LX_INIT_QUERY_ENVIRONMENT_VARIABLE>(Message.Span());
1113
+ auto transaction = channel.StartTransaction();
1114
+ transaction.Send<LX_INIT_QUERY_ENVIRONMENT_VARIABLE>(Message.Span());
1115
1116
//
1117
// Read a response, this will contain the environment variable value if it exists.
1118
//
1119
1119
- Value = channel.ReceiveMessage<LX_INIT_QUERY_ENVIRONMENT_VARIABLE>().Buffer;
1120
+ Value = transaction.Receive<LX_INIT_QUERY_ENVIRONMENT_VARIABLE>().Buffer;
1121
1122
//
1123
// Set the environment variable for future queries.
@@ -1195,8 +1196,9 @@ Return Value:
1196
Message.MessageType = LxInitMessageQueryFeatureFlags;
1197
Message.MessageSize = sizeof(Message);
1198
1198
- channel.SendMessage(Message);
1199
- FeatureFlags = channel.ReceiveMessage<RESULT_MESSAGE<int32_t>>().Result;
1199
+ auto transaction = channel.StartTransaction();
1200
+ transaction.Send(Message);
1201
+ FeatureFlags = transaction.Receive<RESULT_MESSAGE<int32_t>>().Result;
1202
}
1203
1204
UtilSetFeatureFlags(FeatureFlags, FeatureFlagEnv == nullptr);
@@ -1264,9 +1266,10 @@ try
1266
Message.MessageType = LxInitMessageQueryNetworkingMode;
1267
Message.MessageSize = sizeof(Message);
1268
1267
- channel.SendMessage(Message);
1269
+ auto transaction = channel.StartTransaction();
1270
+ transaction.Send(Message);
1271
1269
- const auto& response = channel.ReceiveMessage<RESULT_MESSAGE<uint8_t>>();
1272
+ const auto& response = transaction.Receive<RESULT_MESSAGE<uint8_t>>();
1273
auto NetworkingMode = static_cast<LX_MINI_INIT_NETWORKING_MODE>(response.Result);
1274
1275
THROW_ERRNO_IF(EINVAL, NetworkingMode < LxMiniInitNetworkingModeNone || NetworkingMode > LxMiniInitNetworkingModeVirtioProxy);
@@ -1358,9 +1361,10 @@ try
1361
THROW_LAST_ERROR_IF(channel.Socket() < 0);
1362
1363
wsl::shared::MessageWriter<LX_INIT_QUERY_VM_ID> Message(LxInitMessageQueryVmId);
1361
- channel.SendMessage<LX_INIT_QUERY_VM_ID>(Message.Span());
1364
+ auto transaction = channel.StartTransaction();
1365
+ transaction.Send<LX_INIT_QUERY_VM_ID>(Message.Span());
1366
1363
- return channel.ReceiveMessage<LX_INIT_QUERY_VM_ID>().Buffer;
1367
+ return transaction.Receive<LX_INIT_QUERY_VM_ID>().Buffer;
1368
}
1369
catch (...)
1370
{
@@ -3344,7 +3348,7 @@ Return Value:
3348
return 0;
3349
}
3350
3347
-int ProcessCreateProcessMessage(wsl::shared::SocketChannel& channel, gsl::span<gsl::byte> Buffer)
3351
+int ProcessCreateProcessMessage(wsl::shared::Transaction& Transaction, gsl::span<gsl::byte> Buffer)
3352
{
3353
auto* Message = gslhelpers::try_get_struct<CREATE_PROCESS_MESSAGE>(Buffer);
3354
if (!Message)
@@ -3353,7 +3357,7 @@ int ProcessCreateProcessMessage(wsl::shared::SocketChannel& channel, gsl::span<g
3357
return -1;
3358
}
3359
3356
- auto sendResult = [&](unsigned long Result) { channel.SendResultMessage<int32_t>(Result); };
3360
+ auto sendResult = [&](unsigned long Result) { Transaction.SendResultMessage<int32_t>(Result); };
3361
3362
sockaddr_vm SocketAddress{};
3363
wil::unique_fd ListenSocket{UtilListenVsockAnyPort(&SocketAddress, 1, false)};
src/linux/init/util.h
+3
-2
@@ -35,7 +35,8 @@ Abstract:
35
36
namespace wsl::shared {
37
class SocketChannel;
38
-}
38
+class Transaction;
39
+} // namespace wsl::shared
40
41
namespace wsl::linux {
42
struct WslDistributionConfig;
@@ -312,4 +313,4 @@ uint16_t UtilWinAfToLinuxAf(uint16_t AddressFamily);
313
314
int WriteToFile(const char* Path, const char* Content, int permissions = 0644);
315
315
-int ProcessCreateProcessMessage(wsl::shared::SocketChannel& channel, gsl::span<gsl::byte> Buffer);
\ No newline at end of file
316
+int ProcessCreateProcessMessage(wsl::shared::Transaction& Transaction, gsl::span<gsl::byte> Buffer);
\ No newline at end of file
src/shared/inc/SocketChannel.h
+317
-34
@@ -14,6 +14,7 @@ Abstract:
14
15
#pragma once
16
17
+#include <atomic>
18
#include <mutex>
19
#include "socketshared.h"
20
#include "lxinitshared.h"
@@ -41,6 +42,44 @@ constexpr timeval* DefaultSocketTimeout = nullptr;
42
43
#endif
44
45
+class SocketChannel;
46
+
47
+class Transaction
48
+{
49
+ friend class SocketChannel;
50
+
51
+public:
52
+ ~Transaction() = default;
53
+
54
+ NON_COPYABLE(Transaction);
55
+
56
+ template <typename TMessage>
57
+ void Send(gsl::span<gsl::byte> span);
58
+
59
+ template <typename TMessage>
60
+ void Send(TMessage& message);
61
+
62
+ template <typename TResult>
63
+ void SendResultMessage(TResult value);
64
+
65
+ template <typename TMessage>
66
+ std::pair<TMessage*, gsl::span<gsl::byte>> ReceiveOrClosed(TTimeout timeout = DefaultSocketTimeout);
67
+
68
+ template <typename TMessage>
69
+ TMessage& Receive(gsl::span<gsl::byte>* responseSpan = nullptr, TTimeout timeout = DefaultSocketTimeout);
70
+
71
+private:
72
+ Transaction(SocketChannel& channel, uint32_t id) :
73
+ m_channel(channel), m_id(id), m_step(static_cast<uint32_t>(TRANSACTION_STEP::REQUEST))
74
+ {
75
+ }
76
+
77
+ SocketChannel& m_channel;
78
+ uint32_t m_id;
79
+ /** Use uint32_t as step can go beyond FIRST_REPLY */
80
+ uint32_t m_step;
81
+};
82
+
83
class SocketChannel
84
{
85
@@ -63,6 +102,9 @@ public:
102
m_exitEvent = std::move(other.m_exitEvent);
103
#endif
104
m_ignore_sequence = other.m_ignore_sequence;
105
+ m_sent_non_transaction_messages = other.m_sent_non_transaction_messages;
106
+ m_received_non_transaction_messages = other.m_received_non_transaction_messages;
107
+ m_transaction_id_seed = other.m_transaction_id_seed.load();
108
109
return *this;
110
}
@@ -82,7 +124,7 @@ public:
124
#endif
125
126
template <typename TMessage>
85
- void SendMessage(gsl::span<gsl::byte> span)
127
+ void SendMessage(gsl::span<gsl::byte> span, uint32_t transactionStep = static_cast<uint32_t>(TRANSACTION_STEP::NONE), uint32_t transactionId = 0)
128
{
129
// Ensure that no other thread is using this channel.
130
const std::unique_lock<std::mutex> lock{m_sendMutex, std::try_to_lock};
@@ -103,12 +145,20 @@ public:
145
146
THROW_INVALID_ARG_IF(m_name == nullptr || span.size() < sizeof(TMessage));
147
106
- m_sent_messages++;
107
-
148
auto* header = gslhelpers::try_get_struct<MESSAGE_HEADER>(span);
149
WI_ASSERT(header->MessageSize == span.size());
150
111
- header->SequenceNumber = m_sent_messages;
151
+ if (transactionStep == static_cast<unsigned int>(TRANSACTION_STEP::NONE))
152
+ {
153
+ m_sent_non_transaction_messages++;
154
+ header->TransactionId = m_sent_non_transaction_messages;
155
+ header->TransactionStep = static_cast<unsigned int>(TRANSACTION_STEP::NONE);
156
+ }
157
+ else
158
+ {
159
+ header->TransactionId = transactionId;
160
+ header->TransactionStep = transactionStep;
161
+ }
162
163
#ifdef WIN32
164
@@ -150,7 +200,7 @@ public:
200
}
201
202
template <typename TMessage>
153
- void SendMessage(TMessage& message)
203
+ void SendMessage(TMessage& message, uint32_t transactionStep = static_cast<uint32_t>(TRANSACTION_STEP::NONE), uint32_t transactionId = 0)
204
{
205
// Catch situations where the other SendMessage() method should be used
206
const auto& header = GetMessageHeader(message);
@@ -164,7 +214,7 @@ public:
214
#endif
215
}
216
167
- SendMessage<TMessage>(gslhelpers::struct_as_writeable_bytes(message));
217
+ SendMessage<TMessage>(gslhelpers::struct_as_writeable_bytes(message), transactionStep, transactionId);
218
}
219
220
template <typename TResult>
@@ -179,7 +229,10 @@ public:
229
}
230
231
template <typename TMessage>
182
- std::pair<TMessage*, gsl::span<gsl::byte>> ReceiveMessageOrClosed(TTimeout timeout = DefaultSocketTimeout)
232
+ std::pair<TMessage*, gsl::span<gsl::byte>> ReceiveMessageOrClosed(
233
+ TTimeout timeout = DefaultSocketTimeout,
234
+ uint32_t expectedTransactionStep = static_cast<uint32_t>(TRANSACTION_STEP::NONE),
235
+ uint32_t expectedTransactionId = 0)
236
{
237
WI_ASSERT(m_name != nullptr);
238
@@ -199,20 +252,180 @@ public:
252
#endif
253
}
254
202
- m_received_messages++;
203
-
204
- auto receivedSpan = ReceiveImpl(TMessage::Type, timeout);
205
- if (receivedSpan.empty())
255
+ gsl::span<gsl::byte> receivedSpan{};
256
+ for (;;)
257
{
258
+ if (expectedTransactionStep == static_cast<uint32_t>(TRANSACTION_STEP::NONE))
259
+ {
260
+ // Adhere to the old ++ before receive behavior for non-transaction messages.
261
+ m_received_non_transaction_messages++;
262
+ }
263
+
264
+ receivedSpan = ReceiveImpl(TMessage::Type, timeout);
265
+ if (receivedSpan.empty())
266
+ {
267
+
268
+#ifdef WIN32
269
+ if (errno == HCS_E_CONNECTION_TIMEOUT)
270
+ {
271
+ THROW_HR_MSG(HCS_E_CONNECTION_TIMEOUT, "Timeout: %u, expected type: %hs, channel: %hs", timeout, ToString(TMessage::Type), m_name);
272
+ }
273
+#endif
274
+
275
+ return {nullptr, {}};
276
+ }
277
+
278
+ auto* header = gslhelpers::try_get_struct<MESSAGE_HEADER>(receivedSpan);
279
+ if (header == nullptr)
280
+ {
281
+#ifdef WIN32
282
+ THROW_HR_MSG(E_UNEXPECTED, "Message too small for header: %zd, channel: %hs", receivedSpan.size(), m_name);
283
+#else
284
+ LOG_ERROR("Message too small for header: {}, channel: {}", receivedSpan.size(), m_name);
285
+ THROW_ERRNO(EINVAL);
286
+#endif
287
+ }
288
+
289
+ if (expectedTransactionStep == static_cast<uint32_t>(TRANSACTION_STEP::NONE))
290
+ {
291
+ // Handle non-transaction messages with legacy logic.
292
+ if (!m_ignore_sequence)
293
+ {
294
+ if (header->TransactionStep != static_cast<unsigned int>(TRANSACTION_STEP::NONE))
295
+ {
296
+#ifdef WIN32
297
+ THROW_HR_MSG(
298
+ E_UNEXPECTED,
299
+ "Unexpected transaction message received on non-transaction channel: %hs, message type: %hs",
300
+ m_name,
301
+ ToString(header->MessageType));
302
+#else
303
+ LOG_ERROR(
304
+ "Unexpected transaction message received on non-transaction channel: {}, message type: {}",
305
+ m_name,
306
+ ToString(header->MessageType));
307
+ THROW_ERRNO(EINVAL);
308
+#endif
309
+ }
310
+ if (header->TransactionId != m_received_non_transaction_messages)
311
+ {
312
+#ifdef WIN32
313
+ THROW_HR_MSG(
314
+ E_UNEXPECTED,
315
+ "Unexpected non-transaction message id: %u, expected: %u, channel: %hs",
316
+ header->TransactionId,
317
+ m_received_non_transaction_messages,
318
+ m_name);
319
+#else
320
+ LOG_ERROR("Unexpected non-transaction message id: {}, expected: {}, channel: {}", header->TransactionId, m_received_non_transaction_messages, m_name);
321
+ THROW_ERRNO(EINVAL);
322
+#endif
323
+ }
324
+ }
325
+ break;
326
+ }
327
328
+ // Handle transaction messages
329
+ if (header->TransactionStep == static_cast<uint32_t>(TRANSACTION_STEP::NONE))
330
+ {
331
+ // Skip stale non-transaction messages
332
#ifdef WIN32
209
- if (errno == HCS_E_CONNECTION_TIMEOUT)
333
+ WSL_LOG(
334
+ "DiscardStaleNonTransactionMessage",
335
+ TraceLoggingValue(m_name, "Name"),
336
+ TraceLoggingValue(ToString(header->MessageType), "MessageType"),
337
+ TraceLoggingValue(ToString(TMessage::Type), "ExpectedMessageType"),
338
+ TraceLoggingValue(header->TransactionId, "StaleNonTransactionId"),
339
+ TraceLoggingValue(m_received_non_transaction_messages, "ExpectedNonTransactionId"));
340
+#else
341
+ LOG_WARNING(
342
+ "Discard stale non-transaction message on channel: {}. MessageType: {}, ExpectedMessageType: {}, "
343
+ "StaleNonTransactionId: {}, ExpectedNonTransactionId: {}",
344
+ m_name,
345
+ header->MessageType,
346
+ TMessage::Type,
347
+ header->TransactionId,
348
+ m_received_non_transaction_messages);
349
+#endif
350
+ continue;
351
+ }
352
+
353
+ if (expectedTransactionStep == static_cast<uint32_t>(TRANSACTION_STEP::REQUEST))
354
{
211
- THROW_HR_MSG(HCS_E_CONNECTION_TIMEOUT, "Timeout: %d, expected type: %hs, channel: %hs", timeout, ToString(TMessage::Type), m_name);
355
+ // Skip until we get the next request. No matter the transaction id.
356
+ if (header->TransactionStep != static_cast<unsigned int>(TRANSACTION_STEP::REQUEST))
357
+ {
358
+#ifdef WIN32
359
+ WSL_LOG(
360
+ "DiscardOutOfOrderTransactionMessage",
361
+ TraceLoggingValue(m_name, "Name"),
362
+ TraceLoggingValue(ToString(header->MessageType), "MessageType"),
363
+ TraceLoggingValue(ToString(TMessage::Type), "ExpectedMessageType"),
364
+ TraceLoggingValue(header->TransactionStep, "StaleTransactionStep"),
365
+ TraceLoggingValue(expectedTransactionStep, "ExpectedTransactionStep"));
366
+#else
367
+ LOG_WARNING(
368
+ "Discard out of order transaction message on channel: {}. MessageType: {}, ExpectedMessageType: {}, "
369
+ "StaleTransactionStep: {}, ExpectedTransactionStep: {}",
370
+ m_name,
371
+ header->MessageType,
372
+ TMessage::Type,
373
+ header->TransactionStep,
374
+ expectedTransactionStep);
375
+#endif
376
+ continue;
377
+ }
378
+ break;
379
}
380
+
381
+ auto diff = static_cast<int32_t>(header->TransactionId - expectedTransactionId);
382
+ if (diff < 0)
383
+ {
384
+ // Skip stale transaction messages
385
+#ifdef WIN32
386
+ WSL_LOG(
387
+ "DiscardStaleTransactionMessage",
388
+ TraceLoggingValue(m_name, "Name"),
389
+ TraceLoggingValue(ToString(header->MessageType), "MessageType"),
390
+ TraceLoggingValue(ToString(TMessage::Type), "ExpectedMessageType"),
391
+ TraceLoggingValue(header->TransactionId, "StaleTransactionId"),
392
+ TraceLoggingValue(expectedTransactionId, "ExpectedTransactionId"));
393
+#else
394
+ LOG_WARNING(
395
+ "Discard stale transaction message on channel: {}. MessageType: {}, ExpectedMessageType: {}, "
396
+ "StaleTransactionId: {}, ExpectedTransactionId: {}",
397
+ m_name,
398
+ header->MessageType,
399
+ TMessage::Type,
400
+ header->TransactionId,
401
+ expectedTransactionId);
402
+#endif
403
+ continue;
404
+ }
405
+
406
+ if (diff > 0)
407
+ {
408
+ // Message is from the future.
409
+#ifdef WIN32
410
+ THROW_HR_MSG(E_UNEXPECTED, "Unexpected transaction message id: %u, expected: %u, channel: %hs", header->TransactionId, expectedTransactionId, m_name);
411
+#else
412
+ LOG_ERROR("Unexpected transaction message id: {}, expected: {}, channel: {}", header->TransactionId, expectedTransactionId, m_name);
413
+ THROW_ERRNO(EINVAL);
414
+#endif
415
+ }
416
+
417
+ if (header->TransactionStep != expectedTransactionStep)
418
+ {
419
+ // Broken transaction.
420
+#ifdef WIN32
421
+ THROW_HR_MSG(E_UNEXPECTED, "Unexpected transaction message step: %u, expected: %u, channel: %hs", header->TransactionStep, expectedTransactionStep, m_name);
422
+#else
423
+ LOG_ERROR("Unexpected transaction message step: {}, expected: {}, channel: {}", header->TransactionStep, expectedTransactionStep, m_name);
424
+ THROW_ERRNO(EINVAL);
425
#endif
426
+ }
427
215
- return {nullptr, {}};
428
+ break;
429
}
430
431
auto* message = gslhelpers::try_get_struct<TMessage>(receivedSpan);
@@ -228,7 +441,7 @@ public:
441
#endif
442
}
443
231
- ValidateMessageHeader(GetMessageHeader(*message), TMessage::Type, m_received_messages);
444
+ ValidateMessageHeader(GetMessageHeader(*message), TMessage::Type);
445
446
#ifdef WIN32
447
WSL_LOG(
@@ -243,9 +456,13 @@ public:
456
}
457
458
template <typename TMessage>
246
- TMessage& ReceiveMessage(gsl::span<gsl::byte>* responseSpan = nullptr, TTimeout timeout = DefaultSocketTimeout)
459
+ TMessage& ReceiveMessage(
460
+ gsl::span<gsl::byte>* responseSpan = nullptr,
461
+ TTimeout timeout = DefaultSocketTimeout,
462
+ uint32_t expectedTransactionStep = static_cast<uint32_t>(TRANSACTION_STEP::NONE),
463
+ uint32_t expectedTransactionId = 0)
464
{
248
- auto [message, span] = ReceiveMessageOrClosed<TMessage>(timeout);
465
+ auto [message, span] = ReceiveMessageOrClosed<TMessage>(timeout, expectedTransactionStep, expectedTransactionId);
466
if (message == nullptr)
467
{
468
#ifdef WIN32
@@ -264,16 +481,28 @@ public:
481
return *message;
482
}
483
267
- template <typename TSentMessage>
268
- TSentMessage::TResponse& Transaction(gsl::span<gsl::byte> message, gsl::span<gsl::byte>* responseSpan = nullptr, TTimeout timeout = DefaultSocketTimeout)
484
+ Transaction StartTransaction()
485
+ {
486
+ uint32_t transactionId = m_transaction_id_seed++;
487
+ return wsl::shared::Transaction(*this, transactionId);
488
+ }
489
+
490
+ Transaction ReceiveTransaction()
491
{
270
- SendMessage<TSentMessage>(message);
492
+ // Transaction id should follow the received one on the receive end.
493
+ return wsl::shared::Transaction(*this, 0);
494
+ }
495
272
- return ReceiveMessage<typename TSentMessage::TResponse>(responseSpan, timeout);
496
+ template <typename TSentMessage>
497
+ typename TSentMessage::TResponse& Transaction(gsl::span<gsl::byte> message, gsl::span<gsl::byte>* responseSpan = nullptr, TTimeout timeout = DefaultSocketTimeout)
498
+ {
499
+ auto transaction = StartTransaction();
500
+ transaction.Send<TSentMessage>(message);
501
+ return transaction.Receive<typename TSentMessage::TResponse>(responseSpan, timeout);
502
}
503
504
template <typename TSentMessage>
276
- TSentMessage::TResponse& Transaction(TSentMessage& message, gsl::span<gsl::byte>* responseSpan = nullptr, TTimeout timeout = DefaultSocketTimeout)
505
+ typename TSentMessage::TResponse& Transaction(TSentMessage& message, gsl::span<gsl::byte>* responseSpan = nullptr, TTimeout timeout = DefaultSocketTimeout)
506
{
507
WI_ASSERT(message.Header.MessageSize == sizeof(message));
508
@@ -321,33 +550,33 @@ private:
550
551
#endif
552
324
- void ValidateMessageHeader(const MESSAGE_HEADER& header, LX_MESSAGE_TYPE expected, unsigned int expectedSequence) const
553
+ void ValidateMessageHeader(const MESSAGE_HEADER& header, LX_MESSAGE_TYPE expected) const
554
{
326
- if (header.MessageSize < sizeof(header) || (expected != LxMiniInitMessageAny && header.MessageType != expected) ||
327
- (!m_ignore_sequence && header.SequenceNumber != expectedSequence))
555
+
556
+ if (header.MessageSize < sizeof(header) || (expected != LxMiniInitMessageAny && header.MessageType != expected))
557
{
558
#ifdef WIN32
559
560
THROW_HR_MSG(
561
E_UNEXPECTED,
333
- "Protocol error: Received message size: %u, type: %u, sequence: %u. Expected type: %u, expected sequence: %u, "
562
+ "Protocol error: Received message size: %u, type: %u, id: %u, step: %u. Expected type: %u, "
563
"channel: %hs",
564
header.MessageSize,
565
header.MessageType,
337
- header.SequenceNumber,
566
+ header.TransactionId,
567
+ header.TransactionStep,
568
expected,
339
- expectedSequence,
569
m_name);
570
#else
571
572
LOG_ERROR(
344
- "Protocol error: Received message size: {}, type: {}, sequence: {}. Expected type: {}, expected sequence: {}, "
573
+ "Protocol error: Received message size: {}, type: {}, id: {}, step: {}. Expected type: {}, "
574
"channel: {}",
575
header.MessageSize,
576
header.MessageType,
348
- header.SequenceNumber,
577
+ header.TransactionId,
578
+ header.TransactionStep,
579
expected,
350
- expectedSequence,
580
m_name);
581
582
THROW_ERRNO(EINVAL);
@@ -392,11 +621,65 @@ private:
621
HANDLE m_exitEvent{};
622
623
#endif
395
- uint32_t m_sent_messages = 0;
396
- uint32_t m_received_messages = 0;
624
+ uint32_t m_sent_non_transaction_messages = 0;
625
+ uint32_t m_received_non_transaction_messages = 0;
626
+ std::atomic<uint32_t> m_transaction_id_seed = 0;
627
bool m_ignore_sequence = false;
628
const char* m_name{};
629
std::mutex m_sendMutex;
630
std::mutex m_receiveMutex;
631
};
402
-} // namespace wsl::shared
\ No newline at end of file
632
+
633
+template <typename TMessage>
634
+void Transaction::Send(gsl::span<gsl::byte> span)
635
+{
636
+ m_channel.SendMessage<TMessage>(span, m_step, m_id);
637
+ m_step++;
638
+}
639
+
640
+template <typename TMessage>
641
+void Transaction::Send(TMessage& message)
642
+{
643
+ Send<TMessage>(gslhelpers::struct_as_writeable_bytes(message));
644
+}
645
+
646
+template <typename TResult>
647
+void Transaction::SendResultMessage(TResult value)
648
+{
649
+ RESULT_MESSAGE<TResult> Result{};
650
+ Result.Header.MessageSize = sizeof(Result);
651
+ Result.Header.MessageType = RESULT_MESSAGE<TResult>::Type;
652
+ Result.Result = value;
653
+
654
+ Send(Result);
655
+}
656
+
657
+template <typename TMessage>
658
+std::pair<TMessage*, gsl::span<gsl::byte>> Transaction::ReceiveOrClosed(TTimeout timeout)
659
+{
660
+ auto result = m_channel.ReceiveMessageOrClosed<TMessage>(timeout, m_step, m_id);
661
+ if (m_step == static_cast<uint32_t>(TRANSACTION_STEP::REQUEST) && result.first != nullptr)
662
+ {
663
+ // Use the request's id for the reply side transaction.
664
+ MESSAGE_HEADER& header = m_channel.GetMessageHeader(*result.first);
665
+ m_id = header.TransactionId;
666
+ }
667
+ m_step++;
668
+ return result;
669
+}
670
+
671
+template <typename TMessage>
672
+TMessage& Transaction::Receive(gsl::span<gsl::byte>* responseSpan, TTimeout timeout)
673
+{
674
+ auto& message = m_channel.ReceiveMessage<TMessage>(responseSpan, timeout, m_step, m_id);
675
+ if (m_step == static_cast<uint32_t>(TRANSACTION_STEP::REQUEST))
676
+ {
677
+ // Use the request's id for the reply side transaction.
678
+ MESSAGE_HEADER& header = m_channel.GetMessageHeader(message);
679
+ m_id = header.TransactionId;
680
+ }
681
+ m_step++;
682
+ return message;
683
+}
684
+
685
+} // namespace wsl::shared
src/shared/inc/lxinitshared.h
+11
-3
@@ -475,15 +475,23 @@ inline void PrettyPrint(std::stringstream& Out, LX_MESSAGE_TYPE Value)
475
Out << ToString(Value);
476
}
477
478
+enum class TRANSACTION_STEP : unsigned int
479
+{
480
+ NONE = 0,
481
+ REQUEST = 1,
482
+ FIRST_REPLY = 2,
483
+};
484
+
485
struct MESSAGE_HEADER
486
{
487
static inline auto Type = LxMiniInitMessageAny; // Setting this allows using MESSAGE_HEADER to receive any type of message
488
489
LX_MESSAGE_TYPE MessageType;
490
unsigned int MessageSize;
484
- unsigned int SequenceNumber;
491
+ unsigned int TransactionId;
492
+ unsigned int TransactionStep;
493
486
- PRETTY_PRINT(FIELD(MessageType), FIELD(MessageSize), FIELD(SequenceNumber));
494
+ PRETTY_PRINT(FIELD(MessageType), FIELD(MessageSize), FIELD(TransactionId), FIELD(TransactionStep));
495
};
496
497
//
@@ -771,7 +779,7 @@ typedef struct _LX_GNS_SET_PORT_LISTENER
779
PRETTY_PRINT(FIELD(Header), FIELD(HvSocketPort));
780
} LX_GNS_SET_PORT_LISTENER, *PLX_GNS_SET_PORT_LISTENER;
781
774
-static_assert(sizeof(LX_GNS_SET_PORT_LISTENER) == 16);
782
+static_assert(sizeof(LX_GNS_SET_PORT_LISTENER) == 20);
783
784
typedef struct _LX_GNS_PORT_LISTENER_RELAY
785
{
src/shared/inc/socketshared.h
+4
-4
@@ -95,18 +95,18 @@ try
95
96
LOG_HR_MSG(
97
E_UNEXPECTED,
98
- "Socket closed while reading message. Size: %u, type: %i, sequence: %u",
98
+ "Socket closed while reading message. Size: %u, type: %i, id: %u",
99
Header->MessageSize,
100
Header->MessageType,
101
- Header->SequenceNumber);
101
+ Header->TransactionId);
102
103
#elif defined(__GNUC__)
104
105
LOG_ERROR(
106
- "Socket closed while reading message. Size: {}, type: {}, sequence: {}",
106
+ "Socket closed while reading message. Size: {}, type: {}, id: {}",
107
Header->MessageSize,
108
Header->MessageType,
109
- Header->SequenceNumber);
109
+ Header->TransactionId);
110
111
#endif
112
src/windows/common/GnsPortTrackerChannel.cpp
+5
-3
@@ -33,7 +33,8 @@ void GnsPortTrackerChannel::Run()
33
{
34
for (;;)
35
{
36
- auto [header, range] = m_channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
36
+ auto transaction = m_channel.ReceiveTransaction();
37
+ auto [header, range] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
38
if (header == nullptr)
39
{
40
return;
@@ -46,7 +47,8 @@ void GnsPortTrackerChannel::Run()
47
const auto* message = gslhelpers::try_get_struct<LX_GNS_PORT_ALLOCATION_REQUEST>(range);
48
THROW_HR_IF_MSG(E_UNEXPECTED, !message, "Unexpected message size: %i", header->MessageSize);
49
49
- m_channel.SendResultMessage<int32_t>(m_callback(ConvertPortRequestToSockAddr(message), message->Protocol, message->Allocate));
50
+ transaction.SendResultMessage<int32_t>(
51
+ m_callback(ConvertPortRequestToSockAddr(message), message->Protocol, message->Allocate));
52
}
53
break;
54
case LxGnsMessageIfStateChangeRequest:
@@ -55,7 +57,7 @@ void GnsPortTrackerChannel::Run()
57
THROW_HR_IF_MSG(E_UNEXPECTED, !message, "Unexpected message size: %i", header->MessageSize);
58
59
m_interfaceStateCallback(message->InterfaceName, message->InterfaceUp);
58
- m_channel.SendResultMessage<int32_t>(0);
60
+ transaction.SendResultMessage<int32_t>(0);
61
}
62
break;
63
default:
src/windows/service/exe/LxssCreateProcess.h
+3
-3
@@ -85,15 +85,15 @@ public:
85
wsl::shared::MessageWriter<CREATE_PROCESS_MESSAGE> message(LxInitCreateProcess);
86
message.WriteString(message->PathIndex, Path);
87
gsl::copy(as_bytes(gsl::span(ArgumentsData)), message.InsertBuffer(message->CommandLineIndex, ArgumentsData.size()));
88
- channel.SendMessage<CREATE_PROCESS_MESSAGE>(message.Span());
88
+ auto transaction = channel.StartTransaction();
89
+ transaction.Send<CREATE_PROCESS_MESSAGE>(message.Span());
90
91
auto readResult = [&]() {
91
- const auto& message = channel.ReceiveMessage<RESULT_MESSAGE<int32_t>>(nullptr, Timeout);
92
+ const auto& message = transaction.Receive<RESULT_MESSAGE<int32_t>>(nullptr, Timeout);
93
return message.Result;
94
};
95
96
auto processSocket = wsl::windows::common::hvsocket::Connect(RuntimeId, readResult(), terminatingEvent);
96
-
97
const auto execResult = readResult();
98
THROW_HR_IF_MSG(E_FAIL, execResult != 0, "Failed to execute '%hs', error=%d", Path, execResult);
99
src/windows/service/exe/WslCoreInstance.cpp
+8
-5
@@ -344,7 +344,8 @@ void WslCoreInstance::UpdateTimezone()
344
wsl::windows::common::helpers::GenerateTimezoneUpdateMessage(wsl::windows::common::helpers::GetLinuxTimezone(m_userToken.get()));
345
346
auto lock = m_initChannel->Lock();
347
- m_initChannel->GetChannel().SendMessage<LX_INIT_TIMEZONE_INFORMATION>(gsl::make_span(message));
347
+ auto transaction = m_initChannel->GetChannel().StartTransaction();
348
+ transaction.Send<LX_INIT_TIMEZONE_INFORMATION>(gsl::make_span(message));
349
}
350
351
ULONG64 WslCoreInstance::GetLifetimeManagerId() const
@@ -389,11 +390,12 @@ void WslCoreInstance::Initialize()
390
auto config = wsl::windows::common::helpers::GenerateConfigurationMessage(
391
m_configuration.Name, fixedDrives, m_defaultUid, timezone, {}, m_featureFlags, drvfsMount);
392
392
- m_initChannel->GetChannel().SendMessage<LX_INIT_CONFIGURATION_INFORMATION>(gsl::span(config));
393
+ auto transaction = m_initChannel->GetChannel().StartTransaction();
394
+ transaction.Send<LX_INIT_CONFIGURATION_INFORMATION>(gsl::span(config));
395
396
// Init replies with information about the distribution.
397
gsl::span<gsl::byte> span;
396
- const auto& response = m_initChannel->GetChannel().ReceiveMessage<LX_INIT_CONFIGURATION_INFORMATION_RESPONSE>(&span);
398
+ const auto& response = transaction.Receive<LX_INIT_CONFIGURATION_INFORMATION_RESPONSE>(&span);
399
m_defaultUid = response.DefaultUid;
400
m_plan9Port = response.Plan9Port;
401
m_distributionInfo.PidNamespace = response.PidNamespace;
@@ -473,8 +475,9 @@ bool WslCoreInstance::RequestStop(_In_ bool Force)
475
terminateMessage.Header.MessageSize = sizeof(terminateMessage);
476
terminateMessage.Force = Force;
477
476
- m_initChannel->GetChannel().SendMessage(terminateMessage);
477
- auto [message, span] = m_initChannel->GetChannel().ReceiveMessageOrClosed<RESULT_MESSAGE<bool>>(m_socketTimeout);
478
+ auto transaction = m_initChannel->GetChannel().StartTransaction();
479
+ transaction.Send(terminateMessage);
480
+ auto [message, span] = transaction.ReceiveOrClosed<RESULT_MESSAGE<bool>>(m_socketTimeout);
481
if (message)
482
{
483
shutdown = message->Result;
src/windows/service/exe/WslCoreVm.cpp
+22
-12
@@ -527,7 +527,8 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
527
message.WriteString(message->KernelModulesListOffset, m_vmConfig.KernelModulesList);
528
message->DnsTunnelingIpAddress = m_vmConfig.DnsTunnelingIpAddress.value_or(0);
529
530
- m_miniInitChannel.SendMessage<LX_MINI_INIT_EARLY_CONFIG_MESSAGE>(message.Span());
530
+ auto transaction = m_miniInitChannel.StartTransaction();
531
+ transaction.Send<LX_MINI_INIT_EARLY_CONFIG_MESSAGE>(message.Span());
532
533
{
534
ExecutionContext context(Context::ConfigureNetworking);
@@ -1098,7 +1099,8 @@ void WslCoreVm::CollectCrashDumps(wil::unique_socket&& listenSocket) const
1099
1100
auto channel = wsl::shared::SocketChannel{std::move(socket.value()), "crash_dump", m_terminatingEvent.get()};
1101
1101
- const auto& message = channel.ReceiveMessage<LX_PROCESS_CRASH>();
1102
+ auto transaction = channel.ReceiveTransaction();
1103
+ const auto& message = transaction.Receive<LX_PROCESS_CRASH>();
1104
const char* process = reinterpret_cast<const char*>(&message.Buffer);
1105
1106
constexpr auto dumpExtension = ".dmp";
@@ -1146,7 +1148,7 @@ void WslCoreVm::CollectCrashDumps(wil::unique_socket&& listenSocket) const
1148
wil::unique_hfile file{CreateFileW(fullPath.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, nullptr)};
1149
THROW_LAST_ERROR_IF(!file);
1150
1149
- channel.SendResultMessage<std::int32_t>(0);
1151
+ transaction.SendResultMessage<std::int32_t>(0);
1152
1153
wsl::windows::common::relay::InterruptableRelay(reinterpret_cast<HANDLE>(channel.Socket()), file.get(), nullptr);
1154
}
@@ -1206,7 +1208,8 @@ std::shared_ptr<LxssRunningInstance> WslCoreVm::CreateInstance(
1208
message.WriteString(message->SharedMemoryRootOffset, sharedMemoryRoot);
1209
message.WriteString(message->InstallPathOffset, installPath);
1210
message.WriteString(message->UserProfileOffset, userProfile);
1209
- m_miniInitChannel.SendMessage<LX_MINI_INIT_MESSAGE>(message.Span());
1211
+ auto transaction = m_miniInitChannel.StartTransaction();
1212
+ transaction.Send<LX_MINI_INIT_MESSAGE>(message.Span());
1213
1214
return CreateInstanceInternal(
1215
InstanceId, Configuration, ReceiveTimeout, DefaultUid, ClientLifetimeId, WI_IsFlagSet(flags, LxMiniInitMessageFlagLaunchSystemDistro), ConnectPort);
@@ -1844,7 +1847,8 @@ void WslCoreVm::InitializeGuest()
1847
}
1848
1849
// Send the message.
1847
- m_miniInitChannel.SendMessage<LX_MINI_INIT_CONFIG_MESSAGE>(message.Span());
1850
+ auto transaction = m_miniInitChannel.StartTransaction();
1851
+ transaction.Send<LX_MINI_INIT_CONFIG_MESSAGE>(message.Span());
1852
1853
// If port tracker or localhost relay are enabled, establish a connection with the guest and start processing messages.
1854
switch (message->NetworkingConfiguration.PortTrackerType)
@@ -1978,7 +1982,8 @@ WslCoreVm::DiskMountResult WslCoreVm::MountDiskLockHeld(
1982
message.WriteString(message->OptionsOffset, Options);
1983
1984
// Send the message.
1981
- m_miniInitChannel.SendMessage<LX_MINI_INIT_MOUNT_MESSAGE>(message.Span());
1985
+ auto transaction = m_miniInitChannel.StartTransaction();
1986
+ transaction.Send<LX_MINI_INIT_MOUNT_MESSAGE>(message.Span());
1987
1988
// Accept a connection from mini_init
1989
wsl::shared::SocketChannel channel{AcceptConnection(m_vmConfig.KernelBootTimeout), "MountResult", m_terminatingEvent.get()};
@@ -2106,7 +2111,8 @@ void WslCoreVm::WaitForPmemDeviceInVm(_In_ ULONG PmemId)
2111
{
2112
auto lock = m_lock.lock_exclusive();
2113
2109
- m_miniInitChannel.SendMessage(message);
2114
+ auto transaction = m_miniInitChannel.StartTransaction();
2115
+ transaction.Send(message);
2116
channel = {
2117
AcceptConnection(m_vmConfig.KernelBootTimeout),
2118
"WaitForPmem",
@@ -2415,7 +2421,8 @@ void WslCoreVm::ResizeDistribution(_In_ ULONG Lun, _In_ HANDLE OutputHandle, _In
2421
message.ScsiLun = Lun;
2422
message.NewSize = NewSize;
2423
2418
- m_miniInitChannel.SendMessage(message);
2424
+ auto transaction = m_miniInitChannel.StartTransaction();
2425
+ transaction.Send(message);
2426
2427
wsl::shared::SocketChannel channel{AcceptConnection(m_vmConfig.KernelBootTimeout), "ResizeDistribution", m_terminatingEvent.get()};
2428
auto outputChannel = AcceptConnection(m_vmConfig.KernelBootTimeout);
@@ -2492,7 +2499,8 @@ std::pair<int, LX_MINI_MOUNT_STEP> WslCoreVm::UnmountDisk(_In_ const AttachedDis
2499
message.Header.MessageSize = sizeof(message);
2500
message.ScsiLun = State.Lun;
2501
2495
- m_miniInitChannel.SendMessage(message);
2502
+ auto transaction = m_miniInitChannel.StartTransaction();
2503
+ transaction.Send(message);
2504
2505
// Accept a connection from mini_init.
2506
wsl::shared::SocketChannel channel{AcceptConnection(m_vmConfig.KernelBootTimeout), "MountResult", m_terminatingEvent.get()};
@@ -2507,7 +2515,8 @@ std::pair<int, LX_MINI_MOUNT_STEP> WslCoreVm::UnmountVolume(_In_ const AttachedD
2515
message.WriteString(Name);
2516
2517
// Send the message.
2510
- m_miniInitChannel.SendMessage<LX_MINI_INIT_UNMOUNT_MESSAGE>(message.Span());
2518
+ auto transaction = m_miniInitChannel.StartTransaction();
2519
+ transaction.Send<LX_MINI_INIT_UNMOUNT_MESSAGE>(message.Span());
2520
2521
// Accept a connection from mini_init.
2522
wsl::shared::SocketChannel channel{AcceptConnection(m_vmConfig.KernelBootTimeout), "MountResult", m_terminatingEvent.get()};
@@ -2573,7 +2582,8 @@ try
2582
{
2583
wsl::windows::common::wslutil::SetThreadDescription(L"VirtioFs - Request");
2584
2576
- auto [message, span] = channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
2585
+ auto transaction = channel.ReceiveTransaction();
2586
+ auto [message, span] = transaction.ReceiveOrClosed<MESSAGE_HEADER>();
2587
if (message == nullptr)
2588
{
2589
return;
@@ -2587,7 +2597,7 @@ try
2597
response.WriteString(response->TagOffset, tag);
2598
response.WriteString(response->SourceOffset, source);
2599
2590
- channel.SendMessage<LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE>(response.Span());
2600
+ transaction.Send<LX_INIT_ADD_VIRTIOFS_SHARE_RESPONSE_MESSAGE>(response.Span());
2601
};
2602
2603
if (message->MessageType == LxInitMessageAddVirtioFsDevice)
src/windows/wslrelay/localhost.cpp
+3
-2
@@ -81,7 +81,8 @@ void wsl::windows::wslrelay::localhost::RelayWorker(_In_ wsl::shared::SocketChan
81
82
for (;;)
83
{
84
- auto [Message, Span] = Channel.ReceiveMessageOrClosed<MESSAGE_HEADER>();
84
+ auto Transaction = Channel.ReceiveTransaction();
85
+ auto [Message, Span] = Transaction.ReceiveOrClosed<MESSAGE_HEADER>();
86
if (Message == nullptr)
87
{
88
break;
@@ -151,7 +152,7 @@ void wsl::windows::wslrelay::localhost::RelayWorker(_In_ wsl::shared::SocketChan
152
}
153
}
154
154
- Channel.SendMessage(Response);
155
+ Transaction.Send(Response);
156
break;
157
}
158