Skip to content

Commit

Permalink
[release-v1.7] rpcserver: Update websocket ping timeout handling.
Browse files Browse the repository at this point in the history
Currently, timeouts when responding to a websocket ping control message
with a pong message cause the websocket client to be disconnected, but
these types of failures are nearly always temporary network errors due
to things such as congestion and thus should not result in
disconnection.

In order to make that the case, this modifies the websocket ping handler
to ignore timeout network errors when attempting to respond with a pong
and also takes this opportunity to increase the timeout to 5 seconds
from 1 second to support multi-continent communication.
  • Loading branch information
davecgh committed Jan 8, 2022
1 parent 3d554df commit 14958dd
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 7 deletions.
15 changes: 9 additions & 6 deletions internal/rpcserver/rpcserver.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Copyright (c) 2015-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -6358,19 +6358,22 @@ func (s *Server) route(ctx context.Context) *http.Server {
return
}
ws.SetPingHandler(func(payload string) error {
err := ws.WriteControl(websocket.PongMessage, []byte(payload),
time.Now().Add(time.Second))
log.Debugf("ping received: len %d", len(payload))
log.Tracef("ping payload: %s", payload)
if err != nil {
log.Tracef("ping payload: %q", payload)
var netErr net.Error
err := ws.WriteControl(websocket.PongMessage, []byte(payload),
time.Now().Add(websocketPongTimeout))
if err != nil && !errors.Is(err, websocket.ErrCloseSent) &&
!(errors.As(err, &netErr) && netErr.Timeout()) {

log.Errorf("Failed to send pong: %v", err)
return err
}
return nil
})
ws.SetPongHandler(func(payload string) error {
log.Debugf("pong received: len %d", len(payload))
log.Tracef("pong payload: %s", payload)
log.Tracef("pong payload: %q", payload)
return nil
})
if !authenticated {
Expand Down
6 changes: 5 additions & 1 deletion internal/rpcserver/rpcwebsocket.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Copyright (c) 2015-2022 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

Expand Down Expand Up @@ -52,6 +52,10 @@ const (
// websocketReadLimitAuthenticated is the maximum number of bytes allowed
// for an authenticated JSON-RPC message read from a websocket client.
websocketReadLimitAuthenticated = 1 << 24 // 16 MiB

// websocketPongTimeout is the maximum amount of time attempts to respond to
// websocket ping messages with a pong will wait before giving up.
websocketPongTimeout = time.Second * 5
)

type semaphore chan struct{}
Expand Down

0 comments on commit 14958dd

Please sign in to comment.