diff --git a/packet.go b/packet.go new file mode 100644 index 0000000..060362a --- /dev/null +++ b/packet.go @@ -0,0 +1,56 @@ +package main + +const ( + packetFlagControl = 1 + packetFlagResend = 2 + packetFlagCompression = 4 + packetFlagConnless = 8 +) + +type PacketFlags struct { + connless bool + compression bool + resend bool + control bool +} + +type PacketHeader struct { + flags PacketFlags + ack int + numChunks int + token [4]byte +} + +func (header *PacketHeader) unpack(packet []byte) { + header.flags.unpack(packet) + header.ack = (int(packet[0]&0x3) << 8) | int(packet[1]) + header.numChunks = int(packet[2]) + copy(header.token[:], packet[3:7]) +} + +func (flags *PacketFlags) unpack(packetHeaderRaw []byte) { + flagBits := packetHeaderRaw[0] >> 2 + flags.control = (flagBits & packetFlagControl) != 0 + flags.resend = (flagBits & packetFlagResend) != 0 + flags.compression = (flagBits & packetFlagCompression) != 0 + flags.connless = (flagBits & packetFlagConnless) != 0 +} + +func (flags *PacketFlags) pack() []byte { + data := 0 + + if flags.control { + data |= packetFlagControl + } + if flags.resend { + data |= packetFlagResend + } + if flags.compression { + data |= packetFlagCompression + } + if flags.connless { + data |= packetFlagConnless + } + + return []byte{byte(data)} +} diff --git a/packet_test.go b/packet_test.go new file mode 100644 index 0000000..c6e50dc --- /dev/null +++ b/packet_test.go @@ -0,0 +1,172 @@ +package main + +import ( + "reflect" + "slices" + "testing" +) + +// pack + +func TestPackFlagsUnset(t *testing.T) { + flags := PacketFlags{ + connless: false, + compression: false, + resend: false, + control: false, + } + + got := flags.pack() + want := []byte{0b0000} + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestPackFlagsCompressionSet(t *testing.T) { + flags := PacketFlags{ + connless: false, + compression: true, + resend: false, + control: false, + } + + got := flags.pack() + want := []byte{0b0100} + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestPackFlagsAllSet(t *testing.T) { + flags := PacketFlags{ + connless: true, + compression: true, + resend: true, + control: true, + } + + got := flags.pack() + want := []byte{0b1111} + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +// unpack + +func TestUnpackFlagsAllSet(t *testing.T) { + got := PacketFlags{} + want := PacketFlags{ + connless: true, + compression: true, + resend: true, + control: true, + } + + got.unpack([]byte{0b00111100}) + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestUnpackFlagsControlSet(t *testing.T) { + got := PacketFlags{} + want := PacketFlags{ + connless: false, + compression: false, + resend: false, + control: true, + } + + got.unpack([]byte{0b00000100}) + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestUnpackFlagsUnset(t *testing.T) { + got := PacketFlags{} + want := PacketFlags{ + connless: false, + compression: false, + resend: false, + control: false, + } + + got.unpack([]byte{0b00000000}) + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +// packet header unpack + +func TestUnpackCloseWithReason(t *testing.T) { + got := PacketHeader{} + want := PacketHeader{ + flags: PacketFlags{ + connless: false, + compression: false, + resend: false, + control: true, + }, + ack: 10, + numChunks: 0, + token: [4]byte{0xcf, 0x2e, 0xde, 0x1d}, + } + + got.unpack(slices.Concat([]byte{0x04, 0x0a, 0x00, 0xcf, 0x2e, 0xde, 0x1d, 0x04}, []byte("shutdown"), []byte{0x00})) + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestUnpackHeaderFlagsControlSet(t *testing.T) { + got := PacketHeader{} + want := PacketHeader{ + flags: PacketFlags{ + connless: false, + compression: false, + resend: false, + control: true, + }, + ack: 0, + numChunks: 0, + token: [4]byte{0xff, 0xff, 0xff, 0xff}, + } + + got.unpack([]byte{0b00000100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}) + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} + +func TestUnpackHeaderFlagsAllSet(t *testing.T) { + got := PacketHeader{} + want := PacketHeader{ + flags: PacketFlags{ + connless: true, + compression: true, + resend: true, + control: true, + }, + ack: 0, + numChunks: 0, + token: [4]byte{0xff, 0xff, 0xff, 0xff}, + } + + got.unpack([]byte{0b00111100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}) + + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, wanted %v", got, want) + } +} diff --git a/teeworlds.go b/teeworlds.go index efe33c2..b6ea3ba 100644 --- a/teeworlds.go +++ b/teeworlds.go @@ -1,4 +1,4 @@ -package teeworlds +package main import ( "bufio" diff --git a/teeworlds_test.go b/teeworlds_test.go index f0e9727..a501db9 100644 --- a/teeworlds_test.go +++ b/teeworlds_test.go @@ -1,4 +1,4 @@ -package teeworlds +package main import ( "testing"