Lots of documentation changes and some fairly minor bug fixes and clean up.
This commit is contained in:
Nick Banks 2019-11-27 12:08:15 -08:00 коммит произвёл GitHub
Родитель 69a2cf9d7c
Коммит ddb0055425
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
49 изменённых файлов: 1707 добавлений и 357 удалений

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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 didnt 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 its 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).

16
docs/Streams.md Normal file
Просмотреть файл

@ -0,0 +1,16 @@
Using Streams
======
**TODO**
# Sending
**TODO**
# Receiving
**TODO**
# Shutting Down
**TODO**

Двоичные данные
docs/images/api_objects.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.7 KiB

30
docs/v0/MsQuicClose.md Normal file
Просмотреть файл

@ -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>

64
docs/v0/MsQuicOpen.md Normal file
Просмотреть файл

@ -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>

53
docs/v0/QUIC_STATUS.md Normal file
Просмотреть файл

@ -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>

51
docs/v1/ConnectionOpen.md Normal file
Просмотреть файл

@ -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>

36
docs/v1/GetContext.md Normal file
Просмотреть файл

@ -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>

54
docs/v1/GetParam.md Normal file
Просмотреть файл

@ -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>

30
docs/v1/ListenerClose.md Normal file
Просмотреть файл

@ -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>

37
docs/v1/ListenerOpen.md Normal file
Просмотреть файл

@ -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>

34
docs/v1/ListenerStart.md Normal file
Просмотреть файл

@ -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>

29
docs/v1/ListenerStop.md Normal file
Просмотреть файл

@ -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>

167
docs/v1/QUIC_API_V1.md Normal file
Просмотреть файл

@ -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>

31
docs/v1/SessionClose.md Normal file
Просмотреть файл

@ -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>

52
docs/v1/SessionOpen.md Normal file
Просмотреть файл

@ -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>

37
docs/v1/SetContext.md Normal file
Просмотреть файл

@ -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>

54
docs/v1/SetParam.md Normal file
Просмотреть файл

@ -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>

33
docs/v1/StreamClose.md Normal file
Просмотреть файл

@ -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>

41
docs/v1/StreamOpen.md Normal file
Просмотреть файл

@ -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>

41
docs/v1/StreamSend.md Normal file
Просмотреть файл

@ -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>

38
docs/v1/StreamShutdown.md Normal file
Просмотреть файл

@ -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>

37
docs/v1/StreamStart.md Normal file
Просмотреть файл

@ -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>

Просмотреть файл

@ -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>;