diff --git a/config.go b/config.go index 61c4097a617..5d969a12aaa 100644 --- a/config.go +++ b/config.go @@ -105,7 +105,7 @@ func populateConfig(config *Config) *Config { HandshakeIdleTimeout: handshakeIdleTimeout, MaxIdleTimeout: idleTimeout, AcceptToken: config.AcceptToken, - KeepAlive: config.KeepAlive, + KeepAlivePeriod: config.KeepAlivePeriod, InitialStreamReceiveWindow: initialStreamReceiveWindow, MaxStreamReceiveWindow: maxStreamReceiveWindow, InitialConnectionReceiveWindow: initialConnectionReceiveWindow, diff --git a/config_test.go b/config_test.go index 36f644e4098..692952f4fa8 100644 --- a/config_test.go +++ b/config_test.go @@ -71,8 +71,8 @@ var _ = Describe("Config", func() { f.Set(reflect.ValueOf(int64(12))) case "StatelessResetKey": f.Set(reflect.ValueOf([]byte{1, 2, 3, 4})) - case "KeepAlive": - f.Set(reflect.ValueOf(true)) + case "KeepAlivePeriod": + f.Set(reflect.ValueOf(time.Second)) case "EnableDatagrams": f.Set(reflect.ValueOf(true)) case "DisableVersionNegotiationPackets": diff --git a/connection.go b/connection.go index e0adc80c38d..ce45af86acb 100644 --- a/connection.go +++ b/connection.go @@ -732,7 +732,7 @@ func (s *connection) ConnectionState() ConnectionState { // Time when the next keep-alive packet should be sent. // It returns a zero time if no keep-alive should be sent. func (s *connection) nextKeepAliveTime() time.Time { - if !s.config.KeepAlive || s.keepAlivePingSent || !s.firstAckElicitingPacketAfterIdleSentTime.IsZero() { + if s.config.KeepAlivePeriod == 0 || s.keepAlivePingSent || !s.firstAckElicitingPacketAfterIdleSentTime.IsZero() { return time.Time{} } return s.lastPacketReceivedTime.Add(s.keepAliveInterval) @@ -1618,7 +1618,7 @@ func (s *connection) applyTransportParameters() { params := s.peerParams // Our local idle timeout will always be > 0. s.idleTimeout = utils.MinNonZeroDuration(s.config.MaxIdleTimeout, params.MaxIdleTimeout) - s.keepAliveInterval = utils.MinDuration(s.idleTimeout/2, protocol.MaxKeepAliveInterval) + s.keepAliveInterval = utils.MinDuration(s.config.KeepAlivePeriod, utils.MinDuration(s.idleTimeout/2, protocol.MaxKeepAliveInterval)) s.streamsMap.UpdateLimits(params) s.packer.HandleTransportParameters(params) s.frameParser.SetAckDelayExponent(params.AckDelayExponent) diff --git a/connection_test.go b/connection_test.go index c36681f777a..9c5d3fb9de5 100644 --- a/connection_test.go +++ b/connection_test.go @@ -2102,7 +2102,7 @@ var _ = Describe("Connection", func() { BeforeEach(func() { conn.config.MaxIdleTimeout = 30 * time.Second - conn.config.KeepAlive = true + conn.config.KeepAlivePeriod = 15 * time.Second conn.receivedPacketHandler.ReceivedPacket(0, protocol.ECNNon, protocol.EncryptionHandshake, time.Now(), true) }) @@ -2146,7 +2146,7 @@ var _ = Describe("Connection", func() { It("doesn't send a PING packet if keep-alive is disabled", func() { setRemoteIdleTimeout(5 * time.Second) - conn.config.KeepAlive = false + conn.config.KeepAlivePeriod = 0 conn.lastPacketReceivedTime = time.Now().Add(-time.Second * 5 / 2) runConn() // don't EXPECT() any calls to mconn.Write() diff --git a/http3/client.go b/http3/client.go index 325fd4d4456..c1600e619cb 100644 --- a/http3/client.go +++ b/http3/client.go @@ -10,6 +10,7 @@ import ( "net/http" "strconv" "sync" + "time" "github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go/internal/protocol" @@ -30,7 +31,7 @@ const ( var defaultQuicConfig = &quic.Config{ MaxIncomingStreams: -1, // don't allow the server to create bidirectional streams - KeepAlive: true, + KeepAlivePeriod: 10 * time.Second, Versions: []protocol.VersionNumber{protocol.VersionTLS}, } diff --git a/integrationtests/self/timeout_test.go b/integrationtests/self/timeout_test.go index cd7b82ca2f6..2b61d4ec534 100644 --- a/integrationtests/self/timeout_test.go +++ b/integrationtests/self/timeout_test.go @@ -355,7 +355,7 @@ var _ = Describe("Timeout tests", func() { getTLSClientConfig(), getQuicConfig(&quic.Config{ MaxIdleTimeout: idleTimeout, - KeepAlive: true, + KeepAlivePeriod: idleTimeout / 2, DisablePathMTUDiscovery: true, }), ) @@ -480,7 +480,7 @@ var _ = Describe("Timeout tests", func() { getQuicConfig(&quic.Config{ HandshakeIdleTimeout: handshakeTimeout, MaxIdleTimeout: handshakeTimeout, - KeepAlive: true, + KeepAlivePeriod: handshakeTimeout / 2, DisablePathMTUDiscovery: true, }), ) diff --git a/interface.go b/interface.go index cb1c1de3a39..9f9babf0b1b 100644 --- a/interface.go +++ b/interface.go @@ -281,8 +281,10 @@ type Config struct { // The StatelessResetKey is used to generate stateless reset tokens. // If no key is configured, sending of stateless resets is disabled. StatelessResetKey []byte - // KeepAlive defines whether this peer will periodically send a packet to keep the connection alive. - KeepAlive bool + // KeepAlivePeriod defines whether this peer will periodically send a packet to keep the connection alive. + // If set to 0, then no keep alive is sent. Otherwise, the keep alive is sent on that period (or at most + // every half of MaxIdleTimeout, whichever is smaller). + KeepAlivePeriod time.Duration // DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899). // Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size. // Note that if Path MTU discovery is causing issues on your system, please open a new issue diff --git a/server_test.go b/server_test.go index 509af9e9812..2cdb98d06db 100644 --- a/server_test.go +++ b/server_test.go @@ -127,7 +127,7 @@ var _ = Describe("Server", func() { Expect(server.config.HandshakeIdleTimeout).To(Equal(protocol.DefaultHandshakeIdleTimeout)) Expect(server.config.MaxIdleTimeout).To(Equal(protocol.DefaultIdleTimeout)) Expect(reflect.ValueOf(server.config.AcceptToken)).To(Equal(reflect.ValueOf(defaultAcceptToken))) - Expect(server.config.KeepAlive).To(BeFalse()) + Expect(server.config.KeepAlivePeriod).To(Equal(0 * time.Second)) // stop the listener Expect(ln.Close()).To(Succeed()) }) @@ -140,7 +140,7 @@ var _ = Describe("Server", func() { AcceptToken: acceptToken, HandshakeIdleTimeout: 1337 * time.Hour, MaxIdleTimeout: 42 * time.Minute, - KeepAlive: true, + KeepAlivePeriod: 5 * time.Second, StatelessResetKey: []byte("foobar"), } ln, err := Listen(conn, tlsConf, &config) @@ -151,7 +151,7 @@ var _ = Describe("Server", func() { Expect(server.config.HandshakeIdleTimeout).To(Equal(1337 * time.Hour)) Expect(server.config.MaxIdleTimeout).To(Equal(42 * time.Minute)) Expect(reflect.ValueOf(server.config.AcceptToken)).To(Equal(reflect.ValueOf(acceptToken))) - Expect(server.config.KeepAlive).To(BeTrue()) + Expect(server.config.KeepAlivePeriod).To(Equal(5 * time.Second)) Expect(server.config.StatelessResetKey).To(Equal([]byte("foobar"))) // stop the listener Expect(ln.Close()).To(Succeed())