Added checking for closed connections in websocket handler helpers
Since the websocket handlers run in their own separate goroutines, it's possible that they execute after the websocket connection has been closed and cleaned up. This commit add the necessary checks to ensure stale data isn't added to notification lists and that requests to closed connections are ignored. This closes #92.
This commit is contained in:
parent
44e3a44a9c
commit
4431fd9c0d
1 changed files with 38 additions and 13 deletions
|
@ -80,7 +80,10 @@ func (r *wsContext) AddBlockUpdateRequest(n ntfnChan) {
|
||||||
r.Lock()
|
r.Lock()
|
||||||
defer r.Unlock()
|
defer r.Unlock()
|
||||||
|
|
||||||
rc := r.connections[n]
|
rc, ok := r.connections[n]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
rc.blockUpdates = true
|
rc.blockUpdates = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +93,10 @@ func (r *wsContext) AddAllNewTxRequest(n ntfnChan, verbose bool) {
|
||||||
r.Lock()
|
r.Lock()
|
||||||
defer r.Unlock()
|
defer r.Unlock()
|
||||||
|
|
||||||
rc := r.connections[n]
|
rc, ok := r.connections[n]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
rc.allTxUpdates = true
|
rc.allTxUpdates = true
|
||||||
rc.verboseTxUpdates = verbose
|
rc.verboseTxUpdates = verbose
|
||||||
}
|
}
|
||||||
|
@ -100,6 +106,12 @@ func (r *wsContext) AddTxRequest(n ntfnChan, addr string) {
|
||||||
r.Lock()
|
r.Lock()
|
||||||
defer r.Unlock()
|
defer r.Unlock()
|
||||||
|
|
||||||
|
rc, ok := r.connections[n]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rc.txRequests[addr] = struct{}{}
|
||||||
|
|
||||||
clist, ok := r.txNotifications[addr]
|
clist, ok := r.txNotifications[addr]
|
||||||
if !ok {
|
if !ok {
|
||||||
clist = list.New()
|
clist = list.New()
|
||||||
|
@ -107,9 +119,6 @@ func (r *wsContext) AddTxRequest(n ntfnChan, addr string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
clist.PushBack(n)
|
clist.PushBack(n)
|
||||||
|
|
||||||
rc := r.connections[n]
|
|
||||||
rc.txRequests[addr] = struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *wsContext) removeGlobalTxRequest(n ntfnChan, addr string) {
|
func (r *wsContext) removeGlobalTxRequest(n ntfnChan, addr string) {
|
||||||
|
@ -135,15 +144,18 @@ func (r *wsContext) AddSpentRequest(n ntfnChan, op *btcwire.OutPoint) {
|
||||||
r.Lock()
|
r.Lock()
|
||||||
defer r.Unlock()
|
defer r.Unlock()
|
||||||
|
|
||||||
|
rc, ok := r.connections[n]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rc.spentRequests[*op] = struct{}{}
|
||||||
|
|
||||||
clist, ok := r.spentNotifications[*op]
|
clist, ok := r.spentNotifications[*op]
|
||||||
if !ok {
|
if !ok {
|
||||||
clist = list.New()
|
clist = list.New()
|
||||||
r.spentNotifications[*op] = clist
|
r.spentNotifications[*op] = clist
|
||||||
}
|
}
|
||||||
clist.PushBack(n)
|
clist.PushBack(n)
|
||||||
|
|
||||||
rc := r.connections[n]
|
|
||||||
rc.spentRequests[*op] = struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *wsContext) removeGlobalSpentRequest(n ntfnChan, op *btcwire.OutPoint) {
|
func (r *wsContext) removeGlobalSpentRequest(n ntfnChan, op *btcwire.OutPoint) {
|
||||||
|
@ -170,7 +182,10 @@ func (r *wsContext) RemoveSpentRequest(n ntfnChan, op *btcwire.OutPoint) {
|
||||||
defer r.Unlock()
|
defer r.Unlock()
|
||||||
|
|
||||||
r.removeGlobalSpentRequest(n, op)
|
r.removeGlobalSpentRequest(n, op)
|
||||||
rc := r.connections[n]
|
rc, ok := r.connections[n]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
delete(rc.spentRequests, *op)
|
delete(rc.spentRequests, *op)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,15 +195,18 @@ func (r *wsContext) AddMinedTxRequest(n ntfnChan, txID *btcwire.ShaHash) {
|
||||||
r.Lock()
|
r.Lock()
|
||||||
defer r.Unlock()
|
defer r.Unlock()
|
||||||
|
|
||||||
|
rc, ok := r.connections[n]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rc.minedTxRequests[*txID] = struct{}{}
|
||||||
|
|
||||||
clist, ok := r.minedTxNotifications[*txID]
|
clist, ok := r.minedTxNotifications[*txID]
|
||||||
if !ok {
|
if !ok {
|
||||||
clist = list.New()
|
clist = list.New()
|
||||||
r.minedTxNotifications[*txID] = clist
|
r.minedTxNotifications[*txID] = clist
|
||||||
}
|
}
|
||||||
clist.PushBack(n)
|
clist.PushBack(n)
|
||||||
|
|
||||||
rc := r.connections[n]
|
|
||||||
rc.minedTxRequests[*txID] = struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *wsContext) removeGlobalMinedTxRequest(n ntfnChan, txID *btcwire.ShaHash) {
|
func (r *wsContext) removeGlobalMinedTxRequest(n ntfnChan, txID *btcwire.ShaHash) {
|
||||||
|
@ -221,7 +239,10 @@ func (r *wsContext) RemoveMinedTxRequest(n ntfnChan, txID *btcwire.ShaHash) {
|
||||||
// mined transaction without grabbing any locks.
|
// mined transaction without grabbing any locks.
|
||||||
func (r *wsContext) removeMinedTxRequest(n ntfnChan, txID *btcwire.ShaHash) {
|
func (r *wsContext) removeMinedTxRequest(n ntfnChan, txID *btcwire.ShaHash) {
|
||||||
r.removeGlobalMinedTxRequest(n, txID)
|
r.removeGlobalMinedTxRequest(n, txID)
|
||||||
rc := r.connections[n]
|
rc, ok := r.connections[n]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
delete(rc.minedTxRequests, *txID)
|
delete(rc.minedTxRequests, *txID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,6 +801,10 @@ func (s *rpcServer) websocketJSONHandler(r chan *btcjson.Reply, c handlerChans,
|
||||||
// connection is not already authenticated.
|
// connection is not already authenticated.
|
||||||
s.ws.Lock()
|
s.ws.Lock()
|
||||||
rc := s.ws.connections[c.n]
|
rc := s.ws.connections[c.n]
|
||||||
|
// Note: c.n is guaranteed to be in the s.ws.connections map since it is
|
||||||
|
// called from the main walletReqNotifications for loop. Any calls
|
||||||
|
// from that goroutine will always have valid connections since they
|
||||||
|
// are not removed till after that exits.
|
||||||
if _, ok := cmd.(*btcws.AuthenticateCmd); ok {
|
if _, ok := cmd.(*btcws.AuthenticateCmd); ok {
|
||||||
// Validate the provided credentials.
|
// Validate the provided credentials.
|
||||||
err := websocketAuthenticate(cmd, rc, s.authsha[:])
|
err := websocketAuthenticate(cmd, rc, s.authsha[:])
|
||||||
|
|
Loading…
Reference in a new issue