diff --git a/gapstring/gapstring.go b/gapstring/gapstring.go index 0dca1c4..722eea1 100644 --- a/gapstring/gapstring.go +++ b/gapstring/gapstring.go @@ -280,20 +280,13 @@ func (g GapString) Hexdump() string { return out.String() } -func (g GapString) Uint32LE() (uint32, GapString) { - return binary.LittleEndian.Uint32(g.Slice(0, 4).Bytes()), g.Slice(4, g.Length()) -} - -func (g GapString) Uint16LE() (uint16, GapString) { - return binary.LittleEndian.Uint16(g.Slice(0, 2).Bytes()), g.Slice(2, g.Length()) -} - -func (g GapString) Utf16(o binary.ByteOrder, fill string) string { +// XXX: These should probably move to Packet +func (g GapString) Utf16(order binary.ByteOrder, fill string) string { in := g.Bytes([]byte(fill)...) ints := make([]uint16, len(in)/2) for i := 0; i < len(in); i += 2 { - ints[i/2] = o.Uint16(in[i:]) + ints[i/2] = order.Uint16(in[i:]) } return string(utf16.Decode(ints)) } diff --git a/packet.go b/packet.go index 8eea74b..f3f0427 100644 --- a/packet.go +++ b/packet.go @@ -1,6 +1,7 @@ package netshovel import ( + "encoding/binary" "encoding/hex" "fmt" "strings" @@ -8,19 +9,40 @@ import ( "github.com/dirtbags/netshovel/gapstring" ) +type ShortError struct { + wanted, available int +} +func (e *ShortError) Error() string { + return fmt.Sprintf("Short read: wanted %d of %d available", e.wanted, e.available) +} + +type MissingError struct { +} +func (e *MissingError) Error() string { + return "Operation on missing bytes" +} + type PacketFactory func()Packet -type Field struct { +type NamedField struct { key, value string } +type HeaderField struct { + name string + bits int + value interface{} + order binary.ByteOrder +} + type Packet struct { Name string Opcode int Description string When time.Time Payload gapstring.GapString - Fields []Field + Header []HeaderField + Fields []NamedField } var never = time.Unix(0, 0) @@ -31,7 +53,8 @@ func NewPacket() Packet { Description: "Undefined", When: never, Payload: gapstring.GapString{}, - Fields: []Field{}, + Header: []HeaderField{}, + Fields: []NamedField{}, } } @@ -53,7 +76,7 @@ func (pkt *Packet) Describe() string { func (pkt *Packet) Set(key, value string) { - pkt.Fields = append(pkt.Fields, Field{key, value}) + pkt.Fields = append(pkt.Fields, NamedField{key, value}) } func (pkt *Packet) SetString(key, value string) { @@ -79,3 +102,96 @@ func (pkt *Packet) SetBytes(key string, value []byte) { func (pkt *Packet) SetGapString(key string, value gapstring.GapString) { pkt.Set(key, fmt.Sprintf("%s %s", value.HexString(), value.Runes())) } + +func (pkt *Packet) Peel(octets int) ([]byte, error) { + pllen := pkt.Payload.Length() + if octets > pllen { + return nil, &ShortError{octets, pllen} + } + buf := pkt.Payload.Slice(0, octets) + if buf.Missing() > 0 { + return nil, &MissingError{} + } + + pkt.Payload = pkt.Payload.Slice(octets, pkt.Payload.Length()) + b := buf.Bytes() + return b, nil +} + +func (pkt *Packet) AddHeaderField(order binary.ByteOrder, name string, bits int, value interface{}) { + h := HeaderField{ + name: name, + bits: bits, + value: value, + order: order, + } + pkt.Header = append(pkt.Header, h) +} + +func (pkt *Packet) readUint(order binary.ByteOrder, bits int, name string) (interface{}, error) { + switch bits { + case 8: + case 16: + case 32: + case 64: + default: + return 0, fmt.Errorf("Weird number of bits: %d", bits) + } + + octets := bits >> 3 + b, err := pkt.Peel(octets) + if err != nil { + return 0, err + } + + var value interface{} + switch bits { + case 8: + value = b[0] + case 16: + value = order.Uint16(b) + case 32: + value = order.Uint32(b) + case 64: + value = order.Uint64(b) + } + pkt.AddHeaderField(order, name, bits, value) + + return value, nil +} + +func (pkt *Packet) Uint64LE(name string) (uint64, error) { + value, err := pkt.readUint(binary.LittleEndian, 64, name) + return value.(uint64), err +} + +func (pkt *Packet) Uint32LE(name string) (uint32, error) { + value, err := pkt.readUint(binary.LittleEndian, 32, name) + return value.(uint32), err +} + +func (pkt *Packet) Uint16LE(name string) (uint16, error) { + value, err := pkt.readUint(binary.LittleEndian, 16, name) + return value.(uint16), err +} + +func (pkt *Packet) Uint64BE(name string) (uint64, error) { + value, err := pkt.readUint(binary.BigEndian, 64, name) + return value.(uint64), err +} + +func (pkt *Packet) Uint32BE(name string) (uint32, error) { + value, err := pkt.readUint(binary.BigEndian, 32, name) + return value.(uint32), err +} + +func (pkt *Packet) Uint16BE(name string) (uint16, error) { + value, err := pkt.readUint(binary.BigEndian, 16, name) + return value.(uint16), err +} + +func (pkt *Packet) Uint8(name string) (uint8, error) { + value, err := pkt.readUint(binary.BigEndian, 8, name) + return value.(uint8), err +} +