Bugfix for issue #101.

This commit is contained in:
mydesktop 2014-03-19 18:04:10 -04:00 committed by Dave Collins
parent 049a545427
commit a55ea104c7

25
peer.go
View file

@ -144,6 +144,7 @@ type peer struct {
disconnect int32 // only to be used atomically disconnect int32 // only to be used atomically
persistent bool persistent bool
versionKnown bool versionKnown bool
versionMutex sync.Mutex
knownAddresses map[string]bool knownAddresses map[string]bool
knownInventory *MruInventoryMap knownInventory *MruInventoryMap
knownInvMutex sync.Mutex knownInvMutex sync.Mutex
@ -199,6 +200,15 @@ func (p *peer) AddKnownInventory(invVect *btcwire.InvVect) {
p.knownInventory.Add(invVect) p.knownInventory.Add(invVect)
} }
// VersionKnown returns the whether or not the version of a peer is known locally.
// It is safe for concurrent access.
func (p *peer) VersionKnown() bool {
p.versionMutex.Lock()
defer p.versionMutex.Unlock()
return p.versionKnown
}
// pushVersionMsg sends a version message to the connected peer using the // pushVersionMsg sends a version message to the connected peer using the
// current state. // current state.
func (p *peer) pushVersionMsg() error { func (p *peer) pushVersionMsg() error {
@ -265,9 +275,11 @@ func (p *peer) handleVersionMsg(msg *btcwire.MsgVersion) {
} }
// Limit to one version message per peer. // Limit to one version message per peer.
p.versionMutex.Lock()
if p.versionKnown { if p.versionKnown {
p.logError("Only one version message per peer is allowed %s.", p.logError("Only one version message per peer is allowed %s.",
p) p)
p.versionMutex.Unlock()
p.Disconnect() p.Disconnect()
return return
} }
@ -275,6 +287,7 @@ func (p *peer) handleVersionMsg(msg *btcwire.MsgVersion) {
// Negotiate the protocol version. // Negotiate the protocol version.
p.protocolVersion = minUint32(p.protocolVersion, uint32(msg.ProtocolVersion)) p.protocolVersion = minUint32(p.protocolVersion, uint32(msg.ProtocolVersion))
p.versionKnown = true p.versionKnown = true
p.versionMutex.Unlock()
peerLog.Debugf("Negotiated protocol version %d for peer %s", peerLog.Debugf("Negotiated protocol version %d for peer %s",
p.protocolVersion, p) p.protocolVersion, p)
p.lastBlock = msg.LastBlock p.lastBlock = msg.LastBlock
@ -988,7 +1001,7 @@ func (p *peer) writeMessage(msg btcwire.Message) {
if atomic.LoadInt32(&p.disconnect) != 0 { if atomic.LoadInt32(&p.disconnect) != 0 {
return return
} }
if !p.versionKnown { if !p.VersionKnown() {
switch msg.(type) { switch msg.(type) {
case *btcwire.MsgVersion: case *btcwire.MsgVersion:
// This is OK. // This is OK.
@ -1066,9 +1079,7 @@ func (p *peer) inHandler() {
// timeframe than a general idle timeout. The timer is then reset below // timeframe than a general idle timeout. The timer is then reset below
// to idleTimeoutMinutes for all future messages. // to idleTimeoutMinutes for all future messages.
idleTimer := time.AfterFunc(negotiateTimeoutSeconds*time.Second, func() { idleTimer := time.AfterFunc(negotiateTimeoutSeconds*time.Second, func() {
// XXX technically very very very slightly racy, doesn't really if p.VersionKnown() {
// matter.
if p.versionKnown {
peerLog.Warnf("Peer %s no answer for %d minutes, "+ peerLog.Warnf("Peer %s no answer for %d minutes, "+
"disconnecting", p, idleTimeoutMinutes) "disconnecting", p, idleTimeoutMinutes)
} }
@ -1101,7 +1112,7 @@ out:
p.lastRecv = time.Now() p.lastRecv = time.Now()
// Ensure version message comes first. // Ensure version message comes first.
if _, ok := rmsg.(*btcwire.MsgVersion); !ok && !p.versionKnown { if _, ok := rmsg.(*btcwire.MsgVersion); !ok && !p.VersionKnown() {
p.logError("A version message must precede all others") p.logError("A version message must precede all others")
break out break out
} }
@ -1193,7 +1204,7 @@ out:
p.server.donePeers <- p p.server.donePeers <- p
// Only tell block manager we are gone if we ever told it we existed. // Only tell block manager we are gone if we ever told it we existed.
if p.versionKnown { if p.VersionKnown() {
p.server.blockManager.DonePeer(p) p.server.blockManager.DonePeer(p)
} }
@ -1258,7 +1269,7 @@ out:
case iv := <-p.outputInvChan: case iv := <-p.outputInvChan:
// No handshake? They'll find out soon enough. // No handshake? They'll find out soon enough.
if p.versionKnown { if p.VersionKnown() {
invSendQueue.PushBack(iv) invSendQueue.PushBack(iv)
} }