blob: f3a8b7d570d1ca747a5ab3033a27a03ee807161c [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21
package quic
import (
"bytes"
"encoding/hex"
"fmt"
"strings"
"testing"
)
func (p packetType) String() string {
switch p {
case packetTypeInitial:
return "Initial"
case packetType0RTT:
return "0-RTT"
case packetTypeHandshake:
return "Handshake"
case packetTypeRetry:
return "Retry"
case packetType1RTT:
return "1-RTT"
}
return fmt.Sprintf("unknown packet type %v", byte(p))
}
func TestPacketHeader(t *testing.T) {
for _, test := range []struct {
name string
packet []byte
isLongHeader bool
packetType packetType
dstConnID []byte
}{{
// Initial packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.1
// (truncated)
name: "rfc9001_a1",
packet: unhex(`
c000000001088394c8f03e5157080000 449e7b9aec34d1b1c98dd7689fb8ec11
`),
isLongHeader: true,
packetType: packetTypeInitial,
dstConnID: unhex(`8394c8f03e515708`),
}, {
// Initial packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.3
// (truncated)
name: "rfc9001_a3",
packet: unhex(`
cf000000010008f067a5502a4262b500 4075c0d95a482cd0991cd25b0aac406a
`),
isLongHeader: true,
packetType: packetTypeInitial,
dstConnID: []byte{},
}, {
// Retry packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.4
name: "rfc9001_a4",
packet: unhex(`
ff000000010008f067a5502a4262b574 6f6b656e04a265ba2eff4d829058fb3f
0f2496ba
`),
isLongHeader: true,
packetType: packetTypeRetry,
dstConnID: []byte{},
}, {
// Short header packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.5
name: "rfc9001_a5",
packet: unhex(`
4cfe4189655e5cd55c41f69080575d7999c25a5bfb
`),
isLongHeader: false,
packetType: packetType1RTT,
dstConnID: unhex(`fe4189655e5cd55c`),
}, {
// Version Negotiation packet.
name: "version_negotiation",
packet: unhex(`
80 00000000 01ff0001020304
`),
isLongHeader: true,
packetType: packetTypeVersionNegotiation,
dstConnID: []byte{0xff},
}, {
// Too-short packet.
name: "truncated_after_connid_length",
packet: unhex(`
cf0000000105
`),
isLongHeader: true,
packetType: packetTypeInitial,
dstConnID: nil,
}, {
// Too-short packet.
name: "truncated_after_version",
packet: unhex(`
cf00000001
`),
isLongHeader: true,
packetType: packetTypeInitial,
dstConnID: nil,
}, {
// Much too short packet.
name: "truncated_in_version",
packet: unhex(`
cf000000
`),
isLongHeader: true,
packetType: packetTypeInvalid,
dstConnID: nil,
}} {
t.Run(test.name, func(t *testing.T) {
if got, want := isLongHeader(test.packet[0]), test.isLongHeader; got != want {
t.Errorf("packet %x:\nisLongHeader(packet) = %v, want %v", test.packet, got, want)
}
if got, want := getPacketType(test.packet), test.packetType; got != want {
t.Errorf("packet %x:\ngetPacketType(packet) = %v, want %v", test.packet, got, want)
}
gotConnID, gotOK := dstConnIDForDatagram(test.packet)
wantConnID, wantOK := test.dstConnID, test.dstConnID != nil
if !bytes.Equal(gotConnID, wantConnID) || gotOK != wantOK {
t.Errorf("packet %x:\ndstConnIDForDatagram(packet) = {%x}, %v; want {%x}, %v", test.packet, gotConnID, gotOK, wantConnID, wantOK)
}
})
}
}
func unhex(s string) []byte {
b, err := hex.DecodeString(strings.Map(func(c rune) rune {
switch c {
case ' ', '\t', '\n':
return -1
}
return c
}, s))
if err != nil {
panic(err)
}
return b
}