From 4f3a73bf12874f1050f078922116af68268db772 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Tue, 22 Mar 2022 20:00:00 -0500 Subject: [PATCH] Still reworking new connection sequence. --- LICENSE | 6 +- client/client.pro | 4 +- client/src/login.c | 29 +- client/src/menu.c | 17 ++ client/src/welcome.c | 17 -- schema.sql | 59 ++-- server/server.pro | 4 +- server/src/client/file.c | 74 +++-- server/src/console.c | 8 +- server/src/database.c | 254 ++++++++++++------ server/src/database.h | 68 +++-- server/src/update.c | 122 ++++----- server/src/update.h | 2 +- shared/packets.h | 2 - .../src => shared}/thirdparty/SHA256/LICENSE | 0 .../thirdparty/SHA256/README.md | 0 .../thirdparty/SHA256/mark2/Makefile | 0 .../thirdparty/SHA256/mark2/sha256.C | 0 .../thirdparty/SHA256/mark2/sha256.h | 0 .../src => shared}/thirdparty/SHA256/sha256.c | 0 .../src => shared}/thirdparty/SHA256/sha256.h | 0 21 files changed, 408 insertions(+), 258 deletions(-) rename {client/src => shared}/thirdparty/SHA256/LICENSE (100%) rename {client/src => shared}/thirdparty/SHA256/README.md (100%) rename {client/src => shared}/thirdparty/SHA256/mark2/Makefile (100%) rename {client/src => shared}/thirdparty/SHA256/mark2/sha256.C (100%) rename {client/src => shared}/thirdparty/SHA256/mark2/sha256.h (100%) rename {client/src => shared}/thirdparty/SHA256/sha256.c (100%) rename {client/src => shared}/thirdparty/SHA256/sha256.h (100%) diff --git a/LICENSE b/LICENSE index e796eed..5c2633d 100644 --- a/LICENSE +++ b/LICENSE @@ -133,6 +133,11 @@ MemWatch http://www.linkdata.se/sourcecode/memwatch/ GPL2 +SHA256 +------ +https://github.com/ilvn/SHA256 +MIT + stb_ds.h -------- https://github.com/nothings/stb @@ -147,4 +152,3 @@ tiny-AES128-C ------------- https://github.com/bonybrown/tiny-AES128-C Unlicense - diff --git a/client/client.pro b/client/client.pro index b8f7e90..6591141 100644 --- a/client/client.pro +++ b/client/client.pro @@ -67,6 +67,7 @@ HEADERS = \ $$SHARED/thirdparty/ini/src/ini.h \ $$SHARED/thirdparty/tiny-AES-c/aes.h \ $$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.h \ + $$SHARED/thirdparty/SHA256/sha256.h \ $$SHARED/primes.h \ $$SHARED/packet.h \ $$SHARED/packets.h \ @@ -83,7 +84,6 @@ HEADERS = \ src/signup.h \ src/system/cache.h \ src/system/db.h \ - src/thirdparty/SHA256/sha256.h \ src/thirdparty/minicoro/minicoro.h \ src/system/comport.h \ src/settings.h \ @@ -126,6 +126,7 @@ SOURCES = \ $$SHARED/packet.c \ $$SHARED/thirdparty/tiny-AES-c/aes.c \ $$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \ + $$SHARED/thirdparty/SHA256/sha256.c \ $$SHARED/memory.c \ src/browser.c \ src/file.c \ @@ -160,7 +161,6 @@ SOURCES = \ src/gui/label.c \ src/config.c \ src/main.c \ - src/thirdparty/SHA256/sha256.c \ src/welcome.c \ src/login.c \ src/menu.c \ diff --git a/client/src/login.c b/client/src/login.c index 26f254c..e6a8096 100644 --- a/client/src/login.c +++ b/client/src/login.c @@ -28,6 +28,7 @@ #include "comport.h" #include "network.h" #include "taglist.h" +#include "file.h" #include "login.h" #include "signup.h" @@ -42,6 +43,8 @@ typedef enum LoginStateE { } LoginStateT; +static char *_shaClientDat = NULL; + static WindowT *_winLogin = NULL; static TextboxT *_txtUser = NULL; static TextboxT *_txtPass = NULL; @@ -58,6 +61,7 @@ static void btnLoginClick(WidgetT *widget); static void btnSignUpClick(WidgetT *widget); static void btnMsgBoxCancel(MsgBoxButtonT button); static void btnMsgBoxContinue(MsgBoxButtonT button); +static void loginFilesReady(void); static void packetHandler(PacketDecodeDataT *packet); static void setButtons(uint8_t enabled); static void timLoginProgress(WidgetT *widget); @@ -110,7 +114,11 @@ static void btnMsgBoxContinue(MsgBoxButtonT button) { } -void loginShow() { +static void loginFilesReady(void) { + char *p; + + //***TODO*** Load into database if changed. + p = cacheSha256Get("generated:client.dat"); // ***TODO*** We used to have a FORGOT PASSWORD link here, too. @@ -168,6 +176,25 @@ void loginShow() { } +void loginShow() { + char *p; + char *fileList[] = { + "generated:client.dat", + NULL + }; + + // Keep old SHA to know if we need to reload after updating. + p = cacheSha256Get("generated:client.dat"); + if (p) { + _shaClientDat = strdup(p); + } else { + _shaClientDat = NULL; + } + + fileCacheCheck(loginFilesReady, fileList); +} + + static void packetHandler(PacketDecodeDataT *packet) { char *packetData; int32_t success; diff --git a/client/src/menu.c b/client/src/menu.c index 365e08d..d49f319 100644 --- a/client/src/menu.c +++ b/client/src/menu.c @@ -45,6 +45,8 @@ static void picLogoffClick(WidgetT *widget); static void picProfileClick(WidgetT *widget); +static char *_shaGamesDat = NULL; + static PictureT *_picChat = NULL; static PictureT *_picEmail = NULL; static PictureT *_picForums = NULL; @@ -92,6 +94,10 @@ static void menuEnable(uint8_t enable) { static void menuFilesReady(void) { uint16_t x = vbeDisplayWidthGet() - 49; uint16_t y = vbeDisplayHeightGet() - 49; + char *p; + + //***TODO*** Load into database if changed. + p = cacheSha256Get("generated:games.dat"); _picLogoff = pictureNew(x, y, "menu:48logoff.png"); pictureClickHandlerSet(_picLogoff, picLogoffClick); @@ -125,6 +131,7 @@ static void menuFilesReady(void) { void menuShow(void) { + char *p; char *fileList[] = { "menu:48chat.png", "menu:48email.png", @@ -132,8 +139,18 @@ void menuShow(void) { "menu:48games.png", "menu:48logoff.png", "menu:48profile.png", + "generated:games.dat", NULL }; + + // Keep old SHA to know if we need to reload after updating. + p = cacheSha256Get("generated:games.dat"); + if (p) { + _shaGamesDat = strdup(p); + } else { + _shaGamesDat = NULL; + } + fileCacheCheck(menuFilesReady, fileList); } diff --git a/client/src/welcome.c b/client/src/welcome.c index 91e73d7..e8250dd 100644 --- a/client/src/welcome.c +++ b/client/src/welcome.c @@ -122,17 +122,11 @@ static void btnSettingsClick(WidgetT *widget) { static void packetHandler(PacketDecodeDataT *packet) { PacketEncodeDataT encoded; - char *temp; // Reset timeout. timerReset(_timProgress); switch (packet->packetType) { - case PACKET_TYPE_NUMBER: - // Store in number table. - shput(__runtimeData.integers, &packet->data[4], (int32_t)packet->data[0]); - break; - case PACKET_TYPE_PROCEED: // Connected! Show icon. widgetVisibleSet(W(_picConnect), 1); @@ -141,17 +135,6 @@ static void packetHandler(PacketDecodeDataT *packet) { _state = S_WAIT_FOR_ICON; break; - case PACKET_TYPE_STRING: - // Do we have this string already? - temp = shget(__runtimeData.strings, packet->data); - if (temp) { - DEL(temp); - shdel(__runtimeData.strings, packet->data); - } - // Store in string table. - shput(__runtimeData.strings, packet->data, strdup((char *)&packet->data[strlen((char *)packet->data) + 1])); - break; - case PACKET_TYPE_VERSION: packetContentUnpack(packet->data, "i", &__runtimeData.protocolVersion); // Do we need to update? diff --git a/schema.sql b/schema.sql index 41bf54b..2941dcd 100644 --- a/schema.sql +++ b/schema.sql @@ -65,10 +65,11 @@ CREATE TABLE `files` ( `sha256` varchar(64) NOT NULL, `modified` datetime NOT NULL, `description` varchar(255) NOT NULL DEFAULT '', + `authenticated` tinyint(1) NOT NULL DEFAULT 1, `touched` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `pathIndex` (`path`) -) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1; +) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -81,33 +82,33 @@ DROP TABLE IF EXISTS `games`; CREATE TABLE `games` ( `id` int(11) NOT NULL AUTO_INCREMENT, `active` tinyint(1) NOT NULL DEFAULT 0, - `title` varchar(255) DEFAULT NULL, - `developer` varchar(255) DEFAULT NULL, - `publisher` varchar(255) DEFAULT NULL, - `description` text DEFAULT NULL, - `releaseDate` datetime DEFAULT NULL, - `stars` double DEFAULT NULL, - `starCount` int(11) DEFAULT NULL, - `rating` varchar(255) DEFAULT NULL, - `series` varchar(255) DEFAULT NULL, - `origin` varchar(255) DEFAULT NULL, - `region` varchar(255) DEFAULT NULL, - `shortName` varchar(8) DEFAULT NULL, - `type` varchar(8) DEFAULT NULL, - `maxPlayers` int(11) DEFAULT 2, - `joinable` tinyint(1) DEFAULT 0, - `mobyGames` varchar(255) DEFAULT NULL, - `wiki` varchar(255) DEFAULT NULL, - `manual` varchar(255) DEFAULT NULL, - `root` varchar(255) DEFAULT NULL, - `worksWith` varchar(255) DEFAULT NULL, - `configSys` text DEFAULT NULL, - `autoexecBat` text DEFAULT NULL, - `options` text DEFAULT NULL, - `mods` text DEFAULT NULL, - `notes` text DEFAULT NULL, - `added` datetime DEFAULT NULL, - `modified` datetime DEFAULT NULL, + `title` varchar(255) NOT NULL DEFAULT '', + `developer` varchar(255) NOT NULL DEFAULT '', + `publisher` varchar(255) NOT NULL DEFAULT '', + `description` text NOT NULL DEFAULT '', + `releaseDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `stars` double NOT NULL DEFAULT -1, + `starCount` int(11) NOT NULL DEFAULT -1, + `rating` varchar(255) NOT NULL DEFAULT 'Not Rated.', + `series` varchar(255) NOT NULL DEFAULT '', + `origin` varchar(255) NOT NULL DEFAULT '', + `region` varchar(255) NOT NULL DEFAULT '', + `shortName` varchar(8) NOT NULL, + `type` varchar(8) NOT NULL, + `maxPlayers` int(11) NOT NULL DEFAULT 2, + `joinable` tinyint(1) NOT NULL DEFAULT 0, + `mobyGames` varchar(255) NOT NULL, + `wiki` varchar(255) NOT NULL, + `manual` varchar(255) NOT NULL, + `root` varchar(255) NOT NULL, + `worksWith` varchar(255) NOT NULL, + `configSys` text NOT NULL, + `autoexecBat` text NOT NULL, + `options` text NOT NULL, + `mods` text NOT NULL, + `notes` text NOT NULL, + `added` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `touched` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), KEY `active_index` (`active`) @@ -145,4 +146,4 @@ CREATE TABLE `users` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2022-03-21 20:14:03 +-- Dump completed on 2022-03-22 19:52:16 diff --git a/server/server.pro b/server/server.pro index 2064f50..9609633 100644 --- a/server/server.pro +++ b/server/server.pro @@ -51,7 +51,7 @@ HEADERS = \ $$SHARED/packets.h \ $$SHARED/thirdparty/tiny-AES-c/aes.h \ $$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.h \ - src/thirdparty/sha256.c/sha256.h \ + $$SHARED/thirdparty/SHA256/sha256.h \ src/client.h \ src/client/file.h \ src/client/login.h \ @@ -78,7 +78,7 @@ SOURCES = \ $$SHARED/packet.c \ $$SHARED/thirdparty/tiny-AES-c/aes.c \ $$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \ - src/thirdparty/sha256.c/sha256.c \ + $$SHARED/thirdparty/SHA256/sha256.c \ src/client.c \ src/client/file.c \ src/client/login.c \ diff --git a/server/src/client/file.c b/server/src/client/file.c index d82658b..5ccf3d3 100644 --- a/server/src/client/file.c +++ b/server/src/client/file.c @@ -24,46 +24,49 @@ #include "file.h" +static void clientApiFileFailed(ClientThreadT *client, PacketDecodeDataT *data); static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *data); static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *data); -void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) { - FileRequestsT request = 0; +static void clientApiFileFailed(ClientThreadT *client, PacketDecodeDataT *data) { PacketEncodeDataT encoded = { 0 }; uint8_t *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); + 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); +} - switch (request) { - case FILE_REQUEST_CHECK: - clientApiFileRequestCheck(client, data); - break; - case FILE_REQUEST_NEXT: - clientApiFileRequestNext(client, data); - break; +void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) { + FileRequestsT request = 0; - default: - // 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; - } + // Extract the request type. We get more data later. + packetContentUnpack(data->data, "i", &request); - } // authenticated + switch (request) { + case FILE_REQUEST_CHECK: + clientApiFileRequestCheck(client, data); + break; + + case FILE_REQUEST_NEXT: + clientApiFileRequestNext(client, data); + break; + + default: + // No idea what they want. + clientApiFileFailed(client, data); + break; + } } @@ -78,6 +81,8 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * char buffer[1024] = { 0 }; char buffer2[2064] = { 0 }; uint32_t temp = 0; + DbFileInfoT *info = NULL; + uint8_t mustAuth = 1; // Is something still open? if (client->handle) { @@ -88,8 +93,19 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT * // Extract the request. packetContentUnpack(data->data, "iss", &request, &sha256, &path); + // Get file info we need. + info = dbFileInfoGet(path); + strncpy(shaInDB, info->sha, 128); + mustAuth = info->authenticated; + dbFileInfoRelease(&info); + + // Are they allowed to check this file while un-authenticated? + if (!client->authenticated && mustAuth) { + clientApiFileFailed(client, data); + return; + } + // Look up the entry and compare SHA256. - dbFileSha256Get(path, shaInDB, 128); if (strcasecmp(sha256, shaInDB) == 0) { // File is already current on client. temp = FILE_RESPONSE_OKAY; diff --git a/server/src/console.c b/server/src/console.c index a849122..9a7c2d0 100644 --- a/server/src/console.c +++ b/server/src/console.c @@ -125,9 +125,9 @@ void consoleRun(void) { } // Help. if (!strcasecmp(command, "HELP") || !strcasecmp(command, "?")) { - sendToConsole("HELP or ? - This message.\n"); - sendToConsole("SHUTDOWN - Stop the server.\n"); - sendToConsole("UPDATE [what] - Update client data.\n"); + sendToConsole("HELP or ? - This message.\n"); + sendToConsole("SHUTDOWN - Stop the server.\n"); + sendToConsole("UPDATE - Update client data.\n"); commandOk = 1; } // Shutdown. @@ -137,7 +137,7 @@ void consoleRun(void) { } // Update. if (!strcasecmp(command, "UPDATE")) { - update(p); + update(); commandOk = 1; } // Did we grok it? diff --git a/server/src/database.c b/server/src/database.c index e518918..72347e5 100644 --- a/server/src/database.c +++ b/server/src/database.c @@ -22,7 +22,7 @@ #include #include -#include "thirdparty/sha256.c/sha256.h" +#include "thirdparty/SHA256/sha256.h" #include "array.h" #include "console.h" @@ -37,24 +37,12 @@ #define STATEMENT_MAX 2048 -typedef struct DbFileInfoS { - uint64_t id; - char *path; - uint64_t length; - char *sha; - char *modified; - uint8_t touched; -} DbFileInfoT; - - static MYSQL *_sql = NULL; static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; -static DbFileInfoT *dbFileInfoGet(char *vpath); -static void dbFileInfoRelease(DbFileInfoT **info); -static void dbFileInfoSet(DbFileInfoT *info); -static void dbFileSha256Create(char *file, char *buf); +static void dbFileInfoSet(DbFileInfoT *info); +static void dbFileSha256Create(char *file, char *buf); uint8_t dbConnect(char *host, uint16_t port, char *database, char *user, char *password) { @@ -77,6 +65,69 @@ uint8_t dbConnect(char *host, uint16_t port, char *database, char *user, char *p } +void dbClientConfigRelease(DbClientConfigT **config) { + DbClientConfigT *c = *config; + + if (c) { + DEL(c->name); + DEL(c->data); + DEL(c); + } +} + + +DbClientConfigT **dbClientConfigGet(void) { + char statement[STATEMENT_MAX]; + char *p = statement; + MYSQL_RES *result = NULL; + MYSQL_ROW row = NULL; + int count = 0; + DbClientConfigT *record = NULL; + DbClientConfigT **config = NULL; + + pthread_mutex_lock(&_mutex); + + if (!_sql) { + pthread_mutex_unlock(&_mutex); + return NULL; + } + + p += sprintf(p, "SELECT name, data FROM client"); + if (mysql_real_query(_sql, statement, p - statement) != 0) { + logWrite("dbClientConfigGet: %s\n", mysql_error(_sql)); + pthread_mutex_unlock(&_mutex); + return NULL; + } + + result = mysql_store_result(_sql); + for (count = 0; count < (int)mysql_num_rows(result); count++) { + if ((row = mysql_fetch_row(result)) == NULL) { + logWrite("dbClientConfigGet: %s\n", mysql_error(_sql)); + pthread_mutex_unlock(&_mutex); + while (arrlen(config) > 0) { + record = config[0]; + dbClientConfigRelease(&record); + arrdel(config, 0); + } + arrfree(config); + pthread_mutex_unlock(&_mutex); + return NULL; + } + + NEW(DbClientConfigT, record); + record->name = strdup(row[0]); + record->data = strdup(row[1]); + arrput(config, record); + } + + mysql_free_result(result); + + pthread_mutex_unlock(&_mutex); + + return config; +} + + uint8_t dbDisconnect(void) { if (_sql) { mysql_close(_sql); @@ -89,7 +140,7 @@ uint8_t dbDisconnect(void) { } -static DbFileInfoT *dbFileInfoGet(char *vpath) { +DbFileInfoT *dbFileInfoGet(char *vpath) { char statement[STATEMENT_MAX]; char *p = statement; MYSQL_RES *result = NULL; @@ -110,7 +161,7 @@ static DbFileInfoT *dbFileInfoGet(char *vpath) { count++; } - p += sprintf(p, "SELECT id, path, length, sha256, modified, touched FROM files WHERE path='"); + p += sprintf(p, "SELECT id, path, length, sha256, modified, authenticated, touched FROM files WHERE path='"); p += mysql_real_escape_string(_sql, p, vpath, strlen(vpath)); p += sprintf(p, "'"); if (mysql_real_query(_sql, statement, p - statement) != 0) { @@ -139,12 +190,13 @@ static DbFileInfoT *dbFileInfoGet(char *vpath) { pthread_mutex_unlock(&_mutex); return NULL; } - info->id = atol(row[0]); - info->path = strdup(row[1]); - info->length = atol(row[2]); - info->sha = strdup(row[3]); - info->modified = strdup(row[4]); - info->touched = atoi(row[5]); + info->id = atol(row[0]); + info->path = strdup(row[1]); + info->length = atol(row[2]); + info->sha = strdup(row[3]); + info->modified = strdup(row[4]); + info->authenticated = atoi(row[5]); + info->touched = atoi(row[6]); mysql_free_result(result); @@ -154,7 +206,7 @@ static DbFileInfoT *dbFileInfoGet(char *vpath) { } -static void dbFileInfoRelease(DbFileInfoT **info) { +void dbFileInfoRelease(DbFileInfoT **info) { DbFileInfoT *i = *info; if (i) { @@ -206,11 +258,11 @@ static void dbFileInfoSet(DbFileInfoT *info) { static void dbFileSha256Create(char *file, char *buf) { - FILE *f = NULL; - char buffer[1024] = { 0 }; - char hex[3] = { 0 }; - size_t bytes = 0; - sha256_t hash = { 0 }; + FILE *f = NULL; + char buffer[1024] = { 0 }; + char hex[3] = { 0 }; + size_t bytes = 0; + sha256_context hash = { 0 }; // buf has to be at least 65 bytes. buf[0] = 0; @@ -220,29 +272,106 @@ static void dbFileSha256Create(char *file, char *buf) { sha256_init(&hash); while (bytes = fread(buffer, 1, sizeof(buffer), f), bytes > 0) { - sha256_update(&hash, (unsigned char *)buffer, bytes); + sha256_hash(&hash, (uint8_t *)buffer, bytes); } fclose(f); - sha256_final(&hash, (unsigned char *)buffer); + sha256_done(&hash, (uint8_t *)buffer); for (bytes = 0; bytes < 32; bytes++) { - sprintf(hex, "%0x", (unsigned char)buffer[bytes]); + sprintf(hex, "%0x", (uint8_t)buffer[bytes]); strcat(buf, hex); } buf[64] = 0; } -uint8_t dbFileSha256Get(char *vpath, char *value, uint32_t max) { - DbFileInfoT *info = dbFileInfoGet(vpath); +void dbGameRelease(DbGameT **game) { + DbGameT *g = *game; - if (info) { - strncpy(value, info->sha, max); - dbFileInfoRelease(&info); - return SUCCESS; + if (g) { + DEL(g->title); + DEL(g->publisher); + DEL(g->developer); + DEL(g->description); + DEL(g->releaseDate); + DEL(g->rating); + DEL(g->series); + DEL(g->origin); + DEL(g->shortName); + DEL(g); + } +} + + +DbGameT **dbGamesGet(void) { + char statement[STATEMENT_MAX]; + char *p = statement; + MYSQL_RES *result = NULL; + MYSQL_ROW row = NULL; + int32_t count = 0; + int32_t i = 0; + DbGameT **gameList = NULL; + DbGameT *game = NULL; + + pthread_mutex_lock(&_mutex); + + if (!_sql) { + pthread_mutex_unlock(&_mutex); + return NULL; } - return FAIL; + p += sprintf(p, + "SELECT title, publisher, developer, description, releaseDate, " + "rating, series, origin, shortName, type, maxPlayers, joinable " + "FROM games WHERE active=1"); + if (mysql_real_query(_sql, statement, p - statement) != 0) { + logWrite("dbGamesGet: %s\n", mysql_error(_sql)); + pthread_mutex_unlock(&_mutex); + return NULL; + } + + result = mysql_store_result(_sql); + count = mysql_num_rows(result); + + if (count > 0) { + for (i=0; i 0) { + game = gameList[0]; + dbGameRelease(&game); + arrdel(gameList, 0); + } + arrfree(gameList); + pthread_mutex_unlock(&_mutex); + return NULL; + } + NEW(DbGameT, game); + game->title = strdup(row[0]); + game->publisher = strdup(row[1]); + game->developer = strdup(row[2]); + game->description = strdup(row[3]); + game->releaseDate = strdup(row[4]); + game->rating = strdup(row[5]); + game->series = strdup(row[6]); + game->origin = strdup(row[7]); + game->shortName = strdup(row[8]); + game->type = GAME_TYPE_UNKNOWN; + game->maxPlayers = atoi(row[10]); + game->joinable = atoi(row[11]); + if (!strcasecmp(row[9], "DOOR")) game->type = GAME_TYPE_DOOR; + if (!strcasecmp(row[9], "SERIAL")) game->type = GAME_TYPE_SERIAL; + if (!strcasecmp(row[9], "IPX")) game->type = GAME_TYPE_IPX; + if (!strcasecmp(row[9], "FICTION")) game->type = GAME_TYPE_FICTION; + arrput(gameList, game); + } + } + + mysql_free_result(result); + pthread_mutex_unlock(&_mutex); + + return gameList; } @@ -307,53 +436,6 @@ uint8_t dbSettingsValueGet(char *host, char *key, int32_t *value) { } -uint8_t dbTableGet(char *which, DBTableT ***table) { - char statement[STATEMENT_MAX]; - char *p = statement; - MYSQL_RES *result = NULL; - MYSQL_ROW row; - int count; - DBTableT *record = NULL; - - // By "table" we mean string or number table, not a database table. - - pthread_mutex_lock(&_mutex); - - if (!_sql) { - pthread_mutex_unlock(&_mutex); - return FAIL; - } - - p += sprintf(p, "SELECT name, data FROM "); - p += mysql_real_escape_string(_sql, p, which, strlen(which)); - if (mysql_real_query(_sql, statement, p - statement) != 0) { - logWrite("dbTableGet: %s\n", mysql_error(_sql)); - pthread_mutex_unlock(&_mutex); - return FAIL; - } - - result = mysql_store_result(_sql); - for (count = 0; count < (int)mysql_num_rows(result); count++) { - if ((row = mysql_fetch_row(result)) == NULL) { - logWrite("dbTableGet: %s\n", mysql_error(_sql)); - pthread_mutex_unlock(&_mutex); - return FAIL; - } - - NEW(DBTableT, record); - record->name = strdup(row[0]); - record->data = strdup(row[1]); - arrput(*table, record); - } - - mysql_free_result(result); - - pthread_mutex_unlock(&_mutex); - - return SUCCESS; -} - - uint8_t dbUpdateFileData(char *file, uint64_t len, char *time) { DbFileInfoT *info = NULL; char prefix[1064] = { 0 }; diff --git a/server/src/database.h b/server/src/database.h index 28049e4..477023b 100644 --- a/server/src/database.h +++ b/server/src/database.h @@ -28,25 +28,63 @@ #define DB_CONFIG_ITEM_SIZE 1024 -typedef struct DBTableS { +typedef enum DbGameTypeE { + GAME_TYPE_UNKNOWN = 0, + GAME_TYPE_DOOR, + GAME_TYPE_SERIAL, + GAME_TYPE_IPX, + GAME_TYPE_FICTION +} DbGameTypeT; + + +typedef struct DbClientConfigS { char *name; char *data; -} DBTableT; +} DbClientConfigT; + +typedef struct DbFileInfoS { + uint64_t id; + char *path; + uint64_t length; + char *sha; + char *modified; + uint8_t authenticated; + uint8_t touched; +} DbFileInfoT; + +typedef struct DbGameS { + char *title; + char *publisher; + char *developer; + char *description; + char *releaseDate; + char *rating; + char *series; + char *origin; + char *shortName; + DbGameTypeT type; + uint8_t maxPlayers; + uint8_t joinable; +} DbGameT; -uint8_t dbConnect(char *host, uint16_t port, char *database, char *user, char *password); -uint8_t dbDisconnect(void); -uint8_t dbFileSha256Get(char *vpath, char *value, uint32_t max); -uint8_t dbSettingsStringGet(char *host, char *key, char *value, uint32_t max); -uint8_t dbSettingsValueGet(char *host, char *key, int32_t *value); -uint8_t dbTableGet(char *which, DBTableT ***table); -uint8_t dbUpdateFileData(char *file, uint64_t len, char *time); -uint8_t dbUpdateFilesFinish(void); -uint8_t dbUpdateFilesStart(void); -uint8_t dbUserCreate(char *first, char *last, char *user, char *pass, char *email); -uint8_t dbUserEmailExists(char *email); -uint8_t dbUserLogin(char *user, char *password); -uint8_t dbUserNameExists(char *user); +uint8_t dbConnect(char *host, uint16_t port, char *database, char *user, char *password); +void dbClientConfigRelease(DbClientConfigT **config); +DbClientConfigT **dbClientConfigGet(void); +uint8_t dbDisconnect(void); +DbFileInfoT *dbFileInfoGet(char *vpath); +void dbFileInfoRelease(DbFileInfoT **info); +void dbGameRelease(DbGameT **game); +DbGameT **dbGamesGet(void); +uint8_t dbSettingsStringGet(char *host, char *key, char *value, uint32_t max); +uint8_t dbSettingsValueGet(char *host, char *key, int32_t *value); +uint8_t dbUpdateFileData(char *file, uint64_t len, char *time); +uint8_t dbUpdateFilesFinish(void); +uint8_t dbUpdateFilesStart(void); +uint8_t dbUserCreate(char *first, char *last, char *user, char *pass, char *email); +uint8_t dbUserEmailExists(char *email); +uint8_t dbUserLogin(char *user, char *password); +uint8_t dbUserNameExists(char *user); #endif // DATABASE_H diff --git a/server/src/update.c b/server/src/update.c index 493c54d..3fa3732 100644 --- a/server/src/update.c +++ b/server/src/update.c @@ -31,87 +31,50 @@ #include "update.h" -typedef void *(*UpdateThreadT)(void *); - - static pthread_t _updateThreadHandle = { 0 }; static uint8_t _updateThreadRunning = 0; -static uint8_t _updateAllRunning = 0; -static void *updateAll(void *data); -static void *updateConfig(void *data); -static void *updateFiles(void *path); +static void *updateAll(void *path); +static void updateConfig(void); +static void updateFiles(void *path); static int32_t updateFileEntry(const char *filepath, const struct stat *info, const int typeflag, struct FTW *pathinfo); -static void *updateGames(void *data); +static void updateGames(void); -void update(char *params) { - - char *p = NULL; +void update(void) { pthread_attr_t updateThreadAttributes = { 0 }; - UpdateThreadT updateThread = NULL; - - if (params == NULL) { - consoleMessageQueue("UPDATE [what] - where [what] is:\n"); - consoleMessageQueue(" ALL - Update everything.\n"); - consoleMessageQueue(" CONFIG - Rebuild client configuration.\n"); - consoleMessageQueue(" FILES [path] - Update file data from [path].\n"); - consoleMessageQueue(" GAMES - Rebuild game database.\n"); - return; - } - - // Is there a space in the parameters line? - p = strstr(params, " "); - if (p) { - // Replace it with zero, move P to next character for more parameters. - *p = 0; - p++; - } if (_updateThreadRunning) { consoleMessageQueue("An update is already running. Wait until it completes.\n\r"); return; } - if (!strcasecmp(params, "ALL")) { updateThread = updateAll; _updateAllRunning = 1; } - if (!strcasecmp(params, "CONFIG")) { updateThread = updateConfig; _updateAllRunning = 0; } - if (!strcasecmp(params, "FILES")) { updateThread = updateFiles; _updateAllRunning = 0; } - if (!strcasecmp(params, "GAMES")) { updateThread = updateGames; _updateAllRunning = 0; } - - if (!updateThread) { - consoleMessageQueue("Unknown UPDATE option! Type UPDATE for help.\n\r"); - return; - } - // Start update thread. _updateThreadRunning = 1; if (pthread_attr_init(&updateThreadAttributes) != 0) utilDie("Unable to create update thread attributes.\n"); pthread_attr_setdetachstate(&updateThreadAttributes, PTHREAD_CREATE_JOINABLE); - if (pthread_create(&_updateThreadHandle, &updateThreadAttributes, updateThread, (void *)p) != 0) utilDie("Unable to start update thread.\n"); - + if (pthread_create(&_updateThreadHandle, &updateThreadAttributes, updateAll, NULL) != 0) utilDie("Unable to start update thread.\n"); } static void *updateAll(void *data) { (void)data; - updateConfig(NULL); + updateConfig(); + updateGames(); updateFiles("/"); - updateGames(NULL); pthread_exit(NULL); } -static void *updateConfig(void *data) { - DBTableT *record = NULL; - DBTableT **table = NULL; - char file[MAX_PATH] = { 0 }; - FILE *f = NULL; - - (void)data; +static void updateConfig(void) { + DbClientConfigT *record = NULL; + char file[MAX_PATH] = { 0 }; + FILE *f = NULL; + DbClientConfigT **config = NULL; consoleMessageQueue("Updating client configuration data.\n"); @@ -119,28 +82,24 @@ static void *updateConfig(void *data) { f = fopen(file, "wb"); if (f) { // Fetch string table from DB. - if (dbTableGet("client", &table) == SUCCESS) { - while (arrlen(table)) { - record = table[0]; - arrdel(table, 0); + config = dbClientConfigGet(); + if (config) { + while (arrlen(config)) { + record = config[0]; + arrdel(config, 0); // Write to config file that is sent to the client. fwrite(record->name, strlen(record->name) + 1, 1, f); fwrite(record->data, strlen(record->data) + 1, 1, f); - DEL(record->name); - DEL(record->data); - DEL(record); + dbClientConfigRelease(&record); } - arrfree(table); + arrfree(config); } fclose(f); } - - if (!_updateAllRunning) pthread_exit(NULL); - return NULL; } -static void *updateFiles(void *data) { +static void updateFiles(void *data) { char file[MAX_PATH] = { 0 }; char *path = (char *)data; int32_t result = 0; @@ -161,9 +120,6 @@ static void *updateFiles(void *data) { result = nftw(file, updateFileEntry, 15, FTW_PHYS); dbUpdateFilesFinish(); } - - if (!_updateAllRunning) pthread_exit(NULL); - return NULL; } @@ -252,11 +208,39 @@ static int32_t updateFileEntry(const char *filepath, const struct stat *info, co } -static void *updateGames(void *data) { - (void)data; +static void updateGames(void) { + DbGameT **gameList = NULL; + DbGameT *game = NULL; + char file[MAX_PATH] = { 0 }; + FILE *f = NULL; + uint8_t c = 0; consoleMessageQueue("Updating client game database.\n"); - if (!_updateAllRunning) pthread_exit(NULL); - return NULL; + snprintf(file, MAX_PATH, "%s/files/generated/games.dat", __settingsFile); + f = fopen(file, "wb"); + if (f) { + gameList = dbGamesGet(); + while (arrlen(gameList) > 0) { + game = gameList[0]; + + fwrite(game->title, strlen(game->title) + 1, 1, f); + fwrite(game->publisher, strlen(game->publisher) + 1, 1, f); + fwrite(game->developer, strlen(game->developer) + 1, 1, f); + fwrite(game->description, strlen(game->description) + 1, 1, f); + fwrite(game->releaseDate, strlen(game->releaseDate) + 1, 1, f); + fwrite(game->rating, strlen(game->rating) + 1, 1, f); + fwrite(game->series, strlen(game->series) + 1, 1, f); + fwrite(game->origin, strlen(game->origin) + 1, 1, f); + fwrite(game->shortName, strlen(game->shortName) + 1, 1, f); + c = game->type; fputc(c, f); + c = game->maxPlayers; fputc(c, f); + c = game->joinable; fputc(c, f); + + dbGameRelease(&game); + arrdel(gameList, 0); + } + arrfree(gameList); + fclose(f); + } } diff --git a/server/src/update.h b/server/src/update.h index 7bb9a0b..a4d6b49 100644 --- a/server/src/update.h +++ b/server/src/update.h @@ -22,7 +22,7 @@ #define UPDATE_H -void update(char *params); +void update(void); #endif // UPDATE_H diff --git a/shared/packets.h b/shared/packets.h index 52b5f91..602b503 100644 --- a/shared/packets.h +++ b/shared/packets.h @@ -49,12 +49,10 @@ typedef enum PacketTypeE { // Packets received by only the client: PACKET_TYPE_FILE_RESPONSE, PACKET_TYPE_LOGIN_RESULT, - PACKET_TYPE_NUMBER, PACKET_TYPE_PING, PACKET_TYPE_PROCEED, PACKET_TYPE_SERVER_SHUTDOWN, PACKET_TYPE_SIGNUP_RESULT, - PACKET_TYPE_STRING, // How many packet types do we recognize? PACKET_TYPE_COUNT diff --git a/client/src/thirdparty/SHA256/LICENSE b/shared/thirdparty/SHA256/LICENSE similarity index 100% rename from client/src/thirdparty/SHA256/LICENSE rename to shared/thirdparty/SHA256/LICENSE diff --git a/client/src/thirdparty/SHA256/README.md b/shared/thirdparty/SHA256/README.md similarity index 100% rename from client/src/thirdparty/SHA256/README.md rename to shared/thirdparty/SHA256/README.md diff --git a/client/src/thirdparty/SHA256/mark2/Makefile b/shared/thirdparty/SHA256/mark2/Makefile similarity index 100% rename from client/src/thirdparty/SHA256/mark2/Makefile rename to shared/thirdparty/SHA256/mark2/Makefile diff --git a/client/src/thirdparty/SHA256/mark2/sha256.C b/shared/thirdparty/SHA256/mark2/sha256.C similarity index 100% rename from client/src/thirdparty/SHA256/mark2/sha256.C rename to shared/thirdparty/SHA256/mark2/sha256.C diff --git a/client/src/thirdparty/SHA256/mark2/sha256.h b/shared/thirdparty/SHA256/mark2/sha256.h similarity index 100% rename from client/src/thirdparty/SHA256/mark2/sha256.h rename to shared/thirdparty/SHA256/mark2/sha256.h diff --git a/client/src/thirdparty/SHA256/sha256.c b/shared/thirdparty/SHA256/sha256.c similarity index 100% rename from client/src/thirdparty/SHA256/sha256.c rename to shared/thirdparty/SHA256/sha256.c diff --git a/client/src/thirdparty/SHA256/sha256.h b/shared/thirdparty/SHA256/sha256.h similarity index 100% rename from client/src/thirdparty/SHA256/sha256.h rename to shared/thirdparty/SHA256/sha256.h