Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 submits the same buffer 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 changed
// since the stream's creation.
//
const uint32_t InitialControlFlow = Stream->RecvBuffer.VirtualBufferLength;
CXPLAT_DBG_ASSERT(
InitialControlFlow == Stream->Connection->Settings.StreamRecvWindowBidiRemoteDefault ||
InitialControlFlow == Stream->Connection->Settings.StreamRecvWindowUnidiDefault);

//
// 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
78 changes: 70 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,83 @@ 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}, // Base scenario
{ 1, 100, 1, 100}, // Small buffers
{ 150, 0x50, 150, 0x50}, // Many buffers
};
}
};

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