mirror of
https://github.com/fumiama/WireGold.git
synced 2026-06-04 23:40:26 +08:00
127 lines
3.3 KiB
Go
127 lines
3.3 KiB
Go
package head
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"sync/atomic"
|
|
"unsafe"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/fumiama/WireGold/config"
|
|
"github.com/fumiama/WireGold/internal/algo"
|
|
"github.com/fumiama/WireGold/internal/bin"
|
|
"github.com/fumiama/orbyte/pbuf"
|
|
)
|
|
|
|
func ParsePacketHeader(data []byte) (pbytes PacketBytes, err error) {
|
|
if len(data) <= int(PacketHeadLen) {
|
|
err = ErrDataLenLEHeader
|
|
return
|
|
}
|
|
p := selectPacket()
|
|
sz := 0
|
|
p.P(func(pb *PacketBuf) {
|
|
if bin.IsLittleEndian {
|
|
copy((*[PacketHeadLen]byte)(
|
|
(unsafe.Pointer)(&pb.DAT),
|
|
)[:], data)
|
|
} else {
|
|
pb.DAT.idxdatsz = binary.LittleEndian.Uint32(data[:4])
|
|
pb.DAT.randn = int32(binary.LittleEndian.Uint32(data[4:8]))
|
|
pt := binary.LittleEndian.Uint16(data[8:10])
|
|
pb.DAT.Proto = FlagsProto(pt)
|
|
pb.DAT.TTL = uint8(pt >> 8)
|
|
pb.DAT.SrcPort = binary.LittleEndian.Uint16(data[10:12])
|
|
pb.DAT.DstPort = binary.LittleEndian.Uint16(data[12:14])
|
|
pb.DAT.Offset = binary.LittleEndian.Uint16(data[14:16])
|
|
copy(pb.DAT.src[:], data[16:20])
|
|
copy(pb.DAT.dst[:], data[20:24])
|
|
pb.DAT.md5h8 = binary.LittleEndian.Uint64(data[24:32])
|
|
}
|
|
sz = pb.DAT.Size()
|
|
if !pb.DAT.Proto.IsValid() {
|
|
err = errors.New("invalid proto " + pb.DAT.Proto.String())
|
|
return
|
|
}
|
|
if (!pb.DAT.Proto.HasMore() && (pb.DAT.Offset != 0 ||
|
|
sz+int(PacketHeadLen) != len(data))) ||
|
|
(pb.DAT.Proto.HasMore() && pb.DAT.Offset+
|
|
uint16(len(data[PacketHeadLen:])) > uint16(sz)) {
|
|
err = ErrInvalidOffset
|
|
if config.ShowDebugLog {
|
|
logrus.Warnf("[unbox] invalid offset %04x size %04x", pb.DAT.Offset, sz)
|
|
}
|
|
return
|
|
}
|
|
var crc uint64
|
|
var b [PacketHeadNoCRCLen]byte
|
|
copy(b[:], data[:PacketHeadNoCRCLen])
|
|
ClearTTL(b[:])
|
|
crc = algo.MD5Hash8(b[:])
|
|
if crc != pb.DAT.md5h8 {
|
|
err = ErrBadCRCChecksum
|
|
if config.ShowDebugLog {
|
|
logrus.Warnf("[unbox] exp crc %016x but got %016x", pb.DAT.md5h8, crc)
|
|
}
|
|
return
|
|
}
|
|
if config.ShowDebugLog {
|
|
logrus.Debugln("[unbox] header data len", sz, "read data len", len(data)-int(PacketHeadLen))
|
|
}
|
|
if sz+int(PacketHeadLen) == len(data) {
|
|
pb.Buffer.Write(data[PacketHeadLen:])
|
|
pb.DAT.hashrem = -1
|
|
return
|
|
}
|
|
pb.Buffer.Grow(sz)
|
|
pb.Buffer.Write(make([]byte, sz))
|
|
pb.DAT.hashrem = int64(sz)
|
|
})
|
|
if err != nil {
|
|
p.ManualDestroy()
|
|
return
|
|
}
|
|
pbytes = pbuf.BufferItemToBytes(p).Ignore()
|
|
return
|
|
}
|
|
|
|
// WriteDataSegment 将 data 的数据并发解码到自身 buf.
|
|
//
|
|
// 必须先调用 ParsePacketHeader 获得 packet.
|
|
//
|
|
// return: complete.
|
|
func (p *Packet) WriteDataSegment(data, buf []byte) bool {
|
|
if p.HasFinished() {
|
|
return true
|
|
}
|
|
|
|
flags := FlagsProto(data[8])
|
|
offset := binary.LittleEndian.Uint16(data[14:16])
|
|
if config.ShowDebugLog {
|
|
logrus.Debugln("[unbox] parse data flags", flags, "off", offset)
|
|
}
|
|
|
|
if offset == 0 {
|
|
p.randn = int32(binary.LittleEndian.Uint32(data[4:8]))
|
|
p.Proto = flags
|
|
p.TTL = data[9]
|
|
p.Offset = 0
|
|
p.md5h8 = binary.LittleEndian.Uint64(data[24:32])
|
|
if config.ShowDebugLog {
|
|
logrus.Debugln("[unbox] parse data set zero offset flags", flags)
|
|
}
|
|
}
|
|
|
|
rembytes := atomic.LoadInt64(&p.hashrem)
|
|
if rembytes > 0 {
|
|
n := int64(copy(buf[offset:], data[PacketHeadLen:]))
|
|
newrem := rembytes - n
|
|
for !atomic.CompareAndSwapInt64(&p.hashrem, rembytes, newrem) {
|
|
rembytes = atomic.LoadInt64(&p.hashrem)
|
|
newrem = rembytes - n
|
|
}
|
|
}
|
|
return p.HasFinished()
|
|
}
|