forked from quic-go/quic-go
Merge pull request #3066 from lucas-clemente/zero-rtt-rejection
require the application to handle 0-RTT rejection
This commit is contained in:
@@ -169,15 +169,14 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
case protocol.EncryptionHandshake:
|
||||
h.handshakePackets = nil
|
||||
case protocol.Encryption0RTT:
|
||||
// TODO(#2067): invalidate sent data
|
||||
// This function is only called when 0-RTT is rejected,
|
||||
// and not when the client drops 0-RTT keys when the handshake completes.
|
||||
// When 0-RTT is rejected, all application data sent so far becomes invalid.
|
||||
// Delete the packets from the history and remove them from bytes_in_flight.
|
||||
h.appDataPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
if p.skippedPacket {
|
||||
return true, nil
|
||||
}
|
||||
if p.EncryptionLevel != protocol.Encryption0RTT {
|
||||
return false, nil
|
||||
}
|
||||
h.queueFramesForRetransmission(p)
|
||||
h.removeFromBytesInFlight(p)
|
||||
h.appDataPackets.history.Remove(p.PacketNumber)
|
||||
return true, nil
|
||||
|
||||
@@ -1078,8 +1078,7 @@ var _ = Describe("SentPacketHandler", func() {
|
||||
Expect(handler.handshakePackets).To(BeNil())
|
||||
})
|
||||
|
||||
// TODO(#2067): invalidate 0-RTT data when 0-RTT is rejected
|
||||
It("retransmits 0-RTT packets when 0-RTT keys are dropped", func() {
|
||||
It("doesn't retransmit 0-RTT packets when 0-RTT keys are dropped", func() {
|
||||
for i := protocol.PacketNumber(0); i < 6; i++ {
|
||||
if i == 3 {
|
||||
continue
|
||||
@@ -1094,7 +1093,7 @@ var _ = Describe("SentPacketHandler", func() {
|
||||
}
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11)))
|
||||
handler.DropPackets(protocol.Encryption0RTT)
|
||||
Expect(lostPackets).To(Equal([]protocol.PacketNumber{0, 1, 2, 4, 5}))
|
||||
Expect(lostPackets).To(BeEmpty())
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(6)))
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package flowcontrol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -86,3 +87,18 @@ func (c *connectionFlowController) EnsureMinimumWindowSize(inc protocol.ByteCoun
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
}
|
||||
|
||||
// The flow controller is reset when 0-RTT is rejected.
|
||||
// All stream data is invalidated, it's if we had never opened a stream and never sent any data.
|
||||
// At that point, we only have sent stream data, but we didn't have the keys to open 1-RTT keys yet.
|
||||
func (c *connectionFlowController) Reset() error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
if c.bytesRead > 0 || c.highestReceived > 0 || !c.epochStartTime.IsZero() {
|
||||
return errors.New("flow controller reset after reading data")
|
||||
}
|
||||
c.bytesSent = 0
|
||||
c.lastBlockedAt = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -129,4 +129,28 @@ var _ = Describe("Connection Flow controller", func() {
|
||||
Expect(controller.epochStartTime).To(BeTemporally("~", time.Now(), 100*time.Millisecond))
|
||||
})
|
||||
})
|
||||
|
||||
Context("resetting", func() {
|
||||
It("resets", func() {
|
||||
const initialWindow protocol.ByteCount = 1337
|
||||
controller.UpdateSendWindow(initialWindow)
|
||||
controller.AddBytesSent(1000)
|
||||
Expect(controller.SendWindowSize()).To(Equal(initialWindow - 1000))
|
||||
Expect(controller.Reset()).To(Succeed())
|
||||
Expect(controller.SendWindowSize()).To(Equal(initialWindow))
|
||||
})
|
||||
|
||||
It("says if is blocked after resetting", func() {
|
||||
const initialWindow protocol.ByteCount = 1337
|
||||
controller.UpdateSendWindow(initialWindow)
|
||||
controller.AddBytesSent(initialWindow)
|
||||
blocked, _ := controller.IsNewlyBlocked()
|
||||
Expect(blocked).To(BeTrue())
|
||||
Expect(controller.Reset()).To(Succeed())
|
||||
controller.AddBytesSent(initialWindow)
|
||||
blocked, blockedAt := controller.IsNewlyBlocked()
|
||||
Expect(blocked).To(BeTrue())
|
||||
Expect(blockedAt).To(Equal(initialWindow))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -29,6 +29,7 @@ type StreamFlowController interface {
|
||||
// The ConnectionFlowController is the flow controller for the connection.
|
||||
type ConnectionFlowController interface {
|
||||
flowController
|
||||
Reset() error
|
||||
}
|
||||
|
||||
type connectionFlowControllerI interface {
|
||||
|
||||
@@ -87,6 +87,20 @@ func (mr *MockConnectionFlowControllerMockRecorder) IsNewlyBlocked() *gomock.Cal
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNewlyBlocked", reflect.TypeOf((*MockConnectionFlowController)(nil).IsNewlyBlocked))
|
||||
}
|
||||
|
||||
// Reset mocks base method.
|
||||
func (m *MockConnectionFlowController) Reset() error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Reset")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Reset indicates an expected call of Reset.
|
||||
func (mr *MockConnectionFlowControllerMockRecorder) Reset() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reset", reflect.TypeOf((*MockConnectionFlowController)(nil).Reset))
|
||||
}
|
||||
|
||||
// SendWindowSize mocks base method.
|
||||
func (m *MockConnectionFlowController) SendWindowSize() protocol.ByteCount {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -137,6 +137,20 @@ func (mr *MockEarlySessionMockRecorder) LocalAddr() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LocalAddr", reflect.TypeOf((*MockEarlySession)(nil).LocalAddr))
|
||||
}
|
||||
|
||||
// NextSession mocks base method.
|
||||
func (m *MockEarlySession) NextSession() quic.Session {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NextSession")
|
||||
ret0, _ := ret[0].(quic.Session)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// NextSession indicates an expected call of NextSession.
|
||||
func (mr *MockEarlySessionMockRecorder) NextSession() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NextSession", reflect.TypeOf((*MockEarlySession)(nil).NextSession))
|
||||
}
|
||||
|
||||
// OpenStream mocks base method.
|
||||
func (m *MockEarlySession) OpenStream() (quic.Stream, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
Reference in New Issue
Block a user