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