package p2p import ( "net" ) const ( severityThreshold = 10 ) type DisconnectRequest struct { addr net.Addr reason DiscReason } type PeerErrorHandler struct { quit chan chan bool address net.Addr peerDisconnect chan DisconnectRequest severity int peerErrorChan chan *PeerError blacklist Blacklist } func NewPeerErrorHandler(address net.Addr, peerDisconnect chan DisconnectRequest, peerErrorChan chan *PeerError, blacklist Blacklist) *PeerErrorHandler { return &PeerErrorHandler{ quit: make(chan chan bool), address: address, peerDisconnect: peerDisconnect, peerErrorChan: peerErrorChan, blacklist: blacklist, } } func (self *PeerErrorHandler) Start() { go self.listen() } func (self *PeerErrorHandler) Stop() { q := make(chan bool) self.quit <- q <-q } func (self *PeerErrorHandler) listen() { for { select { case peerError, ok := <-self.peerErrorChan: if ok { logger.Debugf("error %v\n", peerError) go self.handle(peerError) } else { return } case q := <-self.quit: q <- true return } } } func (self *PeerErrorHandler) handle(peerError *PeerError) { reason := DiscReason(' ') switch peerError.Code { case P2PVersionMismatch: reason = DiscIncompatibleVersion case PubkeyMissing, PubkeyInvalid: reason = DiscInvalidIdentity case PubkeyForbidden: reason = DiscUselessPeer case InvalidMsgCode, PacketTooShort, PayloadTooShort, MagicTokenMismatch, EmptyPayload, ProtocolBreach: reason = DiscProtocolError case PingTimeout: reason = DiscReadTimeout case WriteError, MiscError: reason = DiscNetworkError case InvalidGenesis, InvalidNetworkId, InvalidProtocolVersion: reason = DiscSubprotocolError default: self.severity += self.getSeverity(peerError) } if self.severity >= severityThreshold { reason = DiscSubprotocolError } if reason != DiscReason(' ') { self.peerDisconnect <- DisconnectRequest{ addr: self.address, reason: reason, } } } func (self *PeerErrorHandler) getSeverity(peerError *PeerError) int { switch peerError.Code { case ReadError: return 4 //tolerate 3 :) default: return 1 } }