mirror of
https://github.com/sourcegraph/jsonrpc2.git
synced 2026-06-16 04:04:56 +02:00
Fix underlying connection not being closed on protocol error (#64)
Before this commit, the underlying connection of `Conn` was not being closed when a protocol error was encountered. This behavior contradicted with `Conn.DisconnectNotify()` because it reported that the underlying connection was being closed. Additionally, the underlying connection was now orphaned because `Conn` was no longer processing any of the subsequent requests. With this commit, the underlying connection is now being closed when a protocol error is encountered, matching what `Conn.DisconnectNotify()` has already been reporting.
This commit is contained in:
parent
78a3d790f3
commit
028a50bb39
2 changed files with 110 additions and 100 deletions
58
jsonrpc2.go
58
jsonrpc2.go
|
|
@ -366,11 +366,10 @@ type Conn struct {
|
|||
|
||||
h Handler
|
||||
|
||||
mu sync.Mutex
|
||||
shutdown bool
|
||||
closing bool
|
||||
seq uint64
|
||||
pending map[ID]*call
|
||||
mu sync.Mutex
|
||||
closed bool
|
||||
seq uint64
|
||||
pending map[ID]*call
|
||||
|
||||
sending sync.Mutex
|
||||
|
||||
|
|
@ -417,13 +416,29 @@ func NewConn(ctx context.Context, stream ObjectStream, h Handler, opts ...ConnOp
|
|||
// Close closes the JSON-RPC connection. The connection may not be
|
||||
// used after it has been closed.
|
||||
func (c *Conn) Close() error {
|
||||
return c.close(nil)
|
||||
}
|
||||
|
||||
func (c *Conn) close(cause error) error {
|
||||
c.sending.Lock()
|
||||
c.mu.Lock()
|
||||
if c.shutdown || c.closing {
|
||||
c.mu.Unlock()
|
||||
defer c.sending.Unlock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.closed {
|
||||
return ErrClosed
|
||||
}
|
||||
c.closing = true
|
||||
c.mu.Unlock()
|
||||
|
||||
for _, call := range c.pending {
|
||||
close(call.done)
|
||||
}
|
||||
|
||||
if cause != nil && cause != io.EOF && cause != io.ErrUnexpectedEOF {
|
||||
c.logger.Printf("jsonrpc2: protocol error: %v\n", cause)
|
||||
}
|
||||
|
||||
close(c.disconnect)
|
||||
c.closed = true
|
||||
return c.stream.Close()
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +451,7 @@ func (c *Conn) send(_ context.Context, m *anyMessage, wait bool) (cc *call, err
|
|||
var id ID
|
||||
|
||||
c.mu.Lock()
|
||||
if c.shutdown || c.closing {
|
||||
if c.closed {
|
||||
c.mu.Unlock()
|
||||
return nil, ErrClosed
|
||||
}
|
||||
|
|
@ -675,28 +690,7 @@ func (c *Conn) readMessages(ctx context.Context) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.sending.Lock()
|
||||
c.mu.Lock()
|
||||
c.shutdown = true
|
||||
closing := c.closing
|
||||
if err == io.EOF {
|
||||
if closing {
|
||||
err = ErrClosed
|
||||
} else {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}
|
||||
for _, call := range c.pending {
|
||||
call.done <- err
|
||||
close(call.done)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
c.sending.Unlock()
|
||||
if err != io.ErrUnexpectedEOF && !closing {
|
||||
c.logger.Printf("jsonrpc2: protocol error: %v\n", err)
|
||||
}
|
||||
close(c.disconnect)
|
||||
c.close(err)
|
||||
}
|
||||
|
||||
// call represents a JSON-RPC call over its entire lifecycle.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue