refactor: make tie breaking part of the Connection interface

and thus eliminate all knowledge of LocalConnection from the
LocalPeer.handle* methods
This commit is contained in:
Matthias Radestock committed 2015-01-21 21:44:22 +00:00
1 parent 99525ebf85
commit 8af2a1c25d
2 files changed
+36 -22

No files matched your search

+9 -3
View File
@@ -15,6 +15,7 @@ import (
type Connection interface {
Local() *Peer
Remote() *Peer
BreakTie(Connection) ConnectionTieBreak
RemoteTCPAddr() string
Established() bool
Shutdown(error)
@@ -80,6 +81,10 @@ func (conn *RemoteConnection) Remote() *Peer {
return conn.remote
}
func (conn *RemoteConnection) BreakTie(Connection) ConnectionTieBreak {
return TieBreakTied
}
func (conn *RemoteConnection) RemoteTCPAddr() string {
return conn.remoteTCPAddr
}
@@ -124,12 +129,13 @@ func (conn *LocalConnection) Start(acceptNewPeer bool) {
go conn.run(queryChan, acceptNewPeer)
}
func (conn *LocalConnection) BreakTie(dupConn *LocalConnection) ConnectionTieBreak {
func (conn *LocalConnection) BreakTie(dupConn Connection) ConnectionTieBreak {
dupConnLocal := dupConn.(*LocalConnection)
// conn.uid is used as the tie breaker here, in the knowledge that
// both sides will make the same decision.
if conn.uid < dupConn.uid {
if conn.uid < dupConnLocal.uid {
return TieBreakWon
} else if dupConn.uid < conn.uid {
} else if dupConnLocal.uid < conn.uid {
return TieBreakLost
} else {
return TieBreakTied
+27 -19
View File
@@ -163,19 +163,28 @@ func (peer *LocalPeer) queryLoop(queryChan <-chan *PeerInteraction) {
}
switch query.code {
case PAddConnection:
peer.handleAddConnection(query.payload.(*LocalConnection))
conn := query.payload.(*LocalConnection)
if peer.handleAddConnection(conn) {
conn.log("connection added")
}
case PDeleteConnection:
peer.handleDeleteConnection(query.payload.(*LocalConnection))
conn := query.payload.(*LocalConnection)
if peer.handleDeleteConnection(conn) {
conn.log("connection deleted")
}
query.resultChan <- nil
case PConnectionEstablished:
peer.handleConnectionEstablished(query.payload.(*LocalConnection))
conn := query.payload.(*LocalConnection)
if peer.handleConnectionEstablished(conn) {
conn.log("connection fully established")
}
case PSendProtocolMsg:
peer.handleSendProtocolMsg(query.payload.(ProtocolMsg))
}
}
}
func (peer *LocalPeer) handleAddConnection(conn *LocalConnection) {
func (peer *LocalPeer) handleAddConnection(conn Connection) bool {
if peer.Peer != conn.Local() {
log.Fatal("Attempt made to add connection to peer where peer is not the source of connection")
}
@@ -187,33 +196,32 @@ func (peer *LocalPeer) handleAddConnection(conn *LocalConnection) {
// deliberately non symmetrical
if dupConn, found := peer.connections[toName]; found {
if dupConn == conn {
return
return false
}
dupConnLocal := dupConn.(*LocalConnection)
switch conn.BreakTie(dupConnLocal) {
switch conn.BreakTie(dupConn) {
case TieBreakWon:
dupConn.Shutdown(dupErr)
peer.handleDeleteConnection(dupConnLocal)
peer.handleDeleteConnection(dupConn)
case TieBreakLost:
conn.Shutdown(dupErr)
return
return false
case TieBreakTied:
// oh good grief. Sod it, just kill both of them.
conn.Shutdown(dupErr)
dupConn.Shutdown(dupErr)
peer.handleDeleteConnection(dupConnLocal)
return
peer.handleDeleteConnection(dupConn)
return false
}
}
if err := peer.checkConnectionLimit(); err != nil {
conn.Shutdown(err)
return
return false
}
peer.addConnection(conn)
conn.log("connection added")
return true
}
func (peer *LocalPeer) handleDeleteConnection(conn *LocalConnection) {
func (peer *LocalPeer) handleDeleteConnection(conn Connection) bool {
if peer.Peer != conn.Local() {
log.Fatal("Attempt made to delete connection from peer where peer is not the source of connection")
}
@@ -222,29 +230,29 @@ func (peer *LocalPeer) handleDeleteConnection(conn *LocalConnection) {
}
toName := conn.Remote().Name
if connFound, found := peer.connections[toName]; !found || connFound != conn {
return
return false
}
peer.deleteConnection(conn)
conn.log("connection deleted")
// Must do garbage collection first to ensure we don't send out an
// update with unreachable peers (can cause looping)
peer.Router.Peers.GarbageCollect()
if conn.Established() {
peer.broadcastPeerUpdate()
}
return true
}
func (peer *LocalPeer) handleConnectionEstablished(conn *LocalConnection) {
func (peer *LocalPeer) handleConnectionEstablished(conn Connection) bool {
if peer.Peer != conn.Local() {
log.Fatal("Peer informed of active connection where peer is not the source of connection")
}
if dupConn, found := peer.connections[conn.Remote().Name]; !found || conn != dupConn {
conn.Shutdown(fmt.Errorf("Cannot set unknown connection active"))
return
return false
}
peer.connectionEstablished(conn)
conn.log("connection fully established")
peer.broadcastPeerUpdate(conn.Remote())
return true
}
func (peer *LocalPeer) handleSendProtocolMsg(m ProtocolMsg) {