whisper: protect critical section in peer list management

This commit is contained in:
Guillaume Ballet 2018-04-22 14:50:19 +02:00
parent 85bd8607a7
commit ad1156653b

View file

@ -23,6 +23,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"io" "io"
"sync"
"time" "time"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
@ -184,19 +185,21 @@ updateLoop:
} }
// Cleanup and remove the peer from the list // Cleanup and remove the peer from the list
p.server.PeerMutex.Lock()
for i, it := range p.server.Peers { for i, it := range p.server.Peers {
if it.id == p.id { if it.id == p.id {
p.server.Peers = append(p.server.Peers[:i], p.server.Peers[i+1:]...) p.server.Peers = append(p.server.Peers[:i], p.server.Peers[i+1:]...)
break break
} }
} }
p.server.PeerMutex.Unlock()
} }
// LibP2PWhisperServer implements WhisperServer for libp2p. // LibP2PWhisperServer implements WhisperServer for libp2p.
type LibP2PWhisperServer struct { type LibP2PWhisperServer struct {
Host host.Host Host host.Host
Peers []*LibP2PPeer PeerMutex sync.RWMutex // Guard the list of active peers
whisper *Whisper whisper *Whisper
} }
@ -231,20 +234,23 @@ func (server *LibP2PWhisperServer) Start() error {
pid := stream.Conn().RemotePeer() pid := stream.Conn().RemotePeer()
var peer Peer var peer Peer
server.PeerMutex.RLock()
for _, p := range server.Peers { for _, p := range server.Peers {
if p.id == pid { if p.id == pid {
peer = p peer = p
break break
} }
} }
server.PeerMutex.RUnlock()
lps := newLibp2pStream(server, stream).(*LibP2PStream) lps := newLibp2pStream(server, stream).(*LibP2PStream)
// Unknown peer // Unknown peer
if peer == nil { if peer == nil {
peer = newLibP2PPeer(server, server.whisper, pid, lps) peer = newLibP2PPeer(server, server.whisper, pid, lps)
// TODO check critical section server.PeerMutex.Lock()
server.Peers = append(server.Peers, peer.(*LibP2PPeer)) server.Peers = append(server.Peers, peer.(*LibP2PPeer))
server.PeerMutex.Unlock()
} }
go server.whisper.HandlePeer(peer, lps) go server.whisper.HandlePeer(peer, lps)
@ -254,27 +260,33 @@ func (server *LibP2PWhisperServer) Start() error {
// Open a stream to every peer currently known // Open a stream to every peer currently known
var err error var err error
server.PeerMutex.RLock()
for _, p := range server.Peers { for _, p := range server.Peers {
if e := server.connectToPeer(p); e != nil { if e := server.connectToPeer(p); e != nil {
err = e err = e
} }
} }
server.PeerMutex.RUnlock()
return err return err
} }
// Stop stops the server // Stop stops the server
func (server *LibP2PWhisperServer) Stop() { func (server *LibP2PWhisperServer) Stop() {
server.PeerMutex.RLock()
for _, p := range server.Peers { for _, p := range server.Peers {
// TODO send disconnect message // TODO send disconnect message
p.connectionStream.lp2pStream.Close() p.connectionStream.lp2pStream.Close()
} }
server.PeerMutex.RUnlock()
server.Host.Close() server.Host.Close()
} }
// PeerCount returns the peer count for the node // PeerCount returns the peer count for the node
func (server *LibP2PWhisperServer) PeerCount() int { func (server *LibP2PWhisperServer) PeerCount() int {
server.PeerMutex.RLock()
defer server.PeerMutex.RUnlock()
return len(server.Peers) return len(server.Peers)
} }
@ -302,7 +314,9 @@ func (server *LibP2PWhisperServer) AddPeer(addr ma.Multiaddr) *LibP2PPeer {
ipaddr := addr.Decapsulate(ipfsaddrpart) ipaddr := addr.Decapsulate(ipfsaddrpart)
server.Host.Peerstore().AddAddr(peerid, ipaddr, pstore.PermanentAddrTTL) server.Host.Peerstore().AddAddr(peerid, ipaddr, pstore.PermanentAddrTTL)
newPeer := newLibP2PPeer(server, server.whisper, peerid, nil).(*LibP2PPeer) newPeer := newLibP2PPeer(server, server.whisper, peerid, nil).(*LibP2PPeer)
server.PeerMutex.Lock()
server.Peers = append(server.Peers, newPeer) server.Peers = append(server.Peers, newPeer)
server.PeerMutex.Unlock()
return newPeer return newPeer
} }
@ -333,6 +347,10 @@ func NewLibP2PWhisperServer(port uint, whisper *Whisper) (WhisperServer, error)
} }
h := basichost.New(network) h := basichost.New(network)
server := &LibP2PWhisperServer{h, []*LibP2PPeer{}, whisper} server := &LibP2PWhisperServer{
Host: h,
Peers: []*LibP2PPeer{},
whisper: whisper,
}
return server, nil return server, nil
} }