replace time.After in session with a single timer

fixes #128, fixes #127
This commit is contained in:
Lucas Clemente
2016-05-19 14:16:42 +02:00
parent 55727ecd96
commit bd6d893cc4
2 changed files with 33 additions and 29 deletions

View File

@@ -73,6 +73,10 @@ type Session struct {
// Used to calculate the next packet number from the truncated wire
// representation, and sent back in public reset packets
lastRcvdPacketNumber protocol.PacketNumber
lastNetworkActivityTime time.Time
timer *time.Timer
}
// newSession makes a new session
@@ -97,6 +101,8 @@ func newSession(conn connection, v protocol.VersionNumber, connectionID protocol
connectionParametersManager: connectionParametersManager,
undecryptablePackets: make([]receivedPacket, 0, protocol.MaxUndecryptablePackets),
aeadChanged: make(chan struct{}, 1),
timer: time.NewTimer(0),
lastNetworkActivityTime: time.Now(),
}
cryptoStream, _ := session.OpenStream(1)
@@ -128,39 +134,39 @@ func (s *Session) run() {
default:
}
// Note: receive at a nil channel blocks forever
// Calculate the minimum of all timeouts
var smallPacketSendTimer <-chan time.Time
now := time.Now()
firstTimeout := utils.InfDuration
// Small packet send delay
if !s.smallPacketDelayedOccurranceTime.IsZero() {
smallPacketSendTimer = time.After(time.Now().Sub(s.smallPacketDelayedOccurranceTime))
firstTimeout = utils.MinDuration(firstTimeout, s.smallPacketDelayedOccurranceTime.Add(protocol.SmallPacketSendDelay).Sub(now))
}
// RTOs
firstTimeout = utils.MinDuration(firstTimeout, s.sentPacketHandler.TimeToFirstRTO())
// Idle connection timeout
firstTimeout = utils.MinDuration(firstTimeout, s.lastNetworkActivityTime.Add(s.connectionParametersManager.GetIdleConnectionStateLifetime()).Sub(now))
var rtoTimer <-chan time.Time
if d := s.sentPacketHandler.TimeToFirstRTO(); d != utils.InfDuration {
rtoTimer = time.After(d)
}
s.timer.Reset(firstTimeout)
var err error
select {
case <-s.closeChan:
return
case <-s.timer.C:
// We do all the interesting stuff after the switch statement, so
// nothing to see here.
case <-s.sendingScheduled:
// We do all the interesting stuff after the switch statement, so
// nothing to see here.
case p := <-s.receivedPackets:
err = s.handlePacketImpl(p.remoteAddr, p.publicHeader, p.data)
if qErr, ok := err.(*qerr.QuicError); ok && qErr.ErrorCode == qerr.DecryptionFailure {
s.tryQueueingUndecryptablePacket(p)
continue
}
s.scheduleSending()
case <-s.sendingScheduled:
err = s.maybeSendPacket()
case <-smallPacketSendTimer:
err = s.sendPacket()
case <-rtoTimer:
err = s.sendPacket()
case <-s.aeadChanged:
s.tryDecryptingQueuedPackets()
case <-time.After(s.connectionParametersManager.GetIdleConnectionStateLifetime()):
s.Close(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity."))
}
if err != nil {
@@ -177,11 +183,18 @@ func (s *Session) run() {
}
}
if err := s.maybeSendPacket(); err != nil {
s.Close(err)
}
if time.Now().Sub(s.lastNetworkActivityTime) > s.connectionParametersManager.GetIdleConnectionStateLifetime() {
s.Close(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity."))
}
s.garbageCollectStreams()
}
}
func (s *Session) handlePacketImpl(remoteAddr interface{}, hdr *publicHeader, data []byte) error {
s.lastNetworkActivityTime = time.Now()
r := bytes.NewReader(data)
// Calculate packet number
@@ -419,6 +432,10 @@ func (s *Session) maybeSendPacket() error {
s.smallPacketDelayedOccurranceTime = time.Now()
}
if time.Now().Sub(s.smallPacketDelayedOccurranceTime) > protocol.SmallPacketSendDelay {
return s.sendPacket()
}
return nil
}

View File

@@ -414,19 +414,6 @@ var _ = Describe("Session", func() {
Expect(session.sendingScheduled).To(Receive())
})
It("sends after receiving a packet", func() {
Expect(session.sendingScheduled).NotTo(Receive())
session.receivedPackets <- receivedPacket{
publicHeader: &publicHeader{},
data: []byte{
// FNV hash + "foobar"
0x18, 0x6f, 0x44, 0xba, 0x97, 0x35, 0xd, 0x6f, 0xbf, 0x64, 0x3c, 0x79, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72,
},
}
session.run()
Expect(session.sendingScheduled).To(Receive())
})
Context("bundling of small packets", func() {
It("bundles two small frames into one packet", func() {
go session.run()