// 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 }