Skip to content

Commit

Permalink
Bugfix for issue #101.
Browse files Browse the repository at this point in the history
  • Loading branch information
mydesktop authored and davecgh committed Mar 24, 2014
1 parent 049a545 commit a55ea10
Showing 1 changed file with 18 additions and 7 deletions.
25 changes: 18 additions & 7 deletions peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ type peer struct {
disconnect int32 // only to be used atomically
persistent bool
versionKnown bool
versionMutex sync.Mutex
knownAddresses map[string]bool
knownInventory *MruInventoryMap
knownInvMutex sync.Mutex
Expand Down Expand Up @@ -199,6 +200,15 @@ func (p *peer) AddKnownInventory(invVect *btcwire.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
// current state.
func (p *peer) pushVersionMsg() error {
Expand Down Expand Up @@ -265,16 +275,19 @@ func (p *peer) handleVersionMsg(msg *btcwire.MsgVersion) {
}

// Limit to one version message per peer.
p.versionMutex.Lock()
if p.versionKnown {
p.logError("Only one version message per peer is allowed %s.",
p)
p.versionMutex.Unlock()
p.Disconnect()
return
}

// Negotiate the protocol version.
p.protocolVersion = minUint32(p.protocolVersion, uint32(msg.ProtocolVersion))
p.versionKnown = true
p.versionMutex.Unlock()
peerLog.Debugf("Negotiated protocol version %d for peer %s",
p.protocolVersion, p)
p.lastBlock = msg.LastBlock
Expand Down Expand Up @@ -988,7 +1001,7 @@ func (p *peer) writeMessage(msg btcwire.Message) {
if atomic.LoadInt32(&p.disconnect) != 0 {
return
}
if !p.versionKnown {
if !p.VersionKnown() {
switch msg.(type) {
case *btcwire.MsgVersion:
// This is OK.
Expand Down Expand Up @@ -1066,9 +1079,7 @@ func (p *peer) inHandler() {
// timeframe than a general idle timeout. The timer is then reset below
// to idleTimeoutMinutes for all future messages.
idleTimer := time.AfterFunc(negotiateTimeoutSeconds*time.Second, func() {
// XXX technically very very very slightly racy, doesn't really
// matter.
if p.versionKnown {
if p.VersionKnown() {
peerLog.Warnf("Peer %s no answer for %d minutes, "+
"disconnecting", p, idleTimeoutMinutes)
}
Expand Down Expand Up @@ -1101,7 +1112,7 @@ out:
p.lastRecv = time.Now()

// 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")
break out
}
Expand Down Expand Up @@ -1193,7 +1204,7 @@ out:
p.server.donePeers <- p

// 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)
}

Expand Down Expand Up @@ -1258,7 +1269,7 @@ out:

case iv := <-p.outputInvChan:
// No handshake? They'll find out soon enough.
if p.versionKnown {
if p.VersionKnown() {
invSendQueue.PushBack(iv)
}

Expand Down

0 comments on commit a55ea10

Please sign in to comment.