Still reworking new connection sequence.
This commit is contained in:
parent
049f81ed50
commit
4f3a73bf12
21 changed files with 408 additions and 258 deletions
6
LICENSE
6
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
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
59
schema.sql
59
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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
return FAIL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 };
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#define UPDATE_H
|
||||
|
||||
|
||||
void update(char *params);
|
||||
void update(void);
|
||||
|
||||
|
||||
#endif // UPDATE_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
|
||||
|
|
Loading…
Add table
Reference in a new issue