Skip to content

Commit 7a12b7e

Browse files
committed
COPIED_TO_FRAME event is now optional and depends on StreamSend flag
Signed-off-by: HHN <harihara.sn@gmail.com>
1 parent 5bc9b55 commit 7a12b7e

File tree

4 files changed

+162
-13
lines changed

4 files changed

+162
-13
lines changed

docs/api/StreamSend.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Value | Meaning
4747
**QUIC_SEND_FLAG_DELAY_SEND**<br>16 | Provides a hint to MsQuic to indicate the data does not need to be sent immediately, likely because more is soon to follow.
4848
**QUIC_SEND_FLAG_CANCEL_ON_LOSS**<br>32 | Informs MsQuic to irreversibly mark the associated stream to be canceled when packet loss has been detected on it. I.e., all sends on a given stream are subject to this behavior from the moment the flag has been supplied for the first time.
4949
**QUIC_SEND_FLAG_CANCEL_ON_BLOCKED**<br>64 | **Unused and ignored** for `StreamSend` for now
50+
**QUIC_SEND_FLAG_EVENT_ON_FIRST_COPY_TO_FRAME**<br>128 | Informs MsQuic that the first `QUIC_STREAM_EVENT_COPIED_TO_FRAME` should be signalled to the application
5051
5152
`ClientSendContext`
5253

