85 lines
1.9 KiB
Go
85 lines
1.9 KiB
Go
package udp
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"hash/crc32"
|
|
"time"
|
|
)
|
|
|
|
// Packet types
|
|
const (
|
|
PacketTypeData uint8 = iota
|
|
PacketTypeAck
|
|
PacketTypeSessionRequest
|
|
PacketTypeSessionResponse
|
|
PacketTypeKeepAlive
|
|
PacketTypeDisconnect
|
|
PacketTypeFragment
|
|
)
|
|
|
|
// packet represents a protocol packet
|
|
type packet struct {
|
|
Type uint8
|
|
Sequence uint16
|
|
Ack uint16
|
|
Session uint32
|
|
Data []byte
|
|
CRC uint32
|
|
}
|
|
|
|
// Marshal serializes the packet
|
|
func (p *packet) Marshal() []byte {
|
|
dataLen := len(p.Data)
|
|
buf := make([]byte, 15+dataLen) // Fixed header + data
|
|
|
|
buf[0] = p.Type
|
|
binary.BigEndian.PutUint16(buf[1:3], p.Sequence)
|
|
binary.BigEndian.PutUint16(buf[3:5], p.Ack)
|
|
binary.BigEndian.PutUint32(buf[5:9], p.Session)
|
|
binary.BigEndian.PutUint16(buf[9:11], uint16(dataLen))
|
|
copy(buf[11:11+dataLen], p.Data)
|
|
|
|
// Calculate CRC32 for header + data
|
|
p.CRC = crc32.ChecksumIEEE(buf[:11+dataLen])
|
|
binary.BigEndian.PutUint32(buf[11+dataLen:], p.CRC)
|
|
|
|
return buf
|
|
}
|
|
|
|
// Unmarshal deserializes the packet
|
|
func (p *packet) Unmarshal(data []byte) error {
|
|
if len(data) < 15 {
|
|
return fmt.Errorf("packet too short: %d bytes", len(data))
|
|
}
|
|
|
|
p.Type = data[0]
|
|
p.Sequence = binary.BigEndian.Uint16(data[1:3])
|
|
p.Ack = binary.BigEndian.Uint16(data[3:5])
|
|
p.Session = binary.BigEndian.Uint32(data[5:9])
|
|
dataLen := binary.BigEndian.Uint16(data[9:11])
|
|
|
|
if len(data) < 15+int(dataLen) {
|
|
return fmt.Errorf("incomplete packet: expected %d bytes, got %d", 15+dataLen, len(data))
|
|
}
|
|
|
|
p.Data = make([]byte, dataLen)
|
|
copy(p.Data, data[11:11+dataLen])
|
|
p.CRC = binary.BigEndian.Uint32(data[11+dataLen:])
|
|
|
|
// Verify CRC
|
|
expectedCRC := crc32.ChecksumIEEE(data[:11+dataLen])
|
|
if p.CRC != expectedCRC {
|
|
return fmt.Errorf("CRC mismatch: expected %x, got %x", expectedCRC, p.CRC)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// pendingPacket represents a packet awaiting acknowledgment
|
|
type pendingPacket struct {
|
|
packet *packet
|
|
timestamp time.Time
|
|
attempts int
|
|
}
|