Clippy is warning that the size of RetryError (both proto and quinn's
versions) are excessively large for a Result Err variant. This function
fixes these warnings by boxing the contents of both.
This commit makes there be fewer places where SendStream::execute_poll
is called directly. AsyncWrite implementations now go through poll_write,
and poll_write now goes through the write future. This means that
execute_poll is now only called directly from write and write_chunks.
Changes the implementation of `SendStream::stopped` such that the
returned future is static and no longer lifetime-bound onto a mutable
reference to the send stream.
This allows to use the stopped future with combinators or in a separate
task while still sending on the stream concurrently.
Internally, this is done changing the implementation of the stopped
notification to use a cloneable tokio::sync::Notify instead of storing
a single waker.
We maintain explicit send stream future implementation structs for
`Write`, `WriteAll`, `WriteChunk`, and `WriteAllChunks`. However, these
are private. We can significantly simplify this code by instead leaning
more directly on functionality such as async functions and
`std::future::poll_fn`.
TokenMemoryCache is a new implementation of TokenStore.
TokenMemoryCache is designed to store up to 2 tokens per server (this is
configurable) for up to 256 servers (this is also configurable), with a
LRU eviction policy. This is so that it works harmoniously with
rustls::ClientSessionMemoryCache, which by default stores resumption
state for up to 256 servers with a LRU eviction policy.
When a client receives a token from a NEW_TOKEN frame, it submits it to
a TokenStore object for storage. When an endpoint connects to a server,
it queries the TokenStore object for a token applicable to the server
name, and uses it if one is retrieved.
As of this commit, the only provided implementation of TokenStore is
NoneTokenStore, which is equivalent to the lack of a token store, and is
the default.
When a path becomes validated, the server may send the client NEW_TOKEN
frames. These may cause an Incoming to be validated.
- Adds TokenPayload::Validation variant
- Adds relevant configuration to ServerConfig
- Adds `TokenLog` object to server to mitigate token reuse
As of this commit, the only provided implementation of TokenLog is
NoneTokenLog, which is equivalent to the lack of a token log, and is the
default.
The ability for the server to process tokens from NEW_TOKEN frames will
create the possibility of Incoming which are validated, but may still be
retried. This commit creates an API for that. This means that rather
than Incoming.remote_address_validated being tied to retry_src_cid, it
is tied to a new `validated: bool` of `IncomingToken`.
Currently, this field is initialized to true iff retry_src_cid is some.
However, subsequent commits will introduce the possibility for
divergence.
- Adds trait TimeSource
- Adds default implementation StdSystemTime
- Adds ServerConfigParameter time_source: Arc<dyn TimeSource>
- Replaces all SystemTime::now calls in proto with TimeSource.now calls
(there were 2)
This is a backwards-compatible change.
RFC 9000 presents some unfortunate complications to naming things. It
introduces a concept of a "token" that may cause a connection to be
validated early. In some ways, these tokens must be treated discretely
differently based on whether they originated from a NEW_TOKEN frame or
a Retry packet. It also introduces an unrelated concept of a "stateless
reset token".
If our code and documentation were to constantly use phrases like "token
originating from NEW_TOKEN frame," that would be extremely cumbersome.
Moreover, it would risk feeling like leaking spec internals to the user.
As such, this commit tries to move things towards the following naming
convention:
- A token from a NEW_TOKEN frame is called a "validation token", or
"address validation token", although the shorter form should be used
most often.
- A token from a Retry packet is called a "retry token".
We should avoid saying "stateless retry token" because this phrase is
not used at all in RFC 9000 and is confusingly similar to "stateless
reset token". This commit changes public usages of that phrase.
- In the generic case of either, we call it a "token".
- We still call a stateless reset token a "reset token" or "stateless
reset token".