97 lines
2.2 KiB
Go
97 lines
2.2 KiB
Go
// Package tlv contains code to read and write type-length-value messages.
|
|
package tlv
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// MaxMessageSize defines how large a message can be before we reject it.
|
|
const MaxMessageSize = 1024 * 1024 * 1024 // 1GB
|
|
|
|
// ReadTLV reads a type-length-value record from r.
|
|
func ReadTLV(r io.Reader) (byte, []byte, error) {
|
|
typ, err := ReadType(r)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
|
|
buf, err := ReadLV(r)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
return typ, buf, err
|
|
}
|
|
|
|
// ReadType reads the type from a TLV record.
|
|
func ReadType(r io.Reader) (byte, error) {
|
|
var typ [1]byte
|
|
if _, err := io.ReadFull(r, typ[:]); err != nil {
|
|
if err == io.EOF {
|
|
return 0, err
|
|
} else {
|
|
return 0, fmt.Errorf("read message type: %s", err)
|
|
}
|
|
}
|
|
return typ[0], nil
|
|
}
|
|
|
|
// ReadLV reads the length-value from a TLV record.
|
|
func ReadLV(r io.Reader) ([]byte, error) {
|
|
// Read the size of the message.
|
|
var sz int64
|
|
if err := binary.Read(r, binary.BigEndian, &sz); err != nil {
|
|
return nil, fmt.Errorf("read message size: %s", err)
|
|
}
|
|
|
|
if sz < 0 {
|
|
return nil, fmt.Errorf("negative message size is invalid: %d", sz)
|
|
}
|
|
|
|
if sz >= MaxMessageSize {
|
|
return nil, fmt.Errorf("max message size of %d exceeded: %d", MaxMessageSize, sz)
|
|
}
|
|
|
|
// Read the value.
|
|
buf := make([]byte, sz)
|
|
if _, err := io.ReadFull(r, buf); err != nil {
|
|
return nil, fmt.Errorf("read message value: %s", err)
|
|
}
|
|
|
|
return buf, nil
|
|
}
|
|
|
|
// WriteTLV writes a type-length-value record to w.
|
|
func WriteTLV(w io.Writer, typ byte, buf []byte) error {
|
|
if err := WriteType(w, typ); err != nil {
|
|
return err
|
|
}
|
|
if err := WriteLV(w, buf); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WriteType writes the type in a TLV record to w.
|
|
func WriteType(w io.Writer, typ byte) error {
|
|
if _, err := w.Write([]byte{typ}); err != nil {
|
|
return fmt.Errorf("write message type: %s", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WriteLV writes the length-value in a TLV record to w.
|
|
func WriteLV(w io.Writer, buf []byte) error {
|
|
// Write the size of the message.
|
|
if err := binary.Write(w, binary.BigEndian, int64(len(buf))); err != nil {
|
|
return fmt.Errorf("write message size: %s", err)
|
|
}
|
|
|
|
// Write the value.
|
|
if _, err := w.Write(buf); err != nil {
|
|
return fmt.Errorf("write message value: %s", err)
|
|
}
|
|
return nil
|
|
}
|