You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.5 KiB
128 lines
3.5 KiB
3 years ago
|
// This file describes the general packet structure and provides methods to work with them before|after the transportation
|
||
|
|
||
|
// Examples of packets, ready for transportation in pseudo-code:
|
||
|
// []byte(|34|FILEDATA~fe2[gkr3j930f]fwpglkrt[o])
|
||
|
// []byte(|57|FILENAME~theBestFileNameEver_Existed_in'''theUniverse.txt)
|
||
|
// general structure:
|
||
|
// PACKETSIZEDELIMETER packetsize PACKETSIZEDELIMETER packet.Header HEADERDELIMETER packet.Body (without spaces between)
|
||
|
package protocol
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"net"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
// Internal representation of packet before|after the transportation
|
||
|
type Packet struct {
|
||
|
Header Header
|
||
|
Body []byte
|
||
|
}
|
||
|
|
||
|
// Returns a size of the given packet as if it would be sent and presented in bytes.
|
||
|
// ie: FILESIZE~[49 49 56 55 56 53 50 49 54]
|
||
|
// DOES COUNT THE PACKETSIZEDELIMETER
|
||
|
func MeasurePacketSize(packet Packet) uint64 {
|
||
|
packetBytes := new(bytes.Buffer)
|
||
|
packetBytes.Write([]byte(packet.Header))
|
||
|
packetBytes.Write([]byte(HEADERDELIMETER))
|
||
|
packetBytes.Write(packet.Body)
|
||
|
|
||
|
return uint64(packetBytes.Len())
|
||
|
}
|
||
|
|
||
|
// Converts packet bytes into Packet struct
|
||
|
func BytesToPacket(packetbytes []byte) Packet {
|
||
|
var header Header
|
||
|
var body []byte
|
||
|
|
||
|
for counter, b := range packetbytes {
|
||
|
if string(b) == HEADERDELIMETER {
|
||
|
header = Header(packetbytes[0:counter])
|
||
|
body = packetbytes[counter+1:]
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return Packet{
|
||
|
Header: header,
|
||
|
Body: body,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Sends given packet to connection, following all the protocol`s rules.
|
||
|
// ALL packets MUST be sent by this method
|
||
|
func SendPacket(connection net.Conn, packetToSend Packet) error {
|
||
|
packetSize := MeasurePacketSize(packetToSend)
|
||
|
|
||
|
if packetSize > uint64(MAXPACKETSIZE) {
|
||
|
return fmt.Errorf("invalid packet: HEADER: %s BODY: %s: EXCEEDED MAX PACKETSIZE", packetToSend.Header, packetToSend.Body)
|
||
|
}
|
||
|
|
||
|
// packetsize between delimeters (ie: |17|)
|
||
|
packetSizeBytes := []byte(strconv.Itoa(int(packetSize)))
|
||
|
|
||
|
// creating a buffer and writing the whole packet into it
|
||
|
packet := new(bytes.Buffer)
|
||
|
|
||
|
packet.Write([]byte(PACKETSIZEDELIMETER))
|
||
|
packet.Write(packetSizeBytes)
|
||
|
packet.Write([]byte(PACKETSIZEDELIMETER))
|
||
|
|
||
|
packet.Write([]byte(packetToSend.Header))
|
||
|
packet.Write([]byte(HEADERDELIMETER))
|
||
|
packet.Write(packetToSend.Body)
|
||
|
|
||
|
// write the result (ie: |17|FILENAME~file.png)
|
||
|
connection.Write(packet.Bytes())
|
||
|
|
||
|
// for debug purposes (ᗜˬᗜ)
|
||
|
// fmt.Printf("SENDING PACKET: %s%s%s%s%s%s\n",
|
||
|
// []byte(PACKETSIZEDELIMETER), packetSizeBytes, []byte(PACKETSIZEDELIMETER),
|
||
|
// []byte(packetToSend.Header), []byte(HEADERDELIMETER), packetToSend.Body)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Reads a packet from given connection.
|
||
|
// ASSUMING THAT THE PACKETS ARE SENT BY `SendPacket` function !!!!
|
||
|
func ReadFromConn(connection net.Conn) (Packet, error) {
|
||
|
var err error
|
||
|
var delimeterCounter int = 0
|
||
|
var packetSizeStrBuffer string = ""
|
||
|
var packetSize int = 0
|
||
|
|
||
|
for {
|
||
|
buffer := make([]byte, 1)
|
||
|
connection.Read(buffer)
|
||
|
|
||
|
if string(buffer) == PACKETSIZEDELIMETER {
|
||
|
delimeterCounter++
|
||
|
|
||
|
// the first delimeter has been found, skipping the rest of the loop
|
||
|
if delimeterCounter == 1 {
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// the last delimeter, the next read will be the packet itself, so breaking
|
||
|
if delimeterCounter == 2 {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
packetSizeStrBuffer += string(buffer)
|
||
|
}
|
||
|
|
||
|
packetSize, err = strconv.Atoi(packetSizeStrBuffer)
|
||
|
if err != nil {
|
||
|
return Packet{}, fmt.Errorf("could not convert packetsizeStr into int: %s", err)
|
||
|
}
|
||
|
|
||
|
// have a packetsize, now reading the whole packet
|
||
|
packetBuff := make([]byte, packetSize)
|
||
|
connection.Read(packetBuff)
|
||
|
|
||
|
packet := BytesToPacket(packetBuff)
|
||
|
|
||
|
return packet, nil
|
||
|
}
|