From 5655d151b1e1bffc51cdfaf01c3525f71474480a Mon Sep 17 00:00:00 2001 From: Max Hawkins Date: Sun, 2 Dec 2018 11:15:56 -0800 Subject: [PATCH] Add rtcp.RawPacket type This will be returned by Unmarhsal when an unknown type is seen in the packet stream, avoiding an error and allowing the user to write their own packet handling code for that type if desired. Relates to #119 --- pkg/rtcp/packet.go | 3 +- pkg/rtcp/raw_packet.go | 25 +++++++++++++++ pkg/rtcp/raw_packet_test.go | 61 +++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 pkg/rtcp/raw_packet.go create mode 100644 pkg/rtcp/raw_packet_test.go diff --git a/pkg/rtcp/packet.go b/pkg/rtcp/packet.go index ab71ba66..f43f1fe9 100644 --- a/pkg/rtcp/packet.go +++ b/pkg/rtcp/packet.go @@ -36,10 +36,9 @@ func Unmarshal(rawPacket []byte) (Packet, Header, error) { p = new(PictureLossIndication) default: - return nil, h, errWrongType + p = new(RawPacket) } err = p.Unmarshal(rawPacket) return p, h, err - } diff --git a/pkg/rtcp/raw_packet.go b/pkg/rtcp/raw_packet.go new file mode 100644 index 00000000..1556b381 --- /dev/null +++ b/pkg/rtcp/raw_packet.go @@ -0,0 +1,25 @@ +package rtcp + +// RawPacket represents an unparsed RTCP packet. It's returned by Unmarshal when +// a packet with an unknown type is encountered. +type RawPacket []byte + +// Marshal encodes the packet in binary. +func (r RawPacket) Marshal() ([]byte, error) { + return r, nil +} + +// Unmarshal decodes the packet from binary. +func (r *RawPacket) Unmarshal(b []byte) error { + if len(b) < (headerLength) { + return errPacketTooShort + } + *r = b + + var h Header + if err := h.Unmarshal(b); err != nil { + return err + } + + return nil +} diff --git a/pkg/rtcp/raw_packet_test.go b/pkg/rtcp/raw_packet_test.go new file mode 100644 index 00000000..f48ca70a --- /dev/null +++ b/pkg/rtcp/raw_packet_test.go @@ -0,0 +1,61 @@ +package rtcp + +import ( + "reflect" + "testing" +) + +func TestRawPacketRoundTrip(t *testing.T) { + for _, test := range []struct { + Name string + Packet RawPacket + WantMarshalError error + WantUnmarshalError error + }{ + { + Name: "valid", + Packet: RawPacket([]byte{ + // v=2, p=0, count=1, BYE, len=12 + 0x81, 0xcb, 0x00, 0x0c, + // ssrc=0x902f9e2e + 0x90, 0x2f, 0x9e, 0x2e, + // len=3, text=FOO + 0x03, 0x46, 0x4f, 0x4f, + }), + }, + { + Name: "short header", + Packet: RawPacket([]byte{0x00}), + WantUnmarshalError: errPacketTooShort, + }, + { + Name: "invalid header", + Packet: RawPacket([]byte{ + // v=0, p=0, count=0, RR, len=4 + 0x00, 0xc9, 0x00, 0x04, + }), + WantUnmarshalError: errBadVersion, + }, + } { + data, err := test.Packet.Marshal() + if got, want := err, test.WantMarshalError; got != want { + t.Fatalf("Marshal %q: err = %v, want %v", test.Name, got, want) + } + if err != nil { + continue + } + + var decoded RawPacket + err = decoded.Unmarshal(data) + if got, want := err, test.WantUnmarshalError; got != want { + t.Fatalf("Unmarshal %q: err = %v, want %v", test.Name, got, want) + } + if err != nil { + continue + } + + if got, want := decoded, test.Packet; !reflect.DeepEqual(got, want) { + t.Fatalf("%q raw round trip: got %#v, want %#v", test.Name, got, want) + } + } +}