github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/discover/udp.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package discover
    26  
    27  import (
    28  	"bytes"
    29  	"container/list"
    30  	"crypto/ecdsa"
    31  	"errors"
    32  	"fmt"
    33  	"net"
    34  	"time"
    35  
    36  	"github.com/ethereum/go-ethereum/crypto"
    37  	"github.com/ethereum/go-ethereum/log"
    38  	"github.com/ethereum/go-ethereum/p2p/nat"
    39  	"github.com/ethereum/go-ethereum/p2p/netutil"
    40  	"github.com/ethereum/go-ethereum/rlp"
    41  )
    42  
    43  //错误
    44  var (
    45  	errPacketTooSmall   = errors.New("too small")
    46  	errBadHash          = errors.New("bad hash")
    47  	errExpired          = errors.New("expired")
    48  	errUnsolicitedReply = errors.New("unsolicited reply")
    49  	errUnknownNode      = errors.New("unknown node")
    50  	errTimeout          = errors.New("RPC timeout")
    51  	errClockWarp        = errors.New("reply deadline too far in the future")
    52  	errClosed           = errors.New("socket closed")
    53  )
    54  
    55  //超时
    56  const (
    57  	respTimeout = 500 * time.Millisecond
    58  	expiration  = 20 * time.Second
    59  
    60  ntpFailureThreshold = 32               //连续超时,之后检查NTP
    61  ntpWarningCooldown  = 10 * time.Minute //重复NTP警告之前要经过的最短时间
    62  driftThreshold      = 10 * time.Second //警告用户前允许的时钟漂移
    63  )
    64  
    65  //RPC数据包类型
    66  const (
    67  pingPacket = iota + 1 //零为“保留”
    68  	pongPacket
    69  	findnodePacket
    70  	neighborsPacket
    71  )
    72  
    73  //RPC请求结构
    74  type (
    75  	ping struct {
    76  		Version    uint
    77  		From, To   rpcEndpoint
    78  		Expiration uint64
    79  //忽略其他字段(为了向前兼容)。
    80  		Rest []rlp.RawValue `rlp:"tail"`
    81  	}
    82  
    83  //乒乓球是对乒乓球的回应。
    84  	pong struct {
    85  //此字段应镜像UDP信封地址
    86  //提供了一种发现
    87  //外部地址(在NAT之后)。
    88  		To rpcEndpoint
    89  
    90  ReplyTok   []byte //这包含ping包的哈希。
    91  Expiration uint64 //数据包失效的绝对时间戳。
    92  //忽略其他字段(为了向前兼容)。
    93  		Rest []rlp.RawValue `rlp:"tail"`
    94  	}
    95  
    96  //findnode是对接近给定目标的节点的查询。
    97  	findnode struct {
    98  Target     NodeID //不需要是实际的公钥
    99  		Expiration uint64
   100  //忽略其他字段(为了向前兼容)。
   101  		Rest []rlp.RawValue `rlp:"tail"`
   102  	}
   103  
   104  //回复findnode
   105  	neighbors struct {
   106  		Nodes      []rpcNode
   107  		Expiration uint64
   108  //忽略其他字段(为了向前兼容)。
   109  		Rest []rlp.RawValue `rlp:"tail"`
   110  	}
   111  
   112  	rpcNode struct {
   113  IP  net.IP //IPv4的len 4或IPv6的len 16
   114  UDP uint16 //用于发现协议
   115  TCP uint16 //对于RLPX协议
   116  		ID  NodeID
   117  	}
   118  
   119  	rpcEndpoint struct {
   120  IP  net.IP //IPv4的len 4或IPv6的len 16
   121  UDP uint16 //用于发现协议
   122  TCP uint16 //对于RLPX协议
   123  	}
   124  )
   125  
   126  func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint {
   127  	ip := addr.IP.To4()
   128  	if ip == nil {
   129  		ip = addr.IP.To16()
   130  	}
   131  	return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
   132  }
   133  
   134  func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) {
   135  	if rn.UDP <= 1024 {
   136  		return nil, errors.New("low port")
   137  	}
   138  	if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil {
   139  		return nil, err
   140  	}
   141  	if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) {
   142  		return nil, errors.New("not contained in netrestrict whitelist")
   143  	}
   144  	n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP)
   145  	err := n.validateComplete()
   146  	return n, err
   147  }
   148  
   149  func nodeToRPC(n *Node) rpcNode {
   150  	return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP}
   151  }
   152  
   153  type packet interface {
   154  	handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error
   155  	name() string
   156  }
   157  
   158  type conn interface {
   159  	ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)
   160  	WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error)
   161  	Close() error
   162  	LocalAddr() net.Addr
   163  }
   164  
   165  //UDP实现RPC协议。
   166  type udp struct {
   167  	conn        conn
   168  	netrestrict *netutil.Netlist
   169  	priv        *ecdsa.PrivateKey
   170  	ourEndpoint rpcEndpoint
   171  
   172  	addpending chan *pending
   173  	gotreply   chan reply
   174  
   175  	closing chan struct{}
   176  	nat     nat.Interface
   177  
   178  	*Table
   179  }
   180  
   181  //挂起表示挂起的答复。
   182  //
   183  //协议的某些实现希望发送多个
   184  //将数据包回复到findnode。一般来说,任何邻居包都不能
   185  //与特定的findnode包匹配。
   186  //
   187  //我们的实现通过存储
   188  //每个等待答复。来自节点的传入数据包被调度
   189  //到该节点的所有回调函数。
   190  type pending struct {
   191  //这些字段必须在答复中匹配。
   192  	from  NodeID
   193  	ptype byte
   194  
   195  //请求必须完成的时间
   196  	deadline time.Time
   197  
   198  //当匹配的答复到达时调用回调。如果它回来
   199  //如果为true,则从挂起的答复队列中删除回调。
   200  //如果返回错误,则认为答复不完整,并且
   201  //将为下一个匹配的答复再次调用回调。
   202  	callback func(resp interface{}) (done bool)
   203  
   204  //当回调指示完成或
   205  //如果在超时时间内没有收到进一步的答复,则出错。
   206  	errc chan<- error
   207  }
   208  
   209  type reply struct {
   210  	from  NodeID
   211  	ptype byte
   212  	data  interface{}
   213  //循环指示是否存在
   214  //通过此频道发送的匹配请求。
   215  	matched chan<- bool
   216  }
   217  
   218  //无法处理readpacket时,会将其发送到未处理的通道。
   219  type ReadPacket struct {
   220  	Data []byte
   221  	Addr *net.UDPAddr
   222  }
   223  
   224  //配置保存与表相关的设置。
   225  type Config struct {
   226  //需要这些设置并配置UDP侦听器:
   227  	PrivateKey *ecdsa.PrivateKey
   228  
   229  //这些设置是可选的:
   230  AnnounceAddr *net.UDPAddr      //DHT中公布的本地地址
   231  NodeDBPath   string            //如果设置,则节点数据库存储在此文件系统位置
   232  NetRestrict  *netutil.Netlist  //网络白名单
   233  Bootnodes    []*Node           //引导程序节点列表
   234  Unhandled    chan<- ReadPacket //在此通道上发送未处理的数据包
   235  }
   236  
   237  //listenudp返回一个新表,用于侦听laddr上的udp包。
   238  func ListenUDP(c conn, cfg Config) (*Table, error) {
   239  	tab, _, err := newUDP(c, cfg)
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  	log.Info("UDP listener up", "self", tab.self)
   244  	return tab, nil
   245  }
   246  
   247  func newUDP(c conn, cfg Config) (*Table, *udp, error) {
   248  	udp := &udp{
   249  		conn:        c,
   250  		priv:        cfg.PrivateKey,
   251  		netrestrict: cfg.NetRestrict,
   252  		closing:     make(chan struct{}),
   253  		gotreply:    make(chan reply),
   254  		addpending:  make(chan *pending),
   255  	}
   256  	realaddr := c.LocalAddr().(*net.UDPAddr)
   257  	if cfg.AnnounceAddr != nil {
   258  		realaddr = cfg.AnnounceAddr
   259  	}
   260  //TODO:单独的TCP端口
   261  	udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port))
   262  	tab, err := newTable(udp, PubkeyID(&cfg.PrivateKey.PublicKey), realaddr, cfg.NodeDBPath, cfg.Bootnodes)
   263  	if err != nil {
   264  		return nil, nil, err
   265  	}
   266  	udp.Table = tab
   267  
   268  	go udp.loop()
   269  	go udp.readLoop(cfg.Unhandled)
   270  	return udp.Table, udp, nil
   271  }
   272  
   273  func (t *udp) close() {
   274  	close(t.closing)
   275  	t.conn.Close()
   276  //TODO:等待循环结束。
   277  }
   278  
   279  //ping向给定节点发送ping消息并等待答复。
   280  func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error {
   281  	return <-t.sendPing(toid, toaddr, nil)
   282  }
   283  
   284  //发送ping向给定节点发送ping消息并调用回调
   285  //当回复到达时。
   286  func (t *udp) sendPing(toid NodeID, toaddr *net.UDPAddr, callback func()) <-chan error {
   287  	req := &ping{
   288  		Version:    4,
   289  		From:       t.ourEndpoint,
   290  To:         makeEndpoint(toaddr, 0), //TODO:可能使用数据库中已知的TCP端口
   291  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   292  	}
   293  	packet, hash, err := encodePacket(t.priv, pingPacket, req)
   294  	if err != nil {
   295  		errc := make(chan error, 1)
   296  		errc <- err
   297  		return errc
   298  	}
   299  	errc := t.pending(toid, pongPacket, func(p interface{}) bool {
   300  		ok := bytes.Equal(p.(*pong).ReplyTok, hash)
   301  		if ok && callback != nil {
   302  			callback()
   303  		}
   304  		return ok
   305  	})
   306  	t.write(toaddr, req.name(), packet)
   307  	return errc
   308  }
   309  
   310  func (t *udp) waitping(from NodeID) error {
   311  	return <-t.pending(from, pingPacket, func(interface{}) bool { return true })
   312  }
   313  
   314  //findnode向给定节点发送findnode请求,并等待直到
   315  //节点已发送到k个邻居。
   316  func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) {
   317  //如果我们有一段时间没有看到目标节点的ping,它将不会记得
   318  //我们的端点证明和拒绝findnode。先打个乒乓球。
   319  	if time.Since(t.db.lastPingReceived(toid)) > nodeDBNodeExpiration {
   320  		t.ping(toid, toaddr)
   321  		t.waitping(toid)
   322  	}
   323  
   324  	nodes := make([]*Node, 0, bucketSize)
   325  	nreceived := 0
   326  	errc := t.pending(toid, neighborsPacket, func(r interface{}) bool {
   327  		reply := r.(*neighbors)
   328  		for _, rn := range reply.Nodes {
   329  			nreceived++
   330  			n, err := t.nodeFromRPC(toaddr, rn)
   331  			if err != nil {
   332  				log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err)
   333  				continue
   334  			}
   335  			nodes = append(nodes, n)
   336  		}
   337  		return nreceived >= bucketSize
   338  	})
   339  	t.send(toaddr, findnodePacket, &findnode{
   340  		Target:     target,
   341  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   342  	})
   343  	return nodes, <-errc
   344  }
   345  
   346  //挂起向挂起的答复队列添加答复回调。
   347  //有关详细说明,请参阅“挂起”类型的文档。
   348  func (t *udp) pending(id NodeID, ptype byte, callback func(interface{}) bool) <-chan error {
   349  	ch := make(chan error, 1)
   350  	p := &pending{from: id, ptype: ptype, callback: callback, errc: ch}
   351  	select {
   352  	case t.addpending <- p:
   353  //循环将处理它
   354  	case <-t.closing:
   355  		ch <- errClosed
   356  	}
   357  	return ch
   358  }
   359  
   360  func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool {
   361  	matched := make(chan bool, 1)
   362  	select {
   363  	case t.gotreply <- reply{from, ptype, req, matched}:
   364  //循环将处理它
   365  		return <-matched
   366  	case <-t.closing:
   367  		return false
   368  	}
   369  }
   370  
   371  //循环在自己的Goroutine中运行。它跟踪
   372  //刷新计时器和挂起的答复队列。
   373  func (t *udp) loop() {
   374  	var (
   375  		plist        = list.New()
   376  		timeout      = time.NewTimer(0)
   377  nextTimeout  *pending //上次重置超时时的plist头
   378  contTimeouts = 0      //要执行NTP检查的连续超时数
   379  		ntpWarnTime  = time.Unix(0, 0)
   380  	)
   381  <-timeout.C //忽略第一次超时
   382  	defer timeout.Stop()
   383  
   384  	resetTimeout := func() {
   385  		if plist.Front() == nil || nextTimeout == plist.Front().Value {
   386  			return
   387  		}
   388  //启动计时器,以便在下一个挂起的答复过期时触发。
   389  		now := time.Now()
   390  		for el := plist.Front(); el != nil; el = el.Next() {
   391  			nextTimeout = el.Value.(*pending)
   392  			if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout {
   393  				timeout.Reset(dist)
   394  				return
   395  			}
   396  //删除截止时间太长的挂起答复
   397  //未来。如果系统时钟跳变,就会发生这种情况。
   398  //在最后期限被分配后向后。
   399  			nextTimeout.errc <- errClockWarp
   400  			plist.Remove(el)
   401  		}
   402  		nextTimeout = nil
   403  		timeout.Stop()
   404  	}
   405  
   406  	for {
   407  		resetTimeout()
   408  
   409  		select {
   410  		case <-t.closing:
   411  			for el := plist.Front(); el != nil; el = el.Next() {
   412  				el.Value.(*pending).errc <- errClosed
   413  			}
   414  			return
   415  
   416  		case p := <-t.addpending:
   417  			p.deadline = time.Now().Add(respTimeout)
   418  			plist.PushBack(p)
   419  
   420  		case r := <-t.gotreply:
   421  			var matched bool
   422  			for el := plist.Front(); el != nil; el = el.Next() {
   423  				p := el.Value.(*pending)
   424  				if p.from == r.from && p.ptype == r.ptype {
   425  					matched = true
   426  //如果Matcher的回调指示
   427  //所有答复都已收到。这是
   428  //需要多个数据包类型
   429  //应答包。
   430  					if p.callback(r.data) {
   431  						p.errc <- nil
   432  						plist.Remove(el)
   433  					}
   434  //重置连续超时计数器(时间漂移检测)
   435  					contTimeouts = 0
   436  				}
   437  			}
   438  			r.matched <- matched
   439  
   440  		case now := <-timeout.C:
   441  			nextTimeout = nil
   442  
   443  //通知并删除期限已过的回调。
   444  			for el := plist.Front(); el != nil; el = el.Next() {
   445  				p := el.Value.(*pending)
   446  				if now.After(p.deadline) || now.Equal(p.deadline) {
   447  					p.errc <- errTimeout
   448  					plist.Remove(el)
   449  					contTimeouts++
   450  				}
   451  			}
   452  //如果我们累积了太多超时,请执行NTP时间同步检查
   453  			if contTimeouts > ntpFailureThreshold {
   454  				if time.Since(ntpWarnTime) >= ntpWarningCooldown {
   455  					ntpWarnTime = time.Now()
   456  					go checkClockDrift()
   457  				}
   458  				contTimeouts = 0
   459  			}
   460  		}
   461  	}
   462  }
   463  
   464  const (
   465  	macSize  = 256 / 8
   466  	sigSize  = 520 / 8
   467  headSize = macSize + sigSize //包帧数据空间
   468  )
   469  
   470  var (
   471  	headSpace = make([]byte, headSize)
   472  
   473  //邻居答复通过多个数据包发送到
   474  //低于1280字节的限制。我们计算最大数
   475  //通过填充一个包直到它变得太大。
   476  	maxNeighbors int
   477  )
   478  
   479  func init() {
   480  	p := neighbors{Expiration: ^uint64(0)}
   481  	maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)}
   482  	for n := 0; ; n++ {
   483  		p.Nodes = append(p.Nodes, maxSizeNode)
   484  		size, _, err := rlp.EncodeToReader(p)
   485  		if err != nil {
   486  //如果发生这种情况,它将被单元测试捕获。
   487  			panic("cannot encode: " + err.Error())
   488  		}
   489  		if headSize+size+1 >= 1280 {
   490  			maxNeighbors = n
   491  			break
   492  		}
   493  	}
   494  }
   495  
   496  func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) ([]byte, error) {
   497  	packet, hash, err := encodePacket(t.priv, ptype, req)
   498  	if err != nil {
   499  		return hash, err
   500  	}
   501  	return hash, t.write(toaddr, req.name(), packet)
   502  }
   503  
   504  func (t *udp) write(toaddr *net.UDPAddr, what string, packet []byte) error {
   505  	_, err := t.conn.WriteToUDP(packet, toaddr)
   506  	log.Trace(">> "+what, "addr", toaddr, "err", err)
   507  	return err
   508  }
   509  
   510  func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (packet, hash []byte, err error) {
   511  	b := new(bytes.Buffer)
   512  	b.Write(headSpace)
   513  	b.WriteByte(ptype)
   514  	if err := rlp.Encode(b, req); err != nil {
   515  		log.Error("Can't encode discv4 packet", "err", err)
   516  		return nil, nil, err
   517  	}
   518  	packet = b.Bytes()
   519  	sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
   520  	if err != nil {
   521  		log.Error("Can't sign discv4 packet", "err", err)
   522  		return nil, nil, err
   523  	}
   524  	copy(packet[macSize:], sig)
   525  //将哈希添加到前面。注意:这不保护
   526  //以任何方式打包。我们的公钥将是这个哈希的一部分
   527  //未来。
   528  	hash = crypto.Keccak256(packet[macSize:])
   529  	copy(packet, hash)
   530  	return packet, hash, nil
   531  }
   532  
   533  //readloop在自己的goroutine中运行。它处理传入的UDP数据包。
   534  func (t *udp) readLoop(unhandled chan<- ReadPacket) {
   535  	defer t.conn.Close()
   536  	if unhandled != nil {
   537  		defer close(unhandled)
   538  	}
   539  //发现数据包被定义为不大于1280字节。
   540  //大于此尺寸的包装将在末端切割并处理
   541  //因为它们的哈希不匹配而无效。
   542  	buf := make([]byte, 1280)
   543  	for {
   544  		nbytes, from, err := t.conn.ReadFromUDP(buf)
   545  		if netutil.IsTemporaryError(err) {
   546  //忽略临时读取错误。
   547  			log.Debug("Temporary UDP read error", "err", err)
   548  			continue
   549  		} else if err != nil {
   550  //关闭永久错误循环。
   551  			log.Debug("UDP read error", "err", err)
   552  			return
   553  		}
   554  		if t.handlePacket(from, buf[:nbytes]) != nil && unhandled != nil {
   555  			select {
   556  			case unhandled <- ReadPacket{buf[:nbytes], from}:
   557  			default:
   558  			}
   559  		}
   560  	}
   561  }
   562  
   563  func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error {
   564  	packet, fromID, hash, err := decodePacket(buf)
   565  	if err != nil {
   566  		log.Debug("Bad discv4 packet", "addr", from, "err", err)
   567  		return err
   568  	}
   569  	err = packet.handle(t, from, fromID, hash)
   570  	log.Trace("<< "+packet.name(), "addr", from, "err", err)
   571  	return err
   572  }
   573  
   574  func decodePacket(buf []byte) (packet, NodeID, []byte, error) {
   575  	if len(buf) < headSize+1 {
   576  		return nil, NodeID{}, nil, errPacketTooSmall
   577  	}
   578  	hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:]
   579  	shouldhash := crypto.Keccak256(buf[macSize:])
   580  	if !bytes.Equal(hash, shouldhash) {
   581  		return nil, NodeID{}, nil, errBadHash
   582  	}
   583  	fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig)
   584  	if err != nil {
   585  		return nil, NodeID{}, hash, err
   586  	}
   587  	var req packet
   588  	switch ptype := sigdata[0]; ptype {
   589  	case pingPacket:
   590  		req = new(ping)
   591  	case pongPacket:
   592  		req = new(pong)
   593  	case findnodePacket:
   594  		req = new(findnode)
   595  	case neighborsPacket:
   596  		req = new(neighbors)
   597  	default:
   598  		return nil, fromID, hash, fmt.Errorf("unknown type: %d", ptype)
   599  	}
   600  	s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0)
   601  	err = s.Decode(req)
   602  	return req, fromID, hash, err
   603  }
   604  
   605  func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   606  	if expired(req.Expiration) {
   607  		return errExpired
   608  	}
   609  	t.send(from, pongPacket, &pong{
   610  		To:         makeEndpoint(from, req.From.TCP),
   611  		ReplyTok:   mac,
   612  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   613  	})
   614  	t.handleReply(fromID, pingPacket, req)
   615  
   616  //将节点添加到表中。在这样做之前,确保我们最近有足够的乒乓球
   617  //记录在数据库中,以便稍后接受其findnode请求。
   618  	n := NewNode(fromID, from.IP, uint16(from.Port), req.From.TCP)
   619  	if time.Since(t.db.lastPongReceived(fromID)) > nodeDBNodeExpiration {
   620  		t.sendPing(fromID, from, func() { t.addThroughPing(n) })
   621  	} else {
   622  		t.addThroughPing(n)
   623  	}
   624  	t.db.updateLastPingReceived(fromID, time.Now())
   625  	return nil
   626  }
   627  
   628  func (req *ping) name() string { return "PING/v4" }
   629  
   630  func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   631  	if expired(req.Expiration) {
   632  		return errExpired
   633  	}
   634  	if !t.handleReply(fromID, pongPacket, req) {
   635  		return errUnsolicitedReply
   636  	}
   637  	t.db.updateLastPongReceived(fromID, time.Now())
   638  	return nil
   639  }
   640  
   641  func (req *pong) name() string { return "PONG/v4" }
   642  
   643  func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   644  	if expired(req.Expiration) {
   645  		return errExpired
   646  	}
   647  	if !t.db.hasBond(fromID) {
   648  //不存在端点验证pong,我们不处理数据包。这可以防止
   649  //攻击向量,发现协议可用于放大
   650  //DDoS攻击。恶意参与者将使用IP地址发送findnode请求
   651  //目标的UDP端口作为源地址。findnode的接收者
   652  //然后,包将发送一个邻居包(比
   653  //找到受害者。
   654  		return errUnknownNode
   655  	}
   656  	target := crypto.Keccak256Hash(req.Target[:])
   657  	t.mutex.Lock()
   658  	closest := t.closest(target, bucketSize).entries
   659  	t.mutex.Unlock()
   660  
   661  	p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())}
   662  	var sent bool
   663  //以块形式发送邻居,每个数据包最多有maxneighbors
   664  //低于1280字节的限制。
   665  	for _, n := range closest {
   666  		if netutil.CheckRelayIP(from.IP, n.IP) == nil {
   667  			p.Nodes = append(p.Nodes, nodeToRPC(n))
   668  		}
   669  		if len(p.Nodes) == maxNeighbors {
   670  			t.send(from, neighborsPacket, &p)
   671  			p.Nodes = p.Nodes[:0]
   672  			sent = true
   673  		}
   674  	}
   675  	if len(p.Nodes) > 0 || !sent {
   676  		t.send(from, neighborsPacket, &p)
   677  	}
   678  	return nil
   679  }
   680  
   681  func (req *findnode) name() string { return "FINDNODE/v4" }
   682  
   683  func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   684  	if expired(req.Expiration) {
   685  		return errExpired
   686  	}
   687  	if !t.handleReply(fromID, neighborsPacket, req) {
   688  		return errUnsolicitedReply
   689  	}
   690  	return nil
   691  }
   692  
   693  func (req *neighbors) name() string { return "NEIGHBORS/v4" }
   694  
   695  func expired(ts uint64) bool {
   696  	return time.Unix(int64(ts), 0).Before(time.Now())
   697  }