mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
implement packet pacing
This commit is contained in:
parent
c3cc35363b
commit
5ef89733ae
10 changed files with 153 additions and 50 deletions
|
@ -15,6 +15,7 @@ type SentPacketHandler interface {
|
|||
SetHandshakeComplete()
|
||||
|
||||
SendingAllowed() bool
|
||||
TimeUntilSend() time.Time
|
||||
GetStopWaitingFrame(force bool) *wire.StopWaitingFrame
|
||||
GetLowestPacketNotConfirmedAcked() protocol.PacketNumber
|
||||
ShouldSendRetransmittablePacket() bool
|
||||
|
|
|
@ -34,6 +34,7 @@ var ErrDuplicateOrOutOfOrderAck = errors.New("SentPacketHandler: Duplicate or ou
|
|||
|
||||
type sentPacketHandler struct {
|
||||
lastSentPacketNumber protocol.PacketNumber
|
||||
lastPacketSentTime time.Time
|
||||
skippedPackets []protocol.PacketNumber
|
||||
|
||||
numNonRetransmittablePackets int // number of non-retransmittable packets since the last retransmittable packet
|
||||
|
@ -122,8 +123,9 @@ func (h *sentPacketHandler) SentPacket(packet *Packet) error {
|
|||
}
|
||||
}
|
||||
|
||||
h.lastSentPacketNumber = packet.PacketNumber
|
||||
now := time.Now()
|
||||
h.lastSentPacketNumber = packet.PacketNumber
|
||||
h.lastPacketSentTime = now
|
||||
|
||||
var largestAcked protocol.PacketNumber
|
||||
if len(packet.Frames) > 0 {
|
||||
|
@ -386,6 +388,10 @@ func (h *sentPacketHandler) SendingAllowed() bool {
|
|||
return !maxTrackedLimited && (!congestionLimited || haveRetransmissions)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) TimeUntilSend() time.Time {
|
||||
return h.lastPacketSentTime.Add(h.congestion.TimeUntilSend(h.bytesInFlight))
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) retransmitOldestTwoPackets() {
|
||||
if p := h.packetHistory.Front(); p != nil {
|
||||
h.queueRTO(p)
|
||||
|
|
|
@ -741,28 +741,36 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
})
|
||||
|
||||
It("allows or denies sending based on congestion", func() {
|
||||
Expect(handler.retransmissionQueue).To(BeEmpty())
|
||||
handler.bytesInFlight = 100
|
||||
cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount)
|
||||
cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(200))
|
||||
Expect(handler.SendingAllowed()).To(BeTrue())
|
||||
cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(0))
|
||||
cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(75))
|
||||
Expect(handler.SendingAllowed()).To(BeFalse())
|
||||
})
|
||||
|
||||
It("allows or denies sending based on the number of tracked packets", func() {
|
||||
cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount).AnyTimes()
|
||||
cong.EXPECT().GetCongestionWindow().Times(2)
|
||||
Expect(handler.SendingAllowed()).To(BeTrue())
|
||||
handler.retransmissionQueue = make([]*Packet, protocol.MaxTrackedSentPackets)
|
||||
Expect(handler.SendingAllowed()).To(BeFalse())
|
||||
})
|
||||
|
||||
It("allows sending if there are retransmisisons outstanding", func() {
|
||||
cong.EXPECT().GetCongestionWindow().Times(2)
|
||||
handler.bytesInFlight = 100
|
||||
cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(0)).AnyTimes()
|
||||
Expect(handler.retransmissionQueue).To(BeEmpty())
|
||||
Expect(handler.SendingAllowed()).To(BeFalse())
|
||||
handler.retransmissionQueue = []*Packet{nil}
|
||||
handler.retransmissionQueue = []*Packet{{PacketNumber: 3}}
|
||||
Expect(handler.SendingAllowed()).To(BeTrue())
|
||||
})
|
||||
|
||||
It("gets the pacing delay", func() {
|
||||
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any())
|
||||
handler.SentPacket(&Packet{PacketNumber: 1})
|
||||
handler.bytesInFlight = protocol.ByteCount(100)
|
||||
cong.EXPECT().TimeUntilSend(handler.bytesInFlight).Return(time.Hour)
|
||||
Expect(handler.TimeUntilSend()).To(BeTemporally("~", time.Now().Add(time.Hour), time.Second))
|
||||
})
|
||||
})
|
||||
|
||||
Context("calculating RTO", func() {
|
||||
|
|
|
@ -76,15 +76,19 @@ func NewCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestio
|
|||
}
|
||||
}
|
||||
|
||||
func (c *cubicSender) TimeUntilSend(now time.Time, bytesInFlight protocol.ByteCount) time.Duration {
|
||||
// TimeUntilSend returns when the next packet should be sent.
|
||||
func (c *cubicSender) TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration {
|
||||
if c.InRecovery() {
|
||||
// PRR is used when in recovery.
|
||||
return c.prr.TimeUntilSend(c.GetCongestionWindow(), bytesInFlight, c.GetSlowStartThreshold())
|
||||
if c.prr.TimeUntilSend(c.GetCongestionWindow(), bytesInFlight, c.GetSlowStartThreshold()) == 0 {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if c.GetCongestionWindow() > bytesInFlight {
|
||||
return 0
|
||||
delay := c.rttStats.SmoothedRTT() / time.Duration(2*c.GetCongestionWindow()/protocol.DefaultTCPMSS)
|
||||
if !c.InSlowStart() { // adjust delay, such that it's 1.25*cwd/rtt
|
||||
delay = delay * 8 / 5
|
||||
}
|
||||
return utils.InfDuration
|
||||
return delay
|
||||
}
|
||||
|
||||
func (c *cubicSender) OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool) bool {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
@ -43,15 +44,13 @@ var _ = Describe("Cubic Sender", func() {
|
|||
})
|
||||
|
||||
SendAvailableSendWindowLen := func(packetLength protocol.ByteCount) int {
|
||||
// Send as long as TimeUntilSend returns Zero.
|
||||
// Send as long as TimeUntilSend returns InfDuration.
|
||||
packets_sent := 0
|
||||
can_send := sender.TimeUntilSend(clock.Now(), bytesInFlight) == 0
|
||||
for can_send {
|
||||
for bytesInFlight < sender.GetCongestionWindow() {
|
||||
sender.OnPacketSent(clock.Now(), bytesInFlight, packetNumber, packetLength, true)
|
||||
packetNumber++
|
||||
packets_sent++
|
||||
bytesInFlight += packetLength
|
||||
can_send = sender.TimeUntilSend(clock.Now(), bytesInFlight) == 0
|
||||
}
|
||||
return packets_sent
|
||||
}
|
||||
|
@ -86,28 +85,34 @@ var _ = Describe("Cubic Sender", func() {
|
|||
AckNPackets := func(n int) { AckNPacketsLen(n, protocol.DefaultTCPMSS) }
|
||||
LoseNPackets := func(n int) { LoseNPacketsLen(n, protocol.DefaultTCPMSS) }
|
||||
|
||||
It("simpler sender", func() {
|
||||
It("has the right values at startup", func() {
|
||||
// At startup make sure we are at the default.
|
||||
Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP))
|
||||
// At startup make sure we can send.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), 0)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(0)).To(BeZero())
|
||||
// Make sure we can send.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), 0)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(0)).To(BeZero())
|
||||
// And that window is un-affected.
|
||||
Expect(sender.GetCongestionWindow()).To(Equal(defaultWindowTCP))
|
||||
})
|
||||
|
||||
It("paces", func() {
|
||||
clock.Advance(time.Hour)
|
||||
// Fill the send window with data, then verify that we can't send.
|
||||
SendAvailableSendWindow()
|
||||
Expect(sender.TimeUntilSend(clock.Now(), sender.GetCongestionWindow())).ToNot(BeZero())
|
||||
AckNPackets(1)
|
||||
delay := sender.TimeUntilSend(bytesInFlight)
|
||||
Expect(delay).ToNot(BeZero())
|
||||
Expect(delay).ToNot(Equal(utils.InfDuration))
|
||||
})
|
||||
|
||||
It("application limited slow start", func() {
|
||||
// Send exactly 10 packets and ensure the CWND ends at 14 packets.
|
||||
const kNumberOfAcks = 5
|
||||
// At startup make sure we can send.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), 0)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(0)).To(BeZero())
|
||||
// Make sure we can send.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), 0)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(0)).To(BeZero())
|
||||
|
||||
SendAvailableSendWindow()
|
||||
for i := 0; i < kNumberOfAcks; i++ {
|
||||
|
@ -122,10 +127,10 @@ var _ = Describe("Cubic Sender", func() {
|
|||
It("exponential slow start", func() {
|
||||
const kNumberOfAcks = 20
|
||||
// At startup make sure we can send.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), 0)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(0)).To(BeZero())
|
||||
Expect(sender.BandwidthEstimate()).To(BeZero())
|
||||
// Make sure we can send.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), 0)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(0)).To(BeZero())
|
||||
|
||||
for i := 0; i < kNumberOfAcks; i++ {
|
||||
// Send our full send window.
|
||||
|
@ -258,7 +263,8 @@ var _ = Describe("Cubic Sender", func() {
|
|||
Expect(sender.GetCongestionWindow()).To(Equal(expected_send_window))
|
||||
})
|
||||
|
||||
It("no PRR when less than one packet in flight", func() {
|
||||
// this test doesn't work any more after introducing the pacing needed for QUIC
|
||||
PIt("no PRR when less than one packet in flight", func() {
|
||||
SendAvailableSendWindow()
|
||||
LoseNPackets(int(initialCongestionWindowPackets) - 1)
|
||||
AckNPackets(1)
|
||||
|
@ -267,7 +273,7 @@ var _ = Describe("Cubic Sender", func() {
|
|||
// Simulate abandoning all packets by supplying a bytes_in_flight of 0.
|
||||
// PRR should now allow a packet to be sent, even though prr's state
|
||||
// variables believe it has sent enough packets.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), 0)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(0)).To(BeZero())
|
||||
})
|
||||
|
||||
It("slow start packet loss PRR", func() {
|
||||
|
@ -340,7 +346,7 @@ var _ = Describe("Cubic Sender", func() {
|
|||
LoseNPackets(int(num_packets_to_lose))
|
||||
// Immediately after the loss, ensure at least one packet can be sent.
|
||||
// Losses without subsequent acks can occur with timer based loss detection.
|
||||
Expect(sender.TimeUntilSend(clock.Now(), bytesInFlight)).To(BeZero())
|
||||
Expect(sender.TimeUntilSend(bytesInFlight)).To(BeZero())
|
||||
AckNPackets(1)
|
||||
|
||||
// We should now have fallen out of slow start with a reduced window.
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
// A SendAlgorithm performs congestion control and calculates the congestion window
|
||||
type SendAlgorithm interface {
|
||||
TimeUntilSend(now time.Time, bytesInFlight protocol.ByteCount) time.Duration
|
||||
TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration
|
||||
OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool) bool
|
||||
GetCongestionWindow() protocol.ByteCount
|
||||
MaybeExitSlowStart()
|
||||
|
|
|
@ -164,3 +164,15 @@ func (m *MockSentPacketHandler) ShouldSendRetransmittablePacket() bool {
|
|||
func (mr *MockSentPacketHandlerMockRecorder) ShouldSendRetransmittablePacket() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldSendRetransmittablePacket", reflect.TypeOf((*MockSentPacketHandler)(nil).ShouldSendRetransmittablePacket))
|
||||
}
|
||||
|
||||
// TimeUntilSend mocks base method
|
||||
func (m *MockSentPacketHandler) TimeUntilSend() time.Time {
|
||||
ret := m.ctrl.Call(m, "TimeUntilSend")
|
||||
ret0, _ := ret[0].(time.Time)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TimeUntilSend indicates an expected call of TimeUntilSend
|
||||
func (mr *MockSentPacketHandlerMockRecorder) TimeUntilSend() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TimeUntilSend", reflect.TypeOf((*MockSentPacketHandler)(nil).TimeUntilSend))
|
||||
}
|
||||
|
|
|
@ -142,13 +142,13 @@ func (mr *MockSendAlgorithmMockRecorder) SetSlowStartLargeReduction(arg0 interfa
|
|||
}
|
||||
|
||||
// TimeUntilSend mocks base method
|
||||
func (m *MockSendAlgorithm) TimeUntilSend(arg0 time.Time, arg1 protocol.ByteCount) time.Duration {
|
||||
ret := m.ctrl.Call(m, "TimeUntilSend", arg0, arg1)
|
||||
func (m *MockSendAlgorithm) TimeUntilSend(arg0 protocol.ByteCount) time.Duration {
|
||||
ret := m.ctrl.Call(m, "TimeUntilSend", arg0)
|
||||
ret0, _ := ret[0].(time.Duration)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TimeUntilSend indicates an expected call of TimeUntilSend
|
||||
func (mr *MockSendAlgorithmMockRecorder) TimeUntilSend(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TimeUntilSend", reflect.TypeOf((*MockSendAlgorithm)(nil).TimeUntilSend), arg0, arg1)
|
||||
func (mr *MockSendAlgorithmMockRecorder) TimeUntilSend(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TimeUntilSend", reflect.TypeOf((*MockSendAlgorithm)(nil).TimeUntilSend), arg0)
|
||||
}
|
||||
|
|
38
session.go
38
session.go
|
@ -114,6 +114,8 @@ type session struct {
|
|||
|
||||
sessionCreationTime time.Time
|
||||
lastNetworkActivityTime time.Time
|
||||
// pacingDeadline is the time when the next packet should be sent
|
||||
pacingDeadline time.Time
|
||||
|
||||
peerParams *handshake.TransportParameters
|
||||
|
||||
|
@ -355,6 +357,7 @@ func (s *session) run() error {
|
|||
|
||||
runLoop:
|
||||
for {
|
||||
|
||||
// Close immediately if requested
|
||||
select {
|
||||
case closeErr = <-s.closeChan:
|
||||
|
@ -413,29 +416,37 @@ runLoop:
|
|||
s.sentPacketHandler.OnAlarm()
|
||||
}
|
||||
|
||||
if s.config.KeepAlive && s.handshakeComplete && time.Since(s.lastNetworkActivityTime) >= s.peerParams.IdleTimeout/2 {
|
||||
var pacingDeadline time.Time
|
||||
if s.pacingDeadline.IsZero() { // the timer didn't have a pacing deadline set
|
||||
pacingDeadline = s.sentPacketHandler.TimeUntilSend()
|
||||
}
|
||||
if s.config.KeepAlive && !s.keepAlivePingSent && s.handshakeComplete && time.Since(s.lastNetworkActivityTime) >= s.peerParams.IdleTimeout/2 {
|
||||
// send the PING frame since there is no activity in the session
|
||||
s.packer.QueueControlFrame(&wire.PingFrame{})
|
||||
s.keepAlivePingSent = true
|
||||
} else if !pacingDeadline.IsZero() && now.Before(pacingDeadline) {
|
||||
// If we get to this point before the pacing deadline, we should wait until that deadline.
|
||||
// This can happen when scheduleSending is called, or a packet is received.
|
||||
// Set the timer and restart the run loop.
|
||||
s.pacingDeadline = pacingDeadline
|
||||
continue
|
||||
}
|
||||
|
||||
s.pacingDeadline = time.Time{}
|
||||
sendingAllowed := s.sentPacketHandler.SendingAllowed()
|
||||
if !sendingAllowed { // if congestion limited, at least try sending an ACK frame
|
||||
if err := s.maybeSendAckOnlyPacket(); err != nil {
|
||||
s.closeLocal(err)
|
||||
}
|
||||
} else {
|
||||
// repeatedly try sending until we don't have any more data, or run out of the congestion window
|
||||
for sendingAllowed {
|
||||
sentPacket, err := s.sendPacket()
|
||||
if err != nil {
|
||||
s.closeLocal(err)
|
||||
break
|
||||
}
|
||||
if !sentPacket {
|
||||
break
|
||||
}
|
||||
sendingAllowed = s.sentPacketHandler.SendingAllowed()
|
||||
sentPacket, err := s.sendPacket()
|
||||
if err != nil {
|
||||
s.closeLocal(err)
|
||||
}
|
||||
if sentPacket {
|
||||
// Only start the pacing timer if actually a packet was sent.
|
||||
// If one packet was sent, there will probably be more to send when calling sendPacket again.
|
||||
s.pacingDeadline = s.sentPacketHandler.TimeUntilSend()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,6 +499,9 @@ func (s *session) maybeResetTimer() {
|
|||
if !s.receivedTooManyUndecrytablePacketsTime.IsZero() {
|
||||
deadline = utils.MinTime(deadline, s.receivedTooManyUndecrytablePacketsTime.Add(protocol.PublicResetTimeout))
|
||||
}
|
||||
if !s.pacingDeadline.IsZero() {
|
||||
deadline = utils.MinTime(deadline, s.pacingDeadline)
|
||||
}
|
||||
|
||||
s.timer.Reset(deadline)
|
||||
}
|
||||
|
|
|
@ -712,11 +712,14 @@ var _ = Describe("Session", func() {
|
|||
sph.EXPECT().GetLeastUnacked().AnyTimes()
|
||||
sph.EXPECT().ShouldSendRetransmittablePacket().Times(2)
|
||||
sph.EXPECT().SentPacket(gomock.Any()).Times(2)
|
||||
sph.EXPECT().SendingAllowed().Do(func() { // after sending the first packet
|
||||
sph.EXPECT().TimeUntilSend().MinTimes(2).MaxTimes(3).Return(time.Now()) // the test might be completed before the last call
|
||||
sph.EXPECT().SendingAllowed().Do(func() { // after sending the first packet
|
||||
// make sure there's something to send
|
||||
sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 2})
|
||||
}).Return(true).Times(2) // allow 2 packets...
|
||||
sph.EXPECT().SendingAllowed() // ...then report that we're congestion limited
|
||||
// ...then report that we're congestion limited
|
||||
// (at most once, the test might be completed before the run loop executes this)
|
||||
sph.EXPECT().SendingAllowed().MaxTimes(1)
|
||||
sess.sentPacketHandler = sph
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
|
@ -726,6 +729,39 @@ var _ = Describe("Session", func() {
|
|||
}()
|
||||
sess.scheduleSending()
|
||||
Eventually(mconn.written).Should(HaveLen(2))
|
||||
Consistently(mconn.written).Should(HaveLen(2))
|
||||
// make the go routine return
|
||||
streamManager.EXPECT().CloseWithError(gomock.Any())
|
||||
sess.Close(nil)
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("paces packets", func() {
|
||||
sess.queueControlFrame(&wire.MaxDataFrame{ByteOffset: 1})
|
||||
sph := mockackhandler.NewMockSentPacketHandler(mockCtrl)
|
||||
sph.EXPECT().DequeuePacketForRetransmission().Times(2)
|
||||
sph.EXPECT().GetAlarmTimeout().AnyTimes()
|
||||
sph.EXPECT().GetLeastUnacked().AnyTimes()
|
||||
sph.EXPECT().ShouldSendRetransmittablePacket().Times(2)
|
||||
sph.EXPECT().SentPacket(gomock.Any()).Times(2)
|
||||
sph.EXPECT().TimeUntilSend().Return(time.Now().Add(-time.Minute))
|
||||
sph.EXPECT().TimeUntilSend().Return(time.Now().Add(300 * time.Millisecond))
|
||||
sph.EXPECT().TimeUntilSend().Return(time.Now().Add(time.Hour))
|
||||
sph.EXPECT().SendingAllowed().Do(func() { // after sending the first packet
|
||||
// make sure there's something to send
|
||||
sess.packer.QueueControlFrame(&wire.MaxDataFrame{ByteOffset: 2})
|
||||
}).Return(true).Times(2) // allow 2 packets...
|
||||
sess.sentPacketHandler = sph
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
sess.run()
|
||||
close(done)
|
||||
}()
|
||||
sess.scheduleSending()
|
||||
Eventually(mconn.written).Should(HaveLen(1))
|
||||
Consistently(mconn.written, 100*time.Millisecond).Should(HaveLen(1))
|
||||
Eventually(mconn.written).Should(HaveLen(2))
|
||||
// make the go routine return
|
||||
streamManager.EXPECT().CloseWithError(gomock.Any())
|
||||
sess.Close(nil)
|
||||
|
@ -785,6 +821,7 @@ var _ = Describe("Session", func() {
|
|||
sph.EXPECT().GetAlarmTimeout().AnyTimes()
|
||||
sph.EXPECT().SendingAllowed()
|
||||
sph.EXPECT().GetStopWaitingFrame(false).Return(swf)
|
||||
sph.EXPECT().TimeUntilSend()
|
||||
sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) {
|
||||
Expect(p.Frames).To(HaveLen(2))
|
||||
Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{}))
|
||||
|
@ -814,6 +851,7 @@ var _ = Describe("Session", func() {
|
|||
sph.EXPECT().GetLeastUnacked()
|
||||
sph.EXPECT().GetAlarmTimeout().AnyTimes()
|
||||
sph.EXPECT().SendingAllowed()
|
||||
sph.EXPECT().TimeUntilSend()
|
||||
sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) {
|
||||
Expect(p.Frames).To(HaveLen(1))
|
||||
Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{}))
|
||||
|
@ -1026,10 +1064,24 @@ var _ = Describe("Session", func() {
|
|||
})
|
||||
|
||||
It("sets the timer to the ack timer", func() {
|
||||
sph := mockackhandler.NewMockSentPacketHandler(mockCtrl)
|
||||
sph.EXPECT().TimeUntilSend().Return(time.Now())
|
||||
sph.EXPECT().TimeUntilSend().Return(time.Now().Add(time.Hour))
|
||||
sph.EXPECT().GetAlarmTimeout().AnyTimes()
|
||||
sph.EXPECT().SendingAllowed().Return(true).AnyTimes()
|
||||
sph.EXPECT().GetLeastUnacked().Times(2)
|
||||
sph.EXPECT().DequeuePacketForRetransmission()
|
||||
sph.EXPECT().GetStopWaitingFrame(gomock.Any())
|
||||
sph.EXPECT().ShouldSendRetransmittablePacket()
|
||||
sph.EXPECT().SentPacket(gomock.Any()).Do(func(p *ackhandler.Packet) {
|
||||
Expect(p.Frames[0]).To(BeAssignableToTypeOf(&wire.AckFrame{}))
|
||||
Expect(p.Frames[0].(*wire.AckFrame).LargestAcked).To(Equal(protocol.PacketNumber(0x1337)))
|
||||
})
|
||||
sess.sentPacketHandler = sph
|
||||
rph := mockackhandler.NewMockReceivedPacketHandler(mockCtrl)
|
||||
rph.EXPECT().GetAckFrame().Return(&wire.AckFrame{LargestAcked: 0x1337})
|
||||
rph.EXPECT().GetAckFrame()
|
||||
rph.EXPECT().GetAlarmTimeout().Return(time.Now().Add(10 * time.Millisecond)).MinTimes(1)
|
||||
rph.EXPECT().GetAlarmTimeout().Return(time.Now().Add(10 * time.Millisecond))
|
||||
rph.EXPECT().GetAlarmTimeout().Return(time.Now().Add(time.Hour))
|
||||
sess.receivedPacketHandler = rph
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
|
@ -1037,8 +1089,8 @@ var _ = Describe("Session", func() {
|
|||
sess.run()
|
||||
close(done)
|
||||
}()
|
||||
Eventually(mconn.written).Should(Receive(ContainSubstring(string([]byte{0x13, 0x37}))))
|
||||
// make the go routine return
|
||||
Eventually(mconn.written).Should(Receive())
|
||||
// make sure the go routine returns
|
||||
streamManager.EXPECT().CloseWithError(gomock.Any())
|
||||
sess.Close(nil)
|
||||
Eventually(done).Should(BeClosed())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue