Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/Streams.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ There is no guarantee the `QUIC_BUFFER`s indicated in a receive notification wil

The application is responsible for tracking the amount of data received and when a buffer it provided has been fully used.
The application regains full ownership of a buffer after it get a receive notification for all bytes in the buffer and accept them by calling [StreamReceiveComplete](api/StreamReceiveComplete.md).
MsQuic will not re-use a buffer for subsequent receives once it has been fully written, unless the app submit the same memory again.
If the application accepts all the buffer's bytes **inline** from the receive notification, by returning `QUIC_STATUS_SUCCESS` and setting `TotalBufferLength` appropriately,
it can free or reuse the buffer while in the notification handler.

Expand Down
11 changes: 10 additions & 1 deletion src/core/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,15 @@ QuicStreamSwitchToAppOwnedBuffers(
_In_ QUIC_STREAM* Stream
)
{
//
// Preserve the initial receive window size.
// It should not have evolved yet since the stream creation.
//
const uint32_t InitialControlFlow = Stream->RecvBuffer.VirtualBufferLength;
CXPLAT_DBG_ASSERT(
InitialControlFlow == Stream->Connection->Settings.StreamRecvWindowBidiRemoteDefault ||
InitialControlFlow == Stream->Connection->Settings.StreamRecvWindowBidiLocalDefault);

//
// Reset the current receive buffer
//
Expand All @@ -988,7 +997,7 @@ QuicStreamSwitchToAppOwnedBuffers(
(void)QuicRecvBufferInitialize(
&Stream->RecvBuffer,
0,
0,
InitialControlFlow,
QUIC_RECV_BUF_MODE_APP_OWNED,
NULL);
Stream->Flags.UseAppOwnedRecvBuffers = TRUE;
Expand Down
35 changes: 33 additions & 2 deletions src/test/MsQuicTests.h
Original file line number Diff line number Diff line change
Expand Up @@ -642,10 +642,41 @@ QuicTestEcn(
const FamilyArgs& Params
);

void QuicTestStreamAppProvidedBuffers(
struct AppProvidedBuffersConfig {
uint32_t StreamStartBuffersNum;
uint32_t StreamStartBuffersSize;
uint32_t AdditionalBuffersNum;
uint32_t AdditionalBuffersSize;
};

void
QuicTestStreamAppProvidedBuffers_ClientSend(
const AppProvidedBuffersConfig& BufferConfig
);

void
QuicTestStreamAppProvidedBuffers_ServerSend(
const AppProvidedBuffersConfig& BufferConfig
);

void
QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_AbortStream(
const AppProvidedBuffersConfig& BufferConfig
);

void
QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_ProvideMoreBuffer(
const AppProvidedBuffersConfig& BufferConfig
);

void QuicTestStreamAppProvidedBuffersOutOfSpace(
void
QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_AbortStream(
const AppProvidedBuffersConfig& BufferConfig
);

void
QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_ProvideMoreBuffer(
const AppProvidedBuffersConfig& BufferConfig
);

//
Expand Down
76 changes: 68 additions & 8 deletions src/test/bin/quic_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "quic_gtest.cpp.clog.h"
#endif

#include <MsQuicTests.h>

#include <array>

#ifdef QUIC_TEST_DATAPATH_HOOKS_ENABLED
Expand Down Expand Up @@ -2372,23 +2374,81 @@ TEST(Misc, StreamMultiReceive) {
}
}

TEST(Misc, StreamAppProvidedBuffers) {
TestLogger Logger("StreamAppProvidedBuffers");
// App-provided receive buffer tests

struct WithAppProvidedBuffersConfigArgs: public testing::TestWithParam<AppProvidedBuffersConfig> {
static ::std::vector<AppProvidedBuffersConfig> Generate() {
return {
{ 8, 0x500, 8, 0x500}
};
}
};

std::ostream& operator << (std::ostream& o, const AppProvidedBuffersConfig& args) {
return o <<
"Start:" << args.StreamStartBuffersNum << " buffers of" << args.StreamStartBuffersSize << "bytes," <<
"Additional:" << args.AdditionalBuffersNum << " buffers of " << args.AdditionalBuffersSize << "bytes.";
}

TEST_P(WithAppProvidedBuffersConfigArgs, StreamAppProvidedBuffers_ClientSend) {
TestLoggerT<ParamType> Logger("StreamAppProvidedBuffers_ClientSend", GetParam());
if (TestingKernelMode) {
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffers_ClientSend), GetParam()));
} else {
QuicTestStreamAppProvidedBuffers_ClientSend(GetParam());
}
}

TEST_P(WithAppProvidedBuffersConfigArgs, StreamAppProvidedBuffers_ServerSend) {
TestLoggerT<ParamType> Logger("StreamAppProvidedBuffers_ServerSend", GetParam());
if (TestingKernelMode) {
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffers_ServerSend), GetParam()));
} else {
QuicTestStreamAppProvidedBuffers_ServerSend(GetParam());
}
}

