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 }