package main import ( "crypto/rand" "encoding/binary" "errors" "fmt" ) const HeaderSize int = 32 + 1 + 4 + 4 type SessionID [32]byte type Packet struct { // headerLength uint32 sid SessionID flag HeaderFlag sync uint32 dataLength uint32 data []byte } func PacketFromBytes(bytes []byte) Packet { sid := SessionID(bytes[0:32]) flag := HeaderFlag(bytes[32]) sync := binary.LittleEndian.Uint32(bytes[33:37]) dataLength := binary.LittleEndian.Uint32(bytes[37:41]) pck := Packet{ sid: sid, flag: flag, sync: sync, dataLength: dataLength, data: bytes[41 : 41+dataLength], } return pck } func NewAck(pckToAck *Packet) *Packet { data := make([]byte, 4) binary.LittleEndian.PutUint32(data, pckToAck.sync) return &Packet{ sid: pckToAck.sid, flag: Ack, sync: pckToAck.sync + 1, dataLength: uint32(4), data: data, } } func NewRequest(path string) *Packet { data := []byte(path) buf := make([]byte, 32) _, err := rand.Read(buf) if err != nil { panic(err) } return &Packet{ sid: SessionID(buf), flag: Request, sync: 0, dataLength: uint32(len(data)), data: data, } } func NewFile(lastPck *Packet, data []byte) *Packet { return &Packet{ sid: lastPck.sid, flag: File, sync: lastPck.sync + 1, dataLength: uint32(len(data)), data: data, } } func NewEnd(lastFilePck *Packet) *Packet { data := make([]byte, 4) binary.LittleEndian.PutUint32(data, lastFilePck.sync) return &Packet{ sid: lastFilePck.sid, flag: End, sync: lastFilePck.sync + 1, dataLength: uint32(4), data: data, } } func NewResend(sync uint32, lastPck *Packet) *Packet { data := make([]byte, 4) binary.LittleEndian.PutUint32(data, sync) return &Packet{ sid: lastPck.sid, flag: Resend, sync: lastPck.sync + 1, dataLength: uint32(4), data: data, } } func NewPte(fileSize uint32, lastPck *Packet) *Packet { data := make([]byte, 4) binary.LittleEndian.PutUint32(data, fileSize) return &Packet{ sid: lastPck.sid, flag: PTE, sync: lastPck.sync + 1, dataLength: uint32(4), data: data, } } func (pck *Packet) GetUint32Payload() (uint32, error) { flag := pck.flag if flag != PTE && flag != Ack && flag != End && flag != Resend { return 0, errors.New(fmt.Sprintf("Can not get Sync from Packet Type with flag: %v", flag)) } return binary.LittleEndian.Uint32(pck.data), nil } func (pck *Packet) GetFilePath() (string, error) { if pck.flag != Request { return "", errors.New("Can not get FilePath from Packet that is not Request") } return string(pck.data), nil } func (pck *Packet) ToBytes() []byte { arr := make([]byte, HeaderSize+int(pck.dataLength)) copy(arr[0:32], pck.sid[:]) arr[32] = byte(pck.flag) binary.LittleEndian.PutUint32(arr[33:37], pck.sync) binary.LittleEndian.PutUint32(arr[37:41], pck.dataLength) copy(arr[41:], pck.data) return arr } type HeaderFlag uint8 const ( Request HeaderFlag = iota PTE HeaderFlag = iota Ack HeaderFlag = iota File HeaderFlag = iota End HeaderFlag = iota Resend HeaderFlag = iota )