Commit 161f5057 authored by Alexey Borzenkov's avatar Alexey Borzenkov Committed by Rob Pike

net/rpc: fix race condition when request write partially fails

When client fails to write a request is sends caller that error,
however server might have failed to read that request in the mean
time and replied with that error. When client then reads the
response the call would no longer be pending, so call will be nil

Handle this gracefully by discarding such server responses

R=golang-dev, r
CC=golang-dev, rsc
https://golang.org/cl/5956051
parent 68f42ea2
......@@ -88,11 +88,14 @@ func (client *Client) send(call *Call) {
err := client.codec.WriteRequest(&client.request, call.Args)
if err != nil {
client.mutex.Lock()
call = client.pending[seq]
delete(client.pending, seq)
client.mutex.Unlock()
if call != nil {
call.Error = err
call.done()
}
}
}
func (client *Client) input() {
......@@ -113,23 +116,27 @@ func (client *Client) input() {
delete(client.pending, seq)
client.mutex.Unlock()
if response.Error == "" {
err = client.codec.ReadResponseBody(call.Reply)
if err != nil {
call.Error = errors.New("reading body " + err.Error())
}
} else {
if call == nil || response.Error != "" {
// We've got an error response. Give this to the request;
// any subsequent requests will get the ReadResponseBody
// error if there is one.
if call != nil {
call.Error = ServerError(response.Error)
}
err = client.codec.ReadResponseBody(nil)
if err != nil {
err = errors.New("reading error body: " + err.Error())
}
} else if response.Error == "" {
err = client.codec.ReadResponseBody(call.Reply)
if err != nil {
call.Error = errors.New("reading body " + err.Error())
}
}
if call != nil {
call.done()
}
}
// Terminate pending calls.
client.sending.Lock()
client.mutex.Lock()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment