protocol/package.go

272 lines
9.5 KiB
Go
Raw Normal View History

2024-01-16 03:01:44 +08:00
package protocol
import (
2024-01-24 00:48:09 +08:00
"bytes"
"errors"
2024-03-12 00:02:13 +08:00
"fmt"
2024-01-24 01:34:32 +08:00
2024-01-24 00:48:09 +08:00
"git.viry.cc/gomod/glog"
"git.viry.cc/gomod/util"
2024-01-16 03:01:44 +08:00
)
// package的起始标志
var prefix = [headLengthPrefix]uint8{0xff, 0x07, 0x55, 0x00}
var ErrorPackageIncomplete = errors.New("package incomplete")
// head中各部分的长度
const (
2024-01-24 00:48:09 +08:00
headLengthPrefix = 4
headLengthVersion = 1
headLengthCRC32Checksum = 4
headLengthFlag = 1
headLengthEncryptMethod = 1
headLengthCustomValue = 1
headLengthDataSize = 4
headLengthDataCrc32 = 4
2024-01-16 03:01:44 +08:00
)
// head中各部分的偏移
const (
2024-01-24 00:48:09 +08:00
headOffsetPrefix = 0
headOffsetVersion = headOffsetPrefix + headLengthPrefix
headOffsetCRC32Checksum = headOffsetVersion + headLengthVersion
headOffsetFlag = headOffsetCRC32Checksum + headLengthCRC32Checksum
headOffsetEncryptMethod = headOffsetFlag + headLengthFlag
headOffsetCustomValue = headOffsetEncryptMethod + headLengthEncryptMethod
headOffsetDataSize = headOffsetCustomValue + headLengthCustomValue
headOffsetDataCrc32 = headOffsetDataSize + headLengthDataSize
headOffsetData = headOffsetDataCrc32 + headLengthDataCrc32
2024-01-16 03:01:44 +08:00
)
// 计算head的crc32时起始偏移
const headOffsetNeedCheck = headOffsetCRC32Checksum + headLengthCRC32Checksum
// data的加密方式
const (
2024-01-24 00:48:09 +08:00
encryptNone uint8 = iota
2024-01-16 03:01:44 +08:00
)
// flag标志位
const (
2024-02-28 02:49:54 +08:00
// 普通心跳信号,心跳响应信号
2024-01-24 00:48:09 +08:00
flagHeartbeat uint8 = 1 << iota
2024-02-28 02:49:54 +08:00
// 心跳请求信号接收方必须回复flagHeartbeat
2024-02-27 23:38:46 +08:00
flagHeartbeatRequest
2024-01-16 03:01:44 +08:00
)
// package的head的大小 (byte)
const packageHeadSize = headOffsetData
// package的最大size (byte)
const packageMaxSize = 4096
// package的data的最大size (byte)
const dataMaxSize = packageMaxSize - packageHeadSize
type protocolPackage struct {
2024-01-24 00:48:09 +08:00
prefix [headLengthPrefix]byte // 4 byte 0xff 0x55
version uint8 // 1 byte protocol version
crc32 uint32 // 4 byte head crc32 checksum (BigEndian)
flag uint8 // 1 byte flag
encryptMethod uint8 // 1 byte encrypted method
value uint8 // 1 byte custom value (for heartbeat)
dataSize uint32 // 4 byte curSize of data (BigEndian)
dataCrc32 uint32 // 4 byte crc32 of data (BigEndian)
data []byte // ? byte data
2024-01-16 03:01:44 +08:00
}
// 创建新package, 所有新package的创建都必须通过此方法
func newPackage(flag uint8, encrypt uint8, value uint8, data []byte) *protocolPackage {
2024-01-24 00:48:09 +08:00
pkg := &protocolPackage{
prefix: prefix,
version: VERSION,
crc32: 0,
flag: flag,
2024-01-24 01:17:06 +08:00
encryptMethod: encryptNone,
2024-01-24 00:48:09 +08:00
value: value,
dataSize: uint32(len(data)),
dataCrc32: 0,
data: data,
}
pkg.generateDataCheck()
pkg.generateHeadCheck()
2024-01-24 01:17:06 +08:00
pkg.encrypt(encrypt)
2024-01-24 00:48:09 +08:00
return pkg
2024-01-16 03:01:44 +08:00
}
func (p *protocolPackage) Bytes() *bytes.Buffer {
2024-01-24 00:48:09 +08:00
buf := &bytes.Buffer{}
// prefix
buf.Write(p.prefix[:])
// version
buf.WriteByte(p.version)
// crc32
buf.Write(util.UInt32ToBytesSlice(p.crc32))
// flag
buf.WriteByte(p.flag)
// encrypt method
buf.WriteByte(p.encryptMethod)
// value
buf.WriteByte(p.value)
// data curSize
buf.Write(util.UInt32ToBytesSlice(p.dataSize))
// data crc32
buf.Write(util.UInt32ToBytesSlice(p.dataCrc32))
// data
buf.Write(p.data)
return buf
2024-01-16 03:01:44 +08:00
}
// 将head中需要校验的数据拼接起来
func (p *protocolPackage) headNeedCheckBytes() *bytes.Buffer {
2024-01-24 00:48:09 +08:00
buf := &bytes.Buffer{}
buf.WriteByte(p.flag)
buf.WriteByte(p.encryptMethod)
buf.WriteByte(p.value)
buf.Write(util.UInt32ToBytesSlice(p.dataSize))
buf.Write(util.UInt32ToBytesSlice(p.dataCrc32))
return buf
2024-01-16 03:01:44 +08:00
}
// 生成head的crc32
func (p *protocolPackage) generateHeadCheck() {
2024-01-24 00:48:09 +08:00
p.crc32 = util.NewCRC32().FromBytes(p.headNeedCheckBytes().Bytes()).Value()
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] head crc32 is %d", p.crc32)
2024-01-16 03:01:44 +08:00
}
// 校验head的crc32
func (p *protocolPackage) checkHead() bool {
2024-01-24 00:48:09 +08:00
return p.crc32 == util.NewCRC32().FromBytes(p.headNeedCheckBytes().Bytes()).Value()
2024-01-16 03:01:44 +08:00
}
// 生成data的crc32
func (p *protocolPackage) generateDataCheck() {
2024-01-24 00:48:09 +08:00
p.dataCrc32 = util.NewCRC32().FromBytes(p.data).Value()
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] data crc32 is %d", p.dataCrc32)
2024-01-16 03:01:44 +08:00
}
// 校验data的crc32
func (p *protocolPackage) checkData() bool {
2024-01-24 00:48:09 +08:00
if int(p.dataSize) != len(p.data) {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] pkg.dataSize != len(pkg.data)")
2024-01-24 00:48:09 +08:00
return false
}
return p.dataCrc32 == util.NewCRC32().FromBytes(p.data).Value()
2024-01-16 03:01:44 +08:00
}
// encrypt 加密data
2024-01-24 01:17:06 +08:00
func (p *protocolPackage) encrypt(method uint8) {
if p.encryptMethod == method {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] is already encrypted [%d]", method)
2024-01-24 01:17:06 +08:00
return // 已经加密
2024-01-24 00:48:09 +08:00
}
2024-01-24 01:17:06 +08:00
if p.encryptMethod != encryptNone {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] encrypt with other method got [%d] need encryptNone[%d]", p.encryptMethod, encryptNone)
2024-01-24 01:17:06 +08:00
return // 已经通过其他方式加密
2024-01-24 00:48:09 +08:00
}
2024-02-28 02:49:54 +08:00
glog.Warning("[protocol_package] unknown encrypt method")
2024-01-16 03:01:44 +08:00
}
// decrypt 解密data
func (p *protocolPackage) decrypt() {
2024-01-24 01:27:49 +08:00
if !p.isEncrypted() {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] is not encrypted")
2024-01-24 00:48:09 +08:00
return
}
2024-01-16 03:01:44 +08:00
}
2024-01-24 01:17:06 +08:00
// isEncrypted 是否已经加密
func (p *protocolPackage) isEncrypted() bool {
2024-01-24 01:27:49 +08:00
return p.encryptMethod != encryptNone
2024-01-24 01:17:06 +08:00
}
2024-01-16 03:01:44 +08:00
// parsePackage 从buf中读取一个package
//
// 如果协议头标志(prefix)不匹配删除buf中除第一个字符外下一个prefix1到buf开头的所有数据
// 如果协议头标志(prefix)匹配不断从buf中取出数据填充到package结构体
// 如果buf中的数据出错无法正确提取package, 则返回(nil,true), 且已从buf中提取的数据不会退回buf
func parsePackage(buf *bytes.Buffer) (*protocolPackage, error) {
2024-03-12 00:16:47 +08:00
// 协议头标志不匹配删除未知数据寻找下一个package起始位置
if !bytes.Equal(prefix[:], buf.Bytes()[headOffsetPrefix:headOffsetPrefix+headLengthPrefix]) {
glog.Trace("[protocol_package] prefix does not match, need %v got %v", prefix, buf.Bytes()[headOffsetPrefix:headOffsetPrefix+headLengthPrefix])
nextPackageHead(buf)
return nil, fmt.Errorf("prefix does not match, need %v got %v", prefix, buf.Bytes()[headOffsetPrefix:headOffsetPrefix+headLengthPrefix])
}
2024-01-24 00:48:09 +08:00
// 判断package的版本
// 暂时只处理VERSION版本的package
if buf.Len() < headOffsetVersion+headLengthVersion {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] incomplete version information, need %d got %d", headOffsetVersion+headLengthVersion, buf.Len())
2024-01-24 00:48:09 +08:00
return nil, ErrorPackageIncomplete
}
if buf.Bytes()[headOffsetVersion] != VERSION {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] unsupported version need %d got %d", VERSION, buf.Bytes()[headOffsetVersion])
2024-01-24 00:48:09 +08:00
nextPackageHead(buf)
2024-03-12 00:02:13 +08:00
return nil, fmt.Errorf("unsupported version need %d got %d", VERSION, buf.Bytes()[headOffsetVersion])
2024-01-24 00:48:09 +08:00
}
// 开始判断是否为package并提取package
if buf.Len() < packageHeadSize {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] incomplete head, need %d got %d", packageHeadSize, buf.Len())
2024-01-24 00:48:09 +08:00
return nil, ErrorPackageIncomplete
}
head := make([]byte, packageHeadSize)
copy(head, buf.Bytes()[:packageHeadSize])
// 检查head是否完整删除未知数据寻找下一个package起始位置
2024-02-03 10:38:37 +08:00
headChecksum := util.BytesSliceToUInt32(head[headOffsetCRC32Checksum : headOffsetCRC32Checksum+headLengthCRC32Checksum])
2024-01-24 00:48:09 +08:00
headCrc32 := util.NewCRC32().FromBytes(head[headOffsetNeedCheck:]).Value()
if headChecksum != headCrc32 {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] head crc32 checksum does not match, need %d got %d", headChecksum, headCrc32)
2024-01-24 00:48:09 +08:00
nextPackageHead(buf)
2024-03-12 00:02:13 +08:00
return nil, fmt.Errorf("head crc32 checksum does not match, need %d got %d", headChecksum, headCrc32)
2024-01-24 00:48:09 +08:00
}
// 检查package是否完整不完整则等待
2024-02-03 10:38:37 +08:00
packageDataSize := util.BytesSliceToUInt32(head[headOffsetDataSize : headOffsetDataSize+headLengthDataSize])
2024-01-24 00:48:09 +08:00
if packageHeadSize+int(packageDataSize) > buf.Len() {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] incomplete data, need %d got %d", packageHeadSize+packageDataSize, buf.Len())
2024-01-24 00:48:09 +08:00
return nil, ErrorPackageIncomplete
}
// package完整
pkg := &protocolPackage{}
_, _ = buf.Read(make([]byte, packageHeadSize))
// prefix
copy(pkg.prefix[:], head[headOffsetPrefix:headOffsetPrefix+headLengthPrefix])
// crc32
pkg.version = head[headOffsetVersion]
// crc32
pkg.crc32 = headCrc32
// flag
pkg.flag = head[headOffsetFlag]
// encrypt method
pkg.encryptMethod = head[headOffsetEncryptMethod]
// value
pkg.value = head[headOffsetCustomValue]
// data curSize
pkg.dataSize = packageDataSize
// data crc32
pkg.dataCrc32 = util.BytesSliceToUInt32(head[headOffsetDataCrc32 : headOffsetDataCrc32+headLengthDataCrc32])
// data
pkg.data = make([]byte, pkg.dataSize)
_, _ = buf.Read(pkg.data)
dataCrc32 := util.NewCRC32().FromBytes(pkg.data).Value()
if pkg.dataCrc32 != dataCrc32 {
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] data crc32 checksum does not match, need %d got %d", pkg.dataCrc32, dataCrc32)
2024-01-24 00:48:09 +08:00
nextPackageHead(buf)
2024-03-12 00:02:13 +08:00
return nil, fmt.Errorf("data crc32 checksum does not match, need %d got %d", pkg.dataCrc32, dataCrc32)
2024-01-24 00:48:09 +08:00
}
return pkg, nil
2024-01-16 03:01:44 +08:00
}
// 删除掉buf中第一个byte, 并将buf中的起始位置调整到与prefix[0]相同的下一个元素的位置
func nextPackageHead(buf *bytes.Buffer) {
2024-01-24 00:48:09 +08:00
var err error
_, _ = buf.ReadByte()
_, err = buf.ReadBytes(prefix[0]) // 只搜索与prefix[0]相同元素防止prefix[0]出现在buf末尾
if err == nil { // 找到下一个协议头标志把删掉的prefix回退到buffer
_ = buf.UnreadByte()
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] prefix does not match, prefix[0] found, trim buf, buf length [%d]", buf.Len())
2024-01-24 00:48:09 +08:00
} else { // 找不到下一个协议头标志清空buffer
buf.Reset()
2024-02-28 02:49:54 +08:00
glog.Trace("[protocol_package] prefix does not match, prefix[0] not found, reset buf, buf length [%d]", buf.Len())
2024-01-24 00:48:09 +08:00
}
2024-01-16 03:01:44 +08:00
}