code: func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([]*node, error) {
  	// If we haven't seen a ping from the destination node for a while, it won't remember
  	// our endpoint proof and reject findnode. Solicit a ping first.
  	if time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration {
  		<-t.sendPing(toid, toaddr, nil)
  		// Wait for them to ping back and process our pong.
  		time.Sleep(respTimeout)
  	}
  
  	// Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is
  	// active until enough nodes have been received.
  	nodes := make([]*node, 0, bucketSize)
  	nreceived := 0
  	errc := t.pending(toid, toaddr.IP, p_neighborsV4, func(r interface{}) (matched bool, requestDone bool) {
  		reply := r.(*neighborsV4)
  		for _, rn := range reply.Nodes {
  			nreceived++
  			n, err := t.nodeFromRPC(toaddr, rn)
  			if err != nil {
  				t.log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err)
  				continue
  			}
  			nodes = append(nodes, n)
  		}
  		return true, nreceived >= bucketSize
  	})
  	t.send(toaddr, toid, p_findnodeV4, &findnodeV4{
  		Target:     target,
  		Expiration: uint64(time.Now().Add(expiration).Unix()),
  	})
  	return nodes, <-errc
  }
docs: // findnode sends a findnode request to the given node and waits until
  // the node has sent up to k neighbors.