kpmpgsmkii/server/src/client/file.c
2022-02-13 20:38:11 -06:00

166 lines
5.4 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 "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);
}
}