Basic packet processing. No encryption or resending yet.
This commit is contained in:
parent
395899445a
commit
c45b89c8ab
3 changed files with 294 additions and 0 deletions
|
@ -63,6 +63,7 @@ HEADERS = \
|
||||||
$$SHARED/thirdparty/blowfish-api/blowfish.h \
|
$$SHARED/thirdparty/blowfish-api/blowfish.h \
|
||||||
$$SHARED/thirdparty/ini/src/ini.h \
|
$$SHARED/thirdparty/ini/src/ini.h \
|
||||||
$$SHARED/primes.h \
|
$$SHARED/primes.h \
|
||||||
|
$$SHARED/packet.h \
|
||||||
src/config.h \
|
src/config.h \
|
||||||
$$SHARED/util.h \
|
$$SHARED/util.h \
|
||||||
src/gui/msgbox.h \
|
src/gui/msgbox.h \
|
||||||
|
@ -105,6 +106,7 @@ SOURCES = \
|
||||||
$$SHARED/thirdparty/memwatch/memwatch.c \
|
$$SHARED/thirdparty/memwatch/memwatch.c \
|
||||||
$$SHARED/thirdparty/blowfish-api/blowfish.c \
|
$$SHARED/thirdparty/blowfish-api/blowfish.c \
|
||||||
$$SHARED/thirdparty/ini/src/ini.c \
|
$$SHARED/thirdparty/ini/src/ini.c \
|
||||||
|
$$SHARED/packet.c \
|
||||||
src/config.c \
|
src/config.c \
|
||||||
$$SHARED/memory.c \
|
$$SHARED/memory.c \
|
||||||
src/gui/msgbox.c \
|
src/gui/msgbox.c \
|
||||||
|
|
195
shared/packet.c
Normal file
195
shared/packet.c
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||||
|
* Copyright (C) 2020-2021 Scott Duensing
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt);
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t packetCRC(char *data, uint16_t length, uint8_t startAt) {
|
||||||
|
uint16_t x = 0;
|
||||||
|
|
||||||
|
for (x=0; x<length; x++) {
|
||||||
|
startAt += data[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
return startAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, char *input, uint16_t length) {
|
||||||
|
uint16_t x = 0;
|
||||||
|
char c = 0;
|
||||||
|
|
||||||
|
// input and inputLength are incoming raw data or NULL and 0 to continue processing already received data.
|
||||||
|
// Returns 1 on packet ready, 0 on still waiting.
|
||||||
|
|
||||||
|
// Is there input data to add to the queue?
|
||||||
|
if (input != NULL && length > 0) {
|
||||||
|
for (x=0; x<length; x++) {
|
||||||
|
threadData->decodeQueue[threadData->decodeQueueHead++] = input[x];
|
||||||
|
if (threadData->decodeQueueHead >= PACKET_INPUT_QUEUE_SIZE) {
|
||||||
|
threadData->decodeQueueHead = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Do we have data to process?
|
||||||
|
if (threadData->decodeQueueHead == threadData->decodeQueueTail) return 0;
|
||||||
|
|
||||||
|
// Get next byte.
|
||||||
|
c = threadData->decodeQueue[threadData->decodeQueueTail++];
|
||||||
|
if (threadData->decodeQueueTail >= PACKET_INPUT_QUEUE_SIZE) {
|
||||||
|
threadData->decodeQueueTail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New packet?
|
||||||
|
if (threadData->newPacket) {
|
||||||
|
threadData->newPacket = 0;
|
||||||
|
threadData->inEscape = 0;
|
||||||
|
data->length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we escaped?
|
||||||
|
if (threadData->inEscape) {
|
||||||
|
threadData->inEscape = 0;
|
||||||
|
// Is this the end of the packet?
|
||||||
|
if (c != PACKET_FRAME) {
|
||||||
|
threadData->newPacket = 1;
|
||||||
|
|
||||||
|
// Check CRC.
|
||||||
|
if (threadData->decodeBuffer[data->length - 1] != packetCRC(threadData->decodeBuffer, data->length - 1, 0)) continue;
|
||||||
|
|
||||||
|
// Fill decoded data fields.
|
||||||
|
data->packetType = threadData->decodeBuffer[1];
|
||||||
|
data->channel = threadData->decodeBuffer[2];
|
||||||
|
|
||||||
|
// ***TODO*** Blowfish Decryption.
|
||||||
|
if (threadData->decodeBuffer[0] & 32) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy packet data to new buffer.
|
||||||
|
data->data = (char *)malloc(data->length - 4); // 4 for 3 byte header and 1 byte CRC.
|
||||||
|
if (!data) continue;
|
||||||
|
memcpy(data->data, &threadData->decodeBuffer[3], data->length - 4); // Skip header and CRC.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Are we escaping?
|
||||||
|
if (c == PACKET_FRAME) {
|
||||||
|
// Yes. Don't add this byte.
|
||||||
|
threadData->inEscape = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Did we overflow?
|
||||||
|
if (data->length >= PACKET_MAX) {
|
||||||
|
// Yup. Dump it.
|
||||||
|
threadData->newPacket = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Add byte to packet.
|
||||||
|
threadData->decodeBuffer[data->length++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t packetEncode(PacketThreadDataT *threadData, PacketEncodeDataT *data, char *input, uint16_t length) {
|
||||||
|
uint8_t crc = 0;
|
||||||
|
uint8_t control = 0;
|
||||||
|
|
||||||
|
// Returns 1 on success, 0 on failure.
|
||||||
|
|
||||||
|
// Packet too large?
|
||||||
|
if (length > PACKET_MAX) return 0;
|
||||||
|
|
||||||
|
data->dataPointer = NULL;
|
||||||
|
data->length = 0;
|
||||||
|
data->sequence = threadData->sequence++;
|
||||||
|
|
||||||
|
// Make needed header bytes.
|
||||||
|
control = (data->control << 6) + (data->encrypt << 5) + (data->sequence & 0x1f);
|
||||||
|
|
||||||
|
// Calculate CRC over header bytes and payload.
|
||||||
|
crc = packetCRC((char *)&control, 1, crc);
|
||||||
|
crc = packetCRC((char *)&data->packetType, 1, crc);
|
||||||
|
crc = packetCRC((char *)&data->channel, 1, crc);
|
||||||
|
crc = packetCRC(input, length, crc);
|
||||||
|
|
||||||
|
// Add header bytes.
|
||||||
|
threadData->encodeBuffer[data->length++] = control;
|
||||||
|
if (control == PACKET_FRAME) threadData->encodeBuffer[data->length++] = PACKET_FRAME;
|
||||||
|
threadData->encodeBuffer[data->length++] = data->packetType;
|
||||||
|
if (data->packetType == PACKET_FRAME) threadData->encodeBuffer[data->length++] = PACKET_FRAME;
|
||||||
|
threadData->encodeBuffer[data->length++] = data->channel;
|
||||||
|
if (data->channel == PACKET_FRAME) threadData->encodeBuffer[data->length++] = PACKET_FRAME;
|
||||||
|
|
||||||
|
// ***TODO*** Blowfish Encryption.
|
||||||
|
if (data->encrypt) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add payload.
|
||||||
|
while (length--) {
|
||||||
|
// Is this a frame character? If so, escape it.
|
||||||
|
if (*input == PACKET_FRAME) threadData->encodeBuffer[data->length++] = PACKET_FRAME;
|
||||||
|
// Add data.
|
||||||
|
threadData->encodeBuffer[data->length++] = *input++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add CRC.
|
||||||
|
threadData->encodeBuffer[data->length++] = crc;
|
||||||
|
if (crc == PACKET_FRAME) threadData->encodeBuffer[data->length++] = PACKET_FRAME;
|
||||||
|
|
||||||
|
// Mark end of packet.
|
||||||
|
threadData->encodeBuffer[data->length++] = PACKET_FRAME;
|
||||||
|
threadData->encodeBuffer[data->length++] = 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PacketThreadDataT *packetThreadDataCreate(void) {
|
||||||
|
PacketThreadDataT *data = NULL;
|
||||||
|
|
||||||
|
data = (PacketThreadDataT *)malloc(sizeof(PacketThreadDataT));
|
||||||
|
if (data) {
|
||||||
|
data->sequence = 0;
|
||||||
|
data->decodeQueueHead = 0;
|
||||||
|
data->decodeQueueTail = 0;
|
||||||
|
data->newPacket = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void packetThreadDataDestroy(PacketThreadDataT **data) {
|
||||||
|
PacketThreadDataT *d = *data;
|
||||||
|
|
||||||
|
free(d);
|
||||||
|
d = NULL;
|
||||||
|
*data = d;
|
||||||
|
}
|
97
shared/packet.h
Normal file
97
shared/packet.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Kangaroo Punch MultiPlayer Game Server Mark II
|
||||||
|
* Copyright (C) 2020-2021 Scott Duensing
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef PACKET_H
|
||||||
|
#define PACKET_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packet format (without framing):
|
||||||
|
*
|
||||||
|
* Byte 01: cces ssss - Two control bits, one encryption bit, five sequence bits.
|
||||||
|
* Byte 02: pppp pppp - Eight bits, packet type.
|
||||||
|
* Byte 03: cccc cccc - Eight bits, channel.
|
||||||
|
* Byte 04: dddd dddd \
|
||||||
|
* Byte ..: dddd dddd > Packet payload.
|
||||||
|
* Byte X0: dddd dddd /
|
||||||
|
* Byte X1: cccc cccc - Checksum
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define PACKET_MAX 1024 // Maximum number of bytes per packet
|
||||||
|
#define PACKET_SEQUENCE_MAX 32 // Five bits of data
|
||||||
|
|
||||||
|
#define PACKET_INPUT_QUEUE_SIZE 4096
|
||||||
|
#define PACKET_BUFFER_SIZE (PACKET_MAX * 2 + 2 + 8) // Worst case, every byte is a PACKET_FRAME. Add two for ending frame. Add 8 for worst case header and CRC.
|
||||||
|
|
||||||
|
#define PACKET_FRAME 0x7e
|
||||||
|
|
||||||
|
#define PACKET_CONTROL_DAT 0 // Regular data packet.
|
||||||
|
#define PACKET_CONTROL_RTX 1 // Retransmission packet.
|
||||||
|
#define PACKET_CONTROL_NAK 2 // Negative acknowledge.
|
||||||
|
|
||||||
|
#define PACKET_TYPE_NONE 0 // No packet.
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct PacketDecodeDataS {
|
||||||
|
// Output
|
||||||
|
uint8_t packetType; // One of PACKET_TYPE_*
|
||||||
|
char *data; // Buffer received. MUST FREE.
|
||||||
|
uint16_t length; // Length of buffer.
|
||||||
|
uint8_t channel; // Which data channel it arrived on.
|
||||||
|
} PacketDecodeDataT;
|
||||||
|
|
||||||
|
typedef struct PacketEncodeDataS {
|
||||||
|
// Input
|
||||||
|
uint8_t control; // One of PACKET_CONTROL_*
|
||||||
|
uint8_t packetType; // One of PACKET_TYPE_*
|
||||||
|
uint8_t channel; // Which data channel to use.
|
||||||
|
uint8_t encrypt; // Do we want the packet encrypted?
|
||||||
|
// Input & Output
|
||||||
|
uint16_t sequence; // For NAK packets, input the sequence number we missed. Other packets returns the sequence of this packet.
|
||||||
|
// Output
|
||||||
|
char *dataPointer; // Buffer ready to send. DO NOT FREE.
|
||||||
|
uint16_t length; // Length of buffer.
|
||||||
|
} PacketEncodeDataT;
|
||||||
|
|
||||||
|
typedef struct PacketThreadDataS {
|
||||||
|
// Internal state per thread for packet processing.
|
||||||
|
uint8_t sequence;
|
||||||
|
char decodeBuffer[PACKET_MAX];
|
||||||
|
char encodeBuffer[PACKET_BUFFER_SIZE];
|
||||||
|
char decodeQueue[PACKET_INPUT_QUEUE_SIZE];
|
||||||
|
uint16_t decodeQueueHead;
|
||||||
|
uint16_t decodeQueueTail;
|
||||||
|
uint8_t inEscape;
|
||||||
|
uint8_t newPacket;
|
||||||
|
} PacketThreadDataT;
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t packetDecode(PacketThreadDataT *threadData, PacketDecodeDataT *data, char *input, uint16_t length);
|
||||||
|
uint8_t packetEncode(PacketThreadDataT *threadData, PacketEncodeDataT *data, char *input, uint16_t length);
|
||||||
|
PacketThreadDataT *packetThreadDataCreate(void);
|
||||||
|
void packetThreadDataDestroy(PacketThreadDataT **data);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // PACKET_H
|
Loading…
Add table
Reference in a new issue