273 lines
6.8 KiB
C
273 lines
6.8 KiB
C
/*
|
|
* 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 "gui.h"
|
|
#include "comport.h"
|
|
#include "config.h"
|
|
#include "timer.h"
|
|
#include "runtime.h"
|
|
|
|
#include "network.h"
|
|
|
|
|
|
typedef struct NetworkChannelsS {
|
|
uint8_t key;
|
|
netPacketHandler value;
|
|
} NetworkChannelsT;
|
|
|
|
|
|
static netPacketHandler *_systemHandlers = NULL;
|
|
static NetworkChannelsT *_channels = NULL;
|
|
static uint8_t _netRunning = 0;
|
|
static uint8_t _netStarted = 0;
|
|
|
|
|
|
uint8_t netChannelGet(netPacketHandler handler) {
|
|
uint8_t channel = 0;
|
|
uint16_t x = 0;
|
|
|
|
// We reserve 0 for system stuff.
|
|
// Returning 0 means no channel was found.
|
|
|
|
// Find first unused channel.
|
|
for (x=1; x<255; x++) {
|
|
if (hmgeti(_channels, x) < 0) {
|
|
channel = x;
|
|
hmput(_channels, x, handler);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return channel;
|
|
}
|
|
|
|
|
|
void netChannelRelease(uint8_t channel) {
|
|
hmdel(_channels, channel);
|
|
}
|
|
|
|
|
|
void netChannelSystemGet(netPacketHandler handler) {
|
|
arrput(_systemHandlers, handler);
|
|
}
|
|
|
|
|
|
void netChannelSystemRelease(netPacketHandler handler) {
|
|
uint16_t x;
|
|
|
|
for (x=0; x<arrlen(_systemHandlers); /* no increment */) {
|
|
if (_systemHandlers[x] == handler) {
|
|
arrdel(_systemHandlers, x);
|
|
} else {
|
|
x++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void netPacketHandlerStart(void) {
|
|
_netRunning = 1;
|
|
}
|
|
|
|
|
|
void netPacketHandlerStop(void) {
|
|
if (_netRunning) {
|
|
_netRunning = 0;
|
|
|
|
// Return all channels.
|
|
while (hmlen(_channels)) hmdel(_channels, _channels[0].key);
|
|
hmfree(_channels);
|
|
|
|
// Return all system channels.
|
|
while (arrlen(_systemHandlers)) arrdel(_systemHandlers, 0);
|
|
arrfree(_systemHandlers);
|
|
}
|
|
}
|
|
|
|
|
|
void netProcess(void) {
|
|
int32_t r;
|
|
char buffer[1024];
|
|
PacketDecodeDataT *packet;
|
|
PacketDecodeDataT decoded;
|
|
PacketEncodeDataT encoded;
|
|
|
|
// ***TODO*** Detect disconnection. Maybe have callbacks registered that can notify tasks?
|
|
|
|
if (_netRunning) {
|
|
|
|
// Read pending bytes.
|
|
r = comRead(__configData.serialCom - 1, buffer, 1024);
|
|
// New data or not, process anything in the queue.
|
|
if (packetDecode(__packetThreadData, &decoded, buffer, r)) {
|
|
switch (decoded.packetType) {
|
|
case PACKET_TYPE_PING:
|
|
// Reply with PONG
|
|
encoded.control = PACKET_CONTROL_DAT;
|
|
encoded.packetType = PACKET_TYPE_PONG;
|
|
encoded.channel = 0;
|
|
encoded.encrypt = 0;
|
|
packetEncode(__packetThreadData, &encoded, NULL, 0);
|
|
packetSend(__packetThreadData, &encoded);
|
|
packetDecodeDataStaticDestroy(&decoded);
|
|
break;
|
|
|
|
default:
|
|
// Is this the system channel?
|
|
if (decoded.channel == 0) {
|
|
// Send it to all registered handlers.
|
|
for (r=0; r<arrlen(_systemHandlers); r++) {
|
|
// Copy the packet out.
|
|
NEW(PacketDecodeDataT, packet);
|
|
packet->channel = decoded.channel;
|
|
packet->length = decoded.length;
|
|
packet->packetType = decoded.packetType;
|
|
packet->data = (char *)malloc(decoded.length);
|
|
memcpy(packet->data, decoded.data, decoded.length);
|
|
// Send it to the subscriber.
|
|
_systemHandlers[r](packet);
|
|
}
|
|
} else {
|
|
// Does someone want this channel?
|
|
r = hmgeti(_channels, decoded.channel);
|
|
if (r >= 0) {
|
|
// Copy the packet out.
|
|
NEW(PacketDecodeDataT, packet);
|
|
packet->channel = decoded.channel;
|
|
packet->length = decoded.length;
|
|
packet->packetType = decoded.packetType;
|
|
packet->data = (char *)malloc(decoded.length);
|
|
memcpy(packet->data, decoded.data, decoded.length);
|
|
// Send it to the subscriber.
|
|
_channels[r].value(packet);
|
|
}
|
|
}
|
|
// Destroy our copy.
|
|
packetDecodeDataStaticDestroy(&decoded);
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // _netRunning
|
|
}
|
|
|
|
|
|
void netShutdown(void) {
|
|
FILE *cache = NULL;
|
|
|
|
netPacketHandlerStop();
|
|
|
|
if (_netStarted) {
|
|
_netStarted = 0;
|
|
|
|
// Save & free integer table.
|
|
cache = fopen("cache/integer.dat", "wt");
|
|
if (cache) {
|
|
if (__runtimeData.integers) {
|
|
while (shlen(__runtimeData.integers) > 0) {
|
|
//logWrite("[%s]=[%d]\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value);
|
|
fprintf(cache, "%s=%ld\n", __runtimeData.integers[0].key, (long)__runtimeData.integers[0].value);
|
|
shdel(__runtimeData.integers, __runtimeData.integers[0].key);
|
|
}
|
|
shfree(__runtimeData.integers);
|
|
}
|
|
fclose(cache);
|
|
}
|
|
|
|
// Save & free string table.
|
|
cache = fopen("cache/string.dat", "wt");
|
|
if (cache) {
|
|
if (__runtimeData.strings) {
|
|
while (shlen(__runtimeData.strings) > 0) {
|
|
//logWrite("[%s]=[%s]\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
|
|
fprintf(cache, "%s=%s\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
|
|
DEL(__runtimeData.strings[0].value);
|
|
shdel(__runtimeData.strings, __runtimeData.strings[0].key);
|
|
}
|
|
shfree(__runtimeData.strings);
|
|
}
|
|
fclose(cache);
|
|
}
|
|
|
|
packetThreadDataDestroy(&__packetThreadData);
|
|
}
|
|
}
|
|
|
|
|
|
void netStartup(void) {
|
|
FILE *cache = NULL;
|
|
char *line = NULL;
|
|
char *p = NULL;
|
|
char *temp = NULL;
|
|
|
|
if (!_netStarted) {
|
|
_netStarted = 1;
|
|
|
|
__packetThreadData = packetThreadDataCreate(NULL);
|
|
packetSenderRegister(comPacketSender);
|
|
|
|
__runtimeData.integers = NULL;
|
|
__runtimeData.strings = NULL;
|
|
__runtimeData.protocolVersion = 0;
|
|
|
|
sh_new_strdup(__runtimeData.integers);
|
|
sh_new_strdup(__runtimeData.strings);
|
|
|
|
// ***TODO*** Default initial tables
|
|
|
|
line = (char *)malloc(4096);
|
|
if (line) {
|
|
// Load string cache.
|
|
cache = fopen("cache/string.dat", "rt");
|
|
if (cache) {
|
|
while (fscanf(cache, "%s\n", line) != EOF) {
|
|
p = strstr(line, "=");
|
|
if (p) {
|
|
*p = 0;
|
|
p++;
|
|
// Do we have this string already?
|
|
temp = shget(__runtimeData.strings, line);
|
|
if (temp) {
|
|
DEL(temp);
|
|
shdel(__runtimeData.strings, line);
|
|
}
|
|
shput(__runtimeData.strings, line, strdup(p));
|
|
}
|
|
}
|
|
fclose(cache);
|
|
}
|
|
// Load integer cache.
|
|
cache = fopen("cache/integer.dat", "rt");
|
|
if (cache) {
|
|
while (fscanf(cache, "%s\n", line) != EOF) {
|
|
p = strstr(line, "=");
|
|
if (p) {
|
|
*p = 0;
|
|
p++;
|
|
shput(__runtimeData.integers, line, atol(p));
|
|
}
|
|
}
|
|
fclose(cache);
|
|
}
|
|
free(line);
|
|
line = NULL;
|
|
}
|
|
}
|
|
}
|