GOingTunneling/netCode.go

120 lines
3.2 KiB
Go

package main
import (
"encoding/binary"
"errors"
"hash/crc32"
"net"
"strconv"
"strings"
)
// sendPacket sends a packet with the given packetID and data over the provided TCP connection.
func sendPacket(packetID uint8, data []byte, conn *net.TCPConn) error {
// Create a buffer with the packet ID and data
tempBuffer := append([]byte{packetID}, data...)
// Calculate the checksum of the packet ID + data
checksum := crc32.ChecksumIEEE(tempBuffer)
// Convert the checksum to a 4-byte slice
checksumBytes := make([]byte, 4)
binary.LittleEndian.PutUint32(checksumBytes, checksum)
// Prepend the checksum to the beginning of the buffer
tempBuffer = append(checksumBytes, tempBuffer...)
// Calculate the total length (checksum + packet ID + data)
packetLength := uint32(len(tempBuffer))
// Prepare the output buffer with the length field
outBuffer := make([]byte, 4)
binary.LittleEndian.PutUint32(outBuffer, packetLength)
// Append the tempBuffer (checksum + packet ID + data) to outBuffer
outBuffer = append(outBuffer, tempBuffer...)
// Send the packet over the connection
writeLen, err := conn.Write(outBuffer)
if err != nil {
return err
}
if writeLen != len(outBuffer) {
return errors.New("write length does not match output buffer length")
}
return nil
}
// receivePacket receives a packet from the provided TCP connection and verifies it.
func receivePacket(conn *net.TCPConn) (uint8, uint32, []byte, error) {
// Step 1: Read the packet length (4 bytes)
lengthBuffer := make([]byte, 4)
n, err := conn.Read(lengthBuffer)
if err != nil {
return 0, 0, nil, err
}
if n != len(lengthBuffer) {
return 0, 0, nil, errors.New("read length does not match read length")
}
packetLength := binary.LittleEndian.Uint32(lengthBuffer)
// Step 2: Allocate a buffer to hold the rest of the packet (checksum + packetID + data)
packetBuffer := make([]byte, packetLength)
n, err = conn.Read(packetBuffer)
if err != nil {
return 0, 0, nil, err
}
if n != int(packetLength) {
return 0, 0, nil, errors.New("read length does not match packet length")
}
// Ensure we've read enough bytes
if uint32(len(packetBuffer)) != packetLength {
return 0, 0, nil, errors.New("incomplete packet received")
}
// Step 3: Extract the checksum (4 bytes)
receivedChecksum := binary.LittleEndian.Uint32(packetBuffer[:4])
// Step 4: Extract the packet ID (1 byte)
packetID := packetBuffer[4]
// Step 5: Extract the data
data := packetBuffer[5:]
// Step 6: Verify the checksum
calculatedChecksum := crc32.ChecksumIEEE(append([]byte{packetID}, data...))
if receivedChecksum != calculatedChecksum {
return 0, 0, nil, errors.New("checksum mismatch")
}
// Return the packet ID and data
return packetID, uint32(len(data)), data, nil
}
func boolToByte(b bool) byte {
if b {
return 1
}
return 0
}
func byteToBool(b byte) bool {
return b == 1
}
func getCurrentVersion() []uint8 {
versionArrayString := strings.Split(GameVersion, ".")
if len(versionArrayString) < 3 {
return []uint8{}
}
var versionArray []uint8
for i := 0; i < len(versionArrayString); i++ {
intVersion, _ := strconv.Atoi(versionArrayString[i])
versionArray = append(versionArray, uint8(intVersion))
}
return versionArray
}