1
0
Fork 0
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:
Sam Herrmann 2023-02-07 15:46:05 -05:00 committed by GitHub
parent 78a3d790f3
commit 028a50bb39
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 100 deletions

View file

@ -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.