/* * 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 . * */ #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); }