diff --git a/interface.go b/interface.go index 7dd249582..771d98dd1 100644 --- a/interface.go +++ b/interface.go @@ -102,7 +102,6 @@ type Config struct { HandshakeTimeout time.Duration // IdleTimeout is the maximum duration that may pass without any incoming network activity. // This value only applies after the handshake has completed. - // Before that, the idle timeout is set to half the duration of the HandshakeTimeout. // If the timeout is exceeded, the connection is closed. // If this value is zero, the timeout is set to 30 seconds. IdleTimeout time.Duration diff --git a/session.go b/session.go index db236974c..49c170428 100644 --- a/session.go +++ b/session.go @@ -323,12 +323,12 @@ runLoop: if !s.receivedTooManyUndecrytablePacketsTime.IsZero() && s.receivedTooManyUndecrytablePacketsTime.Add(protocol.PublicResetTimeout).Before(now) && len(s.undecryptablePackets) != 0 { s.closeLocal(qerr.Error(qerr.DecryptionFailure, "too many undecryptable packets received")) } - if now.Sub(s.lastNetworkActivityTime) >= s.idleTimeout() { - s.closeLocal(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity.")) - } if !s.handshakeComplete && now.Sub(s.sessionCreationTime) >= s.config.HandshakeTimeout { s.closeLocal(qerr.Error(qerr.HandshakeTimeout, "Crypto handshake did not complete in time.")) } + if s.handshakeComplete && now.Sub(s.lastNetworkActivityTime) >= s.idleTimeout() { + s.closeLocal(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity.")) + } s.garbageCollectStreams() } @@ -373,10 +373,7 @@ func (s *session) maybeResetTimer() { } func (s *session) idleTimeout() time.Duration { - if s.handshakeComplete { - return s.connectionParameters.GetIdleConnectionStateLifetime() - } - return s.config.HandshakeTimeout / 2 + return s.connectionParameters.GetIdleConnectionStateLifetime() } func (s *session) handlePacketImpl(p *receivedPacket) error { diff --git a/session_test.go b/session_test.go index 2250ed8ac..80b11bda7 100644 --- a/session_test.go +++ b/session_test.go @@ -1507,6 +1507,7 @@ var _ = Describe("Session", func() { Context("timeouts", func() { It("times out due to no network activity", func(done Done) { + sess.handshakeComplete = true sess.lastNetworkActivityTime = time.Now().Add(-time.Hour) err := sess.run() // Would normally not return Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.NetworkIdleTimeout)) @@ -1524,27 +1525,22 @@ var _ = Describe("Session", func() { close(done) }) - It("does not use ICSL before handshake", func(done Done) { + It("does not use ICSL before handshake", func() { + defer sess.Close(nil) sess.lastNetworkActivityTime = time.Now().Add(-time.Minute) mockCpm = mocks.NewMockConnectionParametersManager(mockCtrl) mockCpm.EXPECT().GetIdleConnectionStateLifetime().Return(9999 * time.Second).AnyTimes() mockCpm.EXPECT().TruncateConnectionID().Return(false).AnyTimes() sess.connectionParameters = mockCpm sess.packer.connectionParameters = mockCpm - err := sess.run() // Would normally not return - Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.NetworkIdleTimeout)) - Expect(mconn.written).To(Receive(ContainSubstring("No recent network activity."))) - Expect(sess.Context().Done()).To(BeClosed()) - close(done) - }) - - It("times out if the idle period is longer than half the handshake timeout", func(done Done) { - sess.lastNetworkActivityTime = time.Now().Add(-protocol.DefaultHandshakeTimeout / 2).Add(-time.Millisecond) - err := sess.run() // Would normally not return - Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.NetworkIdleTimeout)) - Expect(mconn.written).To(Receive(ContainSubstring("No recent network activity."))) - Expect(sess.Context().Done()).To(BeClosed()) - close(done) + // the handshake timeout is irrelevant here, since it depends on the time the session was created, + // and not on the last network activity + done := make(chan struct{}) + go func() { + _ = sess.run() + close(done) + }() + Consistently(done).ShouldNot(BeClosed()) }) It("uses ICSL after handshake", func(done Done) {