htlcswitch/switch: select on quit channels for switch commands

This commit fixes a deadlock scenario caused when some
switch methods are waiting for a response on the
command's done/err chan. However, no such response will
be delivered if the main event loop has already exited.
This is resolved by selecting on the command's done/err chan
and the server's quit chan simultaneously.
This commit is contained in:
Conner Fromknecht 2018-02-07 17:47:16 -08:00
parent 7bbcbc6fea
commit 1dc12549d2
No known key found for this signature in database
GPG Key ID: 39DE78FBE6ACB0EF

@ -1001,10 +1001,15 @@ func (s *Switch) AddLink(link ChannelLink) error {
select {
case s.linkControl <- command:
return <-command.err
select {
case err := <-command.err:
return err
case <-s.quit:
}
case <-s.quit:
return errors.New("unable to add link htlc switch was stopped")
}
return errors.New("unable to add link htlc switch was stopped")
}
// addLink is used to add the newly created channel link and start use it to
@ -1055,12 +1060,26 @@ func (s *Switch) GetLink(chanID lnwire.ChannelID) (ChannelLink, error) {
done: make(chan ChannelLink, 1),
}
query:
select {
case s.linkControl <- command:
return <-command.done, <-command.err
var link ChannelLink
select {
case link = <-command.done:
case <-s.quit:
break query
}
select {
case err := <-command.err:
return link, err
case <-s.quit:
}
case <-s.quit:
return nil, errors.New("unable to get link htlc switch was stopped")
}
return nil, errors.New("unable to get link htlc switch was stopped")
}
// getLink attempts to return the link that has the specified channel ID.
@ -1101,11 +1120,15 @@ func (s *Switch) RemoveLink(chanID lnwire.ChannelID) error {
select {
case s.linkControl <- command:
return <-command.err
select {
case err := <-command.err:
return err
case <-s.quit:
}
case <-s.quit:
return errors.New("unable to remove link htlc switch was " +
"stopped")
}
return errors.New("unable to remove link htlc switch was stopped")
}
// removeLink is used to remove and stop the channel link.
@ -1154,11 +1177,15 @@ func (s *Switch) UpdateShortChanID(chanID lnwire.ChannelID,
select {
case s.linkControl <- command:
return <-command.err
select {
case err := <-command.err:
return err
case <-s.quit:
}
case <-s.quit:
return errors.New("unable to remove link htlc switch was " +
"stopped")
}
return errors.New("unable to update short chan id htlc switch was stopped")
}
// updateShortChanID updates the short chan ID of an existing link.
@ -1203,12 +1230,26 @@ func (s *Switch) GetLinksByInterface(hop [33]byte) ([]ChannelLink, error) {
done: make(chan []ChannelLink, 1),
}
query:
select {
case s.linkControl <- command:
return <-command.done, <-command.err
var links []ChannelLink
select {
case links = <-command.done:
case <-s.quit:
break query
}
select {
case err := <-command.err:
return links, err
case <-s.quit:
}
case <-s.quit:
return nil, errors.New("unable to get links htlc switch was stopped")
}
return nil, errors.New("unable to get links htlc switch was stopped")
}
// getLinks is function which returns the channel links of the peer by hop