feat(transport): add TestAnnounceHopCount to validate hop count registration and update path handling logic
This commit is contained in:
@@ -577,8 +577,11 @@ func (t *Transport) RequestPath(destinationHash []byte, onInterface string, tag
|
|||||||
pathRequestData = append(destinationHash, tag...)
|
pathRequestData = append(destinationHash, tag...)
|
||||||
}
|
}
|
||||||
|
|
||||||
destHashFull := sha256.Sum256([]byte("rnstransport.path.request"))
|
pathRequestName := "rnstransport.path.request"
|
||||||
pathRequestDestHash := destHashFull[:common.SIZE_16]
|
nameHashFull := sha256.Sum256([]byte(pathRequestName))
|
||||||
|
nameHash10 := nameHashFull[:10]
|
||||||
|
finalHashFull := sha256.Sum256(nameHash10)
|
||||||
|
pathRequestDestHash := finalHashFull[:16]
|
||||||
|
|
||||||
pkt := packet.NewPacket(
|
pkt := packet.NewPacket(
|
||||||
packet.DestinationPlain,
|
packet.DestinationPlain,
|
||||||
@@ -586,11 +589,12 @@ func (t *Transport) RequestPath(destinationHash []byte, onInterface string, tag
|
|||||||
0x00,
|
0x00,
|
||||||
0x00,
|
0x00,
|
||||||
packet.PropagationBroadcast,
|
packet.PropagationBroadcast,
|
||||||
0x01,
|
0x00, // Header Type 1
|
||||||
pathRequestDestHash,
|
nil,
|
||||||
false,
|
false,
|
||||||
0x00,
|
0x00,
|
||||||
)
|
)
|
||||||
|
pkt.DestinationHash = pathRequestDestHash
|
||||||
|
|
||||||
if err := pkt.Pack(); err != nil {
|
if err := pkt.Pack(); err != nil {
|
||||||
return fmt.Errorf("failed to pack path request: %w", err)
|
return fmt.Errorf("failed to pack path request: %w", err)
|
||||||
@@ -1110,16 +1114,15 @@ func (t *Transport) handleAnnouncePacket(data []byte, iface common.NetworkInterf
|
|||||||
// Register the path from this announce
|
// Register the path from this announce
|
||||||
// The destination is reachable via the interface that received this announce
|
// The destination is reachable via the interface that received this announce
|
||||||
if iface != nil {
|
if iface != nil {
|
||||||
// Use unlocked version since we may be called in a locked context
|
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
t.updatePathUnlocked(destinationHash, nil, iface.GetName(), hopCount)
|
t.updatePathUnlocked(destinationHash, nil, iface.GetName(), hopCount+1)
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
debug.Log(debug.DEBUG_INFO, "Registered path", "hash", fmt.Sprintf("%x", destinationHash), "interface", iface.GetName(), "hops", hopCount)
|
debug.Log(debug.DEBUG_INFO, "Registered path", "hash", fmt.Sprintf("%x", destinationHash), "interface", iface.GetName(), "hops", hopCount+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify handlers first, regardless of forwarding limits
|
// Notify handlers first, regardless of forwarding limits
|
||||||
debug.Log(debug.DEBUG_INFO, "Notifying announce handlers", "destHash", fmt.Sprintf("%x", destinationHash), "appDataLen", len(appData))
|
debug.Log(debug.DEBUG_INFO, "Notifying announce handlers", "destHash", fmt.Sprintf("%x", destinationHash), "appDataLen", len(appData))
|
||||||
t.notifyAnnounceHandlers(destinationHash, id, appData, hopCount)
|
t.notifyAnnounceHandlers(destinationHash, id, appData, hopCount+1)
|
||||||
debug.Log(debug.DEBUG_INFO, "Announce handlers notified")
|
debug.Log(debug.DEBUG_INFO, "Announce handlers notified")
|
||||||
|
|
||||||
// Don't forward if max hops reached
|
// Don't forward if max hops reached
|
||||||
@@ -1376,7 +1379,7 @@ func (t *Transport) InitializePathRequestHandler() error {
|
|||||||
return errors.New("transport identity not initialized")
|
return errors.New("transport identity not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
pathRequestDest, err := destination.New(t.transportIdentity, destination.IN, destination.PLAIN, "rnstransport", t, "path", "request")
|
pathRequestDest, err := destination.New(nil, destination.IN, destination.PLAIN, "rnstransport", t, "path", "request")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create path request destination: %w", err)
|
return fmt.Errorf("failed to create path request destination: %w", err)
|
||||||
}
|
}
|
||||||
@@ -1692,6 +1695,14 @@ func (l *Link) HandleResource(resource interface{}) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIdentity sets the identity for the Transport.
|
||||||
|
func (t *Transport) SetIdentity(id *identity.Identity) {
|
||||||
|
t.mutex.Lock()
|
||||||
|
defer t.mutex.Unlock()
|
||||||
|
t.transportIdentity = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start initializes the Transport.
|
||||||
func (t *Transport) Start() error {
|
func (t *Transport) Start() error {
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
defer t.mutex.Unlock()
|
defer t.mutex.Unlock()
|
||||||
|
|||||||
@@ -3,8 +3,12 @@ package transport
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.quad4.io/Networks/Reticulum-Go/pkg/common"
|
"git.quad4.io/Networks/Reticulum-Go/pkg/common"
|
||||||
|
"git.quad4.io/Networks/Reticulum-Go/pkg/destination"
|
||||||
|
"git.quad4.io/Networks/Reticulum-Go/pkg/identity"
|
||||||
|
"git.quad4.io/Networks/Reticulum-Go/pkg/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockInterface struct {
|
type mockInterface struct {
|
||||||
@@ -118,3 +122,68 @@ func TestTransportStatus(t *testing.T) {
|
|||||||
t.Error("Path should be responsive again")
|
t.Error("Path should be responsive again")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAnnounceHopCount(t *testing.T) {
|
||||||
|
config := common.DefaultConfig()
|
||||||
|
tr := NewTransport(config)
|
||||||
|
defer tr.Close()
|
||||||
|
|
||||||
|
iface := &mockInterface{}
|
||||||
|
iface.Name = "wasm0"
|
||||||
|
iface.Enabled = true
|
||||||
|
_ = tr.RegisterInterface("wasm0", iface)
|
||||||
|
|
||||||
|
// Create an identity for the announce
|
||||||
|
id, _ := identity.New()
|
||||||
|
|
||||||
|
// Create a destination to get a valid hash for this identity
|
||||||
|
// NewAnnouncePacket uses "reticulum-go.node" by default
|
||||||
|
dest, _ := destination.New(id, destination.IN, destination.SINGLE, "reticulum-go.node", tr)
|
||||||
|
destHash := dest.GetHash()
|
||||||
|
|
||||||
|
// Create a raw announce packet manually to control hop count
|
||||||
|
// Header(2) + DestHash(16) + Context(1) + Payload...
|
||||||
|
// Header: 0x21 (Announce, Header Type 1, Broadcast, Destination Type Single)
|
||||||
|
// Hop count: 0
|
||||||
|
raw := make([]byte, 2+16+1+148) // header + dest + context + min_announce_payload
|
||||||
|
raw[0] = 0x21
|
||||||
|
raw[1] = 0 // Initial hop count
|
||||||
|
copy(raw[2:18], destHash)
|
||||||
|
raw[18] = 0 // context
|
||||||
|
|
||||||
|
// Announce payload: pubKey(64) + nameHash(10) + randomHash(10) + signature(64)
|
||||||
|
payload := raw[19:]
|
||||||
|
copy(payload[0:64], id.GetPublicKey())
|
||||||
|
// Name hash, random hash, signature - filling with dummy data but valid length
|
||||||
|
// Normally we would sign it properly, but handleAnnouncePacket validates it.
|
||||||
|
// Actually, handleAnnouncePacket WILL fail if signature is invalid.
|
||||||
|
// Use NewAnnouncePacket to get a valid signed packet
|
||||||
|
transportID := make([]byte, 16)
|
||||||
|
annPkt, err := packet.NewAnnouncePacket(destHash, id, []byte("test"), transportID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewAnnouncePacket failed: %v", err)
|
||||||
|
}
|
||||||
|
annRaw, err := annPkt.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Serialize failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override hop count to 0 to simulate neighbor
|
||||||
|
annRaw[1] = 0
|
||||||
|
|
||||||
|
// Handle the packet
|
||||||
|
tr.HandlePacket(annRaw, iface)
|
||||||
|
|
||||||
|
// Wait a bit for the async processing
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
// Check stored hops
|
||||||
|
if !tr.HasPath(destHash) {
|
||||||
|
t.Fatal("Path not registered from announce")
|
||||||
|
}
|
||||||
|
|
||||||
|
hops := tr.HopsTo(destHash)
|
||||||
|
if hops != 1 {
|
||||||
|
t.Errorf("Expected 1 hop for neighbor (received 0), got %d", hops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user