Make pcap.Reader's API look like bufio.Scanner's.

The Next/Packet/Err structure makes read loops much
cleaner, and presents a more familiar interface for people
familiar with the stdlib.
This commit is contained in:
David Anderson 2016-02-27 21:21:10 -08:00
parent 6b9cba0085
commit 178a83f3e0
3 changed files with 42 additions and 28 deletions

View File

@ -27,6 +27,9 @@ type Reader struct {
r io.Reader
order binary.ByteOrder
tmult int64
pkt *Packet
err error
}
// Packet is one raw packet and its metadata.
@ -94,8 +97,26 @@ func NewReader(r io.Reader) (*Reader, error) {
return ret, nil
}
// Next returns the next packet in r.
func (r *Reader) Next() (*Packet, error) {
// Packet returns the packet read by the last call to Next.
func (r *Reader) Packet() *Packet {
return r.pkt
}
// Err returns the first non-EOF error encountered by the Reader.
func (r *Reader) Err() error {
if r.err == io.EOF {
return nil
}
return r.err
}
// Next advances the Reader to the next packet in the input, which
// will then be available through the Packet method. It returns false
// when the Reader stops, either by reaching the end of the input or
// an error. After Next returns false, the Err method will return any
// error that occured while reading, except that if it was io.EOF, Err
// will return nil.
func (r *Reader) Next() bool {
hdr := struct {
Sec uint32
SubSec uint32
@ -104,17 +125,20 @@ func (r *Reader) Next() (*Packet, error) {
}{}
if err := binary.Read(r.r, r.order, &hdr); err != nil {
return nil, err
r.err = err
return false
}
bs := make([]byte, hdr.Len)
if _, err := io.ReadFull(r.r, bs); err != nil {
return nil, err
r.err = err
return false
}
return &Packet{
r.pkt = &Packet{
Timestamp: time.Unix(int64(hdr.Sec), r.tmult*int64(hdr.SubSec)),
Length: int(hdr.OrigLen),
Bytes: bs,
}, nil
}
return true
}

View File

@ -2,7 +2,6 @@ package pcap
import (
"fmt"
"io"
"io/ioutil"
"os"
"testing"
@ -23,18 +22,15 @@ func TestFiles(t *testing.T) {
if r.LinkType != LinkEthernet {
t.Errorf("Expected link type %d, got %d", LinkEthernet, r.LinkType)
}
pkts := []*Packet{}
ReadLoop:
for {
pkt, err := r.Next()
if err != nil {
if err == io.EOF {
break ReadLoop
}
t.Fatalf("Unexpected error reading packets: %s", err)
}
pkts = append(pkts, pkt)
for r.Next() {
pkts = append(pkts, r.Packet())
}
if r.Err() != nil {
t.Fatalf("Reading packets from %s.pcap: %s", fname, r.Err())
}
res := pretty.Sprintf("%# v", pkts)
expectedFile := fmt.Sprintf("testdata/%s.parsed", fname)
expected, err := ioutil.ReadFile(expectedFile)

View File

@ -3,7 +3,6 @@ package pcap
import (
"bytes"
"encoding/binary"
"io"
"reflect"
"testing"
"time"
@ -63,16 +62,11 @@ func TestReadback(t *testing.T) {
t.Fatalf("Wrote link type %d, read back %d", LinkEthernet, r.LinkType)
}
ReadLoop:
for {
pkt, err := r.Next()
if err != nil {
if err == io.EOF {
break ReadLoop
}
t.Fatalf("Unexpected error reading packets: %s", err)
}
readBack = append(readBack, pkt)
for r.Next() {
readBack = append(readBack, r.Packet())
}
if r.Err() != nil {
t.Fatalf("Reading packets back: %s", r.Err())
}
if !reflect.DeepEqual(pkts, readBack) {