mirror of
https://github.com/fumiama/terasu-cloudflared.git
synced 2026-06-10 21:24:52 +08:00
TUN-8006: Update quic-go to latest upstream
This commit is contained in:
2
vendor/github.com/quic-go/quic-go/.golangci.yml
generated
vendored
2
vendor/github.com/quic-go/quic-go/.golangci.yml
generated
vendored
@@ -1,4 +1,6 @@
|
||||
run:
|
||||
skip-files:
|
||||
- internal/handshake/cipher_suite.go
|
||||
linters-settings:
|
||||
depguard:
|
||||
type: blacklist
|
||||
|
||||
217
vendor/github.com/quic-go/quic-go/README.md
generated
vendored
217
vendor/github.com/quic-go/quic-go/README.md
generated
vendored
@@ -4,29 +4,210 @@
|
||||
|
||||
[](https://pkg.go.dev/github.com/quic-go/quic-go)
|
||||
[](https://codecov.io/gh/quic-go/quic-go/)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:quic-go)
|
||||
|
||||
quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go, including the Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) and Datagram Packetization Layer Path MTU
|
||||
Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899)). It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)).
|
||||
quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go. It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)).
|
||||
|
||||
In addition to the RFCs listed above, it currently implements the [IETF QUIC draft-29](https://tools.ietf.org/html/draft-ietf-quic-transport-29). Support for draft-29 will eventually be dropped, as it is phased out of the ecosystem.
|
||||
In addition to these base RFCs, it also implements the following RFCs:
|
||||
* Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221))
|
||||
* Datagram Packetization Layer Path MTU Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899))
|
||||
* QUIC Version 2 ([RFC 9369](https://datatracker.ietf.org/doc/html/rfc9369))
|
||||
* QUIC Event Logging using qlog ([draft-ietf-quic-qlog-main-schema](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/) and [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/))
|
||||
|
||||
## Guides
|
||||
Support for WebTransport over HTTP/3 ([draft-ietf-webtrans-http3](https://datatracker.ietf.org/doc/draft-ietf-webtrans-http3/)) is implemented in [webtransport-go](https://github.com/quic-go/webtransport-go).
|
||||
|
||||
*We currently support Go 1.19.x and Go 1.20.x*
|
||||
## Using QUIC
|
||||
|
||||
Running tests:
|
||||
### Running a Server
|
||||
|
||||
go test ./...
|
||||
The central entry point is the `quic.Transport`. A transport manages QUIC connections running on a single UDP socket. Since QUIC uses Connection IDs, it can demultiplex a listener (accepting incoming connections) and an arbitrary number of outgoing QUIC connections on the same UDP socket.
|
||||
|
||||
### QUIC without HTTP/3
|
||||
```go
|
||||
udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: 1234})
|
||||
// ... error handling
|
||||
tr := quic.Transport{
|
||||
Conn: udpConn,
|
||||
}
|
||||
ln, err := tr.Listen(tlsConf, quicConf)
|
||||
// ... error handling
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
// ... error handling
|
||||
// handle the connection, usually in a new Go routine
|
||||
}
|
||||
}()
|
||||
```
|
||||
|
||||
Take a look at [this echo example](example/echo/echo.go).
|
||||
The listener `ln` can now be used to accept incoming QUIC connections by (repeatedly) calling the `Accept` method (see below for more information on the `quic.Connection`).
|
||||
|
||||
## Usage
|
||||
As a shortcut, `quic.Listen` and `quic.ListenAddr` can be used without explicitly initializing a `quic.Transport`:
|
||||
|
||||
```
|
||||
ln, err := quic.Listen(udpConn, tlsConf, quicConf)
|
||||
```
|
||||
|
||||
When using the shortcut, it's not possible to reuse the same UDP socket for outgoing connections.
|
||||
|
||||
### Running a Client
|
||||
|
||||
As mentioned above, multiple outgoing connections can share a single UDP socket, since QUIC uses Connection IDs to demultiplex connections.
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // 3s handshake timeout
|
||||
defer cancel()
|
||||
conn, err := tr.Dial(ctx, <server address>, <tls.Config>, <quic.Config>)
|
||||
// ... error handling
|
||||
```
|
||||
|
||||
As a shortcut, `quic.Dial` and `quic.DialAddr` can be used without explictly initializing a `quic.Transport`:
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // 3s handshake timeout
|
||||
defer cancel()
|
||||
conn, err := quic.Dial(ctx, conn, <server address>, <tls.Config>, <quic.Config>)
|
||||
```
|
||||
|
||||
Just as we saw before when used a similar shortcut to run a server, it's also not possible to reuse the same UDP socket for other outgoing connections, or to listen for incoming connections.
|
||||
|
||||
### Using a QUIC Connection
|
||||
|
||||
#### Accepting Streams
|
||||
|
||||
QUIC is a stream-multiplexed transport. A `quic.Connection` fundamentally differs from the `net.Conn` and the `net.PacketConn` interface defined in the standard library. Data is sent and received on (unidirectional and bidirectional) streams (and, if supported, in [datagrams](#quic-datagrams)), not on the connection itself. The stream state machine is described in detail in [Section 3 of RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000#section-3).
|
||||
|
||||
Note: A unidirectional stream is a stream that the initiator can only write to (`quic.SendStream`), and the receiver can only read from (`quic.ReceiveStream`). A bidirectional stream (`quic.Stream`) allows reading from and writing to for both sides.
|
||||
|
||||
On the receiver side, streams are accepted using the `AcceptStream` (for bidirectional) and `AcceptUniStream` functions. For most user cases, it makes sense to call these functions in a loop:
|
||||
|
||||
```go
|
||||
for {
|
||||
str, err := conn.AcceptStream(context.Background()) // for bidirectional streams
|
||||
// ... error handling
|
||||
// handle the stream, usually in a new Go routine
|
||||
}
|
||||
```
|
||||
|
||||
These functions return an error when the underlying QUIC connection is closed.
|
||||
|
||||
#### Opening Streams
|
||||
|
||||
There are two slightly different ways to open streams, one synchronous and one (potentially) asynchronous. This API is necessary since the receiver grants us a certain number of streams that we're allowed to open. It may grant us additional streams later on (typically when existing streams are closed), but it means that at the time we want to open a new stream, we might not be able to do so.
|
||||
|
||||
Using the synchronous method `OpenStreamSync` for bidirectional streams, and `OpenUniStreamSync` for unidirectional streams, an application can block until the peer allows opening additional streams. In case that we're allowed to open a new stream, these methods return right away:
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
str, err := conn.OpenStreamSync(ctx) // wait up to 5s to open a new bidirectional stream
|
||||
```
|
||||
|
||||
The asynchronous version never blocks. If it's currently not possible to open a new stream, it returns a `net.Error` timeout error:
|
||||
|
||||
```go
|
||||
str, err := conn.OpenStream()
|
||||
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
||||
// It's currently not possible to open another stream,
|
||||
// but it might be possible later, once the peer allowed us to do so.
|
||||
}
|
||||
```
|
||||
|
||||
These functions return an error when the underlying QUIC connection is closed.
|
||||
|
||||
#### Using Streams
|
||||
|
||||
Using QUIC streams is pretty straightforward. The `quic.ReceiveStream` implements the `io.Reader` interface, and the `quic.SendStream` implements the `io.Writer` interface. A bidirectional stream (`quic.Stream`) implements both these interfaces. Conceptually, a bidirectional stream can be thought of as the composition of two unidirectional streams in opposite directions.
|
||||
|
||||
Calling `Close` on a `quic.SendStream` or a `quic.Stream` closes the send side of the stream. On the receiver side, this will be surfaced as an `io.EOF` returned from the `io.Reader` once all data has been consumed. Note that for bidirectional streams, `Close` _only_ closes the send side of the stream. It is still possible to read from the stream until the peer closes or resets the stream.
|
||||
|
||||
In case the application wishes to abort sending on a `quic.SendStream` or a `quic.Stream` , it can reset the send side by calling `CancelWrite` with an application-defined error code (an unsigned 62-bit number). On the receiver side, this surfaced as a `quic.StreamError` containing that error code on the `io.Reader`. Note that for bidirectional streams, `CancelWrite` _only_ resets the send side of the stream. It is still possible to read from the stream until the peer closes or resets the stream.
|
||||
|
||||
Conversely, in case the application wishes to abort receiving from a `quic.ReceiveStream` or a `quic.Stream`, it can ask the sender to abort data transmission by calling `CancelRead` with an application-defined error code (an unsigned 62-bit number). On the receiver side, this surfaced as a `quic.StreamError` containing that error code on the `io.Writer`. Note that for bidirectional streams, `CancelWrite` _only_ resets the receive side of the stream. It is still possible to write to the stream.
|
||||
|
||||
A bidirectional stream is only closed once both the read and the write side of the stream have been either closed or reset. Only then the peer is granted a new stream according to the maximum number of concurrent streams configured via `quic.Config.MaxIncomingStreams`.
|
||||
|
||||
### Configuring QUIC
|
||||
|
||||
The `quic.Config` struct passed to both the listen and dial calls (see above) contains a wide range of configuration options for QUIC connections, incl. the ability to fine-tune flow control limits, the number of streams that the peer is allowed to open concurrently, keep-alives, idle timeouts, and many more. Please refer to the documentation for the `quic.Config` for details.
|
||||
|
||||
The `quic.Transport` contains a few configuration options that don't apply to any single QUIC connection, but to all connections handled by that transport. It is highly recommend to set the `StatelessResetToken`, which allows endpoints to quickly recover from crashes / reboots of our node (see [Section 10.3 of RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000#section-10.3)).
|
||||
|
||||
### Closing a Connection
|
||||
|
||||
#### When the remote Peer closes the Connection
|
||||
|
||||
In case the peer closes the QUIC connection, all calls to open streams, accept streams, as well as all methods on streams immediately return an error. Additionally, it is set as cancellation cause of the connection context. Users can use errors assertions to find out what exactly went wrong:
|
||||
|
||||
* `quic.VersionNegotiationError`: Happens during the handshake, if there is no overlap between our and the remote's supported QUIC versions.
|
||||
* `quic.HandshakeTimeoutError`: Happens if the QUIC handshake doesn't complete within the time specified in `quic.Config.HandshakeTimeout`.
|
||||
* `quic.IdleTimeoutError`: Happens after completion of the handshake if the connection is idle for longer than the minimum of both peers idle timeouts (as configured by `quic.Config.IdleTimeout`). The connection is considered idle when no stream data (and datagrams, if applicable) are exchanged for that period. The QUIC connection can be instructed to regularly send a packet to prevent a connection from going idle by setting `quic.Config.KeepAlive`. However, this is no guarantee that the peer doesn't suddenly go away (e.g. by abruptly shutting down the node or by crashing), or by a NAT binding expiring, in which case this error might still occur.
|
||||
* `quic.StatelessResetError`: Happens when the remote peer lost the state required to decrypt the packet. This requires the `quic.Transport.StatelessResetToken` to be configured by the peer.
|
||||
* `quic.TransportError`: Happens if when the QUIC protocol is violated. Unless the error code is `APPLICATION_ERROR`, this will not happen unless one of the QUIC stacks involved is misbehaving. Please open an issue if you encounter this error.
|
||||
* `quic.ApplicationError`: Happens when the remote decides to close the connection, see below.
|
||||
|
||||
#### Initiated by the Application
|
||||
|
||||
A `quic.Connection` can be closed using `CloseWithError`:
|
||||
|
||||
```go
|
||||
conn.CloseWithError(0x42, "error 0x42 occurred")
|
||||
```
|
||||
|
||||
Applications can transmit both an error code (an unsigned 62-bit number) as well as a UTF-8 encoded human-readable reason. The error code allows the receiver to learn why the connection was closed, and the reason can be useful for debugging purposes.
|
||||
|
||||
On the receiver side, this is surfaced as a `quic.ApplicationError`.
|
||||
|
||||
### QUIC Datagrams
|
||||
|
||||
Unreliable datagrams are a QUIC extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) that is negotiated during the handshake. Support can be enabled by setting the `quic.Config.EnableDatagram` flag. Note that this doesn't guarantee that the peer also supports datagrams. Whether or not the feature negotiation succeeded can be learned from the `quic.ConnectionState.SupportsDatagrams` obtained from `quic.Connection.ConnectionState()`.
|
||||
|
||||
QUIC DATAGRAMs are a new QUIC frame type sent in QUIC 1-RTT packets (i.e. after completion of the handshake). Therefore, they're end-to-end encrypted and congestion-controlled. However, if a DATAGRAM frame is deemed lost by QUIC's loss detection mechanism, they are not retransmitted.
|
||||
|
||||
Datagrams are sent using the `SendDatagram` method on the `quic.Connection`:
|
||||
|
||||
```go
|
||||
conn.SendDatagram([]byte("foobar"))
|
||||
```
|
||||
|
||||
And received using `ReceiveDatagram`:
|
||||
|
||||
```go
|
||||
msg, err := conn.ReceiveDatagram()
|
||||
```
|
||||
|
||||
Note that this code path is currently not optimized. It works for datagrams that are sent occasionally, but it doesn't achieve the same throughput as writing data on a stream. Please get in touch on issue #3766 if your use case relies on high datagram throughput, or if you'd like to help fix this issue. There are also some restrictions regarding the maximum message size (see #3599).
|
||||
|
||||
### QUIC Event Logging using qlog
|
||||
|
||||
quic-go logs a wide range of events defined in [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/), providing comprehensive insights in the internals of a QUIC connection.
|
||||
|
||||
qlog files can be processed by a number of 3rd-party tools. [qviz](https://qvis.quictools.info/) has proven very useful for debugging all kinds of QUIC connection failures.
|
||||
|
||||
qlog is activated by setting a `Tracer` callback on the `Config`. It is called as soon as quic-go decides to starts the QUIC handshake on a new connection.
|
||||
A useful implementation of this callback could look like this:
|
||||
```go
|
||||
quic.Config{
|
||||
Tracer: func(ctx context.Context, p logging.Perspective, connID quic.ConnectionID) *logging.ConnectionTracer {
|
||||
role := "server"
|
||||
if p == logging.PerspectiveClient {
|
||||
role = "client"
|
||||
}
|
||||
filename := fmt.Sprintf("./log_%s_%s.qlog", connID, role)
|
||||
f, err := os.Create(filename)
|
||||
// handle the error
|
||||
return qlog.NewConnectionTracer(f, p, connID)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This implementation of the callback creates a new qlog file in the current directory named `log_<client / server>_<QUIC connection ID>.qlog`.
|
||||
|
||||
|
||||
## Using HTTP/3
|
||||
|
||||
### As a server
|
||||
|
||||
See the [example server](example/main.go). Starting a QUIC server is very similar to the standard lib http in go:
|
||||
See the [example server](example/main.go). Starting a QUIC server is very similar to the standard library http package in Go:
|
||||
|
||||
```go
|
||||
http.Handle("/", http.FileServer(http.Dir(wwwDir)))
|
||||
@@ -46,12 +227,13 @@ http.Client{
|
||||
## Projects using quic-go
|
||||
|
||||
| Project | Description | Stars |
|
||||
|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) | Free and open source, powerful network-wide ads & trackers blocking DNS server. |  |
|
||||
| [algernon](https://github.com/xyproto/algernon) | Small self-contained pure-Go web server with Lua, Markdown, HTTP/2, QUIC, Redis and PostgreSQL support |  |
|
||||
| [caddy](https://github.com/caddyserver/caddy/) | Fast, multi-platform web server with automatic HTTPS |  |
|
||||
| [cloudflared](https://github.com/cloudflare/cloudflared) | A tunneling daemon that proxies traffic from the Cloudflare network to your origins |  |
|
||||
| [go-libp2p](https://github.com/libp2p/go-libp2p) | libp2p implementation in Go, powering [Kubo](https://github.com/ipfs/kubo) (IPFS) and [Lotus](https://github.com/filecoin-project/lotus) (Filecoin), among others |  |
|
||||
| [Hysteria](https://github.com/apernet/hysteria) | A powerful, lightning fast and censorship resistant proxy |  |
|
||||
| [Mercure](https://github.com/dunglas/mercure) | An open, easy, fast, reliable and battery-efficient solution for real-time communications |  |
|
||||
| [OONI Probe](https://github.com/ooni/probe-cli) | Next generation OONI Probe. Library and CLI tool. |  |
|
||||
| [syncthing](https://github.com/syncthing/syncthing/) | Open Source Continuous File Synchronization |  |
|
||||
@@ -59,6 +241,17 @@ http.Client{
|
||||
| [v2ray-core](https://github.com/v2fly/v2ray-core) | A platform for building proxies to bypass network restrictions |  |
|
||||
| [YoMo](https://github.com/yomorun/yomo) | Streaming Serverless Framework for Geo-distributed System |  |
|
||||
|
||||
If you'd like to see your project added to this list, please send us a PR.
|
||||
|
||||
## Release Policy
|
||||
|
||||
quic-go always aims to support the latest two Go releases.
|
||||
|
||||
### Dependency on forked crypto/tls
|
||||
|
||||
Since the standard library didn't provide any QUIC APIs before the Go 1.21 release, we had to fork crypto/tls to add the required APIs ourselves: [qtls for Go 1.20](https://github.com/quic-go/qtls-go1-20).
|
||||
This had led to a lot of pain in the Go ecosystem, and we're happy that we can rely on Go 1.21 going forward.
|
||||
|
||||
## Contributing
|
||||
|
||||
We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [help wanted](https://github.com/quic-go/quic-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). If you have any questions, please feel free to reach out by opening an issue or leaving a comment.
|
||||
|
||||
34
vendor/github.com/quic-go/quic-go/buffer_pool.go
generated
vendored
34
vendor/github.com/quic-go/quic-go/buffer_pool.go
generated
vendored
@@ -51,18 +51,22 @@ func (b *packetBuffer) Release() {
|
||||
}
|
||||
|
||||
// Len returns the length of Data
|
||||
func (b *packetBuffer) Len() protocol.ByteCount {
|
||||
return protocol.ByteCount(len(b.Data))
|
||||
}
|
||||
func (b *packetBuffer) Len() protocol.ByteCount { return protocol.ByteCount(len(b.Data)) }
|
||||
func (b *packetBuffer) Cap() protocol.ByteCount { return protocol.ByteCount(cap(b.Data)) }
|
||||
|
||||
func (b *packetBuffer) putBack() {
|
||||
if cap(b.Data) != int(protocol.MaxPacketBufferSize) {
|
||||
panic("putPacketBuffer called with packet of wrong size!")
|
||||
if cap(b.Data) == protocol.MaxPacketBufferSize {
|
||||
bufferPool.Put(b)
|
||||
return
|
||||
}
|
||||
bufferPool.Put(b)
|
||||
if cap(b.Data) == protocol.MaxLargePacketBufferSize {
|
||||
largeBufferPool.Put(b)
|
||||
return
|
||||
}
|
||||
panic("putPacketBuffer called with packet of wrong size!")
|
||||
}
|
||||
|
||||
var bufferPool sync.Pool
|
||||
var bufferPool, largeBufferPool sync.Pool
|
||||
|
||||
func getPacketBuffer() *packetBuffer {
|
||||
buf := bufferPool.Get().(*packetBuffer)
|
||||
@@ -71,10 +75,18 @@ func getPacketBuffer() *packetBuffer {
|
||||
return buf
|
||||
}
|
||||
|
||||
func getLargePacketBuffer() *packetBuffer {
|
||||
buf := largeBufferPool.Get().(*packetBuffer)
|
||||
buf.refCount = 1
|
||||
buf.Data = buf.Data[:0]
|
||||
return buf
|
||||
}
|
||||
|
||||
func init() {
|
||||
bufferPool.New = func() interface{} {
|
||||
return &packetBuffer{
|
||||
Data: make([]byte, 0, protocol.MaxPacketBufferSize),
|
||||
}
|
||||
bufferPool.New = func() any {
|
||||
return &packetBuffer{Data: make([]byte, 0, protocol.MaxPacketBufferSize)}
|
||||
}
|
||||
largeBufferPool.New = func() any {
|
||||
return &packetBuffer{Data: make([]byte, 0, protocol.MaxLargePacketBufferSize)}
|
||||
}
|
||||
}
|
||||
|
||||
45
vendor/github.com/quic-go/quic-go/client.go
generated
vendored
45
vendor/github.com/quic-go/quic-go/client.go
generated
vendored
@@ -34,7 +34,7 @@ type client struct {
|
||||
|
||||
conn quicConn
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
tracingID uint64
|
||||
logger utils.Logger
|
||||
}
|
||||
@@ -43,7 +43,9 @@ type client struct {
|
||||
var generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial
|
||||
|
||||
// DialAddr establishes a new QUIC connection to a server.
|
||||
// It uses a new UDP connection and closes this connection when the QUIC connection is closed.
|
||||
// It resolves the address, and then creates a new UDP connection to dial the QUIC server.
|
||||
// When the QUIC connection is closed, this UDP connection is closed.
|
||||
// See Dial for more details.
|
||||
func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (Connection, error) {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
@@ -53,15 +55,15 @@ func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Confi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
tr, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dl.Dial(ctx, udpAddr, tlsConf, conf)
|
||||
return tr.dial(ctx, udpAddr, addr, tlsConf, conf, false)
|
||||
}
|
||||
|
||||
// DialAddrEarly establishes a new 0-RTT QUIC connection to a server.
|
||||
// It uses a new UDP connection and closes this connection when the QUIC connection is closed.
|
||||
// See DialAddr for more details.
|
||||
func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
@@ -71,20 +73,20 @@ func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
tr, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := dl.DialEarly(ctx, udpAddr, tlsConf, conf)
|
||||
conn, err := tr.dial(ctx, udpAddr, addr, tlsConf, conf, true)
|
||||
if err != nil {
|
||||
dl.Close()
|
||||
tr.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn using the provided context.
|
||||
// See DialEarly for details.
|
||||
// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn.
|
||||
// See Dial for more details.
|
||||
func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
|
||||
dl, err := setupTransport(c, tlsConf, false)
|
||||
if err != nil {
|
||||
@@ -98,12 +100,15 @@ func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tl
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Dial establishes a new QUIC connection to a server using a net.PacketConn. If
|
||||
// the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn
|
||||
// does), ECN and packet info support will be enabled. In this case, ReadMsgUDP
|
||||
// and WriteMsgUDP will be used instead of ReadFrom and WriteTo to read/write
|
||||
// packets.
|
||||
// Dial establishes a new QUIC connection to a server using a net.PacketConn.
|
||||
// If the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn does),
|
||||
// ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP
|
||||
// will be used instead of ReadFrom and WriteTo to read/write packets.
|
||||
// The tls.Config must define an application protocol (using NextProtos).
|
||||
//
|
||||
// This is a convenience function. More advanced use cases should instantiate a Transport,
|
||||
// which offers configuration options for a more fine-grained control of the connection establishment,
|
||||
// including reusing the underlying UDP socket for multiple QUIC connections.
|
||||
func Dial(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) {
|
||||
dl, err := setupTransport(c, tlsConf, false)
|
||||
if err != nil {
|
||||
@@ -148,7 +153,7 @@ func dial(
|
||||
if c.config.Tracer != nil {
|
||||
c.tracer = c.config.Tracer(context.WithValue(ctx, ConnectionTracingKey, c.tracingID), protocol.PerspectiveClient, c.destConnID)
|
||||
}
|
||||
if c.tracer != nil {
|
||||
if c.tracer != nil && c.tracer.StartedConnection != nil {
|
||||
c.tracer.StartedConnection(c.sendConn.LocalAddr(), c.sendConn.RemoteAddr(), c.srcConnID, c.destConnID)
|
||||
}
|
||||
if err := c.dial(ctx); err != nil {
|
||||
@@ -158,12 +163,6 @@ func dial(
|
||||
}
|
||||
|
||||
func newClient(sendConn sendConn, connIDGenerator ConnectionIDGenerator, config *Config, tlsConf *tls.Config, onClose func(), use0RTT bool) (*client, error) {
|
||||
if tlsConf == nil {
|
||||
tlsConf = &tls.Config{}
|
||||
} else {
|
||||
tlsConf = tlsConf.Clone()
|
||||
}
|
||||
|
||||
srcConnID, err := connIDGenerator.GenerateConnectionID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -234,7 +233,7 @@ func (c *client) dial(ctx context.Context) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
c.conn.shutdown()
|
||||
return ctx.Err()
|
||||
return context.Cause(ctx)
|
||||
case err := <-errorChan:
|
||||
return err
|
||||
case recreateErr := <-recreateChan:
|
||||
|
||||
8
vendor/github.com/quic-go/quic-go/closed_conn.go
generated
vendored
8
vendor/github.com/quic-go/quic-go/closed_conn.go
generated
vendored
@@ -16,13 +16,13 @@ type closedLocalConn struct {
|
||||
perspective protocol.Perspective
|
||||
logger utils.Logger
|
||||
|
||||
sendPacket func(net.Addr, *packetInfo)
|
||||
sendPacket func(net.Addr, packetInfo)
|
||||
}
|
||||
|
||||
var _ packetHandler = &closedLocalConn{}
|
||||
|
||||
// newClosedLocalConn creates a new closedLocalConn and runs it.
|
||||
func newClosedLocalConn(sendPacket func(net.Addr, *packetInfo), pers protocol.Perspective, logger utils.Logger) packetHandler {
|
||||
func newClosedLocalConn(sendPacket func(net.Addr, packetInfo), pers protocol.Perspective, logger utils.Logger) packetHandler {
|
||||
return &closedLocalConn{
|
||||
sendPacket: sendPacket,
|
||||
perspective: pers,
|
||||
@@ -30,7 +30,7 @@ func newClosedLocalConn(sendPacket func(net.Addr, *packetInfo), pers protocol.Pe
|
||||
}
|
||||
}
|
||||
|
||||
func (c *closedLocalConn) handlePacket(p *receivedPacket) {
|
||||
func (c *closedLocalConn) handlePacket(p receivedPacket) {
|
||||
c.counter++
|
||||
// exponential backoff
|
||||
// only send a CONNECTION_CLOSE for the 1st, 2nd, 4th, 8th, 16th, ... packet arriving
|
||||
@@ -58,7 +58,7 @@ func newClosedRemoteConn(pers protocol.Perspective) packetHandler {
|
||||
return &closedRemoteConn{perspective: pers}
|
||||
}
|
||||
|
||||
func (s *closedRemoteConn) handlePacket(*receivedPacket) {}
|
||||
func (s *closedRemoteConn) handlePacket(receivedPacket) {}
|
||||
func (s *closedRemoteConn) shutdown() {}
|
||||
func (s *closedRemoteConn) destroy(error) {}
|
||||
func (s *closedRemoteConn) getPerspective() protocol.Perspective { return s.perspective }
|
||||
|
||||
10
vendor/github.com/quic-go/quic-go/codecov.yml
generated
vendored
10
vendor/github.com/quic-go/quic-go/codecov.yml
generated
vendored
@@ -1,18 +1,10 @@
|
||||
coverage:
|
||||
round: nearest
|
||||
ignore:
|
||||
- streams_map_incoming_bidi.go
|
||||
- streams_map_incoming_uni.go
|
||||
- streams_map_outgoing_bidi.go
|
||||
- streams_map_outgoing_uni.go
|
||||
- http3/gzip_reader.go
|
||||
- interop/
|
||||
- internal/ackhandler/packet_linkedlist.go
|
||||
- internal/utils/byteinterval_linkedlist.go
|
||||
- internal/utils/newconnectionid_linkedlist.go
|
||||
- internal/utils/packetinterval_linkedlist.go
|
||||
- internal/handshake/cipher_suite.go
|
||||
- internal/utils/linkedlist/linkedlist.go
|
||||
- logging/null_tracer.go
|
||||
- fuzzing/
|
||||
- metrics/
|
||||
status:
|
||||
|
||||
74
vendor/github.com/quic-go/quic-go/config.go
generated
vendored
74
vendor/github.com/quic-go/quic-go/config.go
generated
vendored
@@ -1,13 +1,12 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
|
||||
// Clone clones a Config
|
||||
@@ -17,18 +16,29 @@ func (c *Config) Clone() *Config {
|
||||
}
|
||||
|
||||
func (c *Config) handshakeTimeout() time.Duration {
|
||||
return utils.Max(protocol.DefaultHandshakeTimeout, 2*c.HandshakeIdleTimeout)
|
||||
return 2 * c.HandshakeIdleTimeout
|
||||
}
|
||||
|
||||
func (c *Config) maxRetryTokenAge() time.Duration {
|
||||
return c.handshakeTimeout()
|
||||
}
|
||||
|
||||
func validateConfig(config *Config) error {
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
if config.MaxIncomingStreams > 1<<60 {
|
||||
return errors.New("invalid value for Config.MaxIncomingStreams")
|
||||
const maxStreams = 1 << 60
|
||||
if config.MaxIncomingStreams > maxStreams {
|
||||
config.MaxIncomingStreams = maxStreams
|
||||
}
|
||||
if config.MaxIncomingUniStreams > 1<<60 {
|
||||
return errors.New("invalid value for Config.MaxIncomingUniStreams")
|
||||
if config.MaxIncomingUniStreams > maxStreams {
|
||||
config.MaxIncomingUniStreams = maxStreams
|
||||
}
|
||||
if config.MaxStreamReceiveWindow > quicvarint.Max {
|
||||
config.MaxStreamReceiveWindow = quicvarint.Max
|
||||
}
|
||||
if config.MaxConnectionReceiveWindow > quicvarint.Max {
|
||||
config.MaxConnectionReceiveWindow = quicvarint.Max
|
||||
}
|
||||
// check that all QUIC versions are actually supported
|
||||
for _, v := range config.Versions {
|
||||
@@ -43,12 +53,6 @@ func validateConfig(config *Config) error {
|
||||
// it may be called with nil
|
||||
func populateServerConfig(config *Config) *Config {
|
||||
config = populateConfig(config)
|
||||
if config.MaxTokenAge == 0 {
|
||||
config.MaxTokenAge = protocol.TokenValidity
|
||||
}
|
||||
if config.MaxRetryTokenAge == 0 {
|
||||
config.MaxRetryTokenAge = protocol.RetryTokenValidity
|
||||
}
|
||||
if config.RequireAddressValidation == nil {
|
||||
config.RequireAddressValidation = func(net.Addr) bool { return false }
|
||||
}
|
||||
@@ -101,33 +105,25 @@ func populateConfig(config *Config) *Config {
|
||||
} else if maxIncomingUniStreams < 0 {
|
||||
maxIncomingUniStreams = 0
|
||||
}
|
||||
maxDatagrameFrameSize := config.MaxDatagramFrameSize
|
||||
if maxDatagrameFrameSize == 0 {
|
||||
maxDatagrameFrameSize = int64(protocol.DefaultMaxDatagramFrameSize)
|
||||
}
|
||||
|
||||
return &Config{
|
||||
GetConfigForClient: config.GetConfigForClient,
|
||||
Versions: versions,
|
||||
HandshakeIdleTimeout: handshakeIdleTimeout,
|
||||
MaxIdleTimeout: idleTimeout,
|
||||
MaxTokenAge: config.MaxTokenAge,
|
||||
MaxRetryTokenAge: config.MaxRetryTokenAge,
|
||||
RequireAddressValidation: config.RequireAddressValidation,
|
||||
KeepAlivePeriod: config.KeepAlivePeriod,
|
||||
InitialStreamReceiveWindow: initialStreamReceiveWindow,
|
||||
MaxStreamReceiveWindow: maxStreamReceiveWindow,
|
||||
InitialConnectionReceiveWindow: initialConnectionReceiveWindow,
|
||||
MaxConnectionReceiveWindow: maxConnectionReceiveWindow,
|
||||
AllowConnectionWindowIncrease: config.AllowConnectionWindowIncrease,
|
||||
MaxIncomingStreams: maxIncomingStreams,
|
||||
MaxIncomingUniStreams: maxIncomingUniStreams,
|
||||
TokenStore: config.TokenStore,
|
||||
EnableDatagrams: config.EnableDatagrams,
|
||||
MaxDatagramFrameSize: maxDatagrameFrameSize,
|
||||
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
|
||||
DisableVersionNegotiationPackets: config.DisableVersionNegotiationPackets,
|
||||
Allow0RTT: config.Allow0RTT,
|
||||
Tracer: config.Tracer,
|
||||
GetConfigForClient: config.GetConfigForClient,
|
||||
Versions: versions,
|
||||
HandshakeIdleTimeout: handshakeIdleTimeout,
|
||||
MaxIdleTimeout: idleTimeout,
|
||||
RequireAddressValidation: config.RequireAddressValidation,
|
||||
KeepAlivePeriod: config.KeepAlivePeriod,
|
||||
InitialStreamReceiveWindow: initialStreamReceiveWindow,
|
||||
MaxStreamReceiveWindow: maxStreamReceiveWindow,
|
||||
InitialConnectionReceiveWindow: initialConnectionReceiveWindow,
|
||||
MaxConnectionReceiveWindow: maxConnectionReceiveWindow,
|
||||
AllowConnectionWindowIncrease: config.AllowConnectionWindowIncrease,
|
||||
MaxIncomingStreams: maxIncomingStreams,
|
||||
MaxIncomingUniStreams: maxIncomingUniStreams,
|
||||
TokenStore: config.TokenStore,
|
||||
EnableDatagrams: config.EnableDatagrams,
|
||||
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
|
||||
Allow0RTT: config.Allow0RTT,
|
||||
Tracer: config.Tracer,
|
||||
}
|
||||
}
|
||||
|
||||
986
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
986
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
File diff suppressed because it is too large
Load Diff
14
vendor/github.com/quic-go/quic-go/crypto_stream.go
generated
vendored
14
vendor/github.com/quic-go/quic-go/crypto_stream.go
generated
vendored
@@ -71,17 +71,9 @@ func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
|
||||
|
||||
// GetCryptoData retrieves data that was received in CRYPTO frames
|
||||
func (s *cryptoStreamImpl) GetCryptoData() []byte {
|
||||
if len(s.msgBuf) < 4 {
|
||||
return nil
|
||||
}
|
||||
msgLen := 4 + int(s.msgBuf[1])<<16 + int(s.msgBuf[2])<<8 + int(s.msgBuf[3])
|
||||
if len(s.msgBuf) < msgLen {
|
||||
return nil
|
||||
}
|
||||
msg := make([]byte, msgLen)
|
||||
copy(msg, s.msgBuf[:msgLen])
|
||||
s.msgBuf = s.msgBuf[msgLen:]
|
||||
return msg
|
||||
b := s.msgBuf
|
||||
s.msgBuf = nil
|
||||
return b
|
||||
}
|
||||
|
||||
func (s *cryptoStreamImpl) Finish() error {
|
||||
|
||||
35
vendor/github.com/quic-go/quic-go/crypto_stream_manager.go
generated
vendored
35
vendor/github.com/quic-go/quic-go/crypto_stream_manager.go
generated
vendored
@@ -3,12 +3,14 @@ package quic
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/handshake"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
type cryptoDataHandler interface {
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) bool
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) error
|
||||
NextEvent() handshake.Event
|
||||
}
|
||||
|
||||
type cryptoStreamManager struct {
|
||||
@@ -33,7 +35,7 @@ func newCryptoStreamManager(
|
||||
}
|
||||
}
|
||||
|
||||
func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) (bool /* encryption level changed */, error) {
|
||||
func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) error {
|
||||
var str cryptoStream
|
||||
//nolint:exhaustive // CRYPTO frames cannot be sent in 0-RTT packets.
|
||||
switch encLevel {
|
||||
@@ -44,18 +46,37 @@ func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLeve
|
||||
case protocol.Encryption1RTT:
|
||||
str = m.oneRTTStream
|
||||
default:
|
||||
return false, fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel)
|
||||
return fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel)
|
||||
}
|
||||
if err := str.HandleCryptoFrame(frame); err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
for {
|
||||
data := str.GetCryptoData()
|
||||
if data == nil {
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
if encLevelFinished := m.cryptoHandler.HandleMessage(data, encLevel); encLevelFinished {
|
||||
return true, str.Finish()
|
||||
if err := m.cryptoHandler.HandleMessage(data, encLevel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *cryptoStreamManager) GetPostHandshakeData(maxSize protocol.ByteCount) *wire.CryptoFrame {
|
||||
if !m.oneRTTStream.HasData() {
|
||||
return nil
|
||||
}
|
||||
return m.oneRTTStream.PopCryptoFrame(maxSize)
|
||||
}
|
||||
|
||||
func (m *cryptoStreamManager) Drop(encLevel protocol.EncryptionLevel) error {
|
||||
//nolint:exhaustive // 1-RTT keys should never get dropped.
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
return m.initialStream.Finish()
|
||||
case protocol.EncryptionHandshake:
|
||||
return m.handshakeStream.Finish()
|
||||
default:
|
||||
panic(fmt.Sprintf("dropped unexpected encryption level: %s", encLevel))
|
||||
}
|
||||
}
|
||||
|
||||
5
vendor/github.com/quic-go/quic-go/datagram_queue.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/datagram_queue.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@@ -98,7 +99,7 @@ func (h *datagramQueue) HandleDatagramFrame(f *wire.DatagramFrame) {
|
||||
}
|
||||
|
||||
// Receive gets a received DATAGRAM frame.
|
||||
func (h *datagramQueue) Receive() ([]byte, error) {
|
||||
func (h *datagramQueue) Receive(ctx context.Context) ([]byte, error) {
|
||||
for {
|
||||
h.rcvMx.Lock()
|
||||
if len(h.rcvQueue) > 0 {
|
||||
@@ -113,6 +114,8 @@ func (h *datagramQueue) Receive() ([]byte, error) {
|
||||
continue
|
||||
case <-h.closed:
|
||||
return nil, h.closeErr
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
vendor/github.com/quic-go/quic-go/errors.go
generated
vendored
12
vendor/github.com/quic-go/quic-go/errors.go
generated
vendored
@@ -61,3 +61,15 @@ func (e *StreamError) Error() string {
|
||||
}
|
||||
return fmt.Sprintf("stream %d canceled by %s with error code %d", e.StreamID, pers, e.ErrorCode)
|
||||
}
|
||||
|
||||
// DatagramTooLargeError is returned from Connection.SendDatagram if the payload is too large to be sent.
|
||||
type DatagramTooLargeError struct {
|
||||
PeerMaxDatagramFrameSize int64
|
||||
}
|
||||
|
||||
func (e *DatagramTooLargeError) Is(target error) bool {
|
||||
_, ok := target.(*DatagramTooLargeError)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (e *DatagramTooLargeError) Error() string { return "DATAGRAM frame too large" }
|
||||
|
||||
49
vendor/github.com/quic-go/quic-go/framer.go
generated
vendored
49
vendor/github.com/quic-go/quic-go/framer.go
generated
vendored
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/quic-go/quic-go/internal/ackhandler"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils/ringbuffer"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
@@ -14,10 +15,10 @@ type framer interface {
|
||||
HasData() bool
|
||||
|
||||
QueueControlFrame(wire.Frame)
|
||||
AppendControlFrames([]*ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount)
|
||||
AppendControlFrames([]ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount)
|
||||
|
||||
AddActiveStream(protocol.StreamID)
|
||||
AppendStreamFrames([]*ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount)
|
||||
AppendStreamFrames([]ackhandler.StreamFrame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount)
|
||||
|
||||
Handle0RTTRejection() error
|
||||
}
|
||||
@@ -28,7 +29,7 @@ type framerI struct {
|
||||
streamGetter streamGetter
|
||||
|
||||
activeStreams map[protocol.StreamID]struct{}
|
||||
streamQueue []protocol.StreamID
|
||||
streamQueue ringbuffer.RingBuffer[protocol.StreamID]
|
||||
|
||||
controlFrameMutex sync.Mutex
|
||||
controlFrames []wire.Frame
|
||||
@@ -45,7 +46,7 @@ func newFramer(streamGetter streamGetter) framer {
|
||||
|
||||
func (f *framerI) HasData() bool {
|
||||
f.mutex.Lock()
|
||||
hasData := len(f.streamQueue) > 0
|
||||
hasData := !f.streamQueue.Empty()
|
||||
f.mutex.Unlock()
|
||||
if hasData {
|
||||
return true
|
||||
@@ -62,7 +63,7 @@ func (f *framerI) QueueControlFrame(frame wire.Frame) {
|
||||
f.controlFrameMutex.Unlock()
|
||||
}
|
||||
|
||||
func (f *framerI) AppendControlFrames(frames []*ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount) {
|
||||
func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount) {
|
||||
var length protocol.ByteCount
|
||||
f.controlFrameMutex.Lock()
|
||||
for len(f.controlFrames) > 0 {
|
||||
@@ -71,9 +72,7 @@ func (f *framerI) AppendControlFrames(frames []*ackhandler.Frame, maxLen protoco
|
||||
if length+frameLen > maxLen {
|
||||
break
|
||||
}
|
||||
af := ackhandler.GetFrame()
|
||||
af.Frame = frame
|
||||
frames = append(frames, af)
|
||||
frames = append(frames, ackhandler.Frame{Frame: frame})
|
||||
length += frameLen
|
||||
f.controlFrames = f.controlFrames[:len(f.controlFrames)-1]
|
||||
}
|
||||
@@ -84,24 +83,23 @@ func (f *framerI) AppendControlFrames(frames []*ackhandler.Frame, maxLen protoco
|
||||
func (f *framerI) AddActiveStream(id protocol.StreamID) {
|
||||
f.mutex.Lock()
|
||||
if _, ok := f.activeStreams[id]; !ok {
|
||||
f.streamQueue = append(f.streamQueue, id)
|
||||
f.streamQueue.PushBack(id)
|
||||
f.activeStreams[id] = struct{}{}
|
||||
}
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (f *framerI) AppendStreamFrames(frames []*ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount) {
|
||||
func (f *framerI) AppendStreamFrames(frames []ackhandler.StreamFrame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount) {
|
||||
startLen := len(frames)
|
||||
var length protocol.ByteCount
|
||||
var lastFrame *ackhandler.Frame
|
||||
f.mutex.Lock()
|
||||
// pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet
|
||||
numActiveStreams := len(f.streamQueue)
|
||||
numActiveStreams := f.streamQueue.Len()
|
||||
for i := 0; i < numActiveStreams; i++ {
|
||||
if protocol.MinStreamFrameSize+length > maxLen {
|
||||
break
|
||||
}
|
||||
id := f.streamQueue[0]
|
||||
f.streamQueue = f.streamQueue[1:]
|
||||
id := f.streamQueue.PopFront()
|
||||
// This should never return an error. Better check it anyway.
|
||||
// The stream will only be in the streamQueue, if it enqueued itself there.
|
||||
str, err := f.streamGetter.GetOrOpenSendStream(id)
|
||||
@@ -115,28 +113,27 @@ func (f *framerI) AppendStreamFrames(frames []*ackhandler.Frame, maxLen protocol
|
||||
// Therefore, we can pretend to have more bytes available when popping
|
||||
// the STREAM frame (which will always have the DataLen set).
|
||||
remainingLen += quicvarint.Len(uint64(remainingLen))
|
||||
frame, hasMoreData := str.popStreamFrame(remainingLen, v)
|
||||
frame, ok, hasMoreData := str.popStreamFrame(remainingLen, v)
|
||||
if hasMoreData { // put the stream back in the queue (at the end)
|
||||
f.streamQueue = append(f.streamQueue, id)
|
||||
} else { // no more data to send. Stream is not active any more
|
||||
f.streamQueue.PushBack(id)
|
||||
} else { // no more data to send. Stream is not active
|
||||
delete(f.activeStreams, id)
|
||||
}
|
||||
// The frame can be nil
|
||||
// The frame can be "nil"
|
||||
// * if the receiveStream was canceled after it said it had data
|
||||
// * the remaining size doesn't allow us to add another STREAM frame
|
||||
if frame == nil {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
frames = append(frames, frame)
|
||||
length += frame.Length(v)
|
||||
lastFrame = frame
|
||||
length += frame.Frame.Length(v)
|
||||
}
|
||||
f.mutex.Unlock()
|
||||
if lastFrame != nil {
|
||||
lastFrameLen := lastFrame.Length(v)
|
||||
if len(frames) > startLen {
|
||||
l := frames[len(frames)-1].Frame.Length(v)
|
||||
// account for the smaller size of the last STREAM frame
|
||||
lastFrame.Frame.(*wire.StreamFrame).DataLenPresent = false
|
||||
length += lastFrame.Length(v) - lastFrameLen
|
||||
frames[len(frames)-1].Frame.DataLenPresent = false
|
||||
length += frames[len(frames)-1].Frame.Length(v) - l
|
||||
}
|
||||
return frames, length
|
||||
}
|
||||
@@ -146,7 +143,7 @@ func (f *framerI) Handle0RTTRejection() error {
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
f.controlFrameMutex.Lock()
|
||||
f.streamQueue = f.streamQueue[:0]
|
||||
f.streamQueue.Clear()
|
||||
for id := range f.activeStreams {
|
||||
delete(f.activeStreams, id)
|
||||
}
|
||||
|
||||
66
vendor/github.com/quic-go/quic-go/interface.go
generated
vendored
66
vendor/github.com/quic-go/quic-go/interface.go
generated
vendored
@@ -2,6 +2,7 @@ package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
@@ -19,10 +20,9 @@ type StreamID = protocol.StreamID
|
||||
type VersionNumber = protocol.VersionNumber
|
||||
|
||||
const (
|
||||
// VersionDraft29 is IETF QUIC draft-29
|
||||
VersionDraft29 = protocol.VersionDraft29
|
||||
// Version1 is RFC 9000
|
||||
Version1 = protocol.Version1
|
||||
// Version2 is RFC 9369
|
||||
Version2 = protocol.Version2
|
||||
)
|
||||
|
||||
@@ -122,6 +122,8 @@ type SendStream interface {
|
||||
// The Context is canceled as soon as the write-side of the stream is closed.
|
||||
// This happens when Close() or CancelWrite() is called, or when the peer
|
||||
// cancels the read-side of their stream.
|
||||
// The cancellation cause is set to the error that caused the stream to
|
||||
// close, or `context.Canceled` in case the stream is closed without error.
|
||||
Context() context.Context
|
||||
// SetWriteDeadline sets the deadline for future Write calls
|
||||
// and any currently-blocked Write call.
|
||||
@@ -178,15 +180,17 @@ type Connection interface {
|
||||
// The error string will be sent to the peer.
|
||||
CloseWithError(ApplicationErrorCode, string) error
|
||||
// Context returns a context that is cancelled when the connection is closed.
|
||||
// The cancellation cause is set to the error that caused the connection to
|
||||
// close, or `context.Canceled` in case the listener is closed first.
|
||||
Context() context.Context
|
||||
// ConnectionState returns basic details about the QUIC connection.
|
||||
// Warning: This API should not be considered stable and might change soon.
|
||||
ConnectionState() ConnectionState
|
||||
|
||||
// SendMessage sends a message as a datagram, as specified in RFC 9221.
|
||||
SendMessage([]byte) error
|
||||
// ReceiveMessage gets a message received in a datagram, as specified in RFC 9221.
|
||||
ReceiveMessage() ([]byte, error)
|
||||
// SendDatagram sends a message as a datagram, as specified in RFC 9221.
|
||||
SendDatagram([]byte) error
|
||||
// ReceiveDatagram gets a message received in a datagram, as specified in RFC 9221.
|
||||
ReceiveDatagram(context.Context) ([]byte, error)
|
||||
}
|
||||
|
||||
// An EarlyConnection is a connection that is handshaking.
|
||||
@@ -198,7 +202,7 @@ type EarlyConnection interface {
|
||||
|
||||
// HandshakeComplete blocks until the handshake completes (or fails).
|
||||
// For the client, data sent before completion of the handshake is encrypted with 0-RTT keys.
|
||||
// For the serfer, data sent before completion of the handshake is encrypted with 1-RTT keys,
|
||||
// For the server, data sent before completion of the handshake is encrypted with 1-RTT keys,
|
||||
// however the client's identity is only verified once the handshake completes.
|
||||
HandshakeComplete() <-chan struct{}
|
||||
|
||||
@@ -208,6 +212,9 @@ type EarlyConnection interface {
|
||||
// StatelessResetKey is a key used to derive stateless reset tokens.
|
||||
type StatelessResetKey [32]byte
|
||||
|
||||
// TokenGeneratorKey is a key used to encrypt session resumption tokens.
|
||||
type TokenGeneratorKey = handshake.TokenProtectorKey
|
||||
|
||||
// A ConnectionID is a QUIC Connection ID, as defined in RFC 9000.
|
||||
// It is not able to handle QUIC Connection IDs longer than 20 bytes,
|
||||
// as they are allowed by RFC 8999.
|
||||
@@ -246,7 +253,8 @@ type Config struct {
|
||||
// If not set, it uses all versions available.
|
||||
Versions []VersionNumber
|
||||
// HandshakeIdleTimeout is the idle timeout before completion of the handshake.
|
||||
// Specifically, if we don't receive any packet from the peer within this time, the connection attempt is aborted.
|
||||
// If we don't receive any packet from the peer within this time, the connection attempt is aborted.
|
||||
// Additionally, if the handshake doesn't complete in twice this time, the connection attempt is also aborted.
|
||||
// If this value is zero, the timeout is set to 5 seconds.
|
||||
HandshakeIdleTimeout time.Duration
|
||||
// MaxIdleTimeout is the maximum duration that may pass without any incoming network activity.
|
||||
@@ -260,13 +268,6 @@ type Config struct {
|
||||
// See https://datatracker.ietf.org/doc/html/rfc9000#section-8 for details.
|
||||
// If not set, every client is forced to prove its remote address.
|
||||
RequireAddressValidation func(net.Addr) bool
|
||||
// MaxRetryTokenAge is the maximum age of a Retry token.
|
||||
// If not set, it defaults to 5 seconds. Only valid for a server.
|
||||
MaxRetryTokenAge time.Duration
|
||||
// MaxTokenAge is the maximum age of the token presented during the handshake,
|
||||
// for tokens that were issued on a previous connection.
|
||||
// If not set, it defaults to 24 hours. Only valid for a server.
|
||||
MaxTokenAge time.Duration
|
||||
// The TokenStore stores tokens received from the server.
|
||||
// Tokens are used to skip address validation on future connection attempts.
|
||||
// The key used to store tokens is the ServerName from the tls.Config, if set
|
||||
@@ -276,17 +277,21 @@ type Config struct {
|
||||
// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
|
||||
// will increase the window up to MaxStreamReceiveWindow.
|
||||
// If this value is zero, it will default to 512 KB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
InitialStreamReceiveWindow uint64
|
||||
// MaxStreamReceiveWindow is the maximum stream-level flow control window for receiving data.
|
||||
// If this value is zero, it will default to 6 MB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
MaxStreamReceiveWindow uint64
|
||||
// InitialConnectionReceiveWindow is the initial size of the stream-level flow control window for receiving data.
|
||||
// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
|
||||
// will increase the window up to MaxConnectionReceiveWindow.
|
||||
// If this value is zero, it will default to 512 KB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
InitialConnectionReceiveWindow uint64
|
||||
// MaxConnectionReceiveWindow is the connection-level flow control window for receiving data.
|
||||
// If this value is zero, it will default to 15 MB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
MaxConnectionReceiveWindow uint64
|
||||
// AllowConnectionWindowIncrease is called every time the connection flow controller attempts
|
||||
// to increase the connection flow control window.
|
||||
@@ -296,35 +301,30 @@ type Config struct {
|
||||
// in this callback.
|
||||
AllowConnectionWindowIncrease func(conn Connection, delta uint64) bool
|
||||
// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
|
||||
// Values above 2^60 are invalid.
|
||||
// If not set, it will default to 100.
|
||||
// If set to a negative value, it doesn't allow any bidirectional streams.
|
||||
// Values larger than 2^60 will be clipped to that value.
|
||||
MaxIncomingStreams int64
|
||||
// MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
|
||||
// Values above 2^60 are invalid.
|
||||
// If not set, it will default to 100.
|
||||
// If set to a negative value, it doesn't allow any unidirectional streams.
|
||||
// Values larger than 2^60 will be clipped to that value.
|
||||
MaxIncomingUniStreams int64
|
||||
// KeepAlivePeriod defines whether this peer will periodically send a packet to keep the connection alive.
|
||||
// If set to 0, then no keep alive is sent. Otherwise, the keep alive is sent on that period (or at most
|
||||
// every half of MaxIdleTimeout, whichever is smaller).
|
||||
KeepAlivePeriod time.Duration
|
||||
// DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899).
|
||||
// Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
|
||||
// Note that if Path MTU discovery is causing issues on your system, please open a new issue
|
||||
// This allows the sending of QUIC packets that fully utilize the available MTU of the path.
|
||||
// Path MTU discovery is only available on systems that allow setting of the Don't Fragment (DF) bit.
|
||||
// If unavailable or disabled, packets will be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
|
||||
DisablePathMTUDiscovery bool
|
||||
// DisableVersionNegotiationPackets disables the sending of Version Negotiation packets.
|
||||
// This can be useful if version information is exchanged out-of-band.
|
||||
// It has no effect for a client.
|
||||
DisableVersionNegotiationPackets bool
|
||||
// Allow0RTT allows the application to decide if a 0-RTT connection attempt should be accepted.
|
||||
// Only valid for the server.
|
||||
Allow0RTT bool
|
||||
// Enable QUIC datagram support (RFC 9221).
|
||||
EnableDatagrams bool
|
||||
// Maximum size of QUIC datagram frames (RFC 9221).
|
||||
MaxDatagramFrameSize int64
|
||||
Tracer func(context.Context, logging.Perspective, ConnectionID) logging.ConnectionTracer
|
||||
Tracer func(context.Context, logging.Perspective, ConnectionID) *logging.ConnectionTracer
|
||||
}
|
||||
|
||||
type ClientHelloInfo struct {
|
||||
@@ -333,7 +333,17 @@ type ClientHelloInfo struct {
|
||||
|
||||
// ConnectionState records basic details about a QUIC connection
|
||||
type ConnectionState struct {
|
||||
TLS handshake.ConnectionState
|
||||
// TLS contains information about the TLS connection state, incl. the tls.ConnectionState.
|
||||
TLS tls.ConnectionState
|
||||
// SupportsDatagrams says if support for QUIC datagrams (RFC 9221) was negotiated.
|
||||
// This requires both nodes to support and enable the datagram extensions (via Config.EnableDatagrams).
|
||||
// If datagram support was negotiated, datagrams can be sent and received using the
|
||||
// SendDatagram and ReceiveDatagram methods on the Connection.
|
||||
SupportsDatagrams bool
|
||||
Version VersionNumber
|
||||
// Used0RTT says if 0-RTT resumption was used.
|
||||
Used0RTT bool
|
||||
// Version is the QUIC version of the QUIC connection.
|
||||
Version VersionNumber
|
||||
// GSO says if generic segmentation offload is used
|
||||
GSO bool
|
||||
}
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go
generated
vendored
@@ -10,7 +10,7 @@ func IsFrameAckEliciting(f wire.Frame) bool {
|
||||
}
|
||||
|
||||
// HasAckElicitingFrames returns true if at least one frame is ack-eliciting.
|
||||
func HasAckElicitingFrames(fs []*Frame) bool {
|
||||
func HasAckElicitingFrames(fs []Frame) bool {
|
||||
for _, f := range fs {
|
||||
if IsFrameAckEliciting(f.Frame) {
|
||||
return true
|
||||
|
||||
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go
generated
vendored
@@ -14,10 +14,11 @@ func NewAckHandler(
|
||||
initialMaxDatagramSize protocol.ByteCount,
|
||||
rttStats *utils.RTTStats,
|
||||
clientAddressValidated bool,
|
||||
enableECN bool,
|
||||
pers protocol.Perspective,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
) (SentPacketHandler, ReceivedPacketHandler) {
|
||||
sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, clientAddressValidated, pers, tracer, logger)
|
||||
sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, clientAddressValidated, enableECN, pers, tracer, logger)
|
||||
return sph, newReceivedPacketHandler(sph, rttStats, logger)
|
||||
}
|
||||
|
||||
296
vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
generated
vendored
Normal file
296
vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
generated
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
|
||||
type ecnState uint8
|
||||
|
||||
const (
|
||||
ecnStateInitial ecnState = iota
|
||||
ecnStateTesting
|
||||
ecnStateUnknown
|
||||
ecnStateCapable
|
||||
ecnStateFailed
|
||||
)
|
||||
|
||||
// must fit into an uint8, otherwise numSentTesting and numLostTesting must have a larger type
|
||||
const numECNTestingPackets = 10
|
||||
|
||||
type ecnHandler interface {
|
||||
SentPacket(protocol.PacketNumber, protocol.ECN)
|
||||
Mode() protocol.ECN
|
||||
HandleNewlyAcked(packets []*packet, ect0, ect1, ecnce int64) (congested bool)
|
||||
LostPacket(protocol.PacketNumber)
|
||||
}
|
||||
|
||||
// The ecnTracker performs ECN validation of a path.
|
||||
// Once failed, it doesn't do any re-validation of the path.
|
||||
// It is designed only work for 1-RTT packets, it doesn't handle multiple packet number spaces.
|
||||
// In order to avoid revealing any internal state to on-path observers,
|
||||
// callers should make sure to start using ECN (i.e. calling Mode) for the very first 1-RTT packet sent.
|
||||
// The validation logic implemented here strictly follows the algorithm described in RFC 9000 section 13.4.2 and A.4.
|
||||
type ecnTracker struct {
|
||||
state ecnState
|
||||
numSentTesting, numLostTesting uint8
|
||||
|
||||
firstTestingPacket protocol.PacketNumber
|
||||
lastTestingPacket protocol.PacketNumber
|
||||
firstCapablePacket protocol.PacketNumber
|
||||
|
||||
numSentECT0, numSentECT1 int64
|
||||
numAckedECT0, numAckedECT1, numAckedECNCE int64
|
||||
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
var _ ecnHandler = &ecnTracker{}
|
||||
|
||||
func newECNTracker(logger utils.Logger, tracer *logging.ConnectionTracer) *ecnTracker {
|
||||
return &ecnTracker{
|
||||
firstTestingPacket: protocol.InvalidPacketNumber,
|
||||
lastTestingPacket: protocol.InvalidPacketNumber,
|
||||
firstCapablePacket: protocol.InvalidPacketNumber,
|
||||
state: ecnStateInitial,
|
||||
logger: logger,
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ecnTracker) SentPacket(pn protocol.PacketNumber, ecn protocol.ECN) {
|
||||
//nolint:exhaustive // These are the only ones we need to take care of.
|
||||
switch ecn {
|
||||
case protocol.ECNNon:
|
||||
return
|
||||
case protocol.ECT0:
|
||||
e.numSentECT0++
|
||||
case protocol.ECT1:
|
||||
e.numSentECT1++
|
||||
case protocol.ECNUnsupported:
|
||||
if e.state != ecnStateFailed {
|
||||
panic("didn't expect ECN to be unsupported")
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("sent packet with unexpected ECN marking: %s", ecn))
|
||||
}
|
||||
|
||||
if e.state == ecnStateCapable && e.firstCapablePacket == protocol.InvalidPacketNumber {
|
||||
e.firstCapablePacket = pn
|
||||
}
|
||||
|
||||
if e.state != ecnStateTesting {
|
||||
return
|
||||
}
|
||||
|
||||
e.numSentTesting++
|
||||
if e.firstTestingPacket == protocol.InvalidPacketNumber {
|
||||
e.firstTestingPacket = pn
|
||||
}
|
||||
if e.numSentECT0+e.numSentECT1 >= numECNTestingPackets {
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateUnknown, logging.ECNTriggerNoTrigger)
|
||||
}
|
||||
e.state = ecnStateUnknown
|
||||
e.lastTestingPacket = pn
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ecnTracker) Mode() protocol.ECN {
|
||||
switch e.state {
|
||||
case ecnStateInitial:
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateTesting, logging.ECNTriggerNoTrigger)
|
||||
}
|
||||
e.state = ecnStateTesting
|
||||
return e.Mode()
|
||||
case ecnStateTesting, ecnStateCapable:
|
||||
return protocol.ECT0
|
||||
case ecnStateUnknown, ecnStateFailed:
|
||||
return protocol.ECNNon
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown ECN state: %d", e.state))
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ecnTracker) LostPacket(pn protocol.PacketNumber) {
|
||||
if e.state != ecnStateTesting && e.state != ecnStateUnknown {
|
||||
return
|
||||
}
|
||||
if !e.isTestingPacket(pn) {
|
||||
return
|
||||
}
|
||||
e.numLostTesting++
|
||||
// Only proceed if we have sent all 10 testing packets.
|
||||
if e.state != ecnStateUnknown {
|
||||
return
|
||||
}
|
||||
if e.numLostTesting >= e.numSentTesting {
|
||||
e.logger.Debugf("Disabling ECN. All testing packets were lost.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedLostAllTestingPackets)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return
|
||||
}
|
||||
// Path validation also fails if some testing packets are lost, and all other testing packets where CE-marked
|
||||
e.failIfMangled()
|
||||
}
|
||||
|
||||
// HandleNewlyAcked handles the ECN counts on an ACK frame.
|
||||
// It must only be called for ACK frames that increase the largest acknowledged packet number,
|
||||
// see section 13.4.2.1 of RFC 9000.
|
||||
func (e *ecnTracker) HandleNewlyAcked(packets []*packet, ect0, ect1, ecnce int64) (congested bool) {
|
||||
if e.state == ecnStateFailed {
|
||||
return false
|
||||
}
|
||||
|
||||
// ECN validation can fail if the received total count for either ECT(0) or ECT(1) exceeds
|
||||
// the total number of packets sent with each corresponding ECT codepoint.
|
||||
if ect0 > e.numSentECT0 || ect1 > e.numSentECT1 {
|
||||
e.logger.Debugf("Disabling ECN. Received more ECT(0) / ECT(1) acknowledgements than packets sent.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedMoreECNCountsThanSent)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// Count ECT0 and ECT1 marks that we used when sending the packets that are now being acknowledged.
|
||||
var ackedECT0, ackedECT1 int64
|
||||
for _, p := range packets {
|
||||
//nolint:exhaustive // We only ever send ECT(0) and ECT(1).
|
||||
switch e.ecnMarking(p.PacketNumber) {
|
||||
case protocol.ECT0:
|
||||
ackedECT0++
|
||||
case protocol.ECT1:
|
||||
ackedECT1++
|
||||
}
|
||||
}
|
||||
|
||||
// If an ACK frame newly acknowledges a packet that the endpoint sent with either the ECT(0) or ECT(1)
|
||||
// codepoint set, ECN validation fails if the corresponding ECN counts are not present in the ACK frame.
|
||||
// This check detects:
|
||||
// * paths that bleach all ECN marks, and
|
||||
// * peers that don't report any ECN counts
|
||||
if (ackedECT0 > 0 || ackedECT1 > 0) && ect0 == 0 && ect1 == 0 && ecnce == 0 {
|
||||
e.logger.Debugf("Disabling ECN. ECN-marked packet acknowledged, but no ECN counts on ACK frame.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedNoECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// Determine the increase in ECT0, ECT1 and ECNCE marks
|
||||
newECT0 := ect0 - e.numAckedECT0
|
||||
newECT1 := ect1 - e.numAckedECT1
|
||||
newECNCE := ecnce - e.numAckedECNCE
|
||||
|
||||
// We're only processing ACKs that increase the Largest Acked.
|
||||
// Therefore, the ECN counters should only ever increase.
|
||||
// Any decrease means that the peer's counting logic is broken.
|
||||
if newECT0 < 0 || newECT1 < 0 || newECNCE < 0 {
|
||||
e.logger.Debugf("Disabling ECN. ECN counts decreased unexpectedly.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedDecreasedECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// ECN validation also fails if the sum of the increase in ECT(0) and ECN-CE counts is less than the number
|
||||
// of newly acknowledged packets that were originally sent with an ECT(0) marking.
|
||||
// This could be the result of (partial) bleaching.
|
||||
if newECT0+newECNCE < ackedECT0 {
|
||||
e.logger.Debugf("Disabling ECN. Received less ECT(0) + ECN-CE than packets sent with ECT(0).")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedTooFewECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
// Similarly, ECN validation fails if the sum of the increases to ECT(1) and ECN-CE counts is less than
|
||||
// the number of newly acknowledged packets sent with an ECT(1) marking.
|
||||
if newECT1+newECNCE < ackedECT1 {
|
||||
e.logger.Debugf("Disabling ECN. Received less ECT(1) + ECN-CE than packets sent with ECT(1).")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedTooFewECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// update our counters
|
||||
e.numAckedECT0 = ect0
|
||||
e.numAckedECT1 = ect1
|
||||
e.numAckedECNCE = ecnce
|
||||
|
||||
// Detect mangling (a path remarking all ECN-marked testing packets as CE),
|
||||
// once all 10 testing packets have been sent out.
|
||||
if e.state == ecnStateUnknown {
|
||||
e.failIfMangled()
|
||||
if e.state == ecnStateFailed {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if e.state == ecnStateTesting || e.state == ecnStateUnknown {
|
||||
var ackedTestingPacket bool
|
||||
for _, p := range packets {
|
||||
if e.isTestingPacket(p.PacketNumber) {
|
||||
ackedTestingPacket = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// This check won't succeed if the path is mangling ECN-marks (i.e. rewrites all ECN-marked packets to CE).
|
||||
if ackedTestingPacket && (newECT0 > 0 || newECT1 > 0) {
|
||||
e.logger.Debugf("ECN capability confirmed.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateCapable, logging.ECNTriggerNoTrigger)
|
||||
}
|
||||
e.state = ecnStateCapable
|
||||
}
|
||||
}
|
||||
|
||||
// Don't trust CE marks before having confirmed ECN capability of the path.
|
||||
// Otherwise, mangling would be misinterpreted as actual congestion.
|
||||
return e.state == ecnStateCapable && newECNCE > 0
|
||||
}
|
||||
|
||||
// failIfMangled fails ECN validation if all testing packets are lost or CE-marked.
|
||||
func (e *ecnTracker) failIfMangled() {
|
||||
numAckedECNCE := e.numAckedECNCE + int64(e.numLostTesting)
|
||||
if e.numSentECT0+e.numSentECT1 > numAckedECNCE {
|
||||
return
|
||||
}
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedManglingDetected)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
}
|
||||
|
||||
func (e *ecnTracker) ecnMarking(pn protocol.PacketNumber) protocol.ECN {
|
||||
if pn < e.firstTestingPacket || e.firstTestingPacket == protocol.InvalidPacketNumber {
|
||||
return protocol.ECNNon
|
||||
}
|
||||
if pn < e.lastTestingPacket || e.lastTestingPacket == protocol.InvalidPacketNumber {
|
||||
return protocol.ECT0
|
||||
}
|
||||
if pn < e.firstCapablePacket || e.firstCapablePacket == protocol.InvalidPacketNumber {
|
||||
return protocol.ECNNon
|
||||
}
|
||||
// We don't need to deal with the case when ECN validation fails,
|
||||
// since we're ignoring any ECN counts reported in ACK frames in that case.
|
||||
return protocol.ECT0
|
||||
}
|
||||
|
||||
func (e *ecnTracker) isTestingPacket(pn protocol.PacketNumber) bool {
|
||||
if e.firstTestingPacket == protocol.InvalidPacketNumber {
|
||||
return false
|
||||
}
|
||||
return pn >= e.firstTestingPacket && (pn <= e.lastTestingPacket || e.lastTestingPacket == protocol.InvalidPacketNumber)
|
||||
}
|
||||
30
vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go
generated
vendored
30
vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go
generated
vendored
@@ -1,29 +1,21 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
// FrameHandler handles the acknowledgement and the loss of a frame.
|
||||
type FrameHandler interface {
|
||||
OnAcked(wire.Frame)
|
||||
OnLost(wire.Frame)
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
wire.Frame // nil if the frame has already been acknowledged in another packet
|
||||
OnLost func(wire.Frame)
|
||||
OnAcked func(wire.Frame)
|
||||
Frame wire.Frame // nil if the frame has already been acknowledged in another packet
|
||||
Handler FrameHandler
|
||||
}
|
||||
|
||||
var framePool = sync.Pool{New: func() any { return &Frame{} }}
|
||||
|
||||
func GetFrame() *Frame {
|
||||
f := framePool.Get().(*Frame)
|
||||
f.OnLost = nil
|
||||
f.OnAcked = nil
|
||||
return f
|
||||
}
|
||||
|
||||
func putFrame(f *Frame) {
|
||||
f.Frame = nil
|
||||
f.OnLost = nil
|
||||
f.OnAcked = nil
|
||||
framePool.Put(f)
|
||||
type StreamFrame struct {
|
||||
Frame *wire.StreamFrame
|
||||
Handler FrameHandler
|
||||
}
|
||||
|
||||
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
generated
vendored
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
generated
vendored
@@ -10,25 +10,26 @@ import (
|
||||
// SentPacketHandler handles ACKs received for outgoing packets
|
||||
type SentPacketHandler interface {
|
||||
// SentPacket may modify the packet
|
||||
SentPacket(packet *Packet)
|
||||
ReceivedAck(ackFrame *wire.AckFrame, encLevel protocol.EncryptionLevel, recvTime time.Time) (bool /* 1-RTT packet acked */, error)
|
||||
SentPacket(t time.Time, pn, largestAcked protocol.PacketNumber, streamFrames []StreamFrame, frames []Frame, encLevel protocol.EncryptionLevel, ecn protocol.ECN, size protocol.ByteCount, isPathMTUProbePacket bool)
|
||||
// ReceivedAck processes an ACK frame.
|
||||
// It does not store a copy of the frame.
|
||||
ReceivedAck(f *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) (bool /* 1-RTT packet acked */, error)
|
||||
ReceivedBytes(protocol.ByteCount)
|
||||
DropPackets(protocol.EncryptionLevel)
|
||||
ResetForRetry() error
|
||||
ResetForRetry(rcvTime time.Time) error
|
||||
SetHandshakeConfirmed()
|
||||
|
||||
// The SendMode determines if and what kind of packets can be sent.
|
||||
SendMode() SendMode
|
||||
SendMode(now time.Time) SendMode
|
||||
// TimeUntilSend is the time when the next packet should be sent.
|
||||
// It is used for pacing packets.
|
||||
TimeUntilSend() time.Time
|
||||
// HasPacingBudget says if the pacer allows sending of a (full size) packet at this moment.
|
||||
HasPacingBudget() bool
|
||||
SetMaxDatagramSize(count protocol.ByteCount)
|
||||
|
||||
// only to be called once the handshake is complete
|
||||
QueueProbePacket(protocol.EncryptionLevel) bool /* was a packet queued */
|
||||
|
||||
ECNMode(isShortHeaderPacket bool) protocol.ECN // isShortHeaderPacket should only be true for non-coalesced 1-RTT packets
|
||||
PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
|
||||
PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
|
||||
|
||||
@@ -44,7 +45,7 @@ type sentPacketTracker interface {
|
||||
// ReceivedPacketHandler handles ACKs needed to send for incoming packets
|
||||
type ReceivedPacketHandler interface {
|
||||
IsPotentiallyDuplicate(protocol.PacketNumber, protocol.EncryptionLevel) bool
|
||||
ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, encLevel protocol.EncryptionLevel, rcvTime time.Time, shouldInstigateAck bool) error
|
||||
ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, encLevel protocol.EncryptionLevel, rcvTime time.Time, ackEliciting bool) error
|
||||
DropPackets(protocol.EncryptionLevel)
|
||||
|
||||
GetAlarmTimeout() time.Time
|
||||
|
||||
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
generated
vendored
@@ -2,5 +2,8 @@
|
||||
|
||||
package ackhandler
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker"
|
||||
type SentPacketTracker = sentPacketTracker
|
||||
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_ecn_handler_test.go github.com/quic-go/quic-go/internal/ackhandler ECNHandler"
|
||||
type ECNHandler = ecnHandler
|
||||
|
||||
22
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
22
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
@@ -8,13 +8,14 @@ import (
|
||||
)
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
type packet struct {
|
||||
SendTime time.Time
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []*Frame
|
||||
StreamFrames []StreamFrame
|
||||
Frames []Frame
|
||||
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
|
||||
Length protocol.ByteCount
|
||||
EncryptionLevel protocol.EncryptionLevel
|
||||
SendTime time.Time
|
||||
|
||||
IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
|
||||
|
||||
@@ -23,15 +24,16 @@ type Packet struct {
|
||||
skippedPacket bool
|
||||
}
|
||||
|
||||
func (p *Packet) outstanding() bool {
|
||||
func (p *packet) outstanding() bool {
|
||||
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket
|
||||
}
|
||||
|
||||
var packetPool = sync.Pool{New: func() any { return &Packet{} }}
|
||||
var packetPool = sync.Pool{New: func() any { return &packet{} }}
|
||||
|
||||
func GetPacket() *Packet {
|
||||
p := packetPool.Get().(*Packet)
|
||||
func getPacket() *packet {
|
||||
p := packetPool.Get().(*packet)
|
||||
p.PacketNumber = 0
|
||||
p.StreamFrames = nil
|
||||
p.Frames = nil
|
||||
p.LargestAcked = 0
|
||||
p.Length = 0
|
||||
@@ -46,10 +48,8 @@ func GetPacket() *Packet {
|
||||
|
||||
// We currently only return Packets back into the pool when they're acknowledged (not when they're lost).
|
||||
// This simplifies the code, and gives the vast majority of the performance benefit we can gain from using the pool.
|
||||
func putPacket(p *Packet) {
|
||||
for _, f := range p.Frames {
|
||||
putFrame(f)
|
||||
}
|
||||
func putPacket(p *packet) {
|
||||
p.Frames = nil
|
||||
p.StreamFrames = nil
|
||||
packetPool.Put(p)
|
||||
}
|
||||
|
||||
24
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go
generated
vendored
24
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go
generated
vendored
@@ -7,7 +7,10 @@ import (
|
||||
|
||||
type packetNumberGenerator interface {
|
||||
Peek() protocol.PacketNumber
|
||||
Pop() protocol.PacketNumber
|
||||
// Pop pops the packet number.
|
||||
// It reports if the packet number (before the one just popped) was skipped.
|
||||
// It never skips more than one packet number in a row.
|
||||
Pop() (skipped bool, _ protocol.PacketNumber)
|
||||
}
|
||||
|
||||
type sequentialPacketNumberGenerator struct {
|
||||
@@ -24,10 +27,10 @@ func (p *sequentialPacketNumberGenerator) Peek() protocol.PacketNumber {
|
||||
return p.next
|
||||
}
|
||||
|
||||
func (p *sequentialPacketNumberGenerator) Pop() protocol.PacketNumber {
|
||||
func (p *sequentialPacketNumberGenerator) Pop() (bool, protocol.PacketNumber) {
|
||||
next := p.next
|
||||
p.next++
|
||||
return next
|
||||
return false, next
|
||||
}
|
||||
|
||||
// The skippingPacketNumberGenerator generates the packet number for the next packet
|
||||
@@ -56,21 +59,26 @@ func newSkippingPacketNumberGenerator(initial, initialPeriod, maxPeriod protocol
|
||||
}
|
||||
|
||||
func (p *skippingPacketNumberGenerator) Peek() protocol.PacketNumber {
|
||||
if p.next == p.nextToSkip {
|
||||
return p.next + 1
|
||||
}
|
||||
return p.next
|
||||
}
|
||||
|
||||
func (p *skippingPacketNumberGenerator) Pop() protocol.PacketNumber {
|
||||
func (p *skippingPacketNumberGenerator) Pop() (bool, protocol.PacketNumber) {
|
||||
next := p.next
|
||||
p.next++ // generate a new packet number for the next packet
|
||||
if p.next == p.nextToSkip {
|
||||
p.next++
|
||||
next++
|
||||
p.next += 2
|
||||
p.generateNewSkip()
|
||||
return true, next
|
||||
}
|
||||
return next
|
||||
p.next++ // generate a new packet number for the next packet
|
||||
return false, next
|
||||
}
|
||||
|
||||
func (p *skippingPacketNumberGenerator) generateNewSkip() {
|
||||
// make sure that there are never two consecutive packet numbers that are skipped
|
||||
p.nextToSkip = p.next + 2 + protocol.PacketNumber(p.rng.Int31n(int32(2*p.period)))
|
||||
p.nextToSkip = p.next + 3 + protocol.PacketNumber(p.rng.Int31n(int32(2*p.period)))
|
||||
p.period = utils.Min(2*p.period, p.maxPeriod)
|
||||
}
|
||||
|
||||
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
generated
vendored
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
generated
vendored
@@ -40,24 +40,29 @@ func (h *receivedPacketHandler) ReceivedPacket(
|
||||
ecn protocol.ECN,
|
||||
encLevel protocol.EncryptionLevel,
|
||||
rcvTime time.Time,
|
||||
shouldInstigateAck bool,
|
||||
ackEliciting bool,
|
||||
) error {
|
||||
h.sentPackets.ReceivedPacket(encLevel)
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
return h.initialPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return h.initialPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
|
||||
case protocol.EncryptionHandshake:
|
||||
return h.handshakePackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
// The Handshake packet number space might already have been dropped as a result
|
||||
// of processing the CRYPTO frame that was contained in this packet.
|
||||
if h.handshakePackets == nil {
|
||||
return nil
|
||||
}
|
||||
return h.handshakePackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
|
||||
case protocol.Encryption0RTT:
|
||||
if h.lowest1RTTPacket != protocol.InvalidPacketNumber && pn > h.lowest1RTTPacket {
|
||||
return fmt.Errorf("received packet number %d on a 0-RTT packet after receiving %d on a 1-RTT packet", pn, h.lowest1RTTPacket)
|
||||
}
|
||||
return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
|
||||
case protocol.Encryption1RTT:
|
||||
if h.lowest1RTTPacket == protocol.InvalidPacketNumber || pn < h.lowest1RTTPacket {
|
||||
h.lowest1RTTPacket = pn
|
||||
}
|
||||
if err := h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck); err != nil {
|
||||
if err := h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting); err != nil {
|
||||
return err
|
||||
}
|
||||
h.appDataPackets.IgnoreBelow(h.sentPackets.GetLowestPacketNotConfirmedAcked())
|
||||
|
||||
64
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
generated
vendored
64
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
generated
vendored
@@ -13,10 +13,10 @@ import (
|
||||
const packetsBeforeAck = 2
|
||||
|
||||
type receivedPacketTracker struct {
|
||||
largestObserved protocol.PacketNumber
|
||||
ignoreBelow protocol.PacketNumber
|
||||
largestObservedReceivedTime time.Time
|
||||
ect0, ect1, ecnce uint64
|
||||
largestObserved protocol.PacketNumber
|
||||
ignoreBelow protocol.PacketNumber
|
||||
largestObservedRcvdTime time.Time
|
||||
ect0, ect1, ecnce uint64
|
||||
|
||||
packetHistory *receivedPacketHistory
|
||||
|
||||
@@ -45,25 +45,23 @@ func newReceivedPacketTracker(
|
||||
}
|
||||
}
|
||||
|
||||
func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, shouldInstigateAck bool) error {
|
||||
if isNew := h.packetHistory.ReceivedPacket(packetNumber); !isNew {
|
||||
return fmt.Errorf("recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", packetNumber)
|
||||
func (h *receivedPacketTracker) ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, ackEliciting bool) error {
|
||||
if isNew := h.packetHistory.ReceivedPacket(pn); !isNew {
|
||||
return fmt.Errorf("recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", pn)
|
||||
}
|
||||
|
||||
isMissing := h.isMissing(packetNumber)
|
||||
if packetNumber >= h.largestObserved {
|
||||
h.largestObserved = packetNumber
|
||||
h.largestObservedReceivedTime = rcvTime
|
||||
isMissing := h.isMissing(pn)
|
||||
if pn >= h.largestObserved {
|
||||
h.largestObserved = pn
|
||||
h.largestObservedRcvdTime = rcvTime
|
||||
}
|
||||
|
||||
if shouldInstigateAck {
|
||||
if ackEliciting {
|
||||
h.hasNewAck = true
|
||||
h.maybeQueueACK(pn, rcvTime, ecn, isMissing)
|
||||
}
|
||||
if shouldInstigateAck {
|
||||
h.maybeQueueAck(packetNumber, rcvTime, isMissing)
|
||||
}
|
||||
//nolint:exhaustive // Only need to count ECT(0), ECT(1) and ECN-CE.
|
||||
switch ecn {
|
||||
case protocol.ECNNon:
|
||||
case protocol.ECT0:
|
||||
h.ect0++
|
||||
case protocol.ECT1:
|
||||
@@ -76,14 +74,14 @@ func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumbe
|
||||
|
||||
// IgnoreBelow sets a lower limit for acknowledging packets.
|
||||
// Packets with packet numbers smaller than p will not be acked.
|
||||
func (h *receivedPacketTracker) IgnoreBelow(p protocol.PacketNumber) {
|
||||
if p <= h.ignoreBelow {
|
||||
func (h *receivedPacketTracker) IgnoreBelow(pn protocol.PacketNumber) {
|
||||
if pn <= h.ignoreBelow {
|
||||
return
|
||||
}
|
||||
h.ignoreBelow = p
|
||||
h.packetHistory.DeleteBelow(p)
|
||||
h.ignoreBelow = pn
|
||||
h.packetHistory.DeleteBelow(pn)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tIgnoring all packets below %d.", p)
|
||||
h.logger.Debugf("\tIgnoring all packets below %d.", pn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +101,8 @@ func (h *receivedPacketTracker) hasNewMissingPackets() bool {
|
||||
return highestRange.Smallest > h.lastAck.LargestAcked()+1 && highestRange.Len() == 1
|
||||
}
|
||||
|
||||
// maybeQueueAck queues an ACK, if necessary.
|
||||
func (h *receivedPacketTracker) maybeQueueAck(pn protocol.PacketNumber, rcvTime time.Time, wasMissing bool) {
|
||||
// maybeQueueACK queues an ACK, if necessary.
|
||||
func (h *receivedPacketTracker) maybeQueueACK(pn protocol.PacketNumber, rcvTime time.Time, ecn protocol.ECN, wasMissing bool) {
|
||||
// always acknowledge the first packet
|
||||
if h.lastAck == nil {
|
||||
if !h.ackQueued {
|
||||
@@ -143,12 +141,18 @@ func (h *receivedPacketTracker) maybeQueueAck(pn protocol.PacketNumber, rcvTime
|
||||
h.ackAlarm = rcvTime.Add(h.maxAckDelay)
|
||||
}
|
||||
|
||||
// Queue an ACK if there are new missing packets to report.
|
||||
// queue an ACK if there are new missing packets to report
|
||||
if h.hasNewMissingPackets() {
|
||||
h.logger.Debugf("\tQueuing ACK because there's a new missing packet to report.")
|
||||
h.ackQueued = true
|
||||
}
|
||||
|
||||
// queue an ACK if the packet was ECN-CE marked
|
||||
if ecn == protocol.ECNCE {
|
||||
h.logger.Debugf("\tQueuing ACK because the packet was ECN-CE marked.")
|
||||
h.ackQueued = true
|
||||
}
|
||||
|
||||
if h.ackQueued {
|
||||
// cancel the ack alarm
|
||||
h.ackAlarm = time.Time{}
|
||||
@@ -169,16 +173,18 @@ func (h *receivedPacketTracker) GetAckFrame(onlyIfQueued bool) *wire.AckFrame {
|
||||
}
|
||||
}
|
||||
|
||||
ack := wire.GetAckFrame()
|
||||
ack.DelayTime = utils.Max(0, now.Sub(h.largestObservedReceivedTime))
|
||||
// This function always returns the same ACK frame struct, filled with the most recent values.
|
||||
ack := h.lastAck
|
||||
if ack == nil {
|
||||
ack = &wire.AckFrame{}
|
||||
}
|
||||
ack.Reset()
|
||||
ack.DelayTime = utils.Max(0, now.Sub(h.largestObservedRcvdTime))
|
||||
ack.ECT0 = h.ect0
|
||||
ack.ECT1 = h.ect1
|
||||
ack.ECNCE = h.ecnce
|
||||
ack.AckRanges = h.packetHistory.AppendAckRanges(ack.AckRanges)
|
||||
|
||||
if h.lastAck != nil {
|
||||
wire.PutAckFrame(h.lastAck)
|
||||
}
|
||||
h.lastAck = ack
|
||||
h.ackAlarm = time.Time{}
|
||||
h.ackQueued = false
|
||||
|
||||
6
vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go
generated
vendored
@@ -16,6 +16,10 @@ const (
|
||||
SendPTOHandshake
|
||||
// SendPTOAppData means that an Application data probe packet should be sent
|
||||
SendPTOAppData
|
||||
// SendPacingLimited means that the pacer doesn't allow sending of a packet right now,
|
||||
// but will do in a little while.
|
||||
// The timestamp when sending is allowed again can be obtained via the SentPacketHandler.TimeUntilSend.
|
||||
SendPacingLimited
|
||||
// SendAny means that any packet should be sent
|
||||
SendAny
|
||||
)
|
||||
@@ -34,6 +38,8 @@ func (s SendMode) String() string {
|
||||
return "pto (Application Data)"
|
||||
case SendAny:
|
||||
return "any"
|
||||
case SendPacingLimited:
|
||||
return "pacing limited"
|
||||
default:
|
||||
return fmt.Sprintf("invalid send mode: %d", s)
|
||||
}
|
||||
|
||||
329
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
329
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
@@ -38,7 +38,7 @@ type packetNumberSpace struct {
|
||||
largestSent protocol.PacketNumber
|
||||
}
|
||||
|
||||
func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStats *utils.RTTStats) *packetNumberSpace {
|
||||
func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool) *packetNumberSpace {
|
||||
var pns packetNumberGenerator
|
||||
if skipPNs {
|
||||
pns = newSkippingPacketNumberGenerator(initialPN, protocol.SkipPacketInitialPeriod, protocol.SkipPacketMaxPeriod)
|
||||
@@ -46,7 +46,7 @@ func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStat
|
||||
pns = newSequentialPacketNumberGenerator(initialPN)
|
||||
}
|
||||
return &packetNumberSpace{
|
||||
history: newSentPacketHistory(rttStats),
|
||||
history: newSentPacketHistory(),
|
||||
pns: pns,
|
||||
largestSent: protocol.InvalidPacketNumber,
|
||||
largestAcked: protocol.InvalidPacketNumber,
|
||||
@@ -75,7 +75,7 @@ type sentPacketHandler struct {
|
||||
// Only applies to the application-data packet number space.
|
||||
lowestNotConfirmedAcked protocol.PacketNumber
|
||||
|
||||
ackedPackets []*Packet // to avoid allocations in detectAndRemoveAckedPackets
|
||||
ackedPackets []*packet // to avoid allocations in detectAndRemoveAckedPackets
|
||||
|
||||
bytesInFlight protocol.ByteCount
|
||||
|
||||
@@ -92,9 +92,12 @@ type sentPacketHandler struct {
|
||||
// The alarm timeout
|
||||
alarm time.Time
|
||||
|
||||
enableECN bool
|
||||
ecnTracker ecnHandler
|
||||
|
||||
perspective protocol.Perspective
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
@@ -110,8 +113,9 @@ func newSentPacketHandler(
|
||||
initialMaxDatagramSize protocol.ByteCount,
|
||||
rttStats *utils.RTTStats,
|
||||
clientAddressValidated bool,
|
||||
enableECN bool,
|
||||
pers protocol.Perspective,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
) *sentPacketHandler {
|
||||
congestion := congestion.NewCubicSender(
|
||||
@@ -122,31 +126,26 @@ func newSentPacketHandler(
|
||||
tracer,
|
||||
)
|
||||
|
||||
return &sentPacketHandler{
|
||||
h := &sentPacketHandler{
|
||||
peerCompletedAddressValidation: pers == protocol.PerspectiveServer,
|
||||
peerAddressValidated: pers == protocol.PerspectiveClient || clientAddressValidated,
|
||||
initialPackets: newPacketNumberSpace(initialPN, false, rttStats),
|
||||
handshakePackets: newPacketNumberSpace(0, false, rttStats),
|
||||
appDataPackets: newPacketNumberSpace(0, true, rttStats),
|
||||
initialPackets: newPacketNumberSpace(initialPN, false),
|
||||
handshakePackets: newPacketNumberSpace(0, false),
|
||||
appDataPackets: newPacketNumberSpace(0, true),
|
||||
rttStats: rttStats,
|
||||
congestion: congestion,
|
||||
perspective: pers,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
|
||||
if h.perspective == protocol.PerspectiveClient && encLevel == protocol.EncryptionInitial {
|
||||
// This function is called when the crypto setup seals a Handshake packet.
|
||||
// If this Handshake packet is coalesced behind an Initial packet, we would drop the Initial packet number space
|
||||
// before SentPacket() was called for that Initial packet.
|
||||
return
|
||||
if enableECN {
|
||||
h.enableECN = true
|
||||
h.ecnTracker = newECNTracker(logger, tracer)
|
||||
}
|
||||
h.dropPackets(encLevel)
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) removeFromBytesInFlight(p *Packet) {
|
||||
func (h *sentPacketHandler) removeFromBytesInFlight(p *packet) {
|
||||
if p.includedInBytesInFlight {
|
||||
if p.Length > h.bytesInFlight {
|
||||
panic("negative bytes_in_flight")
|
||||
@@ -156,7 +155,7 @@ func (h *sentPacketHandler) removeFromBytesInFlight(p *Packet) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
|
||||
// The server won't await address validation after the handshake is confirmed.
|
||||
// This applies even if we didn't receive an ACK for a Handshake packet.
|
||||
if h.perspective == protocol.PerspectiveClient && encLevel == protocol.EncryptionHandshake {
|
||||
@@ -165,7 +164,11 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
// remove outstanding packets from bytes_in_flight
|
||||
if encLevel == protocol.EncryptionInitial || encLevel == protocol.EncryptionHandshake {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
pnSpace.history.Iterate(func(p *Packet) (bool, error) {
|
||||
// We might already have dropped this packet number space.
|
||||
if pnSpace == nil {
|
||||
return
|
||||
}
|
||||
pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
||||
h.removeFromBytesInFlight(p)
|
||||
return true, nil
|
||||
})
|
||||
@@ -182,8 +185,8 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
// and not when the client drops 0-RTT keys when the handshake completes.
|
||||
// When 0-RTT is rejected, all application data sent so far becomes invalid.
|
||||
// Delete the packets from the history and remove them from bytes_in_flight.
|
||||
h.appDataPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
if p.EncryptionLevel != protocol.Encryption0RTT {
|
||||
h.appDataPackets.history.Iterate(func(p *packet) (bool, error) {
|
||||
if p.EncryptionLevel != protocol.Encryption0RTT && !p.skippedPacket {
|
||||
return false, nil
|
||||
}
|
||||
h.removeFromBytesInFlight(p)
|
||||
@@ -193,7 +196,7 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
default:
|
||||
panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
|
||||
}
|
||||
if h.tracer != nil && h.ptoCount != 0 {
|
||||
if h.tracer != nil && h.tracer.UpdatedPTOCount != nil && h.ptoCount != 0 {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
}
|
||||
h.ptoCount = 0
|
||||
@@ -228,26 +231,65 @@ func (h *sentPacketHandler) packetsInFlight() int {
|
||||
return packetsInFlight
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SentPacket(p *Packet) {
|
||||
h.bytesSent += p.Length
|
||||
// For the client, drop the Initial packet number space when the first Handshake packet is sent.
|
||||
if h.perspective == protocol.PerspectiveClient && p.EncryptionLevel == protocol.EncryptionHandshake && h.initialPackets != nil {
|
||||
h.dropPackets(protocol.EncryptionInitial)
|
||||
func (h *sentPacketHandler) SentPacket(
|
||||
t time.Time,
|
||||
pn, largestAcked protocol.PacketNumber,
|
||||
streamFrames []StreamFrame,
|
||||
frames []Frame,
|
||||
encLevel protocol.EncryptionLevel,
|
||||
ecn protocol.ECN,
|
||||
size protocol.ByteCount,
|
||||
isPathMTUProbePacket bool,
|
||||
) {
|
||||
h.bytesSent += size
|
||||
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
if h.logger.Debug() && pnSpace.history.HasOutstandingPackets() {
|
||||
for p := utils.Max(0, pnSpace.largestSent+1); p < pn; p++ {
|
||||
h.logger.Debugf("Skipping packet number %d", p)
|
||||
}
|
||||
}
|
||||
isAckEliciting := h.sentPacketImpl(p)
|
||||
|
||||
pnSpace.largestSent = pn
|
||||
isAckEliciting := len(streamFrames) > 0 || len(frames) > 0
|
||||
|
||||
if isAckEliciting {
|
||||
h.getPacketNumberSpace(p.EncryptionLevel).history.SentAckElicitingPacket(p)
|
||||
} else {
|
||||
h.getPacketNumberSpace(p.EncryptionLevel).history.SentNonAckElicitingPacket(p.PacketNumber, p.EncryptionLevel, p.SendTime)
|
||||
putPacket(p)
|
||||
p = nil //nolint:ineffassign // This is just to be on the safe side.
|
||||
pnSpace.lastAckElicitingPacketTime = t
|
||||
h.bytesInFlight += size
|
||||
if h.numProbesToSend > 0 {
|
||||
h.numProbesToSend--
|
||||
}
|
||||
}
|
||||
if h.tracer != nil && isAckEliciting {
|
||||
h.congestion.OnPacketSent(t, h.bytesInFlight, pn, size, isAckEliciting)
|
||||
|
||||
if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil {
|
||||
h.ecnTracker.SentPacket(pn, ecn)
|
||||
}
|
||||
|
||||
if !isAckEliciting {
|
||||
pnSpace.history.SentNonAckElicitingPacket(pn)
|
||||
if !h.peerCompletedAddressValidation {
|
||||
h.setLossDetectionTimer()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
p := getPacket()
|
||||
p.SendTime = t
|
||||
p.PacketNumber = pn
|
||||
p.EncryptionLevel = encLevel
|
||||
p.Length = size
|
||||
p.LargestAcked = largestAcked
|
||||
p.StreamFrames = streamFrames
|
||||
p.Frames = frames
|
||||
p.IsPathMTUProbePacket = isPathMTUProbePacket
|
||||
p.includedInBytesInFlight = true
|
||||
|
||||
pnSpace.history.SentAckElicitingPacket(p)
|
||||
if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
|
||||
h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
|
||||
}
|
||||
if isAckEliciting || !h.peerCompletedAddressValidation {
|
||||
h.setLossDetectionTimer()
|
||||
}
|
||||
h.setLossDetectionTimer()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLevel) *packetNumberSpace {
|
||||
@@ -263,31 +305,6 @@ func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLev
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* is ack-eliciting */ {
|
||||
pnSpace := h.getPacketNumberSpace(packet.EncryptionLevel)
|
||||
|
||||
if h.logger.Debug() && pnSpace.history.HasOutstandingPackets() {
|
||||
for p := utils.Max(0, pnSpace.largestSent+1); p < packet.PacketNumber; p++ {
|
||||
h.logger.Debugf("Skipping packet number %d", p)
|
||||
}
|
||||
}
|
||||
|
||||
pnSpace.largestSent = packet.PacketNumber
|
||||
isAckEliciting := len(packet.Frames) > 0
|
||||
|
||||
if isAckEliciting {
|
||||
pnSpace.lastAckElicitingPacketTime = packet.SendTime
|
||||
packet.includedInBytesInFlight = true
|
||||
h.bytesInFlight += packet.Length
|
||||
if h.numProbesToSend > 0 {
|
||||
h.numProbesToSend--
|
||||
}
|
||||
}
|
||||
h.congestion.OnPacketSent(packet.SendTime, h.bytesInFlight, packet.PacketNumber, packet.Length, isAckEliciting)
|
||||
|
||||
return isAckEliciting
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) (bool /* contained 1-RTT packet */, error) {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
|
||||
@@ -299,8 +316,6 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||
}
|
||||
}
|
||||
|
||||
pnSpace.largestAcked = utils.Max(pnSpace.largestAcked, largestAcked)
|
||||
|
||||
// Servers complete address validation when a protected packet is received.
|
||||
if h.perspective == protocol.PerspectiveClient && !h.peerCompletedAddressValidation &&
|
||||
(encLevel == protocol.EncryptionHandshake || encLevel == protocol.Encryption1RTT) {
|
||||
@@ -330,6 +345,17 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||
h.congestion.MaybeExitSlowStart()
|
||||
}
|
||||
}
|
||||
|
||||
// Only inform the ECN tracker about new 1-RTT ACKs if the ACK increases the largest acked.
|
||||
if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil && largestAcked > pnSpace.largestAcked {
|
||||
congested := h.ecnTracker.HandleNewlyAcked(ackedPackets, int64(ack.ECT0), int64(ack.ECT1), int64(ack.ECNCE))
|
||||
if congested {
|
||||
h.congestion.OnCongestionEvent(largestAcked, 0, priorInFlight)
|
||||
}
|
||||
}
|
||||
|
||||
pnSpace.largestAcked = utils.Max(pnSpace.largestAcked, largestAcked)
|
||||
|
||||
if err := h.detectLostPackets(rcvTime, encLevel); err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -350,18 +376,17 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||
|
||||
// Reset the pto_count unless the client is unsure if the server has validated the client's address.
|
||||
if h.peerCompletedAddressValidation {
|
||||
if h.tracer != nil && h.ptoCount != 0 {
|
||||
if h.tracer != nil && h.tracer.UpdatedPTOCount != nil && h.ptoCount != 0 {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
}
|
||||
h.ptoCount = 0
|
||||
}
|
||||
h.numProbesToSend = 0
|
||||
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
|
||||
h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
|
||||
}
|
||||
|
||||
pnSpace.history.DeleteOldPackets(rcvTime)
|
||||
h.setLossDetectionTimer()
|
||||
return acked1RTTPacket, nil
|
||||
}
|
||||
@@ -371,13 +396,13 @@ func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNu
|
||||
}
|
||||
|
||||
// Packets are returned in ascending packet number order.
|
||||
func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encLevel protocol.EncryptionLevel) ([]*Packet, error) {
|
||||
func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encLevel protocol.EncryptionLevel) ([]*packet, error) {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
h.ackedPackets = h.ackedPackets[:0]
|
||||
ackRangeIndex := 0
|
||||
lowestAcked := ack.LowestAcked()
|
||||
largestAcked := ack.LargestAcked()
|
||||
err := pnSpace.history.Iterate(func(p *Packet) (bool, error) {
|
||||
err := pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
||||
// Ignore packets below the lowest acked
|
||||
if p.PacketNumber < lowestAcked {
|
||||
return true, nil
|
||||
@@ -425,14 +450,19 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
|
||||
}
|
||||
|
||||
for _, f := range p.Frames {
|
||||
if f.OnAcked != nil {
|
||||
f.OnAcked(f.Frame)
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnAcked(f.Frame)
|
||||
}
|
||||
}
|
||||
for _, f := range p.StreamFrames {
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnAcked(f.Frame)
|
||||
}
|
||||
}
|
||||
if err := pnSpace.history.Remove(p.PacketNumber); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.AcknowledgedPacket != nil {
|
||||
h.tracer.AcknowledgedPacket(encLevel, p.PacketNumber)
|
||||
}
|
||||
}
|
||||
@@ -525,7 +555,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
if !lossTime.IsZero() {
|
||||
// Early retransmit timer or time loss detection.
|
||||
h.alarm = lossTime
|
||||
if h.tracer != nil && h.alarm != oldAlarm {
|
||||
if h.tracer != nil && h.tracer.SetLossTimer != nil && h.alarm != oldAlarm {
|
||||
h.tracer.SetLossTimer(logging.TimerTypeACK, encLevel, h.alarm)
|
||||
}
|
||||
return
|
||||
@@ -536,7 +566,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
h.alarm = time.Time{}
|
||||
if !oldAlarm.IsZero() {
|
||||
h.logger.Debugf("Canceling loss detection timer. Amplification limited.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
@@ -548,7 +578,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
h.alarm = time.Time{}
|
||||
if !oldAlarm.IsZero() {
|
||||
h.logger.Debugf("Canceling loss detection timer. No packets in flight.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
@@ -561,14 +591,14 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
if !oldAlarm.IsZero() {
|
||||
h.alarm = time.Time{}
|
||||
h.logger.Debugf("Canceling loss detection timer. No PTO needed..")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
h.alarm = ptoTime
|
||||
if h.tracer != nil && h.alarm != oldAlarm {
|
||||
if h.tracer != nil && h.tracer.SetLossTimer != nil && h.alarm != oldAlarm {
|
||||
h.tracer.SetLossTimer(logging.TimerTypePTO, encLevel, h.alarm)
|
||||
}
|
||||
}
|
||||
@@ -587,30 +617,31 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||
lostSendTime := now.Add(-lossDelay)
|
||||
|
||||
priorInFlight := h.bytesInFlight
|
||||
return pnSpace.history.Iterate(func(p *Packet) (bool, error) {
|
||||
return pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
||||
if p.PacketNumber > pnSpace.largestAcked {
|
||||
return false, nil
|
||||
}
|
||||
if p.declaredLost || p.skippedPacket {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var packetLost bool
|
||||
if p.SendTime.Before(lostSendTime) {
|
||||
packetLost = true
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (time threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossTimeThreshold)
|
||||
if !p.skippedPacket {
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (time threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil && h.tracer.LostPacket != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossTimeThreshold)
|
||||
}
|
||||
}
|
||||
} else if pnSpace.largestAcked >= p.PacketNumber+packetThreshold {
|
||||
packetLost = true
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (reordering threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossReorderingThreshold)
|
||||
if !p.skippedPacket {
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (reordering threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil && h.tracer.LostPacket != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossReorderingThreshold)
|
||||
}
|
||||
}
|
||||
} else if pnSpace.lossTime.IsZero() {
|
||||
// Note: This conditional is only entered once per call
|
||||
@@ -621,12 +652,17 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||
pnSpace.lossTime = lossTime
|
||||
}
|
||||
if packetLost {
|
||||
p = pnSpace.history.DeclareLost(p)
|
||||
// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
|
||||
h.removeFromBytesInFlight(p)
|
||||
h.queueFramesForRetransmission(p)
|
||||
if !p.IsPathMTUProbePacket {
|
||||
h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight)
|
||||
pnSpace.history.DeclareLost(p.PacketNumber)
|
||||
if !p.skippedPacket {
|
||||
// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
|
||||
h.removeFromBytesInFlight(p)
|
||||
h.queueFramesForRetransmission(p)
|
||||
if !p.IsPathMTUProbePacket {
|
||||
h.congestion.OnCongestionEvent(p.PacketNumber, p.Length, priorInFlight)
|
||||
}
|
||||
if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil {
|
||||
h.ecnTracker.LostPacket(p.PacketNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
@@ -640,7 +676,7 @@ func (h *sentPacketHandler) OnLossDetectionTimeout() error {
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", earliestLossTime)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerExpired != nil {
|
||||
h.tracer.LossTimerExpired(logging.TimerTypeACK, encLevel)
|
||||
}
|
||||
// Early retransmit or time loss detection
|
||||
@@ -677,8 +713,12 @@ func (h *sentPacketHandler) OnLossDetectionTimeout() error {
|
||||
h.logger.Debugf("Loss detection alarm for %s fired in PTO mode. PTO count: %d", encLevel, h.ptoCount)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.LossTimerExpired(logging.TimerTypePTO, encLevel)
|
||||
h.tracer.UpdatedPTOCount(h.ptoCount)
|
||||
if h.tracer.LossTimerExpired != nil {
|
||||
h.tracer.LossTimerExpired(logging.TimerTypePTO, encLevel)
|
||||
}
|
||||
if h.tracer.UpdatedPTOCount != nil {
|
||||
h.tracer.UpdatedPTOCount(h.ptoCount)
|
||||
}
|
||||
}
|
||||
h.numProbesToSend += 2
|
||||
//nolint:exhaustive // We never arm a PTO timer for 0-RTT packets.
|
||||
@@ -689,7 +729,8 @@ func (h *sentPacketHandler) OnLossDetectionTimeout() error {
|
||||
h.ptoMode = SendPTOHandshake
|
||||
case protocol.Encryption1RTT:
|
||||
// skip a packet number in order to elicit an immediate ACK
|
||||
_ = h.PopPacketNumber(protocol.Encryption1RTT)
|
||||
pn := h.PopPacketNumber(protocol.Encryption1RTT)
|
||||
h.getPacketNumberSpace(protocol.Encryption1RTT).history.SkippedPacket(pn)
|
||||
h.ptoMode = SendPTOAppData
|
||||
default:
|
||||
return fmt.Errorf("PTO timer in unexpected encryption level: %s", encLevel)
|
||||
@@ -701,25 +742,37 @@ func (h *sentPacketHandler) GetLossDetectionTimeout() time.Time {
|
||||
return h.alarm
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ECNMode(isShortHeaderPacket bool) protocol.ECN {
|
||||
if !h.enableECN {
|
||||
return protocol.ECNUnsupported
|
||||
}
|
||||
if !isShortHeaderPacket {
|
||||
return protocol.ECNNon
|
||||
}
|
||||
return h.ecnTracker.Mode()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) PeekPacketNumber(encLevel protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen) {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
|
||||
var lowestUnacked protocol.PacketNumber
|
||||
if p := pnSpace.history.FirstOutstanding(); p != nil {
|
||||
lowestUnacked = p.PacketNumber
|
||||
} else {
|
||||
lowestUnacked = pnSpace.largestAcked + 1
|
||||
}
|
||||
|
||||
pn := pnSpace.pns.Peek()
|
||||
return pn, protocol.GetPacketNumberLengthForHeader(pn, lowestUnacked)
|
||||
// See section 17.1 of RFC 9000.
|
||||
return pn, protocol.GetPacketNumberLengthForHeader(pn, pnSpace.largestAcked)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) PopPacketNumber(encLevel protocol.EncryptionLevel) protocol.PacketNumber {
|
||||
return h.getPacketNumberSpace(encLevel).pns.Pop()
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
skipped, pn := pnSpace.pns.Pop()
|
||||
if skipped {
|
||||
skippedPN := pn - 1
|
||||
pnSpace.history.SkippedPacket(skippedPN)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Skipping packet number %d", skippedPN)
|
||||
}
|
||||
}
|
||||
return pn
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SendMode() SendMode {
|
||||
func (h *sentPacketHandler) SendMode(now time.Time) SendMode {
|
||||
numTrackedPackets := h.appDataPackets.history.Len()
|
||||
if h.initialPackets != nil {
|
||||
numTrackedPackets += h.initialPackets.history.Len()
|
||||
@@ -758,6 +811,9 @@ func (h *sentPacketHandler) SendMode() SendMode {
|
||||
}
|
||||
return SendAck
|
||||
}
|
||||
if !h.congestion.HasPacingBudget(now) {
|
||||
return SendPacingLimited
|
||||
}
|
||||
return SendAny
|
||||
}
|
||||
|
||||
@@ -765,10 +821,6 @@ func (h *sentPacketHandler) TimeUntilSend() time.Time {
|
||||
return h.congestion.TimeUntilSend(h.bytesInFlight)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) HasPacingBudget() bool {
|
||||
return h.congestion.HasPacingBudget()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SetMaxDatagramSize(s protocol.ByteCount) {
|
||||
h.congestion.SetMaxDatagramSize(s)
|
||||
}
|
||||
@@ -790,24 +842,32 @@ func (h *sentPacketHandler) QueueProbePacket(encLevel protocol.EncryptionLevel)
|
||||
// TODO: don't declare the packet lost here.
|
||||
// Keep track of acknowledged frames instead.
|
||||
h.removeFromBytesInFlight(p)
|
||||
pnSpace.history.DeclareLost(p)
|
||||
pnSpace.history.DeclareLost(p.PacketNumber)
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) queueFramesForRetransmission(p *Packet) {
|
||||
if len(p.Frames) == 0 {
|
||||
func (h *sentPacketHandler) queueFramesForRetransmission(p *packet) {
|
||||
if len(p.Frames) == 0 && len(p.StreamFrames) == 0 {
|
||||
panic("no frames")
|
||||
}
|
||||
for _, f := range p.Frames {
|
||||
f.OnLost(f.Frame)
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnLost(f.Frame)
|
||||
}
|
||||
}
|
||||
for _, f := range p.StreamFrames {
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnLost(f.Frame)
|
||||
}
|
||||
}
|
||||
p.StreamFrames = nil
|
||||
p.Frames = nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ResetForRetry() error {
|
||||
func (h *sentPacketHandler) ResetForRetry(now time.Time) error {
|
||||
h.bytesInFlight = 0
|
||||
var firstPacketSendTime time.Time
|
||||
h.initialPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
h.initialPackets.history.Iterate(func(p *packet) (bool, error) {
|
||||
if firstPacketSendTime.IsZero() {
|
||||
firstPacketSendTime = p.SendTime
|
||||
}
|
||||
@@ -819,7 +879,7 @@ func (h *sentPacketHandler) ResetForRetry() error {
|
||||
})
|
||||
// All application data packets sent at this point are 0-RTT packets.
|
||||
// In the case of a Retry, we can assume that the server dropped all of them.
|
||||
h.appDataPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
h.appDataPackets.history.Iterate(func(p *packet) (bool, error) {
|
||||
if !p.declaredLost && !p.skippedPacket {
|
||||
h.queueFramesForRetransmission(p)
|
||||
}
|
||||
@@ -830,22 +890,23 @@ func (h *sentPacketHandler) ResetForRetry() error {
|
||||
// Otherwise, we don't know which Initial the Retry was sent in response to.
|
||||
if h.ptoCount == 0 {
|
||||
// Don't set the RTT to a value lower than 5ms here.
|
||||
now := time.Now()
|
||||
h.rttStats.UpdateRTT(utils.Max(minRTTAfterRetry, now.Sub(firstPacketSendTime)), 0, now)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
|
||||
h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
|
||||
}
|
||||
}
|
||||
h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Pop(), false, h.rttStats)
|
||||
h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Pop(), true, h.rttStats)
|
||||
h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Peek(), false)
|
||||
h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Peek(), true)
|
||||
oldAlarm := h.alarm
|
||||
h.alarm = time.Time{}
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
if !oldAlarm.IsZero() {
|
||||
if h.tracer.UpdatedPTOCount != nil {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
}
|
||||
if !oldAlarm.IsZero() && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
@@ -854,6 +915,12 @@ func (h *sentPacketHandler) ResetForRetry() error {
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SetHandshakeConfirmed() {
|
||||
if h.initialPackets != nil {
|
||||
panic("didn't drop initial correctly")
|
||||
}
|
||||
if h.handshakePackets != nil {
|
||||
panic("didn't drop handshake correctly")
|
||||
}
|
||||
h.handshakeConfirmed = true
|
||||
// We don't send PTOs for application data packets before the handshake completes.
|
||||
// Make sure the timer is armed now, if necessary.
|
||||
|
||||
248
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
248
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
@@ -2,162 +2,176 @@ package ackhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
list "github.com/quic-go/quic-go/internal/utils/linkedlist"
|
||||
)
|
||||
|
||||
type sentPacketHistory struct {
|
||||
rttStats *utils.RTTStats
|
||||
outstandingPacketList *list.List[*Packet]
|
||||
etcPacketList *list.List[*Packet]
|
||||
packetMap map[protocol.PacketNumber]*list.Element[*Packet]
|
||||
highestSent protocol.PacketNumber
|
||||
packets []*packet
|
||||
|
||||
numOutstanding int
|
||||
|
||||
highestPacketNumber protocol.PacketNumber
|
||||
}
|
||||
|
||||
var packetElementPool sync.Pool
|
||||
|
||||
func init() {
|
||||
packetElementPool = *list.NewPool[*Packet]()
|
||||
}
|
||||
|
||||
func newSentPacketHistory(rttStats *utils.RTTStats) *sentPacketHistory {
|
||||
func newSentPacketHistory() *sentPacketHistory {
|
||||
return &sentPacketHistory{
|
||||
rttStats: rttStats,
|
||||
outstandingPacketList: list.NewWithPool[*Packet](&packetElementPool),
|
||||
etcPacketList: list.NewWithPool[*Packet](&packetElementPool),
|
||||
packetMap: make(map[protocol.PacketNumber]*list.Element[*Packet]),
|
||||
highestSent: protocol.InvalidPacketNumber,
|
||||
packets: make([]*packet, 0, 32),
|
||||
highestPacketNumber: protocol.InvalidPacketNumber,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, t time.Time) {
|
||||
h.registerSentPacket(pn, encLevel, t)
|
||||
func (h *sentPacketHistory) checkSequentialPacketNumberUse(pn protocol.PacketNumber) {
|
||||
if h.highestPacketNumber != protocol.InvalidPacketNumber {
|
||||
if pn != h.highestPacketNumber+1 {
|
||||
panic("non-sequential packet number use")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentAckElicitingPacket(p *Packet) {
|
||||
h.registerSentPacket(p.PacketNumber, p.EncryptionLevel, p.SendTime)
|
||||
func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
|
||||
h.checkSequentialPacketNumberUse(pn)
|
||||
h.highestPacketNumber = pn
|
||||
h.packets = append(h.packets, &packet{
|
||||
PacketNumber: pn,
|
||||
skippedPacket: true,
|
||||
})
|
||||
}
|
||||
|
||||
var el *list.Element[*Packet]
|
||||
func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber) {
|
||||
h.checkSequentialPacketNumberUse(pn)
|
||||
h.highestPacketNumber = pn
|
||||
if len(h.packets) > 0 {
|
||||
h.packets = append(h.packets, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentAckElicitingPacket(p *packet) {
|
||||
h.checkSequentialPacketNumberUse(p.PacketNumber)
|
||||
h.highestPacketNumber = p.PacketNumber
|
||||
h.packets = append(h.packets, p)
|
||||
if p.outstanding() {
|
||||
el = h.outstandingPacketList.PushBack(p)
|
||||
} else {
|
||||
el = h.etcPacketList.PushBack(p)
|
||||
h.numOutstanding++
|
||||
}
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) registerSentPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, t time.Time) {
|
||||
if pn <= h.highestSent {
|
||||
panic("non-sequential packet number use")
|
||||
}
|
||||
// Skipped packet numbers.
|
||||
for p := h.highestSent + 1; p < pn; p++ {
|
||||
el := h.etcPacketList.PushBack(&Packet{
|
||||
PacketNumber: p,
|
||||
EncryptionLevel: encLevel,
|
||||
SendTime: t,
|
||||
skippedPacket: true,
|
||||
})
|
||||
h.packetMap[p] = el
|
||||
}
|
||||
h.highestSent = pn
|
||||
}
|
||||
|
||||
// Iterate iterates through all packets.
|
||||
func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) error {
|
||||
cont := true
|
||||
outstandingEl := h.outstandingPacketList.Front()
|
||||
etcEl := h.etcPacketList.Front()
|
||||
var el *list.Element[*Packet]
|
||||
// whichever has the next packet number is returned first
|
||||
for cont {
|
||||
if outstandingEl == nil || (etcEl != nil && etcEl.Value.PacketNumber < outstandingEl.Value.PacketNumber) {
|
||||
el = etcEl
|
||||
} else {
|
||||
el = outstandingEl
|
||||
func (h *sentPacketHistory) Iterate(cb func(*packet) (cont bool, err error)) error {
|
||||
for _, p := range h.packets {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
if el == nil {
|
||||
return nil
|
||||
}
|
||||
if el == outstandingEl {
|
||||
outstandingEl = outstandingEl.Next()
|
||||
} else {
|
||||
etcEl = etcEl.Next()
|
||||
}
|
||||
var err error
|
||||
cont, err = cb(el.Value)
|
||||
cont, err := cb(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !cont {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FirstOutstanding returns the first outstanding packet.
|
||||
func (h *sentPacketHistory) FirstOutstanding() *Packet {
|
||||
el := h.outstandingPacketList.Front()
|
||||
if el == nil {
|
||||
func (h *sentPacketHistory) FirstOutstanding() *packet {
|
||||
if !h.HasOutstandingPackets() {
|
||||
return nil
|
||||
}
|
||||
return el.Value
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) Len() int {
|
||||
return len(h.packetMap)
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) Remove(p protocol.PacketNumber) error {
|
||||
el, ok := h.packetMap[p]
|
||||
if !ok {
|
||||
return fmt.Errorf("packet %d not found in sent packet history", p)
|
||||
for _, p := range h.packets {
|
||||
if p != nil && p.outstanding() {
|
||||
return p
|
||||
}
|
||||
}
|
||||
el.List().Remove(el)
|
||||
delete(h.packetMap, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) HasOutstandingPackets() bool {
|
||||
return h.outstandingPacketList.Len() > 0
|
||||
func (h *sentPacketHistory) Len() int {
|
||||
return len(h.packets)
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) DeleteOldPackets(now time.Time) {
|
||||
maxAge := 3 * h.rttStats.PTO(false)
|
||||
var nextEl *list.Element[*Packet]
|
||||
// we don't iterate outstandingPacketList, as we should not delete outstanding packets.
|
||||
// being outstanding for more than 3*PTO should only happen in the case of drastic RTT changes.
|
||||
for el := h.etcPacketList.Front(); el != nil; el = nextEl {
|
||||
nextEl = el.Next()
|
||||
p := el.Value
|
||||
if p.SendTime.After(now.Add(-maxAge)) {
|
||||
break
|
||||
}
|
||||
delete(h.packetMap, p.PacketNumber)
|
||||
h.etcPacketList.Remove(el)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) DeclareLost(p *Packet) *Packet {
|
||||
el, ok := h.packetMap[p.PacketNumber]
|
||||
func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error {
|
||||
idx, ok := h.getIndex(pn)
|
||||
if !ok {
|
||||
return nil
|
||||
return fmt.Errorf("packet %d not found in sent packet history", pn)
|
||||
}
|
||||
el.List().Remove(el)
|
||||
p.declaredLost = true
|
||||
// move it to the correct position in the etc list (based on the packet number)
|
||||
for el = h.etcPacketList.Back(); el != nil; el = el.Prev() {
|
||||
if el.Value.PacketNumber < p.PacketNumber {
|
||||
break
|
||||
p := h.packets[idx]
|
||||
if p.outstanding() {
|
||||
h.numOutstanding--
|
||||
if h.numOutstanding < 0 {
|
||||
panic("negative number of outstanding packets")
|
||||
}
|
||||
}
|
||||
if el == nil {
|
||||
el = h.etcPacketList.PushFront(p)
|
||||
} else {
|
||||
el = h.etcPacketList.InsertAfter(p, el)
|
||||
h.packets[idx] = nil
|
||||
// clean up all skipped packets directly before this packet number
|
||||
for idx > 0 {
|
||||
idx--
|
||||
p := h.packets[idx]
|
||||
if p == nil || !p.skippedPacket {
|
||||
break
|
||||
}
|
||||
h.packets[idx] = nil
|
||||
}
|
||||
if idx == 0 {
|
||||
h.cleanupStart()
|
||||
}
|
||||
if len(h.packets) > 0 && h.packets[0] == nil {
|
||||
panic("remove failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getIndex gets the index of packet p in the packets slice.
|
||||
func (h *sentPacketHistory) getIndex(p protocol.PacketNumber) (int, bool) {
|
||||
if len(h.packets) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
first := h.packets[0].PacketNumber
|
||||
if p < first {
|
||||
return 0, false
|
||||
}
|
||||
index := int(p - first)
|
||||
if index > len(h.packets)-1 {
|
||||
return 0, false
|
||||
}
|
||||
return index, true
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) HasOutstandingPackets() bool {
|
||||
return h.numOutstanding > 0
|
||||
}
|
||||
|
||||
// delete all nil entries at the beginning of the packets slice
|
||||
func (h *sentPacketHistory) cleanupStart() {
|
||||
for i, p := range h.packets {
|
||||
if p != nil {
|
||||
h.packets = h.packets[i:]
|
||||
return
|
||||
}
|
||||
}
|
||||
h.packets = h.packets[:0]
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) LowestPacketNumber() protocol.PacketNumber {
|
||||
if len(h.packets) == 0 {
|
||||
return protocol.InvalidPacketNumber
|
||||
}
|
||||
return h.packets[0].PacketNumber
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) DeclareLost(pn protocol.PacketNumber) {
|
||||
idx, ok := h.getIndex(pn)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
p := h.packets[idx]
|
||||
if p.outstanding() {
|
||||
h.numOutstanding--
|
||||
if h.numOutstanding < 0 {
|
||||
panic("negative number of outstanding packets")
|
||||
}
|
||||
}
|
||||
h.packets[idx] = nil
|
||||
if idx == 0 {
|
||||
h.cleanupStart()
|
||||
}
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
return el.Value
|
||||
}
|
||||
|
||||
16
vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
generated
vendored
16
vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
generated
vendored
@@ -56,7 +56,7 @@ type cubicSender struct {
|
||||
maxDatagramSize protocol.ByteCount
|
||||
|
||||
lastState logging.CongestionState
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -70,7 +70,7 @@ func NewCubicSender(
|
||||
rttStats *utils.RTTStats,
|
||||
initialMaxDatagramSize protocol.ByteCount,
|
||||
reno bool,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
) *cubicSender {
|
||||
return newCubicSender(
|
||||
clock,
|
||||
@@ -90,7 +90,7 @@ func newCubicSender(
|
||||
initialMaxDatagramSize,
|
||||
initialCongestionWindow,
|
||||
initialMaxCongestionWindow protocol.ByteCount,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
) *cubicSender {
|
||||
c := &cubicSender{
|
||||
rttStats: rttStats,
|
||||
@@ -108,7 +108,7 @@ func newCubicSender(
|
||||
maxDatagramSize: initialMaxDatagramSize,
|
||||
}
|
||||
c.pacer = newPacer(c.BandwidthEstimate)
|
||||
if c.tracer != nil {
|
||||
if c.tracer != nil && c.tracer.UpdatedCongestionState != nil {
|
||||
c.lastState = logging.CongestionStateSlowStart
|
||||
c.tracer.UpdatedCongestionState(logging.CongestionStateSlowStart)
|
||||
}
|
||||
@@ -120,8 +120,8 @@ func (c *cubicSender) TimeUntilSend(_ protocol.ByteCount) time.Time {
|
||||
return c.pacer.TimeUntilSend()
|
||||
}
|
||||
|
||||
func (c *cubicSender) HasPacingBudget() bool {
|
||||
return c.pacer.Budget(c.clock.Now()) >= c.maxDatagramSize
|
||||
func (c *cubicSender) HasPacingBudget(now time.Time) bool {
|
||||
return c.pacer.Budget(now) >= c.maxDatagramSize
|
||||
}
|
||||
|
||||
func (c *cubicSender) maxCongestionWindow() protocol.ByteCount {
|
||||
@@ -188,7 +188,7 @@ func (c *cubicSender) OnPacketAcked(
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cubicSender) OnPacketLost(packetNumber protocol.PacketNumber, lostBytes, priorInFlight protocol.ByteCount) {
|
||||
func (c *cubicSender) OnCongestionEvent(packetNumber protocol.PacketNumber, lostBytes, priorInFlight protocol.ByteCount) {
|
||||
// TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
|
||||
// already sent should be treated as a single loss event, since it's expected.
|
||||
if packetNumber <= c.largestSentAtLastCutback {
|
||||
@@ -296,7 +296,7 @@ func (c *cubicSender) OnConnectionMigration() {
|
||||
}
|
||||
|
||||
func (c *cubicSender) maybeTraceStateChange(new logging.CongestionState) {
|
||||
if c.tracer == nil || new == c.lastState {
|
||||
if c.tracer == nil || c.tracer.UpdatedCongestionState == nil || new == c.lastState {
|
||||
return
|
||||
}
|
||||
c.tracer.UpdatedCongestionState(new)
|
||||
|
||||
4
vendor/github.com/quic-go/quic-go/internal/congestion/interface.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/internal/congestion/interface.go
generated
vendored
@@ -9,12 +9,12 @@ import (
|
||||
// A SendAlgorithm performs congestion control
|
||||
type SendAlgorithm interface {
|
||||
TimeUntilSend(bytesInFlight protocol.ByteCount) time.Time
|
||||
HasPacingBudget() bool
|
||||
HasPacingBudget(now time.Time) bool
|
||||
OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool)
|
||||
CanSend(bytesInFlight protocol.ByteCount) bool
|
||||
MaybeExitSlowStart()
|
||||
OnPacketAcked(number protocol.PacketNumber, ackedBytes protocol.ByteCount, priorInFlight protocol.ByteCount, eventTime time.Time)
|
||||
OnPacketLost(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount)
|
||||
OnCongestionEvent(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount)
|
||||
OnRetransmissionTimeout(packetsRetransmitted bool)
|
||||
SetMaxDatagramSize(protocol.ByteCount)
|
||||
}
|
||||
|
||||
19
vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
generated
vendored
@@ -1,7 +1,6 @@
|
||||
package congestion
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@@ -26,7 +25,7 @@ func newPacer(getBandwidth func() Bandwidth) *pacer {
|
||||
bw := uint64(getBandwidth() / BytesPerSecond)
|
||||
// Use a slightly higher value than the actual measured bandwidth.
|
||||
// RTT variations then won't result in under-utilization of the congestion window.
|
||||
// Ultimately, this will result in sending packets as acknowledgments are received rather than when timers fire,
|
||||
// Ultimately, this will result in sending packets as acknowledgments are received rather than when timers fire,
|
||||
// provided the congestion window is fully utilized and acknowledgments arrive at regular intervals.
|
||||
return bw * 5 / 4
|
||||
},
|
||||
@@ -37,7 +36,7 @@ func newPacer(getBandwidth func() Bandwidth) *pacer {
|
||||
|
||||
func (p *pacer) SentPacket(sendTime time.Time, size protocol.ByteCount) {
|
||||
budget := p.Budget(sendTime)
|
||||
if size > budget {
|
||||
if size >= budget {
|
||||
p.budgetAtLastSent = 0
|
||||
} else {
|
||||
p.budgetAtLastSent = budget - size
|
||||
@@ -69,10 +68,16 @@ func (p *pacer) TimeUntilSend() time.Time {
|
||||
if p.budgetAtLastSent >= p.maxDatagramSize {
|
||||
return time.Time{}
|
||||
}
|
||||
return p.lastSentTime.Add(utils.Max(
|
||||
protocol.MinPacingDelay,
|
||||
time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.adjustedBandwidth())))*time.Nanosecond,
|
||||
))
|
||||
diff := 1e9 * uint64(p.maxDatagramSize-p.budgetAtLastSent)
|
||||
bw := p.adjustedBandwidth()
|
||||
// We might need to round up this value.
|
||||
// Otherwise, we might have a budget (slightly) smaller than the datagram size when the timer expires.
|
||||
d := diff / bw
|
||||
// this is effectively a math.Ceil, but using only integer math
|
||||
if diff%bw > 0 {
|
||||
d++
|
||||
}
|
||||
return p.lastSentTime.Add(utils.Max(protocol.MinPacingDelay, time.Duration(d)*time.Nanosecond))
|
||||
}
|
||||
|
||||
func (p *pacer) SetMaxDatagramSize(s protocol.ByteCount) {
|
||||
|
||||
69
vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
generated
vendored
69
vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
generated
vendored
@@ -5,11 +5,10 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
func createAEAD(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, v protocol.VersionNumber) cipher.AEAD {
|
||||
func createAEAD(suite *cipherSuite, trafficSecret []byte, v protocol.VersionNumber) cipher.AEAD {
|
||||
keyLabel := hkdfLabelKeyV1
|
||||
ivLabel := hkdfLabelIVV1
|
||||
if v == protocol.Version2 {
|
||||
@@ -93,69 +92,3 @@ func (o *longHeaderOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []
|
||||
func (o *longHeaderOpener) DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte) {
|
||||
o.headerProtector.DecryptHeader(sample, firstByte, pnBytes)
|
||||
}
|
||||
|
||||
type handshakeSealer struct {
|
||||
LongHeaderSealer
|
||||
|
||||
dropInitialKeys func()
|
||||
dropped bool
|
||||
}
|
||||
|
||||
func newHandshakeSealer(
|
||||
aead cipher.AEAD,
|
||||
headerProtector headerProtector,
|
||||
dropInitialKeys func(),
|
||||
perspective protocol.Perspective,
|
||||
) LongHeaderSealer {
|
||||
sealer := newLongHeaderSealer(aead, headerProtector)
|
||||
// The client drops Initial keys when sending the first Handshake packet.
|
||||
if perspective == protocol.PerspectiveServer {
|
||||
return sealer
|
||||
}
|
||||
return &handshakeSealer{
|
||||
LongHeaderSealer: sealer,
|
||||
dropInitialKeys: dropInitialKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *handshakeSealer) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte {
|
||||
data := s.LongHeaderSealer.Seal(dst, src, pn, ad)
|
||||
if !s.dropped {
|
||||
s.dropInitialKeys()
|
||||
s.dropped = true
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
type handshakeOpener struct {
|
||||
LongHeaderOpener
|
||||
|
||||
dropInitialKeys func()
|
||||
dropped bool
|
||||
}
|
||||
|
||||
func newHandshakeOpener(
|
||||
aead cipher.AEAD,
|
||||
headerProtector headerProtector,
|
||||
dropInitialKeys func(),
|
||||
perspective protocol.Perspective,
|
||||
) LongHeaderOpener {
|
||||
opener := newLongHeaderOpener(aead, headerProtector)
|
||||
// The server drops Initial keys when first successfully processing a Handshake packet.
|
||||
if perspective == protocol.PerspectiveClient {
|
||||
return opener
|
||||
}
|
||||
return &handshakeOpener{
|
||||
LongHeaderOpener: opener,
|
||||
dropInitialKeys: dropInitialKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *handshakeOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []byte) ([]byte, error) {
|
||||
dec, err := o.LongHeaderOpener.Open(dst, src, pn, ad)
|
||||
if err == nil && !o.dropped {
|
||||
o.dropInitialKeys()
|
||||
o.dropped = true
|
||||
}
|
||||
return dec, err
|
||||
}
|
||||
|
||||
104
vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
generated
vendored
Normal file
104
vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// These cipher suite implementations are copied from the standard library crypto/tls package.
|
||||
|
||||
const aeadNonceLength = 12
|
||||
|
||||
type cipherSuite struct {
|
||||
ID uint16
|
||||
Hash crypto.Hash
|
||||
KeyLen int
|
||||
AEAD func(key, nonceMask []byte) cipher.AEAD
|
||||
}
|
||||
|
||||
func (s cipherSuite) IVLen() int { return aeadNonceLength }
|
||||
|
||||
func getCipherSuite(id uint16) *cipherSuite {
|
||||
switch id {
|
||||
case tls.TLS_AES_128_GCM_SHA256:
|
||||
return &cipherSuite{ID: tls.TLS_AES_128_GCM_SHA256, Hash: crypto.SHA256, KeyLen: 16, AEAD: aeadAESGCMTLS13}
|
||||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
return &cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown cypher suite: %d", id))
|
||||
}
|
||||
}
|
||||
|
||||
func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD {
|
||||
if len(nonceMask) != aeadNonceLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
}
|
||||
aes, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
aead, err := cipher.NewGCM(aes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ret := &xorNonceAEAD{aead: aead}
|
||||
copy(ret.nonceMask[:], nonceMask)
|
||||
return ret
|
||||
}
|
||||
|
||||
func aeadChaCha20Poly1305(key, nonceMask []byte) cipher.AEAD {
|
||||
if len(nonceMask) != aeadNonceLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
}
|
||||
aead, err := chacha20poly1305.New(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ret := &xorNonceAEAD{aead: aead}
|
||||
copy(ret.nonceMask[:], nonceMask)
|
||||
return ret
|
||||
}
|
||||
|
||||
// xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
|
||||
// before each call.
|
||||
type xorNonceAEAD struct {
|
||||
nonceMask [aeadNonceLength]byte
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
||||
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
||||
func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
|
||||
|
||||
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
21
vendor/github.com/quic-go/quic-go/internal/handshake/conn.go
generated
vendored
Normal file
21
vendor/github.com/quic-go/quic-go/internal/handshake/conn.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
localAddr, remoteAddr net.Addr
|
||||
}
|
||||
|
||||
var _ net.Conn = &conn{}
|
||||
|
||||
func (c *conn) Read([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Write([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Close() error { return nil }
|
||||
func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
|
||||
func (c *conn) LocalAddr() net.Addr { return c.localAddr }
|
||||
func (c *conn) SetReadDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetWriteDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetDeadline(time.Time) error { return nil }
|
||||
710
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
710
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
@@ -6,10 +6,10 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@@ -25,102 +25,25 @@ type quicVersionContextKey struct{}
|
||||
|
||||
var QUICVersionContextKey = &quicVersionContextKey{}
|
||||
|
||||
// TLS unexpected_message alert
|
||||
const alertUnexpectedMessage uint8 = 10
|
||||
|
||||
type messageType uint8
|
||||
|
||||
// TLS handshake message types.
|
||||
const (
|
||||
typeClientHello messageType = 1
|
||||
typeServerHello messageType = 2
|
||||
typeNewSessionTicket messageType = 4
|
||||
typeEncryptedExtensions messageType = 8
|
||||
typeCertificate messageType = 11
|
||||
typeCertificateRequest messageType = 13
|
||||
typeCertificateVerify messageType = 15
|
||||
typeFinished messageType = 20
|
||||
)
|
||||
|
||||
func (m messageType) String() string {
|
||||
switch m {
|
||||
case typeClientHello:
|
||||
return "ClientHello"
|
||||
case typeServerHello:
|
||||
return "ServerHello"
|
||||
case typeNewSessionTicket:
|
||||
return "NewSessionTicket"
|
||||
case typeEncryptedExtensions:
|
||||
return "EncryptedExtensions"
|
||||
case typeCertificate:
|
||||
return "Certificate"
|
||||
case typeCertificateRequest:
|
||||
return "CertificateRequest"
|
||||
case typeCertificateVerify:
|
||||
return "CertificateVerify"
|
||||
case typeFinished:
|
||||
return "Finished"
|
||||
default:
|
||||
return fmt.Sprintf("unknown message type: %d", m)
|
||||
}
|
||||
}
|
||||
|
||||
const clientSessionStateRevision = 3
|
||||
|
||||
type conn struct {
|
||||
localAddr, remoteAddr net.Addr
|
||||
}
|
||||
|
||||
var _ net.Conn = &conn{}
|
||||
|
||||
func newConn(local, remote net.Addr) net.Conn {
|
||||
return &conn{
|
||||
localAddr: local,
|
||||
remoteAddr: remote,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) Read([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Write([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Close() error { return nil }
|
||||
func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
|
||||
func (c *conn) LocalAddr() net.Addr { return c.localAddr }
|
||||
func (c *conn) SetReadDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetWriteDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetDeadline(time.Time) error { return nil }
|
||||
|
||||
type cryptoSetup struct {
|
||||
tlsConf *tls.Config
|
||||
extraConf *qtls.ExtraConfig
|
||||
conn *qtls.Conn
|
||||
tlsConf *tls.Config
|
||||
conn *qtls.QUICConn
|
||||
|
||||
events []Event
|
||||
|
||||
version protocol.VersionNumber
|
||||
|
||||
messageChan chan []byte
|
||||
isReadingHandshakeMessage chan struct{}
|
||||
readFirstHandshakeMessage bool
|
||||
|
||||
ourParams *wire.TransportParameters
|
||||
peerParams *wire.TransportParameters
|
||||
paramsChan <-chan []byte
|
||||
|
||||
runner handshakeRunner
|
||||
|
||||
alertChan chan uint8
|
||||
// handshakeDone is closed as soon as the go routine running qtls.Handshake() returns
|
||||
handshakeDone chan struct{}
|
||||
// is closed when Close() is called
|
||||
closeChan chan struct{}
|
||||
|
||||
zeroRTTParameters *wire.TransportParameters
|
||||
clientHelloWritten bool
|
||||
clientHelloWrittenChan chan struct{} // is closed as soon as the ClientHello is written
|
||||
zeroRTTParametersChan chan<- *wire.TransportParameters
|
||||
allow0RTT bool
|
||||
zeroRTTParameters *wire.TransportParameters
|
||||
allow0RTT bool
|
||||
|
||||
rttStats *utils.RTTStats
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
|
||||
perspective protocol.Perspective
|
||||
@@ -129,169 +52,152 @@ type cryptoSetup struct {
|
||||
|
||||
handshakeCompleteTime time.Time
|
||||
|
||||
readEncLevel protocol.EncryptionLevel
|
||||
writeEncLevel protocol.EncryptionLevel
|
||||
|
||||
zeroRTTOpener LongHeaderOpener // only set for the server
|
||||
zeroRTTSealer LongHeaderSealer // only set for the client
|
||||
|
||||
initialStream io.Writer
|
||||
initialOpener LongHeaderOpener
|
||||
initialSealer LongHeaderSealer
|
||||
|
||||
handshakeStream io.Writer
|
||||
handshakeOpener LongHeaderOpener
|
||||
handshakeSealer LongHeaderSealer
|
||||
|
||||
used0RTT atomic.Bool
|
||||
|
||||
aead *updatableAEAD
|
||||
has1RTTSealer bool
|
||||
has1RTTOpener bool
|
||||
}
|
||||
|
||||
var (
|
||||
_ qtls.RecordLayer = &cryptoSetup{}
|
||||
_ CryptoSetup = &cryptoSetup{}
|
||||
)
|
||||
var _ CryptoSetup = &cryptoSetup{}
|
||||
|
||||
// NewCryptoSetupClient creates a new crypto setup for the client
|
||||
func NewCryptoSetupClient(
|
||||
initialStream io.Writer,
|
||||
handshakeStream io.Writer,
|
||||
connID protocol.ConnectionID,
|
||||
localAddr net.Addr,
|
||||
remoteAddr net.Addr,
|
||||
tp *wire.TransportParameters,
|
||||
runner handshakeRunner,
|
||||
tlsConf *tls.Config,
|
||||
enable0RTT bool,
|
||||
rttStats *utils.RTTStats,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
version protocol.VersionNumber,
|
||||
) (CryptoSetup, <-chan *wire.TransportParameters /* ClientHello written. Receive nil for non-0-RTT */) {
|
||||
cs, clientHelloWritten := newCryptoSetup(
|
||||
initialStream,
|
||||
handshakeStream,
|
||||
) CryptoSetup {
|
||||
cs := newCryptoSetup(
|
||||
connID,
|
||||
tp,
|
||||
runner,
|
||||
tlsConf,
|
||||
enable0RTT,
|
||||
rttStats,
|
||||
tracer,
|
||||
logger,
|
||||
protocol.PerspectiveClient,
|
||||
version,
|
||||
)
|
||||
cs.conn = qtls.Client(newConn(localAddr, remoteAddr), cs.tlsConf, cs.extraConf)
|
||||
return cs, clientHelloWritten
|
||||
|
||||
tlsConf = tlsConf.Clone()
|
||||
tlsConf.MinVersion = tls.VersionTLS13
|
||||
quicConf := &qtls.QUICConfig{TLSConfig: tlsConf}
|
||||
qtls.SetupConfigForClient(quicConf, cs.marshalDataForSessionState, cs.handleDataFromSessionState)
|
||||
cs.tlsConf = tlsConf
|
||||
cs.allow0RTT = enable0RTT
|
||||
|
||||
cs.conn = qtls.QUICClient(quicConf)
|
||||
cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient))
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// NewCryptoSetupServer creates a new crypto setup for the server
|
||||
func NewCryptoSetupServer(
|
||||
initialStream io.Writer,
|
||||
handshakeStream io.Writer,
|
||||
connID protocol.ConnectionID,
|
||||
localAddr net.Addr,
|
||||
remoteAddr net.Addr,
|
||||
localAddr, remoteAddr net.Addr,
|
||||
tp *wire.TransportParameters,
|
||||
runner handshakeRunner,
|
||||
tlsConf *tls.Config,
|
||||
allow0RTT bool,
|
||||
rttStats *utils.RTTStats,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
version protocol.VersionNumber,
|
||||
) CryptoSetup {
|
||||
cs, _ := newCryptoSetup(
|
||||
initialStream,
|
||||
handshakeStream,
|
||||
cs := newCryptoSetup(
|
||||
connID,
|
||||
tp,
|
||||
runner,
|
||||
tlsConf,
|
||||
allow0RTT,
|
||||
rttStats,
|
||||
tracer,
|
||||
logger,
|
||||
protocol.PerspectiveServer,
|
||||
version,
|
||||
)
|
||||
cs.conn = qtls.Server(newConn(localAddr, remoteAddr), cs.tlsConf, cs.extraConf)
|
||||
cs.allow0RTT = allow0RTT
|
||||
|
||||
quicConf := &qtls.QUICConfig{TLSConfig: tlsConf}
|
||||
qtls.SetupConfigForServer(quicConf, cs.allow0RTT, cs.getDataForSessionTicket, cs.handleSessionTicket)
|
||||
addConnToClientHelloInfo(quicConf.TLSConfig, localAddr, remoteAddr)
|
||||
|
||||
cs.tlsConf = quicConf.TLSConfig
|
||||
cs.conn = qtls.QUICServer(quicConf)
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// The tls.Config contains two callbacks that pass in a tls.ClientHelloInfo.
|
||||
// Since crypto/tls doesn't do it, we need to make sure to set the Conn field with a fake net.Conn
|
||||
// that allows the caller to get the local and the remote address.
|
||||
func addConnToClientHelloInfo(conf *tls.Config, localAddr, remoteAddr net.Addr) {
|
||||
if conf.GetConfigForClient != nil {
|
||||
gcfc := conf.GetConfigForClient
|
||||
conf.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
|
||||
c, err := gcfc(info)
|
||||
if c != nil {
|
||||
c = c.Clone()
|
||||
// This won't be necessary anymore once https://github.com/golang/go/issues/63722 is accepted.
|
||||
c.MinVersion = tls.VersionTLS13
|
||||
// We're returning a tls.Config here, so we need to apply this recursively.
|
||||
addConnToClientHelloInfo(c, localAddr, remoteAddr)
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
}
|
||||
if conf.GetCertificate != nil {
|
||||
gc := conf.GetCertificate
|
||||
conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
|
||||
return gc(info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newCryptoSetup(
|
||||
initialStream io.Writer,
|
||||
handshakeStream io.Writer,
|
||||
connID protocol.ConnectionID,
|
||||
tp *wire.TransportParameters,
|
||||
runner handshakeRunner,
|
||||
tlsConf *tls.Config,
|
||||
enable0RTT bool,
|
||||
rttStats *utils.RTTStats,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
perspective protocol.Perspective,
|
||||
version protocol.VersionNumber,
|
||||
) (*cryptoSetup, <-chan *wire.TransportParameters /* ClientHello written. Receive nil for non-0-RTT */) {
|
||||
) *cryptoSetup {
|
||||
initialSealer, initialOpener := NewInitialAEAD(connID, perspective, version)
|
||||
if tracer != nil {
|
||||
if tracer != nil && tracer.UpdatedKeyFromTLS != nil {
|
||||
tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
|
||||
tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
|
||||
}
|
||||
extHandler := newExtensionHandler(tp.Marshal(perspective), perspective, version)
|
||||
zeroRTTParametersChan := make(chan *wire.TransportParameters, 1)
|
||||
cs := &cryptoSetup{
|
||||
tlsConf: tlsConf,
|
||||
initialStream: initialStream,
|
||||
initialSealer: initialSealer,
|
||||
initialOpener: initialOpener,
|
||||
handshakeStream: handshakeStream,
|
||||
aead: newUpdatableAEAD(rttStats, tracer, logger, version),
|
||||
readEncLevel: protocol.EncryptionInitial,
|
||||
writeEncLevel: protocol.EncryptionInitial,
|
||||
runner: runner,
|
||||
allow0RTT: enable0RTT,
|
||||
ourParams: tp,
|
||||
paramsChan: extHandler.TransportParameters(),
|
||||
rttStats: rttStats,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
perspective: perspective,
|
||||
handshakeDone: make(chan struct{}),
|
||||
alertChan: make(chan uint8),
|
||||
clientHelloWrittenChan: make(chan struct{}),
|
||||
zeroRTTParametersChan: zeroRTTParametersChan,
|
||||
messageChan: make(chan []byte, 1),
|
||||
isReadingHandshakeMessage: make(chan struct{}),
|
||||
closeChan: make(chan struct{}),
|
||||
version: version,
|
||||
return &cryptoSetup{
|
||||
initialSealer: initialSealer,
|
||||
initialOpener: initialOpener,
|
||||
aead: newUpdatableAEAD(rttStats, tracer, logger, version),
|
||||
events: make([]Event, 0, 16),
|
||||
ourParams: tp,
|
||||
rttStats: rttStats,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
perspective: perspective,
|
||||
version: version,
|
||||
}
|
||||
var maxEarlyData uint32
|
||||
if enable0RTT {
|
||||
maxEarlyData = math.MaxUint32
|
||||
}
|
||||
cs.extraConf = &qtls.ExtraConfig{
|
||||
GetExtensions: extHandler.GetExtensions,
|
||||
ReceivedExtensions: extHandler.ReceivedExtensions,
|
||||
AlternativeRecordLayer: cs,
|
||||
EnforceNextProtoSelection: true,
|
||||
MaxEarlyData: maxEarlyData,
|
||||
Accept0RTT: cs.accept0RTT,
|
||||
Rejected0RTT: cs.rejected0RTT,
|
||||
Enable0RTT: enable0RTT,
|
||||
GetAppDataForSessionState: cs.marshalDataForSessionState,
|
||||
SetAppDataFromSessionState: cs.handleDataFromSessionState,
|
||||
}
|
||||
return cs, zeroRTTParametersChan
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) {
|
||||
initialSealer, initialOpener := NewInitialAEAD(id, h.perspective, h.version)
|
||||
h.initialSealer = initialSealer
|
||||
h.initialOpener = initialOpener
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
|
||||
}
|
||||
@@ -301,142 +207,109 @@ func (h *cryptoSetup) SetLargest1RTTAcked(pn protocol.PacketNumber) error {
|
||||
return h.aead.SetLargestAcked(pn)
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) RunHandshake() {
|
||||
// Handle errors that might occur when HandleData() is called.
|
||||
handshakeComplete := make(chan struct{})
|
||||
handshakeErrChan := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(h.handshakeDone)
|
||||
if err := h.conn.HandshakeContext(context.WithValue(context.Background(), QUICVersionContextKey, h.version)); err != nil {
|
||||
handshakeErrChan <- err
|
||||
return
|
||||
func (h *cryptoSetup) StartHandshake() error {
|
||||
err := h.conn.Start(context.WithValue(context.Background(), QUICVersionContextKey, h.version))
|
||||
if err != nil {
|
||||
return wrapError(err)
|
||||
}
|
||||
for {
|
||||
ev := h.conn.NextEvent()
|
||||
done, err := h.handleEvent(ev)
|
||||
if err != nil {
|
||||
return wrapError(err)
|
||||
}
|
||||
close(handshakeComplete)
|
||||
}()
|
||||
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
if h.perspective == protocol.PerspectiveClient {
|
||||
select {
|
||||
case err := <-handshakeErrChan:
|
||||
h.onError(0, err.Error())
|
||||
return
|
||||
case <-h.clientHelloWrittenChan:
|
||||
if h.zeroRTTSealer != nil && h.zeroRTTParameters != nil {
|
||||
h.logger.Debugf("Doing 0-RTT.")
|
||||
h.events = append(h.events, Event{Kind: EventRestoredTransportParameters, TransportParameters: h.zeroRTTParameters})
|
||||
} else {
|
||||
h.logger.Debugf("Not doing 0-RTT. Has sealer: %t, has params: %t", h.zeroRTTSealer != nil, h.zeroRTTParameters != nil)
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-handshakeComplete: // return when the handshake is done
|
||||
h.mutex.Lock()
|
||||
h.handshakeCompleteTime = time.Now()
|
||||
h.mutex.Unlock()
|
||||
h.runner.OnHandshakeComplete()
|
||||
case <-h.closeChan:
|
||||
// wait until the Handshake() go routine has returned
|
||||
<-h.handshakeDone
|
||||
case alert := <-h.alertChan:
|
||||
handshakeErr := <-handshakeErrChan
|
||||
h.onError(alert, handshakeErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) onError(alert uint8, message string) {
|
||||
var err error
|
||||
if alert == 0 {
|
||||
err = &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: message}
|
||||
} else {
|
||||
err = qerr.NewLocalCryptoError(alert, message)
|
||||
}
|
||||
h.runner.OnError(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the crypto setup.
|
||||
// It aborts the handshake, if it is still running.
|
||||
// It must only be called once.
|
||||
func (h *cryptoSetup) Close() error {
|
||||
close(h.closeChan)
|
||||
// wait until qtls.Handshake() actually returned
|
||||
<-h.handshakeDone
|
||||
return nil
|
||||
return h.conn.Close()
|
||||
}
|
||||
|
||||
// handleMessage handles a TLS handshake message.
|
||||
// HandleMessage handles a TLS handshake message.
|
||||
// It is called by the crypto streams when a new message is available.
|
||||
// It returns if it is done with messages on the same encryption level.
|
||||
func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLevel) bool /* stream finished */ {
|
||||
msgType := messageType(data[0])
|
||||
h.logger.Debugf("Received %s message (%d bytes, encryption level: %s)", msgType, len(data), encLevel)
|
||||
if err := h.checkEncryptionLevel(msgType, encLevel); err != nil {
|
||||
h.onError(alertUnexpectedMessage, err.Error())
|
||||
return false
|
||||
}
|
||||
if encLevel != protocol.Encryption1RTT {
|
||||
select {
|
||||
case h.messageChan <- data:
|
||||
case <-h.handshakeDone: // handshake errored, nobody is going to consume this message
|
||||
return false
|
||||
}
|
||||
}
|
||||
if encLevel == protocol.Encryption1RTT {
|
||||
h.messageChan <- data
|
||||
h.handlePostHandshakeMessage()
|
||||
return false
|
||||
}
|
||||
readLoop:
|
||||
for {
|
||||
select {
|
||||
case data := <-h.paramsChan:
|
||||
if data == nil {
|
||||
h.onError(0x6d, "missing quic_transport_parameters extension")
|
||||
} else {
|
||||
h.handleTransportParameters(data)
|
||||
}
|
||||
case <-h.isReadingHandshakeMessage:
|
||||
break readLoop
|
||||
case <-h.handshakeDone:
|
||||
break readLoop
|
||||
case <-h.closeChan:
|
||||
break readLoop
|
||||
}
|
||||
}
|
||||
// We're done with the Initial encryption level after processing a ClientHello / ServerHello,
|
||||
// but only if a handshake opener and sealer was created.
|
||||
// Otherwise, a HelloRetryRequest was performed.
|
||||
// We're done with the Handshake encryption level after processing the Finished message.
|
||||
return ((msgType == typeClientHello || msgType == typeServerHello) && h.handshakeOpener != nil && h.handshakeSealer != nil) ||
|
||||
msgType == typeFinished
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) checkEncryptionLevel(msgType messageType, encLevel protocol.EncryptionLevel) error {
|
||||
var expected protocol.EncryptionLevel
|
||||
switch msgType {
|
||||
case typeClientHello, typeServerHello:
|
||||
expected = protocol.EncryptionInitial
|
||||
case typeEncryptedExtensions,
|
||||
typeCertificate,
|
||||
typeCertificateRequest,
|
||||
typeCertificateVerify,
|
||||
typeFinished:
|
||||
expected = protocol.EncryptionHandshake
|
||||
case typeNewSessionTicket:
|
||||
expected = protocol.Encryption1RTT
|
||||
default:
|
||||
return fmt.Errorf("unexpected handshake message: %d", msgType)
|
||||
}
|
||||
if encLevel != expected {
|
||||
return fmt.Errorf("expected handshake message %s to have encryption level %s, has %s", msgType, expected, encLevel)
|
||||
func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
|
||||
if err := h.handleMessage(data, encLevel); err != nil {
|
||||
return wrapError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleTransportParameters(data []byte) {
|
||||
func (h *cryptoSetup) handleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
|
||||
if err := h.conn.HandleData(qtls.ToTLSEncryptionLevel(encLevel), data); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
ev := h.conn.NextEvent()
|
||||
done, err := h.handleEvent(ev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if done {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleEvent(ev qtls.QUICEvent) (done bool, err error) {
|
||||
switch ev.Kind {
|
||||
case qtls.QUICNoEvent:
|
||||
return true, nil
|
||||
case qtls.QUICSetReadSecret:
|
||||
h.SetReadKey(ev.Level, ev.Suite, ev.Data)
|
||||
return false, nil
|
||||
case qtls.QUICSetWriteSecret:
|
||||
h.SetWriteKey(ev.Level, ev.Suite, ev.Data)
|
||||
return false, nil
|
||||
case qtls.QUICTransportParameters:
|
||||
return false, h.handleTransportParameters(ev.Data)
|
||||
case qtls.QUICTransportParametersRequired:
|
||||
h.conn.SetTransportParameters(h.ourParams.Marshal(h.perspective))
|
||||
return false, nil
|
||||
case qtls.QUICRejectedEarlyData:
|
||||
h.rejected0RTT()
|
||||
return false, nil
|
||||
case qtls.QUICWriteData:
|
||||
h.WriteRecord(ev.Level, ev.Data)
|
||||
return false, nil
|
||||
case qtls.QUICHandshakeDone:
|
||||
h.handshakeComplete()
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("unexpected event: %d", ev.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) NextEvent() Event {
|
||||
if len(h.events) == 0 {
|
||||
return Event{Kind: EventNoEvent}
|
||||
}
|
||||
ev := h.events[0]
|
||||
h.events = h.events[1:]
|
||||
return ev
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleTransportParameters(data []byte) error {
|
||||
var tp wire.TransportParameters
|
||||
if err := tp.Unmarshal(data, h.perspective.Opposite()); err != nil {
|
||||
h.runner.OnError(&qerr.TransportError{
|
||||
ErrorCode: qerr.TransportParameterError,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return err
|
||||
}
|
||||
h.peerParams = &tp
|
||||
h.runner.OnReceivedParams(h.peerParams)
|
||||
h.events = append(h.events, Event{Kind: EventReceivedTransportParameters, TransportParameters: h.peerParams})
|
||||
return nil
|
||||
}
|
||||
|
||||
// must be called after receiving the transport parameters
|
||||
@@ -447,13 +320,20 @@ func (h *cryptoSetup) marshalDataForSessionState() []byte {
|
||||
return h.peerParams.MarshalForSessionTicket(b)
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleDataFromSessionState(data []byte) {
|
||||
func (h *cryptoSetup) handleDataFromSessionState(data []byte) (allowEarlyData bool) {
|
||||
tp, err := h.handleDataFromSessionStateImpl(data)
|
||||
if err != nil {
|
||||
h.logger.Debugf("Restoring of transport parameters from session ticket failed: %s", err.Error())
|
||||
return
|
||||
}
|
||||
h.zeroRTTParameters = tp
|
||||
// The session ticket might have been saved from a connection that allowed 0-RTT,
|
||||
// and therefore contain transport parameters.
|
||||
// Only use them if 0-RTT is actually used on the new connection.
|
||||
if tp != nil && h.allow0RTT {
|
||||
h.zeroRTTParameters = tp
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleDataFromSessionStateImpl(data []byte) (*wire.TransportParameters, error) {
|
||||
@@ -477,25 +357,54 @@ func (h *cryptoSetup) handleDataFromSessionStateImpl(data []byte) (*wire.Transpo
|
||||
return &tp, nil
|
||||
}
|
||||
|
||||
// only valid for the server
|
||||
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
||||
var appData []byte
|
||||
// Save transport parameters to the session ticket if we're allowing 0-RTT.
|
||||
if h.extraConf.MaxEarlyData > 0 {
|
||||
appData = (&sessionTicket{
|
||||
Parameters: h.ourParams,
|
||||
RTT: h.rttStats.SmoothedRTT(),
|
||||
}).Marshal()
|
||||
func (h *cryptoSetup) getDataForSessionTicket() []byte {
|
||||
ticket := &sessionTicket{
|
||||
RTT: h.rttStats.SmoothedRTT(),
|
||||
}
|
||||
return h.conn.GetSessionTicket(appData)
|
||||
if h.allow0RTT {
|
||||
ticket.Parameters = h.ourParams
|
||||
}
|
||||
return ticket.Marshal()
|
||||
}
|
||||
|
||||
// accept0RTT is called for the server when receiving the client's session ticket.
|
||||
// It decides whether to accept 0-RTT.
|
||||
func (h *cryptoSetup) accept0RTT(sessionTicketData []byte) bool {
|
||||
// GetSessionTicket generates a new session ticket.
|
||||
// Due to limitations in crypto/tls, it's only possible to generate a single session ticket per connection.
|
||||
// It is only valid for the server.
|
||||
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
||||
if err := qtls.SendSessionTicket(h.conn, h.allow0RTT); err != nil {
|
||||
// Session tickets might be disabled by tls.Config.SessionTicketsDisabled.
|
||||
// We can't check h.tlsConfig here, since the actual config might have been obtained from
|
||||
// the GetConfigForClient callback.
|
||||
// See https://github.com/golang/go/issues/62032.
|
||||
// Once that issue is resolved, this error assertion can be removed.
|
||||
if strings.Contains(err.Error(), "session ticket keys unavailable") {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
ev := h.conn.NextEvent()
|
||||
if ev.Kind != qtls.QUICWriteData || ev.Level != qtls.QUICEncryptionLevelApplication {
|
||||
panic("crypto/tls bug: where's my session ticket?")
|
||||
}
|
||||
ticket := ev.Data
|
||||
if ev := h.conn.NextEvent(); ev.Kind != qtls.QUICNoEvent {
|
||||
panic("crypto/tls bug: why more than one ticket?")
|
||||
}
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
// handleSessionTicket is called for the server when receiving the client's session ticket.
|
||||
// It reads parameters from the session ticket and checks whether to accept 0-RTT if the session ticket enabled 0-RTT.
|
||||
// Note that the fact that the session ticket allows 0-RTT doesn't mean that the actual TLS handshake enables 0-RTT:
|
||||
// A client may use a 0-RTT enabled session to resume a TLS session without using 0-RTT.
|
||||
func (h *cryptoSetup) handleSessionTicket(sessionTicketData []byte, using0RTT bool) bool {
|
||||
var t sessionTicket
|
||||
if err := t.Unmarshal(sessionTicketData); err != nil {
|
||||
h.logger.Debugf("Unmarshalling transport parameters from session ticket failed: %s", err.Error())
|
||||
if err := t.Unmarshal(sessionTicketData, using0RTT); err != nil {
|
||||
h.logger.Debugf("Unmarshalling session ticket failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
h.rttStats.SetInitialRTT(t.RTT)
|
||||
if !using0RTT {
|
||||
return false
|
||||
}
|
||||
valid := h.ourParams.ValidFor0RTT(t.Parameters)
|
||||
@@ -508,7 +417,6 @@ func (h *cryptoSetup) accept0RTT(sessionTicketData []byte) bool {
|
||||
return false
|
||||
}
|
||||
h.logger.Debugf("Accepting 0-RTT. Restoring RTT from session ticket: %s", t.RTT)
|
||||
h.rttStats.SetInitialRTT(t.RTT)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -522,64 +430,16 @@ func (h *cryptoSetup) rejected0RTT() {
|
||||
h.mutex.Unlock()
|
||||
|
||||
if had0RTTKeys {
|
||||
h.runner.DropKeys(protocol.Encryption0RTT)
|
||||
h.events = append(h.events, Event{Kind: EventDiscard0RTTKeys})
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handlePostHandshakeMessage() {
|
||||
// make sure the handshake has already completed
|
||||
<-h.handshakeDone
|
||||
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
// h.alertChan is an unbuffered channel.
|
||||
// If an error occurs during conn.HandlePostHandshakeMessage,
|
||||
// it will be sent on this channel.
|
||||
// Read it from a go-routine so that HandlePostHandshakeMessage doesn't deadlock.
|
||||
alertChan := make(chan uint8, 1)
|
||||
go func() {
|
||||
<-h.isReadingHandshakeMessage
|
||||
select {
|
||||
case alert := <-h.alertChan:
|
||||
alertChan <- alert
|
||||
case <-done:
|
||||
}
|
||||
}()
|
||||
|
||||
if err := h.conn.HandlePostHandshakeMessage(); err != nil {
|
||||
select {
|
||||
case <-h.closeChan:
|
||||
case alert := <-alertChan:
|
||||
h.onError(alert, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReadHandshakeMessage is called by TLS.
|
||||
// It blocks until a new handshake message is available.
|
||||
func (h *cryptoSetup) ReadHandshakeMessage() ([]byte, error) {
|
||||
if !h.readFirstHandshakeMessage {
|
||||
h.readFirstHandshakeMessage = true
|
||||
} else {
|
||||
select {
|
||||
case h.isReadingHandshakeMessage <- struct{}{}:
|
||||
case <-h.closeChan:
|
||||
return nil, errors.New("error while handling the handshake message")
|
||||
}
|
||||
}
|
||||
select {
|
||||
case msg := <-h.messageChan:
|
||||
return msg, nil
|
||||
case <-h.closeChan:
|
||||
return nil, errors.New("error while handling the handshake message")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SetReadKey(encLevel qtls.EncryptionLevel, suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (h *cryptoSetup) SetReadKey(el qtls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
|
||||
suite := getCipherSuite(suiteID)
|
||||
h.mutex.Lock()
|
||||
switch encLevel {
|
||||
case qtls.Encryption0RTT:
|
||||
//nolint:exhaustive // The TLS stack doesn't export Initial keys.
|
||||
switch el {
|
||||
case qtls.QUICEncryptionLevelEarly:
|
||||
if h.perspective == protocol.PerspectiveClient {
|
||||
panic("Received 0-RTT read key for the client")
|
||||
}
|
||||
@@ -587,27 +447,19 @@ func (h *cryptoSetup) SetReadKey(encLevel qtls.EncryptionLevel, suite *qtls.Ciph
|
||||
createAEAD(suite, trafficSecret, h.version),
|
||||
newHeaderProtector(suite, trafficSecret, true, h.version),
|
||||
)
|
||||
h.mutex.Unlock()
|
||||
h.used0RTT.Store(true)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed 0-RTT Read keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.Encryption0RTT, h.perspective.Opposite())
|
||||
}
|
||||
return
|
||||
case qtls.EncryptionHandshake:
|
||||
h.readEncLevel = protocol.EncryptionHandshake
|
||||
h.handshakeOpener = newHandshakeOpener(
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
h.handshakeOpener = newLongHeaderOpener(
|
||||
createAEAD(suite, trafficSecret, h.version),
|
||||
newHeaderProtector(suite, trafficSecret, true, h.version),
|
||||
h.dropInitialKeys,
|
||||
h.perspective,
|
||||
)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed Handshake Read keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
case qtls.EncryptionApplication:
|
||||
h.readEncLevel = protocol.Encryption1RTT
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
h.aead.SetReadKey(suite, trafficSecret)
|
||||
h.has1RTTOpener = true
|
||||
if h.logger.Debug() {
|
||||
@@ -617,15 +469,18 @@ func (h *cryptoSetup) SetReadKey(encLevel qtls.EncryptionLevel, suite *qtls.Ciph
|
||||
panic("unexpected read encryption level")
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(h.readEncLevel, h.perspective.Opposite())
|
||||
h.events = append(h.events, Event{Kind: EventReceivedReadKeys})
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective.Opposite())
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SetWriteKey(encLevel qtls.EncryptionLevel, suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (h *cryptoSetup) SetWriteKey(el qtls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
|
||||
suite := getCipherSuite(suiteID)
|
||||
h.mutex.Lock()
|
||||
switch encLevel {
|
||||
case qtls.Encryption0RTT:
|
||||
//nolint:exhaustive // The TLS stack doesn't export Initial keys.
|
||||
switch el {
|
||||
case qtls.QUICEncryptionLevelEarly:
|
||||
if h.perspective == protocol.PerspectiveServer {
|
||||
panic("Received 0-RTT write key for the server")
|
||||
}
|
||||
@@ -637,32 +492,31 @@ func (h *cryptoSetup) SetWriteKey(encLevel qtls.EncryptionLevel, suite *qtls.Cip
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed 0-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.Encryption0RTT, h.perspective)
|
||||
}
|
||||
// don't set used0RTT here. 0-RTT might still get rejected.
|
||||
return
|
||||
case qtls.EncryptionHandshake:
|
||||
h.writeEncLevel = protocol.EncryptionHandshake
|
||||
h.handshakeSealer = newHandshakeSealer(
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
h.handshakeSealer = newLongHeaderSealer(
|
||||
createAEAD(suite, trafficSecret, h.version),
|
||||
newHeaderProtector(suite, trafficSecret, true, h.version),
|
||||
h.dropInitialKeys,
|
||||
h.perspective,
|
||||
)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed Handshake Write keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
case qtls.EncryptionApplication:
|
||||
h.writeEncLevel = protocol.Encryption1RTT
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
h.aead.SetWriteKey(suite, trafficSecret)
|
||||
h.has1RTTSealer = true
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed 1-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
if h.zeroRTTSealer != nil {
|
||||
// Once we receive handshake keys, we know that 0-RTT was not rejected.
|
||||
h.used0RTT.Store(true)
|
||||
h.zeroRTTSealer = nil
|
||||
h.logger.Debugf("Dropping 0-RTT keys.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
|
||||
h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
|
||||
}
|
||||
}
|
||||
@@ -670,56 +524,40 @@ func (h *cryptoSetup) SetWriteKey(encLevel qtls.EncryptionLevel, suite *qtls.Cip
|
||||
panic("unexpected write encryption level")
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(h.writeEncLevel, h.perspective)
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteRecord is called when TLS writes data
|
||||
func (h *cryptoSetup) WriteRecord(p []byte) (int, error) {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
//nolint:exhaustive // LS records can only be written for Initial and Handshake.
|
||||
switch h.writeEncLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
// assume that the first WriteRecord call contains the ClientHello
|
||||
n, err := h.initialStream.Write(p)
|
||||
if !h.clientHelloWritten && h.perspective == protocol.PerspectiveClient {
|
||||
h.clientHelloWritten = true
|
||||
close(h.clientHelloWrittenChan)
|
||||
if h.zeroRTTSealer != nil && h.zeroRTTParameters != nil {
|
||||
h.logger.Debugf("Doing 0-RTT.")
|
||||
h.zeroRTTParametersChan <- h.zeroRTTParameters
|
||||
} else {
|
||||
h.logger.Debugf("Not doing 0-RTT.")
|
||||
h.zeroRTTParametersChan <- nil
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
case protocol.EncryptionHandshake:
|
||||
return h.handshakeStream.Write(p)
|
||||
func (h *cryptoSetup) WriteRecord(encLevel qtls.QUICEncryptionLevel, p []byte) {
|
||||
//nolint:exhaustive // handshake records can only be written for Initial and Handshake.
|
||||
switch encLevel {
|
||||
case qtls.QUICEncryptionLevelInitial:
|
||||
h.events = append(h.events, Event{Kind: EventWriteInitialData, Data: p})
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
h.events = append(h.events, Event{Kind: EventWriteHandshakeData, Data: p})
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
panic("unexpected write")
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected write encryption level: %s", h.writeEncLevel))
|
||||
panic(fmt.Sprintf("unexpected write encryption level: %s", encLevel))
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SendAlert(alert uint8) {
|
||||
select {
|
||||
case h.alertChan <- alert:
|
||||
case <-h.closeChan:
|
||||
// no need to send an alert when we've already closed
|
||||
}
|
||||
}
|
||||
|
||||
// used a callback in the handshakeSealer and handshakeOpener
|
||||
func (h *cryptoSetup) dropInitialKeys() {
|
||||
func (h *cryptoSetup) DiscardInitialKeys() {
|
||||
h.mutex.Lock()
|
||||
dropped := h.initialOpener != nil
|
||||
h.initialOpener = nil
|
||||
h.initialSealer = nil
|
||||
h.mutex.Unlock()
|
||||
h.runner.DropKeys(protocol.EncryptionInitial)
|
||||
h.logger.Debugf("Dropping Initial keys.")
|
||||
if dropped {
|
||||
h.logger.Debugf("Dropping Initial keys.")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handshakeComplete() {
|
||||
h.handshakeCompleteTime = time.Now()
|
||||
h.events = append(h.events, Event{Kind: EventHandshakeComplete})
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SetHandshakeConfirmed() {
|
||||
@@ -734,7 +572,6 @@ func (h *cryptoSetup) SetHandshakeConfirmed() {
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
if dropped {
|
||||
h.runner.DropKeys(protocol.EncryptionHandshake)
|
||||
h.logger.Debugf("Dropping Handshake keys.")
|
||||
}
|
||||
}
|
||||
@@ -827,7 +664,7 @@ func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
|
||||
if h.zeroRTTOpener != nil && time.Since(h.handshakeCompleteTime) > 3*h.rttStats.PTO(true) {
|
||||
h.zeroRTTOpener = nil
|
||||
h.logger.Debugf("Dropping 0-RTT keys.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
|
||||
h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
|
||||
}
|
||||
}
|
||||
@@ -839,5 +676,16 @@ func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) ConnectionState() ConnectionState {
|
||||
return qtls.GetConnectionState(h.conn)
|
||||
return ConnectionState{
|
||||
ConnectionState: h.conn.ConnectionState(),
|
||||
Used0RTT: h.used0RTT.Load(),
|
||||
}
|
||||
}
|
||||
|
||||
func wrapError(err error) error {
|
||||
// alert 80 is an internal error
|
||||
if alertErr := qtls.AlertError(0); errors.As(err, &alertErr) && alertErr != 80 {
|
||||
return qerr.NewLocalCryptoError(uint8(alertErr), err)
|
||||
}
|
||||
return &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: err.Error()}
|
||||
}
|
||||
|
||||
7
vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
generated
vendored
7
vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
"golang.org/x/crypto/chacha20"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
)
|
||||
|
||||
type headerProtector interface {
|
||||
@@ -25,7 +24,7 @@ func hkdfHeaderProtectionLabel(v protocol.VersionNumber) string {
|
||||
return "quic hp"
|
||||
}
|
||||
|
||||
func newHeaderProtector(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, isLongHeader bool, v protocol.VersionNumber) headerProtector {
|
||||
func newHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, v protocol.VersionNumber) headerProtector {
|
||||
hkdfLabel := hkdfHeaderProtectionLabel(v)
|
||||
switch suite.ID {
|
||||
case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
|
||||
@@ -45,7 +44,7 @@ type aesHeaderProtector struct {
|
||||
|
||||
var _ headerProtector = &aesHeaderProtector{}
|
||||
|
||||
func newAESHeaderProtector(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
func newAESHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
|
||||
block, err := aes.NewCipher(hpKey)
|
||||
if err != nil {
|
||||
@@ -90,7 +89,7 @@ type chachaHeaderProtector struct {
|
||||
|
||||
var _ headerProtector = &chachaHeaderProtector{}
|
||||
|
||||
func newChaChaHeaderProtector(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
func newChaChaHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
|
||||
|
||||
p := &chachaHeaderProtector{
|
||||
|
||||
22
vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go
generated
vendored
22
vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go
generated
vendored
@@ -7,13 +7,11 @@ import (
|
||||
"golang.org/x/crypto/hkdf"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
)
|
||||
|
||||
var (
|
||||
quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}
|
||||
quicSaltV1 = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}
|
||||
quicSaltV2 = []byte{0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9}
|
||||
quicSaltV1 = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}
|
||||
quicSaltV2 = []byte{0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9}
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -27,18 +25,10 @@ func getSalt(v protocol.VersionNumber) []byte {
|
||||
if v == protocol.Version2 {
|
||||
return quicSaltV2
|
||||
}
|
||||
if v == protocol.Version1 {
|
||||
return quicSaltV1
|
||||
}
|
||||
return quicSaltOld
|
||||
return quicSaltV1
|
||||
}
|
||||
|
||||
var initialSuite = &qtls.CipherSuiteTLS13{
|
||||
ID: tls.TLS_AES_128_GCM_SHA256,
|
||||
KeyLen: 16,
|
||||
AEAD: qtls.AEADAESGCMTLS13,
|
||||
Hash: crypto.SHA256,
|
||||
}
|
||||
var initialSuite = getCipherSuite(tls.TLS_AES_128_GCM_SHA256)
|
||||
|
||||
// NewInitialAEAD creates a new AEAD for Initial encryption / decryption.
|
||||
func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective, v protocol.VersionNumber) (LongHeaderSealer, LongHeaderOpener) {
|
||||
@@ -54,8 +44,8 @@ func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective, v p
|
||||
myKey, myIV := computeInitialKeyAndIV(mySecret, v)
|
||||
otherKey, otherIV := computeInitialKeyAndIV(otherSecret, v)
|
||||
|
||||
encrypter := qtls.AEADAESGCMTLS13(myKey, myIV)
|
||||
decrypter := qtls.AEADAESGCMTLS13(otherKey, otherIV)
|
||||
encrypter := initialSuite.AEAD(myKey, myIV)
|
||||
decrypter := initialSuite.AEAD(otherKey, otherIV)
|
||||
|
||||
return newLongHeaderSealer(encrypter, newHeaderProtector(initialSuite, mySecret, true, v)),
|
||||
newLongHeaderOpener(decrypter, newAESHeaderProtector(initialSuite, otherSecret, true, hkdfHeaderProtectionLabel(v)))
|
||||
|
||||
54
vendor/github.com/quic-go/quic-go/internal/handshake/interface.go
generated
vendored
54
vendor/github.com/quic-go/quic-go/internal/handshake/interface.go
generated
vendored
@@ -1,12 +1,12 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
@@ -22,9 +22,6 @@ var (
|
||||
ErrDecryptionFailed = errors.New("decryption failed")
|
||||
)
|
||||
|
||||
// ConnectionState contains information about the state of the connection.
|
||||
type ConnectionState = qtls.ConnectionState
|
||||
|
||||
type headerDecryptor interface {
|
||||
DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte)
|
||||
}
|
||||
@@ -56,29 +53,54 @@ type ShortHeaderSealer interface {
|
||||
KeyPhase() protocol.KeyPhaseBit
|
||||
}
|
||||
|
||||
// A tlsExtensionHandler sends and received the QUIC TLS extension.
|
||||
type tlsExtensionHandler interface {
|
||||
GetExtensions(msgType uint8) []qtls.Extension
|
||||
ReceivedExtensions(msgType uint8, exts []qtls.Extension)
|
||||
TransportParameters() <-chan []byte
|
||||
type ConnectionState struct {
|
||||
tls.ConnectionState
|
||||
Used0RTT bool
|
||||
}
|
||||
|
||||
type handshakeRunner interface {
|
||||
OnReceivedParams(*wire.TransportParameters)
|
||||
OnHandshakeComplete()
|
||||
OnError(error)
|
||||
DropKeys(protocol.EncryptionLevel)
|
||||
// EventKind is the kind of handshake event.
|
||||
type EventKind uint8
|
||||
|
||||
const (
|
||||
// EventNoEvent signals that there are no new handshake events
|
||||
EventNoEvent EventKind = iota + 1
|
||||
// EventWriteInitialData contains new CRYPTO data to send at the Initial encryption level
|
||||
EventWriteInitialData
|
||||
// EventWriteHandshakeData contains new CRYPTO data to send at the Handshake encryption level
|
||||
EventWriteHandshakeData
|
||||
// EventReceivedReadKeys signals that new decryption keys are available.
|
||||
// It doesn't say which encryption level those keys are for.
|
||||
EventReceivedReadKeys
|
||||
// EventDiscard0RTTKeys signals that the Handshake keys were discarded.
|
||||
EventDiscard0RTTKeys
|
||||
// EventReceivedTransportParameters contains the transport parameters sent by the peer.
|
||||
EventReceivedTransportParameters
|
||||
// EventRestoredTransportParameters contains the transport parameters restored from the session ticket.
|
||||
// It is only used for the client.
|
||||
EventRestoredTransportParameters
|
||||
// EventHandshakeComplete signals that the TLS handshake was completed.
|
||||
EventHandshakeComplete
|
||||
)
|
||||
|
||||
// Event is a handshake event.
|
||||
type Event struct {
|
||||
Kind EventKind
|
||||
Data []byte
|
||||
TransportParameters *wire.TransportParameters
|
||||
}
|
||||
|
||||
// CryptoSetup handles the handshake and protecting / unprotecting packets
|
||||
type CryptoSetup interface {
|
||||
RunHandshake()
|
||||
StartHandshake() error
|
||||
io.Closer
|
||||
ChangeConnectionID(protocol.ConnectionID)
|
||||
GetSessionTicket() ([]byte, error)
|
||||
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) bool
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) error
|
||||
NextEvent() Event
|
||||
|
||||
SetLargest1RTTAcked(protocol.PacketNumber) error
|
||||
DiscardInitialKeys()
|
||||
SetHandshakeConfirmed()
|
||||
ConnectionState() ConnectionState
|
||||
|
||||
|
||||
6
vendor/github.com/quic-go/quic-go/internal/handshake/mockgen.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/handshake/mockgen.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
//go:build gomock || generate
|
||||
|
||||
package handshake
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package handshake -destination mock_handshake_runner_test.go github.com/quic-go/quic-go/internal/handshake HandshakeRunner"
|
||||
type HandshakeRunner = handshakeRunner
|
||||
25
vendor/github.com/quic-go/quic-go/internal/handshake/retry.go
generated
vendored
25
vendor/github.com/quic-go/quic-go/internal/handshake/retry.go
generated
vendored
@@ -11,13 +11,11 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
retryAEADdraft29 cipher.AEAD // used for QUIC draft versions up to 34
|
||||
retryAEADv1 cipher.AEAD // used for QUIC v1 (RFC 9000)
|
||||
retryAEADv2 cipher.AEAD // used for QUIC v2
|
||||
retryAEADv1 cipher.AEAD // used for QUIC v1 (RFC 9000)
|
||||
retryAEADv2 cipher.AEAD // used for QUIC v2 (RFC 9369)
|
||||
)
|
||||
|
||||
func init() {
|
||||
retryAEADdraft29 = initAEAD([16]byte{0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1})
|
||||
retryAEADv1 = initAEAD([16]byte{0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e})
|
||||
retryAEADv2 = initAEAD([16]byte{0x8f, 0xb4, 0xb0, 0x1b, 0x56, 0xac, 0x48, 0xe2, 0x60, 0xfb, 0xcb, 0xce, 0xad, 0x7c, 0xcc, 0x92})
|
||||
}
|
||||
@@ -35,11 +33,10 @@ func initAEAD(key [16]byte) cipher.AEAD {
|
||||
}
|
||||
|
||||
var (
|
||||
retryBuf bytes.Buffer
|
||||
retryMutex sync.Mutex
|
||||
retryNonceDraft29 = [12]byte{0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c}
|
||||
retryNonceV1 = [12]byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
|
||||
retryNonceV2 = [12]byte{0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a}
|
||||
retryBuf bytes.Buffer
|
||||
retryMutex sync.Mutex
|
||||
retryNonceV1 = [12]byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
|
||||
retryNonceV2 = [12]byte{0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a}
|
||||
)
|
||||
|
||||
// GetRetryIntegrityTag calculates the integrity tag on a Retry packet
|
||||
@@ -54,14 +51,10 @@ func GetRetryIntegrityTag(retry []byte, origDestConnID protocol.ConnectionID, ve
|
||||
|
||||
var tag [16]byte
|
||||
var sealed []byte
|
||||
//nolint:exhaustive // These are all the versions we support
|
||||
switch version {
|
||||
case protocol.Version1:
|
||||
sealed = retryAEADv1.Seal(tag[:0], retryNonceV1[:], nil, retryBuf.Bytes())
|
||||
case protocol.Version2:
|
||||
if version == protocol.Version2 {
|
||||
sealed = retryAEADv2.Seal(tag[:0], retryNonceV2[:], nil, retryBuf.Bytes())
|
||||
default:
|
||||
sealed = retryAEADdraft29.Seal(tag[:0], retryNonceDraft29[:], nil, retryBuf.Bytes())
|
||||
} else {
|
||||
sealed = retryAEADv1.Seal(tag[:0], retryNonceV1[:], nil, retryBuf.Bytes())
|
||||
}
|
||||
if len(sealed) != 16 {
|
||||
panic(fmt.Sprintf("unexpected Retry integrity tag length: %d", len(sealed)))
|
||||
|
||||
19
vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
generated
vendored
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
|
||||
const sessionTicketRevision = 2
|
||||
const sessionTicketRevision = 4
|
||||
|
||||
type sessionTicket struct {
|
||||
Parameters *wire.TransportParameters
|
||||
@@ -21,10 +21,13 @@ func (t *sessionTicket) Marshal() []byte {
|
||||
b := make([]byte, 0, 256)
|
||||
b = quicvarint.Append(b, sessionTicketRevision)
|
||||
b = quicvarint.Append(b, uint64(t.RTT.Microseconds()))
|
||||
if t.Parameters == nil {
|
||||
return b
|
||||
}
|
||||
return t.Parameters.MarshalForSessionTicket(b)
|
||||
}
|
||||
|
||||
func (t *sessionTicket) Unmarshal(b []byte) error {
|
||||
func (t *sessionTicket) Unmarshal(b []byte, using0RTT bool) error {
|
||||
r := bytes.NewReader(b)
|
||||
rev, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
@@ -37,11 +40,15 @@ func (t *sessionTicket) Unmarshal(b []byte) error {
|
||||
if err != nil {
|
||||
return errors.New("failed to read RTT")
|
||||
}
|
||||
var tp wire.TransportParameters
|
||||
if err := tp.UnmarshalFromSessionTicket(r); err != nil {
|
||||
return fmt.Errorf("unmarshaling transport parameters from session ticket failed: %s", err.Error())
|
||||
if using0RTT {
|
||||
var tp wire.TransportParameters
|
||||
if err := tp.UnmarshalFromSessionTicket(r); err != nil {
|
||||
return fmt.Errorf("unmarshaling transport parameters from session ticket failed: %s", err.Error())
|
||||
}
|
||||
t.Parameters = &tp
|
||||
} else if r.Len() > 0 {
|
||||
return fmt.Errorf("the session ticket has more bytes than expected")
|
||||
}
|
||||
t.Parameters = &tp
|
||||
t.RTT = time.Duration(rtt) * time.Microsecond
|
||||
return nil
|
||||
}
|
||||
|
||||
68
vendor/github.com/quic-go/quic-go/internal/handshake/tls_extension_handler.go
generated
vendored
68
vendor/github.com/quic-go/quic-go/internal/handshake/tls_extension_handler.go
generated
vendored
@@ -1,68 +0,0 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
)
|
||||
|
||||
const (
|
||||
quicTLSExtensionTypeOldDrafts = 0xffa5
|
||||
quicTLSExtensionType = 0x39
|
||||
)
|
||||
|
||||
type extensionHandler struct {
|
||||
ourParams []byte
|
||||
paramsChan chan []byte
|
||||
|
||||
extensionType uint16
|
||||
|
||||
perspective protocol.Perspective
|
||||
}
|
||||
|
||||
var _ tlsExtensionHandler = &extensionHandler{}
|
||||
|
||||
// newExtensionHandler creates a new extension handler
|
||||
func newExtensionHandler(params []byte, pers protocol.Perspective, v protocol.VersionNumber) tlsExtensionHandler {
|
||||
et := uint16(quicTLSExtensionType)
|
||||
if v == protocol.VersionDraft29 {
|
||||
et = quicTLSExtensionTypeOldDrafts
|
||||
}
|
||||
return &extensionHandler{
|
||||
ourParams: params,
|
||||
paramsChan: make(chan []byte),
|
||||
perspective: pers,
|
||||
extensionType: et,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *extensionHandler) GetExtensions(msgType uint8) []qtls.Extension {
|
||||
if (h.perspective == protocol.PerspectiveClient && messageType(msgType) != typeClientHello) ||
|
||||
(h.perspective == protocol.PerspectiveServer && messageType(msgType) != typeEncryptedExtensions) {
|
||||
return nil
|
||||
}
|
||||
return []qtls.Extension{{
|
||||
Type: h.extensionType,
|
||||
Data: h.ourParams,
|
||||
}}
|
||||
}
|
||||
|
||||
func (h *extensionHandler) ReceivedExtensions(msgType uint8, exts []qtls.Extension) {
|
||||
if (h.perspective == protocol.PerspectiveClient && messageType(msgType) != typeEncryptedExtensions) ||
|
||||
(h.perspective == protocol.PerspectiveServer && messageType(msgType) != typeClientHello) {
|
||||
return
|
||||
}
|
||||
|
||||
var data []byte
|
||||
for _, ext := range exts {
|
||||
if ext.Type == h.extensionType {
|
||||
data = ext.Data
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
h.paramsChan <- data
|
||||
}
|
||||
|
||||
func (h *extensionHandler) TransportParameters() <-chan []byte {
|
||||
return h.paramsChan
|
||||
}
|
||||
13
vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go
generated
vendored
13
vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@@ -45,15 +44,9 @@ type TokenGenerator struct {
|
||||
tokenProtector tokenProtector
|
||||
}
|
||||
|
||||
// NewTokenGenerator initializes a new TookenGenerator
|
||||
func NewTokenGenerator(rand io.Reader) (*TokenGenerator, error) {
|
||||
tokenProtector, err := newTokenProtector(rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TokenGenerator{
|
||||
tokenProtector: tokenProtector,
|
||||
}, nil
|
||||
// NewTokenGenerator initializes a new TokenGenerator
|
||||
func NewTokenGenerator(key TokenProtectorKey) *TokenGenerator {
|
||||
return &TokenGenerator{tokenProtector: newTokenProtector(key)}
|
||||
}
|
||||
|
||||
// NewRetryToken generates a new token for a Retry for a given source address
|
||||
|
||||
33
vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go
generated
vendored
33
vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go
generated
vendored
@@ -3,6 +3,7 @@ package handshake
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -10,6 +11,9 @@ import (
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// TokenProtectorKey is the key used to encrypt both Retry and session resumption tokens.
|
||||
type TokenProtectorKey [32]byte
|
||||
|
||||
// TokenProtector is used to create and verify a token
|
||||
type tokenProtector interface {
|
||||
// NewToken creates a new token
|
||||
@@ -18,40 +22,29 @@ type tokenProtector interface {
|
||||
DecodeToken([]byte) ([]byte, error)
|
||||
}
|
||||
|
||||
const (
|
||||
tokenSecretSize = 32
|
||||
tokenNonceSize = 32
|
||||
)
|
||||
const tokenNonceSize = 32
|
||||
|
||||
// tokenProtector is used to create and verify a token
|
||||
type tokenProtectorImpl struct {
|
||||
rand io.Reader
|
||||
secret []byte
|
||||
key TokenProtectorKey
|
||||
}
|
||||
|
||||
// newTokenProtector creates a source for source address tokens
|
||||
func newTokenProtector(rand io.Reader) (tokenProtector, error) {
|
||||
secret := make([]byte, tokenSecretSize)
|
||||
if _, err := rand.Read(secret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tokenProtectorImpl{
|
||||
rand: rand,
|
||||
secret: secret,
|
||||
}, nil
|
||||
func newTokenProtector(key TokenProtectorKey) tokenProtector {
|
||||
return &tokenProtectorImpl{key: key}
|
||||
}
|
||||
|
||||
// NewToken encodes data into a new token.
|
||||
func (s *tokenProtectorImpl) NewToken(data []byte) ([]byte, error) {
|
||||
nonce := make([]byte, tokenNonceSize)
|
||||
if _, err := s.rand.Read(nonce); err != nil {
|
||||
var nonce [tokenNonceSize]byte
|
||||
if _, err := rand.Read(nonce[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aead, aeadNonce, err := s.createAEAD(nonce)
|
||||
aead, aeadNonce, err := s.createAEAD(nonce[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(nonce, aead.Seal(nil, aeadNonce, data, nil)...), nil
|
||||
return append(nonce[:], aead.Seal(nil, aeadNonce, data, nil)...), nil
|
||||
}
|
||||
|
||||
// DecodeToken decodes a token.
|
||||
@@ -68,7 +61,7 @@ func (s *tokenProtectorImpl) DecodeToken(p []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (s *tokenProtectorImpl) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) {
|
||||
h := hkdf.New(sha256.New, s.secret, nonce, []byte("quic-go token source"))
|
||||
h := hkdf.New(sha256.New, s.key[:], nonce, []byte("quic-go token source"))
|
||||
key := make([]byte, 32) // use a 32 byte key, in order to select AES-256
|
||||
if _, err := io.ReadFull(h, key); err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
21
vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
generated
vendored
21
vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qerr"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
@@ -24,7 +23,7 @@ var KeyUpdateInterval uint64 = protocol.KeyUpdateInterval
|
||||
var FirstKeyUpdateInterval uint64 = 100
|
||||
|
||||
type updatableAEAD struct {
|
||||
suite *qtls.CipherSuiteTLS13
|
||||
suite *cipherSuite
|
||||
|
||||
keyPhase protocol.KeyPhase
|
||||
largestAcked protocol.PacketNumber
|
||||
@@ -58,7 +57,7 @@ type updatableAEAD struct {
|
||||
|
||||
rttStats *utils.RTTStats
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
version protocol.VersionNumber
|
||||
|
||||
@@ -71,7 +70,7 @@ var (
|
||||
_ ShortHeaderSealer = &updatableAEAD{}
|
||||
)
|
||||
|
||||
func newUpdatableAEAD(rttStats *utils.RTTStats, tracer logging.ConnectionTracer, logger utils.Logger, version protocol.VersionNumber) *updatableAEAD {
|
||||
func newUpdatableAEAD(rttStats *utils.RTTStats, tracer *logging.ConnectionTracer, logger utils.Logger, version protocol.VersionNumber) *updatableAEAD {
|
||||
return &updatableAEAD{
|
||||
firstPacketNumber: protocol.InvalidPacketNumber,
|
||||
largestAcked: protocol.InvalidPacketNumber,
|
||||
@@ -87,7 +86,7 @@ func newUpdatableAEAD(rttStats *utils.RTTStats, tracer logging.ConnectionTracer,
|
||||
func (a *updatableAEAD) rollKeys() {
|
||||
if a.prevRcvAEAD != nil {
|
||||
a.logger.Debugf("Dropping key phase %d ahead of scheduled time. Drop time was: %s", a.keyPhase-1, a.prevRcvAEADExpiry)
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.DroppedKey != nil {
|
||||
a.tracer.DroppedKey(a.keyPhase - 1)
|
||||
}
|
||||
a.prevRcvAEADExpiry = time.Time{}
|
||||
@@ -121,7 +120,7 @@ func (a *updatableAEAD) getNextTrafficSecret(hash crypto.Hash, ts []byte) []byte
|
||||
// SetReadKey sets the read key.
|
||||
// For the client, this function is called before SetWriteKey.
|
||||
// For the server, this function is called after SetWriteKey.
|
||||
func (a *updatableAEAD) SetReadKey(suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (a *updatableAEAD) SetReadKey(suite *cipherSuite, trafficSecret []byte) {
|
||||
a.rcvAEAD = createAEAD(suite, trafficSecret, a.version)
|
||||
a.headerDecrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
|
||||
if a.suite == nil {
|
||||
@@ -135,7 +134,7 @@ func (a *updatableAEAD) SetReadKey(suite *qtls.CipherSuiteTLS13, trafficSecret [
|
||||
// SetWriteKey sets the write key.
|
||||
// For the client, this function is called after SetReadKey.
|
||||
// For the server, this function is called before SetWriteKey.
|
||||
func (a *updatableAEAD) SetWriteKey(suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (a *updatableAEAD) SetWriteKey(suite *cipherSuite, trafficSecret []byte) {
|
||||
a.sendAEAD = createAEAD(suite, trafficSecret, a.version)
|
||||
a.headerEncrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
|
||||
if a.suite == nil {
|
||||
@@ -146,7 +145,7 @@ func (a *updatableAEAD) SetWriteKey(suite *qtls.CipherSuiteTLS13, trafficSecret
|
||||
a.nextSendAEAD = createAEAD(suite, a.nextSendTrafficSecret, a.version)
|
||||
}
|
||||
|
||||
func (a *updatableAEAD) setAEADParameters(aead cipher.AEAD, suite *qtls.CipherSuiteTLS13) {
|
||||
func (a *updatableAEAD) setAEADParameters(aead cipher.AEAD, suite *cipherSuite) {
|
||||
a.nonceBuf = make([]byte, aead.NonceSize())
|
||||
a.aeadOverhead = aead.Overhead()
|
||||
a.suite = suite
|
||||
@@ -183,7 +182,7 @@ func (a *updatableAEAD) open(dst, src []byte, rcvTime time.Time, pn protocol.Pac
|
||||
a.prevRcvAEAD = nil
|
||||
a.logger.Debugf("Dropping key phase %d", a.keyPhase-1)
|
||||
a.prevRcvAEADExpiry = time.Time{}
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.DroppedKey != nil {
|
||||
a.tracer.DroppedKey(a.keyPhase - 1)
|
||||
}
|
||||
}
|
||||
@@ -217,7 +216,7 @@ func (a *updatableAEAD) open(dst, src []byte, rcvTime time.Time, pn protocol.Pac
|
||||
// The peer initiated this key update. It's safe to drop the keys for the previous generation now.
|
||||
// Start a timer to drop the previous key generation.
|
||||
a.startKeyDropTimer(rcvTime)
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.UpdatedKey != nil {
|
||||
a.tracer.UpdatedKey(a.keyPhase, true)
|
||||
}
|
||||
a.firstRcvdWithCurrentKey = pn
|
||||
@@ -309,7 +308,7 @@ func (a *updatableAEAD) KeyPhase() protocol.KeyPhaseBit {
|
||||
if a.shouldInitiateKeyUpdate() {
|
||||
a.rollKeys()
|
||||
a.logger.Debugf("Initiating key update to key phase %d", a.keyPhase)
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.UpdatedKey != nil {
|
||||
a.tracer.UpdatedKey(a.keyPhase, false)
|
||||
}
|
||||
}
|
||||
|
||||
13
vendor/github.com/quic-go/quic-go/internal/protocol/params.go
generated
vendored
13
vendor/github.com/quic-go/quic-go/internal/protocol/params.go
generated
vendored
@@ -5,6 +5,9 @@ import "time"
|
||||
// DesiredReceiveBufferSize is the kernel UDP receive buffer size that we'd like to use.
|
||||
const DesiredReceiveBufferSize = (1 << 20) * 2 // 2 MB
|
||||
|
||||
// DesiredSendBufferSize is the kernel UDP send buffer size that we'd like to use.
|
||||
const DesiredSendBufferSize = (1 << 20) * 2 // 2 MB
|
||||
|
||||
// InitialPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
|
||||
const InitialPacketSizeIPv4 = 1252
|
||||
|
||||
@@ -62,9 +65,6 @@ const MaxAcceptQueueSize = 32
|
||||
// TokenValidity is the duration that a (non-retry) token is considered valid
|
||||
const TokenValidity = 24 * time.Hour
|
||||
|
||||
// RetryTokenValidity is the duration that a retry token is considered valid
|
||||
const RetryTokenValidity = 10 * time.Second
|
||||
|
||||
// MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
|
||||
// When reached, it imposes a soft limit on sending new packets:
|
||||
// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent.
|
||||
@@ -105,9 +105,6 @@ const DefaultIdleTimeout = 30 * time.Second
|
||||
// DefaultHandshakeIdleTimeout is the default idle timeout used before handshake completion.
|
||||
const DefaultHandshakeIdleTimeout = 5 * time.Second
|
||||
|
||||
// DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds.
|
||||
const DefaultHandshakeTimeout = 10 * time.Second
|
||||
|
||||
// MaxKeepAliveInterval is the maximum time until we send a packet to keep a connection alive.
|
||||
// It should be shorter than the time that NATs clear their mapping.
|
||||
const MaxKeepAliveInterval = 20 * time.Second
|
||||
@@ -132,10 +129,6 @@ const MaxPostHandshakeCryptoFrameSize = 1000
|
||||
// but must ensure that a maximum size ACK frame fits into one packet.
|
||||
const MaxAckFrameSize ByteCount = 1000
|
||||
|
||||
// DefaultMaxDatagramFrameSize is the maximum size of a DATAGRAM frame (RFC 9221).
|
||||
// The size is chosen such that a DATAGRAM frame fits into a QUIC packet.
|
||||
const DefaultMaxDatagramFrameSize ByteCount = 1200
|
||||
|
||||
// DatagramRcvQueueLen is the length of the receive queue for DATAGRAM frames (RFC 9221)
|
||||
const DatagramRcvQueueLen = 128
|
||||
|
||||
|
||||
65
vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
generated
vendored
65
vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
generated
vendored
@@ -37,12 +37,61 @@ func (t PacketType) String() string {
|
||||
type ECN uint8
|
||||
|
||||
const (
|
||||
ECNNon ECN = iota // 00
|
||||
ECT1 // 01
|
||||
ECT0 // 10
|
||||
ECNCE // 11
|
||||
ECNUnsupported ECN = iota
|
||||
ECNNon // 00
|
||||
ECT1 // 01
|
||||
ECT0 // 10
|
||||
ECNCE // 11
|
||||
)
|
||||
|
||||
func ParseECNHeaderBits(bits byte) ECN {
|
||||
switch bits {
|
||||
case 0:
|
||||
return ECNNon
|
||||
case 0b00000010:
|
||||
return ECT0
|
||||
case 0b00000001:
|
||||
return ECT1
|
||||
case 0b00000011:
|
||||
return ECNCE
|
||||
default:
|
||||
panic("invalid ECN bits")
|
||||
}
|
||||
}
|
||||
|
||||
func (e ECN) ToHeaderBits() byte {
|
||||
//nolint:exhaustive // There are only 4 values.
|
||||
switch e {
|
||||
case ECNNon:
|
||||
return 0
|
||||
case ECT0:
|
||||
return 0b00000010
|
||||
case ECT1:
|
||||
return 0b00000001
|
||||
case ECNCE:
|
||||
return 0b00000011
|
||||
default:
|
||||
panic("ECN unsupported")
|
||||
}
|
||||
}
|
||||
|
||||
func (e ECN) String() string {
|
||||
switch e {
|
||||
case ECNUnsupported:
|
||||
return "ECN unsupported"
|
||||
case ECNNon:
|
||||
return "Not-ECT"
|
||||
case ECT1:
|
||||
return "ECT(1)"
|
||||
case ECT0:
|
||||
return "ECT(0)"
|
||||
case ECNCE:
|
||||
return "CE"
|
||||
default:
|
||||
return fmt.Sprintf("invalid ECN value: %d", e)
|
||||
}
|
||||
}
|
||||
|
||||
// A ByteCount in QUIC
|
||||
type ByteCount int64
|
||||
|
||||
@@ -59,7 +108,10 @@ type StatelessResetToken [16]byte
|
||||
// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
|
||||
// UDP adds an additional 8 bytes. This is a total overhead of 48 bytes.
|
||||
// Ethernet's max packet size is 1500 bytes, 1500 - 48 = 1452.
|
||||
const MaxPacketBufferSize ByteCount = 1452
|
||||
const MaxPacketBufferSize = 1452
|
||||
|
||||
// MaxLargePacketBufferSize is used when using GSO
|
||||
const MaxLargePacketBufferSize = 20 * 1024
|
||||
|
||||
// MinInitialPacketSize is the minimum size an Initial packet is required to have.
|
||||
const MinInitialPacketSize = 1200
|
||||
@@ -77,6 +129,9 @@ const MinConnectionIDLenInitial = 8
|
||||
// DefaultAckDelayExponent is the default ack delay exponent
|
||||
const DefaultAckDelayExponent = 3
|
||||
|
||||
// DefaultActiveConnectionIDLimit is the default active connection ID limit
|
||||
const DefaultActiveConnectionIDLimit = 2
|
||||
|
||||
// MaxAckDelayExponent is the maximum ack delay exponent
|
||||
const MaxAckDelayExponent = 20
|
||||
|
||||
|
||||
6
vendor/github.com/quic-go/quic-go/internal/protocol/version.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/protocol/version.go
generated
vendored
@@ -19,14 +19,14 @@ const (
|
||||
// The version numbers, making grepping easier
|
||||
const (
|
||||
VersionUnknown VersionNumber = math.MaxUint32
|
||||
VersionDraft29 VersionNumber = 0xff00001d
|
||||
versionDraft29 VersionNumber = 0xff00001d // draft-29 used to be a widely deployed version
|
||||
Version1 VersionNumber = 0x1
|
||||
Version2 VersionNumber = 0x6b3343cf
|
||||
)
|
||||
|
||||
// SupportedVersions lists the versions that the server supports
|
||||
// must be in sorted descending order
|
||||
var SupportedVersions = []VersionNumber{Version1, Version2, VersionDraft29}
|
||||
var SupportedVersions = []VersionNumber{Version1, Version2}
|
||||
|
||||
// IsValidVersion says if the version is known to quic-go
|
||||
func IsValidVersion(v VersionNumber) bool {
|
||||
@@ -38,7 +38,7 @@ func (vn VersionNumber) String() string {
|
||||
switch vn {
|
||||
case VersionUnknown:
|
||||
return "unknown"
|
||||
case VersionDraft29:
|
||||
case versionDraft29:
|
||||
return "draft-29"
|
||||
case Version1:
|
||||
return "v1"
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go
generated
vendored
@@ -40,7 +40,7 @@ func (e TransportErrorCode) Message() string {
|
||||
if !e.IsCryptoError() {
|
||||
return ""
|
||||
}
|
||||
return qtls.Alert(e - 0x100).Error()
|
||||
return qtls.AlertError(e - 0x100).Error()
|
||||
}
|
||||
|
||||
func (e TransportErrorCode) String() string {
|
||||
|
||||
14
vendor/github.com/quic-go/quic-go/internal/qerr/errors.go
generated
vendored
14
vendor/github.com/quic-go/quic-go/internal/qerr/errors.go
generated
vendored
@@ -17,15 +17,16 @@ type TransportError struct {
|
||||
FrameType uint64
|
||||
ErrorCode TransportErrorCode
|
||||
ErrorMessage string
|
||||
error error // only set for local errors, sometimes
|
||||
}
|
||||
|
||||
var _ error = &TransportError{}
|
||||
|
||||
// NewLocalCryptoError create a new TransportError instance for a crypto error
|
||||
func NewLocalCryptoError(tlsAlert uint8, errorMessage string) *TransportError {
|
||||
func NewLocalCryptoError(tlsAlert uint8, err error) *TransportError {
|
||||
return &TransportError{
|
||||
ErrorCode: 0x100 + TransportErrorCode(tlsAlert),
|
||||
ErrorMessage: errorMessage,
|
||||
ErrorCode: 0x100 + TransportErrorCode(tlsAlert),
|
||||
error: err,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +36,9 @@ func (e *TransportError) Error() string {
|
||||
str += fmt.Sprintf(" (frame type: %#x)", e.FrameType)
|
||||
}
|
||||
msg := e.ErrorMessage
|
||||
if len(msg) == 0 && e.error != nil {
|
||||
msg = e.error.Error()
|
||||
}
|
||||
if len(msg) == 0 {
|
||||
msg = e.ErrorCode.Message()
|
||||
}
|
||||
@@ -48,6 +52,10 @@ func (e *TransportError) Is(target error) bool {
|
||||
return target == net.ErrClosed
|
||||
}
|
||||
|
||||
func (e *TransportError) Unwrap() error {
|
||||
return e.error
|
||||
}
|
||||
|
||||
// An ApplicationErrorCode is an application-defined error code.
|
||||
type ApplicationErrorCode uint64
|
||||
|
||||
|
||||
66
vendor/github.com/quic-go/quic-go/internal/qtls/cipher_suite_go121.go
generated
vendored
Normal file
66
vendor/github.com/quic-go/quic-go/internal/qtls/cipher_suite_go121.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
//go:build go1.21
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type cipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
//go:linkname cipherSuiteTLS13ByID crypto/tls.cipherSuiteTLS13ByID
|
||||
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
|
||||
|
||||
//go:linkname cipherSuitesTLS13 crypto/tls.cipherSuitesTLS13
|
||||
var cipherSuitesTLS13 []unsafe.Pointer
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13 crypto/tls.defaultCipherSuitesTLS13
|
||||
var defaultCipherSuitesTLS13 []uint16
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13NoAES crypto/tls.defaultCipherSuitesTLS13NoAES
|
||||
var defaultCipherSuitesTLS13NoAES []uint16
|
||||
|
||||
var cipherSuitesModified bool
|
||||
|
||||
// SetCipherSuite modifies the cipherSuiteTLS13 slice of cipher suites inside qtls
|
||||
// such that it only contains the cipher suite with the chosen id.
|
||||
// The reset function returned resets them back to the original value.
|
||||
func SetCipherSuite(id uint16) (reset func()) {
|
||||
if cipherSuitesModified {
|
||||
panic("cipher suites modified multiple times without resetting")
|
||||
}
|
||||
cipherSuitesModified = true
|
||||
|
||||
origCipherSuitesTLS13 := append([]unsafe.Pointer{}, cipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13 := append([]uint16{}, defaultCipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13NoAES := append([]uint16{}, defaultCipherSuitesTLS13NoAES...)
|
||||
// The order is given by the order of the slice elements in cipherSuitesTLS13 in qtls.
|
||||
switch id {
|
||||
case tls.TLS_AES_128_GCM_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[:1]
|
||||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[1:2]
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[2:]
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected cipher suite: %d", id))
|
||||
}
|
||||
defaultCipherSuitesTLS13 = []uint16{id}
|
||||
defaultCipherSuitesTLS13NoAES = []uint16{id}
|
||||
|
||||
return func() {
|
||||
cipherSuitesTLS13 = origCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13 = origDefaultCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13NoAES = origDefaultCipherSuitesTLS13NoAES
|
||||
cipherSuitesModified = false
|
||||
}
|
||||
}
|
||||
63
vendor/github.com/quic-go/quic-go/internal/qtls/client_session_cache.go
generated
vendored
Normal file
63
vendor/github.com/quic-go/quic-go/internal/qtls/client_session_cache.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
//go:build go1.21
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
type clientSessionCache struct {
|
||||
getData func() []byte
|
||||
setData func([]byte) (allowEarlyData bool)
|
||||
wrapped tls.ClientSessionCache
|
||||
}
|
||||
|
||||
var _ tls.ClientSessionCache = &clientSessionCache{}
|
||||
|
||||
func (c clientSessionCache) Put(key string, cs *tls.ClientSessionState) {
|
||||
if cs == nil {
|
||||
c.wrapped.Put(key, nil)
|
||||
return
|
||||
}
|
||||
ticket, state, err := cs.ResumptionState()
|
||||
if err != nil || state == nil {
|
||||
c.wrapped.Put(key, cs)
|
||||
return
|
||||
}
|
||||
state.Extra = append(state.Extra, addExtraPrefix(c.getData()))
|
||||
newCS, err := tls.NewResumptionState(ticket, state)
|
||||
if err != nil {
|
||||
// It's not clear why this would error. Just save the original state.
|
||||
c.wrapped.Put(key, cs)
|
||||
return
|
||||
}
|
||||
c.wrapped.Put(key, newCS)
|
||||
}
|
||||
|
||||
func (c clientSessionCache) Get(key string) (*tls.ClientSessionState, bool) {
|
||||
cs, ok := c.wrapped.Get(key)
|
||||
if !ok || cs == nil {
|
||||
return cs, ok
|
||||
}
|
||||
ticket, state, err := cs.ResumptionState()
|
||||
if err != nil {
|
||||
// It's not clear why this would error.
|
||||
// Remove the ticket from the session cache, so we don't run into this error over and over again
|
||||
c.wrapped.Put(key, nil)
|
||||
return nil, false
|
||||
}
|
||||
var earlyData bool
|
||||
// restore QUIC transport parameters and RTT stored in state.Extra
|
||||
if extra := findExtraData(state.Extra); extra != nil {
|
||||
earlyData = c.setData(extra)
|
||||
}
|
||||
state.EarlyData = earlyData
|
||||
session, err := tls.NewResumptionState(ticket, state)
|
||||
if err != nil {
|
||||
// It's not clear why this would error.
|
||||
// Remove the ticket from the session cache, so we don't run into this error over and over again
|
||||
c.wrapped.Put(key, nil)
|
||||
return nil, false
|
||||
}
|
||||
return session, true
|
||||
}
|
||||
145
vendor/github.com/quic-go/quic-go/internal/qtls/go119.go
generated
vendored
145
vendor/github.com/quic-go/quic-go/internal/qtls/go119.go
generated
vendored
@@ -1,145 +0,0 @@
|
||||
//go:build go1.19 && !go1.20
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
"github.com/quic-go/qtls-go1-19"
|
||||
)
|
||||
|
||||
type (
|
||||
// Alert is a TLS alert
|
||||
Alert = qtls.Alert
|
||||
// A Certificate is qtls.Certificate.
|
||||
Certificate = qtls.Certificate
|
||||
// CertificateRequestInfo contains information about a certificate request.
|
||||
CertificateRequestInfo = qtls.CertificateRequestInfo
|
||||
// A CipherSuiteTLS13 is a cipher suite for TLS 1.3
|
||||
CipherSuiteTLS13 = qtls.CipherSuiteTLS13
|
||||
// ClientHelloInfo contains information about a ClientHello.
|
||||
ClientHelloInfo = qtls.ClientHelloInfo
|
||||
// ClientSessionCache is a cache used for session resumption.
|
||||
ClientSessionCache = qtls.ClientSessionCache
|
||||
// ClientSessionState is a state needed for session resumption.
|
||||
ClientSessionState = qtls.ClientSessionState
|
||||
// A Config is a qtls.Config.
|
||||
Config = qtls.Config
|
||||
// A Conn is a qtls.Conn.
|
||||
Conn = qtls.Conn
|
||||
// ConnectionState contains information about the state of the connection.
|
||||
ConnectionState = qtls.ConnectionStateWith0RTT
|
||||
// EncryptionLevel is the encryption level of a message.
|
||||
EncryptionLevel = qtls.EncryptionLevel
|
||||
// Extension is a TLS extension
|
||||
Extension = qtls.Extension
|
||||
// ExtraConfig is the qtls.ExtraConfig
|
||||
ExtraConfig = qtls.ExtraConfig
|
||||
// RecordLayer is a qtls RecordLayer.
|
||||
RecordLayer = qtls.RecordLayer
|
||||
)
|
||||
|
||||
const (
|
||||
// EncryptionHandshake is the Handshake encryption level
|
||||
EncryptionHandshake = qtls.EncryptionHandshake
|
||||
// Encryption0RTT is the 0-RTT encryption level
|
||||
Encryption0RTT = qtls.Encryption0RTT
|
||||
// EncryptionApplication is the application data encryption level
|
||||
EncryptionApplication = qtls.EncryptionApplication
|
||||
)
|
||||
|
||||
// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
|
||||
func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
|
||||
return qtls.AEADAESGCMTLS13(key, fixedNonce)
|
||||
}
|
||||
|
||||
// Client returns a new TLS client side connection.
|
||||
func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Client(conn, config, extraConfig)
|
||||
}
|
||||
|
||||
// Server returns a new TLS server side connection.
|
||||
func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Server(conn, config, extraConfig)
|
||||
}
|
||||
|
||||
func GetConnectionState(conn *Conn) ConnectionState {
|
||||
return conn.ConnectionStateWith0RTT()
|
||||
}
|
||||
|
||||
// ToTLSConnectionState extracts the tls.ConnectionState
|
||||
func ToTLSConnectionState(cs ConnectionState) tls.ConnectionState {
|
||||
return cs.ConnectionState
|
||||
}
|
||||
|
||||
type cipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
//go:linkname cipherSuiteTLS13ByID github.com/quic-go/qtls-go1-19.cipherSuiteTLS13ByID
|
||||
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
|
||||
|
||||
// CipherSuiteTLS13ByID gets a TLS 1.3 cipher suite.
|
||||
func CipherSuiteTLS13ByID(id uint16) *CipherSuiteTLS13 {
|
||||
val := cipherSuiteTLS13ByID(id)
|
||||
cs := (*cipherSuiteTLS13)(unsafe.Pointer(val))
|
||||
return &qtls.CipherSuiteTLS13{
|
||||
ID: cs.ID,
|
||||
KeyLen: cs.KeyLen,
|
||||
AEAD: cs.AEAD,
|
||||
Hash: cs.Hash,
|
||||
}
|
||||
}
|
||||
|
||||
//go:linkname cipherSuitesTLS13 github.com/quic-go/qtls-go1-19.cipherSuitesTLS13
|
||||
var cipherSuitesTLS13 []unsafe.Pointer
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13 github.com/quic-go/qtls-go1-19.defaultCipherSuitesTLS13
|
||||
var defaultCipherSuitesTLS13 []uint16
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13NoAES github.com/quic-go/qtls-go1-19.defaultCipherSuitesTLS13NoAES
|
||||
var defaultCipherSuitesTLS13NoAES []uint16
|
||||
|
||||
var cipherSuitesModified bool
|
||||
|
||||
// SetCipherSuite modifies the cipherSuiteTLS13 slice of cipher suites inside qtls
|
||||
// such that it only contains the cipher suite with the chosen id.
|
||||
// The reset function returned resets them back to the original value.
|
||||
func SetCipherSuite(id uint16) (reset func()) {
|
||||
if cipherSuitesModified {
|
||||
panic("cipher suites modified multiple times without resetting")
|
||||
}
|
||||
cipherSuitesModified = true
|
||||
|
||||
origCipherSuitesTLS13 := append([]unsafe.Pointer{}, cipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13 := append([]uint16{}, defaultCipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13NoAES := append([]uint16{}, defaultCipherSuitesTLS13NoAES...)
|
||||
// The order is given by the order of the slice elements in cipherSuitesTLS13 in qtls.
|
||||
switch id {
|
||||
case tls.TLS_AES_128_GCM_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[:1]
|
||||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[1:2]
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[2:]
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected cipher suite: %d", id))
|
||||
}
|
||||
defaultCipherSuitesTLS13 = []uint16{id}
|
||||
defaultCipherSuitesTLS13NoAES = []uint16{id}
|
||||
|
||||
return func() {
|
||||
cipherSuitesTLS13 = origCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13 = origDefaultCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13NoAES = origDefaultCipherSuitesTLS13NoAES
|
||||
cipherSuitesModified = false
|
||||
}
|
||||
}
|
||||
144
vendor/github.com/quic-go/quic-go/internal/qtls/go120.go
generated
vendored
144
vendor/github.com/quic-go/quic-go/internal/qtls/go120.go
generated
vendored
@@ -1,101 +1,99 @@
|
||||
//go:build go1.20
|
||||
//go:build go1.20 && !go1.21
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
|
||||
"github.com/quic-go/qtls-go1-20"
|
||||
)
|
||||
|
||||
type (
|
||||
// Alert is a TLS alert
|
||||
Alert = qtls.Alert
|
||||
// A Certificate is qtls.Certificate.
|
||||
Certificate = qtls.Certificate
|
||||
// CertificateRequestInfo contains information about a certificate request.
|
||||
CertificateRequestInfo = qtls.CertificateRequestInfo
|
||||
// A CipherSuiteTLS13 is a cipher suite for TLS 1.3
|
||||
CipherSuiteTLS13 = qtls.CipherSuiteTLS13
|
||||
// ClientHelloInfo contains information about a ClientHello.
|
||||
ClientHelloInfo = qtls.ClientHelloInfo
|
||||
// ClientSessionCache is a cache used for session resumption.
|
||||
ClientSessionCache = qtls.ClientSessionCache
|
||||
// ClientSessionState is a state needed for session resumption.
|
||||
ClientSessionState = qtls.ClientSessionState
|
||||
// A Config is a qtls.Config.
|
||||
Config = qtls.Config
|
||||
// A Conn is a qtls.Conn.
|
||||
Conn = qtls.Conn
|
||||
// ConnectionState contains information about the state of the connection.
|
||||
ConnectionState = qtls.ConnectionStateWith0RTT
|
||||
// EncryptionLevel is the encryption level of a message.
|
||||
EncryptionLevel = qtls.EncryptionLevel
|
||||
// Extension is a TLS extension
|
||||
Extension = qtls.Extension
|
||||
// ExtraConfig is the qtls.ExtraConfig
|
||||
ExtraConfig = qtls.ExtraConfig
|
||||
// RecordLayer is a qtls RecordLayer.
|
||||
RecordLayer = qtls.RecordLayer
|
||||
QUICConn = qtls.QUICConn
|
||||
QUICConfig = qtls.QUICConfig
|
||||
QUICEvent = qtls.QUICEvent
|
||||
QUICEventKind = qtls.QUICEventKind
|
||||
QUICEncryptionLevel = qtls.QUICEncryptionLevel
|
||||
AlertError = qtls.AlertError
|
||||
)
|
||||
|
||||
const (
|
||||
// EncryptionHandshake is the Handshake encryption level
|
||||
EncryptionHandshake = qtls.EncryptionHandshake
|
||||
// Encryption0RTT is the 0-RTT encryption level
|
||||
Encryption0RTT = qtls.Encryption0RTT
|
||||
// EncryptionApplication is the application data encryption level
|
||||
EncryptionApplication = qtls.EncryptionApplication
|
||||
QUICEncryptionLevelInitial = qtls.QUICEncryptionLevelInitial
|
||||
QUICEncryptionLevelEarly = qtls.QUICEncryptionLevelEarly
|
||||
QUICEncryptionLevelHandshake = qtls.QUICEncryptionLevelHandshake
|
||||
QUICEncryptionLevelApplication = qtls.QUICEncryptionLevelApplication
|
||||
)
|
||||
|
||||
// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
|
||||
func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
|
||||
return qtls.AEADAESGCMTLS13(key, fixedNonce)
|
||||
const (
|
||||
QUICNoEvent = qtls.QUICNoEvent
|
||||
QUICSetReadSecret = qtls.QUICSetReadSecret
|
||||
QUICSetWriteSecret = qtls.QUICSetWriteSecret
|
||||
QUICWriteData = qtls.QUICWriteData
|
||||
QUICTransportParameters = qtls.QUICTransportParameters
|
||||
QUICTransportParametersRequired = qtls.QUICTransportParametersRequired
|
||||
QUICRejectedEarlyData = qtls.QUICRejectedEarlyData
|
||||
QUICHandshakeDone = qtls.QUICHandshakeDone
|
||||
)
|
||||
|
||||
func SetupConfigForServer(conf *QUICConfig, enable0RTT bool, getDataForSessionTicket func() []byte, handleSessionTicket func([]byte, bool) bool) {
|
||||
qtls.InitSessionTicketKeys(conf.TLSConfig)
|
||||
conf.TLSConfig = conf.TLSConfig.Clone()
|
||||
conf.TLSConfig.MinVersion = tls.VersionTLS13
|
||||
conf.ExtraConfig = &qtls.ExtraConfig{
|
||||
Enable0RTT: enable0RTT,
|
||||
Accept0RTT: func(data []byte) bool {
|
||||
return handleSessionTicket(data, true)
|
||||
},
|
||||
GetAppDataForSessionTicket: getDataForSessionTicket,
|
||||
}
|
||||
}
|
||||
|
||||
// Client returns a new TLS client side connection.
|
||||
func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Client(conn, config, extraConfig)
|
||||
func SetupConfigForClient(conf *QUICConfig, getDataForSessionState func() []byte, setDataFromSessionState func([]byte) bool) {
|
||||
conf.ExtraConfig = &qtls.ExtraConfig{
|
||||
GetAppDataForSessionState: getDataForSessionState,
|
||||
SetAppDataFromSessionState: setDataFromSessionState,
|
||||
}
|
||||
}
|
||||
|
||||
// Server returns a new TLS server side connection.
|
||||
func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Server(conn, config, extraConfig)
|
||||
func QUICServer(config *QUICConfig) *QUICConn {
|
||||
return qtls.QUICServer(config)
|
||||
}
|
||||
|
||||
func GetConnectionState(conn *Conn) ConnectionState {
|
||||
return conn.ConnectionStateWith0RTT()
|
||||
func QUICClient(config *QUICConfig) *QUICConn {
|
||||
return qtls.QUICClient(config)
|
||||
}
|
||||
|
||||
// ToTLSConnectionState extracts the tls.ConnectionState
|
||||
func ToTLSConnectionState(cs ConnectionState) tls.ConnectionState {
|
||||
return cs.ConnectionState
|
||||
func ToTLSEncryptionLevel(e protocol.EncryptionLevel) qtls.QUICEncryptionLevel {
|
||||
switch e {
|
||||
case protocol.EncryptionInitial:
|
||||
return qtls.QUICEncryptionLevelInitial
|
||||
case protocol.EncryptionHandshake:
|
||||
return qtls.QUICEncryptionLevelHandshake
|
||||
case protocol.Encryption1RTT:
|
||||
return qtls.QUICEncryptionLevelApplication
|
||||
case protocol.Encryption0RTT:
|
||||
return qtls.QUICEncryptionLevelEarly
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
type cipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
//go:linkname cipherSuiteTLS13ByID github.com/quic-go/qtls-go1-20.cipherSuiteTLS13ByID
|
||||
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
|
||||
|
||||
// CipherSuiteTLS13ByID gets a TLS 1.3 cipher suite.
|
||||
func CipherSuiteTLS13ByID(id uint16) *CipherSuiteTLS13 {
|
||||
val := cipherSuiteTLS13ByID(id)
|
||||
cs := (*cipherSuiteTLS13)(unsafe.Pointer(val))
|
||||
return &qtls.CipherSuiteTLS13{
|
||||
ID: cs.ID,
|
||||
KeyLen: cs.KeyLen,
|
||||
AEAD: cs.AEAD,
|
||||
Hash: cs.Hash,
|
||||
func FromTLSEncryptionLevel(e qtls.QUICEncryptionLevel) protocol.EncryptionLevel {
|
||||
switch e {
|
||||
case qtls.QUICEncryptionLevelInitial:
|
||||
return protocol.EncryptionInitial
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
return protocol.EncryptionHandshake
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
return protocol.Encryption1RTT
|
||||
case qtls.QUICEncryptionLevelEarly:
|
||||
return protocol.Encryption0RTT
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpect encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,3 +141,7 @@ func SetCipherSuite(id uint16) (reset func()) {
|
||||
cipherSuitesModified = false
|
||||
}
|
||||
}
|
||||
|
||||
func SendSessionTicket(c *QUICConn, allow0RTT bool) error {
|
||||
return c.SendSessionTicket(allow0RTT)
|
||||
}
|
||||
|
||||
156
vendor/github.com/quic-go/quic-go/internal/qtls/go121.go
generated
vendored
156
vendor/github.com/quic-go/quic-go/internal/qtls/go121.go
generated
vendored
@@ -2,4 +2,158 @@
|
||||
|
||||
package qtls
|
||||
|
||||
var _ int = "The version of quic-go you're using can't be built on Go 1.21 yet. For more details, please see https://github.com/quic-go/quic-go/wiki/quic-go-and-Go-versions."
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
)
|
||||
|
||||
type (
|
||||
QUICConn = tls.QUICConn
|
||||
QUICConfig = tls.QUICConfig
|
||||
QUICEvent = tls.QUICEvent
|
||||
QUICEventKind = tls.QUICEventKind
|
||||
QUICEncryptionLevel = tls.QUICEncryptionLevel
|
||||
QUICSessionTicketOptions = tls.QUICSessionTicketOptions
|
||||
AlertError = tls.AlertError
|
||||
)
|
||||
|
||||
const (
|
||||
QUICEncryptionLevelInitial = tls.QUICEncryptionLevelInitial
|
||||
QUICEncryptionLevelEarly = tls.QUICEncryptionLevelEarly
|
||||
QUICEncryptionLevelHandshake = tls.QUICEncryptionLevelHandshake
|
||||
QUICEncryptionLevelApplication = tls.QUICEncryptionLevelApplication
|
||||
)
|
||||
|
||||
const (
|
||||
QUICNoEvent = tls.QUICNoEvent
|
||||
QUICSetReadSecret = tls.QUICSetReadSecret
|
||||
QUICSetWriteSecret = tls.QUICSetWriteSecret
|
||||
QUICWriteData = tls.QUICWriteData
|
||||
QUICTransportParameters = tls.QUICTransportParameters
|
||||
QUICTransportParametersRequired = tls.QUICTransportParametersRequired
|
||||
QUICRejectedEarlyData = tls.QUICRejectedEarlyData
|
||||
QUICHandshakeDone = tls.QUICHandshakeDone
|
||||
)
|
||||
|
||||
func QUICServer(config *QUICConfig) *QUICConn { return tls.QUICServer(config) }
|
||||
func QUICClient(config *QUICConfig) *QUICConn { return tls.QUICClient(config) }
|
||||
|
||||
func SetupConfigForServer(qconf *QUICConfig, _ bool, getData func() []byte, handleSessionTicket func([]byte, bool) bool) {
|
||||
conf := qconf.TLSConfig
|
||||
|
||||
// Workaround for https://github.com/golang/go/issues/60506.
|
||||
// This initializes the session tickets _before_ cloning the config.
|
||||
_, _ = conf.DecryptTicket(nil, tls.ConnectionState{})
|
||||
|
||||
conf = conf.Clone()
|
||||
conf.MinVersion = tls.VersionTLS13
|
||||
qconf.TLSConfig = conf
|
||||
|
||||
// add callbacks to save transport parameters into the session ticket
|
||||
origWrapSession := conf.WrapSession
|
||||
conf.WrapSession = func(cs tls.ConnectionState, state *tls.SessionState) ([]byte, error) {
|
||||
// Add QUIC session ticket
|
||||
state.Extra = append(state.Extra, addExtraPrefix(getData()))
|
||||
|
||||
if origWrapSession != nil {
|
||||
return origWrapSession(cs, state)
|
||||
}
|
||||
b, err := conf.EncryptTicket(cs, state)
|
||||
return b, err
|
||||
}
|
||||
origUnwrapSession := conf.UnwrapSession
|
||||
// UnwrapSession might be called multiple times, as the client can use multiple session tickets.
|
||||
// However, using 0-RTT is only possible with the first session ticket.
|
||||
// crypto/tls guarantees that this callback is called in the same order as the session ticket in the ClientHello.
|
||||
var unwrapCount int
|
||||
conf.UnwrapSession = func(identity []byte, connState tls.ConnectionState) (*tls.SessionState, error) {
|
||||
unwrapCount++
|
||||
var state *tls.SessionState
|
||||
var err error
|
||||
if origUnwrapSession != nil {
|
||||
state, err = origUnwrapSession(identity, connState)
|
||||
} else {
|
||||
state, err = conf.DecryptTicket(identity, connState)
|
||||
}
|
||||
if err != nil || state == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extra := findExtraData(state.Extra)
|
||||
if extra != nil {
|
||||
state.EarlyData = handleSessionTicket(extra, state.EarlyData && unwrapCount == 1)
|
||||
} else {
|
||||
state.EarlyData = false
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetupConfigForClient(qconf *QUICConfig, getData func() []byte, setData func([]byte) bool) {
|
||||
conf := qconf.TLSConfig
|
||||
if conf.ClientSessionCache != nil {
|
||||
origCache := conf.ClientSessionCache
|
||||
conf.ClientSessionCache = &clientSessionCache{
|
||||
wrapped: origCache,
|
||||
getData: getData,
|
||||
setData: setData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ToTLSEncryptionLevel(e protocol.EncryptionLevel) tls.QUICEncryptionLevel {
|
||||
switch e {
|
||||
case protocol.EncryptionInitial:
|
||||
return tls.QUICEncryptionLevelInitial
|
||||
case protocol.EncryptionHandshake:
|
||||
return tls.QUICEncryptionLevelHandshake
|
||||
case protocol.Encryption1RTT:
|
||||
return tls.QUICEncryptionLevelApplication
|
||||
case protocol.Encryption0RTT:
|
||||
return tls.QUICEncryptionLevelEarly
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
func FromTLSEncryptionLevel(e tls.QUICEncryptionLevel) protocol.EncryptionLevel {
|
||||
switch e {
|
||||
case tls.QUICEncryptionLevelInitial:
|
||||
return protocol.EncryptionInitial
|
||||
case tls.QUICEncryptionLevelHandshake:
|
||||
return protocol.EncryptionHandshake
|
||||
case tls.QUICEncryptionLevelApplication:
|
||||
return protocol.Encryption1RTT
|
||||
case tls.QUICEncryptionLevelEarly:
|
||||
return protocol.Encryption0RTT
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpect encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
const extraPrefix = "quic-go1"
|
||||
|
||||
func addExtraPrefix(b []byte) []byte {
|
||||
return append([]byte(extraPrefix), b...)
|
||||
}
|
||||
|
||||
func findExtraData(extras [][]byte) []byte {
|
||||
prefix := []byte(extraPrefix)
|
||||
for _, extra := range extras {
|
||||
if len(extra) < len(prefix) || !bytes.Equal(prefix, extra[:len(prefix)]) {
|
||||
continue
|
||||
}
|
||||
return extra[len(prefix):]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendSessionTicket(c *QUICConn, allow0RTT bool) error {
|
||||
return c.SendSessionTicket(tls.QUICSessionTicketOptions{
|
||||
EarlyData: allow0RTT,
|
||||
})
|
||||
}
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/internal/qtls/go_oldversion.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/qtls/go_oldversion.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
//go:build !go1.19
|
||||
//go:build !go1.20
|
||||
|
||||
package qtls
|
||||
|
||||
|
||||
86
vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go
generated
vendored
Normal file
86
vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package ringbuffer
|
||||
|
||||
// A RingBuffer is a ring buffer.
|
||||
// It acts as a heap that doesn't cause any allocations.
|
||||
type RingBuffer[T any] struct {
|
||||
ring []T
|
||||
headPos, tailPos int
|
||||
full bool
|
||||
}
|
||||
|
||||
// Init preallocs a buffer with a certain size.
|
||||
func (r *RingBuffer[T]) Init(size int) {
|
||||
r.ring = make([]T, size)
|
||||
}
|
||||
|
||||
// Len returns the number of elements in the ring buffer.
|
||||
func (r *RingBuffer[T]) Len() int {
|
||||
if r.full {
|
||||
return len(r.ring)
|
||||
}
|
||||
if r.tailPos >= r.headPos {
|
||||
return r.tailPos - r.headPos
|
||||
}
|
||||
return r.tailPos - r.headPos + len(r.ring)
|
||||
}
|
||||
|
||||
// Empty says if the ring buffer is empty.
|
||||
func (r *RingBuffer[T]) Empty() bool {
|
||||
return !r.full && r.headPos == r.tailPos
|
||||
}
|
||||
|
||||
// PushBack adds a new element.
|
||||
// If the ring buffer is full, its capacity is increased first.
|
||||
func (r *RingBuffer[T]) PushBack(t T) {
|
||||
if r.full || len(r.ring) == 0 {
|
||||
r.grow()
|
||||
}
|
||||
r.ring[r.tailPos] = t
|
||||
r.tailPos++
|
||||
if r.tailPos == len(r.ring) {
|
||||
r.tailPos = 0
|
||||
}
|
||||
if r.tailPos == r.headPos {
|
||||
r.full = true
|
||||
}
|
||||
}
|
||||
|
||||
// PopFront returns the next element.
|
||||
// It must not be called when the buffer is empty, that means that
|
||||
// callers might need to check if there are elements in the buffer first.
|
||||
func (r *RingBuffer[T]) PopFront() T {
|
||||
if r.Empty() {
|
||||
panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: pop from an empty queue")
|
||||
}
|
||||
r.full = false
|
||||
t := r.ring[r.headPos]
|
||||
r.ring[r.headPos] = *new(T)
|
||||
r.headPos++
|
||||
if r.headPos == len(r.ring) {
|
||||
r.headPos = 0
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Grow the maximum size of the queue.
|
||||
// This method assume the queue is full.
|
||||
func (r *RingBuffer[T]) grow() {
|
||||
oldRing := r.ring
|
||||
newSize := len(oldRing) * 2
|
||||
if newSize == 0 {
|
||||
newSize = 1
|
||||
}
|
||||
r.ring = make([]T, newSize)
|
||||
headLen := copy(r.ring, oldRing[r.headPos:])
|
||||
copy(r.ring[headLen:], oldRing[:r.headPos])
|
||||
r.headPos, r.tailPos, r.full = 0, len(oldRing), false
|
||||
}
|
||||
|
||||
// Clear removes all elements.
|
||||
func (r *RingBuffer[T]) Clear() {
|
||||
var zeroValue T
|
||||
for i := range r.ring {
|
||||
r.ring[i] = zeroValue
|
||||
}
|
||||
r.headPos, r.tailPos, r.full = 0, 0, false
|
||||
}
|
||||
6
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
@@ -103,8 +103,12 @@ func (r *RTTStats) SetMaxAckDelay(mad time.Duration) {
|
||||
// SetInitialRTT sets the initial RTT.
|
||||
// It is used during the 0-RTT handshake when restoring the RTT stats from the session state.
|
||||
func (r *RTTStats) SetInitialRTT(t time.Duration) {
|
||||
// On the server side, by the time we get to process the session ticket,
|
||||
// we might already have obtained an RTT measurement.
|
||||
// This can happen if we received the ClientHello in multiple pieces, and one of those pieces was lost.
|
||||
// Discard the restored value. A fresh measurement is always better.
|
||||
if r.hasMeasurement {
|
||||
panic("initial RTT set after first measurement")
|
||||
return
|
||||
}
|
||||
r.smoothedRTT = t
|
||||
r.latestRTT = t
|
||||
|
||||
57
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
generated
vendored
57
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
generated
vendored
@@ -22,19 +22,17 @@ type AckFrame struct {
|
||||
}
|
||||
|
||||
// parseAckFrame reads an ACK frame
|
||||
func parseAckFrame(r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protocol.VersionNumber) (*AckFrame, error) {
|
||||
func parseAckFrame(frame *AckFrame, r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protocol.VersionNumber) error {
|
||||
ecn := typ == ackECNFrameType
|
||||
|
||||
frame := GetAckFrame()
|
||||
|
||||
la, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
largestAcked := protocol.PacketNumber(la)
|
||||
delay, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
delayTime := time.Duration(delay*1<<ackDelayExponent) * time.Microsecond
|
||||
@@ -46,17 +44,17 @@ func parseAckFrame(r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protoc
|
||||
|
||||
numBlocks, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// read the first ACK range
|
||||
ab, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
ackBlock := protocol.PacketNumber(ab)
|
||||
if ackBlock > largestAcked {
|
||||
return nil, errors.New("invalid first ACK range")
|
||||
return errors.New("invalid first ACK range")
|
||||
}
|
||||
smallest := largestAcked - ackBlock
|
||||
|
||||
@@ -65,41 +63,50 @@ func parseAckFrame(r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protoc
|
||||
for i := uint64(0); i < numBlocks; i++ {
|
||||
g, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
gap := protocol.PacketNumber(g)
|
||||
if smallest < gap+2 {
|
||||
return nil, errInvalidAckRanges
|
||||
return errInvalidAckRanges
|
||||
}
|
||||
largest := smallest - gap - 2
|
||||
|
||||
ab, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
ackBlock := protocol.PacketNumber(ab)
|
||||
|
||||
if ackBlock > largest {
|
||||
return nil, errInvalidAckRanges
|
||||
return errInvalidAckRanges
|
||||
}
|
||||
smallest = largest - ackBlock
|
||||
frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largest})
|
||||
}
|
||||
|
||||
if !frame.validateAckRanges() {
|
||||
return nil, errInvalidAckRanges
|
||||
return errInvalidAckRanges
|
||||
}
|
||||
|
||||
// parse (and skip) the ECN section
|
||||
if ecn {
|
||||
for i := 0; i < 3; i++ {
|
||||
if _, err := quicvarint.Read(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ect0, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.ECT0 = ect0
|
||||
ect1, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.ECT1 = ect1
|
||||
ecnce, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.ECNCE = ecnce
|
||||
}
|
||||
|
||||
return frame, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append appends an ACK frame.
|
||||
@@ -242,6 +249,18 @@ func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool {
|
||||
return p <= f.AckRanges[i].Largest
|
||||
}
|
||||
|
||||
func (f *AckFrame) Reset() {
|
||||
f.DelayTime = 0
|
||||
f.ECT0 = 0
|
||||
f.ECT1 = 0
|
||||
f.ECNCE = 0
|
||||
for _, r := range f.AckRanges {
|
||||
r.Largest = 0
|
||||
r.Smallest = 0
|
||||
}
|
||||
f.AckRanges = f.AckRanges[:0]
|
||||
}
|
||||
|
||||
func encodeAckDelay(delay time.Duration) uint64 {
|
||||
return uint64(delay.Nanoseconds() / (1000 * (1 << protocol.AckDelayExponent)))
|
||||
}
|
||||
|
||||
24
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame_pool.go
generated
vendored
24
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame_pool.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package wire
|
||||
|
||||
import "sync"
|
||||
|
||||
var ackFramePool = sync.Pool{New: func() any {
|
||||
return &AckFrame{}
|
||||
}}
|
||||
|
||||
func GetAckFrame() *AckFrame {
|
||||
f := ackFramePool.Get().(*AckFrame)
|
||||
f.AckRanges = f.AckRanges[:0]
|
||||
f.ECNCE = 0
|
||||
f.ECT0 = 0
|
||||
f.ECT1 = 0
|
||||
f.DelayTime = 0
|
||||
return f
|
||||
}
|
||||
|
||||
func PutAckFrame(f *AckFrame) {
|
||||
if cap(f.AckRanges) > 4 {
|
||||
return
|
||||
}
|
||||
ackFramePool.Put(f)
|
||||
}
|
||||
6
vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go
generated
vendored
@@ -8,6 +8,12 @@ import (
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
|
||||
// MaxDatagramSize is the maximum size of a DATAGRAM frame (RFC 9221).
|
||||
// By setting it to a large value, we allow all datagrams that fit into a QUIC packet.
|
||||
// The value is chosen such that it can still be encoded as a 2 byte varint.
|
||||
// This is a var and not a const so it can be set in tests.
|
||||
var MaxDatagramSize protocol.ByteCount = 16383
|
||||
|
||||
// A DatagramFrame is a DATAGRAM frame
|
||||
type DatagramFrame struct {
|
||||
DataLenPresent bool
|
||||
|
||||
12
vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go
generated
vendored
12
vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go
generated
vendored
@@ -39,9 +39,12 @@ const (
|
||||
type frameParser struct {
|
||||
r bytes.Reader // cached bytes.Reader, so we don't have to repeatedly allocate them
|
||||
|
||||
ackDelayExponent uint8
|
||||
|
||||
ackDelayExponent uint8
|
||||
supportsDatagrams bool
|
||||
|
||||
// To avoid allocating when parsing, keep a single ACK frame struct.
|
||||
// It is used over and over again.
|
||||
ackFrame *AckFrame
|
||||
}
|
||||
|
||||
var _ FrameParser = &frameParser{}
|
||||
@@ -51,6 +54,7 @@ func NewFrameParser(supportsDatagrams bool) *frameParser {
|
||||
return &frameParser{
|
||||
r: *bytes.NewReader(nil),
|
||||
supportsDatagrams: supportsDatagrams,
|
||||
ackFrame: &AckFrame{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +109,9 @@ func (p *frameParser) parseFrame(r *bytes.Reader, typ uint64, encLevel protocol.
|
||||
if encLevel != protocol.Encryption1RTT {
|
||||
ackDelayExponent = protocol.DefaultAckDelayExponent
|
||||
}
|
||||
frame, err = parseAckFrame(r, typ, ackDelayExponent, v)
|
||||
p.ackFrame.Reset()
|
||||
err = parseAckFrame(p.ackFrame, r, typ, ackDelayExponent, v)
|
||||
frame = p.ackFrame
|
||||
case resetStreamFrameType:
|
||||
frame, err = parseResetStreamFrame(r, v)
|
||||
case stopSendingFrameType:
|
||||
|
||||
8
vendor/github.com/quic-go/quic-go/internal/wire/header.go
generated
vendored
8
vendor/github.com/quic-go/quic-go/internal/wire/header.go
generated
vendored
@@ -13,8 +13,6 @@ import (
|
||||
)
|
||||
|
||||
// ParseConnectionID parses the destination connection ID of a packet.
|
||||
// It uses the data slice for the connection ID.
|
||||
// That means that the connection ID must not be used after the packet buffer is released.
|
||||
func ParseConnectionID(data []byte, shortHeaderConnIDLen int) (protocol.ConnectionID, error) {
|
||||
if len(data) == 0 {
|
||||
return protocol.ConnectionID{}, io.EOF
|
||||
@@ -76,6 +74,10 @@ func parseArbitraryLenConnectionIDs(r *bytes.Reader) (dest, src protocol.Arbitra
|
||||
return destConnID, srcConnID, nil
|
||||
}
|
||||
|
||||
func IsPotentialQUICPacket(firstByte byte) bool {
|
||||
return firstByte&0x40 > 0
|
||||
}
|
||||
|
||||
// IsLongHeaderPacket says if this is a Long Header packet
|
||||
func IsLongHeaderPacket(firstByte byte) bool {
|
||||
return firstByte&0x80 > 0
|
||||
@@ -110,7 +112,7 @@ func Is0RTTPacket(b []byte) bool {
|
||||
version := protocol.VersionNumber(binary.BigEndian.Uint32(b[1:5]))
|
||||
//nolint:exhaustive // We only need to test QUIC versions that we support.
|
||||
switch version {
|
||||
case protocol.Version1, protocol.VersionDraft29:
|
||||
case protocol.Version1:
|
||||
return b[0]>>4&0b11 == 0b01
|
||||
case protocol.Version2:
|
||||
return b[0]>>4&0b11 == 0b10
|
||||
|
||||
4
vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go
generated
vendored
@@ -2,6 +2,7 @@ package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@@ -34,6 +35,9 @@ func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewC
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connIDLen == 0 {
|
||||
return nil, errors.New("invalid zero-length connection ID")
|
||||
}
|
||||
connID, err := protocol.ReadConnectionID(r, int(connIDLen))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
57
vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go
generated
vendored
57
vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go
generated
vendored
@@ -2,14 +2,13 @@ package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@@ -26,15 +25,6 @@ var AdditionalTransportParametersClient map[uint64][]byte
|
||||
|
||||
const transportParameterMarshalingVersion = 1
|
||||
|
||||
var (
|
||||
randomMutex sync.Mutex
|
||||
random rand.Rand
|
||||
)
|
||||
|
||||
func init() {
|
||||
random = *rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
type transportParameterID uint64
|
||||
|
||||
const (
|
||||
@@ -118,6 +108,7 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
var (
|
||||
readOriginalDestinationConnectionID bool
|
||||
readInitialSourceConnectionID bool
|
||||
readActiveConnectionIDLimit bool
|
||||
)
|
||||
|
||||
p.AckDelayExponent = protocol.DefaultAckDelayExponent
|
||||
@@ -139,6 +130,9 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
}
|
||||
parameterIDs = append(parameterIDs, paramID)
|
||||
switch paramID {
|
||||
case activeConnectionIDLimitParameterID:
|
||||
readActiveConnectionIDLimit = true
|
||||
fallthrough
|
||||
case maxIdleTimeoutParameterID,
|
||||
maxUDPPayloadSizeParameterID,
|
||||
initialMaxDataParameterID,
|
||||
@@ -148,7 +142,6 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
initialMaxStreamsBidiParameterID,
|
||||
initialMaxStreamsUniParameterID,
|
||||
maxAckDelayParameterID,
|
||||
activeConnectionIDLimitParameterID,
|
||||
maxDatagramFrameSizeParameterID,
|
||||
ackDelayExponentParameterID:
|
||||
if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil {
|
||||
@@ -196,6 +189,9 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
}
|
||||
}
|
||||
|
||||
if !readActiveConnectionIDLimit {
|
||||
p.ActiveConnectionIDLimit = protocol.DefaultActiveConnectionIDLimit
|
||||
}
|
||||
if !fromSessionTicket {
|
||||
if sentBy == protocol.PerspectiveServer && !readOriginalDestinationConnectionID {
|
||||
return errors.New("missing original_destination_connection_id")
|
||||
@@ -335,13 +331,12 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
|
||||
b := make([]byte, 0, 256)
|
||||
|
||||
// add a greased value
|
||||
b = quicvarint.Append(b, uint64(27+31*rand.Intn(100)))
|
||||
randomMutex.Lock()
|
||||
length := random.Intn(16)
|
||||
random := make([]byte, 18)
|
||||
rand.Read(random)
|
||||
b = quicvarint.Append(b, 27+31*uint64(random[0]))
|
||||
length := random[1] % 16
|
||||
b = quicvarint.Append(b, uint64(length))
|
||||
b = b[:len(b)+length]
|
||||
random.Read(b[len(b)-length:])
|
||||
randomMutex.Unlock()
|
||||
b = append(b, random[2:2+length]...)
|
||||
|
||||
// initial_max_stream_data_bidi_local
|
||||
b = p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
|
||||
@@ -402,7 +397,9 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
|
||||
}
|
||||
}
|
||||
// active_connection_id_limit
|
||||
b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
if p.ActiveConnectionIDLimit != protocol.DefaultActiveConnectionIDLimit {
|
||||
b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
}
|
||||
// initial_source_connection_id
|
||||
b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID))
|
||||
b = quicvarint.Append(b, uint64(p.InitialSourceConnectionID.Len()))
|
||||
@@ -457,6 +454,10 @@ func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte {
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
|
||||
// initial_max_uni_streams
|
||||
b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
|
||||
// max_datagram_frame_size
|
||||
if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
|
||||
b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
|
||||
}
|
||||
// active_connection_id_limit
|
||||
return p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
}
|
||||
@@ -475,6 +476,9 @@ func (p *TransportParameters) UnmarshalFromSessionTicket(r *bytes.Reader) error
|
||||
|
||||
// ValidFor0RTT checks if the transport parameters match those saved in the session ticket.
|
||||
func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool {
|
||||
if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
|
||||
return false
|
||||
}
|
||||
return p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
|
||||
p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote &&
|
||||
p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni &&
|
||||
@@ -484,6 +488,21 @@ func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool {
|
||||
p.ActiveConnectionIDLimit == saved.ActiveConnectionIDLimit
|
||||
}
|
||||
|
||||
// ValidForUpdate checks that the new transport parameters don't reduce limits after resuming a 0-RTT connection.
|
||||
// It is only used on the client side.
|
||||
func (p *TransportParameters) ValidForUpdate(saved *TransportParameters) bool {
|
||||
if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
|
||||
return false
|
||||
}
|
||||
return p.ActiveConnectionIDLimit >= saved.ActiveConnectionIDLimit &&
|
||||
p.InitialMaxData >= saved.InitialMaxData &&
|
||||
p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
|
||||
p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote &&
|
||||
p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni &&
|
||||
p.MaxBidiStreamNum >= saved.MaxBidiStreamNum &&
|
||||
p.MaxUniStreamNum >= saved.MaxUniStreamNum
|
||||
}
|
||||
|
||||
// String returns a string representation, intended for logging.
|
||||
func (p *TransportParameters) String() string {
|
||||
logString := "&wire.TransportParameters{OriginalDestinationConnectionID: %s, InitialSourceConnectionID: %s, "
|
||||
|
||||
5
vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go
generated
vendored
@@ -40,7 +40,10 @@ func ComposeVersionNegotiation(destConnID, srcConnID protocol.ArbitraryLenConnec
|
||||
buf := bytes.NewBuffer(make([]byte, 0, expectedLen))
|
||||
r := make([]byte, 1)
|
||||
_, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here.
|
||||
buf.WriteByte(r[0] | 0x80)
|
||||
// Setting the "QUIC bit" (0x40) is not required by the RFC,
|
||||
// but it allows clients to demultiplex QUIC with a long list of other protocols.
|
||||
// See RFC 9443 and https://mailarchive.ietf.org/arch/msg/quic/oR4kxGKY6mjtPC1CZegY1ED4beg/ for details.
|
||||
buf.WriteByte(r[0] | 0xc0)
|
||||
utils.BigEndian.WriteUint32(buf, 0) // version 0
|
||||
buf.WriteByte(uint8(destConnID.Len()))
|
||||
buf.Write(destConnID.Bytes())
|
||||
|
||||
255
vendor/github.com/quic-go/quic-go/logging/connection_tracer.go
generated
vendored
Normal file
255
vendor/github.com/quic-go/quic-go/logging/connection_tracer.go
generated
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A ConnectionTracer records events.
|
||||
type ConnectionTracer struct {
|
||||
StartedConnection func(local, remote net.Addr, srcConnID, destConnID ConnectionID)
|
||||
NegotiatedVersion func(chosen VersionNumber, clientVersions, serverVersions []VersionNumber)
|
||||
ClosedConnection func(error)
|
||||
SentTransportParameters func(*TransportParameters)
|
||||
ReceivedTransportParameters func(*TransportParameters)
|
||||
RestoredTransportParameters func(parameters *TransportParameters) // for 0-RTT
|
||||
SentLongHeaderPacket func(*ExtendedHeader, ByteCount, ECN, *AckFrame, []Frame)
|
||||
SentShortHeaderPacket func(*ShortHeader, ByteCount, ECN, *AckFrame, []Frame)
|
||||
ReceivedVersionNegotiationPacket func(dest, src ArbitraryLenConnectionID, _ []VersionNumber)
|
||||
ReceivedRetry func(*Header)
|
||||
ReceivedLongHeaderPacket func(*ExtendedHeader, ByteCount, ECN, []Frame)
|
||||
ReceivedShortHeaderPacket func(*ShortHeader, ByteCount, ECN, []Frame)
|
||||
BufferedPacket func(PacketType, ByteCount)
|
||||
DroppedPacket func(PacketType, PacketNumber, ByteCount, PacketDropReason)
|
||||
UpdatedMetrics func(rttStats *RTTStats, cwnd, bytesInFlight ByteCount, packetsInFlight int)
|
||||
AcknowledgedPacket func(EncryptionLevel, PacketNumber)
|
||||
LostPacket func(EncryptionLevel, PacketNumber, PacketLossReason)
|
||||
UpdatedCongestionState func(CongestionState)
|
||||
UpdatedPTOCount func(value uint32)
|
||||
UpdatedKeyFromTLS func(EncryptionLevel, Perspective)
|
||||
UpdatedKey func(generation KeyPhase, remote bool)
|
||||
DroppedEncryptionLevel func(EncryptionLevel)
|
||||
DroppedKey func(generation KeyPhase)
|
||||
SetLossTimer func(TimerType, EncryptionLevel, time.Time)
|
||||
LossTimerExpired func(TimerType, EncryptionLevel)
|
||||
LossTimerCanceled func()
|
||||
ECNStateUpdated func(state ECNState, trigger ECNStateTrigger)
|
||||
// Close is called when the connection is closed.
|
||||
Close func()
|
||||
Debug func(name, msg string)
|
||||
}
|
||||
|
||||
// NewMultiplexedConnectionTracer creates a new connection tracer that multiplexes events to multiple tracers.
|
||||
func NewMultiplexedConnectionTracer(tracers ...*ConnectionTracer) *ConnectionTracer {
|
||||
if len(tracers) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(tracers) == 1 {
|
||||
return tracers[0]
|
||||
}
|
||||
return &ConnectionTracer{
|
||||
StartedConnection: func(local, remote net.Addr, srcConnID, destConnID ConnectionID) {
|
||||
for _, t := range tracers {
|
||||
if t.StartedConnection != nil {
|
||||
t.StartedConnection(local, remote, srcConnID, destConnID)
|
||||
}
|
||||
}
|
||||
},
|
||||
NegotiatedVersion: func(chosen VersionNumber, clientVersions, serverVersions []VersionNumber) {
|
||||
for _, t := range tracers {
|
||||
if t.NegotiatedVersion != nil {
|
||||
t.NegotiatedVersion(chosen, clientVersions, serverVersions)
|
||||
}
|
||||
}
|
||||
},
|
||||
ClosedConnection: func(e error) {
|
||||
for _, t := range tracers {
|
||||
if t.ClosedConnection != nil {
|
||||
t.ClosedConnection(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
SentTransportParameters: func(tp *TransportParameters) {
|
||||
for _, t := range tracers {
|
||||
if t.SentTransportParameters != nil {
|
||||
t.SentTransportParameters(tp)
|
||||
}
|
||||
}
|
||||
},
|
||||
ReceivedTransportParameters: func(tp *TransportParameters) {
|
||||
for _, t := range tracers {
|
||||
if t.ReceivedTransportParameters != nil {
|
||||
t.ReceivedTransportParameters(tp)
|
||||
}
|
||||
}
|
||||
},
|
||||
RestoredTransportParameters: func(tp *TransportParameters) {
|
||||
for _, t := range tracers {
|
||||
if t.RestoredTransportParameters != nil {
|
||||
t.RestoredTransportParameters(tp)
|
||||
}
|
||||
}
|
||||
},
|
||||
SentLongHeaderPacket: func(hdr *ExtendedHeader, size ByteCount, ecn ECN, ack *AckFrame, frames []Frame) {
|
||||
for _, t := range tracers {
|
||||
if t.SentLongHeaderPacket != nil {
|
||||
t.SentLongHeaderPacket(hdr, size, ecn, ack, frames)
|
||||
}
|
||||
}
|
||||
},
|
||||
SentShortHeaderPacket: func(hdr *ShortHeader, size ByteCount, ecn ECN, ack *AckFrame, frames []Frame) {
|
||||
for _, t := range tracers {
|
||||
if t.SentShortHeaderPacket != nil {
|
||||
t.SentShortHeaderPacket(hdr, size, ecn, ack, frames)
|
||||
}
|
||||
}
|
||||
},
|
||||
ReceivedVersionNegotiationPacket: func(dest, src ArbitraryLenConnectionID, versions []VersionNumber) {
|
||||
for _, t := range tracers {
|
||||
if t.ReceivedVersionNegotiationPacket != nil {
|
||||
t.ReceivedVersionNegotiationPacket(dest, src, versions)
|
||||
}
|
||||
}
|
||||
},
|
||||
ReceivedRetry: func(hdr *Header) {
|
||||
for _, t := range tracers {
|
||||
if t.ReceivedRetry != nil {
|
||||
t.ReceivedRetry(hdr)
|
||||
}
|
||||
}
|
||||
},
|
||||
ReceivedLongHeaderPacket: func(hdr *ExtendedHeader, size ByteCount, ecn ECN, frames []Frame) {
|
||||
for _, t := range tracers {
|
||||
if t.ReceivedLongHeaderPacket != nil {
|
||||
t.ReceivedLongHeaderPacket(hdr, size, ecn, frames)
|
||||
}
|
||||
}
|
||||
},
|
||||
ReceivedShortHeaderPacket: func(hdr *ShortHeader, size ByteCount, ecn ECN, frames []Frame) {
|
||||
for _, t := range tracers {
|
||||
if t.ReceivedShortHeaderPacket != nil {
|
||||
t.ReceivedShortHeaderPacket(hdr, size, ecn, frames)
|
||||
}
|
||||
}
|
||||
},
|
||||
BufferedPacket: func(typ PacketType, size ByteCount) {
|
||||
for _, t := range tracers {
|
||||
if t.BufferedPacket != nil {
|
||||
t.BufferedPacket(typ, size)
|
||||
}
|
||||
}
|
||||
},
|
||||
DroppedPacket: func(typ PacketType, pn PacketNumber, size ByteCount, reason PacketDropReason) {
|
||||
for _, t := range tracers {
|
||||
if t.DroppedPacket != nil {
|
||||
t.DroppedPacket(typ, pn, size, reason)
|
||||
}
|
||||
}
|
||||
},
|
||||
UpdatedMetrics: func(rttStats *RTTStats, cwnd, bytesInFlight ByteCount, packetsInFlight int) {
|
||||
for _, t := range tracers {
|
||||
if t.UpdatedMetrics != nil {
|
||||
t.UpdatedMetrics(rttStats, cwnd, bytesInFlight, packetsInFlight)
|
||||
}
|
||||
}
|
||||
},
|
||||
AcknowledgedPacket: func(encLevel EncryptionLevel, pn PacketNumber) {
|
||||
for _, t := range tracers {
|
||||
if t.AcknowledgedPacket != nil {
|
||||
t.AcknowledgedPacket(encLevel, pn)
|
||||
}
|
||||
}
|
||||
},
|
||||
LostPacket: func(encLevel EncryptionLevel, pn PacketNumber, reason PacketLossReason) {
|
||||
for _, t := range tracers {
|
||||
if t.LostPacket != nil {
|
||||
t.LostPacket(encLevel, pn, reason)
|
||||
}
|
||||
}
|
||||
},
|
||||
UpdatedCongestionState: func(state CongestionState) {
|
||||
for _, t := range tracers {
|
||||
if t.UpdatedCongestionState != nil {
|
||||
t.UpdatedCongestionState(state)
|
||||
}
|
||||
}
|
||||
},
|
||||
UpdatedPTOCount: func(value uint32) {
|
||||
for _, t := range tracers {
|
||||
if t.UpdatedPTOCount != nil {
|
||||
t.UpdatedPTOCount(value)
|
||||
}
|
||||
}
|
||||
},
|
||||
UpdatedKeyFromTLS: func(encLevel EncryptionLevel, perspective Perspective) {
|
||||
for _, t := range tracers {
|
||||
if t.UpdatedKeyFromTLS != nil {
|
||||
t.UpdatedKeyFromTLS(encLevel, perspective)
|
||||
}
|
||||
}
|
||||
},
|
||||
UpdatedKey: func(generation KeyPhase, remote bool) {
|
||||
for _, t := range tracers {
|
||||
if t.UpdatedKey != nil {
|
||||
t.UpdatedKey(generation, remote)
|
||||
}
|
||||
}
|
||||
},
|
||||
DroppedEncryptionLevel: func(encLevel EncryptionLevel) {
|
||||
for _, t := range tracers {
|
||||
if t.DroppedEncryptionLevel != nil {
|
||||
t.DroppedEncryptionLevel(encLevel)
|
||||
}
|
||||
}
|
||||
},
|
||||
DroppedKey: func(generation KeyPhase) {
|
||||
for _, t := range tracers {
|
||||
if t.DroppedKey != nil {
|
||||
t.DroppedKey(generation)
|
||||
}
|
||||
}
|
||||
},
|
||||
SetLossTimer: func(typ TimerType, encLevel EncryptionLevel, exp time.Time) {
|
||||
for _, t := range tracers {
|
||||
if t.SetLossTimer != nil {
|
||||
t.SetLossTimer(typ, encLevel, exp)
|
||||
}
|
||||
}
|
||||
},
|
||||
LossTimerExpired: func(typ TimerType, encLevel EncryptionLevel) {
|
||||
for _, t := range tracers {
|
||||
if t.LossTimerExpired != nil {
|
||||
t.LossTimerExpired(typ, encLevel)
|
||||
}
|
||||
}
|
||||
},
|
||||
LossTimerCanceled: func() {
|
||||
for _, t := range tracers {
|
||||
if t.LossTimerCanceled != nil {
|
||||
t.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
},
|
||||
ECNStateUpdated: func(state ECNState, trigger ECNStateTrigger) {
|
||||
for _, t := range tracers {
|
||||
if t.ECNStateUpdated != nil {
|
||||
t.ECNStateUpdated(state, trigger)
|
||||
}
|
||||
}
|
||||
},
|
||||
Close: func() {
|
||||
for _, t := range tracers {
|
||||
if t.Close != nil {
|
||||
t.Close()
|
||||
}
|
||||
}
|
||||
},
|
||||
Debug: func(name, msg string) {
|
||||
for _, t := range tracers {
|
||||
if t.Debug != nil {
|
||||
t.Debug(name, msg)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
58
vendor/github.com/quic-go/quic-go/logging/interface.go
generated
vendored
58
vendor/github.com/quic-go/quic-go/logging/interface.go
generated
vendored
@@ -3,9 +3,6 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qerr"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
@@ -15,6 +12,8 @@ import (
|
||||
type (
|
||||
// A ByteCount is used to count bytes.
|
||||
ByteCount = protocol.ByteCount
|
||||
// ECN is the ECN value
|
||||
ECN = protocol.ECN
|
||||
// A ConnectionID is a QUIC Connection ID.
|
||||
ConnectionID = protocol.ConnectionID
|
||||
// An ArbitraryLenConnectionID is a QUIC Connection ID that can be up to 255 bytes long.
|
||||
@@ -58,6 +57,19 @@ type (
|
||||
RTTStats = utils.RTTStats
|
||||
)
|
||||
|
||||
const (
|
||||
// ECNUnsupported means that no ECN value was set / received
|
||||
ECNUnsupported = protocol.ECNUnsupported
|
||||
// ECTNot is Not-ECT
|
||||
ECTNot = protocol.ECNNon
|
||||
// ECT0 is ECT(0)
|
||||
ECT0 = protocol.ECT0
|
||||
// ECT1 is ECT(1)
|
||||
ECT1 = protocol.ECT1
|
||||
// ECNCE is CE
|
||||
ECNCE = protocol.ECNCE
|
||||
)
|
||||
|
||||
const (
|
||||
// KeyPhaseZero is key phase bit 0
|
||||
KeyPhaseZero KeyPhaseBit = protocol.KeyPhaseZero
|
||||
@@ -97,43 +109,3 @@ type ShortHeader struct {
|
||||
PacketNumberLen protocol.PacketNumberLen
|
||||
KeyPhase KeyPhaseBit
|
||||
}
|
||||
|
||||
// A Tracer traces events.
|
||||
type Tracer interface {
|
||||
SentPacket(net.Addr, *Header, ByteCount, []Frame)
|
||||
SentVersionNegotiationPacket(_ net.Addr, dest, src ArbitraryLenConnectionID, _ []VersionNumber)
|
||||
DroppedPacket(net.Addr, PacketType, ByteCount, PacketDropReason)
|
||||
}
|
||||
|
||||
// A ConnectionTracer records events.
|
||||
type ConnectionTracer interface {
|
||||
StartedConnection(local, remote net.Addr, srcConnID, destConnID ConnectionID)
|
||||
NegotiatedVersion(chosen VersionNumber, clientVersions, serverVersions []VersionNumber)
|
||||
ClosedConnection(error)
|
||||
SentTransportParameters(*TransportParameters)
|
||||
ReceivedTransportParameters(*TransportParameters)
|
||||
RestoredTransportParameters(parameters *TransportParameters) // for 0-RTT
|
||||
SentLongHeaderPacket(hdr *ExtendedHeader, size ByteCount, ack *AckFrame, frames []Frame)
|
||||
SentShortHeaderPacket(hdr *ShortHeader, size ByteCount, ack *AckFrame, frames []Frame)
|
||||
ReceivedVersionNegotiationPacket(dest, src ArbitraryLenConnectionID, _ []VersionNumber)
|
||||
ReceivedRetry(*Header)
|
||||
ReceivedLongHeaderPacket(hdr *ExtendedHeader, size ByteCount, frames []Frame)
|
||||
ReceivedShortHeaderPacket(hdr *ShortHeader, size ByteCount, frames []Frame)
|
||||
BufferedPacket(PacketType, ByteCount)
|
||||
DroppedPacket(PacketType, ByteCount, PacketDropReason)
|
||||
UpdatedMetrics(rttStats *RTTStats, cwnd, bytesInFlight ByteCount, packetsInFlight int)
|
||||
AcknowledgedPacket(EncryptionLevel, PacketNumber)
|
||||
LostPacket(EncryptionLevel, PacketNumber, PacketLossReason)
|
||||
UpdatedCongestionState(CongestionState)
|
||||
UpdatedPTOCount(value uint32)
|
||||
UpdatedKeyFromTLS(EncryptionLevel, Perspective)
|
||||
UpdatedKey(generation KeyPhase, remote bool)
|
||||
DroppedEncryptionLevel(EncryptionLevel)
|
||||
DroppedKey(generation KeyPhase)
|
||||
SetLossTimer(TimerType, EncryptionLevel, time.Time)
|
||||
LossTimerExpired(TimerType, EncryptionLevel)
|
||||
LossTimerCanceled()
|
||||
// Close is called when the connection is closed.
|
||||
Close()
|
||||
Debug(name, msg string)
|
||||
}
|
||||
|
||||
4
vendor/github.com/quic-go/quic-go/logging/mockgen.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/logging/mockgen.go
generated
vendored
@@ -1,4 +0,0 @@
|
||||
package logging
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package logging -self_package github.com/quic-go/quic-go/logging -destination mock_connection_tracer_test.go github.com/quic-go/quic-go/logging ConnectionTracer"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package logging -self_package github.com/quic-go/quic-go/logging -destination mock_tracer_test.go github.com/quic-go/quic-go/logging Tracer"
|
||||
226
vendor/github.com/quic-go/quic-go/logging/multiplex.go
generated
vendored
226
vendor/github.com/quic-go/quic-go/logging/multiplex.go
generated
vendored
@@ -1,226 +0,0 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type tracerMultiplexer struct {
|
||||
tracers []Tracer
|
||||
}
|
||||
|
||||
var _ Tracer = &tracerMultiplexer{}
|
||||
|
||||
// NewMultiplexedTracer creates a new tracer that multiplexes events to multiple tracers.
|
||||
func NewMultiplexedTracer(tracers ...Tracer) Tracer {
|
||||
if len(tracers) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(tracers) == 1 {
|
||||
return tracers[0]
|
||||
}
|
||||
return &tracerMultiplexer{tracers}
|
||||
}
|
||||
|
||||
func (m *tracerMultiplexer) SentPacket(remote net.Addr, hdr *Header, size ByteCount, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.SentPacket(remote, hdr, size, frames)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *tracerMultiplexer) SentVersionNegotiationPacket(remote net.Addr, dest, src ArbitraryLenConnectionID, versions []VersionNumber) {
|
||||
for _, t := range m.tracers {
|
||||
t.SentVersionNegotiationPacket(remote, dest, src, versions)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *tracerMultiplexer) DroppedPacket(remote net.Addr, typ PacketType, size ByteCount, reason PacketDropReason) {
|
||||
for _, t := range m.tracers {
|
||||
t.DroppedPacket(remote, typ, size, reason)
|
||||
}
|
||||
}
|
||||
|
||||
type connTracerMultiplexer struct {
|
||||
tracers []ConnectionTracer
|
||||
}
|
||||
|
||||
var _ ConnectionTracer = &connTracerMultiplexer{}
|
||||
|
||||
// NewMultiplexedConnectionTracer creates a new connection tracer that multiplexes events to multiple tracers.
|
||||
func NewMultiplexedConnectionTracer(tracers ...ConnectionTracer) ConnectionTracer {
|
||||
if len(tracers) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(tracers) == 1 {
|
||||
return tracers[0]
|
||||
}
|
||||
return &connTracerMultiplexer{tracers: tracers}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) StartedConnection(local, remote net.Addr, srcConnID, destConnID ConnectionID) {
|
||||
for _, t := range m.tracers {
|
||||
t.StartedConnection(local, remote, srcConnID, destConnID)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) NegotiatedVersion(chosen VersionNumber, clientVersions, serverVersions []VersionNumber) {
|
||||
for _, t := range m.tracers {
|
||||
t.NegotiatedVersion(chosen, clientVersions, serverVersions)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ClosedConnection(e error) {
|
||||
for _, t := range m.tracers {
|
||||
t.ClosedConnection(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) SentTransportParameters(tp *TransportParameters) {
|
||||
for _, t := range m.tracers {
|
||||
t.SentTransportParameters(tp)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ReceivedTransportParameters(tp *TransportParameters) {
|
||||
for _, t := range m.tracers {
|
||||
t.ReceivedTransportParameters(tp)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) RestoredTransportParameters(tp *TransportParameters) {
|
||||
for _, t := range m.tracers {
|
||||
t.RestoredTransportParameters(tp)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) SentLongHeaderPacket(hdr *ExtendedHeader, size ByteCount, ack *AckFrame, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.SentLongHeaderPacket(hdr, size, ack, frames)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) SentShortHeaderPacket(hdr *ShortHeader, size ByteCount, ack *AckFrame, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.SentShortHeaderPacket(hdr, size, ack, frames)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ReceivedVersionNegotiationPacket(dest, src ArbitraryLenConnectionID, versions []VersionNumber) {
|
||||
for _, t := range m.tracers {
|
||||
t.ReceivedVersionNegotiationPacket(dest, src, versions)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ReceivedRetry(hdr *Header) {
|
||||
for _, t := range m.tracers {
|
||||
t.ReceivedRetry(hdr)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ReceivedLongHeaderPacket(hdr *ExtendedHeader, size ByteCount, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.ReceivedLongHeaderPacket(hdr, size, frames)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) ReceivedShortHeaderPacket(hdr *ShortHeader, size ByteCount, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.ReceivedShortHeaderPacket(hdr, size, frames)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) BufferedPacket(typ PacketType, size ByteCount) {
|
||||
for _, t := range m.tracers {
|
||||
t.BufferedPacket(typ, size)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) DroppedPacket(typ PacketType, size ByteCount, reason PacketDropReason) {
|
||||
for _, t := range m.tracers {
|
||||
t.DroppedPacket(typ, size, reason)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) UpdatedCongestionState(state CongestionState) {
|
||||
for _, t := range m.tracers {
|
||||
t.UpdatedCongestionState(state)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) UpdatedMetrics(rttStats *RTTStats, cwnd, bytesInFLight ByteCount, packetsInFlight int) {
|
||||
for _, t := range m.tracers {
|
||||
t.UpdatedMetrics(rttStats, cwnd, bytesInFLight, packetsInFlight)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) AcknowledgedPacket(encLevel EncryptionLevel, pn PacketNumber) {
|
||||
for _, t := range m.tracers {
|
||||
t.AcknowledgedPacket(encLevel, pn)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) LostPacket(encLevel EncryptionLevel, pn PacketNumber, reason PacketLossReason) {
|
||||
for _, t := range m.tracers {
|
||||
t.LostPacket(encLevel, pn, reason)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) UpdatedPTOCount(value uint32) {
|
||||
for _, t := range m.tracers {
|
||||
t.UpdatedPTOCount(value)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) UpdatedKeyFromTLS(encLevel EncryptionLevel, perspective Perspective) {
|
||||
for _, t := range m.tracers {
|
||||
t.UpdatedKeyFromTLS(encLevel, perspective)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) UpdatedKey(generation KeyPhase, remote bool) {
|
||||
for _, t := range m.tracers {
|
||||
t.UpdatedKey(generation, remote)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) DroppedEncryptionLevel(encLevel EncryptionLevel) {
|
||||
for _, t := range m.tracers {
|
||||
t.DroppedEncryptionLevel(encLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) DroppedKey(generation KeyPhase) {
|
||||
for _, t := range m.tracers {
|
||||
t.DroppedKey(generation)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) SetLossTimer(typ TimerType, encLevel EncryptionLevel, exp time.Time) {
|
||||
for _, t := range m.tracers {
|
||||
t.SetLossTimer(typ, encLevel, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) LossTimerExpired(typ TimerType, encLevel EncryptionLevel) {
|
||||
for _, t := range m.tracers {
|
||||
t.LossTimerExpired(typ, encLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) LossTimerCanceled() {
|
||||
for _, t := range m.tracers {
|
||||
t.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) Debug(name, msg string) {
|
||||
for _, t := range m.tracers {
|
||||
t.Debug(name, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *connTracerMultiplexer) Close() {
|
||||
for _, t := range m.tracers {
|
||||
t.Close()
|
||||
}
|
||||
}
|
||||
58
vendor/github.com/quic-go/quic-go/logging/null_tracer.go
generated
vendored
58
vendor/github.com/quic-go/quic-go/logging/null_tracer.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The NullTracer is a Tracer that does nothing.
|
||||
// It is useful for embedding.
|
||||
type NullTracer struct{}
|
||||
|
||||
var _ Tracer = &NullTracer{}
|
||||
|
||||
func (n NullTracer) SentPacket(net.Addr, *Header, ByteCount, []Frame) {}
|
||||
func (n NullTracer) SentVersionNegotiationPacket(_ net.Addr, dest, src ArbitraryLenConnectionID, _ []VersionNumber) {
|
||||
}
|
||||
func (n NullTracer) DroppedPacket(net.Addr, PacketType, ByteCount, PacketDropReason) {}
|
||||
|
||||
// The NullConnectionTracer is a ConnectionTracer that does nothing.
|
||||
// It is useful for embedding.
|
||||
type NullConnectionTracer struct{}
|
||||
|
||||
var _ ConnectionTracer = &NullConnectionTracer{}
|
||||
|
||||
func (n NullConnectionTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID ConnectionID) {
|
||||
}
|
||||
|
||||
func (n NullConnectionTracer) NegotiatedVersion(chosen VersionNumber, clientVersions, serverVersions []VersionNumber) {
|
||||
}
|
||||
func (n NullConnectionTracer) ClosedConnection(err error) {}
|
||||
func (n NullConnectionTracer) SentTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) ReceivedTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) RestoredTransportParameters(*TransportParameters) {}
|
||||
func (n NullConnectionTracer) SentLongHeaderPacket(*ExtendedHeader, ByteCount, *AckFrame, []Frame) {}
|
||||
func (n NullConnectionTracer) SentShortHeaderPacket(*ShortHeader, ByteCount, *AckFrame, []Frame) {}
|
||||
func (n NullConnectionTracer) ReceivedVersionNegotiationPacket(dest, src ArbitraryLenConnectionID, _ []VersionNumber) {
|
||||
}
|
||||
func (n NullConnectionTracer) ReceivedRetry(*Header) {}
|
||||
func (n NullConnectionTracer) ReceivedLongHeaderPacket(*ExtendedHeader, ByteCount, []Frame) {}
|
||||
func (n NullConnectionTracer) ReceivedShortHeaderPacket(*ShortHeader, ByteCount, []Frame) {}
|
||||
func (n NullConnectionTracer) BufferedPacket(PacketType, ByteCount) {}
|
||||
func (n NullConnectionTracer) DroppedPacket(PacketType, ByteCount, PacketDropReason) {}
|
||||
|
||||
func (n NullConnectionTracer) UpdatedMetrics(rttStats *RTTStats, cwnd, bytesInFlight ByteCount, packetsInFlight int) {
|
||||
}
|
||||
func (n NullConnectionTracer) AcknowledgedPacket(EncryptionLevel, PacketNumber) {}
|
||||
func (n NullConnectionTracer) LostPacket(EncryptionLevel, PacketNumber, PacketLossReason) {}
|
||||
func (n NullConnectionTracer) UpdatedCongestionState(CongestionState) {}
|
||||
func (n NullConnectionTracer) UpdatedPTOCount(uint32) {}
|
||||
func (n NullConnectionTracer) UpdatedKeyFromTLS(EncryptionLevel, Perspective) {}
|
||||
func (n NullConnectionTracer) UpdatedKey(keyPhase KeyPhase, remote bool) {}
|
||||
func (n NullConnectionTracer) DroppedEncryptionLevel(EncryptionLevel) {}
|
||||
func (n NullConnectionTracer) DroppedKey(KeyPhase) {}
|
||||
func (n NullConnectionTracer) SetLossTimer(TimerType, EncryptionLevel, time.Time) {}
|
||||
func (n NullConnectionTracer) LossTimerExpired(timerType TimerType, level EncryptionLevel) {}
|
||||
func (n NullConnectionTracer) LossTimerCanceled() {}
|
||||
func (n NullConnectionTracer) Close() {}
|
||||
func (n NullConnectionTracer) Debug(name, msg string) {}
|
||||
43
vendor/github.com/quic-go/quic-go/logging/tracer.go
generated
vendored
Normal file
43
vendor/github.com/quic-go/quic-go/logging/tracer.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package logging
|
||||
|
||||
import "net"
|
||||
|
||||
// A Tracer traces events.
|
||||
type Tracer struct {
|
||||
SentPacket func(net.Addr, *Header, ByteCount, []Frame)
|
||||
SentVersionNegotiationPacket func(_ net.Addr, dest, src ArbitraryLenConnectionID, _ []VersionNumber)
|
||||
DroppedPacket func(net.Addr, PacketType, ByteCount, PacketDropReason)
|
||||
}
|
||||
|
||||
// NewMultiplexedTracer creates a new tracer that multiplexes events to multiple tracers.
|
||||
func NewMultiplexedTracer(tracers ...*Tracer) *Tracer {
|
||||
if len(tracers) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(tracers) == 1 {
|
||||
return tracers[0]
|
||||
}
|
||||
return &Tracer{
|
||||
SentPacket: func(remote net.Addr, hdr *Header, size ByteCount, frames []Frame) {
|
||||
for _, t := range tracers {
|
||||
if t.SentPacket != nil {
|
||||
t.SentPacket(remote, hdr, size, frames)
|
||||
}
|
||||
}
|
||||
},
|
||||
SentVersionNegotiationPacket: func(remote net.Addr, dest, src ArbitraryLenConnectionID, versions []VersionNumber) {
|
||||
for _, t := range tracers {
|
||||
if t.SentVersionNegotiationPacket != nil {
|
||||
t.SentVersionNegotiationPacket(remote, dest, src, versions)
|
||||
}
|
||||
}
|
||||
},
|
||||
DroppedPacket: func(remote net.Addr, typ PacketType, size ByteCount, reason PacketDropReason) {
|
||||
for _, t := range tracers {
|
||||
if t.DroppedPacket != nil {
|
||||
t.DroppedPacket(remote, typ, size, reason)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
34
vendor/github.com/quic-go/quic-go/logging/types.go
generated
vendored
34
vendor/github.com/quic-go/quic-go/logging/types.go
generated
vendored
@@ -92,3 +92,37 @@ const (
|
||||
// CongestionStateApplicationLimited means that the congestion controller is application limited
|
||||
CongestionStateApplicationLimited
|
||||
)
|
||||
|
||||
// ECNState is the state of the ECN state machine (see Appendix A.4 of RFC 9000)
|
||||
type ECNState uint8
|
||||
|
||||
const (
|
||||
// ECNStateTesting is the testing state
|
||||
ECNStateTesting ECNState = 1 + iota
|
||||
// ECNStateUnknown is the unknown state
|
||||
ECNStateUnknown
|
||||
// ECNStateFailed is the failed state
|
||||
ECNStateFailed
|
||||
// ECNStateCapable is the capable state
|
||||
ECNStateCapable
|
||||
)
|
||||
|
||||
// ECNStateTrigger is a trigger for an ECN state transition.
|
||||
type ECNStateTrigger uint8
|
||||
|
||||
const (
|
||||
ECNTriggerNoTrigger ECNStateTrigger = iota
|
||||
// ECNFailedNoECNCounts is emitted when an ACK acknowledges ECN-marked packets,
|
||||
// but doesn't contain any ECN counts
|
||||
ECNFailedNoECNCounts
|
||||
// ECNFailedDecreasedECNCounts is emitted when an ACK frame decreases ECN counts
|
||||
ECNFailedDecreasedECNCounts
|
||||
// ECNFailedLostAllTestingPackets is emitted when all ECN testing packets are declared lost
|
||||
ECNFailedLostAllTestingPackets
|
||||
// ECNFailedMoreECNCountsThanSent is emitted when an ACK contains more ECN counts than ECN-marked packets were sent
|
||||
ECNFailedMoreECNCountsThanSent
|
||||
// ECNFailedTooFewECNCounts is emitted when an ACK contains fewer ECN counts than it acknowledges packets
|
||||
ECNFailedTooFewECNCounts
|
||||
// ECNFailedManglingDetected is emitted when the path marks all ECN-marked packets as CE
|
||||
ECNFailedManglingDetected
|
||||
)
|
||||
|
||||
52
vendor/github.com/quic-go/quic-go/mockgen.go
generated
vendored
52
vendor/github.com/quic-go/quic-go/mockgen.go
generated
vendored
@@ -2,73 +2,75 @@
|
||||
|
||||
package quic
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn"
|
||||
type SendConn = sendConn
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_raw_conn_test.go github.com/quic-go/quic-go RawConn"
|
||||
type RawConn = rawConn
|
||||
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender"
|
||||
type Sender = sender
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_internal_test.go github.com/quic-go/quic-go StreamI"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_internal_test.go github.com/quic-go/quic-go StreamI"
|
||||
type StreamI = streamI
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_stream_test.go github.com/quic-go/quic-go CryptoStream"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_stream_test.go github.com/quic-go/quic-go CryptoStream"
|
||||
type CryptoStream = cryptoStream
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_receive_stream_internal_test.go github.com/quic-go/quic-go ReceiveStreamI"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_receive_stream_internal_test.go github.com/quic-go/quic-go ReceiveStreamI"
|
||||
type ReceiveStreamI = receiveStreamI
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_stream_internal_test.go github.com/quic-go/quic-go SendStreamI"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_stream_internal_test.go github.com/quic-go/quic-go SendStreamI"
|
||||
type SendStreamI = sendStreamI
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_getter_test.go github.com/quic-go/quic-go StreamGetter"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_getter_test.go github.com/quic-go/quic-go StreamGetter"
|
||||
type StreamGetter = streamGetter
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender"
|
||||
type StreamSender = streamSender
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_data_handler_test.go github.com/quic-go/quic-go CryptoDataHandler"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_data_handler_test.go github.com/quic-go/quic-go CryptoDataHandler"
|
||||
type CryptoDataHandler = cryptoDataHandler
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource"
|
||||
type FrameSource = frameSource
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource"
|
||||
type AckFrameSource = ackFrameSource
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_manager_test.go github.com/quic-go/quic-go StreamManager"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_manager_test.go github.com/quic-go/quic-go StreamManager"
|
||||
type StreamManager = streamManager
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager"
|
||||
type SealingManager = sealingManager
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unpacker_test.go github.com/quic-go/quic-go Unpacker"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unpacker_test.go github.com/quic-go/quic-go Unpacker"
|
||||
type Unpacker = unpacker
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packer_test.go github.com/quic-go/quic-go Packer"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packer_test.go github.com/quic-go/quic-go Packer"
|
||||
type Packer = packer
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_mtu_discoverer_test.go github.com/quic-go/quic-go MTUDiscoverer"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_mtu_discoverer_test.go github.com/quic-go/quic-go MTUDiscoverer"
|
||||
type MTUDiscoverer = mtuDiscoverer
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner"
|
||||
type ConnRunner = connRunner
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_quic_conn_test.go github.com/quic-go/quic-go QUICConn"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_quic_conn_test.go github.com/quic-go/quic-go QUICConn"
|
||||
type QUICConn = quicConn
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler"
|
||||
type PacketHandler = packetHandler
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unknown_packet_handler_test.go github.com/quic-go/quic-go UnknownPacketHandler"
|
||||
type UnknownPacketHandler = unknownPacketHandler
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_manager_test.go github.com/quic-go/quic-go PacketHandlerManager"
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_manager_test.go github.com/quic-go/quic-go PacketHandlerManager"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_manager_test.go github.com/quic-go/quic-go PacketHandlerManager"
|
||||
type PacketHandlerManager = packetHandlerManager
|
||||
|
||||
// Need to use source mode for the batchConn, since reflect mode follows type aliases.
|
||||
// See https://github.com/golang/mock/issues/244 for details.
|
||||
//
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -source sys_conn_oob.go -destination mock_batch_conn_test.go -mock_names batchConn=MockBatchConn"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package quic -self_package github.com/quic-go/quic-go -source sys_conn_oob.go -destination mock_batch_conn_test.go -mock_names batchConn=MockBatchConn"
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_token_store_test.go github.com/quic-go/quic-go TokenStore"
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_packetconn_test.go net PacketConn"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_token_store_test.go github.com/quic-go/quic-go TokenStore"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_packetconn_test.go net PacketConn"
|
||||
|
||||
83
vendor/github.com/quic-go/quic-go/mtu_discoverer.go
generated
vendored
83
vendor/github.com/quic-go/quic-go/mtu_discoverer.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/ackhandler"
|
||||
@@ -10,7 +11,11 @@ import (
|
||||
)
|
||||
|
||||
type mtuDiscoverer interface {
|
||||
// Start starts the MTU discovery process.
|
||||
// It's unnecessary to call ShouldSendProbe before that.
|
||||
Start(maxPacketSize protocol.ByteCount)
|
||||
ShouldSendProbe(now time.Time) bool
|
||||
CurrentSize() protocol.ByteCount
|
||||
GetPing() (ping ackhandler.Frame, datagramSize protocol.ByteCount)
|
||||
}
|
||||
|
||||
@@ -22,25 +27,38 @@ const (
|
||||
mtuProbeDelay = 5
|
||||
)
|
||||
|
||||
func getMaxPacketSize(addr net.Addr) protocol.ByteCount {
|
||||
maxSize := protocol.ByteCount(protocol.MinInitialPacketSize)
|
||||
// If this is not a UDP address, we don't know anything about the MTU.
|
||||
// Use the minimum size of an Initial packet as the max packet size.
|
||||
if udpAddr, ok := addr.(*net.UDPAddr); ok {
|
||||
if utils.IsIPv4(udpAddr.IP) {
|
||||
maxSize = protocol.InitialPacketSizeIPv4
|
||||
} else {
|
||||
maxSize = protocol.InitialPacketSizeIPv6
|
||||
}
|
||||
}
|
||||
return maxSize
|
||||
}
|
||||
|
||||
type mtuFinder struct {
|
||||
lastProbeTime time.Time
|
||||
probeInFlight bool
|
||||
mtuIncreased func(protocol.ByteCount)
|
||||
|
||||
rttStats *utils.RTTStats
|
||||
inFlight protocol.ByteCount // the size of the probe packet currently in flight. InvalidByteCount if none is in flight
|
||||
current protocol.ByteCount
|
||||
max protocol.ByteCount // the maximum value, as advertised by the peer (or our maximum size buffer)
|
||||
}
|
||||
|
||||
var _ mtuDiscoverer = &mtuFinder{}
|
||||
|
||||
func newMTUDiscoverer(rttStats *utils.RTTStats, start, max protocol.ByteCount, mtuIncreased func(protocol.ByteCount)) mtuDiscoverer {
|
||||
func newMTUDiscoverer(rttStats *utils.RTTStats, start protocol.ByteCount, mtuIncreased func(protocol.ByteCount)) *mtuFinder {
|
||||
return &mtuFinder{
|
||||
current: start,
|
||||
rttStats: rttStats,
|
||||
lastProbeTime: time.Now(), // to make sure the first probe packet is not sent immediately
|
||||
mtuIncreased: mtuIncreased,
|
||||
max: max,
|
||||
inFlight: protocol.InvalidByteCount,
|
||||
current: start,
|
||||
rttStats: rttStats,
|
||||
mtuIncreased: mtuIncreased,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +66,16 @@ func (f *mtuFinder) done() bool {
|
||||
return f.max-f.current <= maxMTUDiff+1
|
||||
}
|
||||
|
||||
func (f *mtuFinder) Start(maxPacketSize protocol.ByteCount) {
|
||||
f.lastProbeTime = time.Now() // makes sure the first probe packet is not sent immediately
|
||||
f.max = maxPacketSize
|
||||
}
|
||||
|
||||
func (f *mtuFinder) ShouldSendProbe(now time.Time) bool {
|
||||
if f.probeInFlight || f.done() {
|
||||
if f.max == 0 || f.lastProbeTime.IsZero() {
|
||||
return false
|
||||
}
|
||||
if f.inFlight != protocol.InvalidByteCount || f.done() {
|
||||
return false
|
||||
}
|
||||
return !now.Before(f.lastProbeTime.Add(mtuProbeDelay * f.rttStats.SmoothedRTT()))
|
||||
@@ -58,17 +84,36 @@ func (f *mtuFinder) ShouldSendProbe(now time.Time) bool {
|
||||
func (f *mtuFinder) GetPing() (ackhandler.Frame, protocol.ByteCount) {
|
||||
size := (f.max + f.current) / 2
|
||||
f.lastProbeTime = time.Now()
|
||||
f.probeInFlight = true
|
||||
f.inFlight = size
|
||||
return ackhandler.Frame{
|
||||
Frame: &wire.PingFrame{},
|
||||
OnLost: func(wire.Frame) {
|
||||
f.probeInFlight = false
|
||||
f.max = size
|
||||
},
|
||||
OnAcked: func(wire.Frame) {
|
||||
f.probeInFlight = false
|
||||
f.current = size
|
||||
f.mtuIncreased(size)
|
||||
},
|
||||
Frame: &wire.PingFrame{},
|
||||
Handler: (*mtuFinderAckHandler)(f),
|
||||
}, size
|
||||
}
|
||||
|
||||
func (f *mtuFinder) CurrentSize() protocol.ByteCount {
|
||||
return f.current
|
||||
}
|
||||
|
||||
type mtuFinderAckHandler mtuFinder
|
||||
|
||||
var _ ackhandler.FrameHandler = &mtuFinderAckHandler{}
|
||||
|
||||
func (h *mtuFinderAckHandler) OnAcked(wire.Frame) {
|
||||
size := h.inFlight
|
||||
if size == protocol.InvalidByteCount {
|
||||
panic("OnAcked callback called although there's no MTU probe packet in flight")
|
||||
}
|
||||
h.inFlight = protocol.InvalidByteCount
|
||||
h.current = size
|
||||
h.mtuIncreased(size)
|
||||
}
|
||||
|
||||
func (h *mtuFinderAckHandler) OnLost(wire.Frame) {
|
||||
size := h.inFlight
|
||||
if size == protocol.InvalidByteCount {
|
||||
panic("OnLost callback called although there's no MTU probe packet in flight")
|
||||
}
|
||||
h.max = size
|
||||
h.inFlight = protocol.InvalidByteCount
|
||||
}
|
||||
|
||||
42
vendor/github.com/quic-go/quic-go/oss-fuzz.sh
generated
vendored
Normal file
42
vendor/github.com/quic-go/quic-go/oss-fuzz.sh
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install Go manually, since oss-fuzz ships with an outdated Go version.
|
||||
# See https://github.com/google/oss-fuzz/pull/10643.
|
||||
export CXX="${CXX} -lresolv" # required by Go 1.20
|
||||
wget https://go.dev/dl/go1.20.5.linux-amd64.tar.gz \
|
||||
&& mkdir temp-go \
|
||||
&& rm -rf /root/.go/* \
|
||||
&& tar -C temp-go/ -xzf go1.20.5.linux-amd64.tar.gz \
|
||||
&& mv temp-go/go/* /root/.go/ \
|
||||
&& rm -rf temp-go go1.20.5.linux-amd64.tar.gz
|
||||
|
||||
(
|
||||
# fuzz qpack
|
||||
compile_go_fuzzer github.com/quic-go/qpack/fuzzing Fuzz qpack_fuzzer
|
||||
)
|
||||
|
||||
(
|
||||
# fuzz quic-go
|
||||
compile_go_fuzzer github.com/quic-go/quic-go/fuzzing/frames Fuzz frame_fuzzer
|
||||
compile_go_fuzzer github.com/quic-go/quic-go/fuzzing/header Fuzz header_fuzzer
|
||||
compile_go_fuzzer github.com/quic-go/quic-go/fuzzing/transportparameters Fuzz transportparameter_fuzzer
|
||||
compile_go_fuzzer github.com/quic-go/quic-go/fuzzing/tokens Fuzz token_fuzzer
|
||||
compile_go_fuzzer github.com/quic-go/quic-go/fuzzing/handshake Fuzz handshake_fuzzer
|
||||
|
||||
if [ $SANITIZER == "coverage" ]; then
|
||||
# no need for corpora if coverage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# generate seed corpora
|
||||
cd $GOPATH/src/github.com/quic-go/quic-go/
|
||||
go generate -x ./fuzzing/...
|
||||
|
||||
zip --quiet -r $OUT/header_fuzzer_seed_corpus.zip fuzzing/header/corpus
|
||||
zip --quiet -r $OUT/frame_fuzzer_seed_corpus.zip fuzzing/frames/corpus
|
||||
zip --quiet -r $OUT/transportparameter_fuzzer_seed_corpus.zip fuzzing/transportparameters/corpus
|
||||
zip --quiet -r $OUT/handshake_fuzzer_seed_corpus.zip fuzzing/handshake/corpus
|
||||
)
|
||||
|
||||
# for debugging
|
||||
ls -al $OUT
|
||||
48
vendor/github.com/quic-go/quic-go/packet_handler_map.go
generated
vendored
48
vendor/github.com/quic-go/quic-go/packet_handler_map.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
"net"
|
||||
@@ -15,28 +14,36 @@ import (
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
type connCapabilities struct {
|
||||
// This connection has the Don't Fragment (DF) bit set.
|
||||
// This means it makes to run DPLPMTUD.
|
||||
DF bool
|
||||
// GSO (Generic Segmentation Offload) supported
|
||||
GSO bool
|
||||
// ECN (Explicit Congestion Notifications) supported
|
||||
ECN bool
|
||||
}
|
||||
|
||||
// rawConn is a connection that allow reading of a receivedPackeh.
|
||||
type rawConn interface {
|
||||
ReadPacket() (*receivedPacket, error)
|
||||
WritePacket(b []byte, addr net.Addr, oob []byte) (int, error)
|
||||
ReadPacket() (receivedPacket, error)
|
||||
// WritePacket writes a packet on the wire.
|
||||
// gsoSize is the size of a single packet, or 0 to disable GSO.
|
||||
// It is invalid to set gsoSize if capabilities.GSO is not set.
|
||||
WritePacket(b []byte, addr net.Addr, packetInfoOOB []byte, gsoSize uint16, ecn protocol.ECN) (int, error)
|
||||
LocalAddr() net.Addr
|
||||
SetReadDeadline(time.Time) error
|
||||
io.Closer
|
||||
|
||||
capabilities() connCapabilities
|
||||
}
|
||||
|
||||
type closePacket struct {
|
||||
payload []byte
|
||||
addr net.Addr
|
||||
info *packetInfo
|
||||
info packetInfo
|
||||
}
|
||||
|
||||
type unknownPacketHandler interface {
|
||||
handlePacket(*receivedPacket)
|
||||
setCloseError(error)
|
||||
}
|
||||
|
||||
var errListenerAlreadySet = errors.New("listener already set")
|
||||
|
||||
type packetHandlerMap struct {
|
||||
mutex sync.Mutex
|
||||
handlers map[protocol.ConnectionID]packetHandler
|
||||
@@ -165,7 +172,7 @@ func (h *packetHandlerMap) ReplaceWithClosed(ids []protocol.ConnectionID, pers p
|
||||
var handler packetHandler
|
||||
if connClosePacket != nil {
|
||||
handler = newClosedLocalConn(
|
||||
func(addr net.Addr, info *packetInfo) {
|
||||
func(addr net.Addr, info packetInfo) {
|
||||
h.enqueueClosePacket(closePacket{payload: connClosePacket, addr: addr, info: info})
|
||||
},
|
||||
pers,
|
||||
@@ -213,23 +220,6 @@ func (h *packetHandlerMap) GetByResetToken(token protocol.StatelessResetToken) (
|
||||
return handler, ok
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) CloseServer() {
|
||||
h.mutex.Lock()
|
||||
var wg sync.WaitGroup
|
||||
for _, handler := range h.handlers {
|
||||
if handler.getPerspective() == protocol.PerspectiveServer {
|
||||
wg.Add(1)
|
||||
go func(handler packetHandler) {
|
||||
// blocks until the CONNECTION_CLOSE has been sent and the run-loop has stopped
|
||||
handler.shutdown()
|
||||
wg.Done()
|
||||
}(handler)
|
||||
}
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) Close(e error) {
|
||||
h.mutex.Lock()
|
||||
|
||||
|
||||
400
vendor/github.com/quic-go/quic-go/packet_packer.go
generated
vendored
400
vendor/github.com/quic-go/quic-go/packet_packer.go
generated
vendored
@@ -1,32 +1,31 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/rand"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/ackhandler"
|
||||
"github.com/quic-go/quic-go/internal/handshake"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qerr"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
var errNothingToPack = errors.New("nothing to pack")
|
||||
|
||||
type packer interface {
|
||||
PackCoalescedPacket(onlyAck bool, v protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackPacket(onlyAck bool, now time.Time, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error)
|
||||
MaybePackProbePacket(protocol.EncryptionLevel, protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackConnectionClose(*qerr.TransportError, protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackApplicationClose(*qerr.ApplicationError, protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackCoalescedPacket(onlyAck bool, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackAckOnlyPacket(maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error)
|
||||
AppendPacket(buf *packetBuffer, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (shortHeaderPacket, error)
|
||||
MaybePackProbePacket(protocol.EncryptionLevel, protocol.ByteCount, protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackConnectionClose(*qerr.TransportError, protocol.ByteCount, protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackApplicationClose(*qerr.ApplicationError, protocol.ByteCount, protocol.VersionNumber) (*coalescedPacket, error)
|
||||
PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error)
|
||||
|
||||
SetMaxPacketSize(protocol.ByteCount)
|
||||
PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, now time.Time, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error)
|
||||
|
||||
HandleTransportParameters(*wire.TransportParameters)
|
||||
SetToken([]byte)
|
||||
}
|
||||
|
||||
@@ -35,26 +34,31 @@ type sealer interface {
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
frames []*ackhandler.Frame
|
||||
ack *wire.AckFrame
|
||||
length protocol.ByteCount
|
||||
streamFrames []ackhandler.StreamFrame
|
||||
frames []ackhandler.Frame
|
||||
ack *wire.AckFrame
|
||||
length protocol.ByteCount
|
||||
}
|
||||
|
||||
type longHeaderPacket struct {
|
||||
header *wire.ExtendedHeader
|
||||
ack *wire.AckFrame
|
||||
frames []*ackhandler.Frame
|
||||
header *wire.ExtendedHeader
|
||||
ack *wire.AckFrame
|
||||
frames []ackhandler.Frame
|
||||
streamFrames []ackhandler.StreamFrame // only used for 0-RTT packets
|
||||
|
||||
length protocol.ByteCount
|
||||
|
||||
isMTUProbePacket bool
|
||||
}
|
||||
|
||||
type shortHeaderPacket struct {
|
||||
*ackhandler.Packet
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []ackhandler.Frame
|
||||
StreamFrames []ackhandler.StreamFrame
|
||||
Ack *wire.AckFrame
|
||||
Length protocol.ByteCount
|
||||
IsPathMTUProbePacket bool
|
||||
|
||||
// used for logging
|
||||
DestConnID protocol.ConnectionID
|
||||
Ack *wire.AckFrame
|
||||
PacketNumberLen protocol.PacketNumberLen
|
||||
KeyPhase protocol.KeyPhaseBit
|
||||
}
|
||||
@@ -67,6 +71,11 @@ type coalescedPacket struct {
|
||||
shortHdrPacket *shortHeaderPacket
|
||||
}
|
||||
|
||||
// IsOnlyShortHeaderPacket says if this packet only contains a short header packet (and no long header packets).
|
||||
func (p *coalescedPacket) IsOnlyShortHeaderPacket() bool {
|
||||
return len(p.longHdrPackets) == 0 && p.shortHdrPacket != nil
|
||||
}
|
||||
|
||||
func (p *longHeaderPacket) EncryptionLevel() protocol.EncryptionLevel {
|
||||
//nolint:exhaustive // Will never be called for Retry packets (and they don't have encrypted data).
|
||||
switch p.header.Type {
|
||||
@@ -83,52 +92,6 @@ func (p *longHeaderPacket) EncryptionLevel() protocol.EncryptionLevel {
|
||||
|
||||
func (p *longHeaderPacket) IsAckEliciting() bool { return ackhandler.HasAckElicitingFrames(p.frames) }
|
||||
|
||||
func (p *longHeaderPacket) ToAckHandlerPacket(now time.Time, q *retransmissionQueue) *ackhandler.Packet {
|
||||
largestAcked := protocol.InvalidPacketNumber
|
||||
if p.ack != nil {
|
||||
largestAcked = p.ack.LargestAcked()
|
||||
}
|
||||
encLevel := p.EncryptionLevel()
|
||||
for i := range p.frames {
|
||||
if p.frames[i].OnLost != nil {
|
||||
continue
|
||||
}
|
||||
//nolint:exhaustive // Short header packets are handled separately.
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
p.frames[i].OnLost = q.AddInitial
|
||||
case protocol.EncryptionHandshake:
|
||||
p.frames[i].OnLost = q.AddHandshake
|
||||
case protocol.Encryption0RTT:
|
||||
p.frames[i].OnLost = q.AddAppData
|
||||
}
|
||||
}
|
||||
|
||||
ap := ackhandler.GetPacket()
|
||||
ap.PacketNumber = p.header.PacketNumber
|
||||
ap.LargestAcked = largestAcked
|
||||
ap.Frames = p.frames
|
||||
ap.Length = p.length
|
||||
ap.EncryptionLevel = encLevel
|
||||
ap.SendTime = now
|
||||
ap.IsPathMTUProbePacket = p.isMTUProbePacket
|
||||
return ap
|
||||
}
|
||||
|
||||
func getMaxPacketSize(addr net.Addr) protocol.ByteCount {
|
||||
maxSize := protocol.ByteCount(protocol.MinInitialPacketSize)
|
||||
// If this is not a UDP address, we don't know anything about the MTU.
|
||||
// Use the minimum size of an Initial packet as the max packet size.
|
||||
if udpAddr, ok := addr.(*net.UDPAddr); ok {
|
||||
if utils.IsIPv4(udpAddr.IP) {
|
||||
maxSize = protocol.InitialPacketSizeIPv4
|
||||
} else {
|
||||
maxSize = protocol.InitialPacketSizeIPv6
|
||||
}
|
||||
}
|
||||
return maxSize
|
||||
}
|
||||
|
||||
type packetNumberManager interface {
|
||||
PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
|
||||
PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
|
||||
@@ -143,8 +106,8 @@ type sealingManager interface {
|
||||
|
||||
type frameSource interface {
|
||||
HasData() bool
|
||||
AppendStreamFrames([]*ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount)
|
||||
AppendControlFrames([]*ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount)
|
||||
AppendStreamFrames([]ackhandler.StreamFrame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount)
|
||||
AppendControlFrames([]ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount)
|
||||
}
|
||||
|
||||
type ackFrameSource interface {
|
||||
@@ -168,14 +131,28 @@ type packetPacker struct {
|
||||
acks ackFrameSource
|
||||
datagramQueue *datagramQueue
|
||||
retransmissionQueue *retransmissionQueue
|
||||
rand rand.Rand
|
||||
|
||||
maxPacketSize protocol.ByteCount
|
||||
numNonAckElicitingAcks int
|
||||
}
|
||||
|
||||
var _ packer = &packetPacker{}
|
||||
|
||||
func newPacketPacker(srcConnID protocol.ConnectionID, getDestConnID func() protocol.ConnectionID, initialStream cryptoStream, handshakeStream cryptoStream, packetNumberManager packetNumberManager, retransmissionQueue *retransmissionQueue, remoteAddr net.Addr, cryptoSetup sealingManager, framer frameSource, acks ackFrameSource, datagramQueue *datagramQueue, perspective protocol.Perspective) *packetPacker {
|
||||
func newPacketPacker(
|
||||
srcConnID protocol.ConnectionID,
|
||||
getDestConnID func() protocol.ConnectionID,
|
||||
initialStream, handshakeStream cryptoStream,
|
||||
packetNumberManager packetNumberManager,
|
||||
retransmissionQueue *retransmissionQueue,
|
||||
cryptoSetup sealingManager,
|
||||
framer frameSource,
|
||||
acks ackFrameSource,
|
||||
datagramQueue *datagramQueue,
|
||||
perspective protocol.Perspective,
|
||||
) *packetPacker {
|
||||
var b [8]byte
|
||||
_, _ = crand.Read(b[:])
|
||||
|
||||
return &packetPacker{
|
||||
cryptoSetup: cryptoSetup,
|
||||
getDestConnID: getDestConnID,
|
||||
@@ -187,24 +164,24 @@ func newPacketPacker(srcConnID protocol.ConnectionID, getDestConnID func() proto
|
||||
perspective: perspective,
|
||||
framer: framer,
|
||||
acks: acks,
|
||||
rand: *rand.New(rand.NewSource(binary.BigEndian.Uint64(b[:]))),
|
||||
pnManager: packetNumberManager,
|
||||
maxPacketSize: getMaxPacketSize(remoteAddr),
|
||||
}
|
||||
}
|
||||
|
||||
// PackConnectionClose packs a packet that closes the connection with a transport error.
|
||||
func (p *packetPacker) PackConnectionClose(e *qerr.TransportError, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
func (p *packetPacker) PackConnectionClose(e *qerr.TransportError, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
var reason string
|
||||
// don't send details of crypto errors
|
||||
if !e.ErrorCode.IsCryptoError() {
|
||||
reason = e.ErrorMessage
|
||||
}
|
||||
return p.packConnectionClose(false, uint64(e.ErrorCode), e.FrameType, reason, v)
|
||||
return p.packConnectionClose(false, uint64(e.ErrorCode), e.FrameType, reason, maxPacketSize, v)
|
||||
}
|
||||
|
||||
// PackApplicationClose packs a packet that closes the connection with an application error.
|
||||
func (p *packetPacker) PackApplicationClose(e *qerr.ApplicationError, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
return p.packConnectionClose(true, uint64(e.ErrorCode), 0, e.ErrorMessage, v)
|
||||
func (p *packetPacker) PackApplicationClose(e *qerr.ApplicationError, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
return p.packConnectionClose(true, uint64(e.ErrorCode), 0, e.ErrorMessage, maxPacketSize, v)
|
||||
}
|
||||
|
||||
func (p *packetPacker) packConnectionClose(
|
||||
@@ -212,6 +189,7 @@ func (p *packetPacker) packConnectionClose(
|
||||
errorCode uint64,
|
||||
frameType uint64,
|
||||
reason string,
|
||||
maxPacketSize protocol.ByteCount,
|
||||
v protocol.VersionNumber,
|
||||
) (*coalescedPacket, error) {
|
||||
var sealers [4]sealer
|
||||
@@ -241,7 +219,7 @@ func (p *packetPacker) packConnectionClose(
|
||||
ccf.ReasonPhrase = ""
|
||||
}
|
||||
pl := payload{
|
||||
frames: []*ackhandler.Frame{{Frame: ccf}},
|
||||
frames: []ackhandler.Frame{{Frame: ccf}},
|
||||
length: ccf.Length(v),
|
||||
}
|
||||
|
||||
@@ -293,20 +271,14 @@ func (p *packetPacker) packConnectionClose(
|
||||
}
|
||||
var paddingLen protocol.ByteCount
|
||||
if encLevel == protocol.EncryptionInitial {
|
||||
paddingLen = p.initialPaddingLen(payloads[i].frames, size)
|
||||
paddingLen = p.initialPaddingLen(payloads[i].frames, size, maxPacketSize)
|
||||
}
|
||||
if encLevel == protocol.Encryption1RTT {
|
||||
ap, ack, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, keyPhase, payloads[i], paddingLen, sealers[i], false, v)
|
||||
shp, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, keyPhase, payloads[i], paddingLen, maxPacketSize, sealers[i], false, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packet.shortHdrPacket = &shortHeaderPacket{
|
||||
Packet: ap,
|
||||
DestConnID: connID,
|
||||
Ack: ack,
|
||||
PacketNumberLen: oneRTTPacketNumberLen,
|
||||
KeyPhase: keyPhase,
|
||||
}
|
||||
packet.shortHdrPacket = &shp
|
||||
} else {
|
||||
longHdrPacket, err := p.appendLongHeaderPacket(buffer, hdrs[i], payloads[i], paddingLen, encLevel, sealers[i], v)
|
||||
if err != nil {
|
||||
@@ -342,25 +314,21 @@ func (p *packetPacker) shortHeaderPacketLength(connID protocol.ConnectionID, pnL
|
||||
}
|
||||
|
||||
// size is the expected size of the packet, if no padding was applied.
|
||||
func (p *packetPacker) initialPaddingLen(frames []*ackhandler.Frame, size protocol.ByteCount) protocol.ByteCount {
|
||||
func (p *packetPacker) initialPaddingLen(frames []ackhandler.Frame, currentSize, maxPacketSize protocol.ByteCount) protocol.ByteCount {
|
||||
// For the server, only ack-eliciting Initial packets need to be padded.
|
||||
if p.perspective == protocol.PerspectiveServer && !ackhandler.HasAckElicitingFrames(frames) {
|
||||
return 0
|
||||
}
|
||||
if size >= p.maxPacketSize {
|
||||
if currentSize >= maxPacketSize {
|
||||
return 0
|
||||
}
|
||||
return p.maxPacketSize - size
|
||||
return maxPacketSize - currentSize
|
||||
}
|
||||
|
||||
// PackCoalescedPacket packs a new packet.
|
||||
// It packs an Initial / Handshake if there is data to send in these packet number spaces.
|
||||
// It should only be called before the handshake is confirmed.
|
||||
func (p *packetPacker) PackCoalescedPacket(onlyAck bool, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
maxPacketSize := p.maxPacketSize
|
||||
if p.perspective == protocol.PerspectiveClient {
|
||||
maxPacketSize = protocol.MinInitialPacketSize
|
||||
}
|
||||
func (p *packetPacker) PackCoalescedPacket(onlyAck bool, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
var (
|
||||
initialHdr, handshakeHdr, zeroRTTHdr *wire.ExtendedHeader
|
||||
initialPayload, handshakePayload, zeroRTTPayload, oneRTTPayload payload
|
||||
@@ -417,7 +385,7 @@ func (p *packetPacker) PackCoalescedPacket(onlyAck bool, v protocol.VersionNumbe
|
||||
if oneRTTPayload.length > 0 {
|
||||
size += p.shortHeaderPacketLength(connID, oneRTTPacketNumberLen, oneRTTPayload) + protocol.ByteCount(oneRTTSealer.Overhead())
|
||||
}
|
||||
} else if p.perspective == protocol.PerspectiveClient { // 0-RTT
|
||||
} else if p.perspective == protocol.PerspectiveClient && !onlyAck { // 0-RTT packets can't contain ACK frames
|
||||
var err error
|
||||
zeroRTTSealer, err = p.cryptoSetup.Get0RTTSealer()
|
||||
if err != nil && err != handshake.ErrKeysDropped && err != handshake.ErrKeysNotYetAvailable {
|
||||
@@ -442,7 +410,7 @@ func (p *packetPacker) PackCoalescedPacket(onlyAck bool, v protocol.VersionNumbe
|
||||
longHdrPackets: make([]*longHeaderPacket, 0, 3),
|
||||
}
|
||||
if initialPayload.length > 0 {
|
||||
padding := p.initialPaddingLen(initialPayload.frames, size)
|
||||
padding := p.initialPaddingLen(initialPayload.frames, size, maxPacketSize)
|
||||
cont, err := p.appendLongHeaderPacket(buffer, initialHdr, initialPayload, padding, protocol.EncryptionInitial, initialSealer, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -463,48 +431,44 @@ func (p *packetPacker) PackCoalescedPacket(onlyAck bool, v protocol.VersionNumbe
|
||||
}
|
||||
packet.longHdrPackets = append(packet.longHdrPackets, longHdrPacket)
|
||||
} else if oneRTTPayload.length > 0 {
|
||||
ap, ack, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, kp, oneRTTPayload, 0, oneRTTSealer, false, v)
|
||||
shp, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, kp, oneRTTPayload, 0, maxPacketSize, oneRTTSealer, false, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packet.shortHdrPacket = &shortHeaderPacket{
|
||||
Packet: ap,
|
||||
DestConnID: connID,
|
||||
Ack: ack,
|
||||
PacketNumberLen: oneRTTPacketNumberLen,
|
||||
KeyPhase: kp,
|
||||
}
|
||||
packet.shortHdrPacket = &shp
|
||||
}
|
||||
return packet, nil
|
||||
}
|
||||
|
||||
// PackPacket packs a packet in the application data packet number space.
|
||||
// PackAckOnlyPacket packs a packet containing only an ACK in the application data packet number space.
|
||||
// It should be called after the handshake is confirmed.
|
||||
func (p *packetPacker) PackPacket(onlyAck bool, now time.Time, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error) {
|
||||
func (p *packetPacker) PackAckOnlyPacket(maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error) {
|
||||
buf := getPacketBuffer()
|
||||
packet, err := p.appendPacket(buf, true, maxPacketSize, v)
|
||||
return packet, buf, err
|
||||
}
|
||||
|
||||
// AppendPacket packs a packet in the application data packet number space.
|
||||
// It should be called after the handshake is confirmed.
|
||||
func (p *packetPacker) AppendPacket(buf *packetBuffer, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (shortHeaderPacket, error) {
|
||||
return p.appendPacket(buf, false, maxPacketSize, v)
|
||||
}
|
||||
|
||||
func (p *packetPacker) appendPacket(buf *packetBuffer, onlyAck bool, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (shortHeaderPacket, error) {
|
||||
sealer, err := p.cryptoSetup.Get1RTTSealer()
|
||||
if err != nil {
|
||||
return shortHeaderPacket{}, nil, err
|
||||
return shortHeaderPacket{}, err
|
||||
}
|
||||
pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
|
||||
connID := p.getDestConnID()
|
||||
hdrLen := wire.ShortHeaderLen(connID, pnLen)
|
||||
pl := p.maybeGetShortHeaderPacket(sealer, hdrLen, p.maxPacketSize, onlyAck, true, v)
|
||||
pl := p.maybeGetShortHeaderPacket(sealer, hdrLen, maxPacketSize, onlyAck, true, v)
|
||||
if pl.length == 0 {
|
||||
return shortHeaderPacket{}, nil, errNothingToPack
|
||||
return shortHeaderPacket{}, errNothingToPack
|
||||
}
|
||||
kp := sealer.KeyPhase()
|
||||
buffer := getPacketBuffer()
|
||||
ap, ack, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, 0, sealer, false, v)
|
||||
if err != nil {
|
||||
return shortHeaderPacket{}, nil, err
|
||||
}
|
||||
return shortHeaderPacket{
|
||||
Packet: ap,
|
||||
DestConnID: connID,
|
||||
Ack: ack,
|
||||
PacketNumberLen: pnLen,
|
||||
KeyPhase: kp,
|
||||
}, buffer, nil
|
||||
|
||||
return p.appendShortHeaderPacket(buf, connID, pn, pnLen, kp, pl, 0, maxPacketSize, sealer, false, v)
|
||||
}
|
||||
|
||||
func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize protocol.ByteCount, encLevel protocol.EncryptionLevel, onlyAck, ackAllowed bool, v protocol.VersionNumber) (*wire.ExtendedHeader, payload) {
|
||||
@@ -519,14 +483,17 @@ func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize protocol.ByteCount, en
|
||||
}
|
||||
|
||||
var s cryptoStream
|
||||
var handler ackhandler.FrameHandler
|
||||
var hasRetransmission bool
|
||||
//nolint:exhaustive // Initial and Handshake are the only two encryption levels here.
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
s = p.initialStream
|
||||
handler = p.retransmissionQueue.InitialAckHandler()
|
||||
hasRetransmission = p.retransmissionQueue.HasInitialData()
|
||||
case protocol.EncryptionHandshake:
|
||||
s = p.handshakeStream
|
||||
handler = p.retransmissionQueue.HandshakeAckHandler()
|
||||
hasRetransmission = p.retransmissionQueue.HasHandshakeData()
|
||||
}
|
||||
|
||||
@@ -550,27 +517,27 @@ func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize protocol.ByteCount, en
|
||||
maxPacketSize -= hdr.GetLength(v)
|
||||
if hasRetransmission {
|
||||
for {
|
||||
var f wire.Frame
|
||||
var f ackhandler.Frame
|
||||
//nolint:exhaustive // 0-RTT packets can't contain any retransmission.s
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
f = p.retransmissionQueue.GetInitialFrame(maxPacketSize, v)
|
||||
f.Frame = p.retransmissionQueue.GetInitialFrame(maxPacketSize, v)
|
||||
f.Handler = p.retransmissionQueue.InitialAckHandler()
|
||||
case protocol.EncryptionHandshake:
|
||||
f = p.retransmissionQueue.GetHandshakeFrame(maxPacketSize, v)
|
||||
f.Frame = p.retransmissionQueue.GetHandshakeFrame(maxPacketSize, v)
|
||||
f.Handler = p.retransmissionQueue.HandshakeAckHandler()
|
||||
}
|
||||
if f == nil {
|
||||
if f.Frame == nil {
|
||||
break
|
||||
}
|
||||
af := ackhandler.GetFrame()
|
||||
af.Frame = f
|
||||
pl.frames = append(pl.frames, af)
|
||||
frameLen := f.Length(v)
|
||||
pl.frames = append(pl.frames, f)
|
||||
frameLen := f.Frame.Length(v)
|
||||
pl.length += frameLen
|
||||
maxPacketSize -= frameLen
|
||||
}
|
||||
} else if s.HasData() {
|
||||
cf := s.PopCryptoFrame(maxPacketSize)
|
||||
pl.frames = []*ackhandler.Frame{{Frame: cf}}
|
||||
pl.frames = []ackhandler.Frame{{Frame: cf, Handler: handler}}
|
||||
pl.length += cf.Length(v)
|
||||
}
|
||||
return hdr, pl
|
||||
@@ -595,18 +562,14 @@ func (p *packetPacker) maybeGetAppDataPacket(maxPayloadSize protocol.ByteCount,
|
||||
pl := p.composeNextPacket(maxPayloadSize, onlyAck, ackAllowed, v)
|
||||
|
||||
// check if we have anything to send
|
||||
if len(pl.frames) == 0 {
|
||||
if len(pl.frames) == 0 && len(pl.streamFrames) == 0 {
|
||||
if pl.ack == nil {
|
||||
return payload{}
|
||||
}
|
||||
// the packet only contains an ACK
|
||||
if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
|
||||
ping := &wire.PingFrame{}
|
||||
// don't retransmit the PING frame when it is lost
|
||||
af := ackhandler.GetFrame()
|
||||
af.Frame = ping
|
||||
af.OnLost = func(wire.Frame) {}
|
||||
pl.frames = append(pl.frames, af)
|
||||
pl.frames = append(pl.frames, ackhandler.Frame{Frame: ping})
|
||||
pl.length += ping.Length(v)
|
||||
p.numNonAckElicitingAcks = 0
|
||||
} else {
|
||||
@@ -621,15 +584,12 @@ func (p *packetPacker) maybeGetAppDataPacket(maxPayloadSize protocol.ByteCount,
|
||||
func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, onlyAck, ackAllowed bool, v protocol.VersionNumber) payload {
|
||||
if onlyAck {
|
||||
if ack := p.acks.GetAckFrame(protocol.Encryption1RTT, true); ack != nil {
|
||||
return payload{
|
||||
ack: ack,
|
||||
length: ack.Length(v),
|
||||
}
|
||||
return payload{ack: ack, length: ack.Length(v)}
|
||||
}
|
||||
return payload{}
|
||||
}
|
||||
|
||||
pl := payload{frames: make([]*ackhandler.Frame, 0, 1)}
|
||||
pl := payload{streamFrames: make([]ackhandler.StreamFrame, 0, 1)}
|
||||
|
||||
hasData := p.framer.HasData()
|
||||
hasRetransmission := p.retransmissionQueue.HasAppData()
|
||||
@@ -647,11 +607,7 @@ func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, onlyAc
|
||||
if f := p.datagramQueue.Peek(); f != nil {
|
||||
size := f.Length(v)
|
||||
if size <= maxFrameSize-pl.length {
|
||||
af := ackhandler.GetFrame()
|
||||
af.Frame = f
|
||||
// set it to a no-op. Then we won't set the default callback, which would retransmit the frame.
|
||||
af.OnLost = func(wire.Frame) {}
|
||||
pl.frames = append(pl.frames, af)
|
||||
pl.frames = append(pl.frames, ackhandler.Frame{Frame: f})
|
||||
pl.length += size
|
||||
p.datagramQueue.Pop()
|
||||
}
|
||||
@@ -672,25 +628,28 @@ func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, onlyAc
|
||||
if f == nil {
|
||||
break
|
||||
}
|
||||
af := ackhandler.GetFrame()
|
||||
af.Frame = f
|
||||
pl.frames = append(pl.frames, af)
|
||||
pl.frames = append(pl.frames, ackhandler.Frame{Frame: f, Handler: p.retransmissionQueue.AppDataAckHandler()})
|
||||
pl.length += f.Length(v)
|
||||
}
|
||||
}
|
||||
|
||||
if hasData {
|
||||
var lengthAdded protocol.ByteCount
|
||||
startLen := len(pl.frames)
|
||||
pl.frames, lengthAdded = p.framer.AppendControlFrames(pl.frames, maxFrameSize-pl.length, v)
|
||||
pl.length += lengthAdded
|
||||
// add handlers for the control frames that were added
|
||||
for i := startLen; i < len(pl.frames); i++ {
|
||||
pl.frames[i].Handler = p.retransmissionQueue.AppDataAckHandler()
|
||||
}
|
||||
|
||||
pl.frames, lengthAdded = p.framer.AppendStreamFrames(pl.frames, maxFrameSize-pl.length, v)
|
||||
pl.streamFrames, lengthAdded = p.framer.AppendStreamFrames(pl.streamFrames, maxFrameSize-pl.length, v)
|
||||
pl.length += lengthAdded
|
||||
}
|
||||
return pl
|
||||
}
|
||||
|
||||
func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel, maxPacketSize protocol.ByteCount, v protocol.VersionNumber) (*coalescedPacket, error) {
|
||||
if encLevel == protocol.Encryption1RTT {
|
||||
s, err := p.cryptoSetup.Get1RTTSealer()
|
||||
if err != nil {
|
||||
@@ -700,23 +659,17 @@ func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel, v
|
||||
connID := p.getDestConnID()
|
||||
pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
|
||||
hdrLen := wire.ShortHeaderLen(connID, pnLen)
|
||||
pl := p.maybeGetAppDataPacket(p.maxPacketSize-protocol.ByteCount(s.Overhead())-hdrLen, false, true, v)
|
||||
pl := p.maybeGetAppDataPacket(maxPacketSize-protocol.ByteCount(s.Overhead())-hdrLen, false, true, v)
|
||||
if pl.length == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
buffer := getPacketBuffer()
|
||||
packet := &coalescedPacket{buffer: buffer}
|
||||
ap, ack, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, 0, s, false, v)
|
||||
shp, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, 0, maxPacketSize, s, false, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packet.shortHdrPacket = &shortHeaderPacket{
|
||||
Packet: ap,
|
||||
DestConnID: connID,
|
||||
Ack: ack,
|
||||
PacketNumberLen: pnLen,
|
||||
KeyPhase: kp,
|
||||
}
|
||||
packet.shortHdrPacket = &shp
|
||||
return packet, nil
|
||||
}
|
||||
|
||||
@@ -731,14 +684,14 @@ func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel, v
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr, pl = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), protocol.EncryptionInitial, false, true, v)
|
||||
hdr, pl = p.maybeGetCryptoPacket(maxPacketSize-protocol.ByteCount(sealer.Overhead()), protocol.EncryptionInitial, false, true, v)
|
||||
case protocol.EncryptionHandshake:
|
||||
var err error
|
||||
sealer, err = p.cryptoSetup.GetHandshakeSealer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr, pl = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), protocol.EncryptionHandshake, false, true, v)
|
||||
hdr, pl = p.maybeGetCryptoPacket(maxPacketSize-protocol.ByteCount(sealer.Overhead()), protocol.EncryptionHandshake, false, true, v)
|
||||
default:
|
||||
panic("unknown encryption level")
|
||||
}
|
||||
@@ -751,7 +704,7 @@ func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel, v
|
||||
size := p.longHeaderPacketLength(hdr, pl, v) + protocol.ByteCount(sealer.Overhead())
|
||||
var padding protocol.ByteCount
|
||||
if encLevel == protocol.EncryptionInitial {
|
||||
padding = p.initialPaddingLen(pl.frames, size)
|
||||
padding = p.initialPaddingLen(pl.frames, size, maxPacketSize)
|
||||
}
|
||||
|
||||
longHdrPacket, err := p.appendLongHeaderPacket(buffer, hdr, pl, padding, encLevel, sealer, v)
|
||||
@@ -762,10 +715,10 @@ func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel, v
|
||||
return packet, nil
|
||||
}
|
||||
|
||||
func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, now time.Time, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error) {
|
||||
func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.VersionNumber) (shortHeaderPacket, *packetBuffer, error) {
|
||||
pl := payload{
|
||||
frames: []*ackhandler.Frame{&ping},
|
||||
length: ping.Length(v),
|
||||
frames: []ackhandler.Frame{ping},
|
||||
length: ping.Frame.Length(v),
|
||||
}
|
||||
buffer := getPacketBuffer()
|
||||
s, err := p.cryptoSetup.Get1RTTSealer()
|
||||
@@ -776,17 +729,8 @@ func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.B
|
||||
pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
|
||||
padding := size - p.shortHeaderPacketLength(connID, pnLen, pl) - protocol.ByteCount(s.Overhead())
|
||||
kp := s.KeyPhase()
|
||||
ap, ack, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, padding, s, true, v)
|
||||
if err != nil {
|
||||
return shortHeaderPacket{}, nil, err
|
||||
}
|
||||
return shortHeaderPacket{
|
||||
Packet: ap,
|
||||
DestConnID: connID,
|
||||
Ack: ack,
|
||||
PacketNumberLen: pnLen,
|
||||
KeyPhase: kp,
|
||||
}, buffer, nil
|
||||
packet, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, padding, size, s, true, v)
|
||||
return packet, buffer, err
|
||||
}
|
||||
|
||||
func (p *packetPacker) getLongHeader(encLevel protocol.EncryptionLevel, v protocol.VersionNumber) *wire.ExtendedHeader {
|
||||
@@ -829,23 +773,22 @@ func (p *packetPacker) appendLongHeaderPacket(buffer *packetBuffer, header *wire
|
||||
}
|
||||
payloadOffset := protocol.ByteCount(len(raw))
|
||||
|
||||
pn := p.pnManager.PopPacketNumber(encLevel)
|
||||
if pn != header.PacketNumber {
|
||||
return nil, errors.New("packetPacker BUG: Peeked and Popped packet numbers do not match")
|
||||
}
|
||||
|
||||
raw, err = p.appendPacketPayload(raw, pl, paddingLen, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw = p.encryptPacket(raw, sealer, pn, payloadOffset, pnLen)
|
||||
raw = p.encryptPacket(raw, sealer, header.PacketNumber, payloadOffset, pnLen)
|
||||
buffer.Data = buffer.Data[:len(buffer.Data)+len(raw)]
|
||||
|
||||
if pn := p.pnManager.PopPacketNumber(encLevel); pn != header.PacketNumber {
|
||||
return nil, fmt.Errorf("packetPacker BUG: Peeked and Popped packet numbers do not match: expected %d, got %d", pn, header.PacketNumber)
|
||||
}
|
||||
return &longHeaderPacket{
|
||||
header: header,
|
||||
ack: pl.ack,
|
||||
frames: pl.frames,
|
||||
length: protocol.ByteCount(len(raw)),
|
||||
header: header,
|
||||
ack: pl.ack,
|
||||
frames: pl.frames,
|
||||
streamFrames: pl.streamFrames,
|
||||
length: protocol.ByteCount(len(raw)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -856,11 +799,11 @@ func (p *packetPacker) appendShortHeaderPacket(
|
||||
pnLen protocol.PacketNumberLen,
|
||||
kp protocol.KeyPhaseBit,
|
||||
pl payload,
|
||||
padding protocol.ByteCount,
|
||||
padding, maxPacketSize protocol.ByteCount,
|
||||
sealer sealer,
|
||||
isMTUProbePacket bool,
|
||||
v protocol.VersionNumber,
|
||||
) (*ackhandler.Packet, *wire.AckFrame, error) {
|
||||
) (shortHeaderPacket, error) {
|
||||
var paddingLen protocol.ByteCount
|
||||
if pl.length < 4-protocol.ByteCount(pnLen) {
|
||||
paddingLen = 4 - protocol.ByteCount(pnLen) - pl.length
|
||||
@@ -871,50 +814,40 @@ func (p *packetPacker) appendShortHeaderPacket(
|
||||
raw := buffer.Data[startLen:]
|
||||
raw, err := wire.AppendShortHeader(raw, connID, pn, pnLen, kp)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return shortHeaderPacket{}, err
|
||||
}
|
||||
payloadOffset := protocol.ByteCount(len(raw))
|
||||
|
||||
if pn != p.pnManager.PopPacketNumber(protocol.Encryption1RTT) {
|
||||
return nil, nil, errors.New("packetPacker BUG: Peeked and Popped packet numbers do not match")
|
||||
}
|
||||
|
||||
raw, err = p.appendPacketPayload(raw, pl, paddingLen, v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return shortHeaderPacket{}, err
|
||||
}
|
||||
if !isMTUProbePacket {
|
||||
if size := protocol.ByteCount(len(raw) + sealer.Overhead()); size > p.maxPacketSize {
|
||||
return nil, nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, p.maxPacketSize)
|
||||
if size := protocol.ByteCount(len(raw) + sealer.Overhead()); size > maxPacketSize {
|
||||
return shortHeaderPacket{}, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, maxPacketSize)
|
||||
}
|
||||
}
|
||||
raw = p.encryptPacket(raw, sealer, pn, payloadOffset, protocol.ByteCount(pnLen))
|
||||
buffer.Data = buffer.Data[:len(buffer.Data)+len(raw)]
|
||||
|
||||
// create the ackhandler.Packet
|
||||
largestAcked := protocol.InvalidPacketNumber
|
||||
if pl.ack != nil {
|
||||
largestAcked = pl.ack.LargestAcked()
|
||||
if newPN := p.pnManager.PopPacketNumber(protocol.Encryption1RTT); newPN != pn {
|
||||
return shortHeaderPacket{}, fmt.Errorf("packetPacker BUG: Peeked and Popped packet numbers do not match: expected %d, got %d", pn, newPN)
|
||||
}
|
||||
for i := range pl.frames {
|
||||
if pl.frames[i].OnLost != nil {
|
||||
continue
|
||||
}
|
||||
pl.frames[i].OnLost = p.retransmissionQueue.AddAppData
|
||||
}
|
||||
|
||||
ap := ackhandler.GetPacket()
|
||||
ap.PacketNumber = pn
|
||||
ap.LargestAcked = largestAcked
|
||||
ap.Frames = pl.frames
|
||||
ap.Length = protocol.ByteCount(len(raw))
|
||||
ap.EncryptionLevel = protocol.Encryption1RTT
|
||||
ap.SendTime = time.Now()
|
||||
ap.IsPathMTUProbePacket = isMTUProbePacket
|
||||
|
||||
return ap, pl.ack, nil
|
||||
return shortHeaderPacket{
|
||||
PacketNumber: pn,
|
||||
PacketNumberLen: pnLen,
|
||||
KeyPhase: kp,
|
||||
StreamFrames: pl.streamFrames,
|
||||
Frames: pl.frames,
|
||||
Ack: pl.ack,
|
||||
Length: protocol.ByteCount(len(raw)),
|
||||
DestConnID: connID,
|
||||
IsPathMTUProbePacket: isMTUProbePacket,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// appendPacketPayload serializes the payload of a packet into the raw byte slice.
|
||||
// It modifies the order of payload.frames.
|
||||
func (p *packetPacker) appendPacketPayload(raw []byte, pl payload, paddingLen protocol.ByteCount, v protocol.VersionNumber) ([]byte, error) {
|
||||
payloadOffset := len(raw)
|
||||
if pl.ack != nil {
|
||||
@@ -927,9 +860,21 @@ func (p *packetPacker) appendPacketPayload(raw []byte, pl payload, paddingLen pr
|
||||
if paddingLen > 0 {
|
||||
raw = append(raw, make([]byte, paddingLen)...)
|
||||
}
|
||||
for _, frame := range pl.frames {
|
||||
// Randomize the order of the control frames.
|
||||
// This makes sure that the receiver doesn't rely on the order in which frames are packed.
|
||||
if len(pl.frames) > 1 {
|
||||
p.rand.Shuffle(len(pl.frames), func(i, j int) { pl.frames[i], pl.frames[j] = pl.frames[j], pl.frames[i] })
|
||||
}
|
||||
for _, f := range pl.frames {
|
||||
var err error
|
||||
raw, err = frame.Append(raw, v)
|
||||
raw, err = f.Frame.Append(raw, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, f := range pl.streamFrames {
|
||||
var err error
|
||||
raw, err = f.Frame.Append(raw, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -953,16 +898,3 @@ func (p *packetPacker) encryptPacket(raw []byte, sealer sealer, pn protocol.Pack
|
||||
func (p *packetPacker) SetToken(token []byte) {
|
||||
p.token = token
|
||||
}
|
||||
|
||||
// When a higher MTU is discovered, use it.
|
||||
func (p *packetPacker) SetMaxPacketSize(s protocol.ByteCount) {
|
||||
p.maxPacketSize = s
|
||||
}
|
||||
|
||||
// If the peer sets a max_packet_size that's smaller than the size we're currently using,
|
||||
// we need to reduce the size of packets we send.
|
||||
func (p *packetPacker) HandleTransportParameters(params *wire.TransportParameters) {
|
||||
if params.MaxUDPPayloadSize != 0 {
|
||||
p.maxPacketSize = utils.Min(p.maxPacketSize, params.MaxUDPPayloadSize)
|
||||
}
|
||||
}
|
||||
|
||||
19
vendor/github.com/quic-go/quic-go/quicvarint/varint.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/quicvarint/varint.go
generated
vendored
@@ -70,25 +70,6 @@ func Read(r io.ByteReader) (uint64, error) {
|
||||
return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil
|
||||
}
|
||||
|
||||
// Write writes i in the QUIC varint format to w.
|
||||
// Deprecated: use Append instead.
|
||||
func Write(w Writer, i uint64) {
|
||||
if i <= maxVarInt1 {
|
||||
w.WriteByte(uint8(i))
|
||||
} else if i <= maxVarInt2 {
|
||||
w.Write([]byte{uint8(i>>8) | 0x40, uint8(i)})
|
||||
} else if i <= maxVarInt4 {
|
||||
w.Write([]byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)})
|
||||
} else if i <= maxVarInt8 {
|
||||
w.Write([]byte{
|
||||
uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32),
|
||||
uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i),
|
||||
})
|
||||
} else {
|
||||
panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
|
||||
}
|
||||
}
|
||||
|
||||
// Append appends i in the QUIC varint format.
|
||||
func Append(b []byte, i uint64) []byte {
|
||||
if i <= maxVarInt1 {
|
||||
|
||||
4
vendor/github.com/quic-go/quic-go/receive_stream.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/receive_stream.go
generated
vendored
@@ -179,6 +179,10 @@ func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, err
|
||||
|
||||
if s.readPosInFrame >= len(s.currentFrame) && s.currentFrameIsLast {
|
||||
s.finRead = true
|
||||
s.currentFrame = nil
|
||||
if s.currentFrameDone != nil {
|
||||
s.currentFrameDone()
|
||||
}
|
||||
return true, bytesRead, io.EOF
|
||||
}
|
||||
}
|
||||
|
||||
57
vendor/github.com/quic-go/quic-go/retransmission_queue.go
generated
vendored
57
vendor/github.com/quic-go/quic-go/retransmission_queue.go
generated
vendored
@@ -3,6 +3,8 @@ package quic
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/ackhandler"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
@@ -21,7 +23,23 @@ func newRetransmissionQueue() *retransmissionQueue {
|
||||
return &retransmissionQueue{}
|
||||
}
|
||||
|
||||
func (q *retransmissionQueue) AddInitial(f wire.Frame) {
|
||||
// AddPing queues a ping.
|
||||
// It is used when a probe packet needs to be sent
|
||||
func (q *retransmissionQueue) AddPing(encLevel protocol.EncryptionLevel) {
|
||||
//nolint:exhaustive // Cannot send probe packets for 0-RTT.
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
q.addInitial(&wire.PingFrame{})
|
||||
case protocol.EncryptionHandshake:
|
||||
q.addHandshake(&wire.PingFrame{})
|
||||
case protocol.Encryption1RTT:
|
||||
q.addAppData(&wire.PingFrame{})
|
||||
default:
|
||||
panic("unexpected encryption level")
|
||||
}
|
||||
}
|
||||
|
||||
func (q *retransmissionQueue) addInitial(f wire.Frame) {
|
||||
if cf, ok := f.(*wire.CryptoFrame); ok {
|
||||
q.initialCryptoData = append(q.initialCryptoData, cf)
|
||||
return
|
||||
@@ -29,7 +47,7 @@ func (q *retransmissionQueue) AddInitial(f wire.Frame) {
|
||||
q.initial = append(q.initial, f)
|
||||
}
|
||||
|
||||
func (q *retransmissionQueue) AddHandshake(f wire.Frame) {
|
||||
func (q *retransmissionQueue) addHandshake(f wire.Frame) {
|
||||
if cf, ok := f.(*wire.CryptoFrame); ok {
|
||||
q.handshakeCryptoData = append(q.handshakeCryptoData, cf)
|
||||
return
|
||||
@@ -49,7 +67,7 @@ func (q *retransmissionQueue) HasAppData() bool {
|
||||
return len(q.appData) > 0
|
||||
}
|
||||
|
||||
func (q *retransmissionQueue) AddAppData(f wire.Frame) {
|
||||
func (q *retransmissionQueue) addAppData(f wire.Frame) {
|
||||
if _, ok := f.(*wire.StreamFrame); ok {
|
||||
panic("STREAM frames are handled with their respective streams.")
|
||||
}
|
||||
@@ -127,3 +145,36 @@ func (q *retransmissionQueue) DropPackets(encLevel protocol.EncryptionLevel) {
|
||||
panic(fmt.Sprintf("unexpected encryption level: %s", encLevel))
|
||||
}
|
||||
}
|
||||
|
||||
func (q *retransmissionQueue) InitialAckHandler() ackhandler.FrameHandler {
|
||||
return (*retransmissionQueueInitialAckHandler)(q)
|
||||
}
|
||||
|
||||
func (q *retransmissionQueue) HandshakeAckHandler() ackhandler.FrameHandler {
|
||||
return (*retransmissionQueueHandshakeAckHandler)(q)
|
||||
}
|
||||
|
||||
func (q *retransmissionQueue) AppDataAckHandler() ackhandler.FrameHandler {
|
||||
return (*retransmissionQueueAppDataAckHandler)(q)
|
||||
}
|
||||
|
||||
type retransmissionQueueInitialAckHandler retransmissionQueue
|
||||
|
||||
func (q *retransmissionQueueInitialAckHandler) OnAcked(wire.Frame) {}
|
||||
func (q *retransmissionQueueInitialAckHandler) OnLost(f wire.Frame) {
|
||||
(*retransmissionQueue)(q).addInitial(f)
|
||||
}
|
||||
|
||||
type retransmissionQueueHandshakeAckHandler retransmissionQueue
|
||||
|
||||
func (q *retransmissionQueueHandshakeAckHandler) OnAcked(wire.Frame) {}
|
||||
func (q *retransmissionQueueHandshakeAckHandler) OnLost(f wire.Frame) {
|
||||
(*retransmissionQueue)(q).addHandshake(f)
|
||||
}
|
||||
|
||||
type retransmissionQueueAppDataAckHandler retransmissionQueue
|
||||
|
||||
func (q *retransmissionQueueAppDataAckHandler) OnAcked(wire.Frame) {}
|
||||
func (q *retransmissionQueueAppDataAckHandler) OnLost(f wire.Frame) {
|
||||
(*retransmissionQueue)(q).addAppData(f)
|
||||
}
|
||||
|
||||
92
vendor/github.com/quic-go/quic-go/send_conn.go
generated
vendored
92
vendor/github.com/quic-go/quic-go/send_conn.go
generated
vendored
@@ -2,52 +2,102 @@ package quic
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
// A sendConn allows sending using a simple Write() on a non-connected packet conn.
|
||||
type sendConn interface {
|
||||
Write([]byte) error
|
||||
Write(b []byte, gsoSize uint16, ecn protocol.ECN) error
|
||||
Close() error
|
||||
LocalAddr() net.Addr
|
||||
RemoteAddr() net.Addr
|
||||
|
||||
capabilities() connCapabilities
|
||||
}
|
||||
|
||||
type sconn struct {
|
||||
rawConn
|
||||
|
||||
localAddr net.Addr
|
||||
remoteAddr net.Addr
|
||||
info *packetInfo
|
||||
oob []byte
|
||||
|
||||
logger utils.Logger
|
||||
|
||||
packetInfoOOB []byte
|
||||
// If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled.
|
||||
gotGSOError bool
|
||||
// Used to catch the error sometimes returned by the first sendmsg call on Linux,
|
||||
// see https://github.com/golang/go/issues/63322.
|
||||
wroteFirstPacket bool
|
||||
}
|
||||
|
||||
var _ sendConn = &sconn{}
|
||||
|
||||
func newSendConn(c rawConn, remote net.Addr, info *packetInfo) *sconn {
|
||||
func newSendConn(c rawConn, remote net.Addr, info packetInfo, logger utils.Logger) *sconn {
|
||||
localAddr := c.LocalAddr()
|
||||
if info.addr.IsValid() {
|
||||
if udpAddr, ok := localAddr.(*net.UDPAddr); ok {
|
||||
addrCopy := *udpAddr
|
||||
addrCopy.IP = info.addr.AsSlice()
|
||||
localAddr = &addrCopy
|
||||
}
|
||||
}
|
||||
|
||||
oob := info.OOB()
|
||||
// increase oob slice capacity, so we can add the UDP_SEGMENT and ECN control messages without allocating
|
||||
l := len(oob)
|
||||
oob = append(oob, make([]byte, 64)...)[:l]
|
||||
return &sconn{
|
||||
rawConn: c,
|
||||
remoteAddr: remote,
|
||||
info: info,
|
||||
oob: info.OOB(),
|
||||
rawConn: c,
|
||||
localAddr: localAddr,
|
||||
remoteAddr: remote,
|
||||
packetInfoOOB: oob,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *sconn) Write(p []byte) error {
|
||||
_, err := c.WritePacket(p, c.remoteAddr, c.oob)
|
||||
func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
|
||||
err := c.writePacket(p, c.remoteAddr, c.packetInfoOOB, gsoSize, ecn)
|
||||
if err != nil && isGSOError(err) {
|
||||
// disable GSO for future calls
|
||||
c.gotGSOError = true
|
||||
if c.logger.Debug() {
|
||||
c.logger.Debugf("GSO failed when sending to %s", c.remoteAddr)
|
||||
}
|
||||
// send out the packets one by one
|
||||
for len(p) > 0 {
|
||||
l := len(p)
|
||||
if l > int(gsoSize) {
|
||||
l = int(gsoSize)
|
||||
}
|
||||
if err := c.writePacket(p[:l], c.remoteAddr, c.packetInfoOOB, 0, ecn); err != nil {
|
||||
return err
|
||||
}
|
||||
p = p[l:]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *sconn) RemoteAddr() net.Addr {
|
||||
return c.remoteAddr
|
||||
func (c *sconn) writePacket(p []byte, addr net.Addr, oob []byte, gsoSize uint16, ecn protocol.ECN) error {
|
||||
_, err := c.WritePacket(p, addr, oob, gsoSize, ecn)
|
||||
if err != nil && !c.wroteFirstPacket && isPermissionError(err) {
|
||||
_, err = c.WritePacket(p, addr, oob, gsoSize, ecn)
|
||||
}
|
||||
c.wroteFirstPacket = true
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *sconn) LocalAddr() net.Addr {
|
||||
addr := c.rawConn.LocalAddr()
|
||||
if c.info != nil {
|
||||
if udpAddr, ok := addr.(*net.UDPAddr); ok {
|
||||
addrCopy := *udpAddr
|
||||
addrCopy.IP = c.info.addr
|
||||
addr = &addrCopy
|
||||
}
|
||||
func (c *sconn) capabilities() connCapabilities {
|
||||
capabilities := c.rawConn.capabilities()
|
||||
if capabilities.GSO {
|
||||
capabilities.GSO = !c.gotGSOError
|
||||
}
|
||||
return addr
|
||||
return capabilities
|
||||
}
|
||||
|
||||
func (c *sconn) RemoteAddr() net.Addr { return c.remoteAddr }
|
||||
func (c *sconn) LocalAddr() net.Addr { return c.localAddr }
|
||||
|
||||
26
vendor/github.com/quic-go/quic-go/send_queue.go
generated
vendored
26
vendor/github.com/quic-go/quic-go/send_queue.go
generated
vendored
@@ -1,15 +1,23 @@
|
||||
package quic
|
||||
|
||||
import "github.com/quic-go/quic-go/internal/protocol"
|
||||
|
||||
type sender interface {
|
||||
Send(p *packetBuffer)
|
||||
Send(p *packetBuffer, gsoSize uint16, ecn protocol.ECN)
|
||||
Run() error
|
||||
WouldBlock() bool
|
||||
Available() <-chan struct{}
|
||||
Close()
|
||||
}
|
||||
|
||||
type queueEntry struct {
|
||||
buf *packetBuffer
|
||||
gsoSize uint16
|
||||
ecn protocol.ECN
|
||||
}
|
||||
|
||||
type sendQueue struct {
|
||||
queue chan *packetBuffer
|
||||
queue chan queueEntry
|
||||
closeCalled chan struct{} // runStopped when Close() is called
|
||||
runStopped chan struct{} // runStopped when the run loop returns
|
||||
available chan struct{}
|
||||
@@ -26,16 +34,16 @@ func newSendQueue(conn sendConn) sender {
|
||||
runStopped: make(chan struct{}),
|
||||
closeCalled: make(chan struct{}),
|
||||
available: make(chan struct{}, 1),
|
||||
queue: make(chan *packetBuffer, sendQueueCapacity),
|
||||
queue: make(chan queueEntry, sendQueueCapacity),
|
||||
}
|
||||
}
|
||||
|
||||
// Send sends out a packet. It's guaranteed to not block.
|
||||
// Callers need to make sure that there's actually space in the send queue by calling WouldBlock.
|
||||
// Otherwise Send will panic.
|
||||
func (h *sendQueue) Send(p *packetBuffer) {
|
||||
func (h *sendQueue) Send(p *packetBuffer, gsoSize uint16, ecn protocol.ECN) {
|
||||
select {
|
||||
case h.queue <- p:
|
||||
case h.queue <- queueEntry{buf: p, gsoSize: gsoSize, ecn: ecn}:
|
||||
// clear available channel if we've reached capacity
|
||||
if len(h.queue) == sendQueueCapacity {
|
||||
select {
|
||||
@@ -69,17 +77,17 @@ func (h *sendQueue) Run() error {
|
||||
h.closeCalled = nil // prevent this case from being selected again
|
||||
// make sure that all queued packets are actually sent out
|
||||
shouldClose = true
|
||||
case p := <-h.queue:
|
||||
if err := h.conn.Write(p.Data); err != nil {
|
||||
case e := <-h.queue:
|
||||
if err := h.conn.Write(e.buf.Data, e.gsoSize, e.ecn); err != nil {
|
||||
// This additional check enables:
|
||||
// 1. Checking for "datagram too large" message from the kernel, as such,
|
||||
// 2. Path MTU discovery,and
|
||||
// 3. Eventual detection of loss PingFrame.
|
||||
if !isMsgSizeErr(err) {
|
||||
if !isSendMsgSizeErr(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
p.Release()
|
||||
e.buf.Release()
|
||||
select {
|
||||
case h.available <- struct{}{}:
|
||||
default:
|
||||
|
||||
105
vendor/github.com/quic-go/quic-go/send_stream.go
generated
vendored
105
vendor/github.com/quic-go/quic-go/send_stream.go
generated
vendored
@@ -18,7 +18,7 @@ type sendStreamI interface {
|
||||
SendStream
|
||||
handleStopSendingFrame(*wire.StopSendingFrame)
|
||||
hasData() bool
|
||||
popStreamFrame(maxBytes protocol.ByteCount, v protocol.VersionNumber) (*ackhandler.Frame, bool)
|
||||
popStreamFrame(maxBytes protocol.ByteCount, v protocol.VersionNumber) (frame ackhandler.StreamFrame, ok, hasMore bool)
|
||||
closeForShutdown(error)
|
||||
updateSendWindow(protocol.ByteCount)
|
||||
}
|
||||
@@ -30,7 +30,7 @@ type sendStream struct {
|
||||
retransmissionQueue []*wire.StreamFrame
|
||||
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
ctxCancel context.CancelCauseFunc
|
||||
|
||||
streamID protocol.StreamID
|
||||
sender streamSender
|
||||
@@ -71,7 +71,7 @@ func newSendStream(
|
||||
writeChan: make(chan struct{}, 1),
|
||||
writeOnce: make(chan struct{}, 1), // cap: 1, to protect against concurrent use of Write
|
||||
}
|
||||
s.ctx, s.ctxCancel = context.WithCancel(context.Background())
|
||||
s.ctx, s.ctxCancel = context.WithCancelCause(context.Background())
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ func (s *sendStream) canBufferStreamFrame() bool {
|
||||
|
||||
// popStreamFrame returns the next STREAM frame that is supposed to be sent on this stream
|
||||
// maxBytes is the maximum length this frame (including frame header) will have.
|
||||
func (s *sendStream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.VersionNumber) (*ackhandler.Frame, bool /* has more data to send */) {
|
||||
func (s *sendStream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.VersionNumber) (af ackhandler.StreamFrame, ok, hasMore bool) {
|
||||
s.mutex.Lock()
|
||||
f, hasMoreData := s.popNewOrRetransmittedStreamFrame(maxBytes, v)
|
||||
if f != nil {
|
||||
@@ -207,13 +207,12 @@ func (s *sendStream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.Vers
|
||||
s.mutex.Unlock()
|
||||
|
||||
if f == nil {
|
||||
return nil, hasMoreData
|
||||
return ackhandler.StreamFrame{}, false, hasMoreData
|
||||
}
|
||||
af := ackhandler.GetFrame()
|
||||
af.Frame = f
|
||||
af.OnLost = s.queueRetransmission
|
||||
af.OnAcked = s.frameAcked
|
||||
return af, hasMoreData
|
||||
return ackhandler.StreamFrame{
|
||||
Frame: f,
|
||||
Handler: (*sendStreamAckHandler)(s),
|
||||
}, true, hasMoreData
|
||||
}
|
||||
|
||||
func (s *sendStream) popNewOrRetransmittedStreamFrame(maxBytes protocol.ByteCount, v protocol.VersionNumber) (*wire.StreamFrame, bool /* has more data to send */) {
|
||||
@@ -348,26 +347,6 @@ func (s *sendStream) getDataForWriting(f *wire.StreamFrame, maxBytes protocol.By
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sendStream) frameAcked(f wire.Frame) {
|
||||
f.(*wire.StreamFrame).PutBack()
|
||||
|
||||
s.mutex.Lock()
|
||||
if s.cancelWriteErr != nil {
|
||||
s.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
s.numOutstandingFrames--
|
||||
if s.numOutstandingFrames < 0 {
|
||||
panic("numOutStandingFrames negative")
|
||||
}
|
||||
newlyCompleted := s.isNewlyCompleted()
|
||||
s.mutex.Unlock()
|
||||
|
||||
if newlyCompleted {
|
||||
s.sender.onStreamCompleted(s.streamID)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sendStream) isNewlyCompleted() bool {
|
||||
completed := (s.finSent || s.cancelWriteErr != nil) && s.numOutstandingFrames == 0 && len(s.retransmissionQueue) == 0
|
||||
if completed && !s.completed {
|
||||
@@ -377,24 +356,6 @@ func (s *sendStream) isNewlyCompleted() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *sendStream) queueRetransmission(f wire.Frame) {
|
||||
sf := f.(*wire.StreamFrame)
|
||||
sf.DataLenPresent = true
|
||||
s.mutex.Lock()
|
||||
if s.cancelWriteErr != nil {
|
||||
s.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
s.retransmissionQueue = append(s.retransmissionQueue, sf)
|
||||
s.numOutstandingFrames--
|
||||
if s.numOutstandingFrames < 0 {
|
||||
panic("numOutStandingFrames negative")
|
||||
}
|
||||
s.mutex.Unlock()
|
||||
|
||||
s.sender.onHasStreamData(s.streamID)
|
||||
}
|
||||
|
||||
func (s *sendStream) Close() error {
|
||||
s.mutex.Lock()
|
||||
if s.closeForShutdownErr != nil {
|
||||
@@ -405,7 +366,7 @@ func (s *sendStream) Close() error {
|
||||
s.mutex.Unlock()
|
||||
return fmt.Errorf("close called for canceled stream %d", s.streamID)
|
||||
}
|
||||
s.ctxCancel()
|
||||
s.ctxCancel(nil)
|
||||
s.finishedWriting = true
|
||||
s.mutex.Unlock()
|
||||
|
||||
@@ -424,8 +385,8 @@ func (s *sendStream) cancelWriteImpl(errorCode qerr.StreamErrorCode, remote bool
|
||||
s.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
s.ctxCancel()
|
||||
s.cancelWriteErr = &StreamError{StreamID: s.streamID, ErrorCode: errorCode, Remote: remote}
|
||||
s.ctxCancel(s.cancelWriteErr)
|
||||
s.numOutstandingFrames = 0
|
||||
s.retransmissionQueue = nil
|
||||
newlyCompleted := s.isNewlyCompleted()
|
||||
@@ -474,7 +435,7 @@ func (s *sendStream) SetWriteDeadline(t time.Time) error {
|
||||
// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST.
|
||||
func (s *sendStream) closeForShutdown(err error) {
|
||||
s.mutex.Lock()
|
||||
s.ctxCancel()
|
||||
s.ctxCancel(err)
|
||||
s.closeForShutdownErr = err
|
||||
s.mutex.Unlock()
|
||||
s.signalWrite()
|
||||
@@ -487,3 +448,45 @@ func (s *sendStream) signalWrite() {
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
type sendStreamAckHandler sendStream
|
||||
|
||||
var _ ackhandler.FrameHandler = &sendStreamAckHandler{}
|
||||
|
||||
func (s *sendStreamAckHandler) OnAcked(f wire.Frame) {
|
||||
sf := f.(*wire.StreamFrame)
|
||||
sf.PutBack()
|
||||
s.mutex.Lock()
|
||||
if s.cancelWriteErr != nil {
|
||||
s.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
s.numOutstandingFrames--
|
||||
if s.numOutstandingFrames < 0 {
|
||||
panic("numOutStandingFrames negative")
|
||||
}
|
||||
newlyCompleted := (*sendStream)(s).isNewlyCompleted()
|
||||
s.mutex.Unlock()
|
||||
|
||||
if newlyCompleted {
|
||||
s.sender.onStreamCompleted(s.streamID)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sendStreamAckHandler) OnLost(f wire.Frame) {
|
||||
sf := f.(*wire.StreamFrame)
|
||||
s.mutex.Lock()
|
||||
if s.cancelWriteErr != nil {
|
||||
s.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
sf.DataLenPresent = true
|
||||
s.retransmissionQueue = append(s.retransmissionQueue, sf)
|
||||
s.numOutstandingFrames--
|
||||
if s.numOutstandingFrames < 0 {
|
||||
panic("numOutStandingFrames negative")
|
||||
}
|
||||
s.mutex.Unlock()
|
||||
|
||||
s.sender.onHasStreamData(s.streamID)
|
||||
}
|
||||
|
||||
393
vendor/github.com/quic-go/quic-go/server.go
generated
vendored
393
vendor/github.com/quic-go/quic-go/server.go
generated
vendored
@@ -2,7 +2,6 @@ package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -24,7 +23,7 @@ var ErrServerClosed = errors.New("quic: server closed")
|
||||
|
||||
// packetHandler handles packets
|
||||
type packetHandler interface {
|
||||
handlePacket(*receivedPacket)
|
||||
handlePacket(receivedPacket)
|
||||
shutdown()
|
||||
destroy(error)
|
||||
getPerspective() protocol.Perspective
|
||||
@@ -35,14 +34,13 @@ type packetHandlerManager interface {
|
||||
GetByResetToken(protocol.StatelessResetToken) (packetHandler, bool)
|
||||
AddWithConnID(protocol.ConnectionID, protocol.ConnectionID, func() (packetHandler, bool)) bool
|
||||
Close(error)
|
||||
CloseServer()
|
||||
connRunner
|
||||
}
|
||||
|
||||
type quicConn interface {
|
||||
EarlyConnection
|
||||
earlyConnReady() <-chan struct{}
|
||||
handlePacket(*receivedPacket)
|
||||
handlePacket(receivedPacket)
|
||||
GetVersion() protocol.VersionNumber
|
||||
getPerspective() protocol.Perspective
|
||||
run() error
|
||||
@@ -51,15 +49,19 @@ type quicConn interface {
|
||||
}
|
||||
|
||||
type zeroRTTQueue struct {
|
||||
packets []*receivedPacket
|
||||
packets []receivedPacket
|
||||
expiration time.Time
|
||||
}
|
||||
|
||||
type rejectedPacket struct {
|
||||
receivedPacket
|
||||
hdr *wire.Header
|
||||
}
|
||||
|
||||
// A Listener of QUIC
|
||||
type baseServer struct {
|
||||
mutex sync.Mutex
|
||||
|
||||
acceptEarlyConns bool
|
||||
disableVersionNegotiation bool
|
||||
acceptEarlyConns bool
|
||||
|
||||
tlsConf *tls.Config
|
||||
config *Config
|
||||
@@ -67,12 +69,13 @@ type baseServer struct {
|
||||
conn rawConn
|
||||
|
||||
tokenGenerator *handshake.TokenGenerator
|
||||
maxTokenAge time.Duration
|
||||
|
||||
connIDGenerator ConnectionIDGenerator
|
||||
connHandler packetHandlerManager
|
||||
onClose func()
|
||||
|
||||
receivedPackets chan *receivedPacket
|
||||
receivedPackets chan receivedPacket
|
||||
|
||||
nextZeroRTTCleanup time.Time
|
||||
zeroRTTQueues map[protocol.ConnectionID]*zeroRTTQueue // only initialized if acceptEarlyConns == true
|
||||
@@ -92,21 +95,26 @@ type baseServer struct {
|
||||
*tls.Config,
|
||||
*handshake.TokenGenerator,
|
||||
bool, /* client address validated by an address validation token */
|
||||
logging.ConnectionTracer,
|
||||
*logging.ConnectionTracer,
|
||||
uint64,
|
||||
utils.Logger,
|
||||
protocol.VersionNumber,
|
||||
) quicConn
|
||||
|
||||
serverError error
|
||||
errorChan chan struct{}
|
||||
closed bool
|
||||
running chan struct{} // closed as soon as run() returns
|
||||
closeOnce sync.Once
|
||||
errorChan chan struct{} // is closed when the server is closed
|
||||
closeErr error
|
||||
running chan struct{} // closed as soon as run() returns
|
||||
|
||||
versionNegotiationQueue chan receivedPacket
|
||||
invalidTokenQueue chan rejectedPacket
|
||||
connectionRefusedQueue chan rejectedPacket
|
||||
retryQueue chan rejectedPacket
|
||||
|
||||
connQueue chan quicConn
|
||||
connQueueLen int32 // to be used as an atomic
|
||||
|
||||
tracer logging.Tracer
|
||||
tracer *logging.Tracer
|
||||
|
||||
logger utils.Logger
|
||||
}
|
||||
@@ -122,7 +130,12 @@ func (l *Listener) Accept(ctx context.Context) (Connection, error) {
|
||||
return l.baseServer.Accept(ctx)
|
||||
}
|
||||
|
||||
// Close the server. All active connections will be closed.
|
||||
// Close closes the listener.
|
||||
// Accept will return ErrServerClosed as soon as all connections in the accept queue have been accepted.
|
||||
// QUIC handshakes that are still in flight will be rejected with a CONNECTION_REFUSED error.
|
||||
// The effect of closing the listener depends on how it was created:
|
||||
// * if it was created using Transport.Listen, already established connections will be unaffected
|
||||
// * if it was created using the Listen convenience method, all established connection will be closed immediately
|
||||
func (l *Listener) Close() error {
|
||||
return l.baseServer.Close()
|
||||
}
|
||||
@@ -158,8 +171,7 @@ func (l *EarlyListener) Addr() net.Addr {
|
||||
}
|
||||
|
||||
// ListenAddr creates a QUIC server listening on a given address.
|
||||
// The tls.Config must not be nil and must contain a certificate configuration.
|
||||
// The quic.Config may be nil, in that case the default values will be used.
|
||||
// See Listen for more details.
|
||||
func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (*Listener, error) {
|
||||
conn, err := listenUDP(addr)
|
||||
if err != nil {
|
||||
@@ -193,16 +205,20 @@ func listenUDP(addr string) (*net.UDPConn, error) {
|
||||
return net.ListenUDP("udp", udpAddr)
|
||||
}
|
||||
|
||||
// Listen listens for QUIC connections on a given net.PacketConn. If the
|
||||
// PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn
|
||||
// does), ECN and packet info support will be enabled. In this case, ReadMsgUDP
|
||||
// and WriteMsgUDP will be used instead of ReadFrom and WriteTo to read/write
|
||||
// packets. A single net.PacketConn only be used for a single call to Listen.
|
||||
// The PacketConn can be used for simultaneous calls to Dial. QUIC connection
|
||||
// IDs are used for demultiplexing the different connections.
|
||||
// Listen listens for QUIC connections on a given net.PacketConn.
|
||||
// If the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn does),
|
||||
// ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP
|
||||
// will be used instead of ReadFrom and WriteTo to read/write packets.
|
||||
// A single net.PacketConn can only be used for a single call to Listen.
|
||||
//
|
||||
// The tls.Config must not be nil and must contain a certificate configuration.
|
||||
// Furthermore, it must define an application control (using NextProtos).
|
||||
// The quic.Config may be nil, in that case the default values will be used.
|
||||
//
|
||||
// This is a convenience function. More advanced use cases should instantiate a Transport,
|
||||
// which offers configuration options for a more fine-grained control of the connection establishment,
|
||||
// including reusing the underlying UDP socket for outgoing QUIC connections.
|
||||
// When closing a listener created with Listen, all established QUIC connections will be closed immediately.
|
||||
func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*Listener, error) {
|
||||
tr := &Transport{Conn: conn, isSingleUse: true}
|
||||
return tr.Listen(tlsConf, config)
|
||||
@@ -220,37 +236,43 @@ func newServer(
|
||||
connIDGenerator ConnectionIDGenerator,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
tracer logging.Tracer,
|
||||
tracer *logging.Tracer,
|
||||
onClose func(),
|
||||
tokenGeneratorKey TokenGeneratorKey,
|
||||
maxTokenAge time.Duration,
|
||||
disableVersionNegotiation bool,
|
||||
acceptEarly bool,
|
||||
) (*baseServer, error) {
|
||||
tokenGenerator, err := handshake.NewTokenGenerator(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
) *baseServer {
|
||||
s := &baseServer{
|
||||
conn: conn,
|
||||
tlsConf: tlsConf,
|
||||
config: config,
|
||||
tokenGenerator: tokenGenerator,
|
||||
connIDGenerator: connIDGenerator,
|
||||
connHandler: connHandler,
|
||||
connQueue: make(chan quicConn),
|
||||
errorChan: make(chan struct{}),
|
||||
running: make(chan struct{}),
|
||||
receivedPackets: make(chan *receivedPacket, protocol.MaxServerUnprocessedPackets),
|
||||
newConn: newConnection,
|
||||
tracer: tracer,
|
||||
logger: utils.DefaultLogger.WithPrefix("server"),
|
||||
acceptEarlyConns: acceptEarly,
|
||||
onClose: onClose,
|
||||
conn: conn,
|
||||
tlsConf: tlsConf,
|
||||
config: config,
|
||||
tokenGenerator: handshake.NewTokenGenerator(tokenGeneratorKey),
|
||||
maxTokenAge: maxTokenAge,
|
||||
connIDGenerator: connIDGenerator,
|
||||
connHandler: connHandler,
|
||||
connQueue: make(chan quicConn),
|
||||
errorChan: make(chan struct{}),
|
||||
running: make(chan struct{}),
|
||||
receivedPackets: make(chan receivedPacket, protocol.MaxServerUnprocessedPackets),
|
||||
versionNegotiationQueue: make(chan receivedPacket, 4),
|
||||
invalidTokenQueue: make(chan rejectedPacket, 4),
|
||||
connectionRefusedQueue: make(chan rejectedPacket, 4),
|
||||
retryQueue: make(chan rejectedPacket, 8),
|
||||
newConn: newConnection,
|
||||
tracer: tracer,
|
||||
logger: utils.DefaultLogger.WithPrefix("server"),
|
||||
acceptEarlyConns: acceptEarly,
|
||||
disableVersionNegotiation: disableVersionNegotiation,
|
||||
onClose: onClose,
|
||||
}
|
||||
if acceptEarly {
|
||||
s.zeroRTTQueues = map[protocol.ConnectionID]*zeroRTTQueue{}
|
||||
}
|
||||
go s.run()
|
||||
go s.runSendQueue()
|
||||
s.logger.Debugf("Listening for %s connections on %s", conn.LocalAddr().Network(), conn.LocalAddr().String())
|
||||
return s, nil
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *baseServer) run() {
|
||||
@@ -272,6 +294,23 @@ func (s *baseServer) run() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) runSendQueue() {
|
||||
for {
|
||||
select {
|
||||
case <-s.running:
|
||||
return
|
||||
case p := <-s.versionNegotiationQueue:
|
||||
s.maybeSendVersionNegotiationPacket(p)
|
||||
case p := <-s.invalidTokenQueue:
|
||||
s.maybeSendInvalidToken(p)
|
||||
case p := <-s.connectionRefusedQueue:
|
||||
s.sendConnectionRefused(p)
|
||||
case p := <-s.retryQueue:
|
||||
s.sendRetry(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accept returns connections that already completed the handshake.
|
||||
// It is only valid if acceptEarlyConns is false.
|
||||
func (s *baseServer) Accept(ctx context.Context) (Connection, error) {
|
||||
@@ -286,38 +325,25 @@ func (s *baseServer) accept(ctx context.Context) (quicConn, error) {
|
||||
atomic.AddInt32(&s.connQueueLen, -1)
|
||||
return conn, nil
|
||||
case <-s.errorChan:
|
||||
return nil, s.serverError
|
||||
return nil, s.closeErr
|
||||
}
|
||||
}
|
||||
|
||||
// Close the server
|
||||
func (s *baseServer) Close() error {
|
||||
s.mutex.Lock()
|
||||
if s.closed {
|
||||
s.mutex.Unlock()
|
||||
return nil
|
||||
}
|
||||
if s.serverError == nil {
|
||||
s.serverError = ErrServerClosed
|
||||
}
|
||||
s.closed = true
|
||||
close(s.errorChan)
|
||||
s.mutex.Unlock()
|
||||
|
||||
<-s.running
|
||||
s.onClose()
|
||||
s.close(ErrServerClosed, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *baseServer) setCloseError(e error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
if s.closed {
|
||||
return
|
||||
}
|
||||
s.closed = true
|
||||
s.serverError = e
|
||||
close(s.errorChan)
|
||||
func (s *baseServer) close(e error, notifyOnClose bool) {
|
||||
s.closeOnce.Do(func() {
|
||||
s.closeErr = e
|
||||
close(s.errorChan)
|
||||
|
||||
<-s.running
|
||||
if notifyOnClose {
|
||||
s.onClose()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Addr returns the server's network address
|
||||
@@ -325,25 +351,25 @@ func (s *baseServer) Addr() net.Addr {
|
||||
return s.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *baseServer) handlePacket(p *receivedPacket) {
|
||||
func (s *baseServer) handlePacket(p receivedPacket) {
|
||||
select {
|
||||
case s.receivedPackets <- p:
|
||||
default:
|
||||
s.logger.Debugf("Dropping packet from %s (%d bytes). Server receive queue full.", p.remoteAddr, p.Size())
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer still in use? */ {
|
||||
func (s *baseServer) handlePacketImpl(p receivedPacket) bool /* is the buffer still in use? */ {
|
||||
if !s.nextZeroRTTCleanup.IsZero() && p.rcvTime.After(s.nextZeroRTTCleanup) {
|
||||
defer s.cleanupZeroRTTQueues(p.rcvTime)
|
||||
}
|
||||
|
||||
if wire.IsVersionNegotiationPacket(p.data) {
|
||||
s.logger.Debugf("Dropping Version Negotiation packet.")
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeVersionNegotiation, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
@@ -353,32 +379,33 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
panic(fmt.Sprintf("misrouted packet: %#v", p.data))
|
||||
}
|
||||
v, err := wire.ParseVersion(p.data)
|
||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||
if err != nil || !protocol.IsSupportedVersion(s.config.Versions, v) {
|
||||
if err != nil || p.Size() < protocol.MinUnknownVersionPacketSize {
|
||||
s.logger.Debugf("Dropping a packet with an unknown version that is too small (%d bytes)", p.Size())
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
_, src, dest, err := wire.ParseArbitraryLenConnectionIDs(p.data)
|
||||
if err != nil { // should never happen
|
||||
s.logger.Debugf("Dropping a packet with an unknown version for which we failed to parse connection IDs")
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if !s.config.DisableVersionNegotiationPackets {
|
||||
go s.sendVersionNegotiationPacket(p.remoteAddr, src, dest, p.info.OOB(), v)
|
||||
// drop the packet if we failed to parse the protocol version
|
||||
if err != nil {
|
||||
s.logger.Debugf("Dropping a packet with an unknown version")
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||
if !protocol.IsSupportedVersion(s.config.Versions, v) {
|
||||
if s.disableVersionNegotiation {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Size() < protocol.MinUnknownVersionPacketSize {
|
||||
s.logger.Debugf("Dropping a packet with an unsupported version number %d that is too small (%d bytes)", v, p.Size())
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return s.enqueueVersionNegotiationPacket(p)
|
||||
}
|
||||
|
||||
if wire.Is0RTTPacket(p.data) {
|
||||
if !s.acceptEarlyConns {
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
@@ -390,7 +417,7 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
// The header will then be parsed again.
|
||||
hdr, _, _, err := wire.ParsePacket(p.data)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
s.logger.Debugf("Error parsing packet: %s", err)
|
||||
@@ -398,7 +425,7 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
}
|
||||
if hdr.Type == protocol.PacketTypeInitial && p.Size() < protocol.MinInitialPacketSize {
|
||||
s.logger.Debugf("Dropping a packet that is too small to be a valid Initial (%d bytes)", p.Size())
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
@@ -409,7 +436,7 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
// There's little point in sending a Stateless Reset, since the client
|
||||
// might not have received the token yet.
|
||||
s.logger.Debugf("Dropping long header packet of type %s (%d bytes)", hdr.Type, len(p.data))
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
@@ -425,10 +452,10 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *baseServer) handle0RTTPacket(p *receivedPacket) bool {
|
||||
func (s *baseServer) handle0RTTPacket(p receivedPacket) bool {
|
||||
connID, err := wire.ParseConnectionID(p.data, 0)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
return false
|
||||
@@ -442,7 +469,7 @@ func (s *baseServer) handle0RTTPacket(p *receivedPacket) bool {
|
||||
|
||||
if q, ok := s.zeroRTTQueues[connID]; ok {
|
||||
if len(q.packets) >= protocol.Max0RTTQueueLen {
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
return false
|
||||
@@ -452,12 +479,12 @@ func (s *baseServer) handle0RTTPacket(p *receivedPacket) bool {
|
||||
}
|
||||
|
||||
if len(s.zeroRTTQueues) >= protocol.Max0RTTQueues {
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
return false
|
||||
}
|
||||
queue := &zeroRTTQueue{packets: make([]*receivedPacket, 1, 8)}
|
||||
queue := &zeroRTTQueue{packets: make([]receivedPacket, 1, 8)}
|
||||
queue.packets[0] = p
|
||||
expiration := p.rcvTime.Add(protocol.Max0RTTQueueingDuration)
|
||||
queue.expiration = expiration
|
||||
@@ -480,7 +507,7 @@ func (s *baseServer) cleanupZeroRTTQueues(now time.Time) {
|
||||
continue
|
||||
}
|
||||
for _, p := range q.packets {
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
p.buffer.Release()
|
||||
@@ -504,19 +531,19 @@ func (s *baseServer) validateToken(token *handshake.Token, addr net.Addr) bool {
|
||||
if !token.ValidateRemoteAddr(addr) {
|
||||
return false
|
||||
}
|
||||
if !token.IsRetryToken && time.Since(token.SentTime) > s.config.MaxTokenAge {
|
||||
if !token.IsRetryToken && time.Since(token.SentTime) > s.maxTokenAge {
|
||||
return false
|
||||
}
|
||||
if token.IsRetryToken && time.Since(token.SentTime) > s.config.MaxRetryTokenAge {
|
||||
if token.IsRetryToken && time.Since(token.SentTime) > s.config.maxRetryTokenAge() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) error {
|
||||
func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error {
|
||||
if len(hdr.Token) == 0 && hdr.DestConnectionID.Len() < protocol.MinConnectionIDLenInitial {
|
||||
p.buffer.Release()
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return errors.New("too short connection ID")
|
||||
@@ -557,35 +584,35 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
// For Retry tokens, we send an INVALID_ERROR if
|
||||
// * the token is too old, or
|
||||
// * the token is invalid, in case of a retry token.
|
||||
go func() {
|
||||
defer p.buffer.Release()
|
||||
if err := s.maybeSendInvalidToken(p, hdr); err != nil {
|
||||
s.logger.Debugf("Error sending INVALID_TOKEN error: %s", err)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case s.invalidTokenQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
|
||||
default:
|
||||
// drop packet if we can't send out the INVALID_TOKEN packets fast enough
|
||||
p.buffer.Release()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if token == nil && s.config.RequireAddressValidation(p.remoteAddr) {
|
||||
// Retry invalidates all 0-RTT packets sent.
|
||||
delete(s.zeroRTTQueues, hdr.DestConnectionID)
|
||||
go func() {
|
||||
defer p.buffer.Release()
|
||||
if err := s.sendRetry(p.remoteAddr, hdr, p.info); err != nil {
|
||||
s.logger.Debugf("Error sending Retry: %s", err)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case s.retryQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
|
||||
default:
|
||||
// drop packet if we can't send out Retry packets fast enough
|
||||
p.buffer.Release()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if queueLen := atomic.LoadInt32(&s.connQueueLen); queueLen >= protocol.MaxAcceptQueueSize {
|
||||
s.logger.Debugf("Rejecting new connection. Server currently busy. Accept queue length: %d (max %d)", queueLen, protocol.MaxAcceptQueueSize)
|
||||
go func() {
|
||||
defer p.buffer.Release()
|
||||
if err := s.sendConnectionRefused(p.remoteAddr, hdr, p.info); err != nil {
|
||||
s.logger.Debugf("Error rejecting connection: %s", err)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case s.connectionRefusedQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
|
||||
default:
|
||||
// drop packet if we can't send out the CONNECTION_REFUSED fast enough
|
||||
p.buffer.Release()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -606,7 +633,7 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
}
|
||||
config = populateConfig(conf)
|
||||
}
|
||||
var tracer logging.ConnectionTracer
|
||||
var tracer *logging.ConnectionTracer
|
||||
if config.Tracer != nil {
|
||||
// Use the same connection ID that is passed to the client's GetLogWriter callback.
|
||||
connID := hdr.DestConnectionID
|
||||
@@ -616,7 +643,7 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
tracer = config.Tracer(context.WithValue(context.Background(), ConnectionTracingKey, tracingID), protocol.PerspectiveServer, connID)
|
||||
}
|
||||
conn = s.newConn(
|
||||
newSendConn(s.conn, p.remoteAddr, p.info),
|
||||
newSendConn(s.conn, p.remoteAddr, p.info, s.logger),
|
||||
s.connHandler,
|
||||
origDestConnID,
|
||||
retrySrcConnID,
|
||||
@@ -645,12 +672,12 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
|
||||
return conn, true
|
||||
}); !added {
|
||||
go func() {
|
||||
defer p.buffer.Release()
|
||||
if err := s.sendConnectionRefused(p.remoteAddr, hdr, p.info); err != nil {
|
||||
s.logger.Debugf("Error rejecting connection: %s", err)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case s.connectionRefusedQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
|
||||
default:
|
||||
// drop packet if we can't send out the CONNECTION_REFUSED fast enough
|
||||
p.buffer.Release()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
go conn.run()
|
||||
@@ -665,8 +692,11 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
func (s *baseServer) handleNewConn(conn quicConn) {
|
||||
connCtx := conn.Context()
|
||||
if s.acceptEarlyConns {
|
||||
// wait until the early connection is ready (or the handshake fails)
|
||||
// wait until the early connection is ready, the handshake fails, or the server is closed
|
||||
select {
|
||||
case <-s.errorChan:
|
||||
conn.destroy(&qerr.TransportError{ErrorCode: ConnectionRefused})
|
||||
return
|
||||
case <-conn.earlyConnReady():
|
||||
case <-connCtx.Done():
|
||||
return
|
||||
@@ -674,6 +704,9 @@ func (s *baseServer) handleNewConn(conn quicConn) {
|
||||
} else {
|
||||
// wait until the handshake is complete (or fails)
|
||||
select {
|
||||
case <-s.errorChan:
|
||||
conn.destroy(&qerr.TransportError{ErrorCode: ConnectionRefused})
|
||||
return
|
||||
case <-conn.HandshakeComplete():
|
||||
case <-connCtx.Done():
|
||||
return
|
||||
@@ -690,7 +723,14 @@ func (s *baseServer) handleNewConn(conn quicConn) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info *packetInfo) error {
|
||||
func (s *baseServer) sendRetry(p rejectedPacket) {
|
||||
if err := s.sendRetryPacket(p); err != nil {
|
||||
s.logger.Debugf("Error sending Retry packet: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) sendRetryPacket(p rejectedPacket) error {
|
||||
hdr := p.hdr
|
||||
// Log the Initial packet now.
|
||||
// If no Retry is sent, the packet will be logged by the connection.
|
||||
(&wire.ExtendedHeader{Header: *hdr}).Log(s.logger)
|
||||
@@ -698,7 +738,7 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info *pack
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
token, err := s.tokenGenerator.NewRetryToken(remoteAddr, hdr.DestConnectionID, srcConnID)
|
||||
token, err := s.tokenGenerator.NewRetryToken(p.remoteAddr, hdr.DestConnectionID, srcConnID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -723,47 +763,55 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info *pack
|
||||
// append the Retry integrity tag
|
||||
tag := handshake.GetRetryIntegrityTag(buf.Data, hdr.DestConnectionID, hdr.Version)
|
||||
buf.Data = append(buf.Data, tag[:]...)
|
||||
if s.tracer != nil {
|
||||
s.tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(buf.Data)), nil)
|
||||
if s.tracer != nil && s.tracer.SentPacket != nil {
|
||||
s.tracer.SentPacket(p.remoteAddr, &replyHdr.Header, protocol.ByteCount(len(buf.Data)), nil)
|
||||
}
|
||||
_, err = s.conn.WritePacket(buf.Data, remoteAddr, info.OOB())
|
||||
_, err = s.conn.WritePacket(buf.Data, p.remoteAddr, p.info.OOB(), 0, protocol.ECNUnsupported)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *baseServer) maybeSendInvalidToken(p *receivedPacket, hdr *wire.Header) error {
|
||||
func (s *baseServer) maybeSendInvalidToken(p rejectedPacket) {
|
||||
defer p.buffer.Release()
|
||||
|
||||
// Only send INVALID_TOKEN if we can unprotect the packet.
|
||||
// This makes sure that we won't send it for packets that were corrupted.
|
||||
hdr := p.hdr
|
||||
sealer, opener := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version)
|
||||
data := p.data[:hdr.ParsedLen()+hdr.Length]
|
||||
extHdr, err := unpackLongHeader(opener, hdr, data, hdr.Version)
|
||||
// Only send INVALID_TOKEN if we can unprotect the packet.
|
||||
// This makes sure that we won't send it for packets that were corrupted.
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
// don't return the error here. Just drop the packet.
|
||||
return nil
|
||||
return
|
||||
}
|
||||
hdrLen := extHdr.ParsedLen()
|
||||
if _, err := opener.Open(data[hdrLen:hdrLen], data[hdrLen:], extHdr.PacketNumber, data[:hdrLen]); err != nil {
|
||||
// don't return the error here. Just drop the packet.
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropPayloadDecryptError)
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
if s.logger.Debug() {
|
||||
s.logger.Debugf("Client sent an invalid retry token. Sending INVALID_TOKEN to %s.", p.remoteAddr)
|
||||
}
|
||||
return s.sendError(p.remoteAddr, hdr, sealer, qerr.InvalidToken, p.info)
|
||||
if err := s.sendError(p.remoteAddr, hdr, sealer, qerr.InvalidToken, p.info); err != nil {
|
||||
s.logger.Debugf("Error sending INVALID_TOKEN error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) sendConnectionRefused(remoteAddr net.Addr, hdr *wire.Header, info *packetInfo) error {
|
||||
sealer, _ := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version)
|
||||
return s.sendError(remoteAddr, hdr, sealer, qerr.ConnectionRefused, info)
|
||||
func (s *baseServer) sendConnectionRefused(p rejectedPacket) {
|
||||
defer p.buffer.Release()
|
||||
sealer, _ := handshake.NewInitialAEAD(p.hdr.DestConnectionID, protocol.PerspectiveServer, p.hdr.Version)
|
||||
if err := s.sendError(p.remoteAddr, p.hdr, sealer, qerr.ConnectionRefused, p.info); err != nil {
|
||||
s.logger.Debugf("Error sending CONNECTION_REFUSED error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// sendError sends the error as a response to the packet received with header hdr
|
||||
func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer handshake.LongHeaderSealer, errorCode qerr.TransportErrorCode, info *packetInfo) error {
|
||||
func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer handshake.LongHeaderSealer, errorCode qerr.TransportErrorCode, info packetInfo) error {
|
||||
b := getPacketBuffer()
|
||||
defer b.Release()
|
||||
|
||||
@@ -800,21 +848,48 @@ func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer han
|
||||
|
||||
replyHdr.Log(s.logger)
|
||||
wire.LogFrame(s.logger, ccf, true)
|
||||
if s.tracer != nil {
|
||||
if s.tracer != nil && s.tracer.SentPacket != nil {
|
||||
s.tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(b.Data)), []logging.Frame{ccf})
|
||||
}
|
||||
_, err = s.conn.WritePacket(b.Data, remoteAddr, info.OOB())
|
||||
_, err = s.conn.WritePacket(b.Data, remoteAddr, info.OOB(), 0, protocol.ECNUnsupported)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *baseServer) sendVersionNegotiationPacket(remote net.Addr, src, dest protocol.ArbitraryLenConnectionID, oob []byte, v protocol.VersionNumber) {
|
||||
func (s *baseServer) enqueueVersionNegotiationPacket(p receivedPacket) (bufferInUse bool) {
|
||||
select {
|
||||
case s.versionNegotiationQueue <- p:
|
||||
return true
|
||||
default:
|
||||
// it's fine to not send version negotiation packets when we are busy
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *baseServer) maybeSendVersionNegotiationPacket(p receivedPacket) {
|
||||
defer p.buffer.Release()
|
||||
|
||||
v, err := wire.ParseVersion(p.data)
|
||||
if err != nil {
|
||||
s.logger.Debugf("failed to parse version for sending version negotiation packet: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, src, dest, err := wire.ParseArbitraryLenConnectionIDs(p.data)
|
||||
if err != nil { // should never happen
|
||||
s.logger.Debugf("Dropping a packet with an unknown version for which we failed to parse connection IDs")
|
||||
if s.tracer != nil && s.tracer.DroppedPacket != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Debugf("Client offered version %s, sending Version Negotiation", v)
|
||||
|
||||
data := wire.ComposeVersionNegotiation(dest, src, s.config.Versions)
|
||||
if s.tracer != nil {
|
||||
s.tracer.SentVersionNegotiationPacket(remote, src, dest, s.config.Versions)
|
||||
if s.tracer != nil && s.tracer.SentVersionNegotiationPacket != nil {
|
||||
s.tracer.SentVersionNegotiationPacket(p.remoteAddr, src, dest, s.config.Versions)
|
||||
}
|
||||
if _, err := s.conn.WritePacket(data, remote, oob); err != nil {
|
||||
if _, err := s.conn.WritePacket(data, p.remoteAddr, p.info.OOB(), 0, protocol.ECNUnsupported); err != nil {
|
||||
s.logger.Debugf("Error sending Version Negotiation: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/stream.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/stream.go
generated
vendored
@@ -60,7 +60,7 @@ type streamI interface {
|
||||
// for sending
|
||||
hasData() bool
|
||||
handleStopSendingFrame(*wire.StopSendingFrame)
|
||||
popStreamFrame(maxBytes protocol.ByteCount, v protocol.VersionNumber) (*ackhandler.Frame, bool)
|
||||
popStreamFrame(maxBytes protocol.ByteCount, v protocol.VersionNumber) (ackhandler.StreamFrame, bool, bool)
|
||||
updateSendWindow(protocol.ByteCount)
|
||||
}
|
||||
|
||||
|
||||
53
vendor/github.com/quic-go/quic-go/sys_conn.go
generated
vendored
53
vendor/github.com/quic-go/quic-go/sys_conn.go
generated
vendored
@@ -1,7 +1,11 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -15,6 +19,7 @@ import (
|
||||
type OOBCapablePacketConn interface {
|
||||
net.PacketConn
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
SetReadBuffer(int) error
|
||||
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
|
||||
WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
|
||||
}
|
||||
@@ -22,9 +27,31 @@ type OOBCapablePacketConn interface {
|
||||
var _ OOBCapablePacketConn = &net.UDPConn{}
|
||||
|
||||
func wrapConn(pc net.PacketConn) (rawConn, error) {
|
||||
if err := setReceiveBuffer(pc); err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
setBufferWarningOnce.Do(func() {
|
||||
if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
|
||||
return
|
||||
}
|
||||
log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
if err := setSendBuffer(pc); err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
setBufferWarningOnce.Do(func() {
|
||||
if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
|
||||
return
|
||||
}
|
||||
log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
conn, ok := pc.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
})
|
||||
var supportsDF bool
|
||||
if ok {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
@@ -33,7 +60,8 @@ func wrapConn(pc net.PacketConn) (rawConn, error) {
|
||||
|
||||
if _, ok := pc.LocalAddr().(*net.UDPAddr); ok {
|
||||
// Only set DF on sockets that we expect to be able to handle that configuration.
|
||||
err = setDF(rawConn)
|
||||
var err error
|
||||
supportsDF, err = setDF(rawConn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,32 +70,33 @@ func wrapConn(pc net.PacketConn) (rawConn, error) {
|
||||
c, ok := pc.(OOBCapablePacketConn)
|
||||
if !ok {
|
||||
utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.")
|
||||
return &basicConn{PacketConn: pc}, nil
|
||||
return &basicConn{PacketConn: pc, supportsDF: supportsDF}, nil
|
||||
}
|
||||
return newConn(c)
|
||||
return newConn(c, supportsDF)
|
||||
}
|
||||
|
||||
// The basicConn is the most trivial implementation of a connection.
|
||||
// The basicConn is the most trivial implementation of a rawConn.
|
||||
// It reads a single packet from the underlying net.PacketConn.
|
||||
// It is used when
|
||||
// * the net.PacketConn is not a OOBCapablePacketConn, and
|
||||
// * when the OS doesn't support OOB.
|
||||
type basicConn struct {
|
||||
net.PacketConn
|
||||
supportsDF bool
|
||||
}
|
||||
|
||||
var _ rawConn = &basicConn{}
|
||||
|
||||
func (c *basicConn) ReadPacket() (*receivedPacket, error) {
|
||||
func (c *basicConn) ReadPacket() (receivedPacket, error) {
|
||||
buffer := getPacketBuffer()
|
||||
// The packet size should not exceed protocol.MaxPacketBufferSize bytes
|
||||
// If it does, we only read a truncated packet, which will then end up undecryptable
|
||||
buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
|
||||
n, addr, err := c.PacketConn.ReadFrom(buffer.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return receivedPacket{}, err
|
||||
}
|
||||
return &receivedPacket{
|
||||
return receivedPacket{
|
||||
remoteAddr: addr,
|
||||
rcvTime: time.Now(),
|
||||
data: buffer.Data[:n],
|
||||
@@ -75,6 +104,14 @@ func (c *basicConn) ReadPacket() (*receivedPacket, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte) (n int, err error) {
|
||||
func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte, gsoSize uint16, ecn protocol.ECN) (n int, err error) {
|
||||
if gsoSize != 0 {
|
||||
panic("cannot use GSO with a basicConn")
|
||||
}
|
||||
if ecn != protocol.ECNUnsupported {
|
||||
panic("cannot use ECN with a basicConn")
|
||||
}
|
||||
return c.PacketConn.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} }
|
||||
|
||||
68
vendor/github.com/quic-go/quic-go/sys_conn_buffers.go
generated
vendored
Normal file
68
vendor/github.com/quic-go/quic-go/sys_conn_buffers.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
//go:generate sh -c "echo '// Code generated by go generate. DO NOT EDIT.\n// Source: sys_conn_buffers.go\n' > sys_conn_buffers_write.go && sed -e 's/SetReadBuffer/SetWriteBuffer/g' -e 's/setReceiveBuffer/setSendBuffer/g' -e 's/inspectReadBuffer/inspectWriteBuffer/g' -e 's/protocol\\.DesiredReceiveBufferSize/protocol\\.DesiredSendBufferSize/g' -e 's/forceSetReceiveBuffer/forceSetSendBuffer/g' -e 's/receive buffer/send buffer/g' sys_conn_buffers.go | sed '/^\\/\\/go:generate/d' >> sys_conn_buffers_write.go"
|
||||
func setReceiveBuffer(c net.PacketConn) error {
|
||||
conn, ok := c.(interface{ SetReadBuffer(int) error })
|
||||
if !ok {
|
||||
return errors.New("connection doesn't allow setting of receive buffer size. Not a *net.UDPConn?")
|
||||
}
|
||||
|
||||
var syscallConn syscall.RawConn
|
||||
if sc, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
}); ok {
|
||||
var err error
|
||||
syscallConn, err = sc.SyscallConn()
|
||||
if err != nil {
|
||||
syscallConn = nil
|
||||
}
|
||||
}
|
||||
// The connection has a SetReadBuffer method, but we couldn't obtain a syscall.RawConn.
|
||||
// This shouldn't happen for a net.UDPConn, but is possible if the connection just implements the
|
||||
// net.PacketConn interface and the SetReadBuffer method.
|
||||
// We have no way of checking if increasing the buffer size actually worked.
|
||||
if syscallConn == nil {
|
||||
return conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
|
||||
}
|
||||
|
||||
size, err := inspectReadBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
if size >= protocol.DesiredReceiveBufferSize {
|
||||
utils.DefaultLogger.Debugf("Conn has receive buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024)
|
||||
return nil
|
||||
}
|
||||
// Ignore the error. We check if we succeeded by querying the buffer size afterward.
|
||||
_ = conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
|
||||
newSize, err := inspectReadBuffer(syscallConn)
|
||||
if newSize < protocol.DesiredReceiveBufferSize {
|
||||
// Try again with RCVBUFFORCE on Linux
|
||||
_ = forceSetReceiveBuffer(syscallConn, protocol.DesiredReceiveBufferSize)
|
||||
newSize, err = inspectReadBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
if newSize == size {
|
||||
return fmt.Errorf("failed to increase receive buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredReceiveBufferSize/1024, newSize/1024)
|
||||
}
|
||||
if newSize < protocol.DesiredReceiveBufferSize {
|
||||
return fmt.Errorf("failed to sufficiently increase receive buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024, newSize/1024)
|
||||
}
|
||||
utils.DefaultLogger.Debugf("Increased receive buffer size to %d kiB", newSize/1024)
|
||||
return nil
|
||||
}
|
||||
70
vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go
generated
vendored
Normal file
70
vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// Code generated by go generate. DO NOT EDIT.
|
||||
// Source: sys_conn_buffers.go
|
||||
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
func setSendBuffer(c net.PacketConn) error {
|
||||
conn, ok := c.(interface{ SetWriteBuffer(int) error })
|
||||
if !ok {
|
||||
return errors.New("connection doesn't allow setting of send buffer size. Not a *net.UDPConn?")
|
||||
}
|
||||
|
||||
var syscallConn syscall.RawConn
|
||||
if sc, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
}); ok {
|
||||
var err error
|
||||
syscallConn, err = sc.SyscallConn()
|
||||
if err != nil {
|
||||
syscallConn = nil
|
||||
}
|
||||
}
|
||||
// The connection has a SetWriteBuffer method, but we couldn't obtain a syscall.RawConn.
|
||||
// This shouldn't happen for a net.UDPConn, but is possible if the connection just implements the
|
||||
// net.PacketConn interface and the SetWriteBuffer method.
|
||||
// We have no way of checking if increasing the buffer size actually worked.
|
||||
if syscallConn == nil {
|
||||
return conn.SetWriteBuffer(protocol.DesiredSendBufferSize)
|
||||
}
|
||||
|
||||
size, err := inspectWriteBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine send buffer size: %w", err)
|
||||
}
|
||||
if size >= protocol.DesiredSendBufferSize {
|
||||
utils.DefaultLogger.Debugf("Conn has send buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredSendBufferSize/1024)
|
||||
return nil
|
||||
}
|
||||
// Ignore the error. We check if we succeeded by querying the buffer size afterward.
|
||||
_ = conn.SetWriteBuffer(protocol.DesiredSendBufferSize)
|
||||
newSize, err := inspectWriteBuffer(syscallConn)
|
||||
if newSize < protocol.DesiredSendBufferSize {
|
||||
// Try again with RCVBUFFORCE on Linux
|
||||
_ = forceSetSendBuffer(syscallConn, protocol.DesiredSendBufferSize)
|
||||
newSize, err = inspectWriteBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine send buffer size: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine send buffer size: %w", err)
|
||||
}
|
||||
if newSize == size {
|
||||
return fmt.Errorf("failed to increase send buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredSendBufferSize/1024, newSize/1024)
|
||||
}
|
||||
if newSize < protocol.DesiredSendBufferSize {
|
||||
return fmt.Errorf("failed to sufficiently increase send buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredSendBufferSize/1024, newSize/1024)
|
||||
}
|
||||
utils.DefaultLogger.Debugf("Increased send buffer size to %d kiB", newSize/1024)
|
||||
return nil
|
||||
}
|
||||
17
vendor/github.com/quic-go/quic-go/sys_conn_df.go
generated
vendored
17
vendor/github.com/quic-go/quic-go/sys_conn_df.go
generated
vendored
@@ -1,15 +1,22 @@
|
||||
//go:build !linux && !windows
|
||||
//go:build !linux && !windows && !darwin
|
||||
|
||||
package quic
|
||||
|
||||
import "syscall"
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func setDF(rawConn syscall.RawConn) error {
|
||||
func setDF(syscall.RawConn) (bool, error) {
|
||||
// no-op on unsupported platforms
|
||||
return nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func isMsgSizeErr(err error) bool {
|
||||
func isSendMsgSizeErr(err error) bool {
|
||||
// to be implemented for more specific platforms
|
||||
return false
|
||||
}
|
||||
|
||||
func isRecvMsgSizeErr(err error) bool {
|
||||
// to be implemented for more specific platforms
|
||||
return false
|
||||
}
|
||||
|
||||
74
vendor/github.com/quic-go/quic-go/sys_conn_df_darwin.go
generated
vendored
Normal file
74
vendor/github.com/quic-go/quic-go/sys_conn_df_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
//go:build darwin
|
||||
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
func setDF(rawConn syscall.RawConn) (bool, error) {
|
||||
// Setting DF bit is only supported from macOS11
|
||||
// https://github.com/chromium/chromium/blob/117.0.5881.2/net/socket/udp_socket_posix.cc#L555
|
||||
if supportsDF, err := isAtLeastMacOS11(); !supportsDF || err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Enabling IP_DONTFRAG will force the kernel to return "sendto: message too long"
|
||||
// and the datagram will not be fragmented
|
||||
var errDFIPv4, errDFIPv6 error
|
||||
if err := rawConn.Control(func(fd uintptr) {
|
||||
errDFIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_DONTFRAG, 1)
|
||||
errDFIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_DONTFRAG, 1)
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch {
|
||||
case errDFIPv4 == nil && errDFIPv6 == nil:
|
||||
utils.DefaultLogger.Debugf("Setting DF for IPv4 and IPv6.")
|
||||
case errDFIPv4 == nil && errDFIPv6 != nil:
|
||||
utils.DefaultLogger.Debugf("Setting DF for IPv4.")
|
||||
case errDFIPv4 != nil && errDFIPv6 == nil:
|
||||
utils.DefaultLogger.Debugf("Setting DF for IPv6.")
|
||||
// On macOS, the syscall for setting DF bit for IPv4 fails on dual-stack listeners.
|
||||
// Treat the connection as not having DF enabled, even though the DF bit will be set
|
||||
// when used for IPv6.
|
||||
// See https://github.com/quic-go/quic-go/issues/3793 for details.
|
||||
return false, nil
|
||||
case errDFIPv4 != nil && errDFIPv6 != nil:
|
||||
return false, errors.New("setting DF failed for both IPv4 and IPv6")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func isSendMsgSizeErr(err error) bool {
|
||||
return errors.Is(err, unix.EMSGSIZE)
|
||||
}
|
||||
|
||||
func isRecvMsgSizeErr(error) bool { return false }
|
||||
|
||||
func isAtLeastMacOS11() (bool, error) {
|
||||
uname := &unix.Utsname{}
|
||||
err := unix.Uname(uname)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
release := string(uname.Release[:])
|
||||
if idx := strings.Index(release, "."); idx != -1 {
|
||||
version, err := strconv.Atoi(release[:idx])
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Darwin version 20 is macOS version 11
|
||||
// https://en.wikipedia.org/wiki/Darwin_(operating_system)#Darwin_20_onwards
|
||||
return version >= 20, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
12
vendor/github.com/quic-go/quic-go/sys_conn_df_linux.go
generated
vendored
12
vendor/github.com/quic-go/quic-go/sys_conn_df_linux.go
generated
vendored
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
func setDF(rawConn syscall.RawConn) error {
|
||||
func setDF(rawConn syscall.RawConn) (bool, error) {
|
||||
// Enabling IP_MTU_DISCOVER will force the kernel to return "sendto: message too long"
|
||||
// and the datagram will not be fragmented
|
||||
var errDFIPv4, errDFIPv6 error
|
||||
@@ -19,7 +19,7 @@ func setDF(rawConn syscall.RawConn) error {
|
||||
errDFIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_MTU_DISCOVER, unix.IP_PMTUDISC_DO)
|
||||
errDFIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_MTU_DISCOVER, unix.IPV6_PMTUDISC_DO)
|
||||
}); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
switch {
|
||||
case errDFIPv4 == nil && errDFIPv6 == nil:
|
||||
@@ -29,12 +29,14 @@ func setDF(rawConn syscall.RawConn) error {
|
||||
case errDFIPv4 != nil && errDFIPv6 == nil:
|
||||
utils.DefaultLogger.Debugf("Setting DF for IPv6.")
|
||||
case errDFIPv4 != nil && errDFIPv6 != nil:
|
||||
return errors.New("setting DF failed for both IPv4 and IPv6")
|
||||
return false, errors.New("setting DF failed for both IPv4 and IPv6")
|
||||
}
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func isMsgSizeErr(err error) bool {
|
||||
func isSendMsgSizeErr(err error) bool {
|
||||
// https://man7.org/linux/man-pages/man7/udp.7.html
|
||||
return errors.Is(err, unix.EMSGSIZE)
|
||||
}
|
||||
|
||||
func isRecvMsgSizeErr(error) bool { return false }
|
||||
|
||||
24
vendor/github.com/quic-go/quic-go/sys_conn_df_windows.go
generated
vendored
24
vendor/github.com/quic-go/quic-go/sys_conn_df_windows.go
generated
vendored
@@ -12,20 +12,23 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// same for both IPv4 and IPv6 on Windows
|
||||
// IP_DONTFRAGMENT controls the Don't Fragment (DF) bit.
|
||||
//
|
||||
// It's the same code point for both IPv4 and IPv6 on Windows.
|
||||
// https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinSock/constant.IP_DONTFRAG.html
|
||||
// https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinSock/constant.IPV6_DONTFRAG.html
|
||||
//
|
||||
//nolint:stylecheck
|
||||
IP_DONTFRAGMENT = 14
|
||||
IPV6_DONTFRAG = 14
|
||||
)
|
||||
|
||||
func setDF(rawConn syscall.RawConn) error {
|
||||
func setDF(rawConn syscall.RawConn) (bool, error) {
|
||||
var errDFIPv4, errDFIPv6 error
|
||||
if err := rawConn.Control(func(fd uintptr) {
|
||||
errDFIPv4 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, IP_DONTFRAGMENT, 1)
|
||||
errDFIPv6 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, IPV6_DONTFRAG, 1)
|
||||
errDFIPv6 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, IP_DONTFRAGMENT, 1)
|
||||
}); err != nil {
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
switch {
|
||||
case errDFIPv4 == nil && errDFIPv6 == nil:
|
||||
@@ -35,12 +38,17 @@ func setDF(rawConn syscall.RawConn) error {
|
||||
case errDFIPv4 != nil && errDFIPv6 == nil:
|
||||
utils.DefaultLogger.Debugf("Setting DF for IPv6.")
|
||||
case errDFIPv4 != nil && errDFIPv6 != nil:
|
||||
return errors.New("setting DF failed for both IPv4 and IPv6")
|
||||
return false, errors.New("setting DF failed for both IPv4 and IPv6")
|
||||
}
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func isMsgSizeErr(err error) bool {
|
||||
func isSendMsgSizeErr(err error) bool {
|
||||
// https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
|
||||
return errors.Is(err, windows.WSAEMSGSIZE)
|
||||
}
|
||||
|
||||
func isRecvMsgSizeErr(err error) bool {
|
||||
// https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
|
||||
return errors.Is(err, windows.WSAEMSGSIZE)
|
||||
}
|
||||
|
||||
31
vendor/github.com/quic-go/quic-go/sys_conn_helper_darwin.go
generated
vendored
31
vendor/github.com/quic-go/quic-go/sys_conn_helper_darwin.go
generated
vendored
@@ -2,20 +2,35 @@
|
||||
|
||||
package quic
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
const msgTypeIPTOS = unix.IP_RECVTOS
|
||||
|
||||
const (
|
||||
ipv4RECVPKTINFO = unix.IP_RECVPKTINFO
|
||||
ipv6RECVPKTINFO = 0x3d
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
msgTypeIPv4PKTINFO = unix.IP_PKTINFO
|
||||
msgTypeIPv6PKTINFO = 0x2e
|
||||
msgTypeIPTOS = unix.IP_RECVTOS
|
||||
ipv4PKTINFO = unix.IP_RECVPKTINFO
|
||||
)
|
||||
|
||||
const ecnIPv4DataLen = 4
|
||||
|
||||
// ReadBatch only returns a single packet on OSX,
|
||||
// see https://godoc.org/golang.org/x/net/ipv4#PacketConn.ReadBatch.
|
||||
const batchSize = 1
|
||||
|
||||
func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) {
|
||||
// struct in_pktinfo {
|
||||
// unsigned int ipi_ifindex; /* Interface index */
|
||||
// struct in_addr ipi_spec_dst; /* Local address */
|
||||
// struct in_addr ipi_addr; /* Header Destination address */
|
||||
// };
|
||||
if len(body) != 12 {
|
||||
return netip.Addr{}, 0, false
|
||||
}
|
||||
return netip.AddrFrom4(*(*[4]byte)(body[8:12])), binary.LittleEndian.Uint32(body), true
|
||||
}
|
||||
|
||||
func isGSOSupported(syscall.RawConn) bool { return false }
|
||||
|
||||
30
vendor/github.com/quic-go/quic-go/sys_conn_helper_freebsd.go
generated
vendored
30
vendor/github.com/quic-go/quic-go/sys_conn_helper_freebsd.go
generated
vendored
@@ -2,20 +2,30 @@
|
||||
|
||||
package quic
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
msgTypeIPTOS = unix.IP_RECVTOS
|
||||
ipv4PKTINFO = 0x7
|
||||
)
|
||||
|
||||
const (
|
||||
ipv4RECVPKTINFO = 0x7
|
||||
ipv6RECVPKTINFO = 0x24
|
||||
)
|
||||
|
||||
const (
|
||||
msgTypeIPv4PKTINFO = 0x7
|
||||
msgTypeIPv6PKTINFO = 0x2e
|
||||
)
|
||||
const ecnIPv4DataLen = 1
|
||||
|
||||
const batchSize = 8
|
||||
|
||||
func parseIPv4PktInfo(body []byte) (ip netip.Addr, _ uint32, ok bool) {
|
||||
// struct in_pktinfo {
|
||||
// struct in_addr ipi_addr; /* Header Destination address */
|
||||
// };
|
||||
if len(body) != 4 {
|
||||
return netip.Addr{}, 0, false
|
||||
}
|
||||
return netip.AddrFrom4(*(*[4]byte)(body)), 0, true
|
||||
}
|
||||
|
||||
func isGSOSupported(syscall.RawConn) bool { return false }
|
||||
|
||||
107
vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go
generated
vendored
107
vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go
generated
vendored
@@ -2,18 +2,109 @@
|
||||
|
||||
package quic
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
const msgTypeIPTOS = unix.IP_TOS
|
||||
|
||||
const (
|
||||
ipv4RECVPKTINFO = unix.IP_PKTINFO
|
||||
ipv6RECVPKTINFO = unix.IPV6_RECVPKTINFO
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
msgTypeIPv4PKTINFO = unix.IP_PKTINFO
|
||||
msgTypeIPv6PKTINFO = unix.IPV6_PKTINFO
|
||||
msgTypeIPTOS = unix.IP_TOS
|
||||
ipv4PKTINFO = unix.IP_PKTINFO
|
||||
)
|
||||
|
||||
const ecnIPv4DataLen = 1
|
||||
|
||||
const batchSize = 8 // needs to smaller than MaxUint8 (otherwise the type of oobConn.readPos has to be changed)
|
||||
|
||||
func forceSetReceiveBuffer(c syscall.RawConn, bytes int) error {
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
serr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, bytes)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return serr
|
||||
}
|
||||
|
||||
func forceSetSendBuffer(c syscall.RawConn, bytes int) error {
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
serr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, bytes)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return serr
|
||||
}
|
||||
|
||||
func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) {
|
||||
// struct in_pktinfo {
|
||||
// unsigned int ipi_ifindex; /* Interface index */
|
||||
// struct in_addr ipi_spec_dst; /* Local address */
|
||||
// struct in_addr ipi_addr; /* Header Destination address */
|
||||
// };
|
||||
if len(body) != 12 {
|
||||
return netip.Addr{}, 0, false
|
||||
}
|
||||
return netip.AddrFrom4(*(*[4]byte)(body[8:12])), binary.LittleEndian.Uint32(body), true
|
||||
}
|
||||
|
||||
// isGSOSupported tests if the kernel supports GSO.
|
||||
// Sending with GSO might still fail later on, if the interface doesn't support it (see isGSOError).
|
||||
func isGSOSupported(conn syscall.RawConn) bool {
|
||||
disabled, err := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_GSO"))
|
||||
if err == nil && disabled {
|
||||
return false
|
||||
}
|
||||
var serr error
|
||||
if err := conn.Control(func(fd uintptr) {
|
||||
_, serr = unix.GetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_SEGMENT)
|
||||
}); err != nil {
|
||||
return false
|
||||
}
|
||||
return serr == nil
|
||||
}
|
||||
|
||||
func appendUDPSegmentSizeMsg(b []byte, size uint16) []byte {
|
||||
startLen := len(b)
|
||||
const dataLen = 2 // payload is a uint16
|
||||
b = append(b, make([]byte, unix.CmsgSpace(dataLen))...)
|
||||
h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen]))
|
||||
h.Level = syscall.IPPROTO_UDP
|
||||
h.Type = unix.UDP_SEGMENT
|
||||
h.SetLen(unix.CmsgLen(dataLen))
|
||||
|
||||
// UnixRights uses the private `data` method, but I *think* this achieves the same goal.
|
||||
offset := startLen + unix.CmsgSpace(0)
|
||||
*(*uint16)(unsafe.Pointer(&b[offset])) = size
|
||||
return b
|
||||
}
|
||||
|
||||
func isGSOError(err error) bool {
|
||||
var serr *os.SyscallError
|
||||
if errors.As(err, &serr) {
|
||||
// EIO is returned by udp_send_skb() if the device driver does not have tx checksums enabled,
|
||||
// which is a hard requirement of UDP_SEGMENT. See:
|
||||
// https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man7/udp.7?id=806eabd74910447f21005160e90957bde4db0183#n228
|
||||
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv4/udp.c?h=v6.2&id=c9c3395d5e3dcc6daee66c6908354d47bf98cb0c#n942
|
||||
return serr.Err == unix.EIO
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// The first sendmsg call on a new UDP socket sometimes errors on Linux.
|
||||
// It's not clear why this happens.
|
||||
// See https://github.com/golang/go/issues/63322.
|
||||
func isPermissionError(err error) bool {
|
||||
var serr *os.SyscallError
|
||||
if errors.As(err, &serr) {
|
||||
return serr.Syscall == "sendmsg" && serr.Err == unix.EPERM
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
10
vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go
generated
vendored
Normal file
10
vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build !linux
|
||||
|
||||
package quic
|
||||
|
||||
func forceSetReceiveBuffer(c any, bytes int) error { return nil }
|
||||
func forceSetSendBuffer(c any, bytes int) error { return nil }
|
||||
|
||||
func appendUDPSegmentSizeMsg([]byte, uint16) []byte { return nil }
|
||||
func isGSOError(error) bool { return false }
|
||||
func isPermissionError(err error) bool { return false }
|
||||
16
vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go
generated
vendored
16
vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go
generated
vendored
@@ -2,14 +2,20 @@
|
||||
|
||||
package quic
|
||||
|
||||
import "net"
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
func newConn(c net.PacketConn) (rawConn, error) {
|
||||
return &basicConn{PacketConn: c}, nil
|
||||
func newConn(c net.PacketConn, supportsDF bool) (*basicConn, error) {
|
||||
return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
|
||||
}
|
||||
|
||||
func inspectReadBuffer(interface{}) (int, error) {
|
||||
return 0, nil
|
||||
func inspectReadBuffer(any) (int, error) { return 0, nil }
|
||||
func inspectWriteBuffer(any) (int, error) { return 0, nil }
|
||||
|
||||
type packetInfo struct {
|
||||
addr netip.Addr
|
||||
}
|
||||
|
||||
func (i *packetInfo) OOB() []byte { return nil }
|
||||
|
||||
197
vendor/github.com/quic-go/quic-go/sys_conn_oob.go
generated
vendored
197
vendor/github.com/quic-go/quic-go/sys_conn_oob.go
generated
vendored
@@ -5,10 +5,15 @@ package quic
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/net/ipv6"
|
||||
@@ -32,20 +37,10 @@ type batchConn interface {
|
||||
ReadBatch(ms []ipv4.Message, flags int) (int, error)
|
||||
}
|
||||
|
||||
func inspectReadBuffer(c interface{}) (int, error) {
|
||||
conn, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
})
|
||||
if !ok {
|
||||
return 0, errors.New("doesn't have a SyscallConn")
|
||||
}
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("couldn't get syscall.RawConn: %w", err)
|
||||
}
|
||||
func inspectReadBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := rawConn.Control(func(fd uintptr) {
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
@@ -53,6 +48,22 @@ func inspectReadBuffer(c interface{}) (int, error) {
|
||||
return size, serr
|
||||
}
|
||||
|
||||
func inspectWriteBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return size, serr
|
||||
}
|
||||
|
||||
func isECNDisabled() bool {
|
||||
disabled, err := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_ECN"))
|
||||
return err == nil && disabled
|
||||
}
|
||||
|
||||
type oobConn struct {
|
||||
OOBCapablePacketConn
|
||||
batchConn batchConn
|
||||
@@ -61,11 +72,13 @@ type oobConn struct {
|
||||
// Packets received from the kernel, but not yet returned by ReadPacket().
|
||||
messages []ipv4.Message
|
||||
buffers [batchSize]*packetBuffer
|
||||
|
||||
cap connCapabilities
|
||||
}
|
||||
|
||||
var _ rawConn = &oobConn{}
|
||||
|
||||
func newConn(c OOBCapablePacketConn) (*oobConn, error) {
|
||||
func newConn(c OOBCapablePacketConn, supportsDF bool) (*oobConn, error) {
|
||||
rawConn, err := c.SyscallConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -83,8 +96,8 @@ func newConn(c OOBCapablePacketConn) (*oobConn, error) {
|
||||
errECNIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVTCLASS, 1)
|
||||
|
||||
if needsPacketInfo {
|
||||
errPIIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, ipv4RECVPKTINFO, 1)
|
||||
errPIIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, ipv6RECVPKTINFO, 1)
|
||||
errPIIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, ipv4PKTINFO, 1)
|
||||
errPIIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVPKTINFO, 1)
|
||||
}
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@@ -132,6 +145,11 @@ func newConn(c OOBCapablePacketConn) (*oobConn, error) {
|
||||
batchConn: bc,
|
||||
messages: msgs,
|
||||
readPos: batchSize,
|
||||
cap: connCapabilities{
|
||||
DF: supportsDF,
|
||||
GSO: isGSOSupported(rawConn),
|
||||
ECN: !isECNDisabled(),
|
||||
},
|
||||
}
|
||||
for i := 0; i < batchSize; i++ {
|
||||
oobConn.messages[i].OOB = make([]byte, oobBufferSize)
|
||||
@@ -139,7 +157,9 @@ func newConn(c OOBCapablePacketConn) (*oobConn, error) {
|
||||
return oobConn, nil
|
||||
}
|
||||
|
||||
func (c *oobConn) ReadPacket() (*receivedPacket, error) {
|
||||
var invalidCmsgOnceV4, invalidCmsgOnceV6 sync.Once
|
||||
|
||||
func (c *oobConn) ReadPacket() (receivedPacket, error) {
|
||||
if len(c.messages) == int(c.readPos) { // all messages read. Read the next batch of messages.
|
||||
c.messages = c.messages[:batchSize]
|
||||
// replace buffers data buffers up to the packet that has been consumed during the last ReadBatch call
|
||||
@@ -153,7 +173,7 @@ func (c *oobConn) ReadPacket() (*receivedPacket, error) {
|
||||
|
||||
n, err := c.batchConn.ReadBatch(c.messages, 0)
|
||||
if n == 0 || err != nil {
|
||||
return nil, err
|
||||
return receivedPacket{}, err
|
||||
}
|
||||
c.messages = c.messages[:n]
|
||||
}
|
||||
@@ -163,102 +183,149 @@ func (c *oobConn) ReadPacket() (*receivedPacket, error) {
|
||||
c.readPos++
|
||||
|
||||
data := msg.OOB[:msg.NN]
|
||||
var ecn protocol.ECN
|
||||
var destIP net.IP
|
||||
var ifIndex uint32
|
||||
p := receivedPacket{
|
||||
remoteAddr: msg.Addr,
|
||||
rcvTime: time.Now(),
|
||||
data: msg.Buffers[0][:msg.N],
|
||||
buffer: buffer,
|
||||
}
|
||||
for len(data) > 0 {
|
||||
hdr, body, remainder, err := unix.ParseOneSocketControlMessage(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return receivedPacket{}, err
|
||||
}
|
||||
if hdr.Level == unix.IPPROTO_IP {
|
||||
switch hdr.Type {
|
||||
case msgTypeIPTOS:
|
||||
ecn = protocol.ECN(body[0] & ecnMask)
|
||||
case msgTypeIPv4PKTINFO:
|
||||
// struct in_pktinfo {
|
||||
// unsigned int ipi_ifindex; /* Interface index */
|
||||
// struct in_addr ipi_spec_dst; /* Local address */
|
||||
// struct in_addr ipi_addr; /* Header Destination
|
||||
// address */
|
||||
// };
|
||||
ip := make([]byte, 4)
|
||||
if len(body) == 12 {
|
||||
ifIndex = binary.LittleEndian.Uint32(body)
|
||||
copy(ip, body[8:12])
|
||||
} else if len(body) == 4 {
|
||||
// FreeBSD
|
||||
copy(ip, body)
|
||||
p.ecn = protocol.ParseECNHeaderBits(body[0] & ecnMask)
|
||||
case ipv4PKTINFO:
|
||||
ip, ifIndex, ok := parseIPv4PktInfo(body)
|
||||
if ok {
|
||||
p.info.addr = ip
|
||||
p.info.ifIndex = ifIndex
|
||||
} else {
|
||||
invalidCmsgOnceV4.Do(func() {
|
||||
log.Printf("Received invalid IPv4 packet info control message: %+x. "+
|
||||
"This should never occur, please open a new issue and include details about the architecture.", body)
|
||||
})
|
||||
}
|
||||
destIP = net.IP(ip)
|
||||
}
|
||||
}
|
||||
if hdr.Level == unix.IPPROTO_IPV6 {
|
||||
switch hdr.Type {
|
||||
case unix.IPV6_TCLASS:
|
||||
ecn = protocol.ECN(body[0] & ecnMask)
|
||||
case msgTypeIPv6PKTINFO:
|
||||
p.ecn = protocol.ParseECNHeaderBits(body[0] & ecnMask)
|
||||
case unix.IPV6_PKTINFO:
|
||||
// struct in6_pktinfo {
|
||||
// struct in6_addr ipi6_addr; /* src/dst IPv6 address */
|
||||
// unsigned int ipi6_ifindex; /* send/recv interface index */
|
||||
// };
|
||||
if len(body) == 20 {
|
||||
ip := make([]byte, 16)
|
||||
copy(ip, body[:16])
|
||||
destIP = net.IP(ip)
|
||||
ifIndex = binary.LittleEndian.Uint32(body[16:])
|
||||
p.info.addr = netip.AddrFrom16(*(*[16]byte)(body[:16]))
|
||||
p.info.ifIndex = binary.LittleEndian.Uint32(body[16:])
|
||||
} else {
|
||||
invalidCmsgOnceV6.Do(func() {
|
||||
log.Printf("Received invalid IPv6 packet info control message: %+x. "+
|
||||
"This should never occur, please open a new issue and include details about the architecture.", body)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
data = remainder
|
||||
}
|
||||
var info *packetInfo
|
||||
if destIP != nil {
|
||||
info = &packetInfo{
|
||||
addr: destIP,
|
||||
ifIndex: ifIndex,
|
||||
}
|
||||
}
|
||||
return &receivedPacket{
|
||||
remoteAddr: msg.Addr,
|
||||
rcvTime: time.Now(),
|
||||
data: msg.Buffers[0][:msg.N],
|
||||
ecn: ecn,
|
||||
info: info,
|
||||
buffer: buffer,
|
||||
}, nil
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (c *oobConn) WritePacket(b []byte, addr net.Addr, oob []byte) (n int, err error) {
|
||||
n, _, err = c.OOBCapablePacketConn.WriteMsgUDP(b, oob, addr.(*net.UDPAddr))
|
||||
// WritePacket writes a new packet.
|
||||
func (c *oobConn) WritePacket(b []byte, addr net.Addr, packetInfoOOB []byte, gsoSize uint16, ecn protocol.ECN) (int, error) {
|
||||
oob := packetInfoOOB
|
||||
if gsoSize > 0 {
|
||||
if !c.capabilities().GSO {
|
||||
panic("GSO disabled")
|
||||
}
|
||||
oob = appendUDPSegmentSizeMsg(oob, gsoSize)
|
||||
}
|
||||
if ecn != protocol.ECNUnsupported {
|
||||
if !c.capabilities().ECN {
|
||||
panic("tried to send a ECN-marked packet although ECN is disabled")
|
||||
}
|
||||
if remoteUDPAddr, ok := addr.(*net.UDPAddr); ok {
|
||||
if remoteUDPAddr.IP.To4() != nil {
|
||||
oob = appendIPv4ECNMsg(oob, ecn)
|
||||
} else {
|
||||
oob = appendIPv6ECNMsg(oob, ecn)
|
||||
}
|
||||
}
|
||||
}
|
||||
n, _, err := c.OOBCapablePacketConn.WriteMsgUDP(b, oob, addr.(*net.UDPAddr))
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *oobConn) capabilities() connCapabilities {
|
||||
return c.cap
|
||||
}
|
||||
|
||||
type packetInfo struct {
|
||||
addr netip.Addr
|
||||
ifIndex uint32
|
||||
}
|
||||
|
||||
func (info *packetInfo) OOB() []byte {
|
||||
if info == nil {
|
||||
return nil
|
||||
}
|
||||
if ip4 := info.addr.To4(); ip4 != nil {
|
||||
if info.addr.Is4() {
|
||||
ip := info.addr.As4()
|
||||
// struct in_pktinfo {
|
||||
// unsigned int ipi_ifindex; /* Interface index */
|
||||
// struct in_addr ipi_spec_dst; /* Local address */
|
||||
// struct in_addr ipi_addr; /* Header Destination address */
|
||||
// };
|
||||
cm := ipv4.ControlMessage{
|
||||
Src: ip4,
|
||||
Src: ip[:],
|
||||
IfIndex: int(info.ifIndex),
|
||||
}
|
||||
return cm.Marshal()
|
||||
} else if len(info.addr) == 16 {
|
||||
} else if info.addr.Is6() {
|
||||
ip := info.addr.As16()
|
||||
// struct in6_pktinfo {
|
||||
// struct in6_addr ipi6_addr; /* src/dst IPv6 address */
|
||||
// unsigned int ipi6_ifindex; /* send/recv interface index */
|
||||
// };
|
||||
cm := ipv6.ControlMessage{
|
||||
Src: info.addr,
|
||||
Src: ip[:],
|
||||
IfIndex: int(info.ifIndex),
|
||||
}
|
||||
return cm.Marshal()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendIPv4ECNMsg(b []byte, val protocol.ECN) []byte {
|
||||
startLen := len(b)
|
||||
b = append(b, make([]byte, unix.CmsgSpace(ecnIPv4DataLen))...)
|
||||
h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen]))
|
||||
h.Level = syscall.IPPROTO_IP
|
||||
h.Type = unix.IP_TOS
|
||||
h.SetLen(unix.CmsgLen(ecnIPv4DataLen))
|
||||
|
||||
// UnixRights uses the private `data` method, but I *think* this achieves the same goal.
|
||||
offset := startLen + unix.CmsgSpace(0)
|
||||
b[offset] = val.ToHeaderBits()
|
||||
return b
|
||||
}
|
||||
|
||||
func appendIPv6ECNMsg(b []byte, val protocol.ECN) []byte {
|
||||
startLen := len(b)
|
||||
const dataLen = 4
|
||||
b = append(b, make([]byte, unix.CmsgSpace(dataLen))...)
|
||||
h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen]))
|
||||
h.Level = syscall.IPPROTO_IPV6
|
||||
h.Type = unix.IPV6_TCLASS
|
||||
h.SetLen(unix.CmsgLen(dataLen))
|
||||
|
||||
// UnixRights uses the private `data` method, but I *think* this achieves the same goal.
|
||||
offset := startLen + unix.CmsgSpace(0)
|
||||
b[offset] = val.ToHeaderBits()
|
||||
return b
|
||||
}
|
||||
|
||||
37
vendor/github.com/quic-go/quic-go/sys_conn_windows.go
generated
vendored
37
vendor/github.com/quic-go/quic-go/sys_conn_windows.go
generated
vendored
@@ -3,32 +3,20 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func newConn(c OOBCapablePacketConn) (rawConn, error) {
|
||||
return &basicConn{PacketConn: c}, nil
|
||||
func newConn(c OOBCapablePacketConn, supportsDF bool) (*basicConn, error) {
|
||||
return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
|
||||
}
|
||||
|
||||
func inspectReadBuffer(c net.PacketConn) (int, error) {
|
||||
conn, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
})
|
||||
if !ok {
|
||||
return 0, errors.New("doesn't have a SyscallConn")
|
||||
}
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("couldn't get syscall.RawConn: %w", err)
|
||||
}
|
||||
func inspectReadBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := rawConn.Control(func(fd uintptr) {
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = windows.GetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_RCVBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
@@ -36,4 +24,19 @@ func inspectReadBuffer(c net.PacketConn) (int, error) {
|
||||
return size, serr
|
||||
}
|
||||
|
||||
func inspectWriteBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = windows.GetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_SNDBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return size, serr
|
||||
}
|
||||
|
||||
type packetInfo struct {
|
||||
addr netip.Addr
|
||||
}
|
||||
|
||||
func (i *packetInfo) OOB() []byte { return nil }
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/tools.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/tools.go
generated
vendored
@@ -3,6 +3,6 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
_ "github.com/golang/mock/mockgen"
|
||||
_ "github.com/onsi/ginkgo/v2/ginkgo"
|
||||
_ "go.uber.org/mock/mockgen"
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user