diff --git a/build.sh b/build.sh index f36a139..8c264a8 100755 --- a/build.sh +++ b/build.sh @@ -26,11 +26,11 @@ mkdir -p \ obj/client/src/system \ obj/client/src/dos \ obj/client/src/gui \ - obj/client/src/thirdparty/SHA256 \ obj/client/src/thirdparty/serial \ obj/shared/thirdparty/memwatch \ obj/shared/thirdparty/blowfish-api \ obj/shared/thirdparty/ini/src \ + obj/shared/thirdparty/SHA256 \ obj/shared/thirdparty/tiny-AES-c \ obj/shared/thirdparty/tiny-AES128-C diff --git a/client/client.pro b/client/client.pro index 6591141..d6846ee 100644 --- a/client/client.pro +++ b/client/client.pro @@ -21,7 +21,9 @@ TEMPLATE = app CONFIG -= qt -CONFIG += ASAN +CONFIG += \ + ASAN \ + c99 DESTDIR = $$OUT_PWD/bin SHARED = $$PWD/../shared @@ -71,6 +73,7 @@ HEADERS = \ $$SHARED/primes.h \ $$SHARED/packet.h \ $$SHARED/packets.h \ + ../shared/macros.h \ src/browser.h \ src/config.h \ $$SHARED/util.h \ diff --git a/client/src/file.c b/client/src/file.c index b9a8f5d..7843f23 100644 --- a/client/src/file.c +++ b/client/src/file.c @@ -73,6 +73,8 @@ void fileCacheCheck(fileCallback callback, char *vpaths[]) { FileListT *newList = NULL; uint16_t i = 0; + BEGIN + // Add new entries to anything already in the queue. NEW(FileListT, newList); newList->callback = callback; @@ -90,6 +92,8 @@ void fileCacheCheck(fileCallback callback, char *vpaths[]) { } fileCheckNext(); + + END } @@ -102,6 +106,8 @@ static void fileCheckNext(void) { char *shaPointer = NULL; static char *badSHA = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; + BEGIN + do { // This is ugly since both lists kind of depend on each other. doRecheck = 0; @@ -110,9 +116,11 @@ static void fileCheckNext(void) { if (_current == NULL) { // End of queue? if (arrlen(_fileList) == 0) { + logWrite("End of file queue.\n"); arrfree(_fileList); if (_dialogVisible) guiDelete(D(_winFile)); netChannelRelease(_channel); + _channel = 0; return; } @@ -127,6 +135,7 @@ static void fileCheckNext(void) { // End of current queue file list? if (arrlen(_current->files) == 0) { // End of list! + logWrite("End of file list.\n"); arrfree(_current->files); _current->callback(); DEL(_current); @@ -136,6 +145,7 @@ static void fileCheckNext(void) { // No. Get next file. _file = _current->files[0]; arrdel(_current->files, 0); + logWrite("File to check: %s\n", _file); } } while (doRecheck); @@ -151,6 +161,8 @@ static void fileCheckNext(void) { packetEncode(__packetThreadData, &encoded, packetData, length); packetSend(__packetThreadData, &encoded); DEL(packetData); + + END } @@ -184,6 +196,7 @@ static void fileShowError(char *message) { // Show error. This is fatal. if (_dialogVisible) guiDelete(D(_winFile)); netChannelRelease(_channel); + _channel = 0; msgBoxOne("Uh Oh!", MSGBOX_ICON_QUESTION, message, "Okay", btnMsgBoxOkay); } @@ -195,6 +208,8 @@ static void packetHandler(PacketDecodeDataT *packet) { uint16_t length = 0; uint32_t temp = 0; + BEGIN + if (packet->packetType == PACKET_TYPE_FILE_RESPONSE) { // Extract the response type. We get more data later. packetContentUnpack(packet->data, "i", &response); @@ -218,6 +233,7 @@ static void packetHandler(PacketDecodeDataT *packet) { if (!_dialogVisible) fileShowDialog(); // Are we starting a new file? if (_handle == NULL) { + logWrite("Creating file %s\n", _file); _handle = cacheFOpen(_file, "wb"); if (!_handle) { fileShowError("Unable to write to cache."); @@ -225,9 +241,11 @@ static void packetHandler(PacketDecodeDataT *packet) { } } // Write data to file, skipping first integer stored in packet. + logWrite("Writing %d bytes\n", packet->length - 4); fwrite(&packet->data[4], packet->length - 4, 1, _handle); // Is this file complete? if (ftell(_handle) >= _currentLength) { + logWrite("Closing file %s\n", _file); // Close this file. cacheFClose(_handle); _handle = NULL; @@ -256,6 +274,8 @@ static void packetHandler(PacketDecodeDataT *packet) { } packetDecodeDataDestroy(&packet); + + END } @@ -264,6 +284,8 @@ static void timTimerTimeout(WidgetT *widget) { (void)widget; + BEGIN + // Download timed out. timerStop(_timTimer); @@ -284,4 +306,6 @@ static void timTimerTimeout(WidgetT *widget) { arrfree(_fileList); if (missing) fileShowError("Unable to download needed files."); + + END } diff --git a/client/src/gui/image.c b/client/src/gui/image.c index c1c3068..c562ca5 100644 --- a/client/src/gui/image.c +++ b/client/src/gui/image.c @@ -80,6 +80,7 @@ void imageCacheIfNeeded(char *cacheFilename, char *sha256) { char *rawSha = NULL; FILE *f = NULL; + // This function expects a cache filename, not a real filesystem filename! len = strlen(cacheFilename); @@ -96,7 +97,7 @@ void imageCacheIfNeeded(char *cacheFilename, char *sha256) { temp = (char *)malloc(strlen(cacheFilename) + 5); if (!temp) return; sprintf(temp, "%s.raw", cacheFilename); - rawSha = cacheSha256Get(temp); + rawSha = strdup(cacheSha256Get(temp)); if (!rawSha || strcmp(rawSha, sha256) != 0) { // The decompressed file either does not exist or the SHA does not match the file we're checking. logWrite("Unpacking %s - %s\n", cacheFilenameGet(cacheFilename), cacheFilename); diff --git a/client/src/login.c b/client/src/login.c index e6a8096..6cf0d7d 100644 --- a/client/src/login.c +++ b/client/src/login.c @@ -117,6 +117,8 @@ static void btnMsgBoxContinue(MsgBoxButtonT button) { static void loginFilesReady(void) { char *p; + BEGIN + //***TODO*** Load into database if changed. p = cacheSha256Get("generated:client.dat"); @@ -173,6 +175,8 @@ static void loginFilesReady(void) { textboxValueSet(_txtUser, "test"); textboxValueSet(_txtPass, "test"); + + END } @@ -183,6 +187,8 @@ void loginShow() { NULL }; + BEGIN + // Keep old SHA to know if we need to reload after updating. p = cacheSha256Get("generated:client.dat"); if (p) { @@ -192,6 +198,8 @@ void loginShow() { } fileCacheCheck(loginFilesReady, fileList); + + END } @@ -199,6 +207,8 @@ static void packetHandler(PacketDecodeDataT *packet) { char *packetData; int32_t success; + BEGIN + switch (packet->packetType) { case PACKET_TYPE_LOGIN_RESULT: packetContentUnpack(packet->data, "is", &success, &packetData); @@ -220,6 +230,8 @@ static void packetHandler(PacketDecodeDataT *packet) { } packetDecodeDataDestroy(&packet); + + END } @@ -238,6 +250,8 @@ static void timLoginProgress(WidgetT *widget) { PacketEncodeDataT encoded; TimerT *t = (TimerT *)widget; + BEGIN + switch (_state) { case S_START_LOGIN: setButtons(0); @@ -260,5 +274,7 @@ static void timLoginProgress(WidgetT *widget) { msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "No response received.", "Okay", btnMsgBoxContinue); break; } + + END } diff --git a/client/src/main.c b/client/src/main.c index 480790f..65d852f 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -298,6 +298,8 @@ extern void browserShow(void); int main(int argc, char *argv[]) { + // Don't call BEGIN - no point. + if (startup(argc, argv)) return 1; // Perform "first run" setup tasks or start the client? @@ -311,5 +313,7 @@ int main(int argc, char *argv[]) { settingsShow(checkSettings); } + // Can't call END here - log is already closed. + return 0; } diff --git a/client/src/menu.c b/client/src/menu.c index d49f319..87147c1 100644 --- a/client/src/menu.c +++ b/client/src/menu.c @@ -96,6 +96,8 @@ static void menuFilesReady(void) { uint16_t y = vbeDisplayHeightGet() - 49; char *p; + BEGIN + //***TODO*** Load into database if changed. p = cacheSha256Get("generated:games.dat"); @@ -127,6 +129,8 @@ static void menuFilesReady(void) { _picProfile = pictureNew(x, y, "menu:48profile.png"); pictureClickHandlerSet(_picProfile, picProfileClick); guiAttach(guiRootGet(), W(_picProfile)); + + END } @@ -143,6 +147,8 @@ void menuShow(void) { NULL }; + BEGIN + // Keep old SHA to know if we need to reload after updating. p = cacheSha256Get("generated:games.dat"); if (p) { @@ -152,6 +158,8 @@ void menuShow(void) { } fileCacheCheck(menuFilesReady, fileList); + + END } diff --git a/client/src/signup.c b/client/src/signup.c index bfff892..b11b204 100644 --- a/client/src/signup.c +++ b/client/src/signup.c @@ -133,6 +133,8 @@ static void packetHandler(PacketDecodeDataT *packet) { uint32_t length; char *packetData; + BEGIN + // Reset timeout. timerReset(_timProgress); @@ -154,6 +156,8 @@ static void packetHandler(PacketDecodeDataT *packet) { } packetDecodeDataDestroy(&packet); + + END } @@ -165,6 +169,8 @@ static void setButtons(uint8_t enabled) { void signupShow(void) { + BEGIN + TagItemT uiSignUp[] = { T_START, T_WINDOW, O(_winSignUp), @@ -256,6 +262,8 @@ void signupShow(void) { textboxValueSet(_txtUser, "test"); textboxValueSet(_txtPass1, "test"); textboxValueSet(_txtPass2, "test"); + + END } @@ -265,6 +273,8 @@ static void timSignUpProgress(WidgetT *widget) { uint8_t *packetData; TimerT *t = (TimerT *)widget; + BEGIN + switch (_state) { case S_START_SIGNUP: packetData = packetContentPack(&length, "sssss", @@ -292,6 +302,8 @@ static void timSignUpProgress(WidgetT *widget) { msgBoxOne("Uh Oh!", MSGBOX_ICON_ERROR, "No response received.", "Okay", btnMsgBoxContinue); break; } + + END } diff --git a/client/src/system/cache.c b/client/src/system/cache.c index 3ff46d3..0d63f51 100644 --- a/client/src/system/cache.c +++ b/client/src/system/cache.c @@ -250,6 +250,7 @@ uint8_t cachePreUnpack(char *name) { uint32_t length = 0; uint32_t total = 0; int8_t buffer[8192] = { 0 }; + int8_t sha[65] = { 0 }; uint8_t hv[32] = { 0 }; char virtualPath[CACHE_VIRTUAL_PATH_MAX] = { 0 }; @@ -267,8 +268,8 @@ uint8_t cachePreUnpack(char *name) { } while (virtualPath[i - 1] != 0); // Read SHA256. fread(hv, 1, sizeof(hv), in); - for (i=0; i<32; i++) sprintf((char *)&buffer[i * 2], "%02x", hv[i]); - buffer[64] = 0; + for (i=0; i<32; i++) sprintf((char *)&sha[i * 2], "%02x", hv[i]); + sha[64] = 0; // Read length. fread(&length, 1, sizeof(uint32_t), in); // Get filename from cache manager & create missing directories. @@ -279,7 +280,7 @@ uint8_t cachePreUnpack(char *name) { osMkDirP(temp); DEL(temp); } while (osFileExists(entryDir)); - cacheEntryAdd((char *)buffer, entryName, virtualPath); + cacheEntryAdd((char *)sha, entryName, virtualPath); out = fopen(entryDir, "wb"); if (out) { // Copy out data. @@ -294,7 +295,7 @@ uint8_t cachePreUnpack(char *name) { fwrite(buffer, 1, i, out); } while (length > 0); fclose(out); - imageCacheIfNeeded(virtualPath, (char *)buffer); + imageCacheIfNeeded(virtualPath, (char *)sha); } else { result = FAIL; } diff --git a/client/src/system/db.c b/client/src/system/db.c index d28b0c9..e6bf8b0 100644 --- a/client/src/system/db.c +++ b/client/src/system/db.c @@ -68,10 +68,10 @@ static sqlite3_stmt *dbSqlBind(char *sql, char *format, va_list args) { uint8_t dbExecute(char *sql, char *format, ...) { - char *error; + char *error = NULL; int32_t r; va_list args; - sqlite3_stmt *stmt; + sqlite3_stmt *stmt = NULL; if (format == NULL) { // No parameters, just run it. @@ -81,20 +81,25 @@ uint8_t dbExecute(char *sql, char *format, ...) { stmt = dbSqlBind(sql, format, args); va_end(args); r = (sqlite3_step(stmt) == SQLITE_DONE ? SQLITE_OK : SQLITE_ERROR); - sqlite3_finalize(stmt); } + if (r == SQLITE_ERROR) logWrite("DB: %s\n", error); + + if (stmt) sqlite3_finalize(stmt); + return r == SQLITE_OK ? SUCCESS : FAIL; } uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...) { va_list args; - sqlite3_stmt *stmt; + sqlite3_stmt *stmt = NULL; int32_t r; static double d; static int32_t i; - static char *v; + static char *v = NULL; + + if (v) DEL(v); if (format == NULL) { // No parameters, just run it. @@ -122,6 +127,7 @@ uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...) case 'v': v = (char *)sqlite3_column_text(stmt, 0); + if (v) v = strdup(v); // Make a copy so it doesn't get clobbered. *result = v; break; @@ -132,6 +138,8 @@ uint8_t dbQuerySingle(char rformat, void **result, char *sql, char *format, ...) } } + sqlite3_finalize(stmt); + return r == SQLITE_OK ? SUCCESS : FAIL; } diff --git a/client/src/system/os.h b/client/src/system/os.h index 1128b76..83dd743 100644 --- a/client/src/system/os.h +++ b/client/src/system/os.h @@ -73,33 +73,15 @@ void linuxOsStartup(void); #endif - -// Should be after system headers in this file. -#define MEMORY_CHECK_ENABLED -#include "memory.h" +#include "macros.h" // Now our headers. -#include "log.h" -#include "util.h" #include "packet.h" #include "cache.h" - -// Allocation helpers. -#define NEW(t,v) (v)=(t*)calloc(1, sizeof(t)) -#define DEL(v) { if (v) { free(v); v = NULL; } } - -#define SUCCESS 1 -#define FAIL 0 - -// Some helper defines. -#define DIVISIBLE_BY_EIGHT(x) ((((x) >> 3) << 3) == (x)) -#define HIGH_BYTE(b) ((uint8_t)(((b) & 0xFF00) >> 8)) -#define LOW_BYTE(b) ((uint8_t)((b) & 0x00FF)) - - +#ifndef PacketThreadDataT typedef struct PacketThreadDataS PacketThreadDataT; - +#endif extern PacketThreadDataT *__packetThreadData; // Declared in main.c diff --git a/client/src/welcome.c b/client/src/welcome.c index e8250dd..321e2ac 100644 --- a/client/src/welcome.c +++ b/client/src/welcome.c @@ -123,6 +123,8 @@ static void btnSettingsClick(WidgetT *widget) { static void packetHandler(PacketDecodeDataT *packet) { PacketEncodeDataT encoded; + BEGIN + // Reset timeout. timerReset(_timProgress); @@ -160,6 +162,8 @@ static void packetHandler(PacketDecodeDataT *packet) { } packetDecodeDataDestroy(&packet); + + END } @@ -180,6 +184,8 @@ void welcomeShow(void) { // 450x128 logo + BEGIN + TagItemT uiWelcome[] = { T_START, T_WINDOW, O(_winWelcome), @@ -234,6 +240,8 @@ void welcomeShow(void) { }; tagListRun(uiWelcome); + + END } @@ -244,6 +252,8 @@ static void timWelcomeProgress(WidgetT *widget) { static char buffer[1024] = { 0 }; static uint16_t offset = 0; + BEGIN + switch (_state) { case S_START_CONNECT: // Ghost all buttons. @@ -361,4 +371,6 @@ static void timWelcomeProgress(WidgetT *widget) { loginShow(); break; } + + END } diff --git a/server/src/client/file.c b/server/src/client/file.c index 5ccf3d3..f0cdc9f 100644 --- a/server/src/client/file.c +++ b/server/src/client/file.c @@ -50,6 +50,8 @@ static void clientApiFileFailed(ClientThreadT *client, PacketDecodeDataT *data) void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) { FileRequestsT request = 0; + BEGIN + // Extract the request type. We get more data later. packetContentUnpack(data->data, "i", &request); @@ -67,6 +69,8 @@ void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) { clientApiFileFailed(client, data); break; } + + END } @@ -84,6 +88,8 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * DbFileInfoT *info = NULL; uint8_t mustAuth = 1; + BEGIN + // Is something still open? if (client->handle) { fclose(client->handle); @@ -101,12 +107,14 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * // Are they allowed to check this file while un-authenticated? if (!client->authenticated && mustAuth) { + logWrite("Unauthenticated user requested file: %s\n", path); clientApiFileFailed(client, data); return; } // Look up the entry and compare SHA256. if (strcasecmp(sha256, shaInDB) == 0) { + logWrite("SHAs match for %s\n", path); // File is already current on client. temp = FILE_RESPONSE_OKAY; packetData = packetContentPack(&length, "i", temp); @@ -118,6 +126,7 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * packetSend(client->packetThreadData, &encoded); DEL(packetData); } else { + logWrite("SHAs do NOT match for %s\n", path); // Get real path by flipping colons to slashes. temp = 0; while (path[temp] != 0) { @@ -133,6 +142,7 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * // Open file & get file size. client->handle = fopen(buffer2, "rb"); if (!client->handle) { + logWrite("Unable to open file: %s\n", buffer2); DEL(sha256); DEL(path); // ***TODO*** Handle error @@ -142,6 +152,8 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * client->fileSize = ftell(client->handle); fseek(client->handle, 0, SEEK_SET); + logWrite("Sending %s - %d bytes\n", buffer2, client->fileSize); + // Send file metadata to start transfer temp = FILE_RESPONSE_SEND; packetData = packetContentPack(&length, "iis", temp, client->fileSize, shaInDB); @@ -159,6 +171,8 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * // Start sending actual file data. clientApiFileRequestNext(client, data); } + + END } @@ -168,6 +182,8 @@ static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *d uint16_t length = 0; uint8_t packetData[PACKET_MAX]; + BEGIN + // Do we have an open file? if (client->handle) { // Add response type. @@ -179,10 +195,12 @@ static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *d length = client->fileSize - ftell(client->handle); if (length > PACKET_MAX - (10 + sizeof(int32_t))) { // File is larger than a packet size. + logWrite("Sending file fraction %d bytes\n", length); length = PACKET_MAX - (10 + sizeof(int32_t)); // 4 for integer of response type. 10 more because a full PACKET_MAX causes issues. fread(&packetData[sizeof(int32_t)], length, 1, client->handle); } else { // File remains will fit in this packet. + logWrite("Sending file end %d bytes\n", length); fread(&packetData[sizeof(int32_t)], length, 1, client->handle); fclose(client->handle); client->handle = NULL; @@ -197,4 +215,6 @@ static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *d // Send it. packetSend(client->packetThreadData, &encoded); } + + END } diff --git a/server/src/database.c b/server/src/database.c index 72347e5..a343607 100644 --- a/server/src/database.c +++ b/server/src/database.c @@ -1,4 +1,4 @@ -/* +/* * Kangaroo Punch MultiPlayer Game Server Mark II * Copyright (C) 2020-2021 Scott Duensing * @@ -278,7 +278,7 @@ static void dbFileSha256Create(char *file, char *buf) { sha256_done(&hash, (uint8_t *)buffer); for (bytes = 0; bytes < 32; bytes++) { - sprintf(hex, "%0x", (uint8_t)buffer[bytes]); + sprintf(hex, "%02x", (uint8_t)buffer[bytes]); strcat(buf, hex); } buf[64] = 0; diff --git a/server/src/os.h b/server/src/os.h index eadf141..318877d 100644 --- a/server/src/os.h +++ b/server/src/os.h @@ -31,23 +31,7 @@ #include #include -// Should be after system headers in this file. -#define MEMORY_CHECK_ENABLED -#include "memory.h" - -// Now our headers. -#include "log.h" -#include "util.h" - - -// Allocation helpers. -#define NEW(t,v) (v)=(t*)malloc(sizeof(t)) -#define DEL(v) {free(v); v=NULL;} - -#define SUCCESS 1 -#define FAIL 0 - -#define MAX_PATH 1024 +#include "macros.h" // Declared in main.c diff --git a/shared/macros.h b/shared/macros.h new file mode 100644 index 0000000..c95ae02 --- /dev/null +++ b/shared/macros.h @@ -0,0 +1,55 @@ +/* + * 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 . + * + */ + + +#ifndef MACROS_H +#define MACROS_H + + +#include + +// Should be after system headers in this file. +#define MEMORY_CHECK_ENABLED +#include "memory.h" + +// Now our headers. +#include "log.h" +#include "util.h" + +// Debug helpers. +#define BEGIN logWrite("BEGIN - %s @ %s (%d)\n", __FILE__, __func__, __LINE__); +#define END logWrite("END - %s @ %s (%d)\n", __FILE__, __func__, __LINE__); + +// Allocation helpers. +#define NEW(t,v) (v)=(t*)malloc(sizeof(t)) +#define DEL(v) {free(v); v=NULL;} + +// Some helper defines. +#define DIVISIBLE_BY_EIGHT(x) ((((x) >> 3) << 3) == (x)) +#define HIGH_BYTE(b) ((uint8_t)(((b) & 0xFF00) >> 8)) +#define LOW_BYTE(b) ((uint8_t)((b) & 0x00FF)) + + +#define SUCCESS 1 +#define FAIL 0 + +#define MAX_PATH 1024 + + +#endif // MACROS_H