102 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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
 | 
						|
	}
 | 
						|
}
 |