Make Packet headers self-describing! Neat!
This commit is contained in:
parent
620e16bbd0
commit
495a68ce4b
|
@ -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))
|
||||
}
|
||||
|
|
124
packet.go
124
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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue