]> Cypherpunks repositories - gostls13.git/commitdiff
rpc: don't panic on write error.
authorRob Pike <r@golang.org>
Tue, 18 Oct 2011 22:52:49 +0000 (15:52 -0700)
committerRob Pike <r@golang.org>
Tue, 18 Oct 2011 22:52:49 +0000 (15:52 -0700)
The mechanism to record the error in the call is already in place.
Fixes #2382.

R=golang-dev, dsymonds, bradfitz, r
CC=golang-dev
https://golang.org/cl/5307043

src/pkg/rpc/client.go
src/pkg/rpc/server_test.go

index c77901c6dca8f9c946a4ca7ee043cf0f87667dc1..3dc6df1c4b3096c21424a4fc3441237afc631a57 100644 (file)
@@ -85,7 +85,8 @@ func (client *Client) send(c *Call) {
        client.request.Seq = c.seq
        client.request.ServiceMethod = c.ServiceMethod
        if err := client.codec.WriteRequest(&client.request, c.Args); err != nil {
-               panic("rpc: client encode error: " + err.String())
+               c.Error = err
+               c.done()
        }
 }
 
@@ -251,10 +252,10 @@ func (client *Client) Close() os.Error {
 // the same Call object.  If done is nil, Go will allocate a new channel.
 // If non-nil, done must be buffered or Go will deliberately crash.
 func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
-       c := new(Call)
-       c.ServiceMethod = serviceMethod
-       c.Args = args
-       c.Reply = reply
+       call := new(Call)
+       call.ServiceMethod = serviceMethod
+       call.Args = args
+       call.Reply = reply
        if done == nil {
                done = make(chan *Call, 10) // buffered.
        } else {
@@ -266,14 +267,14 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
                        log.Panic("rpc: done channel is unbuffered")
                }
        }
-       c.Done = done
+       call.Done = done
        if client.shutdown {
-               c.Error = ErrShutdown
-               c.done()
-               return c
+               call.Error = ErrShutdown
+               call.done()
+               return call
        }
-       client.send(c)
-       return c
+       client.send(call)
+       return call
 }
 
 // Call invokes the named function, waits for it to complete, and returns its error status.
index cb2db2a65d34670a9f94f2b0b9dad7157cd733c3..029741b28b51a85efa6e1ab4d594db5de852d0c4 100644 (file)
@@ -467,6 +467,32 @@ func TestCountMallocsOverHTTP(t *testing.T) {
        fmt.Printf("mallocs per HTTP rpc round trip: %d\n", countMallocs(dialHTTP, t))
 }
 
+type writeCrasher struct{}
+
+func (writeCrasher) Close() os.Error {
+       return nil
+}
+
+func (writeCrasher) Read(p []byte) (int, os.Error) {
+       return 0, os.EOF
+}
+
+func (writeCrasher) Write(p []byte) (int, os.Error) {
+       return 0, os.NewError("fake write failure")
+}
+
+func TestClientWriteError(t *testing.T) {
+       c := NewClient(writeCrasher{})
+       res := false
+       err := c.Call("foo", 1, &res)
+       if err == nil {
+               t.Fatal("expected error")
+       }
+       if err.String() != "fake write failure" {
+               t.Error("unexpected value of error:", err)
+       }
+}
+
 func benchmarkEndToEnd(dial func() (*Client, os.Error), b *testing.B) {
        b.StopTimer()
        once.Do(startServer)