TEST_P(WithAppProvidedBuffersConfigArgs, StreamAppProvidedBuffersOutOfSpace_ClientSend_AbortStream) {
TestLoggerT<ParamType> Logger("StreamAppProvidedBuffersOutOfSpace_ClientSend_AbortStream", GetParam());
if (TestingKernelMode) {
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_AbortStream), GetParam()));
} else {
QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_AbortStream(GetParam());
}
}

TEST_P(WithAppProvidedBuffersConfigArgs, StreamAppProvidedBuffersOutOfSpace_ClientSend_ProvideMoreBuffer) {
TestLoggerT<ParamType> Logger("StreamAppProvidedBuffersOutOfSpace_ClientSend_ProvideMoreBuffer", GetParam());
if (TestingKernelMode) {
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_ProvideMoreBuffer), GetParam()));
} else {
QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_ProvideMoreBuffer(GetParam());
}
}

TEST_P(WithAppProvidedBuffersConfigArgs, StreamAppProvidedBuffersOutOfSpace_ServerSend_AbortStream) {
TestLoggerT<ParamType> Logger("StreamAppProvidedBuffersOutOfSpace_ServerSend_AbortStream", GetParam());
if (TestingKernelMode) {
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffers)));
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_AbortStream), GetParam()));
} else {
QuicTestStreamAppProvidedBuffers();
QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_AbortStream(GetParam());
}
}

TEST(Misc, StreamAppProvidedBuffersOutOfSpace) {
TestLogger Logger("QuicTestStreamAppProvidedBuffersOutOfSpace");
TEST_P(WithAppProvidedBuffersConfigArgs, StreamAppProvidedBuffersOutOfSpace_ServerSend_ProvideMoreBuffer) {
TestLoggerT<ParamType> Logger("StreamAppProvidedBuffersOutOfSpace_ServerSend_ProvideMoreBuffer", GetParam());
if (TestingKernelMode) {
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffersOutOfSpace)));
ASSERT_TRUE(InvokeKernelTest(FUNC(QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_ProvideMoreBuffer), GetParam()));
} else {
QuicTestStreamAppProvidedBuffersOutOfSpace();
QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_ProvideMoreBuffer(GetParam());
}
}

INSTANTIATE_TEST_SUITE_P(
Misc,
WithAppProvidedBuffersConfigArgs,
testing::ValuesIn(WithAppProvidedBuffersConfigArgs::Generate()));

#endif // QUIC_API_ENABLE_PREVIEW_FEATURES

TEST(Misc, StreamBlockUnblockUnidiConnFlowControl) {
Expand Down
8 changes: 6 additions & 2 deletions src/test/bin/winkernel/control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -762,8 +762,12 @@ ExecuteTestRequest(
RegisterTestFunction(QuicTestStreamReliableResetMultipleSends);
#endif
RegisterTestFunction(QuicTestTlsHandshakeInfo);
RegisterTestFunction(QuicTestStreamAppProvidedBuffers);
RegisterTestFunction(QuicTestStreamAppProvidedBuffersOutOfSpace);
RegisterTestFunction(QuicTestStreamAppProvidedBuffers_ClientSend);
RegisterTestFunction(QuicTestStreamAppProvidedBuffers_ServerSend);
RegisterTestFunction(QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_AbortStream);
RegisterTestFunction(QuicTestStreamAppProvidedBuffersOutOfSpace_ClientSend_ProvideMoreBuffer);
RegisterTestFunction(QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_AbortStream);
RegisterTestFunction(QuicTestStreamAppProvidedBuffersOutOfSpace_ServerSend_ProvideMoreBuffer);

// Fail if no function matched
char Buffer[256];
Expand Down
Loading
Loading