Skip to content

Commit 963b977

Browse files
committed
Allow refusing all client connections with max_conns: -1
Signed-off-by: Neil Twigg <neil@nats.io>
1 parent a69f51f commit 963b977

File tree

6 files changed

+69
-5
lines changed

6 files changed

+69
-5
lines changed

server/mqtt.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ func (s *Server) createMQTTClient(conn net.Conn, ws *websocket) *client {
585585
return c
586586
}
587587

588-
if opts.MaxConn > 0 && len(s.clients) >= opts.MaxConn {
588+
if opts.MaxConn < 0 || (opts.MaxConn > 0 && len(s.clients) >= opts.MaxConn) {
589589
s.mu.Unlock()
590590
c.maxConnExceeded()
591591
return nil

server/reload.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,10 +575,10 @@ func (m *maxConnOption) Apply(server *Server) {
575575
}
576576
server.mu.Unlock()
577577

578-
if m.newValue > 0 && len(clients) > m.newValue {
578+
if newc := max(0, m.newValue); len(clients) > newc {
579579
// Close connections til we are within the limit.
580580
var (
581-
numClose = len(clients) - m.newValue
581+
numClose = len(clients) - newc
582582
closed = 0
583583
)
584584
for _, client := range clients {

server/reload_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,6 +2025,59 @@ func TestConfigReloadMaxConnections(t *testing.T) {
20252025
}
20262026
}
20272027

2028+
// Ensure Reload supports refusing all connections. Test this by starting a
2029+
// server with no max connections, connecting two clients, reloading with a
2030+
// max connections of one, and ensuring one client is disconnected.
2031+
func TestConfigReloadMaxConnectionsPreventAll(t *testing.T) {
2032+
server, opts, config := runReloadServerWithConfig(t, "./configs/reload/basic.conf")
2033+
defer server.Shutdown()
2034+
2035+
// Make two connections.
2036+
addr := fmt.Sprintf("nats://%s:%d", opts.Host, server.Addr().(*net.TCPAddr).Port)
2037+
nc1, err := nats.Connect(addr)
2038+
if err != nil {
2039+
t.Fatalf("Error creating client: %v", err)
2040+
}
2041+
defer nc1.Close()
2042+
closed := make(chan struct{}, 1)
2043+
nc1.SetDisconnectHandler(func(*nats.Conn) {
2044+
closed <- struct{}{}
2045+
})
2046+
nc2, err := nats.Connect(addr)
2047+
if err != nil {
2048+
t.Fatalf("Error creating client: %v", err)
2049+
}
2050+
defer nc2.Close()
2051+
nc2.SetDisconnectHandler(func(*nats.Conn) {
2052+
closed <- struct{}{}
2053+
})
2054+
2055+
if numClients := server.NumClients(); numClients != 2 {
2056+
t.Fatalf("Expected 2 clients, got %d", numClients)
2057+
}
2058+
2059+
// Set max connections to one.
2060+
changeCurrentConfigContent(t, config, "./configs/reload/max_connections_refuse_all.conf")
2061+
if err := server.Reload(); err != nil {
2062+
t.Fatalf("Error reloading config: %v", err)
2063+
}
2064+
2065+
// Ensure one connection was closed.
2066+
select {
2067+
case <-closed:
2068+
case <-time.After(5 * time.Second):
2069+
t.Fatal("Expected to be disconnected")
2070+
}
2071+
2072+
checkClientsCount(t, server, 0)
2073+
2074+
// Ensure new connections fail.
2075+
_, err = nats.Connect(addr)
2076+
if err == nil {
2077+
t.Fatal("Expected error on connect")
2078+
}
2079+
}
2080+
20282081
// Ensure reload supports changing the max payload size. Test this by starting
20292082
// a server with the default size limit, ensuring publishes work, reloading
20302083
// with a restrictive limit, and ensuring publishing an oversized message fails

server/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3377,7 +3377,7 @@ func (s *Server) createClientEx(conn net.Conn, inProcess bool) *client {
33773377

33783378
// If there is a max connections specified, check that adding
33793379
// this new client would not push us over the max
3380-
if opts.MaxConn > 0 && len(s.clients) >= opts.MaxConn {
3380+
if opts.MaxConn < 0 || (opts.MaxConn > 0 && len(s.clients) >= opts.MaxConn) {
33813381
s.mu.Unlock()
33823382
c.maxConnExceeded()
33833383
return nil

server/server_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,17 @@ func TestMaxConnections(t *testing.T) {
588588
}
589589
}
590590

591+
func TestMaxConnectionsPreventsAll(t *testing.T) {
592+
opts := DefaultOptions()
593+
opts.MaxConn = -1
594+
s := RunServer(opts)
595+
defer s.Shutdown()
596+
597+
addr := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port)
598+
_, err := nats.Connect(addr)
599+
require_Error(t, err)
600+
}
601+
591602
func TestMaxSubscriptions(t *testing.T) {
592603
opts := DefaultOptions()
593604
opts.MaxSubs = 10

server/websocket.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ func (s *Server) createWSClient(conn net.Conn, ws *websocket) *client {
13241324
return c
13251325
}
13261326

1327-
if opts.MaxConn > 0 && len(s.clients) >= opts.MaxConn {
1327+
if opts.MaxConn < 0 || (opts.MaxConn > 0 && len(s.clients) >= opts.MaxConn) {
13281328
s.mu.Unlock()
13291329
c.maxConnExceeded()
13301330
return nil

0 commit comments

Comments
 (0)