Still reworking new connection sequence.

This commit is contained in:
Scott Duensing 2022-03-22 20:00:00 -05:00
parent 049f81ed50
commit 4f3a73bf12
21 changed files with 408 additions and 258 deletions

View file

@ -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

View file

@ -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 \

View file

@ -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;

View file

@ -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);
}

View file

@ -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?

View file

@ -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

View file

@ -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 \

View file

@ -24,18 +24,32 @@
#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) {
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);
}
void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) {
FileRequestsT request = 0;
// Extract the request type. We get more data later.
packetContentUnpack(data->data, "i", &request);
@ -50,20 +64,9 @@ void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) {
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);
clientApiFileFailed(client, data);
break;
}
} // authenticated
}
@ -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;

View file

@ -127,7 +127,7 @@ void consoleRun(void) {
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("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?

View file

@ -22,7 +22,7 @@
#include <pthread.h>
#include <crypt.h>
#include "thirdparty/sha256.c/sha256.h"
#include "thirdparty/SHA256/sha256.h"
#include "array.h"
#include "console.h"
@ -37,22 +37,10 @@
#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);
@ -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) {
@ -144,7 +195,8 @@ static DbFileInfoT *dbFileInfoGet(char *vpath) {
info->length = atol(row[2]);
info->sha = strdup(row[3]);
info->modified = strdup(row[4]);
info->touched = atoi(row[5]);
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) {
@ -210,7 +262,7 @@ static void dbFileSha256Create(char *file, char *buf) {
char buffer[1024] = { 0 };
char hex[3] = { 0 };
size_t bytes = 0;
sha256_t hash = { 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<count; i++) {
if ((row = mysql_fetch_row(result)) == NULL) {
logWrite("dbGamesGet: %s\n", mysql_error(_sql));
mysql_free_result(result);
while (arrlen(gameList) > 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 };

View file

@ -28,18 +28,56 @@
#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);
void dbClientConfigRelease(DbClientConfigT **config);
DbClientConfigT **dbClientConfigGet(void);
uint8_t dbDisconnect(void);
uint8_t dbFileSha256Get(char *vpath, char *value, uint32_t max);
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 dbTableGet(char *which, DBTableT ***table);
uint8_t dbUpdateFileData(char *file, uint64_t len, char *time);
uint8_t dbUpdateFilesFinish(void);
uint8_t dbUpdateFilesStart(void);

View file

@ -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;
static void updateConfig(void) {
DbClientConfigT *record = NULL;
char file[MAX_PATH] = { 0 };
FILE *f = NULL;
(void)data;
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);
}
}

View file

@ -22,7 +22,7 @@
#define UPDATE_H
void update(char *params);
void update(void);
#endif // UPDATE_H

View file

@ -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