зеркало из https://github.com/microsoft/msquic.git
Sync Latest - 11/27/19 (#14)
Lots of documentation changes and some fairly minor bug fixes and clean up.
This commit is contained in:
Родитель
69a2cf9d7c
Коммит
ddb0055425
58
README.md
58
README.md
|
@ -1,8 +1,10 @@
|
|||
MsQuic
|
||||
======
|
||||
|
||||
MsQuic is an implementation of the [IETF QUIC](https://tools.ietf.org/html/draft-ietf-quic-transport)
|
||||
protocol by Microsoft. It is a cross platform, general purpose QUIC library written in C.
|
||||
MsQuic is a Microsoft implementation of the [IETF QUIC](https://tools.ietf.org/html/draft-ietf-quic-transport)
|
||||
protocol. It is cross platform, written in C and designed to be a general purpose QUIC library.
|
||||
|
||||
> **Important** The MsQuic library, as well as the protocol itself, is still a work in progress. Version 1 is not yet finalized and may continue to experience breaking changes until it is finalized.
|
||||
|
||||
[![Build Status](https://microsoft.visualstudio.com/OS/_apis/build/status/microsoft.msquic?branchName=master)](https://microsoft.visualstudio.com/OS/_build/latest?definitionId=45975&branchName=master)
|
||||
|
||||
|
@ -14,42 +16,56 @@ QUIC has many benefits when compared to existing TLS over TCP scenarios:
|
|||
* All packets are encrypted
|
||||
* Parallel streams of application data.
|
||||
* Improved (compared to TCP) congestion control and loss recovery.
|
||||
* 0-RTT (_support depends on TLS library_)
|
||||
* Exchange application data in the first round trip (0-RTT).
|
||||
* Survives a change in the clients IP address or port.
|
||||
* Easily extendable for new features (such as unreliable delivery).
|
||||
|
||||
**Note** - Several QUIC protocol features are still unimplemented:
|
||||
|
||||
* NAT Rebinding
|
||||
* Client Migration
|
||||
* Server Preferred Address
|
||||
* Full Path MTU Discovery
|
||||
> **Important** Several QUIC protocol features are not fully implemented:
|
||||
>
|
||||
> * 0-RTT with Schannel and OpenSSL
|
||||
> * NAT Rebinding
|
||||
> * Client Migration
|
||||
> * Server Preferred Address
|
||||
> * Path MTU Discovery
|
||||
|
||||
## Library Features
|
||||
|
||||
* Optimized for throughput performance and minimal latency.
|
||||
* Optimized for maximal throughput and minimal latency.
|
||||
* Asychronous IO.
|
||||
* Receive side scaling (RSS).
|
||||
* UDP send and receive coalescing.
|
||||
* UDP send and receive coalescing support.
|
||||
|
||||
# Source Code
|
||||
## Building
|
||||
|
||||
You can find detailed instructions for building the library [here](./docs/BUILD.md).
|
||||
|
||||
## Documentation
|
||||
|
||||
You can find more detailed information on how to use MsQuic in the [the API documentation](./docs/API.md).
|
||||
|
||||
## Source Code
|
||||
|
||||
The source is divided into several directories:
|
||||
|
||||
* `bin` - Packages up all static libraries into the platform specific binaries.
|
||||
* `core` - The platform independent code that implements the QUIC protocol.
|
||||
* `core` - Platform independent code that implements the QUIC protocol.
|
||||
* `docs` - All MsQuic documentation.
|
||||
* `inc` - Header files used by all the other directories.
|
||||
* `manifest` - Windows [ETW manifest](https://docs.microsoft.com/en-us/windows/win32/wes/writing-an-instrumentation-manifest) and related files.
|
||||
* `platform` - Platform specific code for OS types, sockets and TLS.
|
||||
* `submodules` - All the modules that MsQuic depends on.
|
||||
* `test` - Test code for the MsQuic API / protocol.
|
||||
* `tools` - Several tools for exercising MsQuic.
|
||||
|
||||
You can find more detailed information on how to use MsQuic in the [the API documentation](./docs/API.md).
|
||||
|
||||
# Building
|
||||
|
||||
You can find detailed instructions [here](./docs/BUILD.md).
|
||||
* `tools` - Tools for exercising MsQuic.
|
||||
* `attack` - Adversarial tool for exploiting protocol weaknesses.
|
||||
* `etw` - Windows specific tool for processing MsQuic ETW logs.
|
||||
* `interop` - Runs through the [IETF interop scenarios](https://github.com/quicwg/base-drafts/wiki/15th-Implementation-Draft).
|
||||
* `ping` - Simple tool for gathering throughput measurements. Read more [here](./tools/ping/readme.md).
|
||||
* `sample` - Minimal example of how to use the MsQuic API.
|
||||
* `spin` - Randomly executes the MsQuic API to discover bugs.
|
||||
|
||||
# Contributing
|
||||
|
||||
For the near future, **external contributions will not be accepted**. We are still
|
||||
For the time being, **external contributions will not be accepted**. We are still
|
||||
working on setting up internal repository sycnhronization and continuous integration,
|
||||
and until that happens, this repository will be a simple copy of the Microsoft internal
|
||||
one.
|
||||
|
|
|
@ -1630,6 +1630,7 @@ QuicConnHandshakeConfigure(
|
|||
}
|
||||
|
||||
if (Connection->OrigCID != NULL) {
|
||||
QUIC_DBG_ASSERT(Connection->OrigCID->Length <= QUIC_MAX_CONNECTION_ID_LENGTH_V1);
|
||||
LocalTP.Flags |= QUIC_TP_FLAG_ORIGINAL_CONNECTION_ID;
|
||||
LocalTP.OriginalConnectionIDLength = Connection->OrigCID->Length;
|
||||
QuicCopyMemory(
|
||||
|
@ -1699,7 +1700,7 @@ QuicConnHandshakeConfigure(
|
|||
}
|
||||
|
||||
LocalTP.MaxAckDelay =
|
||||
Connection->MaxAckDelayMs + MsQuicLib.TimerResolutionMs; // TODO - Include queue delay?
|
||||
Connection->MaxAckDelayMs + MsQuicLib.TimerResolutionMs;
|
||||
|
||||
if (Connection->AckDelayExponent != QUIC_DEFAULT_ACK_DELAY_EXPONENT) {
|
||||
LocalTP.Flags |= QUIC_TP_FLAG_ACK_DELAY_EXPONENT;
|
||||
|
@ -2130,6 +2131,8 @@ QuicConnRecvRetry(
|
|||
return;
|
||||
}
|
||||
|
||||
QUIC_DBG_ASSERT(OrigDestCIDLength <= QUIC_MAX_CONNECTION_ID_LENGTH_V1);
|
||||
|
||||
//
|
||||
// Cache the Retry token.
|
||||
//
|
||||
|
@ -2354,7 +2357,8 @@ QuicConnRecvHeader(
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Connection->Paths[0].IsPeerValidated && Packet->ValidToken) {
|
||||
QUIC_PATH* Path = &Connection->Paths[0];
|
||||
if (!Path->IsPeerValidated && Packet->ValidToken) {
|
||||
|
||||
QUIC_DBG_ASSERT(TokenBuffer == NULL);
|
||||
QuicPacketDecodeRetryTokenV1(Packet, &TokenBuffer, &TokenLength);
|
||||
|
@ -2362,11 +2366,13 @@ QuicConnRecvHeader(
|
|||
|
||||
QUIC_RETRY_TOKEN_CONTENTS Token;
|
||||
if (!QuicRetryTokenDecrypt(Packet, TokenBuffer, &Token)) {
|
||||
QUIC_DBG_ASSERT(FALSE);
|
||||
QUIC_DBG_ASSERT(FALSE); // Was already decrypted sucessfully once.
|
||||
QuicPacketLogDrop(Connection, Packet, "Retry token decrypt failure");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
QUIC_DBG_ASSERT(Token.OrigConnIdLength <= sizeof(Token.OrigConnId));
|
||||
QUIC_DBG_ASSERT(QuicAddrCompare(&Path->RemoteAddress, &Token.RemoteAddress));
|
||||
|
||||
Connection->OrigCID =
|
||||
QUIC_ALLOC_NONPAGED(
|
||||
|
@ -2383,7 +2389,7 @@ QuicConnRecvHeader(
|
|||
Token.OrigConnId,
|
||||
Token.OrigConnIdLength);
|
||||
|
||||
QuicPathSetValid(Connection, &Connection->Paths[0], QUIC_PATH_VALID_INITIAL_TOKEN);
|
||||
QuicPathSetValid(Connection, Path, QUIC_PATH_VALID_INITIAL_TOKEN);
|
||||
}
|
||||
|
||||
Packet->KeyType = QuicPacketTypeToKeyType(Packet->LH->Type);
|
||||
|
@ -3882,6 +3888,9 @@ QuicConnResetIdleTimeout(
|
|||
}
|
||||
|
||||
QuicConnTimerSet(Connection, QUIC_CONN_TIMER_IDLE, IdleTimeoutMs);
|
||||
|
||||
} else {
|
||||
QuicConnTimerCancel(Connection, QUIC_CONN_TIMER_IDLE);
|
||||
}
|
||||
|
||||
if (Connection->KeepAliveIntervalMs != 0) {
|
||||
|
|
169
core/crypto.c
169
core/crypto.c
|
@ -270,7 +270,6 @@ QuicCryptoReset(
|
|||
QUIC_TEL_ASSERT(!Crypto->TlsCallPending);
|
||||
QUIC_TEL_ASSERT(Crypto->RecvTotalConsumed == 0);
|
||||
|
||||
Crypto->FirstHandshakePacketProcessed = FALSE;
|
||||
Crypto->MaxSentLength = 0;
|
||||
Crypto->UnAckedOffset = 0;
|
||||
Crypto->NextSendOffset = 0;
|
||||
|
@ -895,7 +894,8 @@ QuicCryptoOnAck(
|
|||
&SacksUpdated);
|
||||
if (Sack == NULL) {
|
||||
|
||||
QUIC_FRE_ASSERT(FALSE); // TODO - Allow this function to fail or treat as fatal error.
|
||||
QuicConnFatalError(Connection, QUIC_STATUS_OUT_OF_MEMORY, "Out of memory");
|
||||
return;
|
||||
|
||||
} else if (SacksUpdated) {
|
||||
|
||||
|
@ -963,13 +963,17 @@ QuicCryptoProcessDataFrame(
|
|||
} else {
|
||||
|
||||
if (KeyType != Crypto->TlsState.ReadKey) {
|
||||
LogWarning("[cryp][%p] Ignoring received crypto data with wrong key, %hu vs %hu!",
|
||||
Connection, KeyType, Crypto->TlsState.ReadKey);
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
//
|
||||
// TODO - If it was retransmitted data, it would be OK to ignore, but if they are
|
||||
// sending at the wrong encryption level, we fatal.
|
||||
//
|
||||
if (QuicRecvBufferAlreadyReadData(
|
||||
&Crypto->RecvBuffer,
|
||||
Crypto->RecvEncryptLevelStartOffset + Frame->Offset,
|
||||
(uint16_t)Frame->Length)) {
|
||||
Status = QUIC_STATUS_SUCCESS;
|
||||
} else {
|
||||
EventWriteQuicConnError(
|
||||
Connection, "Tried crypto with incorrect key.");
|
||||
QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION);
|
||||
Status = QUIC_STATUS_INVALID_STATE;
|
||||
}
|
||||
goto Error;
|
||||
}
|
||||
|
||||
|
@ -986,6 +990,11 @@ QuicCryptoProcessDataFrame(
|
|||
&FlowControlLimit,
|
||||
DataReady);
|
||||
if (QUIC_FAILED(Status)) {
|
||||
if (Status == QUIC_STATUS_BUFFER_TOO_SMALL) {
|
||||
EventWriteQuicConnError(
|
||||
Connection, "Tried to write beyond crypto flow control limit.");
|
||||
QuicConnTransportError(Connection, QUIC_ERROR_CRYPTO_BUFFER_EXCEEDED);
|
||||
}
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
|
@ -995,11 +1004,6 @@ QuicCryptoProcessDataFrame(
|
|||
|
||||
Error:
|
||||
|
||||
if (Status == QUIC_STATUS_BUFFER_TOO_SMALL) {
|
||||
LogWarning("[conn][%p] Tried to write beyond crypto flow control limit!", Connection);
|
||||
QuicConnTransportError(Connection, QUIC_ERROR_CRYPTO_BUFFER_EXCEEDED);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -1073,21 +1077,13 @@ QuicCryptoProcessTlsCompletion(
|
|||
{
|
||||
PQUIC_CONNECTION Connection = QuicCryptoGetConnection(Crypto);
|
||||
|
||||
Crypto->FirstHandshakePacketProcessed = TRUE;
|
||||
|
||||
if (ResultFlags & QUIC_TLS_RESULT_ERROR) {
|
||||
LogVerbose("[conn][%p] Received error from TLS, %u", Connection,
|
||||
Crypto->TlsState.AlertCode);
|
||||
EventWriteQuicConnErrorStatus(
|
||||
Connection, Crypto->TlsState.AlertCode, "Received alert from TLS.");
|
||||
QuicConnTransportError(
|
||||
Connection,
|
||||
QUIC_ERROR_CRYPTO_ERROR(0xFF & Crypto->TlsState.AlertCode));
|
||||
|
||||
if (!Connection->State.Connected) {
|
||||
//
|
||||
// Make sure to process error and connection complete only.
|
||||
//
|
||||
ResultFlags = QUIC_TLS_RESULT_ERROR | QUIC_TLS_RESULT_COMPLETE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ResultFlags & QUIC_TLS_RESULT_EARLY_DATA_ACCEPT) {
|
||||
|
@ -1160,9 +1156,16 @@ QuicCryptoProcessTlsCompletion(
|
|||
|
||||
if (ResultFlags & QUIC_TLS_RESULT_READ_KEY_UPDATED) {
|
||||
//
|
||||
// TODO - Make sure there isn't any data received past the current Recv
|
||||
// offset at the previous encryption level.
|
||||
// Make sure there isn't any data received past the current Recv offset
|
||||
// at the previous encryption level.
|
||||
//
|
||||
if (QuicRecvBufferHasUnreadData(&Crypto->RecvBuffer)) {
|
||||
EventWriteQuicConnError(
|
||||
Connection, "Leftover crypto data in previous encryption level.");
|
||||
QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION);
|
||||
return;
|
||||
}
|
||||
|
||||
Crypto->RecvEncryptLevelStartOffset = Crypto->RecvTotalConsumed;
|
||||
EventWriteQuicConnReadKeyUpdated(Connection, Crypto->TlsState.ReadKey);
|
||||
|
||||
|
@ -1219,81 +1222,66 @@ QuicCryptoProcessTlsCompletion(
|
|||
&QuicCryptoGetConnection(Crypto)->Send,
|
||||
QUIC_CONN_SEND_FLAG_CRYPTO);
|
||||
QuicCryptoDumpSendState(Crypto);
|
||||
|
||||
} else if (!Crypto->FirstHandshakePacketProcessed &&
|
||||
!(ResultFlags & QUIC_TLS_RESULT_ERROR) &&
|
||||
QuicConnIsServer(Connection)) {
|
||||
//
|
||||
// We just received our first packet, but it didn't include enough
|
||||
// payload to elicit a response. That constitutes an invalid first
|
||||
// packet from the client.
|
||||
//
|
||||
LogWarning("[conn][%p] Received invalid first handshake packet", Connection);
|
||||
QuicConnTransportError(Connection, QUIC_ERROR_PROTOCOL_VIOLATION);
|
||||
ResultFlags |= QUIC_TLS_RESULT_ERROR;
|
||||
}
|
||||
|
||||
if (ResultFlags & QUIC_TLS_RESULT_COMPLETE) {
|
||||
BOOLEAN Successful = !(ResultFlags & QUIC_TLS_RESULT_ERROR);
|
||||
QUIC_DBG_ASSERT(!(ResultFlags & QUIC_TLS_RESULT_ERROR));
|
||||
QUIC_TEL_ASSERT(!Connection->State.Connected);
|
||||
|
||||
if (Successful) {
|
||||
EventWriteQuicConnHandshakeComplete(Connection);
|
||||
|
||||
EventWriteQuicConnHandshakeComplete(Connection);
|
||||
//
|
||||
// We should have the 1-RTT keys by connection complete time.
|
||||
//
|
||||
QUIC_TEL_ASSERT(Crypto->TlsState.ReadKeys[QUIC_PACKET_KEY_1_RTT] != NULL);
|
||||
QUIC_TEL_ASSERT(Crypto->TlsState.WriteKeys[QUIC_PACKET_KEY_1_RTT] != NULL);
|
||||
|
||||
//
|
||||
// Only mark the handshake as complete on success.
|
||||
//
|
||||
Connection->State.Connected = TRUE;
|
||||
InterlockedDecrement(&Connection->Paths[0].Binding->HandshakeConnections);
|
||||
InterlockedExchangeAdd64(
|
||||
(LONG64*)&MsQuicLib.CurrentHandshakeMemoryUsage,
|
||||
-1 * (LONG64)QUIC_CONN_HANDSHAKE_MEMORY_USAGE);
|
||||
|
||||
(void)QuicConnGenerateNewSourceCid(Connection, FALSE);
|
||||
|
||||
if (!QuicConnIsServer(Connection) &&
|
||||
Connection->RemoteServerName != NULL) {
|
||||
|
||||
QUIC_SEC_CONFIG* SecConfig = QuicTlsGetSecConfig(Crypto->TLS);
|
||||
|
||||
//
|
||||
// We should have the 1-RTT keys by connection complete time.
|
||||
// Cache this information for future connections in this
|
||||
// session to make use of.
|
||||
//
|
||||
QUIC_TEL_ASSERT(Crypto->TlsState.ReadKeys[QUIC_PACKET_KEY_1_RTT] != NULL);
|
||||
QUIC_TEL_ASSERT(Crypto->TlsState.WriteKeys[QUIC_PACKET_KEY_1_RTT] != NULL);
|
||||
QUIC_TEL_ASSERT(Connection->Session != NULL);
|
||||
QuicSessionServerCacheSetState(
|
||||
Connection->Session,
|
||||
Connection->RemoteServerName,
|
||||
Connection->Stats.QuicVersion,
|
||||
&Connection->PeerTransportParams,
|
||||
SecConfig);
|
||||
|
||||
//
|
||||
// Only mark the handshake as complete on success.
|
||||
//
|
||||
Connection->State.Connected = TRUE;
|
||||
InterlockedDecrement(&Connection->Paths[0].Binding->HandshakeConnections);
|
||||
InterlockedExchangeAdd64(
|
||||
(LONG64*)&MsQuicLib.CurrentHandshakeMemoryUsage,
|
||||
-1 * (LONG64)QUIC_CONN_HANDSHAKE_MEMORY_USAGE);
|
||||
QuicTlsSecConfigRelease(SecConfig);
|
||||
}
|
||||
|
||||
(void)QuicConnGenerateNewSourceCid(Connection, FALSE);
|
||||
QUIC_CONNECTION_EVENT Event;
|
||||
Event.Type = QUIC_CONNECTION_EVENT_CONNECTED;
|
||||
Event.CONNECTED.EarlyDataAccepted = Crypto->TlsState.EarlyDataAccepted;
|
||||
LogVerbose("[conn][%p] Indicating QUIC_CONNECTION_EVENT_CONNECTED (EarlyData=%hu)",
|
||||
Connection, Event.CONNECTED.EarlyDataAccepted);
|
||||
(void)QuicConnIndicateEvent(Connection, &Event);
|
||||
|
||||
if (!QuicConnIsServer(Connection) &&
|
||||
Connection->RemoteServerName != NULL) {
|
||||
QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PMTUD);
|
||||
|
||||
QUIC_SEC_CONFIG* SecConfig = QuicTlsGetSecConfig(Crypto->TLS);
|
||||
|
||||
//
|
||||
// Cache this information for future connections in this
|
||||
// session to make use of.
|
||||
//
|
||||
QUIC_TEL_ASSERT(Connection->Session != NULL);
|
||||
QuicSessionServerCacheSetState(
|
||||
Connection->Session,
|
||||
Connection->RemoteServerName,
|
||||
Connection->Stats.QuicVersion,
|
||||
&Connection->PeerTransportParams,
|
||||
SecConfig);
|
||||
|
||||
QuicTlsSecConfigRelease(SecConfig);
|
||||
}
|
||||
|
||||
QUIC_CONNECTION_EVENT Event;
|
||||
Event.Type = QUIC_CONNECTION_EVENT_CONNECTED;
|
||||
Event.CONNECTED.EarlyDataAccepted = Crypto->TlsState.EarlyDataAccepted;
|
||||
LogVerbose("[conn][%p] Indicating QUIC_CONNECTION_EVENT_CONNECTED (EarlyData=%hu)",
|
||||
Connection, Event.CONNECTED.EarlyDataAccepted);
|
||||
(void)QuicConnIndicateEvent(Connection, &Event);
|
||||
|
||||
QuicSendSetSendFlag(&Connection->Send, QUIC_CONN_SEND_FLAG_PMTUD);
|
||||
|
||||
if (QuicConnIsServer(Connection) &&
|
||||
Crypto->TlsState.BufferOffset1Rtt != 0 &&
|
||||
Crypto->UnAckedOffset == Crypto->TlsState.BufferTotalLength) {
|
||||
QuicCryptoOnServerComplete(Crypto); // TODO - If sending 0-RTT tickets ever becomes
|
||||
// controllable by the app, this logic will have
|
||||
// to take that into account.
|
||||
}
|
||||
if (QuicConnIsServer(Connection) &&
|
||||
Crypto->TlsState.BufferOffset1Rtt != 0 &&
|
||||
Crypto->UnAckedOffset == Crypto->TlsState.BufferTotalLength) {
|
||||
QuicCryptoOnServerComplete(Crypto); // TODO - If sending 0-RTT tickets ever becomes
|
||||
// controllable by the app, this logic will have
|
||||
// to take that into account.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1440,7 +1428,8 @@ QuicCryptoProcessData(
|
|||
}
|
||||
|
||||
if (AcceptResult != QUIC_CONNECTION_ACCEPT) {
|
||||
LogInfo("[conn][%p] Conection Rejected, Reason=%u", Connection, AcceptResult); // TODO - ETW
|
||||
EventWriteQuicConnErrorStatus(
|
||||
Connection, AcceptResult, "Connection rejected.");
|
||||
if (AcceptResult == QUIC_CONNECTION_REJECT_NO_LISTENER) {
|
||||
QuicConnTransportError(
|
||||
Connection,
|
||||
|
|
|
@ -20,11 +20,6 @@ typedef struct _QUIC_CRYPTO {
|
|||
//
|
||||
BOOLEAN Initialized : 1;
|
||||
|
||||
//
|
||||
// Indicates the first handshake packet received has been completely processed.
|
||||
//
|
||||
BOOLEAN FirstHandshakePacketProcessed : 1;
|
||||
|
||||
//
|
||||
// Indicates the send state is in recovery.
|
||||
//
|
||||
|
|
|
@ -275,7 +275,6 @@ QuicAckFrameEncode(
|
|||
//
|
||||
// Decodes the ACK_FRAME (has packet numbers from largest to smallest) to a
|
||||
// QUIC_RANGE format (smallest to largest).
|
||||
// TODO - Continue to work with QUICWG to try to get this reversed.
|
||||
//
|
||||
_Success_(return != FALSE)
|
||||
BOOLEAN
|
||||
|
|
|
@ -1095,7 +1095,7 @@ QuicLibraryOnListenerRegistered(
|
|||
QuicWorkerPoolInitialize(
|
||||
NULL,
|
||||
0,
|
||||
max(1, MsQuicLib.PartitionCount / 4), // TODO - Something better that PartitionCount / 4?
|
||||
max(1, MsQuicLib.PartitionCount / 4),
|
||||
&MsQuicLib.WorkerPool))) {
|
||||
Success = FALSE;
|
||||
}
|
||||
|
|
|
@ -50,10 +50,6 @@ typedef struct _QUIC_LOOKUP {
|
|||
} HASH;
|
||||
};
|
||||
|
||||
//
|
||||
// TODO - Closed/Tombstone connection tracking?
|
||||
//
|
||||
|
||||
} QUIC_LOOKUP, *PQUIC_LOOKUP;
|
||||
|
||||
//
|
||||
|
|
|
@ -862,10 +862,6 @@ QuicLossDetectionDiscardPackets(
|
|||
AckedRetransmittableBytes += Packet->PacketLength;
|
||||
}
|
||||
|
||||
//
|
||||
// TODO - What about largest packet number? Should that be updated?
|
||||
//
|
||||
|
||||
QuicLossDetectionOnPacketAcknowledged(LossDetection, EncryptLevel, Packet);
|
||||
QuicSentPacketPoolReturnPacketMetadata(&Connection->Worker->SentPacketPool, Packet);
|
||||
|
||||
|
|
|
@ -211,6 +211,26 @@ QuicRecvBufferSetVirtualBufferLength(
|
|||
RecvBuffer->VirtualBufferLength = NewLength;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
QuicRecvBufferHasUnreadData(
|
||||
_In_ PQUIC_RECV_BUFFER RecvBuffer
|
||||
)
|
||||
{
|
||||
return QuicRecvBufferGetTotalLength(RecvBuffer) > RecvBuffer->BaseOffset;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
QuicRecvBufferAlreadyReadData(
|
||||
_In_ PQUIC_RECV_BUFFER RecvBuffer,
|
||||
_In_ uint64_t BufferOffset,
|
||||
_In_ uint16_t BufferLength
|
||||
)
|
||||
{
|
||||
return BufferOffset + BufferLength <= RecvBuffer->BaseOffset;
|
||||
}
|
||||
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
QUIC_STATUS
|
||||
QuicRecvBufferWrite(
|
||||
|
|
|
@ -93,6 +93,26 @@ QuicRecvBufferSetVirtualBufferLength(
|
|||
_In_ uint32_t NewLength
|
||||
);
|
||||
|
||||
//
|
||||
// Returns TRUE there is any unread data in the receive buffer.
|
||||
//
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
QuicRecvBufferHasUnreadData(
|
||||
_In_ PQUIC_RECV_BUFFER RecvBuffer
|
||||
);
|
||||
|
||||
//
|
||||
// Returns TRUE if the data was already read out of the receive buffer.
|
||||
//
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
BOOLEAN
|
||||
QuicRecvBufferAlreadyReadData(
|
||||
_In_ PQUIC_RECV_BUFFER RecvBuffer,
|
||||
_In_ uint64_t BufferOffset,
|
||||
_In_ uint16_t BufferLength
|
||||
);
|
||||
|
||||
//
|
||||
// Buffers a (possibly out-of-order or duplicate) range of bytes.
|
||||
//
|
||||
|
|
|
@ -878,7 +878,7 @@ QuicSendFlush(
|
|||
return QUIC_SEND_COMPLETE;
|
||||
}
|
||||
|
||||
QUIC_PATH* Path = &Connection->Paths[0]; // TODO - How to pick?
|
||||
QUIC_PATH* Path = &Connection->Paths[0];
|
||||
if (Path->DestCid == NULL) {
|
||||
return QUIC_SEND_COMPLETE;
|
||||
}
|
||||
|
|
109
docs/API.md
109
docs/API.md
|
@ -5,35 +5,47 @@ The MsQuic API is written in C (like the rest of the libary) and is cross platfo
|
|||
|
||||
The primary API header can be found in the `inc` directory: [msquic.h](../inc/msquic.h)
|
||||
|
||||
## Terms
|
||||
> **Important** The MsQuic API is still a work in progress. Version 1 is not yet finalized and will continue to experience breaking changes until it is finalized.
|
||||
|
||||
# Terminology
|
||||
|
||||
Term | Definition
|
||||
--- | ---
|
||||
*app* | The application that is calling into MsQuic
|
||||
*client* | The app that initiates a connection
|
||||
*server* | The app that accepts a connection from a peer
|
||||
*app* | The application that is calling into MsQuic.
|
||||
*client* | The app that initiates a connection.
|
||||
*server* | The app that accepts a connection from a peer.
|
||||
*handle* | A pointer to an MsQuic object.
|
||||
*endpoint* | One side of a connection; client or server.
|
||||
*peer* | The *other* side of a connection.
|
||||
*callback handler* | The function pointer the app registers with an MsQuic object.
|
||||
*app context* or<br> *context* | A (possibly null) pointer registered with an MsQuic object. It is passed to callback handlers.
|
||||
*event* | An upcall to a callback handler.
|
||||
|
||||
## High Level Overview
|
||||
# High Level Overview
|
||||
|
||||
## Object Model
|
||||
|
||||
![API Objects](images/api_objects.png)
|
||||
|
||||
The API supports both server and client applications. All functionality is exposed primarily via a set of different objects:
|
||||
|
||||
**Api** - The top level handle and function table for all other API calls.
|
||||
[**Api**](#library-function-table) - The top level handle and function table for all other API calls.
|
||||
|
||||
**Registration** – Manages the execution context for all child objects. An app may open multiple registrations but ideally should only open one.
|
||||
[**Registration**](#registration) – Manages the execution context for all child objects. An app may open multiple registrations but ideally should only open one.
|
||||
|
||||
**Security Configuration** – Abstracts the configuration for the TLS layer. This primarily consists of a certificate that is used for authentication. The app may create as many of these as necessary.
|
||||
[**Security Configuration**](#security-configuration) – Abstracts the configuration for the TLS layer. This primarily consists of a certificate that is used for authentication. The app may create as many of these as necessary.
|
||||
|
||||
**Session** – Abstracts several different session-layer concepts: TLS Session Resumption, Application Protocol Layer Negotiation (ALPN) and platform specifics (such as Server Silo and Network Compartment ID on Windows). The app may create as many of these as necessary.
|
||||
[**Session**](#session) – Abstracts several different session-layer concepts: TLS Session Resumption, Application Protocol Layer Negotiation (ALPN) and platform specifics (such as Server Silo and Network Compartment ID on Windows). The app may create as many of these as necessary.
|
||||
|
||||
**Listener** – Server side only, this object provides the interface for an app to accept incoming connections from clients. Once the connection has been accepted, it is independent of the listener. The app may create as many of these as necessary.
|
||||
[**Listener**](#listener) – Server side only, this object provides the interface for an app to accept incoming connections from clients. Once the connection has been accepted, it is independent of the listener. The app may create as many of these as necessary.
|
||||
|
||||
**Connection** – Represents the actual QUIC connection state between the client and server. The app may create (and/or accept) as many of these as necessary.
|
||||
[**Connection**](#connection) – Represents the actual QUIC connection state between the client and server. The app may create (and/or accept) as many of these as necessary.
|
||||
|
||||
**Stream** – The layer at which application data is exchanged. Streams may be opened by either peer of a connection and may be unidirectional or bidirectional. For a single connection, as many streams as necessary may be created.
|
||||
[**Stream**](#stream) – The layer at which application data is exchanged. Streams may be opened by either peer of a connection and may be unidirectional or bidirectional. For a single connection, as many streams as necessary may be created.
|
||||
|
||||
### Versioning
|
||||
## Versioning
|
||||
|
||||
MsQuic API is explicitly versioned by making the API function table version specific. The top level `MsQuicOpen` function takes an `ApiVersion` parameter as input and returns the corresponding function table. This allows for new versions of the function table to be easily added in the future.
|
||||
MsQuic API is explicitly versioned by making the API function table version specific. The top level [MsQuicOpen](v0/MsQuicOpen.md) function takes an `ApiVersion` parameter as input and returns the corresponding function table. This allows for new versions of the function table to be easily added in the future.
|
||||
|
||||
The API version number **needs to change** when:
|
||||
- The signature of an existing function changes.
|
||||
|
@ -44,12 +56,77 @@ The API version number **does not need to change** when:
|
|||
- New functions are added. They are appended to the existing function table.
|
||||
- The behavior of an existing function changes but can either be controlled via a flags field or doesn't break existing clients.
|
||||
|
||||
### Execution Mode
|
||||
## Execution Mode
|
||||
|
||||
In general, MsQuic uses a callback model for all asynchronous events up to the app. This includes things like connection state changes, new streams being created, stream data being received, and stream sends completing. All these events are indicated to the app via a callback on a thread owned by MsQuic.
|
||||
In general, MsQuic uses a callback model for all asynchronous events up to the app. This includes things like connection state changes, new streams being created, stream data being received, and stream sends completing. All these events are indicated to the app via the callback handler, on a thread owned by MsQuic.
|
||||
|
||||
Apps are expected to keep any execution time in the callback **to a minimum**. MsQuic does not use separate threads for the protocol execution and upcalls to the app. Therefore, any significant delays on the callback **will delay the protocol**. Any significant time or work needed to be completed by the app must happen on its own thread.
|
||||
|
||||
This doesn't mean the app isn't allowed to do any work in the callback. In fact, many things are expressly designed to be most efficient when the app does them on the callback. For instance, closing a handle to a connection or stream is ideally implemented in the "shutdown complete" indications.
|
||||
|
||||
One important aspect of this design is that all blocking calls invoked on a callback always happen inline (to prevent deadlocks), and will supercede any calls in progress or queued from a separate thread.
|
||||
|
||||
# API Objects
|
||||
|
||||
## Library Function Table
|
||||
|
||||
There are only two top level functions:
|
||||
|
||||
- [MsQuicOpen](v0/MsQuicOpen.md) - Initializes the MsQuic library and returns a version specific function table.
|
||||
- [MsQuicClose](v0/MsQuicClose.md) - Cleans up the function table and releases the library reference from the previous [MsQuicOpen](v0/MsQuicOpen.md) call.
|
||||
|
||||
As mentioned above (see [Versioning](#versioning)), [MsQuicOpen](v0/MsQuicOpen.md) takes an API version number as input and returns the corresponding version specific function table. This function table contains the functions for the rest of the MsQuic API.
|
||||
|
||||
When the app is done with the MsQuic library, it **must** call [MsQuicClose](v0/MsQuicClose.md) and pass in the function table it received from [MsQuicOpen](v0/MsQuicOpen.md). This allows for the library state to be cleaned up.
|
||||
|
||||
Please note, there is no explicit start/stop API for this library. Each API function table has a reference on the QUIC library: the library is initialized when the first call to [MsQuicOpen](v0/MsQuicOpen.md) succeeds and uninitialized when the last call to [MsQuicClose](v0/MsQuicClose.md) completes. An app should therefore beware of repeatedly calling [MsQuicOpen](v0/MsQuicOpen.md) and [MsQuicClose](v0/MsQuicClose.md), as library setup/cleanup can be expensive.
|
||||
|
||||
## Registration
|
||||
|
||||
Generally, each app only needs a single registration. The registration represents the execution context where all logic for the app's connections run. The library will create a number of worker threads for each registration, shared for all the connections. This execution context is not shared between different registrations.
|
||||
|
||||
A registration is created by calling [RegistrationOpen](v1/RegistrationOpen.md) and deleted by calling [RegistrationClose](v1/RegistrationClose.md).
|
||||
|
||||
## Security Configuration
|
||||
|
||||
Currently only used on the server side, the security configuration (AKA security config) abstracts a server certificate (and other configuration) used by a [listener](#listener) to accept an incoming connection request.
|
||||
|
||||
A security config is created by calling [SecConfigCreate](v1/SecConfigCreate.md) and deleted by calling [SecConfigDelete](v1/SecConfigDelete.md).
|
||||
|
||||
## Session
|
||||
|
||||
An app must create a session before it can create any listeners or connections. Each session maintains certain transport and platform state common to all child handles. Primarily, this consists of the ALPN string used for the connection handshakes and TLS state used for session resumption. On Windows platforms it also inherits the Silo and Network Compartment ID from the thread that creates it.
|
||||
|
||||
A session is created by calling [SessionOpen](v1/SessionOpen.md) and deleted by calling [SessionClose](v1/SessionClose.md). [SessionClose](v1/SessionClose.md) **will block** on all oustanding connections. Therefore do not call it on any MsQuic event callback, as it will likely create a deadlock.
|
||||
|
||||
## Listener
|
||||
|
||||
To create a QUIC server, an app must create a listener via [ListenerOpen](v1/ListenerOpen.md). This will return a new listener handle that is ready to start accepting incoming connections. Then, the app must call [ListenerStart](v1/ListenerStart.md) to get callbacks for new incoming connections. [ListenerStart](v1/ListenerStart.md) takes the network address the app wants to listener on.
|
||||
|
||||
When a new connection is started by a client, the app will get a callback allowing it to accept the connection. This happens via the `QUIC_LISTENER_EVENT_NEW_CONNECTION` callback event, which contains all the currently known information in the `QUIC_NEW_CONNECTION_INFO` struct. The app is required to do one of three things in response to this event:
|
||||
|
||||
1. Return a failure status, indicating it didn’t accept the new connection.
|
||||
2. Return `QUIC_STATUS_SUCCESS` and set the SecConfig output parameter in the event.
|
||||
3. Return `QUIC_STATUS_PENDING`, which allows the SecConfig to be set later, via a call to SetParam with the `QUIC_PARAM_CONN_SEC_CONFIG` option.
|
||||
|
||||
If both 2 and 3 above, the app now has ownership of the connection object. It **must** set the callback handler via [SetCallbackHandler](v1/SetCallbackHandler.md) before the callback returns. Additionally, it must call [ConnectionClose](v1/ConnectionClose.md) on the connection to clean it up when it’s done with the connection. Also, in case 2, if the app does not set the SecConfig, it is treated as case 1.
|
||||
|
||||
When the app wishes to stop accepting new connections and stop further callbacks to the registered handler, it can call [ListenerStop](v1/ListenerStop.md). This call will block while any existing callbacks complete, and when it returns no future callbacks will occur. Therefore, the app ***must not** call this on any other library callbacks. The app may call [ListenerStart](v1/ListenerStart.md) again on the listener to start listening for incoming connections again.
|
||||
|
||||
To clean up the listener object, the app calls [ListenerClose](v1/ListenerClose.md). If the listener was not previously stopped, this function implicitly calls [ListenerStop](v1/ListenerStop.md), so all the same restrictions to that call apply.
|
||||
|
||||
## Connection
|
||||
|
||||
A connection handle represents a single QUIC connection and is generally the same thing on both client and server side. The main difference between client and server is just how the handle gets initially created. On client it is created explicitly by the app via a call to [ConnectionOpen](v1/ConnectionOpen.md). On server it is created by the listener and delivered to the app via a callback to the registered `QUIC_LISTENER_CALLBACK_HANDLER`. Just like all objects in MsQuic, the connection requires the app to be registered for event callbacks always. After the client creates the new connection, it starts the process of connecting to a remote server by calling [ConnectionStart](v1/ConnectionStart.md). If the connection attempt succeeds, the connection event handler will be invoked for a `QUIC_CONNECTION_EVENT_CONNECTED` event; otherwise a `QUIC_CONNECTION_EVENT_CLOSED` event will be received.
|
||||
|
||||
Once the app has a connection (either client or server) it can start opening streams and receiving events for remotely opened streams. Remotely opened streams are indicated to the callback handler via a `QUIC_CONNECTION_EVENT_NEW_STREAM` event. The app is required to immediately call [SetCallbackHandler](v1/SetCallbackHandler.md) to register a callback handler for the new stream. See [Stream](#stream) usage for more details on how stream are used.
|
||||
|
||||
When the app is done with the connection, it can then call [ConnectionShutdown](v1/ConnectionShutdown.md) to start the process of shutting down. This would cause the connection to immediately shutdown all open streams and send the shutdown indication to the peer over the network. When this process completes, the connection will invoke the event handler with a `QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE` event. After this, the app would be free to call [ConnectionClose](v1/ConnectionClose.md) to free up the connection resources.
|
||||
|
||||
## Stream
|
||||
|
||||
Streams are the primary means of exchanging app data over a connection. Streams can be bidirectional and unidirectional. They can also be initiated/opened by either endpoint (Client or server). Each endpoint dicates exactly how many streams of each type (unidirectional or bidirectional) their peer can open at a given time. Finally, they can be shutdown by either endpoint, in either direction.
|
||||
|
||||
A stream handle represents a single QUIC stream. It can be locally created by a call to [StreamOpen](v1/StreamOpen.md) or remotely created and then indicated to the app via the connection's callback handler via a `QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED` event. Locally created streams must be started (via [StreamStart](v1/StreamStart.md)) before they can practically be used. Remote streams are already started when indicated to the app.
|
||||
|
||||
Once the stream handle is available and started, the app can start receiving events on its callback handler (such as `QUIC_STREAM_EVENT_RECV`) and start sending on the stream (via [StreamSend](v1/StreamSend.md)). For more details see [Using Streams](Streams.md).
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
Using Streams
|
||||
======
|
||||
|
||||
**TODO**
|
||||
|
||||
# Sending
|
||||
|
||||
**TODO**
|
||||
|
||||
# Receiving
|
||||
|
||||
**TODO**
|
||||
|
||||
# Shutting Down
|
||||
|
||||
**TODO**
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 7.7 KiB |
|
@ -0,0 +1,30 @@
|
|||
MsQuicClose function
|
||||
======
|
||||
|
||||
Closes an existing handle to the MsQuic library, releasing the reference on the library and freeing the function table.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
_Pre_defensive_
|
||||
void
|
||||
QUIC_API
|
||||
MsQuicClose(
|
||||
_In_ const void* QuicApi
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`QuicApi`
|
||||
|
||||
The function table from a previous call to [MsQuicOpen](MsQuicOpen.md).
|
||||
|
||||
# Remarks
|
||||
|
||||
This function **must** be called when the app is done with the MsQuic library.
|
||||
|
||||
# See Also
|
||||
|
||||
[MsQuicOpen](MsQuicOpen.md)<br>
|
|
@ -0,0 +1,64 @@
|
|||
MsQuicOpen function
|
||||
======
|
||||
|
||||
Opens a new handle to the MsQuic library.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
_Pre_defensive_
|
||||
QUIC_STATUS
|
||||
QUIC_API
|
||||
MsQuicOpen(
|
||||
_In_ uint32_t ApiVersion,
|
||||
_Out_ void** QuicApi
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`ApiVersion`
|
||||
|
||||
The version number of the API handle and function table to open.
|
||||
|
||||
Value | Meaning
|
||||
--- | ---
|
||||
**QUIC_API_VERSION_1**<br>0x00000001 | Version 1 of the MsQuic API.<br>`QuicApi` returns a pointer to a [QUIC_API_V1](../v1/QUIC_API_V1.md) function table.
|
||||
|
||||
`QuicApi`
|
||||
|
||||
On success, returns a pointer to the new version specific function table. The table above explains the mappings between `ApiVersion` to function table.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
This function is the entry point for the MsQuic API. This function may be called multiple times to get multiple new function tables, but this is generally unnecessary. An app should only need call this once.
|
||||
|
||||
For every successful call to **MsQuicOpen** the app must call [MsQuicClose](MsQuicClose.md), passing in the function table from *QuicApi* when the app is done with it.
|
||||
|
||||
## Helpers
|
||||
|
||||
Version specific helpers of this function are included inline:
|
||||
|
||||
### MsQuicOpenV1
|
||||
|
||||
```C
|
||||
inline
|
||||
QUIC_STATUS
|
||||
QUIC_API
|
||||
MsQuicOpenV1(
|
||||
_Out_ QUIC_API_V1** QuicApi
|
||||
)
|
||||
{
|
||||
return MsQuicOpen(QUIC_API_VERSION_1, (void**)QuicApi);
|
||||
}
|
||||
```
|
||||
|
||||
# See Also
|
||||
|
||||
[MsQuicClose](MsQuicClose.md)<br>
|
||||
[QUIC_API_V1](../v1/QUIC_API_V1.md)<br>
|
|
@ -0,0 +1,53 @@
|
|||
QUIC_STATUS type
|
||||
======
|
||||
|
||||
The status type MsQuic uses for all API return codes.
|
||||
|
||||
# Syntax
|
||||
|
||||
## Windows (User Mode)
|
||||
|
||||
```C
|
||||
#define QUIC_STATUS HRESULT
|
||||
#define QUIC_FAILED(X) FAILED(X)
|
||||
#define QUIC_SUCCEEDED(X) SUCCEEDED(X)
|
||||
```
|
||||
|
||||
## Linux
|
||||
|
||||
```C
|
||||
#define QUIC_STATUS ULONG
|
||||
#define QUIC_FAILED(X) ((int)(X) > 0)
|
||||
#define QUIC_SUCCEEDED(X) ((int)(X) <= 0)
|
||||
```
|
||||
|
||||
# Remarks
|
||||
|
||||
The **QUIC_STATUS** type is a cross platform abstraction of the current platform's error code space. It allows for both success and failure values, which can be easily determined by the `QUIC_SUCCEEDED` and `QUIC_FAILED` macros.
|
||||
|
||||
The MsQuic headers define a number of different possible values for this (see below) but this list is not exhaustive. The platform specific functionality (for example UDP sockets) may also return platform specific error codes up to the app.
|
||||
|
||||
## Well-Known Status Codes
|
||||
|
||||
Value | Meaning
|
||||
--- | ---
|
||||
**QUIC_STATUS_SUCCESS** | The operation completed successfully.
|
||||
**QUIC_STATUS_PENDING** | The operation is pending.
|
||||
**QUIC_STATUS_CONTINUE** | The operation will continue.
|
||||
**QUIC_STATUS_OUT_OF_MEMORY** | Allocation of memory failed.
|
||||
**QUIC_STATUS_INVALID_PARAMETER** | An invalid parameter was encountered.
|
||||
**QUIC_STATUS_INVALID_STATE** | The current state was not valid for this operation.
|
||||
**QUIC_STATUS_NOT_SUPPORTED** | The operation was not supported.
|
||||
**QUIC_STATUS_NOT_FOUND** | The object was not found.
|
||||
**QUIC_STATUS_BUFFER_TOO_SMALL** | The buffer was too small for the operation.
|
||||
**QUIC_STATUS_HANDSHAKE_FAILURE** | The connection handshake failed.
|
||||
**QUIC_STATUS_ABORTED** | The connection or stream was aborted.
|
||||
**QUIC_STATUS_ADDRESS_IN_USE** | The local address is already in use.
|
||||
**QUIC_STATUS_CONNECTION_TIMEOUT** | The connection timed out waiting for a response from the peer.
|
||||
**QUIC_STATUS_CONNECTION_IDLE** | The connection timed out from inactivity.
|
||||
**QUIC_STATUS_INTERNAL_ERROR** | An internal error was encountered.
|
||||
**QUIC_STATUS_UNREACHABLE** | The server is currently unreachable.
|
||||
**QUIC_STATUS_SERVER_BUSY** | The server is currently busy.
|
||||
**QUIC_STATUS_PROTOCOL_ERROR** | A protocol error was encountered.
|
||||
**QUIC_STATUS_VER_NEG_ERROR** | A version negotiation error was encountered.
|
||||
**QUIC_STATUS_TLS_ERROR** | A TLS layer error was encountered.
|
|
@ -0,0 +1,32 @@
|
|||
ConnectionClose function
|
||||
======
|
||||
|
||||
Closes an existing connection.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_CONNECTION_CLOSE_FN)(
|
||||
_In_ _Pre_defensive_ __drv_freesMem(Mem)
|
||||
HQUIC Connection
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Connection`
|
||||
|
||||
The valid handle to an open connection object.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ConnectionOpen](ConnectionOpen.md)<br>
|
||||
[ConnectionShutdown](ConnectionShutdown.md)<br>
|
||||
[ConnectionStart](ConnectionStart.md)<br>
|
|
@ -0,0 +1,51 @@
|
|||
ConnectionOpen function
|
||||
======
|
||||
|
||||
Creates a new connection.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_CONNECTION_OPEN_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Session,
|
||||
_In_ _Pre_defensive_ QUIC_CONNECTION_CALLBACK_HANDLER Handler,
|
||||
_In_opt_ void* Context,
|
||||
_Outptr_ _At_(*Connection, __drv_allocatesMem(Mem)) _Pre_defensive_
|
||||
HQUIC* Connection
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Session`
|
||||
|
||||
The valid handle to an open session object.
|
||||
|
||||
`Handler`
|
||||
|
||||
A pointer to the app's callback handler to be invoked for all connection events.
|
||||
|
||||
`Context`
|
||||
|
||||
The app context pointer (possibly null) to be associated with the connection object.
|
||||
|
||||
`Connection`
|
||||
|
||||
On success, returns a handle to the newly opened connection object.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ConnectionClose](ConnectionClose.md)<br>
|
||||
[ConnectionShutdown](ConnectionShutdown.md)<br>
|
||||
[ConnectionStart](ConnectionStart.md)<br>
|
|
@ -0,0 +1,46 @@
|
|||
ConnectionShutdown function
|
||||
======
|
||||
|
||||
Starts the shutdown process on a connection.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_CONNECTION_SHUTDOWN_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Connection,
|
||||
_In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags,
|
||||
_In_ _Pre_defensive_ QUIC_UINT62 ErrorCode // Application defined error code
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Connection`
|
||||
|
||||
The valid handle to an open connection object.
|
||||
|
||||
`Flags`
|
||||
|
||||
The flags that control the behavior of the shutdown.
|
||||
|
||||
Value | Meaning
|
||||
--- | ---
|
||||
**QUIC_CONNECTION_SHUTDOWN_FLAG_NONE**<br>0 | The connection is shutdown gracefully and informs the peer.
|
||||
**QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT**<br>1 | The connection is immediately shutdown without informing the peer.
|
||||
|
||||
`ErrorCode`
|
||||
|
||||
The 62-bit error code to indicate to the peer as the reason for the shutdown.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ConnectionOpen](ConnectionOpen.md)<br>
|
||||
[ConnectionClose](ConnectionClose.md)<br>
|
||||
[ConnectionStart](ConnectionStart.md)<br>
|
|
@ -0,0 +1,57 @@
|
|||
ConnectionStart function
|
||||
======
|
||||
|
||||
Starts connecting to the server.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_CONNECTION_START_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Connection,
|
||||
_In_ QUIC_ADDRESS_FAMILY Family,
|
||||
_In_reads_opt_z_(QUIC_MAX_SNI_LENGTH)
|
||||
const char* ServerName,
|
||||
_In_ uint16_t ServerPort // Host byte order
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Connection`
|
||||
|
||||
The valid handle to an open connection object.
|
||||
|
||||
`Family`
|
||||
|
||||
The address family to use for resolving the IP address of the *ServerName* parameter. Supported values are as follows:
|
||||
|
||||
Value | Meaning
|
||||
--- | ---
|
||||
**AF_UNSPEC**<br>0 | Unspecified address family.
|
||||
**AF_INET**<br>2 | Version 4 IP address family.
|
||||
**AF_INET6**<br>23 | Version 6 IP address family.
|
||||
|
||||
`ServerName`
|
||||
|
||||
The name of the server to connect to. It may also be an IP literal.
|
||||
|
||||
`ServerPort`
|
||||
|
||||
The UDP port, in host byte order, to connect to on the server.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ConnectionOpen](ConnectionStart.md)<br>
|
||||
[ConnectionClose](ConnectionClose.md)<br>
|
||||
[ConnectionShutdown](ConnectionShutdown.md)<br>
|
|
@ -0,0 +1,36 @@
|
|||
GetContext function
|
||||
======
|
||||
|
||||
Gets the application context from the API object.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
void*
|
||||
(QUIC_API * QUIC_GET_CONTEXT_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Handle
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Handle`
|
||||
|
||||
The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns the previously set application context for the object.
|
||||
|
||||
# Remarks
|
||||
|
||||
This function allows the app to query the application context it has previously set on the object.
|
||||
|
||||
> **Important** There is no internal synchronization for this context. If the app calls **GetContext**, [SetContext](SetContext.md) and/or [SetCallbackHandler](SetCallbackHandler.md) on different threads, it must provide for the necessary synchronization mechanisms.
|
||||
|
||||
# See Also
|
||||
|
||||
[SetContext](SetContext.md)<br>
|
||||
[SetCallbackHandler](SetCallbackHandler.md)<br>
|
|
@ -0,0 +1,54 @@
|
|||
GetParam function
|
||||
======
|
||||
|
||||
Gets a parameter from an API object.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_GET_PARAM_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Handle,
|
||||
_In_ _Pre_defensive_ QUIC_PARAM_LEVEL Level,
|
||||
_In_ uint32_t Param,
|
||||
_Inout_ _Pre_defensive_ uint32_t* BufferLength,
|
||||
_Out_writes_bytes_opt_(*BufferLength)
|
||||
void* Buffer
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Handle`
|
||||
|
||||
The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects.
|
||||
|
||||
`Level`
|
||||
|
||||
The level at which the parameter is defined (for example, `QUIC_PARAM_LEVEL_CONNECTION`).
|
||||
|
||||
`Param`
|
||||
|
||||
The parameter for which the value is to be set (for example, `QUIC_PARAM_CONN_IDLE_TIMEOUT`). The *Param* parameter must be a parameter defined within the specified *Level*, or behavior is undefined.
|
||||
|
||||
`BufferLength`
|
||||
|
||||
The size, in bytes, of the buffer pointed to by the *Buffer* parameter.
|
||||
|
||||
`Buffer`
|
||||
|
||||
A pointer to the buffer in which the value for the requested parameter is specified.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[SetParam](SetParam.md)<br>
|
|
@ -0,0 +1,30 @@
|
|||
ListenerClose function
|
||||
======
|
||||
|
||||
Closes an existing listener.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_LISTENER_CLOSE_FN)(
|
||||
_In_ _Pre_defensive_ __drv_freesMem(Mem)
|
||||
HQUIC Listener
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ListenerOpen](ListenerOpen.md)<br>
|
||||
[ListenerStart](ListenerStart.md)<br>
|
||||
[ListenerStop](ListenerStop.md)<br>
|
|
@ -0,0 +1,37 @@
|
|||
ListenerOpen function
|
||||
======
|
||||
|
||||
Creates a new listener.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_LISTENER_OPEN_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Session,
|
||||
_In_ _Pre_defensive_ QUIC_LISTENER_CALLBACK_HANDLER Handler,
|
||||
_In_opt_ void* Context,
|
||||
_Outptr_ _At_(*Listener, __drv_allocatesMem(Mem)) _Pre_defensive_
|
||||
HQUIC* Listener
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ListenerClose](ListenerClose.md)<br>
|
||||
[ListenerStart](ListenerStart.md)<br>
|
||||
[ListenerStop](ListenerStop.md)<br>
|
|
@ -0,0 +1,34 @@
|
|||
ListenerStart function
|
||||
======
|
||||
|
||||
Starts listening for incoming connection requests.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_LISTENER_START_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Listener,
|
||||
_In_opt_ const QUIC_ADDR* LocalAddress
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ListenerOpen](ListenerOpen.md)<br>
|
||||
[ListenerClose](ListenerClose.md)<br>
|
||||
[ListenerStop](ListenerStop.md)<br>
|
|
@ -0,0 +1,29 @@
|
|||
ListenerStop function
|
||||
======
|
||||
|
||||
Stops listening for incoming connection requests.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_LISTENER_STOP_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Listener
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[ListenerOpen](ListenerOpen.md)<br>
|
||||
[ListenerClose](ListenerClose.md)<br>
|
||||
[ListenerStart](ListenerStart.md)<br>
|
|
@ -0,0 +1,167 @@
|
|||
QUIC_API_V1 structure
|
||||
======
|
||||
|
||||
Deletes an existing registration.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef struct _QUIC_API_V1 {
|
||||
|
||||
uint32_t Version; // QUIC_API_VERSION_1
|
||||
|
||||
QUIC_SET_CONTEXT_FN SetContext;
|
||||
QUIC_GET_CONTEXT_FN GetContext;
|
||||
QUIC_SET_CALLBACK_HANDLER_FN SetCallbackHandler;
|
||||
|
||||
QUIC_SET_PARAM_FN SetParam;
|
||||
QUIC_GET_PARAM_FN GetParam;
|
||||
|
||||
QUIC_REGISTRATION_OPEN_FN RegistrationOpen;
|
||||
QUIC_REGISTRATION_CLOSE_FN RegistrationClose;
|
||||
|
||||
QUIC_SEC_CONFIG_CREATE_FN SecConfigCreate;
|
||||
QUIC_SEC_CONFIG_DELETE_FN SecConfigDelete;
|
||||
|
||||
QUIC_SESSION_OPEN_FN SessionOpen;
|
||||
QUIC_SESSION_CLOSE_FN SessionClose;
|
||||
QUIC_SESSION_SHUTDOWN_FN SessionShutdown;
|
||||
|
||||
QUIC_LISTENER_OPEN_FN ListenerOpen;
|
||||
QUIC_LISTENER_CLOSE_FN ListenerClose;
|
||||
QUIC_LISTENER_START_FN ListenerStart;
|
||||
QUIC_LISTENER_STOP_FN ListenerStop;
|
||||
|
||||
QUIC_CONNECTION_OPEN_FN ConnectionOpen;
|
||||
QUIC_CONNECTION_CLOSE_FN ConnectionClose;
|
||||
QUIC_CONNECTION_SHUTDOWN_FN ConnectionShutdown;
|
||||
QUIC_CONNECTION_START_FN ConnectionStart;
|
||||
|
||||
QUIC_STREAM_OPEN_FN StreamOpen;
|
||||
QUIC_STREAM_CLOSE_FN StreamClose;
|
||||
QUIC_STREAM_START_FN StreamStart;
|
||||
QUIC_STREAM_SHUTDOWN_FN StreamShutdown;
|
||||
QUIC_STREAM_SEND_FN StreamSend;
|
||||
QUIC_STREAM_RECEIVE_COMPLETE_FN StreamReceiveComplete;
|
||||
QUIC_STREAM_RECEIVE_SET_ENABLED_FN StreamReceiveSetEnabled;
|
||||
|
||||
} QUIC_API_V1;
|
||||
```
|
||||
|
||||
# Members
|
||||
|
||||
`Version`
|
||||
|
||||
The API version this structure is for. Always `QUIC_API_VERSION_1`.
|
||||
|
||||
`SetContext`
|
||||
|
||||
See [SetContext](SetContext.md)
|
||||
|
||||
`GetContext`
|
||||
|
||||
See [GetContext](GetContext.md)
|
||||
|
||||
`SetCallbackHandler`
|
||||
|
||||
See [SetCallbackHandler](SetCallbackHandler.md)
|
||||
|
||||
`SetParam`
|
||||
|
||||
See [SetParam](SetParam.md)
|
||||
|
||||
`GetParam`
|
||||
|
||||
See [GetParam](GetParam.md)
|
||||
|
||||
`RegistrationOpen`
|
||||
|
||||
See [RegistrationOpen](RegistrationOpen.md)
|
||||
|
||||
`RegistrationClose`
|
||||
|
||||
See [RegistrationClose](RegistrationClose.md)
|
||||
|
||||
`SecConfigCreate`
|
||||
|
||||
See [SecConfigCreate](SecConfigCreate.md)
|
||||
|
||||
`SecConfigDelete`
|
||||
|
||||
See [SecConfigDelete](SecConfigDelete.md)
|
||||
|
||||
`SessionOpen`
|
||||
|
||||
See [SessionOpen](SessionOpen.md)
|
||||
|
||||
`SessionClose`
|
||||
|
||||
See [SessionClose](SessionClose.md)
|
||||
|
||||
`SessionShutdown`
|
||||
|
||||
See [SessionShutdown](SessionShutdown.md)
|
||||
|
||||
`ListenerOpen`
|
||||
|
||||
See [ListenerOpen](ListenerOpen.md)
|
||||
|
||||
`ListenerClose`
|
||||
|
||||
See [ListenerClose](ListenerClose.md)
|
||||
|
||||
`ListenerStart`
|
||||
|
||||
See [ListenerStart](ListenerStart.md)
|
||||
|
||||
`ListenerStop`
|
||||
|
||||
See [ListenerStop](ListenerStop.md)
|
||||
|
||||
`ConnectionOpen`
|
||||
|
||||
See [ConnectionOpen](ConnectionOpen.md)
|
||||
|
||||
`ConnectionClose`
|
||||
|
||||
See [ConnectionClose](ConnectionClose.md)
|
||||
|
||||
`ConnectionShutdown`
|
||||
|
||||
See [ConnectionShutdown](ConnectionShutdown.md)
|
||||
|
||||
`ConnectionStart`
|
||||
|
||||
See [ConnectionStart](ConnectionStart.md)
|
||||
|
||||
`StreamOpen`
|
||||
|
||||
See [StreamOpen](StreamOpen.md)
|
||||
|
||||
`StreamClose`
|
||||
|
||||
See [StreamClose](StreamClose.md)
|
||||
|
||||
`StreamStart`
|
||||
|
||||
See [StreamStart](StreamStart.md)
|
||||
|
||||
`StreamShutdown`
|
||||
|
||||
See [StreamShutdown](StreamShutdown.md)
|
||||
|
||||
`StreamSend`
|
||||
|
||||
See [StreamSend](StreamSend.md)
|
||||
|
||||
`StreamReceiveComplete`
|
||||
|
||||
See [StreamReceiveComplete](StreamReceiveComplete.md)
|
||||
|
||||
`StreamReceiveSetEnabled`
|
||||
|
||||
See [StreamReceiveSetEnabled](StreamReceiveSetEnabled.md)
|
||||
|
||||
# See Also
|
||||
|
||||
[MsQuicOpen](..\v0/MsQuicOpen.md)<br>
|
|
@ -0,0 +1,30 @@
|
|||
RegistrationClose function
|
||||
======
|
||||
|
||||
Closes an existing registration.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_REGISTRATION_CLOSE_FN)(
|
||||
_In_ _Pre_defensive_ __drv_freesMem(Mem)
|
||||
HQUIC Registration
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Registration`
|
||||
|
||||
A registration handle from a previous call to [RegistrationOpen](RegistrationOpen.md).
|
||||
|
||||
# Remarks
|
||||
|
||||
The application **must** close/delete all child security configurations and session objects before closing the registration. This call **will block** on those outstanding objects being cleaned up. Do no call it on any MsQuic event callback, or it will deadlock.
|
||||
|
||||
# See Also
|
||||
|
||||
[RegistrationOpen](RegistrationOpen.md)<br>
|
|
@ -0,0 +1,39 @@
|
|||
RegistrationOpen function
|
||||
======
|
||||
|
||||
Creates a new registration.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_REGISTRATION_OPEN_FN)(
|
||||
_In_opt_z_ _Pre_defensive_ const char* AppName,
|
||||
_Outptr_ _At_(*Registration, __drv_allocatesMem(Mem)) _Pre_defensive_
|
||||
HQUIC* Registration
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`AppName`
|
||||
|
||||
An optional name for the application layer, used purely for debugging purposes.
|
||||
|
||||
`Registration`
|
||||
|
||||
On success, returns a handle the the newly created registration.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[RegistrationClose](RegistrationClose.md)<br>
|
|
@ -0,0 +1,67 @@
|
|||
SecConfigCreate function
|
||||
======
|
||||
|
||||
Asynchronously creates a new security configuration.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_SEC_CONFIG_CREATE_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Registration,
|
||||
_In_ QUIC_SEC_CONFIG_FLAGS Flags,
|
||||
_In_opt_ void* Certificate,
|
||||
_In_opt_z_ const char* Principal,
|
||||
_In_opt_ void* Context,
|
||||
_In_ _Pre_defensive_
|
||||
QUIC_SEC_CONFIG_CREATE_COMPLETE_HANDLER CompletionHandler
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Registration`
|
||||
|
||||
The valid handle to an open registration object.
|
||||
|
||||
`Flags`
|
||||
|
||||
The flags that control the type of the structure passed into the *Certificate* parameter.
|
||||
|
||||
Value | Meaning
|
||||
--- | ---
|
||||
**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH**<br>0x00000001 | The *Certificate* parameter points to a `QUIC_CERTIFICATE_HASH` struct.
|
||||
**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_HASH_STORE**<br>0x00000002 | The *Certificate* parameter points to a `QUIC_CERTIFICATE_HASH_STORE` struct.
|
||||
**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_CONTEXT**<br>0x00000004 | The *Certificate* parameter points to a `PCCERT_CONTEXT` (Windows specific) struct.
|
||||
**QUIC_SEC_CONFIG_FLAG_CERTIFICATE_FILE**<br>0x00000008 | The *Certificate* parameter points to a `QUIC_CERTIFICATE_FILE` struct.
|
||||
**QUIC_SEC_CONFIG_FLAG_ENABLE_OCSP**<br>0x000000010 | This option can be used in conjunction with the above, and enables the Online Certificate Status Protocol (OCSP).
|
||||
|
||||
`Certificate`
|
||||
|
||||
A pointer to a certificate configuration struct whos type is determined by the *Flags* field.
|
||||
|
||||
`Principal`
|
||||
|
||||
An optional pointer, to a null-terminated string that specifies the name of the principal whose credentials the security config will reference.
|
||||
|
||||
`Context`
|
||||
|
||||
The app context pointer to be passed back into the *CompletionHandler*.
|
||||
|
||||
`CompletionHandler`
|
||||
|
||||
A pointer to the app's callback handler to be executed when the security config creation has completed.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[SecConfigDelete](SecConfigDelete.md)<br>
|
|
@ -0,0 +1,27 @@
|
|||
SecConfigDelete function
|
||||
======
|
||||
|
||||
Deletes an existing security configuration.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_SEC_CONFIG_DELETE_FN)(
|
||||
_In_ _Pre_defensive_ QUIC_SEC_CONFIG* SecurityConfig
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[SecConfigCreate](SecConfigCreate.md)<br>
|
|
@ -0,0 +1,31 @@
|
|||
SessionClose function
|
||||
======
|
||||
|
||||
Closes an existing session.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_SESSION_CLOSE_FN)(
|
||||
_In_ _Pre_defensive_ __drv_freesMem(Mem)
|
||||
HQUIC Session
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Session`
|
||||
|
||||
The valid handle to an open session object.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[SessionOpen](SessionOpen.md)<br>
|
||||
[SessionShutdown](SessionShutdown.md)<br>
|
|
@ -0,0 +1,52 @@
|
|||
SessionOpen function
|
||||
======
|
||||
|
||||
Creates a new session.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_SESSION_OPEN_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Registration,
|
||||
_In_reads_z_(QUIC_MAX_ALPN_LENGTH)
|
||||
const char* Alpn, // Application-Layer Protocol Negotiation
|
||||
_In_opt_ void* Context,
|
||||
_Outptr_ _At_(*Session, __drv_allocatesMem(Mem)) _Pre_defensive_
|
||||
HQUIC* Session
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Registration`
|
||||
|
||||
The valid handle to an open registration object.
|
||||
|
||||
`Alpn`
|
||||
|
||||
A null-terminated string for the Application-Layer Protocol Negotiation (ALPN) TLS extension.
|
||||
|
||||
`Context`
|
||||
|
||||
The app context pointer to be associated with the session object.
|
||||
|
||||
`Connection`
|
||||
|
||||
On success, returns a handle to the newly opened session object.
|
||||
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[SessionClose](SessionClose.md)<br>
|
||||
[SessionShutdown](SessionShutdown.md)<br>
|
|
@ -0,0 +1,46 @@
|
|||
SessionShutdown function
|
||||
======
|
||||
|
||||
Starts the shutdown process for all connections in the session.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_SESSION_SHUTDOWN_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Session,
|
||||
_In_ QUIC_CONNECTION_SHUTDOWN_FLAGS Flags,
|
||||
_In_ _Pre_defensive_ QUIC_UINT62 ErrorCode // Application defined error code
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Session`
|
||||
|
||||
The valid handle to an open session object.
|
||||
|
||||
`Flags`
|
||||
|
||||
The flags that control the behavior of the shutdown.
|
||||
|
||||
Value | Meaning
|
||||
--- | ---
|
||||
**QUIC_CONNECTION_SHUTDOWN_FLAG_NONE**<br>0 | The connection is shutdown gracefully and informs the peer.
|
||||
**QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT**<br>1 | The connection is immediately shutdown without informing the peer.
|
||||
|
||||
`ErrorCode`
|
||||
|
||||
The 62-bit error code to indicate to the peer as the reason for the shutdown.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[SessionOpen](SessionOpen.md)<br>
|
||||
[SessionClose](SessionClose.md)<br>
|
||||
[ConnectionShutdown](ConnectionShutdown.md)<br>
|
|
@ -0,0 +1,42 @@
|
|||
SetCallbackHandler function
|
||||
======
|
||||
|
||||
Sets the application context and callback function pointer for the API object.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_SET_CALLBACK_HANDLER_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Handle,
|
||||
_In_ void* Handler,
|
||||
_In_opt_ void* Context
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Handle`
|
||||
|
||||
The valid handle to any API object that uses callback handlers. This includes handles to listener, connection and stream objects.
|
||||
|
||||
`Handler`
|
||||
|
||||
A new application callback handler to register with the API object.
|
||||
|
||||
`Context`
|
||||
|
||||
A new application context to register with the API object.
|
||||
|
||||
# Remarks
|
||||
|
||||
This function allows the app to set the application callback handler and context for the API object. The context can be later retrieved by a call to [GetContext](GetContext.md). It is also passed into all callback handler events for the object.
|
||||
|
||||
> **Important** There is no internal synchronization for this callback handler or context. If the app calls [GetContext](GetContext.md), [SetContext](SetContext.md) and/or **SetCallbackHandler** on different threads, it must provide for the necessary synchronization mechanisms.
|
||||
|
||||
# See Also
|
||||
|
||||
[GetContext](GetContext.md)<br>
|
||||
[SetContext](SetContext.md)<br>
|
|
@ -0,0 +1,37 @@
|
|||
SetContext function
|
||||
======
|
||||
|
||||
Sets the application context for the API object.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_SET_CONTEXT_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Handle,
|
||||
_In_opt_ void* Context
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Handle`
|
||||
|
||||
The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects.
|
||||
|
||||
`Context`
|
||||
|
||||
A new application context to register with the API object.
|
||||
|
||||
# Remarks
|
||||
|
||||
This function allows the app to set the application context for the API object. This context can be later retrieved by a call to [GetContext](GetContext.md). It is also passed into all callback handler events for the object.
|
||||
|
||||
> **Important** There is no internal synchronization for this context. If the app calls [GetContext](GetContext.md), **SetContext** and/or [SetCallbackHandler](SetCallbackHandler.md) on different threads, it must provide for the necessary synchronization mechanisms.
|
||||
|
||||
# See Also
|
||||
|
||||
[GetContext](GetContext.md)<br>
|
||||
[SetCallbackHandler](SetCallbackHandler.md)<br>
|
|
@ -0,0 +1,54 @@
|
|||
SetParam function
|
||||
======
|
||||
|
||||
Sets a parameter on an API object.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_SET_PARAM_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Handle,
|
||||
_In_ _Pre_defensive_ QUIC_PARAM_LEVEL Level,
|
||||
_In_ uint32_t Param,
|
||||
_In_ uint32_t BufferLength,
|
||||
_In_reads_bytes_(BufferLength)
|
||||
const void* Buffer
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
`Handle`
|
||||
|
||||
The valid handle to any API object. This includes handles to registration, session, listener, connection and stream objects.
|
||||
|
||||
`Level`
|
||||
|
||||
The level at which the parameter is defined (for example, `QUIC_PARAM_LEVEL_CONNECTION`).
|
||||
|
||||
`Param`
|
||||
|
||||
The parameter for which the value is to be set (for example, `QUIC_PARAM_CONN_IDLE_TIMEOUT`). The *Param* parameter must be a parameter defined within the specified *Level*, or behavior is undefined.
|
||||
|
||||
`BufferLength`
|
||||
|
||||
A pointer to the size, in bytes, of the *Buffer* buffer.
|
||||
|
||||
`Buffer`
|
||||
|
||||
A pointer to the buffer in which the value for the requested option is to be returned.
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[GetParam](GetParam.md)<br>
|
|
@ -0,0 +1,33 @@
|
|||
StreamClose function
|
||||
======
|
||||
|
||||
Closes an existing stream.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
void
|
||||
(QUIC_API * QUIC_STREAM_CLOSE_FN)(
|
||||
_In_ _Pre_defensive_ __drv_freesMem(Mem)
|
||||
HQUIC Stream
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[StreamOpen](StreamOpen.md)<br>
|
||||
[StreamStart](StreamStart.md)<br>
|
||||
[StreamShutdown](StreamShutdown.md)<br>
|
||||
[StreamSend](StreamSend.md)<br>
|
||||
[StreamReceiveComplete](StreamReceiveComplete.md)<br>
|
||||
[StreamReceiveSetEnabled](StreamReceiveSetEnabled.md)<br>
|
|
@ -0,0 +1,41 @@
|
|||
StreamOpen function
|
||||
======
|
||||
|
||||
Creates a new stream.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_STREAM_OPEN_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Connection,
|
||||
_In_ QUIC_STREAM_OPEN_FLAGS Flags,
|
||||
_In_ _Pre_defensive_ QUIC_STREAM_CALLBACK_HANDLER Handler,
|
||||
_In_opt_ void* Context,
|
||||
_Outptr_ _At_(*Stream, __drv_allocatesMem(Mem)) _Pre_defensive_
|
||||
HQUIC* Stream
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[StreamClose](StreamClose.md)<br>
|
||||
[StreamStart](StreamStart.md)<br>
|
||||
[StreamShutdown](StreamShutdown.md)<br>
|
||||
[StreamSend](StreamSend.md)<br>
|
||||
[StreamReceiveComplete](StreamReceiveComplete.md)<br>
|
||||
[StreamReceiveSetEnabled](StreamReceiveSetEnabled.md)<br>
|
|
@ -0,0 +1,37 @@
|
|||
StreamReceiveComplete function
|
||||
======
|
||||
|
||||
Completes a receive that was previously pended.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_STREAM_RECEIVE_COMPLETE_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Stream,
|
||||
_In_ uint64_t BufferLength
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[StreamOpen](StreamOpen.md)<br>
|
||||
[StreamClose](StreamClose.md)<br>
|
||||
[StreamStart](StreamStart.md)<br>
|
||||
[StreamShutdown](StreamShutdown.md)<br>
|
||||
[StreamSend](StreamSend.md)<br>
|
||||
[StreamReceiveSetEnabled](StreamReceiveSetEnabled.md)<br>
|
|
@ -0,0 +1,37 @@
|
|||
StreamReceiveSetEnabled function
|
||||
======
|
||||
|
||||
Enables or disables receive callbacks on a stream.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_STREAM_RECEIVE_SET_ENABLED_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Stream,
|
||||
_In_ BOOLEAN IsEnabled
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[StreamOpen](StreamOpen.md)<br>
|
||||
[StreamClose](StreamClose.md)<br>
|
||||
[StreamStart](StreamStart.md)<br>
|
||||
[StreamShutdown](StreamShutdown.md)<br>
|
||||
[StreamSend](StreamSend.md)<br>
|
||||
[StreamReceiveComplete](StreamReceiveComplete.md)<br>
|
|
@ -0,0 +1,41 @@
|
|||
StreamSend function
|
||||
======
|
||||
|
||||
Queues app data to be sent on a stream.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_STREAM_SEND_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Stream,
|
||||
_In_reads_(BufferCount) _Pre_defensive_
|
||||
const QUIC_BUFFER* const Buffers,
|
||||
_In_ uint32_t BufferCount,
|
||||
_In_ QUIC_SEND_FLAGS Flags,
|
||||
_In_opt_ void* ClientSendContext
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[StreamOpen](StreamOpen.md)<br>
|
||||
[StreamClose](StreamClose.md)<br>
|
||||
[StreamStart](StreamStart.md)<br>
|
||||
[StreamShutdown](StreamShutdown.md)<br>
|
||||
[StreamReceiveComplete](StreamReceiveComplete.md)<br>
|
||||
[StreamReceiveSetEnabled](StreamReceiveSetEnabled.md)<br>
|
|
@ -0,0 +1,38 @@
|
|||
StreamShutdown function
|
||||
======
|
||||
|
||||
Starts the shutdown process on a stream.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(DISPATCH_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_STREAM_SHUTDOWN_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Stream,
|
||||
_In_ QUIC_STREAM_SHUTDOWN_FLAGS Flags,
|
||||
_In_ _Pre_defensive_ QUIC_UINT62 ErrorCode // Application defined error code
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[StreamOpen](StreamOpen.md)<br>
|
||||
[StreamClose](StreamClose.md)<br>
|
||||
[StreamStart](StreamStart.md)<br>
|
||||
[StreamSend](StreamSend.md)<br>
|
||||
[StreamReceiveComplete](StreamReceiveComplete.md)<br>
|
||||
[StreamReceiveSetEnabled](StreamReceiveSetEnabled.md)<br>
|
|
@ -0,0 +1,37 @@
|
|||
StreamStart function
|
||||
======
|
||||
|
||||
Assigns an ID and starts processing the stream.
|
||||
|
||||
# Syntax
|
||||
|
||||
```C
|
||||
typedef
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
QUIC_STATUS
|
||||
(QUIC_API * QUIC_STREAM_START_FN)(
|
||||
_In_ _Pre_defensive_ HQUIC Stream,
|
||||
_In_ QUIC_STREAM_START_FLAGS Flags
|
||||
);
|
||||
```
|
||||
|
||||
# Parameters
|
||||
|
||||
**TODO**
|
||||
|
||||
# Return Value
|
||||
|
||||
The function returns a [QUIC_STATUS](../v0/QUIC_STATUS.md). The app may use `QUIC_FAILED` or `QUIC_SUCCEEDED` to determine if the function failed or succeeded.
|
||||
|
||||
# Remarks
|
||||
|
||||
**TODO**
|
||||
|
||||
# See Also
|
||||
|
||||
[StreamOpen](StreamOpen.md)<br>
|
||||
[StreamClose](StreamClose.md)<br>
|
||||
[StreamShutdown](StreamShutdown.md)<br>
|
||||
[StreamSend](StreamSend.md)<br>
|
||||
[StreamReceiveComplete](StreamReceiveComplete.md)<br>
|
||||
[StreamReceiveSetEnabled](StreamReceiveSetEnabled.md)<br>
|
182
inc/msquic.h
182
inc/msquic.h
|
@ -8,187 +8,7 @@ Abstract:
|
|||
Declarations for the MsQuic API, which enables applications and drivers to
|
||||
create QUIC connections as a client or server.
|
||||
|
||||
-=---=--=-
|
||||
Terminology:
|
||||
-=---=--=-
|
||||
|
||||
app - the application or driver that is calling into MsQuic.
|
||||
client - the app that initiates a connection.
|
||||
server - the app that listens until it receives a connection request from a
|
||||
peer.
|
||||
|
||||
-=---=--=-
|
||||
Handles:
|
||||
-=---=--=-
|
||||
|
||||
A handle is an API context pointer for the app to hold and pass to API
|
||||
functions. A handle represents a registration, session, listener, connection
|
||||
or stream. When an inbound connection is accepted by a listener, a handle is
|
||||
created for the new connection and given to the client via its
|
||||
QUIC_LISTENER_CALLBACK; otherwise handles are created by SessionOpen,
|
||||
ListenerOpen, ConnectionOpen or StreamOpen. A handle is closed with
|
||||
SessionClose, ListenerClose, ConnectionClose or StreamClose as appropriate.
|
||||
|
||||
-=---=--=---=-
|
||||
App contexts:
|
||||
-=---=--=---=-
|
||||
|
||||
The app can associate a context pointer with a handle by calling SetContext
|
||||
(or disassociate a previously associated context pointer by passing NULL
|
||||
instead of a valid pointer). This context pointer is provided in all event
|
||||
callbacks for that handle.
|
||||
|
||||
-=---=--=---=--=-
|
||||
High-level usage:
|
||||
-=---=--=---=--=-
|
||||
|
||||
Using the library:
|
||||
|
||||
There is no explicit start/stop API for this library. Each API function
|
||||
table has a reference on the QUIC library: the library is initialized when
|
||||
the first call to MsQuicOpen succeeds and uninitialized when the last call
|
||||
to MsQuicClose completes. An app should therefore beware of repeatedly
|
||||
calling MsQuicOpen and MsQuicClose, as library setup/cleanup can be
|
||||
expensive.
|
||||
|
||||
Each call to MsQuicOpen takes a version on input and returns the version
|
||||
specific API function table. This function table is used for calling the
|
||||
rest of the API functions.
|
||||
|
||||
Creating a registration:
|
||||
|
||||
Generally, each app only needs a single registration. The registration
|
||||
represents the execution context where all logic for the app's connections
|
||||
run. The library will create a number of worker threads for each
|
||||
registration, shared for all the connections.
|
||||
|
||||
Creating sessions:
|
||||
|
||||
An app must create a session before it can create any listeners or
|
||||
connections. Each session maintains certain transport and platform state
|
||||
common to all child handles. Primarily, this consists of the ALPN string
|
||||
used for the connection handshakes and TLS state used for session resumption.
|
||||
On Windows platforms it also inherits the Silo and Network Compartment ID
|
||||
from the thread that creates it.
|
||||
|
||||
Connecting to peers:
|
||||
|
||||
A server creates a listener, providing an event handler, and calls
|
||||
ListenerStart to make it start listening. Each time a connection request is
|
||||
received from a peer, a NEW_CONNECTION event is indicated to the app. If
|
||||
accepted, the app must either return success and set the security config or
|
||||
return pending and set the security config at a later time. In both of these
|
||||
cases, the app now owns the connection and may do whatever it wishes with it,
|
||||
including closing it, at any time. If the connection isn't accepted, the app
|
||||
must return an error or success and not set the security config. In this
|
||||
case, the app MUST NOT close the connection handle. For accepted connections,
|
||||
the app MUST register an event handler for the connection before this event
|
||||
callback returns.
|
||||
|
||||
A client initiates a connection by creating a connection object with an
|
||||
event handler with ConnectionOpen and calling ConnectionStart. Once the
|
||||
connection handshake is finished, the event handler is given a CONNECTED
|
||||
event to indicate that the connection is ready (if the handshake fails, a
|
||||
SHUTDOWN_COMPLETE event is indicated instead).
|
||||
|
||||
Connection lifetime:
|
||||
|
||||
Once an app has a connection handle it may call any function on it until it
|
||||
calls ConnectionClose, which effectively frees the connection object. Once
|
||||
the function returns, the app is guaranteed not to get any future callbacks
|
||||
for that connection.
|
||||
|
||||
The app initiates the shutdown process by calling ConnectionShutdown on the
|
||||
connection. This immediately terminates all other work on the connection
|
||||
and indicates the state to the peer. It also implicitly triggers the
|
||||
shutdown process on all child streams. The peer gets the SHUTDOWN_INITIATED_BY_PEER
|
||||
event with the error code that was passed into ConnectionShutdown. Once the
|
||||
shutdown process has completed, both sides will get the SHUTDOWN_COMPLETE
|
||||
event.
|
||||
|
||||
In certain cases, such as idle or being disconnected, the transport itself
|
||||
may initiate the shutdown of the connection. In this case the app (on both
|
||||
sides) will get the SHUTDOWN_INITIATED_BY_TRANSPORT_TRANSPORT event with a
|
||||
status code indicating why the shutdown was started. Again, once the
|
||||
shutdown process has completed, the app will get the SHUTDOWN_COMPLETE event.
|
||||
|
||||
The SHUTDOWN_COMPLETE event is guaranteed to be indicated for every
|
||||
connection as the last event.
|
||||
|
||||
Creating and using streams:
|
||||
|
||||
In order to send and receive data over a QUIC connection, the app uses
|
||||
streams, which are independent data channels associated with that connection.
|
||||
Streams are either opened by the peer and subsequently indicated in
|
||||
PEER_STREAM_STARTED events, or created by local calls to StreamOpen.
|
||||
|
||||
Once a stream is open, data is sent on the stream by calls to StreamSend
|
||||
and received via RECEIVE events given to its event handler.
|
||||
|
||||
Stream lifetime:
|
||||
|
||||
A stream is closed by a call to StreamClose, preceded optionally by a call
|
||||
to StreamShutdown to gracefully close the stream. The stream can be shut
|
||||
down in one direction or the other in separate calls to StreamShutdown if
|
||||
desired (this behavior can be used to request that the peer stop sending any
|
||||
more data on the stream but continue sending data).
|
||||
|
||||
Similar to the connection, the SHUTDOWN_COMPLETE event is guaranteed to
|
||||
be indicated for every stream as the last event. The SEND_SHUTDOWN_COMPLETE
|
||||
event is also guaranteed to be indicated for every stream that has a
|
||||
send path (bidirection and local unidirectional streams).
|
||||
|
||||
The PEER_SEND_SHUTDOWN, PEER_SEND_ABORTED and PEER_RECEIVE_ABORTED events
|
||||
only occur if the peer explicitly performs those operations on the stream. A
|
||||
stream can be shut down implicitly if the connection is shut down while
|
||||
streams are still open. In this case, there are no explicit peer shutdown
|
||||
events on the stream.
|
||||
|
||||
Receiving data:
|
||||
|
||||
Stream data is indicated via the RECEIVE event. Receive indications can be
|
||||
completed synchronously (by returning QUIC_STATUS_SUCCESS/QUIC_STATUS_CONTINUE)
|
||||
or asynchronously (by returning QUIC_STATUS_PENDING and later calling
|
||||
StreamReceiveComplete). The app must not return any status other than
|
||||
QUIC_STATUS_SUCCESS, QUIC_STATUS_CONTINUE, or QUIC_STATUS_PENDING. If the
|
||||
indicated data results in an application layer error, the app should then
|
||||
call StreamShutdown with an appropriate error.
|
||||
|
||||
The number of bytes is reported in the TotalBufferLength field, which can be
|
||||
reduced by the app to partially accept the indication. If an indication is
|
||||
accepted partially with QUIC_STATUS_SUCCESS, indications are paused until the
|
||||
app calls StreamReceiveSetEnabled with IsEnabled = TRUE (this behavior
|
||||
can be used by the app to apply backpressure on the stream). If an indication
|
||||
is accepted partially with QUIC_STATUS_CONTINUE, indications will continue
|
||||
to be made.
|
||||
|
||||
Note: An asynchronous partial acceptance always results in indications being
|
||||
paused- there is no status parameter for StreamReceiveComplete, so
|
||||
QUIC_STATUS_CONTINUE cannot be passed.
|
||||
|
||||
Sending data:
|
||||
|
||||
For optimum bulk send performance, an app needs to keep an appropriate
|
||||
number of bytes posted in send requests. This ideal buffer size is dependent
|
||||
on the network, and represents the ideal sum in bytes of all concurrent send
|
||||
requests posted on the connection.
|
||||
|
||||
By default, MsQuic buffers send requests and completes them automatically,
|
||||
and dynamically sets its internal buffer size to maintain good throughput.
|
||||
The app can therefore keep a single send request posted on a stream, and
|
||||
post another request each time the previous request is completed, and
|
||||
performance will be good.
|
||||
|
||||
Some apps prefer to turn off MsQuic's internal buffering. This can be done
|
||||
by setting the QUIC_PARAM_CONN_SEND_BUFFERING option to FALSE. When
|
||||
buffering is turned off, each send request is completed only when all the
|
||||
bytes in the request are acknowledged by the peer. An app that turns off
|
||||
send buffering should query QUIC_PARAM_STREAM_IDEAL_SEND_BUFFER_SIZE after
|
||||
creating a stream and handle QUIC_STREAM_EVENT_IDEAL_SEND_BUFFER_SIZE for
|
||||
updates to the ideal send buffer size, and keep at least that many bytes
|
||||
posted for the stream. The data should be posted in multiple send requests
|
||||
on each stream, rather than all in one request. Turning off buffering is
|
||||
error-prone and should be avoided if possible.
|
||||
For more detailed information, see ../docs/API.md
|
||||
|
||||
Supported Platforms:
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ GetTlsIdentifier(
|
|||
#ifdef _KERNEL_MODE
|
||||
#define NtStatusToQuicStatus(x) (x)
|
||||
#else
|
||||
#define NtStatusToQuicStatus(x) HRESULT_FROM_WIN32(RtlNtStatusToDosError(x)) // TODO - Plain cast?
|
||||
#define NtStatusToQuicStatus(x) HRESULT_FROM_WIN32(RtlNtStatusToDosError(x))
|
||||
#endif
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
|
@ -1737,9 +1737,6 @@ QuicTlsWriteDataToSchannel(
|
|||
if (MissingBuffer != NULL && MissingBuffer->cbBuffer != 0) {
|
||||
LogInfo("[ tls][%p][%c] TLS message missing %u bytes of data.",
|
||||
TlsContext, GetTlsIdentifier(TlsContext), MissingBuffer->cbBuffer);
|
||||
//
|
||||
// TODO: Indicate this up and use it?
|
||||
//
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -89,10 +89,7 @@ DrillPacketDescriptor::write(
|
|||
} else {
|
||||
PacketBuffer.push_back((uint8_t) DestCID.size());
|
||||
}
|
||||
for (auto cidByte : DestCID)
|
||||
{
|
||||
PacketBuffer.push_back(cidByte);
|
||||
}
|
||||
PacketBuffer.insert(PacketBuffer.end(), DestCID.begin(), DestCID.end());
|
||||
|
||||
//
|
||||
// Copy Source CID.
|
||||
|
@ -102,11 +99,7 @@ DrillPacketDescriptor::write(
|
|||
} else {
|
||||
PacketBuffer.push_back((uint8_t) SourceCID.size());
|
||||
}
|
||||
for (auto cidByte : SourceCID)
|
||||
{
|
||||
PacketBuffer.push_back(cidByte);
|
||||
}
|
||||
|
||||
PacketBuffer.insert(PacketBuffer.end(), SourceCID.begin(), SourceCID.end());
|
||||
|
||||
//
|
||||
// TODO: Do type-specific stuff here.
|
||||
|
@ -138,18 +131,12 @@ DrillInitialPacketDescriptor::write(
|
|||
} else {
|
||||
EncodedTokenLength = QuicDrillEncodeQuicVarInt(Token.size());
|
||||
}
|
||||
for (auto tokenLenByte : EncodedTokenLength)
|
||||
{
|
||||
PacketBuffer.push_back(tokenLenByte);
|
||||
}
|
||||
PacketBuffer.insert(PacketBuffer.end(), EncodedTokenLength.begin(), EncodedTokenLength.end());
|
||||
|
||||
CalculatedPacketLength += EncodedTokenLength.size();
|
||||
|
||||
if (Token.size()) {
|
||||
for (auto tokenByte : Token)
|
||||
{
|
||||
PacketBuffer.push_back(tokenByte);
|
||||
}
|
||||
PacketBuffer.insert(PacketBuffer.end(), Token.begin(), Token.end());
|
||||
CalculatedPacketLength += Token.size();
|
||||
}
|
||||
|
||||
|
@ -189,18 +176,12 @@ DrillInitialPacketDescriptor::write(
|
|||
} else {
|
||||
PacketLengthBuffer = QuicDrillEncodeQuicVarInt(CalculatedPacketLength);
|
||||
}
|
||||
for (auto packetLenByte : PacketLengthBuffer)
|
||||
{
|
||||
PacketBuffer.push_back(packetLenByte);
|
||||
}
|
||||
PacketBuffer.insert(PacketBuffer.end(), PacketLengthBuffer.begin(), PacketLengthBuffer.end());
|
||||
|
||||
//
|
||||
// Write packet number.
|
||||
//
|
||||
for (auto packetNumByte : PacketNumberBuffer)
|
||||
{
|
||||
PacketBuffer.push_back(packetNumByte);
|
||||
}
|
||||
PacketBuffer.insert(PacketBuffer.end(), PacketNumberBuffer.begin(), PacketNumberBuffer.end());
|
||||
|
||||
//
|
||||
// TODO: Write payload here.
|
||||
|
|
|
@ -19,6 +19,16 @@ class DrillBuffer : public Rtl::KArray<uint8_t>
|
|||
}
|
||||
|
||||
size_t size() { return count(); }
|
||||
|
||||
void
|
||||
insert(
|
||||
_In_ const iterator &dest,
|
||||
_In_ const const_iterator &start,
|
||||
_In_ const const_iterator &end
|
||||
)
|
||||
{
|
||||
QUIC_FRE_ASSERT(insertAt(dest, start, end));
|
||||
}
|
||||
};
|
||||
#else
|
||||
using DrillBuffer = std::vector<uint8_t>;
|
||||
|
|
Загрузка…
Ссылка в новой задаче