Files
zeromesh/internal/vl1/packet.go

118 lines
2.4 KiB
Go

package vl1
import (
"encoding/binary"
"fmt"
)
const (
Version = 1
MaxPacketSize = 65535
HeaderSize = 8
MaxFrameSize = 65535
MinFrameSize = 14
PacketTypeHandshake = byte(1)
PacketTypeData = byte(2)
PacketTypeKeepalive = byte(3)
)
type Header struct {
Version byte
Type byte
NetworkID uint32
Length uint16
}
func (h *Header) Encode(buf []byte) {
buf[0] = h.Version
buf[1] = h.Type
binary.BigEndian.PutUint32(buf[2:6], h.NetworkID)
binary.BigEndian.PutUint16(buf[6:8], h.Length)
}
func (h *Header) Decode(buf []byte) error {
if len(buf) < HeaderSize {
return fmt.Errorf("header too short: %d < %d", len(buf), HeaderSize)
}
h.Version = buf[0]
h.Type = buf[1]
h.NetworkID = binary.BigEndian.Uint32(buf[2:6])
h.Length = binary.BigEndian.Uint16(buf[6:8])
return nil
}
type Packet struct {
Header Header
Payload []byte
}
func NewHandshakePacket(payload []byte) Packet {
return Packet{
Header: Header{
Version: Version,
Type: PacketTypeHandshake,
Length: uint16(len(payload)),
},
Payload: payload,
}
}
func NewDataPacket(networkID uint32, payload []byte) Packet {
return Packet{
Header: Header{
Version: Version,
Type: PacketTypeData,
NetworkID: networkID,
Length: uint16(len(payload)),
},
Payload: payload,
}
}
func NewKeepalivePacket() Packet {
return Packet{
Header: Header{
Version: Version,
Type: PacketTypeKeepalive,
Length: 0,
},
}
}
func (p *Packet) Encode() []byte {
total := HeaderSize + len(p.Payload)
buf := make([]byte, total)
p.Header.Length = uint16(len(p.Payload))
p.Header.Encode(buf[:HeaderSize])
copy(buf[HeaderSize:], p.Payload)
return buf
}
func DecodePacket(data []byte) (*Packet, error) {
var p Packet
if err := p.Header.Decode(data); err != nil {
return nil, err
}
payloadLen := int(p.Header.Length)
if HeaderSize+payloadLen > len(data) {
return nil, fmt.Errorf("packet truncated: header claims %d + %d > %d", HeaderSize, payloadLen, len(data))
}
p.Payload = make([]byte, payloadLen)
copy(p.Payload, data[HeaderSize:HeaderSize+payloadLen])
return &p, nil
}
func DecodePacketInto(p *Packet, data []byte) error {
if err := p.Header.Decode(data); err != nil {
return err
}
payloadLen := int(p.Header.Length)
if HeaderSize+payloadLen > len(data) {
return fmt.Errorf("packet truncated")
}
p.Payload = make([]byte, payloadLen)
copy(p.Payload, data[HeaderSize:HeaderSize+payloadLen])
return nil
}