streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

commit 2891cccd2f9ecaaa53bd3897d5962e96980324a1
parent 707e234349846c8aa9f5ace53518e88033627e31
Author: Oliver Lowe <o@olowe.co>
Date:   Sun,  4 Aug 2024 19:17:10 +1000

pcap: store packet timestamp as a time.Time

Easier to work with.

Diffstat:
Mpcap/parser.go | 57++++++++++++++++++++++++++++++++++++++-------------------
Mpcap/parser_test.go | 11+++++++++++
2 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/pcap/parser.go b/pcap/parser.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "fmt" "io" + "time" ) const ( @@ -22,12 +23,18 @@ type GlobalHeader struct { } type Header struct { - TsSec uint32 - TsUsec uint32 + Time time.Time InclLen uint32 OrigLen uint32 } +type header struct { + Seconds uint32 + SubSeconds uint32 // micro or nanoseconds + InclLen uint32 + OrigLen uint32 +} + type Packet struct { Header Header Data []byte @@ -48,56 +55,68 @@ func decode(reader io.Reader) (*File, error) { return nil, fmt.Errorf("unknown magic number %#x", magic) } - var header GlobalHeader - if err := binary.Read(reader, binary.LittleEndian, &header); err != nil { + var gheader GlobalHeader + if err := binary.Read(reader, binary.LittleEndian, &gheader); err != nil { return nil, fmt.Errorf("read global header: %w", err) } var packets []Packet for i := 1; ; i++ { - var header Header - err := binary.Read(reader, binary.LittleEndian, &header) + var h header + err := binary.Read(reader, binary.LittleEndian, &h) if err == io.EOF { break } else if err != nil { return nil, fmt.Errorf("packet %d: read header: %w", i, err) } + hh := Header{ + Time: time.Unix(int64(h.Seconds), int64(h.SubSeconds)*1000), + InclLen: h.InclLen, + OrigLen: h.OrigLen, + } - data := make([]byte, header.InclLen) + data := make([]byte, h.InclLen) if _, err = io.ReadFull(reader, data); err != nil { return nil, fmt.Errorf("packet %d: read data: %w", i, err) } packets = append(packets, Packet{ - Header: header, + Header: hh, Data: data, }) } return &File{ - Header: header, + Header: gheader, Packets: packets, }, nil } func encode(file *File) ([]byte, error) { - buf := new(bytes.Buffer) - if err := binary.Write(buf, binary.NativeEndian, magicLittleEndian); err != nil { - return nil, fmt.Errorf("write magic number: %w", err) - } - + b := make([]byte, 4) + binary.NativeEndian.PutUint32(b, magicLittleEndian) + buf := bytes.NewBuffer(b) if err := binary.Write(buf, binary.LittleEndian, &file.Header); err != nil { return nil, fmt.Errorf("global header: %v", err) } - for _, packet := range file.Packets { - if err := binary.Write(buf, binary.LittleEndian, &packet.Header); err != nil { - return nil, fmt.Errorf("Packet Header: %v", err) + for _, p := range file.Packets { + sec, nsec := timestamp(p.Header.Time) + usec := nsec / 1000 + h := header{sec, usec, p.Header.InclLen, p.Header.OrigLen} + if err := binary.Write(buf, binary.LittleEndian, &h); err != nil { + return nil, fmt.Errorf("packet header: %v", err) } - if err := binary.Write(buf, binary.LittleEndian, &packet.Data); err != nil { - return nil, fmt.Errorf("Packet Data: %v", err) + if err := binary.Write(buf, binary.LittleEndian, &p.Data); err != nil { + return nil, fmt.Errorf("packet data: %v", err) } } return buf.Bytes(), nil } + +func timestamp(t time.Time) (seconds, nanoSeconds uint32) { + seconds = uint32(t.Unix()) + nanoSeconds = uint32(t.UnixNano() - t.Unix()*1e9) + return +} diff --git a/pcap/parser_test.go b/pcap/parser_test.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "testing" + "time" ) func TestReadFile(t *testing.T) { @@ -77,3 +78,13 @@ func TestReadFile(t *testing.T) { } } + +func TestTimestamp(t *testing.T) { + want := [2]uint32{1, 100} + when := time.Unix(1, 100) + sec, nsec := timestamp(when) + got := [2]uint32{sec, nsec} + if got != want { + t.Errorf("timestamp(%s) = %v, want %v", when, got, want) + } +}