118 lines
2.4 KiB
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
|
|
}
|