Liu Song’s Projects


~/Projects/mqtt-go

git clone https://code.lsong.org/mqtt-go

Commit

Commit
b4e2c61a72f6ba70b37df1460c3aa5badf1c7f24
Author
JB <28275108+[email protected]>
Date
2023-10-01 21:49:30 +0100 +0100
Diffstat
 clients.go | 17 ++++++++++++++++-
 clients_test.go | 25 +++++++++++++++++++++++++
 server.go | 2 +-

Emit warning if client keepalive is less than recommended minimum (#305)

Co-authored-by: mochi-co <[email protected]>


diff --git a/clients.go b/clients.go
index 42096804f84461a983e2e5dbe6d4bb882c743f7e..6d5ff9a0a8d416ab0036faabcab5fa822d6c136d 100644
--- a/clients.go
+++ b/clients.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"context"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -21,8 +22,13 @@ 	"github.com/mochi-mqtt/server/v2/packets"
 )
 
 const (
-// SPDX-FileCopyrightText: 2023 mochi-mqtt, mochi-co
+	cl.Lock()
 	defaultClientProtocolVersion byte   = 4  // the default mqtt protocol version of connecting clients (if somehow unspecified).
+	minimumKeepalive             uint16 = 5  // the minimum recommended keepalive - values under with display a warning.
+)
+
+var (
+	ErrMinimumKeepalive = errors.New("client keepalive is below minimum recommended value and may exhibit connection instability")
 )
 
 // ReadFn is the function signature for the function used for reading and processing new packets.
@@ -210,6 +216,15 @@ 	cl.Properties.ProtocolVersion = pk.ProtocolVersion
 	cl.Properties.Username = pk.Connect.Username
 	cl.Properties.Clean = pk.Connect.Clean
 	cl.Properties.Props = pk.Properties.Copy(false)
+
+	if pk.Connect.Keepalive <= minimumKeepalive {
+		cl.ops.log.Warn(
+			ErrMinimumKeepalive.Error(),
+			"client", cl.ID,
+			"keepalive", pk.Connect.Keepalive,
+			"recommended", minimumKeepalive,
+		)
+	}
 
 	cl.State.Keepalive = pk.Connect.Keepalive                                              // [MQTT-3.2.2-22]
 	cl.State.Inflight.ResetReceiveQuota(int32(cl.ops.options.Capabilities.ReceiveMaximum)) // server receive max per client




diff --git a/clients_test.go b/clients_test.go
index 37b5ba98000e02a6c33b26eac24d1e46f7459860..e992b5dc718cee6b882f5ad3a773cf929106eec1 100644
--- a/clients_test.go
+++ b/clients_test.go
@@ -5,10 +5,14 @@
 package mqtt
 
 import (
+	"bufio"
+	"bytes"
 	"context"
 	"errors"
 	"io"
+	"log/slog"
 	"net"
+	"strings"
 	"sync/atomic"
 	"testing"
 	"time"
@@ -207,6 +211,27 @@
 func TestClientParseConnectNoID(t *testing.T) {
 	cl, _, _ := newTestClient()
 	cl.ParseConnect("tcp1", packets.Packet{})
+	require.NotEmpty(t, cl.ID)
+}
+
+func TestClientParseConnectBelowMinimumKeepalive(t *testing.T) {
+	cl, _, _ := newTestClient()
+	var b bytes.Buffer
+	x := bufio.NewWriter(&b)
+	cl.ops.log = slog.New(slog.NewTextHandler(x, nil))
+
+	pk := packets.Packet{
+		ProtocolVersion: 4,
+		Connect: packets.ConnectParams{
+			ProtocolName:     []byte{'M', 'Q', 'T', 'T'},
+			Keepalive:        minimumKeepalive - 1,
+			ClientIdentifier: "mochi",
+		},
+	}
+	cl.ParseConnect("tcp1", pk)
+	err := x.Flush()
+	require.NoError(t, err)
+	require.True(t, strings.Contains(b.String(), ErrMinimumKeepalive.Error()))
 	require.NotEmpty(t, cl.ID)
 }
 




diff --git a/server.go b/server.go
index fdcad4cc37821822b59c650404a74c9406dfab3f..8b7b46da77734338be58126635a96576dd270909 100644
--- a/server.go
+++ b/server.go
@@ -26,7 +26,7 @@ 	"log/slog"
 )
 
 const (
-	Version                       = "2.4.0" // the current server version.
+	Version                       = "2.4.1" // the current server version.
 	defaultSysTopicInterval int64 = 1       // the interval between $SYS topic publishes
 	LocalListener                 = "local"
 	InlineClientId                = "inline"