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 }