mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2025-03-04 02:14:40 +01:00
Update quic-go
This commit is contained in:
parent
f49196c6e8
commit
41bc703873
26 changed files with 1097 additions and 637 deletions
2
go.mod
2
go.mod
|
@ -21,7 +21,7 @@ require (
|
||||||
github.com/miekg/dns v1.1.63
|
github.com/miekg/dns v1.1.63
|
||||||
github.com/opencoff/go-sieve v0.2.1
|
github.com/opencoff/go-sieve v0.2.1
|
||||||
github.com/powerman/check v1.8.0
|
github.com/powerman/check v1.8.0
|
||||||
github.com/quic-go/quic-go v0.49.0
|
github.com/quic-go/quic-go v0.50.0
|
||||||
golang.org/x/crypto v0.33.0
|
golang.org/x/crypto v0.33.0
|
||||||
golang.org/x/net v0.35.0
|
golang.org/x/net v0.35.0
|
||||||
golang.org/x/sys v0.30.0
|
golang.org/x/sys v0.30.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -75,8 +75,8 @@ github.com/powerman/deepequal v0.1.0 h1:sVwtyTsBuYIvdbLR1O2wzRY63YgPqdGZmk/o80l+
|
||||||
github.com/powerman/deepequal v0.1.0/go.mod h1:3k7aG/slufBhUANdN67o/UPg8i5YaiJ6FmibWX0cn04=
|
github.com/powerman/deepequal v0.1.0/go.mod h1:3k7aG/slufBhUANdN67o/UPg8i5YaiJ6FmibWX0cn04=
|
||||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||||
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
|
github.com/quic-go/quic-go v0.50.0 h1:3H/ld1pa3CYhkcc20TPIyG1bNsdhn9qZBGN3b9/UyUo=
|
||||||
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
|
github.com/quic-go/quic-go v0.50.0/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E=
|
||||||
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
|
||||||
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
|
||||||
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
|
||||||
|
|
59
vendor/github.com/quic-go/quic-go/conn_id_manager.go
generated
vendored
59
vendor/github.com/quic-go/quic-go/conn_id_manager.go
generated
vendored
|
@ -19,6 +19,9 @@ type newConnID struct {
|
||||||
type connIDManager struct {
|
type connIDManager struct {
|
||||||
queue list.List[newConnID]
|
queue list.List[newConnID]
|
||||||
|
|
||||||
|
highestProbingID uint64
|
||||||
|
pathProbing map[pathID]newConnID // initialized lazily
|
||||||
|
|
||||||
handshakeComplete bool
|
handshakeComplete bool
|
||||||
activeSequenceNumber uint64
|
activeSequenceNumber uint64
|
||||||
highestRetired uint64
|
highestRetired uint64
|
||||||
|
@ -76,13 +79,23 @@ func (h *connIDManager) add(f *wire.NewConnectionIDFrame) error {
|
||||||
}
|
}
|
||||||
// If the NEW_CONNECTION_ID frame is reordered, such that its sequence number is smaller than the currently active
|
// If the NEW_CONNECTION_ID frame is reordered, such that its sequence number is smaller than the currently active
|
||||||
// connection ID or if it was already retired, send the RETIRE_CONNECTION_ID frame immediately.
|
// connection ID or if it was already retired, send the RETIRE_CONNECTION_ID frame immediately.
|
||||||
if f.SequenceNumber < h.activeSequenceNumber || f.SequenceNumber < h.highestRetired {
|
if f.SequenceNumber < max(h.activeSequenceNumber, h.highestProbingID) || f.SequenceNumber < h.highestRetired {
|
||||||
h.queueControlFrame(&wire.RetireConnectionIDFrame{
|
h.queueControlFrame(&wire.RetireConnectionIDFrame{
|
||||||
SequenceNumber: f.SequenceNumber,
|
SequenceNumber: f.SequenceNumber,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f.RetirePriorTo != 0 && h.pathProbing != nil {
|
||||||
|
for id, entry := range h.pathProbing {
|
||||||
|
if entry.SequenceNumber < f.RetirePriorTo {
|
||||||
|
h.queueControlFrame(&wire.RetireConnectionIDFrame{
|
||||||
|
SequenceNumber: entry.SequenceNumber,
|
||||||
|
})
|
||||||
|
delete(h.pathProbing, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Retire elements in the queue.
|
// Retire elements in the queue.
|
||||||
// Doesn't retire the active connection ID.
|
// Doesn't retire the active connection ID.
|
||||||
if f.RetirePriorTo > h.highestRetired {
|
if f.RetirePriorTo > h.highestRetired {
|
||||||
|
@ -225,6 +238,50 @@ func (h *connIDManager) SetHandshakeComplete() {
|
||||||
h.handshakeComplete = true
|
h.handshakeComplete = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConnIDForPath retrieves a connection ID for a new path (i.e. not the active one).
|
||||||
|
// Once a connection ID is allocated for a path, it cannot be used for a different path.
|
||||||
|
// When called with the same pathID, it will return the same connection ID,
|
||||||
|
// unless the peer requested that this connection ID be retired.
|
||||||
|
func (h *connIDManager) GetConnIDForPath(id pathID) (protocol.ConnectionID, bool) {
|
||||||
|
h.assertNotClosed()
|
||||||
|
// if we're using zero-length connection IDs, we don't need to change the connection ID
|
||||||
|
if h.activeConnectionID.Len() == 0 {
|
||||||
|
return protocol.ConnectionID{}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.pathProbing == nil {
|
||||||
|
h.pathProbing = make(map[pathID]newConnID)
|
||||||
|
}
|
||||||
|
entry, ok := h.pathProbing[id]
|
||||||
|
if ok {
|
||||||
|
return entry.ConnectionID, true
|
||||||
|
}
|
||||||
|
if h.queue.Len() == 0 {
|
||||||
|
return protocol.ConnectionID{}, false
|
||||||
|
}
|
||||||
|
front := h.queue.Remove(h.queue.Front())
|
||||||
|
h.pathProbing[id] = front
|
||||||
|
h.highestProbingID = front.SequenceNumber
|
||||||
|
return front.ConnectionID, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *connIDManager) RetireConnIDForPath(pathID pathID) {
|
||||||
|
h.assertNotClosed()
|
||||||
|
// if we're using zero-length connection IDs, we don't need to change the connection ID
|
||||||
|
if h.activeConnectionID.Len() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, ok := h.pathProbing[pathID]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.queueControlFrame(&wire.RetireConnectionIDFrame{
|
||||||
|
SequenceNumber: entry.SequenceNumber,
|
||||||
|
})
|
||||||
|
delete(h.pathProbing, pathID)
|
||||||
|
}
|
||||||
|
|
||||||
// Using the connIDManager after it has been closed can have disastrous effects:
|
// Using the connIDManager after it has been closed can have disastrous effects:
|
||||||
// If the connection ID is rotated, a new entry would be inserted into the packet handler map,
|
// If the connection ID is rotated, a new entry would be inserted into the packet handler map,
|
||||||
// leading to a memory leak of the connection struct.
|
// leading to a memory leak of the connection struct.
|
||||||
|
|
575
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
575
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
File diff suppressed because it is too large
Load diff
24
vendor/github.com/quic-go/quic-go/http3/server.go
generated
vendored
24
vendor/github.com/quic-go/quic-go/http3/server.go
generated
vendored
|
@ -684,7 +684,7 @@ func (s *Server) handleRequest(conn *connection, str quic.Stream, datagrams *dat
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
logger = slog.Default()
|
logger = slog.Default()
|
||||||
}
|
}
|
||||||
logger.Error("http: panic serving", "arg", p, "trace", string(buf))
|
logger.Error("http3: panic serving", "arg", p, "trace", string(buf))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
handler.ServeHTTP(r, req)
|
handler.ServeHTTP(r, req)
|
||||||
|
@ -694,18 +694,6 @@ func (s *Server) handleRequest(conn *connection, str quic.Stream, datagrams *dat
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// only write response when there is no panic
|
|
||||||
if !panicked {
|
|
||||||
// response not written to the client yet, set Content-Length
|
|
||||||
if !r.headerWritten {
|
|
||||||
if _, haveCL := r.header["Content-Length"]; !haveCL {
|
|
||||||
r.header.Set("Content-Length", strconv.FormatInt(r.numWritten, 10))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.Flush()
|
|
||||||
r.flushTrailers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// abort the stream when there is a panic
|
// abort the stream when there is a panic
|
||||||
if panicked {
|
if panicked {
|
||||||
str.CancelRead(quic.StreamErrorCode(ErrCodeInternalError))
|
str.CancelRead(quic.StreamErrorCode(ErrCodeInternalError))
|
||||||
|
@ -713,9 +701,17 @@ func (s *Server) handleRequest(conn *connection, str quic.Stream, datagrams *dat
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// response not written to the client yet, set Content-Length
|
||||||
|
if !r.headerWritten {
|
||||||
|
if _, haveCL := r.header["Content-Length"]; !haveCL {
|
||||||
|
r.header.Set("Content-Length", strconv.FormatInt(r.numWritten, 10))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.Flush()
|
||||||
|
r.flushTrailers()
|
||||||
|
|
||||||
// If the EOF was read by the handler, CancelRead() is a no-op.
|
// If the EOF was read by the handler, CancelRead() is a no-op.
|
||||||
str.CancelRead(quic.StreamErrorCode(ErrCodeNoError))
|
str.CancelRead(quic.StreamErrorCode(ErrCodeNoError))
|
||||||
|
|
||||||
str.Close()
|
str.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
generated
vendored
|
@ -10,7 +10,7 @@ import (
|
||||||
// SentPacketHandler handles ACKs received for outgoing packets
|
// SentPacketHandler handles ACKs received for outgoing packets
|
||||||
type SentPacketHandler interface {
|
type SentPacketHandler interface {
|
||||||
// SentPacket may modify the packet
|
// SentPacket may modify the packet
|
||||||
SentPacket(t time.Time, pn, largestAcked protocol.PacketNumber, streamFrames []StreamFrame, frames []Frame, encLevel protocol.EncryptionLevel, ecn protocol.ECN, size protocol.ByteCount, isPathMTUProbePacket bool)
|
SentPacket(t time.Time, pn, largestAcked protocol.PacketNumber, streamFrames []StreamFrame, frames []Frame, encLevel protocol.EncryptionLevel, ecn protocol.ECN, size protocol.ByteCount, isPathMTUProbePacket, isPathProbePacket bool)
|
||||||
// ReceivedAck processes an ACK frame.
|
// ReceivedAck processes an ACK frame.
|
||||||
// It does not store a copy of the 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)
|
ReceivedAck(f *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) (bool /* 1-RTT packet acked */, error)
|
||||||
|
@ -34,6 +34,8 @@ type SentPacketHandler interface {
|
||||||
|
|
||||||
GetLossDetectionTimeout() time.Time
|
GetLossDetectionTimeout() time.Time
|
||||||
OnLossDetectionTimeout(now time.Time) error
|
OnLossDetectionTimeout(now time.Time) error
|
||||||
|
|
||||||
|
MigratedPath(now time.Time, initialMaxPacketSize protocol.ByteCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
type sentPacketTracker interface {
|
type sentPacketTracker interface {
|
||||||
|
|
3
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
3
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
|
@ -22,10 +22,11 @@ type packet struct {
|
||||||
includedInBytesInFlight bool
|
includedInBytesInFlight bool
|
||||||
declaredLost bool
|
declaredLost bool
|
||||||
skippedPacket bool
|
skippedPacket bool
|
||||||
|
isPathProbePacket bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *packet) outstanding() bool {
|
func (p *packet) outstanding() bool {
|
||||||
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket
|
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket && !p.isPathProbePacket
|
||||||
}
|
}
|
||||||
|
|
||||||
var packetPool = sync.Pool{New: func() any { return &packet{} }}
|
var packetPool = sync.Pool{New: func() any { return &packet{} }}
|
||||||
|
|
217
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
217
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
|
@ -27,6 +27,9 @@ const (
|
||||||
maxPTODuration = 60 * time.Second
|
maxPTODuration = 60 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Path probe packets are declared lost after this time.
|
||||||
|
const pathProbePacketLossTimeout = time.Second
|
||||||
|
|
||||||
type packetNumberSpace struct {
|
type packetNumberSpace struct {
|
||||||
history sentPacketHistory
|
history sentPacketHistory
|
||||||
pns packetNumberGenerator
|
pns packetNumberGenerator
|
||||||
|
@ -174,10 +177,9 @@ func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel, now t
|
||||||
if pnSpace == nil {
|
if pnSpace == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
for p := range pnSpace.history.Packets() {
|
||||||
h.removeFromBytesInFlight(p)
|
h.removeFromBytesInFlight(p)
|
||||||
return true, nil
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
// drop the packet history
|
// drop the packet history
|
||||||
//nolint:exhaustive // Not every packet number space can be dropped.
|
//nolint:exhaustive // Not every packet number space can be dropped.
|
||||||
|
@ -194,14 +196,13 @@ func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel, now t
|
||||||
// and not when the client drops 0-RTT keys when the handshake completes.
|
// 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.
|
// 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.
|
// Delete the packets from the history and remove them from bytes_in_flight.
|
||||||
h.appDataPackets.history.Iterate(func(p *packet) (bool, error) {
|
for p := range h.appDataPackets.history.Packets() {
|
||||||
if p.EncryptionLevel != protocol.Encryption0RTT && !p.skippedPacket {
|
if p.EncryptionLevel != protocol.Encryption0RTT && !p.skippedPacket {
|
||||||
return false, nil
|
break
|
||||||
}
|
}
|
||||||
h.removeFromBytesInFlight(p)
|
h.removeFromBytesInFlight(p)
|
||||||
h.appDataPackets.history.Remove(p.PacketNumber)
|
h.appDataPackets.history.Remove(p.PacketNumber)
|
||||||
return true, nil
|
}
|
||||||
})
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
|
panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
|
||||||
}
|
}
|
||||||
|
@ -249,11 +250,12 @@ func (h *sentPacketHandler) SentPacket(
|
||||||
ecn protocol.ECN,
|
ecn protocol.ECN,
|
||||||
size protocol.ByteCount,
|
size protocol.ByteCount,
|
||||||
isPathMTUProbePacket bool,
|
isPathMTUProbePacket bool,
|
||||||
|
isPathProbePacket bool,
|
||||||
) {
|
) {
|
||||||
h.bytesSent += size
|
h.bytesSent += size
|
||||||
|
|
||||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||||
if h.logger.Debug() && pnSpace.history.HasOutstandingPackets() {
|
if h.logger.Debug() && (pnSpace.history.HasOutstandingPackets() || pnSpace.history.HasOutstandingPathProbes()) {
|
||||||
for p := max(0, pnSpace.largestSent+1); p < pn; p++ {
|
for p := max(0, pnSpace.largestSent+1); p < pn; p++ {
|
||||||
h.logger.Debugf("Skipping packet number %d", p)
|
h.logger.Debugf("Skipping packet number %d", p)
|
||||||
}
|
}
|
||||||
|
@ -262,6 +264,18 @@ func (h *sentPacketHandler) SentPacket(
|
||||||
pnSpace.largestSent = pn
|
pnSpace.largestSent = pn
|
||||||
isAckEliciting := len(streamFrames) > 0 || len(frames) > 0
|
isAckEliciting := len(streamFrames) > 0 || len(frames) > 0
|
||||||
|
|
||||||
|
if isPathProbePacket {
|
||||||
|
p := getPacket()
|
||||||
|
p.SendTime = t
|
||||||
|
p.PacketNumber = pn
|
||||||
|
p.EncryptionLevel = encLevel
|
||||||
|
p.Length = size
|
||||||
|
p.Frames = frames
|
||||||
|
p.isPathProbePacket = true
|
||||||
|
pnSpace.history.SentPathProbePacket(p)
|
||||||
|
h.setLossDetectionTimer(t)
|
||||||
|
return
|
||||||
|
}
|
||||||
if isAckEliciting {
|
if isAckEliciting {
|
||||||
pnSpace.lastAckElicitingPacketTime = t
|
pnSpace.lastAckElicitingPacketTime = t
|
||||||
h.bytesInFlight += size
|
h.bytesInFlight += size
|
||||||
|
@ -341,7 +355,7 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||||
}
|
}
|
||||||
// update the RTT, if the largest acked is newly acknowledged
|
// update the RTT, if the largest acked is newly acknowledged
|
||||||
if len(ackedPackets) > 0 {
|
if len(ackedPackets) > 0 {
|
||||||
if p := ackedPackets[len(ackedPackets)-1]; p.PacketNumber == ack.LargestAcked() {
|
if p := ackedPackets[len(ackedPackets)-1]; p.PacketNumber == ack.LargestAcked() && !p.isPathProbePacket {
|
||||||
// don't use the ack delay for Initial and Handshake packets
|
// don't use the ack delay for Initial and Handshake packets
|
||||||
var ackDelay time.Duration
|
var ackDelay time.Duration
|
||||||
if encLevel == protocol.Encryption1RTT {
|
if encLevel == protocol.Encryption1RTT {
|
||||||
|
@ -365,8 +379,9 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||||
|
|
||||||
pnSpace.largestAcked = max(pnSpace.largestAcked, largestAcked)
|
pnSpace.largestAcked = max(pnSpace.largestAcked, largestAcked)
|
||||||
|
|
||||||
if err := h.detectLostPackets(rcvTime, encLevel); err != nil {
|
h.detectLostPackets(rcvTime, encLevel)
|
||||||
return false, err
|
if encLevel == protocol.Encryption1RTT {
|
||||||
|
h.detectLostPathProbes(rcvTime)
|
||||||
}
|
}
|
||||||
var acked1RTTPacket bool
|
var acked1RTTPacket bool
|
||||||
for _, p := range ackedPackets {
|
for _, p := range ackedPackets {
|
||||||
|
@ -377,7 +392,9 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||||
acked1RTTPacket = true
|
acked1RTTPacket = true
|
||||||
}
|
}
|
||||||
h.removeFromBytesInFlight(p)
|
h.removeFromBytesInFlight(p)
|
||||||
putPacket(p)
|
if !p.isPathProbePacket {
|
||||||
|
putPacket(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// After this point, we must not use ackedPackets any longer!
|
// After this point, we must not use ackedPackets any longer!
|
||||||
// We've already returned the buffers.
|
// We've already returned the buffers.
|
||||||
|
@ -411,14 +428,13 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
|
||||||
ackRangeIndex := 0
|
ackRangeIndex := 0
|
||||||
lowestAcked := ack.LowestAcked()
|
lowestAcked := ack.LowestAcked()
|
||||||
largestAcked := ack.LargestAcked()
|
largestAcked := ack.LargestAcked()
|
||||||
err := pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
for p := range pnSpace.history.Packets() {
|
||||||
// Ignore packets below the lowest acked
|
// ignore packets below the lowest acked
|
||||||
if p.PacketNumber < lowestAcked {
|
if p.PacketNumber < lowestAcked {
|
||||||
return true, nil
|
continue
|
||||||
}
|
}
|
||||||
// Break after largest acked is reached
|
|
||||||
if p.PacketNumber > largestAcked {
|
if p.PacketNumber > largestAcked {
|
||||||
return false, nil
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if ack.HasMissingRanges() {
|
if ack.HasMissingRanges() {
|
||||||
|
@ -430,21 +446,28 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.PacketNumber < ackRange.Smallest { // packet not contained in ACK range
|
if p.PacketNumber < ackRange.Smallest { // packet not contained in ACK range
|
||||||
return true, nil
|
continue
|
||||||
}
|
}
|
||||||
if p.PacketNumber > ackRange.Largest {
|
if p.PacketNumber > ackRange.Largest {
|
||||||
return false, fmt.Errorf("BUG: ackhandler would have acked wrong packet %d, while evaluating range %d -> %d", p.PacketNumber, ackRange.Smallest, ackRange.Largest)
|
return nil, fmt.Errorf("BUG: ackhandler would have acked wrong packet %d, while evaluating range %d -> %d", p.PacketNumber, ackRange.Smallest, ackRange.Largest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.skippedPacket {
|
if p.skippedPacket {
|
||||||
return false, &qerr.TransportError{
|
return nil, &qerr.TransportError{
|
||||||
ErrorCode: qerr.ProtocolViolation,
|
ErrorCode: qerr.ProtocolViolation,
|
||||||
ErrorMessage: fmt.Sprintf("received an ACK for skipped packet number: %d (%s)", p.PacketNumber, encLevel),
|
ErrorMessage: fmt.Sprintf("received an ACK for skipped packet number: %d (%s)", p.PacketNumber, encLevel),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if p.isPathProbePacket {
|
||||||
|
probePacket := pnSpace.history.RemovePathProbe(p.PacketNumber)
|
||||||
|
if probePacket == nil {
|
||||||
|
panic(fmt.Sprintf("path probe doesn't exist: %d", p.PacketNumber))
|
||||||
|
}
|
||||||
|
h.ackedPackets = append(h.ackedPackets, probePacket)
|
||||||
|
continue
|
||||||
|
}
|
||||||
h.ackedPackets = append(h.ackedPackets, p)
|
h.ackedPackets = append(h.ackedPackets, p)
|
||||||
return true, nil
|
}
|
||||||
})
|
|
||||||
if h.logger.Debug() && len(h.ackedPackets) > 0 {
|
if h.logger.Debug() && len(h.ackedPackets) > 0 {
|
||||||
pns := make([]protocol.PacketNumber, len(h.ackedPackets))
|
pns := make([]protocol.PacketNumber, len(h.ackedPackets))
|
||||||
for i, p := range h.ackedPackets {
|
for i, p := range h.ackedPackets {
|
||||||
|
@ -475,8 +498,7 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
|
||||||
h.tracer.AcknowledgedPacket(encLevel, p.PacketNumber)
|
h.tracer.AcknowledgedPacket(encLevel, p.PacketNumber)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return h.ackedPackets, nil
|
||||||
return h.ackedPackets, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *sentPacketHandler) getLossTimeAndSpace() (time.Time, protocol.EncryptionLevel) {
|
func (h *sentPacketHandler) getLossTimeAndSpace() (time.Time, protocol.EncryptionLevel) {
|
||||||
|
@ -507,7 +529,7 @@ func (h *sentPacketHandler) getScaledPTO(includeMaxAckDelay bool) time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// same logic as getLossTimeAndSpace, but for lastAckElicitingPacketTime instead of lossTime
|
// same logic as getLossTimeAndSpace, but for lastAckElicitingPacketTime instead of lossTime
|
||||||
func (h *sentPacketHandler) getPTOTimeAndSpace(now time.Time) (pto time.Time, encLevel protocol.EncryptionLevel, ok bool) {
|
func (h *sentPacketHandler) getPTOTimeAndSpace(now time.Time) (pto time.Time, encLevel protocol.EncryptionLevel) {
|
||||||
// We only send application data probe packets once the handshake is confirmed,
|
// We only send application data probe packets once the handshake is confirmed,
|
||||||
// because before that, we don't have the keys to decrypt ACKs sent in 1-RTT packets.
|
// because before that, we don't have the keys to decrypt ACKs sent in 1-RTT packets.
|
||||||
if !h.handshakeConfirmed && !h.hasOutstandingCryptoPackets() {
|
if !h.handshakeConfirmed && !h.hasOutstandingCryptoPackets() {
|
||||||
|
@ -516,32 +538,35 @@ func (h *sentPacketHandler) getPTOTimeAndSpace(now time.Time) (pto time.Time, en
|
||||||
}
|
}
|
||||||
t := now.Add(h.getScaledPTO(false))
|
t := now.Add(h.getScaledPTO(false))
|
||||||
if h.initialPackets != nil {
|
if h.initialPackets != nil {
|
||||||
return t, protocol.EncryptionInitial, true
|
return t, protocol.EncryptionInitial
|
||||||
}
|
}
|
||||||
return t, protocol.EncryptionHandshake, true
|
return t, protocol.EncryptionHandshake
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.initialPackets != nil {
|
if h.initialPackets != nil && h.initialPackets.history.HasOutstandingPackets() &&
|
||||||
|
!h.initialPackets.lastAckElicitingPacketTime.IsZero() {
|
||||||
encLevel = protocol.EncryptionInitial
|
encLevel = protocol.EncryptionInitial
|
||||||
if t := h.initialPackets.lastAckElicitingPacketTime; !t.IsZero() {
|
if t := h.initialPackets.lastAckElicitingPacketTime; !t.IsZero() {
|
||||||
pto = t.Add(h.getScaledPTO(false))
|
pto = t.Add(h.getScaledPTO(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h.handshakePackets != nil && !h.handshakePackets.lastAckElicitingPacketTime.IsZero() {
|
if h.handshakePackets != nil && h.handshakePackets.history.HasOutstandingPackets() &&
|
||||||
|
!h.handshakePackets.lastAckElicitingPacketTime.IsZero() {
|
||||||
t := h.handshakePackets.lastAckElicitingPacketTime.Add(h.getScaledPTO(false))
|
t := h.handshakePackets.lastAckElicitingPacketTime.Add(h.getScaledPTO(false))
|
||||||
if pto.IsZero() || (!t.IsZero() && t.Before(pto)) {
|
if pto.IsZero() || (!t.IsZero() && t.Before(pto)) {
|
||||||
pto = t
|
pto = t
|
||||||
encLevel = protocol.EncryptionHandshake
|
encLevel = protocol.EncryptionHandshake
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h.handshakeConfirmed && !h.appDataPackets.lastAckElicitingPacketTime.IsZero() {
|
if h.handshakeConfirmed && h.appDataPackets.history.HasOutstandingPackets() &&
|
||||||
|
!h.appDataPackets.lastAckElicitingPacketTime.IsZero() {
|
||||||
t := h.appDataPackets.lastAckElicitingPacketTime.Add(h.getScaledPTO(true))
|
t := h.appDataPackets.lastAckElicitingPacketTime.Add(h.getScaledPTO(true))
|
||||||
if pto.IsZero() || (!t.IsZero() && t.Before(pto)) {
|
if pto.IsZero() || (!t.IsZero() && t.Before(pto)) {
|
||||||
pto = t
|
pto = t
|
||||||
encLevel = protocol.Encryption1RTT
|
encLevel = protocol.Encryption1RTT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pto, encLevel, true
|
return pto, encLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *sentPacketHandler) hasOutstandingCryptoPackets() bool {
|
func (h *sentPacketHandler) hasOutstandingCryptoPackets() bool {
|
||||||
|
@ -573,8 +598,8 @@ func (h *sentPacketHandler) setLossDetectionTimer(now time.Time) {
|
||||||
|
|
||||||
func (h *sentPacketHandler) lossDetectionTime(now time.Time) alarmTimer {
|
func (h *sentPacketHandler) lossDetectionTime(now time.Time) alarmTimer {
|
||||||
// cancel the alarm if no packets are outstanding
|
// cancel the alarm if no packets are outstanding
|
||||||
if h.peerCompletedAddressValidation &&
|
if h.peerCompletedAddressValidation && !h.hasOutstandingCryptoPackets() &&
|
||||||
!h.hasOutstandingCryptoPackets() && !h.appDataPackets.history.HasOutstandingPackets() {
|
!h.appDataPackets.history.HasOutstandingPackets() && !h.appDataPackets.history.HasOutstandingPathProbes() {
|
||||||
return alarmTimer{}
|
return alarmTimer{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,28 +608,62 @@ func (h *sentPacketHandler) lossDetectionTime(now time.Time) alarmTimer {
|
||||||
return alarmTimer{}
|
return alarmTimer{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pathProbeLossTime time.Time
|
||||||
|
if h.appDataPackets.history.HasOutstandingPathProbes() {
|
||||||
|
if p := h.appDataPackets.history.FirstOutstandingPathProbe(); p != nil {
|
||||||
|
pathProbeLossTime = p.SendTime.Add(pathProbePacketLossTimeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// early retransmit timer or time loss detection
|
// early retransmit timer or time loss detection
|
||||||
lossTime, encLevel := h.getLossTimeAndSpace()
|
lossTime, encLevel := h.getLossTimeAndSpace()
|
||||||
if !lossTime.IsZero() {
|
if !lossTime.IsZero() && (pathProbeLossTime.IsZero() || lossTime.Before(pathProbeLossTime)) {
|
||||||
return alarmTimer{
|
return alarmTimer{
|
||||||
Time: lossTime,
|
Time: lossTime,
|
||||||
TimerType: logging.TimerTypeACK,
|
TimerType: logging.TimerTypeACK,
|
||||||
EncryptionLevel: encLevel,
|
EncryptionLevel: encLevel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ptoTime, encLevel := h.getPTOTimeAndSpace(now)
|
||||||
ptoTime, encLevel, ok := h.getPTOTimeAndSpace(now)
|
if !ptoTime.IsZero() && (pathProbeLossTime.IsZero() || ptoTime.Before(pathProbeLossTime)) {
|
||||||
if !ok {
|
return alarmTimer{
|
||||||
return alarmTimer{}
|
Time: ptoTime,
|
||||||
|
TimerType: logging.TimerTypePTO,
|
||||||
|
EncryptionLevel: encLevel,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return alarmTimer{
|
if !pathProbeLossTime.IsZero() {
|
||||||
Time: ptoTime,
|
return alarmTimer{
|
||||||
TimerType: logging.TimerTypePTO,
|
Time: pathProbeLossTime,
|
||||||
EncryptionLevel: encLevel,
|
TimerType: logging.TimerTypePathProbe,
|
||||||
|
EncryptionLevel: encLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alarmTimer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *sentPacketHandler) detectLostPathProbes(now time.Time) {
|
||||||
|
if !h.appDataPackets.history.HasOutstandingPathProbes() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lossTime := now.Add(-pathProbePacketLossTimeout)
|
||||||
|
// RemovePathProbe cannot be called while iterating.
|
||||||
|
var lostPathProbes []*packet
|
||||||
|
for p := range h.appDataPackets.history.PathProbes() {
|
||||||
|
if !p.SendTime.After(lossTime) {
|
||||||
|
lostPathProbes = append(lostPathProbes, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, p := range lostPathProbes {
|
||||||
|
for _, f := range p.Frames {
|
||||||
|
f.Handler.OnLost(f.Frame)
|
||||||
|
}
|
||||||
|
h.appDataPackets.history.Remove(p.PacketNumber)
|
||||||
|
h.appDataPackets.history.RemovePathProbe(p.PacketNumber)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.EncryptionLevel) error {
|
func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.EncryptionLevel) {
|
||||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||||
pnSpace.lossTime = time.Time{}
|
pnSpace.lossTime = time.Time{}
|
||||||
|
|
||||||
|
@ -618,15 +677,16 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||||
lostSendTime := now.Add(-lossDelay)
|
lostSendTime := now.Add(-lossDelay)
|
||||||
|
|
||||||
priorInFlight := h.bytesInFlight
|
priorInFlight := h.bytesInFlight
|
||||||
return pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
for p := range pnSpace.history.Packets() {
|
||||||
if p.PacketNumber > pnSpace.largestAcked {
|
if p.PacketNumber > pnSpace.largestAcked {
|
||||||
return false, nil
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isRegularPacket := !p.skippedPacket && !p.isPathProbePacket
|
||||||
var packetLost bool
|
var packetLost bool
|
||||||
if !p.SendTime.After(lostSendTime) {
|
if !p.SendTime.After(lostSendTime) {
|
||||||
packetLost = true
|
packetLost = true
|
||||||
if !p.skippedPacket {
|
if isRegularPacket {
|
||||||
if h.logger.Debug() {
|
if h.logger.Debug() {
|
||||||
h.logger.Debugf("\tlost packet %d (time threshold)", p.PacketNumber)
|
h.logger.Debugf("\tlost packet %d (time threshold)", p.PacketNumber)
|
||||||
}
|
}
|
||||||
|
@ -636,7 +696,7 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||||
}
|
}
|
||||||
} else if pnSpace.largestAcked >= p.PacketNumber+packetThreshold {
|
} else if pnSpace.largestAcked >= p.PacketNumber+packetThreshold {
|
||||||
packetLost = true
|
packetLost = true
|
||||||
if !p.skippedPacket {
|
if isRegularPacket {
|
||||||
if h.logger.Debug() {
|
if h.logger.Debug() {
|
||||||
h.logger.Debugf("\tlost packet %d (reordering threshold)", p.PacketNumber)
|
h.logger.Debugf("\tlost packet %d (reordering threshold)", p.PacketNumber)
|
||||||
}
|
}
|
||||||
|
@ -654,7 +714,7 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||||
}
|
}
|
||||||
if packetLost {
|
if packetLost {
|
||||||
pnSpace.history.DeclareLost(p.PacketNumber)
|
pnSpace.history.DeclareLost(p.PacketNumber)
|
||||||
if !p.skippedPacket {
|
if isRegularPacket {
|
||||||
// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
|
// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
|
||||||
h.removeFromBytesInFlight(p)
|
h.removeFromBytesInFlight(p)
|
||||||
h.queueFramesForRetransmission(p)
|
h.queueFramesForRetransmission(p)
|
||||||
|
@ -666,12 +726,16 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true, nil
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *sentPacketHandler) OnLossDetectionTimeout(now time.Time) error {
|
func (h *sentPacketHandler) OnLossDetectionTimeout(now time.Time) error {
|
||||||
defer h.setLossDetectionTimer(now)
|
defer h.setLossDetectionTimer(now)
|
||||||
|
|
||||||
|
if h.handshakeConfirmed {
|
||||||
|
h.detectLostPathProbes(now)
|
||||||
|
}
|
||||||
|
|
||||||
earliestLossTime, encLevel := h.getLossTimeAndSpace()
|
earliestLossTime, encLevel := h.getLossTimeAndSpace()
|
||||||
if !earliestLossTime.IsZero() {
|
if !earliestLossTime.IsZero() {
|
||||||
if h.logger.Debug() {
|
if h.logger.Debug() {
|
||||||
|
@ -681,7 +745,8 @@ func (h *sentPacketHandler) OnLossDetectionTimeout(now time.Time) error {
|
||||||
h.tracer.LossTimerExpired(logging.TimerTypeACK, encLevel)
|
h.tracer.LossTimerExpired(logging.TimerTypeACK, encLevel)
|
||||||
}
|
}
|
||||||
// Early retransmit or time loss detection
|
// Early retransmit or time loss detection
|
||||||
return h.detectLostPackets(now, encLevel)
|
h.detectLostPackets(now, encLevel)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PTO
|
// PTO
|
||||||
|
@ -702,11 +767,12 @@ func (h *sentPacketHandler) OnLossDetectionTimeout(now time.Time) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, encLevel, ok := h.getPTOTimeAndSpace(now)
|
ptoTime, encLevel := h.getPTOTimeAndSpace(now)
|
||||||
if !ok {
|
if ptoTime.IsZero() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if ps := h.getPacketNumberSpace(encLevel); !ps.history.HasOutstandingPackets() && !h.peerCompletedAddressValidation {
|
ps := h.getPacketNumberSpace(encLevel)
|
||||||
|
if !ps.history.HasOutstandingPackets() && !ps.history.HasOutstandingPathProbes() && !h.peerCompletedAddressValidation {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
h.ptoCount++
|
h.ptoCount++
|
||||||
|
@ -868,24 +934,21 @@ func (h *sentPacketHandler) queueFramesForRetransmission(p *packet) {
|
||||||
func (h *sentPacketHandler) ResetForRetry(now time.Time) {
|
func (h *sentPacketHandler) ResetForRetry(now time.Time) {
|
||||||
h.bytesInFlight = 0
|
h.bytesInFlight = 0
|
||||||
var firstPacketSendTime time.Time
|
var firstPacketSendTime time.Time
|
||||||
h.initialPackets.history.Iterate(func(p *packet) (bool, error) {
|
for p := range h.initialPackets.history.Packets() {
|
||||||
if firstPacketSendTime.IsZero() {
|
if firstPacketSendTime.IsZero() {
|
||||||
firstPacketSendTime = p.SendTime
|
firstPacketSendTime = p.SendTime
|
||||||
}
|
}
|
||||||
if p.declaredLost || p.skippedPacket {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
h.queueFramesForRetransmission(p)
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
// 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) {
|
|
||||||
if !p.declaredLost && !p.skippedPacket {
|
if !p.declaredLost && !p.skippedPacket {
|
||||||
h.queueFramesForRetransmission(p)
|
h.queueFramesForRetransmission(p)
|
||||||
}
|
}
|
||||||
return true, nil
|
}
|
||||||
})
|
// 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.
|
||||||
|
for p := range h.appDataPackets.history.Packets() {
|
||||||
|
if !p.declaredLost && !p.skippedPacket {
|
||||||
|
h.queueFramesForRetransmission(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only use the Retry to estimate the RTT if we didn't send any retransmission for the Initial.
|
// Only use the Retry to estimate the RTT if we didn't send any retransmission for the Initial.
|
||||||
// Otherwise, we don't know which Initial the Retry was sent in response to.
|
// Otherwise, we don't know which Initial the Retry was sent in response to.
|
||||||
|
@ -913,3 +976,25 @@ func (h *sentPacketHandler) ResetForRetry(now time.Time) {
|
||||||
}
|
}
|
||||||
h.ptoCount = 0
|
h.ptoCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *sentPacketHandler) MigratedPath(now time.Time, initialMaxDatagramSize protocol.ByteCount) {
|
||||||
|
h.rttStats.ResetForPathMigration()
|
||||||
|
for p := range h.appDataPackets.history.Packets() {
|
||||||
|
h.appDataPackets.history.DeclareLost(p.PacketNumber)
|
||||||
|
if !p.skippedPacket && !p.isPathProbePacket {
|
||||||
|
h.removeFromBytesInFlight(p)
|
||||||
|
h.queueFramesForRetransmission(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for p := range h.appDataPackets.history.PathProbes() {
|
||||||
|
h.appDataPackets.history.RemovePathProbe(p.PacketNumber)
|
||||||
|
}
|
||||||
|
h.congestion = congestion.NewCubicSender(
|
||||||
|
congestion.DefaultClock{},
|
||||||
|
h.rttStats,
|
||||||
|
initialMaxDatagramSize,
|
||||||
|
true, // use Reno
|
||||||
|
h.tracer,
|
||||||
|
)
|
||||||
|
h.setLossDetectionTimer(now)
|
||||||
|
}
|
||||||
|
|
82
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
82
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
|
@ -2,12 +2,14 @@ package ackhandler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"iter"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go/internal/protocol"
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sentPacketHistory struct {
|
type sentPacketHistory struct {
|
||||||
packets []*packet
|
packets []*packet
|
||||||
|
pathProbePackets []*packet
|
||||||
|
|
||||||
numOutstanding int
|
numOutstanding int
|
||||||
|
|
||||||
|
@ -32,11 +34,11 @@ func (h *sentPacketHistory) checkSequentialPacketNumberUse(pn protocol.PacketNum
|
||||||
panic("non-sequential packet number use")
|
panic("non-sequential packet number use")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
h.highestPacketNumber = pn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
|
func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
|
||||||
h.checkSequentialPacketNumberUse(pn)
|
h.checkSequentialPacketNumberUse(pn)
|
||||||
h.highestPacketNumber = pn
|
|
||||||
h.packets = append(h.packets, &packet{
|
h.packets = append(h.packets, &packet{
|
||||||
PacketNumber: pn,
|
PacketNumber: pn,
|
||||||
skippedPacket: true,
|
skippedPacket: true,
|
||||||
|
@ -45,7 +47,6 @@ func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
|
||||||
|
|
||||||
func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber) {
|
func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber) {
|
||||||
h.checkSequentialPacketNumberUse(pn)
|
h.checkSequentialPacketNumberUse(pn)
|
||||||
h.highestPacketNumber = pn
|
|
||||||
if len(h.packets) > 0 {
|
if len(h.packets) > 0 {
|
||||||
h.packets = append(h.packets, nil)
|
h.packets = append(h.packets, nil)
|
||||||
}
|
}
|
||||||
|
@ -53,28 +54,42 @@ func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber)
|
||||||
|
|
||||||
func (h *sentPacketHistory) SentAckElicitingPacket(p *packet) {
|
func (h *sentPacketHistory) SentAckElicitingPacket(p *packet) {
|
||||||
h.checkSequentialPacketNumberUse(p.PacketNumber)
|
h.checkSequentialPacketNumberUse(p.PacketNumber)
|
||||||
h.highestPacketNumber = p.PacketNumber
|
|
||||||
h.packets = append(h.packets, p)
|
h.packets = append(h.packets, p)
|
||||||
if p.outstanding() {
|
if p.outstanding() {
|
||||||
h.numOutstanding++
|
h.numOutstanding++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate iterates through all packets.
|
func (h *sentPacketHistory) SentPathProbePacket(p *packet) {
|
||||||
func (h *sentPacketHistory) Iterate(cb func(*packet) (cont bool, err error)) error {
|
h.checkSequentialPacketNumberUse(p.PacketNumber)
|
||||||
for _, p := range h.packets {
|
h.packets = append(h.packets, &packet{
|
||||||
if p == nil {
|
PacketNumber: p.PacketNumber,
|
||||||
continue
|
isPathProbePacket: true,
|
||||||
}
|
})
|
||||||
cont, err := cb(p)
|
h.pathProbePackets = append(h.pathProbePackets, p)
|
||||||
if err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
func (h *sentPacketHistory) Packets() iter.Seq[*packet] {
|
||||||
if !cont {
|
return func(yield func(*packet) bool) {
|
||||||
return nil
|
for _, p := range h.packets {
|
||||||
|
if p == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !yield(p) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *sentPacketHistory) PathProbes() iter.Seq[*packet] {
|
||||||
|
return func(yield func(*packet) bool) {
|
||||||
|
for _, p := range h.pathProbePackets {
|
||||||
|
if !yield(p) {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FirstOutstanding returns the first outstanding packet.
|
// FirstOutstanding returns the first outstanding packet.
|
||||||
|
@ -90,6 +105,14 @@ func (h *sentPacketHistory) FirstOutstanding() *packet {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FirstOutstandingPathProbe returns the first outstanding path probe packet
|
||||||
|
func (h *sentPacketHistory) FirstOutstandingPathProbe() *packet {
|
||||||
|
if len(h.pathProbePackets) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return h.pathProbePackets[0]
|
||||||
|
}
|
||||||
|
|
||||||
func (h *sentPacketHistory) Len() int {
|
func (h *sentPacketHistory) Len() int {
|
||||||
return len(h.packets)
|
return len(h.packets)
|
||||||
}
|
}
|
||||||
|
@ -125,6 +148,27 @@ func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemovePathProbe removes a path probe packet.
|
||||||
|
// It scales O(N), but that's ok, since we don't expect to send many path probe packets.
|
||||||
|
// It is not valid to call this function in IteratePathProbes.
|
||||||
|
func (h *sentPacketHistory) RemovePathProbe(pn protocol.PacketNumber) *packet {
|
||||||
|
var packetToDelete *packet
|
||||||
|
idx := -1
|
||||||
|
for i, p := range h.pathProbePackets {
|
||||||
|
if p.PacketNumber == pn {
|
||||||
|
packetToDelete = p
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx != -1 {
|
||||||
|
// don't use slices.Delete, because it zeros the deleted element
|
||||||
|
copy(h.pathProbePackets[idx:], h.pathProbePackets[idx+1:])
|
||||||
|
h.pathProbePackets = h.pathProbePackets[:len(h.pathProbePackets)-1]
|
||||||
|
}
|
||||||
|
return packetToDelete
|
||||||
|
}
|
||||||
|
|
||||||
// getIndex gets the index of packet p in the packets slice.
|
// getIndex gets the index of packet p in the packets slice.
|
||||||
func (h *sentPacketHistory) getIndex(p protocol.PacketNumber) (int, bool) {
|
func (h *sentPacketHistory) getIndex(p protocol.PacketNumber) (int, bool) {
|
||||||
if len(h.packets) == 0 {
|
if len(h.packets) == 0 {
|
||||||
|
@ -145,6 +189,10 @@ func (h *sentPacketHistory) HasOutstandingPackets() bool {
|
||||||
return h.numOutstanding > 0
|
return h.numOutstanding > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *sentPacketHistory) HasOutstandingPathProbes() bool {
|
||||||
|
return len(h.pathProbePackets) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// delete all nil entries at the beginning of the packets slice
|
// delete all nil entries at the beginning of the packets slice
|
||||||
func (h *sentPacketHistory) cleanupStart() {
|
func (h *sentPacketHistory) cleanupStart() {
|
||||||
for i, p := range h.packets {
|
for i, p := range h.packets {
|
||||||
|
|
93
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
93
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
"github.com/quic-go/quic-go/internal/protocol"
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
"github.com/quic-go/quic-go/internal/qerr"
|
"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/internal/utils"
|
||||||
"github.com/quic-go/quic-go/internal/wire"
|
"github.com/quic-go/quic-go/internal/wire"
|
||||||
"github.com/quic-go/quic-go/logging"
|
"github.com/quic-go/quic-go/logging"
|
||||||
|
@ -89,12 +88,13 @@ func NewCryptoSetupClient(
|
||||||
|
|
||||||
tlsConf = tlsConf.Clone()
|
tlsConf = tlsConf.Clone()
|
||||||
tlsConf.MinVersion = tls.VersionTLS13
|
tlsConf.MinVersion = tls.VersionTLS13
|
||||||
quicConf := &tls.QUICConfig{TLSConfig: tlsConf}
|
|
||||||
qtls.SetupConfigForClient(quicConf, cs.marshalDataForSessionState, cs.handleDataFromSessionState)
|
|
||||||
cs.tlsConf = tlsConf
|
cs.tlsConf = tlsConf
|
||||||
cs.allow0RTT = enable0RTT
|
cs.allow0RTT = enable0RTT
|
||||||
|
|
||||||
cs.conn = tls.QUICClient(quicConf)
|
cs.conn = tls.QUICClient(&tls.QUICConfig{
|
||||||
|
TLSConfig: tlsConf,
|
||||||
|
EnableSessionEvents: true,
|
||||||
|
})
|
||||||
cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient))
|
cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient))
|
||||||
|
|
||||||
return cs
|
return cs
|
||||||
|
@ -123,9 +123,13 @@ func NewCryptoSetupServer(
|
||||||
)
|
)
|
||||||
cs.allow0RTT = allow0RTT
|
cs.allow0RTT = allow0RTT
|
||||||
|
|
||||||
tlsConf = qtls.SetupConfigForServer(tlsConf, localAddr, remoteAddr, cs.getDataForSessionTicket, cs.handleSessionTicket)
|
tlsConf = setupConfigForServer(tlsConf, localAddr, remoteAddr)
|
||||||
|
|
||||||
cs.tlsConf = tlsConf
|
cs.tlsConf = tlsConf
|
||||||
cs.conn = tls.QUICServer(&tls.QUICConfig{TLSConfig: tlsConf})
|
cs.conn = tls.QUICServer(&tls.QUICConfig{
|
||||||
|
TLSConfig: tlsConf,
|
||||||
|
EnableSessionEvents: true,
|
||||||
|
})
|
||||||
return cs
|
return cs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,11 +182,10 @@ func (h *cryptoSetup) StartHandshake(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
ev := h.conn.NextEvent()
|
ev := h.conn.NextEvent()
|
||||||
done, err := h.handleEvent(ev)
|
if err := h.handleEvent(ev); err != nil {
|
||||||
if err != nil {
|
|
||||||
return wrapError(err)
|
return wrapError(err)
|
||||||
}
|
}
|
||||||
if done {
|
if ev.Kind == tls.QUICNoEvent {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,53 +216,78 @@ func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLev
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *cryptoSetup) handleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
|
func (h *cryptoSetup) handleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
|
||||||
if err := h.conn.HandleData(qtls.ToTLSEncryptionLevel(encLevel), data); err != nil {
|
if err := h.conn.HandleData(encLevel.ToTLSEncryptionLevel(), data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
ev := h.conn.NextEvent()
|
ev := h.conn.NextEvent()
|
||||||
done, err := h.handleEvent(ev)
|
if err := h.handleEvent(ev); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if done {
|
if ev.Kind == tls.QUICNoEvent {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *cryptoSetup) handleEvent(ev tls.QUICEvent) (done bool, err error) {
|
func (h *cryptoSetup) handleEvent(ev tls.QUICEvent) (err error) {
|
||||||
//nolint:exhaustive
|
|
||||||
// Go 1.23 added new 0-RTT events, see https://github.com/quic-go/quic-go/issues/4272.
|
|
||||||
// We will start using these events when dropping support for Go 1.22.
|
|
||||||
switch ev.Kind {
|
switch ev.Kind {
|
||||||
case tls.QUICNoEvent:
|
case tls.QUICNoEvent:
|
||||||
return true, nil
|
return nil
|
||||||
case tls.QUICSetReadSecret:
|
case tls.QUICSetReadSecret:
|
||||||
h.setReadKey(ev.Level, ev.Suite, ev.Data)
|
h.setReadKey(ev.Level, ev.Suite, ev.Data)
|
||||||
return false, nil
|
return nil
|
||||||
case tls.QUICSetWriteSecret:
|
case tls.QUICSetWriteSecret:
|
||||||
h.setWriteKey(ev.Level, ev.Suite, ev.Data)
|
h.setWriteKey(ev.Level, ev.Suite, ev.Data)
|
||||||
return false, nil
|
return nil
|
||||||
case tls.QUICTransportParameters:
|
case tls.QUICTransportParameters:
|
||||||
return false, h.handleTransportParameters(ev.Data)
|
return h.handleTransportParameters(ev.Data)
|
||||||
case tls.QUICTransportParametersRequired:
|
case tls.QUICTransportParametersRequired:
|
||||||
h.conn.SetTransportParameters(h.ourParams.Marshal(h.perspective))
|
h.conn.SetTransportParameters(h.ourParams.Marshal(h.perspective))
|
||||||
return false, nil
|
return nil
|
||||||
case tls.QUICRejectedEarlyData:
|
case tls.QUICRejectedEarlyData:
|
||||||
h.rejected0RTT()
|
h.rejected0RTT()
|
||||||
return false, nil
|
return nil
|
||||||
case tls.QUICWriteData:
|
case tls.QUICWriteData:
|
||||||
h.writeRecord(ev.Level, ev.Data)
|
h.writeRecord(ev.Level, ev.Data)
|
||||||
return false, nil
|
return nil
|
||||||
case tls.QUICHandshakeDone:
|
case tls.QUICHandshakeDone:
|
||||||
h.handshakeComplete()
|
h.handshakeComplete()
|
||||||
return false, nil
|
return nil
|
||||||
|
case tls.QUICStoreSession:
|
||||||
|
if h.perspective == protocol.PerspectiveServer {
|
||||||
|
panic("cryptoSetup BUG: unexpected QUICStoreSession event for the server")
|
||||||
|
}
|
||||||
|
ev.SessionState.Extra = append(
|
||||||
|
ev.SessionState.Extra,
|
||||||
|
addSessionStateExtraPrefix(h.marshalDataForSessionState(ev.SessionState.EarlyData)),
|
||||||
|
)
|
||||||
|
return h.conn.StoreSession(ev.SessionState)
|
||||||
|
case tls.QUICResumeSession:
|
||||||
|
var allowEarlyData bool
|
||||||
|
switch h.perspective {
|
||||||
|
case protocol.PerspectiveClient:
|
||||||
|
// for clients, this event occurs when a session ticket is selected
|
||||||
|
allowEarlyData = h.handleDataFromSessionState(
|
||||||
|
findSessionStateExtraData(ev.SessionState.Extra),
|
||||||
|
ev.SessionState.EarlyData,
|
||||||
|
)
|
||||||
|
case protocol.PerspectiveServer:
|
||||||
|
// for servers, this event occurs when receiving the client's session ticket
|
||||||
|
allowEarlyData = h.handleSessionTicket(
|
||||||
|
findSessionStateExtraData(ev.SessionState.Extra),
|
||||||
|
ev.SessionState.EarlyData,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if ev.SessionState.EarlyData {
|
||||||
|
ev.SessionState.EarlyData = allowEarlyData
|
||||||
|
}
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
// Unknown events should be ignored.
|
// Unknown events should be ignored.
|
||||||
// crypto/tls will ensure that this is safe to do.
|
// crypto/tls will ensure that this is safe to do.
|
||||||
// See the discussion following https://github.com/golang/go/issues/68124#issuecomment-2187042510 for details.
|
// See the discussion following https://github.com/golang/go/issues/68124#issuecomment-2187042510 for details.
|
||||||
return false, nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,7 +378,10 @@ func (h *cryptoSetup) getDataForSessionTicket() []byte {
|
||||||
// Due to limitations in crypto/tls, it's only possible to generate a single session ticket per connection.
|
// 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.
|
// It is only valid for the server.
|
||||||
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
||||||
if err := h.conn.SendSessionTicket(tls.QUICSessionTicketOptions{EarlyData: h.allow0RTT}); err != nil {
|
if err := h.conn.SendSessionTicket(tls.QUICSessionTicketOptions{
|
||||||
|
EarlyData: h.allow0RTT,
|
||||||
|
Extra: [][]byte{addSessionStateExtraPrefix(h.getDataForSessionTicket())},
|
||||||
|
}); err != nil {
|
||||||
// Session tickets might be disabled by tls.Config.SessionTicketsDisabled.
|
// 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
|
// We can't check h.tlsConfig here, since the actual config might have been obtained from
|
||||||
// the GetConfigForClient callback.
|
// the GetConfigForClient callback.
|
||||||
|
@ -376,9 +407,9 @@ func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
||||||
// It reads parameters from the session ticket and checks whether to accept 0-RTT if the session ticket enabled 0-RTT.
|
// 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:
|
// 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.
|
// 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 {
|
func (h *cryptoSetup) handleSessionTicket(data []byte, using0RTT bool) (allowEarlyData bool) {
|
||||||
var t sessionTicket
|
var t sessionTicket
|
||||||
if err := t.Unmarshal(sessionTicketData, using0RTT); err != nil {
|
if err := t.Unmarshal(data, using0RTT); err != nil {
|
||||||
h.logger.Debugf("Unmarshalling session ticket failed: %s", err.Error())
|
h.logger.Debugf("Unmarshalling session ticket failed: %s", err.Error())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -446,7 +477,7 @@ func (h *cryptoSetup) setReadKey(el tls.QUICEncryptionLevel, suiteID uint16, tra
|
||||||
}
|
}
|
||||||
h.events = append(h.events, Event{Kind: EventReceivedReadKeys})
|
h.events = append(h.events, Event{Kind: EventReceivedReadKeys})
|
||||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||||
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective.Opposite())
|
h.tracer.UpdatedKeyFromTLS(protocol.FromTLSEncryptionLevel(el), h.perspective.Opposite())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +528,7 @@ func (h *cryptoSetup) setWriteKey(el tls.QUICEncryptionLevel, suiteID uint16, tr
|
||||||
panic("unexpected write encryption level")
|
panic("unexpected write encryption level")
|
||||||
}
|
}
|
||||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||||
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective)
|
h.tracer.UpdatedKeyFromTLS(protocol.FromTLSEncryptionLevel(el), h.perspective)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package qtls
|
package handshake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
2
vendor/github.com/quic-go/quic-go/internal/handshake/hkdf.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/handshake/hkdf.go
generated
vendored
|
@ -8,8 +8,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// hkdfExpandLabel HKDF expands a label as defined in RFC 8446, section 7.1.
|
// hkdfExpandLabel HKDF expands a label as defined in RFC 8446, section 7.1.
|
||||||
// Since this implementation avoids using a cryptobyte.Builder, it is about 15% faster than the
|
|
||||||
// hkdfExpandLabel in the standard library.
|
|
||||||
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
|
func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
|
||||||
b := make([]byte, 3, 3+6+len(label)+1+len(context))
|
b := make([]byte, 3, 3+6+len(label)+1+len(context))
|
||||||
binary.BigEndian.PutUint16(b, uint16(length))
|
binary.BigEndian.PutUint16(b, uint16(length))
|
||||||
|
|
18
vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
generated
vendored
18
vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
generated
vendored
|
@ -1,6 +1,7 @@
|
||||||
package handshake
|
package handshake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
@ -52,3 +53,20 @@ func (t *sessionTicket) Unmarshal(b []byte, using0RTT bool) error {
|
||||||
t.RTT = time.Duration(rtt) * time.Microsecond
|
t.RTT = time.Duration(rtt) * time.Microsecond
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const extraPrefix = "quic-go1"
|
||||||
|
|
||||||
|
func addSessionStateExtraPrefix(b []byte) []byte {
|
||||||
|
return append([]byte(extraPrefix), b...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findSessionStateExtraData(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
|
||||||
|
}
|
||||||
|
|
39
vendor/github.com/quic-go/quic-go/internal/handshake/tls_config.go
generated
vendored
Normal file
39
vendor/github.com/quic-go/quic-go/internal/handshake/tls_config.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package handshake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupConfigForServer(conf *tls.Config, localAddr, remoteAddr net.Addr) *tls.Config {
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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 {
|
||||||
|
// we're returning a tls.Config here, so we need to apply this recursively
|
||||||
|
c = setupConfigForServer(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conf
|
||||||
|
}
|
35
vendor/github.com/quic-go/quic-go/internal/protocol/encryption_level.go
generated
vendored
35
vendor/github.com/quic-go/quic-go/internal/protocol/encryption_level.go
generated
vendored
|
@ -1,5 +1,10 @@
|
||||||
package protocol
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// EncryptionLevel is the encryption level
|
// EncryptionLevel is the encryption level
|
||||||
// Default value is Unencrypted
|
// Default value is Unencrypted
|
||||||
type EncryptionLevel uint8
|
type EncryptionLevel uint8
|
||||||
|
@ -28,3 +33,33 @@ func (e EncryptionLevel) String() string {
|
||||||
}
|
}
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e EncryptionLevel) ToTLSEncryptionLevel() tls.QUICEncryptionLevel {
|
||||||
|
switch e {
|
||||||
|
case EncryptionInitial:
|
||||||
|
return tls.QUICEncryptionLevelInitial
|
||||||
|
case EncryptionHandshake:
|
||||||
|
return tls.QUICEncryptionLevelHandshake
|
||||||
|
case Encryption1RTT:
|
||||||
|
return tls.QUICEncryptionLevelApplication
|
||||||
|
case Encryption0RTT:
|
||||||
|
return tls.QUICEncryptionLevelEarly
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unexpected encryption level: %s", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromTLSEncryptionLevel(e tls.QUICEncryptionLevel) EncryptionLevel {
|
||||||
|
switch e {
|
||||||
|
case tls.QUICEncryptionLevelInitial:
|
||||||
|
return EncryptionInitial
|
||||||
|
case tls.QUICEncryptionLevelHandshake:
|
||||||
|
return EncryptionHandshake
|
||||||
|
case tls.QUICEncryptionLevelApplication:
|
||||||
|
return Encryption1RTT
|
||||||
|
case tls.QUICEncryptionLevelEarly:
|
||||||
|
return Encryption0RTT
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unexpect encryption level: %s", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
52
vendor/github.com/quic-go/quic-go/internal/qtls/cipher_suite.go
generated
vendored
52
vendor/github.com/quic-go/quic-go/internal/qtls/cipher_suite.go
generated
vendored
|
@ -1,52 +0,0 @@
|
||||||
package qtls
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
//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
|
|
||||||
}
|
|
||||||
}
|
|
70
vendor/github.com/quic-go/quic-go/internal/qtls/client_session_cache.go
generated
vendored
70
vendor/github.com/quic-go/quic-go/internal/qtls/client_session_cache.go
generated
vendored
|
@ -1,70 +0,0 @@
|
||||||
package qtls
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type clientSessionCache struct {
|
|
||||||
mx sync.Mutex
|
|
||||||
getData func(earlyData bool) []byte
|
|
||||||
setData func(data []byte, earlyData bool) (allowEarlyData bool)
|
|
||||||
wrapped tls.ClientSessionCache
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ tls.ClientSessionCache = &clientSessionCache{}
|
|
||||||
|
|
||||||
func (c *clientSessionCache) Put(key string, cs *tls.ClientSessionState) {
|
|
||||||
c.mx.Lock()
|
|
||||||
defer c.mx.Unlock()
|
|
||||||
|
|
||||||
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(state.EarlyData)))
|
|
||||||
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) {
|
|
||||||
c.mx.Lock()
|
|
||||||
defer c.mx.Unlock()
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
// restore QUIC transport parameters and RTT stored in state.Extra
|
|
||||||
if extra := findExtraData(state.Extra); extra != nil {
|
|
||||||
earlyData := c.setData(extra, state.EarlyData)
|
|
||||||
if state.EarlyData {
|
|
||||||
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
|
|
||||||
}
|
|
150
vendor/github.com/quic-go/quic-go/internal/qtls/qtls.go
generated
vendored
150
vendor/github.com/quic-go/quic-go/internal/qtls/qtls.go
generated
vendored
|
@ -1,150 +0,0 @@
|
||||||
package qtls
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/quic-go/quic-go/internal/protocol"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetupConfigForServer(
|
|
||||||
conf *tls.Config,
|
|
||||||
localAddr, remoteAddr net.Addr,
|
|
||||||
getData func() []byte,
|
|
||||||
handleSessionTicket func([]byte, bool) bool,
|
|
||||||
) *tls.Config {
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
// 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.
|
|
||||||
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 {
|
|
||||||
// We're returning a tls.Config here, so we need to apply this recursively.
|
|
||||||
c = SetupConfigForServer(c, localAddr, remoteAddr, getData, handleSessionTicket)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conf
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetupConfigForClient(
|
|
||||||
qconf *tls.QUICConfig,
|
|
||||||
getData func(earlyData bool) []byte,
|
|
||||||
setData func(data []byte, earlyData bool) (allowEarlyData 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
|
|
||||||
}
|
|
9
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
9
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
|
@ -108,3 +108,12 @@ func (r *RTTStats) SetInitialRTT(t time.Duration) {
|
||||||
r.smoothedRTT = t
|
r.smoothedRTT = t
|
||||||
r.latestRTT = t
|
r.latestRTT = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RTTStats) ResetForPathMigration() {
|
||||||
|
r.hasMeasurement = false
|
||||||
|
r.minRTT = 0
|
||||||
|
r.latestRTT = 0
|
||||||
|
r.smoothedRTT = 0
|
||||||
|
r.meanDeviation = 0
|
||||||
|
// max_ack_delay remains valid
|
||||||
|
}
|
||||||
|
|
4
vendor/github.com/quic-go/quic-go/logging/types.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/logging/types.go
generated
vendored
|
@ -63,9 +63,11 @@ type TimerType uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TimerTypeACK is the timer type for the early retransmit timer
|
// TimerTypeACK is the timer type for the early retransmit timer
|
||||||
TimerTypeACK TimerType = iota
|
TimerTypeACK TimerType = iota + 1
|
||||||
// TimerTypePTO is the timer type for the PTO retransmit timer
|
// TimerTypePTO is the timer type for the PTO retransmit timer
|
||||||
TimerTypePTO
|
TimerTypePTO
|
||||||
|
// TimerTypePathProbe is the timer type for the path probe retransmit timer
|
||||||
|
TimerTypePathProbe
|
||||||
)
|
)
|
||||||
|
|
||||||
// TimeoutReason is the reason why a connection is closed
|
// TimeoutReason is the reason why a connection is closed
|
||||||
|
|
43
vendor/github.com/quic-go/quic-go/mtu_discoverer.go
generated
vendored
43
vendor/github.com/quic-go/quic-go/mtu_discoverer.go
generated
vendored
|
@ -17,6 +17,7 @@ type mtuDiscoverer interface {
|
||||||
ShouldSendProbe(now time.Time) bool
|
ShouldSendProbe(now time.Time) bool
|
||||||
CurrentSize() protocol.ByteCount
|
CurrentSize() protocol.ByteCount
|
||||||
GetPing(now time.Time) (ping ackhandler.Frame, datagramSize protocol.ByteCount)
|
GetPing(now time.Time) (ping ackhandler.Frame, datagramSize protocol.ByteCount)
|
||||||
|
Reset(now time.Time, start, max protocol.ByteCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -88,7 +89,6 @@ const (
|
||||||
|
|
||||||
type mtuFinder struct {
|
type mtuFinder struct {
|
||||||
lastProbeTime time.Time
|
lastProbeTime time.Time
|
||||||
mtuIncreased func(protocol.ByteCount)
|
|
||||||
|
|
||||||
rttStats *utils.RTTStats
|
rttStats *utils.RTTStats
|
||||||
|
|
||||||
|
@ -99,6 +99,11 @@ type mtuFinder struct {
|
||||||
lost [maxLostMTUProbes]protocol.ByteCount
|
lost [maxLostMTUProbes]protocol.ByteCount
|
||||||
lastProbeWasLost bool
|
lastProbeWasLost bool
|
||||||
|
|
||||||
|
// The generation is used to ignore ACKs / losses for probe packets sent before a reset.
|
||||||
|
// Resets happen when the connection is migrated to a new path.
|
||||||
|
// We're therefore not concerned about overflows of this counter.
|
||||||
|
generation uint8
|
||||||
|
|
||||||
tracer *logging.ConnectionTracer
|
tracer *logging.ConnectionTracer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,16 +112,19 @@ var _ mtuDiscoverer = &mtuFinder{}
|
||||||
func newMTUDiscoverer(
|
func newMTUDiscoverer(
|
||||||
rttStats *utils.RTTStats,
|
rttStats *utils.RTTStats,
|
||||||
start, max protocol.ByteCount,
|
start, max protocol.ByteCount,
|
||||||
mtuIncreased func(protocol.ByteCount),
|
|
||||||
tracer *logging.ConnectionTracer,
|
tracer *logging.ConnectionTracer,
|
||||||
) *mtuFinder {
|
) *mtuFinder {
|
||||||
f := &mtuFinder{
|
f := &mtuFinder{
|
||||||
inFlight: protocol.InvalidByteCount,
|
inFlight: protocol.InvalidByteCount,
|
||||||
min: start,
|
rttStats: rttStats,
|
||||||
rttStats: rttStats,
|
tracer: tracer,
|
||||||
mtuIncreased: mtuIncreased,
|
|
||||||
tracer: tracer,
|
|
||||||
}
|
}
|
||||||
|
f.init(start, max)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *mtuFinder) init(start, max protocol.ByteCount) {
|
||||||
|
f.min = start
|
||||||
for i := range f.lost {
|
for i := range f.lost {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
f.lost[i] = max
|
f.lost[i] = max
|
||||||
|
@ -124,7 +132,6 @@ func newMTUDiscoverer(
|
||||||
}
|
}
|
||||||
f.lost[i] = protocol.InvalidByteCount
|
f.lost[i] = protocol.InvalidByteCount
|
||||||
}
|
}
|
||||||
return f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *mtuFinder) done() bool {
|
func (f *mtuFinder) done() bool {
|
||||||
|
@ -165,7 +172,7 @@ func (f *mtuFinder) GetPing(now time.Time) (ackhandler.Frame, protocol.ByteCount
|
||||||
f.inFlight = size
|
f.inFlight = size
|
||||||
return ackhandler.Frame{
|
return ackhandler.Frame{
|
||||||
Frame: &wire.PingFrame{},
|
Frame: &wire.PingFrame{},
|
||||||
Handler: &mtuFinderAckHandler{f},
|
Handler: &mtuFinderAckHandler{mtuFinder: f, generation: f.generation},
|
||||||
}, size
|
}, size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,13 +180,26 @@ func (f *mtuFinder) CurrentSize() protocol.ByteCount {
|
||||||
return f.min
|
return f.min
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *mtuFinder) Reset(now time.Time, start, max protocol.ByteCount) {
|
||||||
|
f.generation++
|
||||||
|
f.lastProbeTime = now
|
||||||
|
f.lastProbeWasLost = false
|
||||||
|
f.inFlight = protocol.InvalidByteCount
|
||||||
|
f.init(start, max)
|
||||||
|
}
|
||||||
|
|
||||||
type mtuFinderAckHandler struct {
|
type mtuFinderAckHandler struct {
|
||||||
*mtuFinder
|
*mtuFinder
|
||||||
|
generation uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ackhandler.FrameHandler = &mtuFinderAckHandler{}
|
var _ ackhandler.FrameHandler = &mtuFinderAckHandler{}
|
||||||
|
|
||||||
func (h *mtuFinderAckHandler) OnAcked(wire.Frame) {
|
func (h *mtuFinderAckHandler) OnAcked(wire.Frame) {
|
||||||
|
if h.generation != h.mtuFinder.generation {
|
||||||
|
// ACK for probe sent before reset
|
||||||
|
return
|
||||||
|
}
|
||||||
size := h.inFlight
|
size := h.inFlight
|
||||||
if size == protocol.InvalidByteCount {
|
if size == protocol.InvalidByteCount {
|
||||||
panic("OnAcked callback called although there's no MTU probe packet in flight")
|
panic("OnAcked callback called although there's no MTU probe packet in flight")
|
||||||
|
@ -207,10 +227,13 @@ func (h *mtuFinderAckHandler) OnAcked(wire.Frame) {
|
||||||
if h.tracer != nil && h.tracer.UpdatedMTU != nil {
|
if h.tracer != nil && h.tracer.UpdatedMTU != nil {
|
||||||
h.tracer.UpdatedMTU(size, h.done())
|
h.tracer.UpdatedMTU(size, h.done())
|
||||||
}
|
}
|
||||||
h.mtuIncreased(size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *mtuFinderAckHandler) OnLost(wire.Frame) {
|
func (h *mtuFinderAckHandler) OnLost(wire.Frame) {
|
||||||
|
if h.generation != h.mtuFinder.generation {
|
||||||
|
// probe sent before reset received
|
||||||
|
return
|
||||||
|
}
|
||||||
size := h.inFlight
|
size := h.inFlight
|
||||||
if size == protocol.InvalidByteCount {
|
if size == protocol.InvalidByteCount {
|
||||||
panic("OnLost callback called although there's no MTU probe packet in flight")
|
panic("OnLost callback called although there's no MTU probe packet in flight")
|
||||||
|
|
36
vendor/github.com/quic-go/quic-go/packet_packer.go
generated
vendored
36
vendor/github.com/quic-go/quic-go/packet_packer.go
generated
vendored
|
@ -22,9 +22,10 @@ type packer interface {
|
||||||
PackCoalescedPacket(onlyAck bool, maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (*coalescedPacket, error)
|
PackCoalescedPacket(onlyAck bool, maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (*coalescedPacket, error)
|
||||||
PackAckOnlyPacket(maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)
|
PackAckOnlyPacket(maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)
|
||||||
AppendPacket(buf *packetBuffer, maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (shortHeaderPacket, error)
|
AppendPacket(buf *packetBuffer, maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (shortHeaderPacket, error)
|
||||||
MaybePackProbePacket(protocol.EncryptionLevel, protocol.ByteCount, time.Time, protocol.Version) (*coalescedPacket, error)
|
MaybePackPTOProbePacket(protocol.EncryptionLevel, protocol.ByteCount, time.Time, protocol.Version) (*coalescedPacket, error)
|
||||||
PackConnectionClose(*qerr.TransportError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
|
PackConnectionClose(*qerr.TransportError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
|
||||||
PackApplicationClose(*qerr.ApplicationError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
|
PackApplicationClose(*qerr.ApplicationError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
|
||||||
|
PackPathProbePacket(protocol.ConnectionID, ackhandler.Frame, protocol.Version) (shortHeaderPacket, *packetBuffer, error)
|
||||||
PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)
|
PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)
|
||||||
|
|
||||||
SetToken([]byte)
|
SetToken([]byte)
|
||||||
|
@ -57,6 +58,7 @@ type shortHeaderPacket struct {
|
||||||
Ack *wire.AckFrame
|
Ack *wire.AckFrame
|
||||||
Length protocol.ByteCount
|
Length protocol.ByteCount
|
||||||
IsPathMTUProbePacket bool
|
IsPathMTUProbePacket bool
|
||||||
|
IsPathProbePacket bool
|
||||||
|
|
||||||
// used for logging
|
// used for logging
|
||||||
DestConnID protocol.ConnectionID
|
DestConnID protocol.ConnectionID
|
||||||
|
@ -269,17 +271,17 @@ func (p *packetPacker) packConnectionClose(
|
||||||
if sealers[i] == nil {
|
if sealers[i] == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var paddingLen protocol.ByteCount
|
|
||||||
if encLevel == protocol.EncryptionInitial {
|
|
||||||
paddingLen = p.initialPaddingLen(payloads[i].frames, size, maxPacketSize)
|
|
||||||
}
|
|
||||||
if encLevel == protocol.Encryption1RTT {
|
if encLevel == protocol.Encryption1RTT {
|
||||||
shp, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, keyPhase, payloads[i], paddingLen, maxPacketSize, sealers[i], false, v)
|
shp, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, keyPhase, payloads[i], 0, maxPacketSize, sealers[i], false, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
packet.shortHdrPacket = &shp
|
packet.shortHdrPacket = &shp
|
||||||
} else {
|
} else {
|
||||||
|
var paddingLen protocol.ByteCount
|
||||||
|
if encLevel == protocol.EncryptionInitial {
|
||||||
|
paddingLen = p.initialPaddingLen(payloads[i].frames, size, maxPacketSize)
|
||||||
|
}
|
||||||
longHdrPacket, err := p.appendLongHeaderPacket(buffer, hdrs[i], payloads[i], paddingLen, encLevel, sealers[i], v)
|
longHdrPacket, err := p.appendLongHeaderPacket(buffer, hdrs[i], payloads[i], paddingLen, encLevel, sealers[i], v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -707,7 +709,7 @@ func (p *packetPacker) composeNextPacket(
|
||||||
return pl
|
return pl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *packetPacker) MaybePackProbePacket(
|
func (p *packetPacker) MaybePackPTOProbePacket(
|
||||||
encLevel protocol.EncryptionLevel,
|
encLevel protocol.EncryptionLevel,
|
||||||
maxPacketSize protocol.ByteCount,
|
maxPacketSize protocol.ByteCount,
|
||||||
now time.Time,
|
now time.Time,
|
||||||
|
@ -792,6 +794,26 @@ func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.B
|
||||||
return packet, buffer, err
|
return packet, buffer, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *packetPacker) PackPathProbePacket(connID protocol.ConnectionID, f ackhandler.Frame, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) {
|
||||||
|
pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
|
||||||
|
buf := getPacketBuffer()
|
||||||
|
s, err := p.cryptoSetup.Get1RTTSealer()
|
||||||
|
if err != nil {
|
||||||
|
return shortHeaderPacket{}, nil, err
|
||||||
|
}
|
||||||
|
payload := payload{
|
||||||
|
frames: []ackhandler.Frame{f},
|
||||||
|
length: f.Frame.Length(v),
|
||||||
|
}
|
||||||
|
padding := protocol.MinInitialPacketSize - p.shortHeaderPacketLength(connID, pnLen, payload) - protocol.ByteCount(s.Overhead())
|
||||||
|
packet, err := p.appendShortHeaderPacket(buf, connID, pn, pnLen, s.KeyPhase(), payload, padding, protocol.MinInitialPacketSize, s, false, v)
|
||||||
|
if err != nil {
|
||||||
|
return shortHeaderPacket{}, nil, err
|
||||||
|
}
|
||||||
|
packet.IsPathProbePacket = true
|
||||||
|
return packet, buf, err
|
||||||
|
}
|
||||||
|
|
||||||
func (p *packetPacker) getLongHeader(encLevel protocol.EncryptionLevel, v protocol.Version) *wire.ExtendedHeader {
|
func (p *packetPacker) getLongHeader(encLevel protocol.EncryptionLevel, v protocol.Version) *wire.ExtendedHeader {
|
||||||
pn, pnLen := p.pnManager.PeekPacketNumber(encLevel)
|
pn, pnLen := p.pnManager.PeekPacketNumber(encLevel)
|
||||||
hdr := &wire.ExtendedHeader{
|
hdr := &wire.ExtendedHeader{
|
||||||
|
|
145
vendor/github.com/quic-go/quic-go/path_manager.go
generated
vendored
Normal file
145
vendor/github.com/quic-go/quic-go/path_manager.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
package quic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/quic-go/quic-go/internal/ackhandler"
|
||||||
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
|
"github.com/quic-go/quic-go/internal/utils"
|
||||||
|
"github.com/quic-go/quic-go/internal/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pathID int64
|
||||||
|
|
||||||
|
const maxPaths = 3
|
||||||
|
|
||||||
|
type path struct {
|
||||||
|
addr net.Addr
|
||||||
|
pathChallenge [8]byte
|
||||||
|
validated bool
|
||||||
|
rcvdNonProbing bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type pathManager struct {
|
||||||
|
nextPathID pathID
|
||||||
|
paths map[pathID]*path
|
||||||
|
|
||||||
|
getConnID func(pathID) (_ protocol.ConnectionID, ok bool)
|
||||||
|
retireConnID func(pathID)
|
||||||
|
|
||||||
|
logger utils.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPathManager(
|
||||||
|
getConnID func(pathID) (_ protocol.ConnectionID, ok bool),
|
||||||
|
retireConnID func(pathID),
|
||||||
|
logger utils.Logger,
|
||||||
|
) *pathManager {
|
||||||
|
return &pathManager{
|
||||||
|
paths: make(map[pathID]*path),
|
||||||
|
getConnID: getConnID,
|
||||||
|
retireConnID: retireConnID,
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a path challenge frame if one should be sent.
|
||||||
|
// May return nil.
|
||||||
|
func (pm *pathManager) HandlePacket(p receivedPacket, isNonProbing bool) (_ protocol.ConnectionID, _ ackhandler.Frame, shouldSwitch bool) {
|
||||||
|
for _, path := range pm.paths {
|
||||||
|
if addrsEqual(path.addr, p.remoteAddr) {
|
||||||
|
// already sent a PATH_CHALLENGE for this path
|
||||||
|
if isNonProbing {
|
||||||
|
path.rcvdNonProbing = true
|
||||||
|
}
|
||||||
|
if pm.logger.Debug() {
|
||||||
|
pm.logger.Debugf("received packet for path %s that was already probed, validated: %t", p.remoteAddr, path.validated)
|
||||||
|
}
|
||||||
|
return protocol.ConnectionID{}, ackhandler.Frame{}, path.validated && path.rcvdNonProbing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pm.paths) >= maxPaths {
|
||||||
|
if pm.logger.Debug() {
|
||||||
|
pm.logger.Debugf("received packet for previously unseen path %s, but already have %d paths", p.remoteAddr, len(pm.paths))
|
||||||
|
}
|
||||||
|
return protocol.ConnectionID{}, ackhandler.Frame{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// previously unseen path, initiate path validation by sending a PATH_CHALLENGE
|
||||||
|
connID, ok := pm.getConnID(pm.nextPathID)
|
||||||
|
if !ok {
|
||||||
|
pm.logger.Debugf("skipping validation of new path %s since no connection ID is available", p.remoteAddr)
|
||||||
|
return protocol.ConnectionID{}, ackhandler.Frame{}, false
|
||||||
|
}
|
||||||
|
var b [8]byte
|
||||||
|
rand.Read(b[:])
|
||||||
|
pm.paths[pm.nextPathID] = &path{
|
||||||
|
addr: p.remoteAddr,
|
||||||
|
pathChallenge: b,
|
||||||
|
rcvdNonProbing: isNonProbing,
|
||||||
|
}
|
||||||
|
pm.nextPathID++
|
||||||
|
frame := ackhandler.Frame{
|
||||||
|
Frame: &wire.PathChallengeFrame{Data: b},
|
||||||
|
Handler: (*pathManagerAckHandler)(pm),
|
||||||
|
}
|
||||||
|
pm.logger.Debugf("enqueueing PATH_CHALLENGE for new path %s", p.remoteAddr)
|
||||||
|
return connID, frame, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pm *pathManager) HandlePathResponseFrame(f *wire.PathResponseFrame) {
|
||||||
|
for _, p := range pm.paths {
|
||||||
|
if f.Data == p.pathChallenge {
|
||||||
|
// path validated
|
||||||
|
p.validated = true
|
||||||
|
pm.logger.Debugf("path %s validated", p.addr)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SwitchToPath is called when the connection switches to a new path
|
||||||
|
func (pm *pathManager) SwitchToPath(addr net.Addr) {
|
||||||
|
// retire all other paths
|
||||||
|
for id := range pm.paths {
|
||||||
|
if addrsEqual(pm.paths[id].addr, addr) {
|
||||||
|
pm.logger.Debugf("switching to path %d (%s)", id, addr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pm.retireConnID(id)
|
||||||
|
}
|
||||||
|
clear(pm.paths)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pathManagerAckHandler pathManager
|
||||||
|
|
||||||
|
var _ ackhandler.FrameHandler = &pathManagerAckHandler{}
|
||||||
|
|
||||||
|
// Acknowledging the frame doesn't validate the path, only receiving the PATH_RESPONSE does.
|
||||||
|
func (pm *pathManagerAckHandler) OnAcked(f wire.Frame) {}
|
||||||
|
|
||||||
|
func (pm *pathManagerAckHandler) OnLost(f wire.Frame) {
|
||||||
|
// TODO: retransmit the packet the first time it is lost
|
||||||
|
pc := f.(*wire.PathChallengeFrame)
|
||||||
|
for id, path := range pm.paths {
|
||||||
|
if path.pathChallenge == pc.Data {
|
||||||
|
delete(pm.paths, id)
|
||||||
|
pm.retireConnID(id)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addrsEqual(addr1, addr2 net.Addr) bool {
|
||||||
|
if addr1 == nil || addr2 == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
a1, ok1 := addr1.(*net.UDPAddr)
|
||||||
|
a2, ok2 := addr2.(*net.UDPAddr)
|
||||||
|
if ok1 && ok2 {
|
||||||
|
return a1.IP.Equal(a2.IP) && a1.Port == a2.Port
|
||||||
|
}
|
||||||
|
return addr1.String() == addr2.String()
|
||||||
|
}
|
50
vendor/github.com/quic-go/quic-go/send_conn.go
generated
vendored
50
vendor/github.com/quic-go/quic-go/send_conn.go
generated
vendored
|
@ -2,6 +2,7 @@ package quic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go/internal/protocol"
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
"github.com/quic-go/quic-go/internal/utils"
|
"github.com/quic-go/quic-go/internal/utils"
|
||||||
|
@ -10,22 +11,29 @@ import (
|
||||||
// A sendConn allows sending using a simple Write() on a non-connected packet conn.
|
// A sendConn allows sending using a simple Write() on a non-connected packet conn.
|
||||||
type sendConn interface {
|
type sendConn interface {
|
||||||
Write(b []byte, gsoSize uint16, ecn protocol.ECN) error
|
Write(b []byte, gsoSize uint16, ecn protocol.ECN) error
|
||||||
|
WriteTo([]byte, net.Addr) error
|
||||||
Close() error
|
Close() error
|
||||||
LocalAddr() net.Addr
|
LocalAddr() net.Addr
|
||||||
RemoteAddr() net.Addr
|
RemoteAddr() net.Addr
|
||||||
|
ChangeRemoteAddr(addr net.Addr, info packetInfo)
|
||||||
|
|
||||||
capabilities() connCapabilities
|
capabilities() connCapabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type remoteAddrInfo struct {
|
||||||
|
addr net.Addr
|
||||||
|
oob []byte
|
||||||
|
}
|
||||||
|
|
||||||
type sconn struct {
|
type sconn struct {
|
||||||
rawConn
|
rawConn
|
||||||
|
|
||||||
localAddr net.Addr
|
localAddr net.Addr
|
||||||
remoteAddr net.Addr
|
|
||||||
|
remoteAddrInfo atomic.Pointer[remoteAddrInfo]
|
||||||
|
|
||||||
logger utils.Logger
|
logger utils.Logger
|
||||||
|
|
||||||
packetInfoOOB []byte
|
|
||||||
// If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled.
|
// If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled.
|
||||||
gotGSOError bool
|
gotGSOError bool
|
||||||
// Used to catch the error sometimes returned by the first sendmsg call on Linux,
|
// Used to catch the error sometimes returned by the first sendmsg call on Linux,
|
||||||
|
@ -49,22 +57,26 @@ func newSendConn(c rawConn, remote net.Addr, info packetInfo, logger utils.Logge
|
||||||
// increase oob slice capacity, so we can add the UDP_SEGMENT and ECN control messages without allocating
|
// increase oob slice capacity, so we can add the UDP_SEGMENT and ECN control messages without allocating
|
||||||
l := len(oob)
|
l := len(oob)
|
||||||
oob = append(oob, make([]byte, 64)...)[:l]
|
oob = append(oob, make([]byte, 64)...)[:l]
|
||||||
return &sconn{
|
sc := &sconn{
|
||||||
rawConn: c,
|
rawConn: c,
|
||||||
localAddr: localAddr,
|
localAddr: localAddr,
|
||||||
remoteAddr: remote,
|
logger: logger,
|
||||||
packetInfoOOB: oob,
|
|
||||||
logger: logger,
|
|
||||||
}
|
}
|
||||||
|
sc.remoteAddrInfo.Store(&remoteAddrInfo{
|
||||||
|
addr: remote,
|
||||||
|
oob: oob,
|
||||||
|
})
|
||||||
|
return sc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
|
func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
|
||||||
err := c.writePacket(p, c.remoteAddr, c.packetInfoOOB, gsoSize, ecn)
|
ai := c.remoteAddrInfo.Load()
|
||||||
|
err := c.writePacket(p, ai.addr, ai.oob, gsoSize, ecn)
|
||||||
if err != nil && isGSOError(err) {
|
if err != nil && isGSOError(err) {
|
||||||
// disable GSO for future calls
|
// disable GSO for future calls
|
||||||
c.gotGSOError = true
|
c.gotGSOError = true
|
||||||
if c.logger.Debug() {
|
if c.logger.Debug() {
|
||||||
c.logger.Debugf("GSO failed when sending to %s", c.remoteAddr)
|
c.logger.Debugf("GSO failed when sending to %s", ai.addr)
|
||||||
}
|
}
|
||||||
// send out the packets one by one
|
// send out the packets one by one
|
||||||
for len(p) > 0 {
|
for len(p) > 0 {
|
||||||
|
@ -72,7 +84,7 @@ func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
|
||||||
if l > int(gsoSize) {
|
if l > int(gsoSize) {
|
||||||
l = int(gsoSize)
|
l = int(gsoSize)
|
||||||
}
|
}
|
||||||
if err := c.writePacket(p[:l], c.remoteAddr, c.packetInfoOOB, 0, ecn); err != nil {
|
if err := c.writePacket(p[:l], ai.addr, ai.oob, 0, ecn); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p = p[l:]
|
p = p[l:]
|
||||||
|
@ -91,6 +103,11 @@ func (c *sconn) writePacket(p []byte, addr net.Addr, oob []byte, gsoSize uint16,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *sconn) WriteTo(b []byte, addr net.Addr) error {
|
||||||
|
_, err := c.WritePacket(b, addr, nil, 0, protocol.ECNUnsupported)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *sconn) capabilities() connCapabilities {
|
func (c *sconn) capabilities() connCapabilities {
|
||||||
capabilities := c.rawConn.capabilities()
|
capabilities := c.rawConn.capabilities()
|
||||||
if capabilities.GSO {
|
if capabilities.GSO {
|
||||||
|
@ -99,5 +116,12 @@ func (c *sconn) capabilities() connCapabilities {
|
||||||
return capabilities
|
return capabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sconn) RemoteAddr() net.Addr { return c.remoteAddr }
|
func (c *sconn) ChangeRemoteAddr(addr net.Addr, info packetInfo) {
|
||||||
|
c.remoteAddrInfo.Store(&remoteAddrInfo{
|
||||||
|
addr: addr,
|
||||||
|
oob: info.OOB(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *sconn) RemoteAddr() net.Addr { return c.remoteAddrInfo.Load().addr }
|
||||||
func (c *sconn) LocalAddr() net.Addr { return c.localAddr }
|
func (c *sconn) LocalAddr() net.Addr { return c.localAddr }
|
||||||
|
|
11
vendor/github.com/quic-go/quic-go/send_queue.go
generated
vendored
11
vendor/github.com/quic-go/quic-go/send_queue.go
generated
vendored
|
@ -1,9 +1,14 @@
|
||||||
package quic
|
package quic
|
||||||
|
|
||||||
import "github.com/quic-go/quic-go/internal/protocol"
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
type sender interface {
|
type sender interface {
|
||||||
Send(p *packetBuffer, gsoSize uint16, ecn protocol.ECN)
|
Send(p *packetBuffer, gsoSize uint16, ecn protocol.ECN)
|
||||||
|
SendProbe(*packetBuffer, net.Addr)
|
||||||
Run() error
|
Run() error
|
||||||
WouldBlock() bool
|
WouldBlock() bool
|
||||||
Available() <-chan struct{}
|
Available() <-chan struct{}
|
||||||
|
@ -57,6 +62,10 @@ func (h *sendQueue) Send(p *packetBuffer, gsoSize uint16, ecn protocol.ECN) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *sendQueue) SendProbe(p *packetBuffer, addr net.Addr) {
|
||||||
|
h.conn.WriteTo(p.Data, addr)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *sendQueue) WouldBlock() bool {
|
func (h *sendQueue) WouldBlock() bool {
|
||||||
return len(h.queue) == sendQueueCapacity
|
return len(h.queue) == sendQueueCapacity
|
||||||
}
|
}
|
||||||
|
|
5
vendor/modules.txt
vendored
5
vendor/modules.txt
vendored
|
@ -107,8 +107,8 @@ github.com/powerman/deepequal
|
||||||
# github.com/quic-go/qpack v0.5.1
|
# github.com/quic-go/qpack v0.5.1
|
||||||
## explicit; go 1.22
|
## explicit; go 1.22
|
||||||
github.com/quic-go/qpack
|
github.com/quic-go/qpack
|
||||||
# github.com/quic-go/quic-go v0.49.0
|
# github.com/quic-go/quic-go v0.50.0
|
||||||
## explicit; go 1.22
|
## explicit; go 1.23
|
||||||
github.com/quic-go/quic-go
|
github.com/quic-go/quic-go
|
||||||
github.com/quic-go/quic-go/http3
|
github.com/quic-go/quic-go/http3
|
||||||
github.com/quic-go/quic-go/internal/ackhandler
|
github.com/quic-go/quic-go/internal/ackhandler
|
||||||
|
@ -117,7 +117,6 @@ github.com/quic-go/quic-go/internal/flowcontrol
|
||||||
github.com/quic-go/quic-go/internal/handshake
|
github.com/quic-go/quic-go/internal/handshake
|
||||||
github.com/quic-go/quic-go/internal/protocol
|
github.com/quic-go/quic-go/internal/protocol
|
||||||
github.com/quic-go/quic-go/internal/qerr
|
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/internal/utils
|
||||||
github.com/quic-go/quic-go/internal/utils/linkedlist
|
github.com/quic-go/quic-go/internal/utils/linkedlist
|
||||||
github.com/quic-go/quic-go/internal/utils/ringbuffer
|
github.com/quic-go/quic-go/internal/utils/ringbuffer
|
||||||
|
|
Loading…
Add table
Reference in a new issue