/* * 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 "database.h" #include "settings.h" #include "file.h" static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *data); static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *data); void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) { FileRequestsT request = 0; PacketEncodeDataT encoded = { 0 }; char *packetData = NULL; uint16_t length = 0; // Must be logged in to do file operations. if (client->authenticated) { // Extract the request type. We get more data later. packetContentUnpack(data->data, "i", &request); switch (request) { case FILE_REQUEST_CHECK: clientApiFileRequestCheck(client, data); break; case FILE_REQUEST_NEXT: clientApiFileRequestNext(client, data); break; default: logWrite("Got FILE_REQUEST_UNKNOWN [%d] %d\n\r", request, data->length); // No idea what they want. packetData = packetContentPack(&length, "i", FILE_RESPONSE_UNKNOWN); // Build packet. encoded.control = PACKET_CONTROL_DAT; encoded.packetType = PACKET_TYPE_FILE_RESPONSE; encoded.channel = data->channel; encoded.encrypt = 0; packetEncode(client->packetThreadData, &encoded, packetData, length); // Send it. packetSend(client->packetThreadData, &encoded); DEL(packetData); break; } } // authenticated } static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *data) { FileRequestsT request = 0; char *path = NULL; char *sha256 = NULL; PacketEncodeDataT encoded = { 0 }; char *packetData = NULL; uint16_t length = 0; char buffer[1024] = { 0 }; char buffer2[1024] = { 0 }; uint32_t temp = 0; logWrite("Got FILE_REQUEST_CHECK\n\r"); // Extract the request. packetContentUnpack(data->data, "iss", &request, &sha256, &path); logWrite("[%s] [%s]\n\r", sha256, path); // Look up the entry and compare SHA256. dbFileSha256Get(path, buffer, FILE_VIRTUAL_PATH_MAX); if (strcasecmp(sha256, buffer) == 0) { logWrite("File is current. Sending FILE_RESPONSE_OKAY.\n\r"); // File is already current on client. temp = FILE_RESPONSE_OKAY; packetData = packetContentPack(&length, "i", temp); encoded.control = PACKET_CONTROL_DAT; encoded.packetType = PACKET_TYPE_FILE_RESPONSE; encoded.channel = data->channel; encoded.encrypt = 0; packetEncode(client->packetThreadData, &encoded, packetData, length); packetSend(client->packetThreadData, &encoded); DEL(packetData); } else { logWrite("File needs updated.\n\r"); // Get real path. dbFileRealPathGet(path, buffer, FILE_VIRTUAL_PATH_MAX); snprintf(buffer2, 1024, "%s%s", __settingsFile, buffer); // Open file & get file size. client->handle = fopen(buffer2, "rb"); if (!client->handle) { // ***TODO*** Handle error } fseek(client->handle, 0, SEEK_END); client->fileSize = ftell(client->handle); fseek(client->handle, 0, SEEK_SET); // Start sending new file to client. packetData = (char *)malloc(PACKET_MAX); if (!packetData) { // ***TODO*** Handle error } logWrite("Size is %d\n\r", client->fileSize); clientApiFileRequestNext(client, data); } } static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *data) { uint32_t temp = 0; PacketEncodeDataT encoded = { 0 }; uint16_t length = 0; uint16_t dataSize = 0; char packetData[PACKET_MAX]; // Do we have an open file? if (client->handle) { logWrite("Sending FILE_RESPONSE_SEND.\n\r"); // Add response type. temp = FILE_RESPONSE_SEND; memcpy(packetData, &temp, sizeof(int32_t)); // Add file length. memcpy(&packetData[4], &client->fileSize, sizeof(int32_t)); // Add file data. dataSize = client->fileSize - ftell(client->handle); if (dataSize > PACKET_MAX - 8) { // File is larger than a packet size. dataSize = PACKET_MAX - 8; // 8 for two integers of response data. fread(&packetData[8], dataSize, 1, client->handle); } else { // File remains will fit in this packet. fread(&packetData[8], dataSize, 1, client->handle); fclose(client->handle); client->handle = NULL; } logWrite("Sending %d bytes\n\r", dataSize); // Build packet. encoded.control = PACKET_CONTROL_DAT; encoded.packetType = PACKET_TYPE_FILE_RESPONSE; encoded.channel = data->channel; encoded.encrypt = 0; packetEncode(client->packetThreadData, &encoded, packetData, length); // Send it. packetSend(client->packetThreadData, &encoded); } }