src/core/api.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,7 +1106,11 @@ MsQuicStreamSend(
11061106
SendRequest->Flags = Flags & ~QUIC_SEND_FLAGS_INTERNAL;
11071107
SendRequest->TotalLength = TotalLength;
11081108
SendRequest->ClientContext = ClientSendContext;
1109-
SendRequest->BytesToBeCopiedBeforeNextCopiedToFrameEvent = 0;
1109+
if(Flags & QUIC_SEND_FLAG_EVENT_ON_FIRST_COPY_TO_FRAME) {
1110+
SendRequest->BytesToBeCopiedBeforeNextCopiedToFrameEvent = 0;
1111+
} else {
1112+
SendRequest->BytesToBeCopiedBeforeNextCopiedToFrameEvent = UINT64_MAX;
1113+
}
11101114

11111115
#pragma warning(push)
11121116
#pragma warning(disable:6240) // CXPLAT_AT_DISPATCH only really does anything for kernel mode
@@ -1860,7 +1864,11 @@ MsQuicDatagramSend(
18601864
SendRequest->Flags = Flags;
18611865
SendRequest->TotalLength = TotalLength;
18621866
SendRequest->ClientContext = ClientSendContext;
1863-
SendRequest->BytesToBeCopiedBeforeNextCopiedToFrameEvent = 0;
1867+
if(Flags & QUIC_SEND_FLAG_EVENT_ON_FIRST_COPY_TO_FRAME) {
1868+
SendRequest->BytesToBeCopiedBeforeNextCopiedToFrameEvent = 0;
1869+
} else {
1870+
SendRequest->BytesToBeCopiedBeforeNextCopiedToFrameEvent = UINT64_MAX;
1871+
}
18641872

18651873
Status = QuicDatagramQueueSend(&Connection->Datagram, SendRequest);
18661874

src/inc/msquic.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -240,15 +240,16 @@ typedef enum QUIC_RECEIVE_FLAGS {
240240
DEFINE_ENUM_FLAG_OPERATORS(QUIC_RECEIVE_FLAGS)
241241

242242
typedef enum QUIC_SEND_FLAGS {
243-
QUIC_SEND_FLAG_NONE = 0x0000,
244-
QUIC_SEND_FLAG_ALLOW_0_RTT = 0x0001, // Allows the use of encrypting with 0-RTT key.
245-
QUIC_SEND_FLAG_START = 0x0002, // Asynchronously starts the stream with the sent data.
246-
QUIC_SEND_FLAG_FIN = 0x0004, // Indicates the request is the one last sent on the stream.
247-
QUIC_SEND_FLAG_DGRAM_PRIORITY = 0x0008, // Indicates the datagram is higher priority than others.
248-
QUIC_SEND_FLAG_DELAY_SEND = 0x0010, // Indicates the send should be delayed because more will be queued soon.
249-
QUIC_SEND_FLAG_CANCEL_ON_LOSS = 0x0020, // Indicates that a stream is to be cancelled when packet loss is detected.
250-
QUIC_SEND_FLAG_PRIORITY_WORK = 0x0040, // Higher priority than other connection work.
251-
QUIC_SEND_FLAG_CANCEL_ON_BLOCKED = 0x0080, // Indicates that a frame should be dropped when it can't be sent immediately.
243+
QUIC_SEND_FLAG_NONE = 0x0000,
244+
QUIC_SEND_FLAG_ALLOW_0_RTT = 0x0001, // Allows the use of encrypting with 0-RTT key.
245+
QUIC_SEND_FLAG_START = 0x0002, // Asynchronously starts the stream with the sent data.
246+
QUIC_SEND_FLAG_FIN = 0x0004, // Indicates the request is the one last sent on the stream.
247+
QUIC_SEND_FLAG_DGRAM_PRIORITY = 0x0008, // Indicates the datagram is higher priority than others.
248+
QUIC_SEND_FLAG_DELAY_SEND = 0x0010, // Indicates the send should be delayed because more will be queued soon.
249+
QUIC_SEND_FLAG_CANCEL_ON_LOSS = 0x0020, // Indicates that a stream is to be cancelled when packet loss is detected.
250+
QUIC_SEND_FLAG_PRIORITY_WORK = 0x0040, // Higher priority than other connection work.
251+
QUIC_SEND_FLAG_CANCEL_ON_BLOCKED = 0x0080, // Indicates that a frame should be dropped when it can't be sent immediately.
252+
QUIC_SEND_FLAG_EVENT_ON_FIRST_COPY_TO_FRAME = 0x0100, // Event is signaled when data from the send request is copied to a frame for the first time
252253
} QUIC_SEND_FLAGS;
253254

254255
DEFINE_ENUM_FLAG_OPERATORS(QUIC_SEND_FLAGS)

src/test/lib/EventTest.cpp

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,144 @@ QuicTestValidateStreamEvents9(
16781678
{
16791679
TestScopeLogger ScopeLogger(__FUNCTION__);
16801680

1681+
#ifdef QUIC_PARAM_STREAM_RELIABLE_OFFSET
1682+
MsQuicSettings Settings;
1683+
Settings.SetPeerBidiStreamCount(1).SetMinimumMtu(1280).SetMaximumMtu(1280);
1684+
Settings.SetReliableResetEnabled(true);
1685+
MsQuicConfiguration ServerConfiguration(Registration, "MsQuicTest", Settings, ServerSelfSignedCredConfig);
1686+
TEST_TRUE(ServerConfiguration.IsValid());
1687+
1688+
MsQuicConfiguration ClientConfiguration(Registration, "MsQuicTest", Settings, MsQuicCredentialConfig());
1689+
TEST_TRUE(ClientConfiguration.IsValid());
1690+
1691+
{ // Connections scope
1692+
ConnValidator Client, Server(ServerConfiguration);
1693+
1694+
Listener.Context = &Server;
1695+
1696+
TEST_QUIC_SUCCEEDED(
1697+
MsQuic->ConnectionOpen(
1698+
Registration,
1699+
ConnValidatorCallback,
1700+
&Client,
1701+
&Client.Handle));
1702+
1703+
{ // Stream scope
1704+
1705+
StreamValidator ClientStream(
1706+
new(std::nothrow) StreamEventValidator* [5] {
1707+
new(std::nothrow) StreamStartCompleteEventValidator(),
1708+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_SEND_COMPLETE, 0, true),
1709+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE),
1710+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE, QUIC_EVENT_ACTION_SHUTDOWN_CONNECTION),
1711+
nullptr
1712+
});
1713+
StreamValidator ServerStream(
1714+
new(std::nothrow) StreamEventValidator* [6] {
1715+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_RECEIVE),
1716+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_PEER_SEND_ABORTED),
1717+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_PEER_RECEIVE_ABORTED),
1718+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_SEND_SHUTDOWN_COMPLETE),
1719+
new(std::nothrow) StreamEventValidator(QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE),
1720+
nullptr
1721+
});
1722+
1723+
Client.SetExpectedEvents(
1724+
new(std::nothrow) ConnEventValidator* [8] {
1725+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_RELIABLE_RESET_NEGOTIATED),
1726+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_STREAMS_AVAILABLE),
1727+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_DATAGRAM_STATE_CHANGED),
1728+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_CONNECTED),
1729+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_STREAMS_AVAILABLE, 0, true),
1730+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED, 0, true), // TODO - Schannel does resumption regardless
1731+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE),
1732+
nullptr
1733+
});
1734+
Server.SetExpectedEvents(
1735+
new(std::nothrow) ConnEventValidator* [6] {
1736+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_RELIABLE_RESET_NEGOTIATED),
1737+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_CONNECTED),
1738+
new(std::nothrow) NewStreamEventValidator(&ServerStream),
1739+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER),
1740+
new(std::nothrow) ConnEventValidator(QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE),
1741+
nullptr
1742+
});
1743+
1744+
TEST_QUIC_SUCCEEDED(
1745+
MsQuic->StreamOpen(
1746+
Client.Handle,
1747+
QUIC_STREAM_OPEN_FLAG_NONE,
1748+
StreamValidatorCallback,
1749+
&ClientStream,
1750+
&ClientStream.Handle));
1751+
TEST_QUIC_SUCCEEDED(
1752+
MsQuic->StreamStart(
1753+
ClientStream.Handle,
1754+
QUIC_STREAM_START_FLAG_NONE));
1755+
1756+
TEST_QUIC_SUCCEEDED(
1757+
MsQuic->ConnectionStart(
1758+
Client.Handle,
1759+
ClientConfiguration,
1760+
QuicAddrGetFamily(&ServerLocalAddr.SockAddr),
1761+
QUIC_TEST_LOOPBACK_FOR_AF(
1762+
QuicAddrGetFamily(&ServerLocalAddr.SockAddr)),
1763+
ServerLocalAddr.GetPort()));
1764+
1765+
TEST_TRUE(Client.HandshakeComplete.WaitTimeout(1000));
1766+
CxPlatSleep(200);
1767+
1768+
uint8_t Buffer[1] = {0x1};
1769+
QUIC_BUFFER SendBuffer = { sizeof(Buffer), (uint8_t*) Buffer };
1770+
TEST_QUIC_SUCCEEDED(
1771+
MsQuic->StreamSend(
1772+
ClientStream.Handle,
1773+
&SendBuffer,
1774+
1,
1775+
QUIC_SEND_FLAG_NONE,
1776+
nullptr));
1777+
1778+
uint64_t ReliableOffset = 1;
1779+
TEST_QUIC_SUCCEEDED(
1780+
MsQuic->SetParam(
1781+
ClientStream.Handle,
1782+
QUIC_PARAM_STREAM_RELIABLE_OFFSET,
1783+
sizeof(ReliableOffset),
1784+
&ReliableOffset
1785+
)
1786+
);
1787+
1788+
CxPlatSleep(100); // Wait for the sends to be processed
1789+
1790+
TEST_QUIC_SUCCEEDED(
1791+
MsQuic->StreamShutdown(
1792+
ClientStream.Handle,
1793+
QUIC_STREAM_SHUTDOWN_FLAG_ABORT,
1794+
0));
1795+
1796+
TEST_TRUE(Client.Complete.WaitTimeout(2000));
1797+
TEST_TRUE(Server.Complete.WaitTimeout(1000));
1798+
} // Stream scope
1799+
} // Connections scope
1800+
#else // QUIC_PARAM_STREAM_RELIABLE_OFFSET
1801+
UNREFERENCED_PARAMETER(Registration);
1802+
UNREFERENCED_PARAMETER(Listener);
1803+
UNREFERENCED_PARAMETER(ServerLocalAddr);
1804+
#endif // QUIC_PARAM_STREAM_RELIABLE_OFFSET
1805+
}
1806+
1807+
void
1808+
QuicTestValidateStreamEvents10(
1809+
_In_ MsQuicRegistration& Registration,
1810+
_In_ MsQuicListener& Listener,
1811+
_In_ QuicAddr& ServerLocalAddr
1812+
)
1813+
{
1814+
// Tests for the `QUIC_STREAM_EVENT_COPIED_TO_FRAME` event
1815+
// This test is a duplicate of the previous one,
1816+
// except for StreamSend has the `QUIC_SEND_FLAG_EVENT_ON_FIRST_COPY_TO_FRAME` flag
1817+
TestScopeLogger ScopeLogger(__FUNCTION__);
1818+
16811819
#ifdef QUIC_PARAM_STREAM_RELIABLE_OFFSET
16821820
MsQuicSettings Settings;
16831821
Settings.SetPeerBidiStreamCount(1).SetMinimumMtu(1280).SetMaximumMtu(1280);
@@ -1773,7 +1911,7 @@ QuicTestValidateStreamEvents9(
17731911
ClientStream.Handle,
17741912
&SendBuffer,
17751913
1,
1776-
QUIC_SEND_FLAG_NONE,
1914+
QUIC_SEND_FLAG_EVENT_ON_FIRST_COPY_TO_FRAME,
17771915
nullptr));
17781916

17791917
uint64_t ReliableOffset = 1;
@@ -1831,7 +1969,8 @@ void QuicTestValidateStreamEvents(uint32_t Test)
18311969
QuicTestValidateStreamEvents6,
18321970
QuicTestValidateStreamEvents7,
18331971
QuicTestValidateStreamEvents8,
1834-
QuicTestValidateStreamEvents9
1972+
QuicTestValidateStreamEvents9,
1973+
QuicTestValidateStreamEvents10
18351974
};
18361975

18371976
Tests[Test](Registration, Listener, ServerLocalAddr);

0 commit comments

Comments
 (0)