You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If the server rejects the "early_data" extension, the client application MAY opt to retransmit the Application Data previously sent in early data once the handshake has been completed. Note that automatic retransmission of early data could result in incorrect assumptions regarding the status of the connection. For instance, when the negotiated connection selects a different ALPN protocol from what was used for the early data, an application might need to construct different messages. Similarly, if early data assumes anything about the connection state, it might be sent in error after the handshake completes.
For example, it might be the case that the original connection used application protocol X, but the resumed connection negotiates the use of application protocol Y. 0-RTT data is sent under the assumption that protocol X is used. Obviously, one can't just retransmit that data and assume that it's valid for Y.
In QUIC, we also check if the transport parameters used on the old connection are valid. For example, on the original connection the server might have allowed 10 concurrent streams, but that limit was reduced in the mean time and now only allows 5 concurrent streams. A blind retransmission of 0-RTT data might lead to a protocol violation if the client opened more than 5 streams to send 0-RTT data.
This is just a normal Session with an additional method that allows applications to determine when the handshake completes. When 0-RTT is rejected, we currently just retransmit this data in 1-RTT packets, ignoring the problems described in the previous section.
Proposal
When 0-RTT is rejected, we return a quic.Err0RTTRejected from all calls on the session and on streams. An application that wishes to use 0-RTT needs to handle this error gracefully.
We extend the EarlySession interface:
typeEarlySessioninterface {
SessionHandshakeCompleted() context.Context// If 0-RTT is rejected, the old session becomes invalid.// All calls to OpenStream and AcceptStream will return an Err0RTTRejected,// as will all calls to Read and Write on streams opened on that session.// In that case, NextSession has to be called to obtain the new session.// It is invalid to call this method before a Err0RTTRejected has been returned.NextSession() Session
}
As soon as this error occurs, the application needs to obtain a new session using NextSession(). This returns the session established during the handshake. It's the application's responsibility to reopen streams and retransmit data (if it wishes to do so) on this new session.
Internally, we won't allocate a new session, but we'll use the call to NextSession to reset application state:
all flow-control state is reset to its initial state
the streams map to its initial state, thereby invalidating all streams that might have been opened during 0-RTT
we remove all 0-RTT packets from the packet history and from the bytes in flight
We don't reset any congestion controller state. Having an RTT estimate is valuable and completely independent of the outcome of the cryptographic handshake.
The text was updated successfully, but these errors were encountered:
After offline discussion with @mvdan: The API is probably the best we can do in the general case.
However, most application don't have a need for the most general case: Most of them will just use a single ALPN, and won't be interested in changing any data they sent during 0-RTT in the corner case where 0-RTT is rejected.
This situation calls for a config option quic.Config.RecreateApplicationStateOn0RTTRejection that applications can set if they just want to do the easy thing: Fire some application data in 0-RTT, and just "retransmit" in 1-RTT when 0-RTT is rejected.
We can't use QUIC's retransmission logic for this, since flow control limits might have changed, as well as the stream limit. Instead, we can build a wrapper around the session and the streams, and buffer all writes to streams until the handshake is complete, as suggested in option 2 in libp2p/go-libp2p#1533.
Background
When 0-RTT is rejected, this invalidates all application data sent in 0-RTT packets.
Section 4.2.10 of RFC 8446 says:
For example, it might be the case that the original connection used application protocol
X
, but the resumed connection negotiates the use of application protocolY
. 0-RTT data is sent under the assumption that protocolX
is used. Obviously, one can't just retransmit that data and assume that it's valid forY
.In QUIC, we also check if the transport parameters used on the old connection are valid. For example, on the original connection the server might have allowed 10 concurrent streams, but that limit was reduced in the mean time and now only allows 5 concurrent streams. A blind retransmission of 0-RTT data might lead to a protocol violation if the client opened more than 5 streams to send 0-RTT data.
Current Implementation
When dialing a 0-RTT-enabled connection (using
DialEarly
), quic-go returns anEarlySession
:https://github.com/lucas-clemente/quic-go/blob/9b627ac93d5e74268118d6c099265de6eb9dee44/interface.go#L199-L210
This is just a normal
Session
with an additional method that allows applications to determine when the handshake completes. When 0-RTT is rejected, we currently just retransmit this data in 1-RTT packets, ignoring the problems described in the previous section.Proposal
When 0-RTT is rejected, we return a
quic.Err0RTTRejected
from all calls on the session and on streams. An application that wishes to use 0-RTT needs to handle this error gracefully.We extend the
EarlySession
interface:As soon as this error occurs, the application needs to obtain a new session using
NextSession()
. This returns the session established during the handshake. It's the application's responsibility to reopen streams and retransmit data (if it wishes to do so) on this new session.Internally, we won't allocate a new
session
, but we'll use the call toNextSession
to reset application state:We don't reset any congestion controller state. Having an RTT estimate is valuable and completely independent of the outcome of the cryptographic handshake.
The text was updated successfully, but these errors were encountered: