This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
package cmpp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestReceiptVersionLayout(t *testing.T) {
|
||||
for _, version := range []Type{V20, V21, V30} {
|
||||
width, size := 21, 60
|
||||
if version == V30 {
|
||||
width, size = 32, 71
|
||||
}
|
||||
original := CmppReceiptPkt{MsgId: ^uint64(0), Stat: "DELIVRD", SubmitTime: "2609201200", DoneTime: "2609201201", DestTerminalId: strings.Repeat("9", width), SmscSequence: ^uint32(0)}
|
||||
raw, err := original.PackVersion(version)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(raw) != size || binary.BigEndian.Uint32(raw[size-4:]) != ^uint32(0) {
|
||||
t.Fatalf("wrong layout: %x", raw)
|
||||
}
|
||||
var decoded CmppReceiptPkt
|
||||
if err = decoded.UnpackVersion(raw, version); err != nil || !reflect.DeepEqual(decoded, original) {
|
||||
t.Fatalf("roundtrip: %+v %v", decoded, err)
|
||||
}
|
||||
for _, bad := range [][]byte{raw[:len(raw)-1], append(append([]byte{}, raw...), 0)} {
|
||||
if decoded.UnpackVersion(bad, version) == nil {
|
||||
t.Fatal("invalid length accepted")
|
||||
}
|
||||
}
|
||||
other := V30
|
||||
if version == V30 {
|
||||
other = V20
|
||||
}
|
||||
if decoded.UnpackVersion(raw, other) == nil {
|
||||
t.Fatal("wrong version accepted")
|
||||
}
|
||||
original.DestTerminalId += "1"
|
||||
if _, err = original.PackVersion(version); err == nil {
|
||||
t.Fatal("truncated destination")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Real TCP peers exercise the bounded reader, not only Pack/Unpack in memory.
|
||||
func tcpPair(t *testing.T, version Type) (*Conn, net.Conn) {
|
||||
t.Helper()
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
client, err := net.Dial("tcp", listener.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
server, err := listener.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conn := NewConn(server, version)
|
||||
conn.SetState(CONN_AUTHOK)
|
||||
t.Cleanup(func() { conn.Close(); client.Close() })
|
||||
return conn, client
|
||||
}
|
||||
|
||||
func TestCMPP3LargeSubmitAndMalformedPackets(t *testing.T) {
|
||||
for _, length := range []int{140, 159} {
|
||||
p := Cmpp3SubmitReqPkt{DestUsrTl: 99, DestTerminalId: make([]string, 99), MsgLength: uint8(length), MsgContent: strings.Repeat("x", length)}
|
||||
if length == 140 {
|
||||
p.MsgFmt = 8
|
||||
}
|
||||
raw, err := p.Pack(^uint32(0))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(raw) != 3331+length {
|
||||
t.Fatalf("size %d", len(raw))
|
||||
}
|
||||
conn, peer := tcpPair(t, V30)
|
||||
go peer.Write(raw)
|
||||
pkt, err := conn.RecvAndUnpackPkt(time.Second)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
decoded := pkt.(*Cmpp3SubmitReqPkt)
|
||||
if decoded.SeqId != ^uint32(0) || len(decoded.DestTerminalId) != 99 || decoded.MsgContent != p.MsgContent {
|
||||
t.Fatal("wire mismatch")
|
||||
}
|
||||
var d Cmpp3SubmitReqPkt
|
||||
if d.Unpack(raw[8:len(raw)-1]) == nil || d.Unpack(append(raw[8:], 0)) == nil {
|
||||
t.Fatal("malformed body accepted")
|
||||
}
|
||||
p.DestUsrTl = 100
|
||||
p.DestTerminalId = append(p.DestTerminalId, "")
|
||||
if _, err = p.Pack(0); err == nil {
|
||||
t.Fatal("100 destinations accepted")
|
||||
}
|
||||
}
|
||||
for _, size := range []uint32{0, 11, CMPP3_PACKET_MAX + 1, ^uint32(0)} {
|
||||
conn, peer := tcpPair(t, V30)
|
||||
raw := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(raw, size)
|
||||
go peer.Write(raw)
|
||||
if _, err := conn.RecvAndUnpackPkt(time.Second); err == nil {
|
||||
t.Fatalf("accepted length %d", size)
|
||||
}
|
||||
}
|
||||
p := Cmpp3SubmitReqPkt{DestUsrTl: 1, DestTerminalId: []string{"1"}, MsgFmt: 8, MsgLength: 141, MsgContent: strings.Repeat("a", 141)}
|
||||
if _, err := p.Pack(0); err == nil {
|
||||
t.Fatal("oversized non-ASCII accepted")
|
||||
}
|
||||
p.MsgFmt, p.MsgLength, p.MsgContent = 0, 160, strings.Repeat("a", 160)
|
||||
if _, err := p.Pack(0); err == nil {
|
||||
t.Fatal("ASCII must be strictly shorter than 160 bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectStatusKeepsAll32Bits(t *testing.T) {
|
||||
for _, status := range []uint32{0, 5, 255, 256, ^uint32(0)} {
|
||||
t.Run(fmt.Sprint(status), func(t *testing.T) {
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer listener.Close()
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
peer, e := listener.Accept()
|
||||
if e != nil {
|
||||
done <- e
|
||||
return
|
||||
}
|
||||
conn := NewConn(peer, V30)
|
||||
defer conn.Close()
|
||||
conn.SetState(CONN_CONNECTED)
|
||||
req, e := conn.RecvAndUnpackPkt(time.Second)
|
||||
if e == nil {
|
||||
e = conn.SendPkt(&Cmpp3ConnRspPkt{Status: status, Version: V30}, req.(*CmppConnReqPkt).SeqId)
|
||||
}
|
||||
done <- e
|
||||
}()
|
||||
client := NewClient(V30)
|
||||
defer client.Disconnect()
|
||||
err = client.Connect(listener.Addr().String(), "123456", "secret", time.Second)
|
||||
if status == 0 && err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if status != 0 && (err == nil || !strings.Contains(err.Error(), fmt.Sprintf("status=%d", status))) {
|
||||
t.Fatalf("status truncated: %v", err)
|
||||
}
|
||||
if e := <-done; e != nil {
|
||||
t.Fatal(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestSequenceSkipsInFlightAcrossWrap(t *testing.T) {
|
||||
conn, peer := tcpPair(t, V30)
|
||||
sequences := make(chan uint32, 3)
|
||||
sequences <- ^uint32(0)
|
||||
sequences <- 0
|
||||
sequences <- 1
|
||||
conn.SeqId = sequences
|
||||
client := &Client{conn: conn, typ: V30}
|
||||
read := make(chan error, 1)
|
||||
go func() { raw := make([]byte, 12); _, err := peer.Read(raw); read <- err }()
|
||||
seq, err := client.SendReqPktAvailable(&CmppActiveTestReqPkt{}, func(n uint32) bool { return n != ^uint32(0) })
|
||||
if err != nil || seq != 0 {
|
||||
t.Fatalf("zero lost: %d %v", seq, err)
|
||||
}
|
||||
if err = <-read; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user