mirror of
https://github.com/soypat/lneto.git
synced 2026-08-10 18:03:43 +00:00
8813ccef82
* various icmp fixes * improve existing tests
173 lines
4.5 KiB
Go
173 lines
4.5 KiB
Go
package icmpv4
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/soypat/lneto/internal"
|
|
)
|
|
|
|
const (
|
|
testHashSeed = 0xdeadbeef
|
|
)
|
|
|
|
func TestClients(t *testing.T) {
|
|
const sizebuffer = 64
|
|
const queuesize = 2
|
|
var sender, responder Client
|
|
err := sender.Configure(ClientConfig{
|
|
ResponseQueueBuffer: make([]byte, sizebuffer),
|
|
ResponseQueueLimit: queuesize,
|
|
HashSeed: testHashSeed,
|
|
ID: 1,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = responder.Configure(ClientConfig{
|
|
ResponseQueueBuffer: make([]byte, sizebuffer),
|
|
ResponseQueueLimit: queuesize,
|
|
HashSeed: testHashSeed,
|
|
ID: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
pattern := []byte("ab12")
|
|
size := 8
|
|
var buf [64]byte
|
|
key1 := testSingleExchange(t, &sender, &responder, buf[:], pattern, uint16(size))
|
|
completed, ok := sender.PingPop(key1)
|
|
if !completed || !ok {
|
|
t.Fatal("ping did not complete or not exist")
|
|
}
|
|
n, err := sender.Encapsulate(buf[:], -1, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if n > 0 {
|
|
t.Error("sender: expected no more data to be sent")
|
|
}
|
|
n, err = responder.Encapsulate(buf[:], -1, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
} else if n > 0 {
|
|
t.Error("responder: expected no more data to be sent")
|
|
}
|
|
}
|
|
|
|
func testSingleExchange(t *testing.T, sender, responder *Client, buf []byte, pattern []byte, size uint16) (senderKey uint32) {
|
|
const frameOff = 0
|
|
const ipOff = -1
|
|
n, err := responder.Encapsulate(buf, ipOff, frameOff)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
} else if n > 0 {
|
|
t.Fatal("expected no data pending to be sent from responder")
|
|
}
|
|
senderKey, n = testSendEcho(t, sender, buf, pattern, size)
|
|
completed, ok := sender.PingPeek(senderKey)
|
|
if !ok {
|
|
t.Error("ping key not exist")
|
|
} else if completed {
|
|
t.Error("ping completed before response")
|
|
}
|
|
ifrm, _ := NewFrame(buf[frameOff : frameOff+n])
|
|
efrm := FrameEcho{Frame: ifrm}
|
|
id, seq := efrm.Identifier(), efrm.SequenceNumber()
|
|
err1 := responder.Demux(buf[:frameOff+n], frameOff)
|
|
if err1 != nil {
|
|
t.Error("responder demux during single", err1)
|
|
}
|
|
n, err = responder.Encapsulate(buf, ipOff, frameOff)
|
|
if err != nil {
|
|
t.Error("responder encaps during single", err)
|
|
return
|
|
} else if n == 0 && err1 == nil {
|
|
t.Error("responder wrote no data")
|
|
return
|
|
}
|
|
ifrm, err = NewFrame(buf[frameOff : frameOff+n])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ifrm.Type() != TypeEchoReply {
|
|
t.Fatalf("expected echo reply %d", ifrm.Type())
|
|
}
|
|
efrm = FrameEcho{Frame: ifrm}
|
|
if efrm.Identifier() != id {
|
|
t.Error("mismatched identifier want/got:", id, efrm.Identifier())
|
|
}
|
|
if efrm.SequenceNumber() != seq {
|
|
t.Error("mismatched sequence number want/got:", seq, efrm.SequenceNumber())
|
|
}
|
|
data := efrm.Data()
|
|
testPatternMatch(t, data, pattern, int(size))
|
|
err = sender.Demux(buf[:frameOff+n], frameOff)
|
|
if err != nil {
|
|
t.Error("sender demuxed response", err)
|
|
}
|
|
completed, ok = sender.PingPeek(senderKey)
|
|
if !completed {
|
|
t.Error("expected ping to have completed")
|
|
}
|
|
if !ok {
|
|
t.Error("ping key not exist after completion")
|
|
}
|
|
if completed2, ok2 := sender.PingPeek(senderKey); completed != completed2 || ok != ok2 {
|
|
t.Error("change in status after peek")
|
|
}
|
|
n, err = sender.Encapsulate(buf, ipOff, frameOff)
|
|
if err != nil {
|
|
t.Error("error after done")
|
|
}
|
|
if n > 0 {
|
|
t.Error("expected no data to be sent after ping completion", n)
|
|
}
|
|
return senderKey
|
|
}
|
|
|
|
func testSendEcho(t *testing.T, sender *Client, buf []byte, pattern []byte, size uint16) (key uint32, n int) {
|
|
t.Helper()
|
|
const frameOff = 0
|
|
const ipOff = -1
|
|
n, err := sender.Encapsulate(buf, ipOff, frameOff)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
} else if n > 0 {
|
|
t.Fatal("expected no data pending to send on testSendEcho start")
|
|
}
|
|
key, err = sender.PingStart([4]byte{1}, pattern, size)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
n, err = sender.Encapsulate(buf[:], ipOff, frameOff)
|
|
if err != nil {
|
|
t.Errorf("sender encapsulate: %v", err)
|
|
}
|
|
ifrm, err := NewFrame(buf[:n])
|
|
if err != nil {
|
|
t.Fatal(err) // only fails in short frame case.
|
|
}
|
|
if ifrm.Type() != TypeEcho {
|
|
t.Errorf("not echo type on send: %d", ifrm.Type())
|
|
}
|
|
efrm := FrameEcho{Frame: ifrm}
|
|
data := efrm.Data()
|
|
testPatternMatch(t, data, pattern, int(size))
|
|
return key, n
|
|
}
|
|
|
|
func testPatternMatch(t *testing.T, data []byte, pattern []byte, size int) {
|
|
t.Helper()
|
|
if len(data) != size {
|
|
t.Errorf("pattern size mismatch, want %d, got %d", size, len(data))
|
|
}
|
|
for i := 0; i < size; i += len(pattern) {
|
|
got := data[i:min(len(data), i+len(pattern))]
|
|
want := pattern[:len(got)]
|
|
if !internal.BytesEqual(got, want) {
|
|
t.Errorf("pattern data mismatch at %d, got %s, want %s", i, got, want)
|
|
}
|
|
}
|
|
}
|