From c2b099dd9706b71cb2ff5f539cc974681610f79d Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 8 Dec 2025 15:49:07 +0100 Subject: [PATCH] client: make use of shutdownLock on Read access c.shutdownLock protects access to c.shutdown, but before this commit this is only used when calling Close(), thus only protecting against parallel user calls to Close(), but it was not used when checking whether the channel is shutdown in the exported function IsClosed(), potentially returning an incorrect value. It was also not used in send() and listen(). To address this, turn the c.shutdownLock Mutex into a RWMutex, and make use of it in all these cases, enabling use of the same RPCClient from multiple parallel goroutines. Fixes: https://github.com/hashicorp/serf/issues/782 Signed-off-by: Claudio Fontana --- client/rpc_client.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/rpc_client.go b/client/rpc_client.go index a1c242ad0..24e917eff 100644 --- a/client/rpc_client.go +++ b/client/rpc_client.go @@ -80,7 +80,7 @@ type RPCClient struct { shutdown bool shutdownCh chan struct{} - shutdownLock sync.Mutex + shutdownLock sync.RWMutex } // send is used to send an object using the MsgPack encoding. send @@ -89,7 +89,7 @@ func (c *RPCClient) send(header *requestHeader, obj interface{}) error { c.writeLock.Lock() defer c.writeLock.Unlock() - if c.shutdown { + if c.IsClosed() { return clientClosed } @@ -184,6 +184,8 @@ func ClientFromConfig(c *Config) (*RPCClient, error) { type StreamHandle uint64 func (c *RPCClient) IsClosed() bool { + c.shutdownLock.RLock() + defer c.shutdownLock.RUnlock() return c.shutdown } @@ -848,7 +850,7 @@ func (c *RPCClient) listen() { var respHeader responseHeader for { if err := c.dec.Decode(&respHeader); err != nil { - if !c.shutdown { + if !c.IsClosed() { log.Printf("[ERR] agent.client: Failed to decode response header: %v", err) } break