mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
p2p/discover: fix nits in UDP transport
We would skip sending neighbors replies if there were fewer than maxNeighbors results and CheckRelayIP returned an error for the last one. While here, also resolve a TODO about pong reply tokens.
This commit is contained in:
parent
e87bb1f380
commit
94dcdb5152
2 changed files with 42 additions and 27 deletions
|
|
@ -273,14 +273,20 @@ func (t *udp) close() {
|
|||
|
||||
// ping sends a ping message to the given node and waits for a reply.
|
||||
func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error {
|
||||
// TODO: maybe check for ReplyTo field in callback to measure RTT
|
||||
errc := t.pending(toid, pongPacket, func(interface{}) bool { return true })
|
||||
t.send(toaddr, pingPacket, &ping{
|
||||
req := &ping{
|
||||
Version: Version,
|
||||
From: t.ourEndpoint,
|
||||
To: makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB
|
||||
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
||||
}
|
||||
packet, hash, err := encodePacket(t.priv, pingPacket, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errc := t.pending(toid, pongPacket, func(p interface{}) bool {
|
||||
return bytes.Equal(p.(*pong).ReplyTok, hash)
|
||||
})
|
||||
t.write(toaddr, req.name(), packet)
|
||||
return <-errc
|
||||
}
|
||||
|
||||
|
|
@ -464,36 +470,41 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) error {
|
||||
packet, err := encodePacket(t.priv, ptype, req)
|
||||
func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) ([]byte, error) {
|
||||
packet, hash, err := encodePacket(t.priv, ptype, req)
|
||||
if err != nil {
|
||||
return err
|
||||
return hash, err
|
||||
}
|
||||
_, err = t.conn.WriteToUDP(packet, toaddr)
|
||||
log.Trace(">> "+req.name(), "addr", toaddr, "err", err)
|
||||
return hash, t.write(toaddr, req.name(), packet)
|
||||
}
|
||||
|
||||
func (t *udp) write(toaddr *net.UDPAddr, what string, packet []byte) error {
|
||||
_, err := t.conn.WriteToUDP(packet, toaddr)
|
||||
log.Trace(">> "+what, "addr", toaddr, "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte, error) {
|
||||
func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (packet, hash []byte, err error) {
|
||||
b := new(bytes.Buffer)
|
||||
b.Write(headSpace)
|
||||
b.WriteByte(ptype)
|
||||
if err := rlp.Encode(b, req); err != nil {
|
||||
log.Error("Can't encode discv4 packet", "err", err)
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
packet := b.Bytes()
|
||||
packet = b.Bytes()
|
||||
sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
|
||||
if err != nil {
|
||||
log.Error("Can't sign discv4 packet", "err", err)
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
copy(packet[macSize:], sig)
|
||||
// add the hash to the front. Note: this doesn't protect the
|
||||
// packet in any way. Our public key will be part of this hash in
|
||||
// The future.
|
||||
copy(packet, crypto.Keccak256(packet[macSize:]))
|
||||
return packet, nil
|
||||
hash = crypto.Keccak256(packet[macSize:])
|
||||
copy(packet, hash)
|
||||
return packet, hash, nil
|
||||
}
|
||||
|
||||
// readLoop runs in its own goroutine. it handles incoming UDP packets.
|
||||
|
|
@ -618,18 +629,22 @@ func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte
|
|||
t.mutex.Unlock()
|
||||
|
||||
p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())}
|
||||
var sent bool
|
||||
// Send neighbors in chunks with at most maxNeighbors per packet
|
||||
// to stay below the 1280 byte limit.
|
||||
for i, n := range closest {
|
||||
if netutil.CheckRelayIP(from.IP, n.IP) != nil {
|
||||
continue
|
||||
for _, n := range closest {
|
||||
if netutil.CheckRelayIP(from.IP, n.IP) == nil {
|
||||
p.Nodes = append(p.Nodes, nodeToRPC(n))
|
||||
}
|
||||
p.Nodes = append(p.Nodes, nodeToRPC(n))
|
||||
if len(p.Nodes) == maxNeighbors || i == len(closest)-1 {
|
||||
if len(p.Nodes) == maxNeighbors {
|
||||
t.send(from, neighborsPacket, &p)
|
||||
p.Nodes = p.Nodes[:0]
|
||||
sent = true
|
||||
}
|
||||
}
|
||||
if len(p.Nodes) > 0 || !sent {
|
||||
t.send(from, neighborsPacket, &p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ func newUDPTest(t *testing.T) *udpTest {
|
|||
|
||||
// handles a packet as if it had been sent to the transport.
|
||||
func (test *udpTest) packetIn(wantError error, ptype byte, data packet) error {
|
||||
enc, err := encodePacket(test.remotekey, ptype, data)
|
||||
enc, _, err := encodePacket(test.remotekey, ptype, data)
|
||||
if err != nil {
|
||||
return test.errorf("packet (%d) encode error: %v", ptype, err)
|
||||
}
|
||||
|
|
@ -91,19 +91,19 @@ func (test *udpTest) packetIn(wantError error, ptype byte, data packet) error {
|
|||
|
||||
// waits for a packet to be sent by the transport.
|
||||
// validate should have type func(*udpTest, X) error, where X is a packet type.
|
||||
func (test *udpTest) waitPacketOut(validate interface{}) error {
|
||||
func (test *udpTest) waitPacketOut(validate interface{}) ([]byte, error) {
|
||||
dgram := test.pipe.waitPacketOut()
|
||||
p, _, _, err := decodePacket(dgram)
|
||||
p, _, hash, err := decodePacket(dgram)
|
||||
if err != nil {
|
||||
return test.errorf("sent packet decode error: %v", err)
|
||||
return hash, test.errorf("sent packet decode error: %v", err)
|
||||
}
|
||||
fn := reflect.ValueOf(validate)
|
||||
exptype := fn.Type().In(0)
|
||||
if reflect.TypeOf(p) != exptype {
|
||||
return test.errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype)
|
||||
return hash, test.errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype)
|
||||
}
|
||||
fn.Call([]reflect.Value{reflect.ValueOf(p)})
|
||||
return nil
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func (test *udpTest) errorf(format string, args ...interface{}) error {
|
||||
|
|
@ -352,7 +352,7 @@ func TestUDP_successfulPing(t *testing.T) {
|
|||
})
|
||||
|
||||
// remote is unknown, the table pings back.
|
||||
test.waitPacketOut(func(p *ping) error {
|
||||
hash, _ := test.waitPacketOut(func(p *ping) error {
|
||||
if !reflect.DeepEqual(p.From, test.udp.ourEndpoint) {
|
||||
t.Errorf("got ping.From %v, want %v", p.From, test.udp.ourEndpoint)
|
||||
}
|
||||
|
|
@ -366,7 +366,7 @@ func TestUDP_successfulPing(t *testing.T) {
|
|||
}
|
||||
return nil
|
||||
})
|
||||
test.packetIn(nil, pongPacket, &pong{Expiration: futureExp})
|
||||
test.packetIn(nil, pongPacket, &pong{ReplyTok: hash, Expiration: futureExp})
|
||||
|
||||
// the node should be added to the table shortly after getting the
|
||||
// pong packet.
|
||||
|
|
|
|||
Loading…
Reference in a new issue