kpmpgsmkii/server/src/client.c
2021-12-06 19:44:34 -06:00

130 lines
3.5 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 "client.h"
#include "array.h"
#include "network.h"
#include "console.h"
#include "packet.h"
#include "server.h"
static uint8_t clientDequeuePacket(ClientThreadT *client);
static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data);
static uint8_t clientDequeuePacket(ClientThreadT *client) {
uint16_t length = 0;
char *data = NULL;
PacketDecodeDataT decode = { 0 };
ClientRawPacketT *packet = NULL;
// Is there new data to process?
pthread_mutex_lock(&client->packetQueueMutex);
if (arrlenu(client->packetQueue) > 0) {
packet = client->packetQueue[0];
length = packet->length;
data = packet->data;
arrdel(client->packetQueue, 0);
}
pthread_mutex_unlock(&client->packetQueueMutex);
// New data or not, process anything in the queue.
if (packetDecode(client->packetThreadData, &decode, data, length)) {
clientProcessPacket(client, &decode);
DEL(decode.data);
if (packet) {
DEL(packet->data);
DEL(packet);
}
return 1;
}
// No packet.
return 0;
}
static void clientProcessPacket(ClientThreadT *client, PacketDecodeDataT *data) {
PacketEncodeDataT encoded = { 0 };
switch (data->packetType) {
case PACKET_TYPE_PING:
// Build PONG packet.
encoded.control = PACKET_CONTROL_DAT;
encoded.packetType = PACKET_TYPE_PONG;
encoded.channel = 1;
encoded.encrypt = 0;
packetEncode(client->packetThreadData, &encoded, NULL, 0);
// Send it.
packetSend(client->packetThreadData, &encoded);
logWrite("Got PING, sent PONG\n\r");
break;
case PACKET_TYPE_CLIENT_SHUTDOWN:
serverDisconnectClient(client);
break;
default:
consoleMessageQueue("%ld: Channel %d Unknown Packet %d\n", client->threadIndex, data->channel, data->packetType);
break;
}
}
void clientQueuePacket(ClientThreadT *client, uint8_t *data, uint32_t length) {
ClientRawPacketT *packet = NULL;
packet = (ClientRawPacketT *)malloc(sizeof(ClientRawPacketT));
if (packet) {
packet->data = (char *)malloc(length);
if (packet->data) {
memcpy(packet->data, data, length);
packet->length = length;
}
pthread_mutex_lock(&client->packetQueueMutex);
arrput(client->packetQueue, packet);
pthread_mutex_unlock(&client->packetQueueMutex);
}
}
void *clientThread(void *data) {
ENetPeer *peer = (ENetPeer *)data;
ClientThreadT *client = (ClientThreadT *)peer->data;
struct timespec remaining = { 0, 0 };
struct timespec sleepTime = { 0, 1000000000/100 }; // 1/100th second.
// Process packets until we're done.
while (client->running) {
if (!clientDequeuePacket(client)) {
// Don't eat all the CPU.
nanosleep(&remaining, &sleepTime);
}
}
// Clean up client data on the way out.
arrfree(client->packetQueue);
pthread_mutex_destroy(&client->packetQueueMutex);
pthread_exit(NULL);
}