Skip to content
Open
Changes from 5 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
104 changes: 102 additions & 2 deletions src/tools/spin/spinquic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,13 @@ struct SpinQuicGlobals {
uint32_t AlpnCount {0};
const size_t SendBufferSize { MaxBufferSizes[BufferCount - 1] + UINT8_MAX };
uint8_t* SendBuffer;
uint8_t* RecvBuffer;
SpinQuicGlobals() {
SendBuffer = new uint8_t[SendBufferSize];
for (size_t i = 0; i < SendBufferSize; i++) {
SendBuffer[i] = (uint8_t)i;
}
RecvBuffer = new uint8_t[SendBufferSize];
}
~SpinQuicGlobals() {
while (ClientConfigurations.size() > 0) {
Expand All @@ -237,7 +239,20 @@ struct SpinQuicGlobals {
free(Alpns);
}
if (Registration) {
MsQuic->RegistrationClose(Registration);
if (rand() % 2 == 0) {
CXPLAT_EVENT CloseComplete;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Consider using a CxPlatEvent since this is C++.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CxPlatEvent throws an error. I think it requires the CX_PLATFORM_TYPE which comes from the platform headers which we dont include

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you just need to include msquic.hpp after msquichelper.h

Copy link
Copy Markdown
Contributor Author

@gaurav2699 gaurav2699 Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesnt work either cause it causes name collisions:
C:\Users\gaurasingh\msquic\src\tools\spin\spinquic.cpp(203,23): error C2040: 'MsQuic': 'QUIC_API_TABLE' differs in leve ls of indirection from 'const MsQuicApi *'
msquic.hpp declares extern const MsQuicApi* MsQuic; while spinquic.cpp declares static QUIC_API_TABLE MsQuic. Including msquic.hpp causes a name collision.

CxPlatEventInitialize(&CloseComplete, TRUE, FALSE);
MsQuic->RegistrationClose2(
Registration,
[](void* Context) -> void {
CxPlatEventSet(*(CXPLAT_EVENT*)Context);
},
&CloseComplete);
CxPlatEventWaitForever(CloseComplete);
CxPlatEventUninitialize(CloseComplete);
} else {
MsQuic->RegistrationClose(Registration);
}
}
if (MsQuic) {
#ifndef FUZZING
Expand All @@ -246,6 +261,7 @@ struct SpinQuicGlobals {
MsQuicClose(MsQuic);
}
delete [] SendBuffer;
delete [] RecvBuffer;
}
};

Expand All @@ -270,6 +286,8 @@ typedef enum {
SpinQuicAPICallCompleteCertificateValidation,
SpinQuicAPICallStreamReceiveSetEnabled,
SpinQuicAPICallStreamReceiveComplete,
SpinQuicAPICallConnectionPoolCreate,
SpinQuicAPICallStreamProvideReceiveBuffers,
SpinQuicAPICallCount // Always the last element
} SpinQuicAPICall;

Expand Down Expand Up @@ -491,8 +509,21 @@ QUIC_STATUS QUIC_API SpinQuicHandleConnectionEvent(HQUIC Connection, void* , QUI
if (GetRandom(2) == 0) {
Event->PEER_STREAM_STARTED.Flags |= QUIC_STREAM_OPEN_FLAG_DELAY_ID_FC_UPDATES;
}
if (GetRandom(5) == 0) {
Event->PEER_STREAM_STARTED.Flags |= QUIC_STREAM_OPEN_FLAG_APP_OWNED_BUFFERS;
}
auto StreamCtx = new SpinQuicStream(*ctx, Event->PEER_STREAM_STARTED.Stream);
MsQuic.SetCallbackHandler(Event->PEER_STREAM_STARTED.Stream, (void *)SpinQuicHandleStreamEvent, StreamCtx);
if (Event->PEER_STREAM_STARTED.Flags & QUIC_STREAM_OPEN_FLAG_APP_OWNED_BUFFERS) {
static uint8_t RecvBuffer[64000];
uint32_t BufCount = GetRandom(3) + 1; // 1-3 buffers
std::vector<QUIC_BUFFER> Buffers(BufCount);
for (uint32_t i = 0; i < BufCount; i++) {
Buffers[i].Length = MaxBufferSizes[GetRandom(BufferCount)];
Buffers[i].Buffer = RecvBuffer;
}
MsQuic.StreamProvideReceiveBuffers(Event->PEER_STREAM_STARTED.Stream, BufCount, Buffers.data());
}
ctx->AddStream(Event->PEER_STREAM_STARTED.Stream);
break;
}
Expand Down Expand Up @@ -975,9 +1006,19 @@ void Spin(Gbs& Gb, LockableVector<HQUIC>& Connections, std::vector<HQUIC>* Liste
BAIL_ON_NULL_CONNECTION(Connection);
HQUIC Stream;
auto ctx = new SpinQuicStream(*SpinQuicConnection::Get(Connection));
QUIC_STATUS Status = MsQuic.StreamOpen(Connection, (QUIC_STREAM_OPEN_FLAGS)GetRandom(8), SpinQuicHandleStreamEvent, ctx, &Stream);
QUIC_STREAM_OPEN_FLAGS OpenFlags = (QUIC_STREAM_OPEN_FLAGS)GetRandom(16);
QUIC_STATUS Status = MsQuic.StreamOpen(Connection, OpenFlags, SpinQuicHandleStreamEvent, ctx, &Stream);
if (QUIC_SUCCEEDED(Status)) {
ctx->Handle = Stream;
if ((OpenFlags & QUIC_STREAM_OPEN_FLAG_APP_OWNED_BUFFERS) && GetRandom(2) == 0) {
uint32_t BufCount = GetRandom(3) + 1; // 1-3 buffers
std::vector<QUIC_BUFFER> Buffers(BufCount);
for (uint32_t i = 0; i < BufCount; i++) {
Buffers[i].Length = MaxBufferSizes[GetRandom(BufferCount)];
Buffers[i].Buffer = Gb.RecvBuffer;
}
MsQuic.StreamProvideReceiveBuffers(Stream, BufCount, Buffers.data());
}
SpinQuicGetRandomParam(Stream, ThreadID);
SpinQuicSetRandomStreamParam(Stream, ThreadID);
SpinQuicConnection::Get(Connection)->AddStream(Stream);
Expand Down Expand Up @@ -1166,6 +1207,65 @@ void Spin(Gbs& Gb, LockableVector<HQUIC>& Connections, std::vector<HQUIC>* Liste
MsQuic.ConnectionCertificateValidationComplete(Connection, GetRandom(2) == 0, QUIC_TLS_ALERT_CODE_BAD_CERTIFICATE);
break;
}
case SpinQuicAPICallConnectionPoolCreate: {
if (!IsServer) {
uint16_t PoolSize = (uint16_t)(GetRandom(4) + 1); // 1-4 connections
std::vector<HQUIC> PoolConnections(PoolSize, nullptr);
std::vector<void*> Contexts(PoolSize, &ThreadID);
QUIC_CONNECTION_POOL_CONFIG PoolConfig = {0};
PoolConfig.Registration = Gb.Registration;
PoolConfig.Configuration = GetRandomFromVector(Gb.ClientConfigurations);
PoolConfig.Handler = SpinQuicHandleConnectionEvent;
PoolConfig.Context = Contexts.data();
PoolConfig.ServerName = SpinSettings.ServerName;
PoolConfig.ServerAddress = nullptr;
PoolConfig.Family = QUIC_ADDRESS_FAMILY_INET;
PoolConfig.ServerPort = GetRandomFromVector(SpinSettings.Ports);
PoolConfig.NumberOfConnections = PoolSize;
PoolConfig.CibirIds = nullptr;
PoolConfig.CibirIdLength = 0;
PoolConfig.Flags = (QUIC_CONNECTION_POOL_FLAGS)GetRandom(2);
QUIC_STATUS Status = MsQuic.ConnectionPoolCreate(&PoolConfig, PoolConnections.data());
if (QUIC_SUCCEEDED(Status)) {
for (uint16_t i = 0; i < PoolSize; i++) {
auto ctx = new(std::nothrow) SpinQuicConnection(PoolConnections[i], ThreadID);
if (ctx != nullptr) {
std::lock_guard<std::mutex> Lock(Connections);
Connections.push_back(PoolConnections[i]);
} else {
MsQuic.ConnectionClose(PoolConnections[i]);
}
}
} else if (!(PoolConfig.Flags & QUIC_CONNECTION_POOL_FLAG_CLOSE_ON_FAILURE)) {
for (uint16_t i = 0; i < PoolSize; i++) {
if (PoolConnections[i] != nullptr) {
MsQuic.ConnectionClose(PoolConnections[i]);
}
}
}
}
break;
}
case SpinQuicAPICallStreamProvideReceiveBuffers: {
auto Connection = Connections.TryGetRandom();
BAIL_ON_NULL_CONNECTION(Connection);
auto ctx = SpinQuicConnection::Get(Connection);
{
std::lock_guard<std::mutex> Lock(ctx->Lock);
auto Stream = ctx->TryGetStream();
if (Stream == nullptr) {
continue;
}
uint32_t BufCount = GetRandom(3) + 1; // 1-3 buffers
std::vector<QUIC_BUFFER> Buffers(BufCount);
for (uint32_t i = 0; i < BufCount; i++) {
Buffers[i].Length = MaxBufferSizes[GetRandom(BufferCount)];
Buffers[i].Buffer = Gb.RecvBuffer;
}
MsQuic.StreamProvideReceiveBuffers(Stream, BufCount, Buffers.data());
}
break;
}
default:
break;
}
Expand Down
Loading