]> Cypherpunks repositories - gostls13.git/commitdiff
net/rpc: do not leak client socket on closed connection
authorDavid Crawshaw <david.crawshaw@zentus.com>
Sun, 11 May 2014 21:46:44 +0000 (14:46 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Sun, 11 May 2014 21:46:44 +0000 (14:46 -0700)
Fixes #6897.

LGTM=bradfitz
R=golang-codereviews, bradfitz, r, rsc
CC=golang-codereviews
https://golang.org/cl/91230045

src/pkg/net/rpc/client.go
src/pkg/net/rpc/client_test.go [new file with mode: 0644]

index c524d0a0a2de37204d255e02f35aee369093009e..21f79b06844638e485f055b3a24c0407be310c64 100644 (file)
@@ -39,14 +39,16 @@ type Call struct {
 // with a single Client, and a Client may be used by
 // multiple goroutines simultaneously.
 type Client struct {
-       mutex    sync.Mutex // protects pending, seq, request
-       sending  sync.Mutex
+       codec ClientCodec
+
+       sending sync.Mutex
+
+       mutex    sync.Mutex // protects following
        request  Request
        seq      uint64
-       codec    ClientCodec
        pending  map[uint64]*Call
-       closing  bool
-       shutdown bool
+       closing  bool // user has called Close
+       shutdown bool // server has told us to stop
 }
 
 // A ClientCodec implements writing of RPC requests and
@@ -274,7 +276,7 @@ func Dial(network, address string) (*Client, error) {
 
 func (client *Client) Close() error {
        client.mutex.Lock()
-       if client.shutdown || client.closing {
+       if client.closing {
                client.mutex.Unlock()
                return ErrShutdown
        }
diff --git a/src/pkg/net/rpc/client_test.go b/src/pkg/net/rpc/client_test.go
new file mode 100644 (file)
index 0000000..bbfc1ec
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+       "errors"
+       "testing"
+)
+
+type shutdownCodec struct {
+       responded chan int
+       closed    bool
+}
+
+func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
+func (c *shutdownCodec) ReadResponseBody(interface{}) error       { return nil }
+func (c *shutdownCodec) ReadResponseHeader(*Response) error {
+       c.responded <- 1
+       return errors.New("shutdownCodec ReadResponseHeader")
+}
+func (c *shutdownCodec) Close() error {
+       c.closed = true
+       return nil
+}
+
+func TestCloseCodec(t *testing.T) {
+       codec := &shutdownCodec{responded: make(chan int)}
+       client := NewClientWithCodec(codec)
+       <-codec.responded
+       client.Close()
+       if !codec.closed {
+               t.Error("client.Close did not close codec")
+       }
+}