quic transport rfc
[toc]
2 Stream
2.1 Stream Identifiers
Streams are identified by an unsigned 62-bit integer, referred to as
the Stream ID. Stream IDs are encoded as a variable-length integer. The least significant two bits of the Stream ID
are used to identify the type of stream (unidirectional or
bidirectional) and the initiator of the stream.
The least significant bit (0x1) of the Stream ID identifies the
initiator of the stream. Clients initiate even-numbered streams
(those with the least significant bit set to 0); servers initiate
odd-numbered streams (with the bit set to 1).
The second least significant bit (0x2) of the Stream ID
differentiates between unidirectional streams and bidirectional
streams. Unidirectional streams always have this bit set to 1 and
bidirectional streams have this bit set to 0.
+----------+----------------------------------+
| Low Bits | Stream Type |
+----------+----------------------------------+
| 0x0 | Client-Initiated, Bidirectional |
| 0x1 | Server-Initiated, Bidirectional |
| 0x2 | Client-Initiated, Unidirectional |
| 0x3 | Server-Initiated, Unidirectional |
+----------+----------------------------------+
A QUIC endpoint MUST NOT reuse a Stream ID.
2.2 Stream Concurrency
QUIC allows for an arbitrary number of streams to operate
concurrently. An endpoint limits the number of concurrently active
incoming streams by limiting the maximum stream ID.
The maximum stream ID is specific to each endpoint and applies only
to the peer that receives the setting.
A receiver MUST ignore any MAX_STREAM_ID frame that does not increase the maximum stream ID.
2.3 Sending and Receiving Data
Endpoints uses streams to send and receive data. Endpoints send
STREAM frames, which encapsulate data for a stream.
2.4 Stream Prioritization
QUIC does not provide frames for exchanging prioritization
information. Instead it relies on receiving priority information
from the application that uses QUIC.
3 Stream States: Life of a Stream
3.1 Send Stream States
The sending part of stream that the endpoint initiates (types 0 and 2
for clients, 1 and 3 for servers) is opened by the application or
application protocol.
- The "Ready" state represents a newly created
stream that is able to accept data from the application. Stream data
might be buffered in this state in preparation for sending. - Sending the first STREAM or STREAM_BLOCKED frame causes a send stream
to enter the "Send" state. In the "Send" state, an endpoint transmits data in STREAM frames. - After the application indicates that stream data is complete and a
STREAM frame containing the FIN bit is sent, the send stream enters
the "Data Sent" state. - Once all stream data has been successfully acknowledged, the send
stream enters the "Data Recvd" state, which is a terminal state. - From any of the "Ready", "Send", or "Data Sent" states, an
application can signal that it wishes to abandon transmission of
stream data. Similarly, the endpoint might receive a STOP_SENDING
frame from its peer. In either case, the endpoint sends a RST_STREAM
frame, which causes the stream to enter the "Reset Sent" state. - Once a packet containing a RST_STREAM has been acknowledged, the send
stream enters the "Reset Recvd" state, which is a terminal state.
3.2 Receive Stream States
The receiving part of a stream initiated by a peer (types 1 and 3 for
a client, or 0 and 2 for a server) are created when the first STREAM,
STREAM_BLOCKED, RST_STREAM, or MAX_STREAM_DATA (bidirectional only,
see below) is received for that stream.
3.3 Permitted Frame Types
The sender of a stream sends just three frame types that affect the
state of a stream at either sender or receiver: STREAM, STREAM_BLOCKED, and RST_STREAM.
The receiver of a stream sends MAX_STREAM_DATA and STOP_SENDING frames.
3.4 Bidirectional Stream States
image3.5 Solicited State Transitions
If an endpoint is no longer interested in the data it is receiving on
a stream, it MAY send a STOP_SENDING frame identifying that stream to
prompt closure of the stream in the opposite direction. This
typically indicates that the receiving application is no longer
reading data it receives from the stream, but is not a guarantee that
incoming data will be ignored.
4 Flow Control
A receiver advertises the number of octets it is prepared
to receive on a given stream and for the entire connection. This
leads to two levels of flow control in QUIC:
- Stream flow control, which prevents a single stream from consuming
the entire receive buffer for a connection. - Connection flow control, which prevents senders from exceeding a
receiver’s buffer capacity for the connection, and A data receiver sets initial credits for all streams by sending transport parameters during the handshake.
A data receiver sends MAX_STREAM_DATA or MAX_DATA frames to the
sender to advertise additional credit.
- MAX_STREAM_DATA frames send the maximum absolute byte offset of a stream,
- MAX_DATA frames send the maximum of the sum of the absolute byte offsets of all streams.
4.1 Handling of Stream Cancellation
the RST_STREAM frame (Section 19.2) includes the
largest offset of data sent on the stream. On receiving a RST_STREAM
frame, a receiver definitively knows how many bytes were sent on that
stream before the RST_STREAM frame, and the receiver MUST use the
final offset to account for all bytes sent on the stream in its
connection level flow controller.
4.2 Data Limit Increments
A receiver MAY use an autotuning mechanism to tune the frequency and
amount that it increases data limits based on a round-trip time
estimate and the rate at which the receiving application consumes
data, similar to common TCP implementations.
4.3 Stream Final Offset
The final offset is the count of the number of octets that are
transmitted on a stream. For a stream that is reset, the final
offset is carried explicitly in a RST_STREAM frame. Otherwise, the
final offset is the offset of the end of the data carried in a STREAM
frame marked with a FIN flag, or 0 in the case of incoming
unidirectional streams.
4.4 Flow Control for Cryptographic Handshake
QUIC relies on the cryptographic protocol
implementation to avoid excessive buffering of data.
4.5 Stream Limit Increment
An endpoint limits the number of concurrently active incoming streams
by limiting the maximum stream ID.
An initial value is set in the transport parameters and is subsequently increased by MAX_STREAM_ID frames.
5 Connections
A QUIC connection is a single conversation between two QUIC endpoints.
QUIC’s connection establishment combines version
negotiation with the cryptographic and transport handshakes to reduce
connection establishment latency.
5.1 Connection ID
Each connection possesses a set of connection identifiers, or
connection IDs, each of which can be identify the connection.Connection IDs are independently selected by endpoints; each endpoint
selects the connection IDs that its peer uses.
5.1.1 Issuing Connection IDs
Each Connection ID has an associated sequence number to assist in
deduplicating messages. The sequence number of
the initial connection ID is 0. If the preferred_address transport
parameter is sent, the sequence number of the supplied connection ID
is 1.
Additional connection IDs are communicated to the peer using
NEW_CONNECTION_ID frames. The sequence number on
each newly-issued connection ID MUST increase by 1.
5.1.2 Consuming and Retiring Connection IDs
An endpoint can change the connection ID it uses for a peer to
another available one at any time during the connection.
An endpoint maintains a set of connection IDs received from its peer,
any of which it can use when sending packets. When the endpoint
wishes to remove a connection ID from use, it sends a
RETIRE_CONNECTION_ID frame to its peer, indicating that the peer
might bring a new connection ID into circulation using the
NEW_CONNECTION_ID frame.
As discussed in Section 9.5, each connection ID MUST be used on
packets sent from only one local address. An endpoint that migrates
away from a local address SHOULD retire all connection IDs used on
that address once it no longer plans to use that address.
5.2 Matching Packets to Connections
Incoming packets are classified on receipt. Packets can either be
associated with an existing connection, or - for servers -
potentially create a new connection.
5.2.1 Client Packet Handling
Valid packets sent to clients always include a Destination Connection
ID that matches a value the client selects. Clients that choose to
receive zero-length connection IDs can use the address/port tuple to
identify a connection. Packets that don’t match an existing
connection are discarded.
5.2.2 Server Packet Handling
- If a server receives a packet that has an unsupported version, but
the packet is sufficiently large to initiate a new connection for any
version supported by the server, it SHOULD send a Version Negotiation
packet. - Packets with a supported version, or no version field, are matched to
a connection using the connection ID or - for packets with zerolength connection IDs - the address tuple. If the packet doesn’t
match an existing connection, the server continues below.- If the packet is an Initial packet fully conforming with the
specification, the server proceeds with the handshake. - If a server isn’t currently accepting any new connections, it SHOULD
send an Initial packet containing a CONNECTION_CLOSE frame with error
code SERVER_BUSY. - If the packet is a 0-RTT packet, the server MAY buffer a limited
number of these packets in anticipation of a late-arriving Initial
Packet.
- If the packet is an Initial packet fully conforming with the
- Servers MUST drop incoming packets under all other circumstances.
6 Version Negotiation
Version negotiation ensures that client and server agree to a QUIC
version that is mutually supported.
6.1 Sending Version Negotiation Packets
If the version selected by the client is not acceptable to the
server, the server responds with a Version Negotiation packet. This includes a list of versions that the server will accept.
6.2 Handling Version Negotiation Packets
The client selects an acceptable protocol version from the list
provided by the server. The client then attempts to create a connection using that version.
The client MUST use the long header format and include its selected
version on all packets until it has 1-RTT keys and it has received a
packet from the server which is not a Version Negotiation packet.
6.3 Using Reserved Versions
7 Cryptographic and Transport Handshake
QUIC relies on a combined cryptographic and transport handshake to
minimize connection establishment latency.
7.1 Example Handshake Flows
imageimage
7.2 Negotiating Connection IDs
During the handshake, packets with the long header are
used to establish the connection ID that each endpoint uses. Each
endpoint uses the Source Connection ID field to specify the
connection ID that is used in the Destination Connection ID field of
packets being sent to them. Upon receiving a packet, each endpoint
sets the Destination Connection ID it sends to match the value of the
Source Connection ID that they receive.
7.3 Transport Parameters
During connection establishment, both endpoints make authenticated
declarations of their transport parameters. These declarations are
made unilaterally by each endpoint. Endpoints are required to comply
with the restrictions implied by these parameters; the description of
each parameter includes rules for its handling.
7.3.1 Values of Transport Parameters for 0-RTT
A client that attempts to send 0-RTT data MUST remember the transport
parameters used by the server. The transport parameters that the
server advertises during connection establishment apply to all
connections that are resumed using the keying material established
during that handshake.
7.3.2 New Transport Parameters
New transport parameters can be used to negotiate new protocol behavior.
7.3.3 Version Negotiation Validation
To protect against QUIC version downgrade attacks, the transport parameters include three fields that encode version information. These parameters are used to retroactively authenticate the choice of version.
8 Address Validation
Address validation is used by QUIC to avoid being used for a traffic
amplification attack.
8.1 Address Validation During Connection Establishment
Connection establishment implicitly provides address validation for
both endpoints. In particular, receipt of a packet protected with
Handshake keys confirms that the client received the Initial packet
from the server. Once the server has successfully processed a
Handshake packet from the client, it can consider the client address
to have been validated.
8.1.1 Address Validation using Retry Packets
QUIC uses token-based address validation during connection
establishment.
Upon receiving the client’s Initial packet, the server can request address validation by sending a Retry packet containing a token. This token is repeated by the client in an Initial packet after it receives the Retry packet. In response to receiving a token in an Initial packet, a server can either abort the connection or permit it to proceed.
image8.1.2 Address Validation for Future Connections
A server MAY provide clients with an address validation token during
one connection that can be used on a subsequent connection.
The server uses the NEW_TOKEN frame to provide the
client with an address validation token that can be used to validate
future connections. The client may then use this token to validate
future connections by including it in the Initial packet’s header.
8.1.3 Address Validation Token Integrity
An address validation token MUST be difficult to guess. Including a
large enough random value in the token would be sufficient, but this
depends on the server remembering the value it sends to clients.
A token could include information about the claimed client address (IP
and port), a timestamp, and any other supplementary information the
server will need to validate the token in the future.
8.2 Path Validation
Path validation is used during connection migration by the migrating endpoint to verify reachability of a peer from a new local address.
Path validation can be used at any time by either endpoint.
8.3 Initiating Path Validation
To initiate path validation, an endpoint sends a PATH_CHALLENGE frame
containing a random payload on the path to be validated.
8.4 Path Validation Responses
On receiving a PATH_CHALLENGE frame, an endpoint MUST respond
immediately by echoing the data contained in the PATH_CHALLENGE frame
in a PATH_RESPONSE frame.
8.5 Successful Path Validation
A new address is considered valid when a PATH_RESPONSE frame is
received containing data that was sent in a previous PATH_CHALLENGE.
For path validation to be successful, a PATH_RESPONSE frame MUST be
received from the same remote address to which the corresponding
PATH_CHALLENGE was sent.
8.6 Failed Path Validation
Path validation only fails when the endpoint attempting to validate
the path abandons its attempt to validate the path.
9 Connection Migration
9.1 Probing a New Path
An endpoint MAY probe for peer reachability from a new local address
using path validation prior to migrating the connection to the new local address.
9.2 Initiating Connection Migration
A migrating endpoint can send to its peer
knowing that the peer is willing to receive at the peer’s current
address. Thus an endpoint can migrate to a new local address without
first validating the peer’s address.
9.3 Responding to Connection Migration
Receiving a packet from a new peer address containing a non-probing
frame indicates that the peer has migrated to that address.
In response to such a packet, an endpoint MUST start sending
subsequent packets to the new peer address and MUST initiate path
validation to verify the peer’s ownership of the unvalidated address.
9.3.1 Handling Address Spoofing by a Peer
An endpoint is required to validate a
peer’s new address to confirm the peer’s possession of the new
address. Until a peer’s address is deemed valid, an endpoint MUST
limit the rate at which it sends data to this address. The endpoint
MUST NOT send more than a minimum congestion window’s worth of data
per estimated round-trip time.
9.3.2 Handling Address Spoofing by an On-path Attacker
An on-path attacker could cause a spurious connection migration by
copying and forwarding a packet with a spoofed address such that it
arrives before the original packet. The packet with the spoofed
address will be seen to come from a migrating connection, and the
original packet will be seen as a duplicate and dropped.
To protect the connection from failing due to such a spurious
migration, an endpoint MUST revert to using the last validated peer
address when validation of a new peer address fails.
9.4 Loss Detection and Congestion Control
The capacity available on the new path might not be the same as the
old path. Packets sent on the old path SHOULD NOT contribute to
congestion control or RTT estimation for the new path.
A sender can make exceptions for probe packets so that their loss detection is
independent and does not unduly cause the congestion controller to
reduce its sending rate. An endpoint might set a separate timer when
a PATH_CHALLENGE is sent, which is cancelled when the corresponding
PATH_RESPONSE is received. If the timer fires before the
PATH_RESPONSE is received, the endpoint might send a new
PATH_CHALLENGE, and restart the timer for a longer period of time.
9.5 Privacy Implications of Connection Migration
An endpoint that moves between networks might not wish to have their
activity correlated by any entity other than their peer, so different
connection IDs are used when sending from different local addresses,
as discussed in Section 5.1. For this to be effective endpoints need
to ensure that connections IDs they provide cannot be linked by any
other entity.
The goal here is to ensure that packets
sent on different paths cannot be correlated. To fulfill this
privacy requirement, endpoints that initiate migration and use
connection IDs with length greater than zero SHOULD provide their
peers with new connection IDs before migration.
9.6 Server’s Preferred Address
QUIC allows servers to accept connections on one IP address and
attempt to transfer these connections to a more preferred address
shortly after the handshake.
9.6.1 Communicating A Preferred Address
A server conveys a preferred address by including the
preferred_address transport parameter in the TLS handshake.
Once the handshake is finished, the client SHOULD initiate path
validation of the server’s preferred address using
the connection ID provided in the preferred_address transport parameter.
9.6.2 Responding to Connection Migration
A server might receive a packet addressed to its preferred IP address
at any time after it accepts a connection. If this packet contains a
PATH_CHALLENGE frame, the server sends a PATH_RESPONSE frame.
The server SHOULD also initiate path validation of the client using
its preferred address and the address from which it received the
client probe.
9.6.3 Interaction of Client Migration and Preferred Address
A client might need to perform a connection migration before it has
migrated to the server’s preferred address. In this case, the client
SHOULD perform path validation to both the original and preferred
server address from the client’s new address concurrently.
If path validation of the server’s preferred address succeeds, the
client MUST abandon validation of the original address and migrate to
using the server’s preferred address. If path validation of the
server’s preferred address fails but validation of the server’s
original address succeeds, the client MAY migrate to its new address
and continue sending to the server’s original address.
10. Connection Termination
Connections should remain open until they become idle for a prenegotiated period of time. A QUIC connection, once established, can
be terminated in one of three ways:
- idle timeout
- immediate close
- stateless reset
10.1 Closing and Draining Connection States
The closing and draining connection states exist to ensure that connections close cleanly and that delayed or reordered packets are properly discarded.
10.2 Idle Timeout
If the idle timeout is enabled, a connection that remains idle for
longer than the advertised idle timeout is closed.
10.3 Immediate Close
An endpoint sends a closing frame (CONNECTION_CLOSE or
APPLICATION_CLOSE) to terminate the connection immediately. Any
closing frame causes all streams to immediately become closed; open
streams can be assumed to be implicitly reset.
10.4 Stateless Reset
A stateless reset is provided as an option of last resort for an
endpoint that does not have access to the state of a connection.
10.4.1 Detecting a Stateless Reset
An endpoint detects a potential stateless reset when a packet with a
short header either cannot be decrypted or is marked as a duplicate
packet.
The endpoint then compares the last 16 octets of the packet
with the Stateless Reset Token provided by its peer.
If these values are identical, the endpoint MUST enter the draining
period and not send any further packets on this connection. If the
comparison fails, the packet can be discarded.
10.4.2 Calculating a Stateless Reset Token
The stateless reset token MUST be difficult to guess. In order to create a Stateless Reset Token, an endpoint could randomly generate a secret for every connection that it creates.
A single static key can be used across all connections to the same
endpoint by generating the proof using a second iteration of a
preimage-resistant function that takes a static key and the
connection ID chosen by the endpoint as input. An
endpoint could use HMAC (for example, HMAC(static_key,
connection_id)) or HKDF (for example, using the static key
as input keying material, with the connection ID as salt). The
output of this function is truncated to 16 octets to produce the
Stateless Reset Token for that connection.
10.4.3 Looping
A Stateless Reset might trigger the sending of a Stateless Reset in response, which could lead to infinite exchanges.
An endpoint MUST ensure that every Stateless Reset that it sends is
smaller than the packet which triggered it, unless it maintains state
sufficient to prevent looping. In the event of a loop, this results
in packets eventually being too small to trigger a response.
11 Error Handling
An endpoint that detects an error SHOULD signal the existence of that
error to its peer.
Both transport-level and application-level errors can affect an entire connection, while only application-level errors can be isolated to a single stream.
11.1 Connection Errors
Errors that result in the connection being unusable, such as an
obvious violation of protocol semantics or corruption of state that
affects an entire connection, MUST be signaled using a
CONNECTION_CLOSE or APPLICATION_CLOSE frame.
11.2 Stream Errors
If an application-level error affects a single stream, but otherwise leaves the connection in a recoverable state, the endpoint can send a RST_STREAM frame with an appropriate error code to terminate just the affected stream. RST_STREAM MUST be instigated by the application and MUST carry an application error code.
12 Packets and Frames
QUIC endpoints communicate by exchanging packets. Packets are carried in UDP datagrams and have confidentiality and integrity protection.
- Packets that carry the long header are Initial, Retry, Handshake, and 0-RTT Protected packets.
- Packets with the short header are designed for minimal overhead and are used after a connection is established.
- Version negotiation uses a packet with a special format.
12.1 Protected Packets
All QUIC packets except Version Negotiation and Retry packets use authenticated encryption with additional data (AEAD) to provide confidentiality and integrity protection.
- Initial packets:are protected using keys that are statically derived. It only exists to ensure that the sender of the packet is on the network path.
- All other packets are protected with keys derived from the cryptographic handshake. Packets protected with 0-RTT and 1-RTT keys are expected to have
confidentiality and data origin authentication; the cryptographic
handshake ensures that only the communicating endpoints receive the
corresponding keys.
12.2 Coalescing Packets
A sender can coalesce multiple QUIC packets into one UDP datagram.
Every QUIC packet that is coalesced into a single UDP datagram is
separate and complete. Though the values of some fields in the
packet header might be redundant, no fields are omitted. Retry packets, Version Negotiation packets, and packets with a short header cannot be followed by other packets in the same UDP datagram.
12.3 Packet Numbers
The packet number is an integer in the range 0 to 2^62-1.
This number is used in determining the cryptographic nonce for packet protection. Each endpoint maintains a separate packet number for sending and receiving.
12.4 Frames and Frame Types
QUIC payloads MUST contain at least one frame, and MAY contain
multiple frames and multiple frame types.
image image image
13 Packetization and Reliability
A sender can minimize per-packet bandwidth and computational costs by
bundling as many frames as possible within a QUIC packet. A sender
MAY wait for a short period of time to bundle multiple frames before
sending a packet that is not maximally packed, to avoid sending out
large numbers of small packets.
13.1 Packet Processing and Acknowledgment
A packet MUST NOT be acknowledged until packet protection has been successfully removed and all frames contained in the packet have been processed.
13.1.1 Sending ACK Frames
To avoid creating an indefinite feedback loop, an endpoint MUST NOT
send an ACK frame in response to a packet containing only ACK or
PADDING frames, even if there are packet gaps which precede the
received packet. The endpoint MUST however acknowledge packets
containing only ACK or PADDING frames when sending ACK frames in
response to other packets.
13.1.2 ACK Frames and Packet Protection
ACK frames MUST only be carried in a packet that has the same packet
number space as the packet being ACKed.
13.2 Retransmission of Information
In general, information is sent again when a packet containing that information is determined to be lost and sending ceases when a packet containing that information is acknowledged.
- CRYPTO frames: retransmitted according to the rules in [QUIC-RECOVERY], until all data has been acknowledged.
- STREAM frames: retransmitted in new STREAM frames unless the endpoint has sent a RST_STREAM for that stream.
- ACK frames: An ACK frame SHOULD contain all unacknowledged acknowledgments.
- RST_STREAM frame: is sent until acknowledged or until all stream data is acknowledged by the peer.
- STOP_SENDING frame: is sent until the receive stream enters either a "Data Recvd" or "Reset Recvd" state.
- CONNECTION_CLOSE and APPLICATION_CLOSE frames: are not sent again when packet loss is detected.
- MAX_DATA frames: if the packet containing the most recently sent MAX_DATA frame is declared lost, or when the endpoint decides to update the limit.
- MAX_STREAM_DATA frames:
- MAX_STREAM_ID frames:
- BLOCKED, STREAM_BLOCKED, and STREAM_ID_BLOCKED frames: if packets containing the most recent frame for a scope is lost, but only while the endpoint is blocked on the corresponding limit.
- PATH_CHALLENGE frames: is sent periodically until a matching PATH_RESPONSE frame is received or until there is no remaining need for liveness or path validation checking.
- PATH_RESPONSE frames:are sent just once.
- NEW_CONNECTION_ID frames、RETIRE_CONNECTION_ID frames: retransmitted if the packet containing them is lost.
- PADDING frames: not require repair.
13.3 Explicit Congestion Notification(ECN)
QUIC endpoints use Explicit Congestion Notification (ECN) to detect and respond to network congestion.
ECN allows a network node to indicate congestion in the network by setting a codepoint in the IP header of a packet instead of dropping it.
在TCP连接上使用ECN是可选的;对于要使用的ECN,必须在连接建立时通过在SYN和SYN-ACK段中包含合适的选项来协商它。原则上应该可以将ECN与UDP之上的协议一起使用。但是,UDP要求应用程序执行拥塞控制,并且当前的网络API不允许访问ECN位。
ECN使用IPv4或IPv6标头中DiffServ字段的两个最低有效(最右)位来编码四个不同的代码点:
- 00 - 非ECN能力的运输,非ECT
- 10 - ECN能力运输,ECT(0)
- 01 - ECN能力运输,ECT(1)
- 11 - 遇到拥堵,CE。
当两个端点都支持ECN时,它们使用ECT(0)或ECT(1)标记其数据包。如果分组遍历正在经历拥塞的活动队列管理(AQM)队列(例如,使用随机早期检测(RED)的队列)并且相应的路由器支持ECN,则它可以将代码点改变为CE而不是丢弃分组。该行为被称为“标记”,其目的是通知接收端点即将发生的拥塞。在接收端点处,该拥塞指示由上层协议(传输层)处理 协议)并且需要回送到发送节点以便发信号以降低其传输速率。
13.3.1 ECN Counters
On receiving a packet with an ECT(ECN Capable Transport) or CE(Congestion Experienced) codepoint, an endpoint that can access the IP ECN codepoints increases the corresponding ECT(0), ECT(1), or CE count, and includes these counters in subsequent ACK frames
13.3.2 ECN Verification
Each endpoint independently verifies and enables use of ECN by
setting the IP header ECN codepoint to ECN Capable Transport (ECT)
for the path from it to the other peer.
To verify both that a path supports ECN and the peer can provide ECN
feedback, an endpoint MUST set the ECT(0) codepoint in the IP header
of all outgoing packets.
14 Packet Size
The QUIC packet size includes the QUIC header and integrity check,
but not the UDP or IP header.
- The payload of a UDP datagram carrying the Initial packet MUST be
expanded to at least 1200 octets, by adding PADDING frames to the
Initial packet and/or by combining the Initial packet with a 0-RTT
packet.
14.1 Path Maximum Transmission Unit
The Path Maximum Transmission Unit (PMTU) is the maximum size of the
entire IP header, UDP header, and UDP payload. The UDP payload
includes the QUIC packet header, protected payload, and any
authentication fields.
Endpoints MAY use PMTU Discovery for detecting the PMTU, setting the PMTU appropriately, and storing the result of previous PMTU determinations. In the absence of these mechanisms, QUIC endpoints SHOULD NOT send IP packets larger than 1280 octets.
14.1.1 IPv4 PMTU Discovery
Endpoints that implement PMTUD in IPv4:
- Set the IPv4 Don’t Fragment (DF) bit on a small proportion of packets, so that most invalid ICMP messages arrive when there are no DF packets outstanding, and can therefore be identified as spurious.
- Store additional information from the IP or UDP headers from DF packets (for example, the IP ID or UDP checksum) to further authenticate incoming Datagram Too Big messages.
- Any reduction in PMTU due to a report contained in an ICMP packet is provisional until QUIC’s loss detection algorithm determines that the packet is actually lost.
14.2 Special Considerations for Packetization Layer PMTU Discovery
15 Versions
QUIC versions are identified using a 32-bit unsigned number.
- The version 0x00000000 is reserved to represent version negotiation.
- Versions that follow the pattern 0x?a?a?a?a are reserved for use in
forcing version negotiation to be exercised.
16 Variable-Length Integer Encoding
QUIC packets and frames commonly use a variable-length encoding for
non-negative integer values. This encoding ensures that smaller
integer values need fewer octets to encode.
The QUIC variable-length integer encoding reserves the two most
significant bits of the first octet to encode the base 2 logarithm of
the integer encoding length in octets. The integer value is encoded
on the remaining bits, in network byte order.
17 Packet Formats
All numeric values are encoded in network byte order (that is, bigendian) and all field sizes are in bits.
17.1 Packet Number Encoding and Decoding
The number of bits required to represent the packet number is first reduced by including only a variable number of the least significant bits of the packet number.
imageThe size of the packet number encoding is at least one more than the base 2 logarithm of the number of contiguous unacknowledged packet numbers, including the new packet.
Recovering the full packet number is necessary to successfully remove packet protection. Once packet number protection is removed, the packet number is decoded by finding the packet number value that is closest to the next expected packet. The next expected packet is the highest received packet number plus one.
17.2 Long Header Packet
Long headers are used for packets that are sent prior to the
completion of version negotiation and establishment of 1-RTT keys.
The header form, type, connection ID lengths octet, destination and source connection IDs, and version fields of a long header packet are version-independent. The packet number and values for packet types defined in Table 6 are version-specific.
17.3 Short Header Packet
The short header can be used after the version and 1-RTT keys are
negotiated.
The header form and connection ID field of a short header packet are
version-independent. The remaining fields are specific to the
selected QUIC version.
17.4 Version Negotiation Packet
The Version Negotiation packet is a response to a client packet that
contains a version that is not supported by the server, and is only
sent by servers.
A Version Negotiation packet cannot be explicitly acknowledged in an ACK frame by a client. Receiving another Initial packet implicitly acknowledges a Version Negotiation packet. A Version Negotiation packet consumes an entire UDP datagram.
17.5 Initial Packet
imageThe client and server use the Initial packet type for any packet that
contains an initial cryptographic handshake message.
A server sends its first Initial packet in response to a client
Initial. A server may send multiple Initial packets.
The payload of an Initial packet includes a CRYPTO frame (or frames)
containing a cryptographic handshake message, ACK frames, or both.
PADDING and CONNECTION_CLOSE frames are also permitted.
17.5.1 Starting Packet Numbers
The first Initial packet sent by either endpoint contains a packet
number of 0. The packet number MUST increase monotonically
thereafter.
17.5.2 0-RTT Packet Numbers
A client only receives acknowledgments for its 0-RTT packets once the handshake is complete. Consequently, a server might expect 0-RTT packets to start with a packet number of 0.
A client SHOULD instead generate a fresh cryptographic handshake
message and start packet numbers from 0. This ensures that new 0-RTT
packets will not use the same keys, avoiding any risk of key and
nonce reuse; this also prevents 0-RTT packets from previous handshake
attempts from being accepted as part of the connection.
17.6 Handshake Packet
A Handshake packet is used to carry acknowledgments and cryptographic handshake messages from the server and client.
17.7 Retry Packet
A Retry packet carries an address validation token created by the server. It is used by a server that wishes to perform a stateless retry.
image18 Transport Parameter Encoding
QUIC encodes transport parameters into a sequence of octets, which
are then included in the cryptographic handshake.
uint32 QuicVersion;
enum {
initial_max_stream_data_bidi_local(0),
initial_max_data(1),
initial_max_bidi_streams(2),
idle_timeout(3),
preferred_address(4),
max_packet_size(5),
stateless_reset_token(6),
ack_delay_exponent(7),
initial_max_uni_streams(8),
disable_migration(9),
initial_max_stream_data_bidi_remote(10),
initial_max_stream_data_uni(11),
max_ack_delay(12),
original_connection_id(13),
(65535)
} TransportParameterId;
struct {
TransportParameterId parameter;
opaque value<0..2^16-1>;
} TransportParameter;
struct {
select (Handshake.msg_type) {
case client_hello:
QuicVersion initial_version;
case encrypted_extensions:
QuicVersion negotiated_version;
QuicVersion supported_versions<4..2^8-4>;
};
TransportParameter parameters<0..2^16-1>;
} TransportParameters;
struct {
enum { IPv4(4), IPv6(6), (15) } ipVersion;
opaque ipAddress<4..2^8-1>;
uint16 port;
opaque connectionId<0..18>;
opaque statelessResetToken[16];
} PreferredAddress;
Figure 15: Definition of TransportParameters
19 Frame Types and Formats
Packets contain one or more frames.
19.1 PADDING Frame
The PADDING frame (type=0x00) has no semantic value. PADDING frames
can be used to increase the size of a packet.
19.2 RST_STREAM Frame
An endpoint may use a RST_STREAM frame (type=0x01) to abruptly
terminate a stream.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Application Error Code (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Final Offset (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.3 CONNECTION_CLOSE frame
An endpoint sends a CONNECTION_CLOSE frame (type=0x02) to notify its
peer that the connection is being closed. CONNECTION_CLOSE is used
to signal errors at the QUIC layer, or the absence of errors (with
the NO_ERROR code).
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Error Code (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Frame Type (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reason Phrase Length (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reason Phrase (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.4 APPLICATION_CLOSE frame
An APPLICATION_CLOSE frame (type=0x03) is used to signal an error
with the protocol that uses QUIC.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Error Code (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reason Phrase Length (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reason Phrase (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.5 MAX_DATA Frame
The MAX_DATA frame (type=0x04) is used in flow control to inform the
peer of the maximum amount of data that can be sent on the connection
as a whole.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Maximum Data (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.6 MAX_STREAM_DATA Frame
The MAX_STREAM_DATA frame (type=0x05) is used in flow control to
inform a peer of the maximum amount of data that can be sent on a
stream.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Maximum Stream Data (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.7 MAX_STREAM_ID Frame
The MAX_STREAM_ID frame (type=0x06) informs the peer of the maximum
stream ID that they are permitted to open.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Maximum Stream ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.8 PING Frame
Endpoints can use PING frames (type=0x07) to verify that their peers are still alive or to check reachability to the peer. The PING frame contains no additional fields. The receiver of a PING frame simply needs to acknowledge the packet containing this frame.
19.9 BLOCKED Frame
A sender SHOULD send a BLOCKED frame (type=0x08) when it wishes to send data, but is unable to due to connection-level flow control. BLOCKED frames can be used as input to tuning of flow control algorithms.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Offset (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.10 STREAM_BLOCKED Frame
A sender SHOULD send a STREAM_BLOCKED frame (type=0x09) when it
wishes to send data, but is unable to due to stream-level flow
control.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Offset (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.11 STREAM_ID_BLOCKED Frame
A sender SHOULD send a STREAM_ID_BLOCKED frame (type=0x0a) when it
wishes to open a stream, but is unable to due to the maximum stream
ID limit set by its peer.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.12 NEW_CONNECTION_ID Frame
An endpoint sends a NEW_CONNECTION_ID frame (type=0x0b) to provide
its peer with alternative connection IDs that can be used to break
linkability when migrating connections.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length (8) | Sequence Number (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Connection ID (32..144) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Stateless Reset Token (128) +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.13 RETIRE_CONNECTION_ID Frame
An endpoint sends a RETIRE_CONNECTION_ID frame (type=0x1b) to
indicate that it will no longer use a connection ID that was issued
by its peer. Sending a RETIRE_CONNECTION_ID frame also serves as a
request to the peer to send additional connection IDs for future use. New connection IDs can be delivered to a peer using the NEW_CONNECTION_ID frame.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.14 STOP_SENDING Frame
An endpoint may use a STOP_SENDING frame (type=0x0c) to communicate that incoming data is being discarded on receipt at application request. This signals a peer to abruptly terminate transmission on a stream.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Application Error Code (16) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.15 ACK Frame
Receivers send ACK frames (types 0x1a and 0x1b) to inform senders of
packets they have received and processed. The ACK frame contains one
or more ACK Blocks. ACK Blocks are ranges of acknowledged packets.
If the frame type is 0x1b, ACK frames also contain the sum of ECN
marks received on the connection up until this point.
It is expected that a sender will reuse the same packet number across
different packet number spaces. ACK frames only acknowledge the
packet numbers that were transmitted by the sender in the same packet
number space of the packet that the ACK was received in.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Largest Acknowledged (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ACK Delay (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ACK Block Count (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ACK Blocks (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [ECN Section] ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.15.1 ACK Block Section
The ACK Block Section consists of alternating Gap and ACK Block
fields in descending packet number order.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| First ACK Block (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Gap (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Additional ACK Block (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Gap (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Additional ACK Block (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Gap (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Additional ACK Block (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.15.2 ECN section
The ECN section should only be parsed when the ACK frame type byte is
0x1b.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ECT(0) Count (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ECT(1) Count (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ECN-CE Count (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.16 PATH_CHALLENGE Frame
Endpoints can use PATH_CHALLENGE frames (type=0x0e) to check reachability to the peer and for path validation during connection migration.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Data (8) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.17 PATH_RESPONSE Frame
The PATH_RESPONSE frame (type=0x0f) is sent in response to a PATH_CHALLENGE frame.
19.18 NEW_TOKEN frame
A server sends a NEW_TOKEN frame (type=0x19) to provide the client a token to send in the header of an Initial packet for a future connection.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Token Length (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Token (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.19 STREAM Frames
STREAM frames implicitly create a stream and carry stream data. The STREAM frame takes the form 0b00010XXX (or the set of values from 0x10 to 0x17).
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [Offset (i)] ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [Length (i)] ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stream Data (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.20 CRYPTO Frame
The CRYPTO frame (type=0x18) is used to transmit cryptographic handshake messages. It can be sent in all packet types.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Offset (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Crypto Data (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19.21 Extension Frames
An extension to QUIC that wishes to use a new type of frame MUST
first ensure that a peer is able to understand the frame. An
endpoint can use a transport parameter to signal its willingness to
receive one or more extension frame types with the one transport
parameter.
20 Transport Error Codes
QUIC error codes are 16-bit unsigned integers.
20.1 Application Protocol Error Codes
Application protocol error codes are 16-bit unsigned integers, but the management of application error codes are left to application protocols. Application protocol error codes are used for the RST_STREAM and APPLICATION_CLOSE frames. QUIC reserves the error code with a value of 0 to mean STOPPING.