kpmpgsmkii/client/src/network.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;
}
}
}