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/ http://www.linkdata.se/sourcecode/memwatch/
GPL2 GPL2
SHA256
------
https://github.com/ilvn/SHA256
MIT
stb_ds.h stb_ds.h
-------- --------
https://github.com/nothings/stb https://github.com/nothings/stb
@ -147,4 +152,3 @@ tiny-AES128-C
------------- -------------
https://github.com/bonybrown/tiny-AES128-C https://github.com/bonybrown/tiny-AES128-C
Unlicense Unlicense

View file

@ -67,6 +67,7 @@ HEADERS = \
$$SHARED/thirdparty/ini/src/ini.h \ $$SHARED/thirdparty/ini/src/ini.h \
$$SHARED/thirdparty/tiny-AES-c/aes.h \ $$SHARED/thirdparty/tiny-AES-c/aes.h \
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.h \ $$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.h \
$$SHARED/thirdparty/SHA256/sha256.h \
$$SHARED/primes.h \ $$SHARED/primes.h \
$$SHARED/packet.h \ $$SHARED/packet.h \
$$SHARED/packets.h \ $$SHARED/packets.h \
@ -83,7 +84,6 @@ HEADERS = \
src/signup.h \ src/signup.h \
src/system/cache.h \ src/system/cache.h \
src/system/db.h \ src/system/db.h \
src/thirdparty/SHA256/sha256.h \
src/thirdparty/minicoro/minicoro.h \ src/thirdparty/minicoro/minicoro.h \
src/system/comport.h \ src/system/comport.h \
src/settings.h \ src/settings.h \
@ -126,6 +126,7 @@ SOURCES = \
$$SHARED/packet.c \ $$SHARED/packet.c \
$$SHARED/thirdparty/tiny-AES-c/aes.c \ $$SHARED/thirdparty/tiny-AES-c/aes.c \
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \ $$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \
$$SHARED/thirdparty/SHA256/sha256.c \
$$SHARED/memory.c \ $$SHARED/memory.c \
src/browser.c \ src/browser.c \
src/file.c \ src/file.c \
@ -160,7 +161,6 @@ SOURCES = \
src/gui/label.c \ src/gui/label.c \
src/config.c \ src/config.c \
src/main.c \ src/main.c \
src/thirdparty/SHA256/sha256.c \
src/welcome.c \ src/welcome.c \
src/login.c \ src/login.c \
src/menu.c \ src/menu.c \

View file

@ -28,6 +28,7 @@
#include "comport.h" #include "comport.h"
#include "network.h" #include "network.h"
#include "taglist.h" #include "taglist.h"
#include "file.h"
#include "login.h" #include "login.h"
#include "signup.h" #include "signup.h"
@ -42,6 +43,8 @@ typedef enum LoginStateE {
} LoginStateT; } LoginStateT;
static char *_shaClientDat = NULL;
static WindowT *_winLogin = NULL; static WindowT *_winLogin = NULL;
static TextboxT *_txtUser = NULL; static TextboxT *_txtUser = NULL;
static TextboxT *_txtPass = NULL; static TextboxT *_txtPass = NULL;
@ -58,6 +61,7 @@ static void btnLoginClick(WidgetT *widget);
static void btnSignUpClick(WidgetT *widget); static void btnSignUpClick(WidgetT *widget);
static void btnMsgBoxCancel(MsgBoxButtonT button); static void btnMsgBoxCancel(MsgBoxButtonT button);
static void btnMsgBoxContinue(MsgBoxButtonT button); static void btnMsgBoxContinue(MsgBoxButtonT button);
static void loginFilesReady(void);
static void packetHandler(PacketDecodeDataT *packet); static void packetHandler(PacketDecodeDataT *packet);
static void setButtons(uint8_t enabled); static void setButtons(uint8_t enabled);
static void timLoginProgress(WidgetT *widget); 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. // ***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) { static void packetHandler(PacketDecodeDataT *packet) {
char *packetData; char *packetData;
int32_t success; int32_t success;

View file

@ -45,6 +45,8 @@ static void picLogoffClick(WidgetT *widget);
static void picProfileClick(WidgetT *widget); static void picProfileClick(WidgetT *widget);
static char *_shaGamesDat = NULL;
static PictureT *_picChat = NULL; static PictureT *_picChat = NULL;
static PictureT *_picEmail = NULL; static PictureT *_picEmail = NULL;
static PictureT *_picForums = NULL; static PictureT *_picForums = NULL;
@ -92,6 +94,10 @@ static void menuEnable(uint8_t enable) {
static void menuFilesReady(void) { static void menuFilesReady(void) {
uint16_t x = vbeDisplayWidthGet() - 49; uint16_t x = vbeDisplayWidthGet() - 49;
uint16_t y = vbeDisplayHeightGet() - 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"); _picLogoff = pictureNew(x, y, "menu:48logoff.png");
pictureClickHandlerSet(_picLogoff, picLogoffClick); pictureClickHandlerSet(_picLogoff, picLogoffClick);
@ -125,6 +131,7 @@ static void menuFilesReady(void) {
void menuShow(void) { void menuShow(void) {
char *p;
char *fileList[] = { char *fileList[] = {
"menu:48chat.png", "menu:48chat.png",
"menu:48email.png", "menu:48email.png",
@ -132,8 +139,18 @@ void menuShow(void) {
"menu:48games.png", "menu:48games.png",
"menu:48logoff.png", "menu:48logoff.png",
"menu:48profile.png", "menu:48profile.png",
"generated:games.dat",
NULL 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); fileCacheCheck(menuFilesReady, fileList);
} }

View file

@ -122,17 +122,11 @@ static void btnSettingsClick(WidgetT *widget) {
static void packetHandler(PacketDecodeDataT *packet) { static void packetHandler(PacketDecodeDataT *packet) {
PacketEncodeDataT encoded; PacketEncodeDataT encoded;
char *temp;
// Reset timeout. // Reset timeout.
timerReset(_timProgress); timerReset(_timProgress);
switch (packet->packetType) { 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: case PACKET_TYPE_PROCEED:
// Connected! Show icon. // Connected! Show icon.
widgetVisibleSet(W(_picConnect), 1); widgetVisibleSet(W(_picConnect), 1);
@ -141,17 +135,6 @@ static void packetHandler(PacketDecodeDataT *packet) {
_state = S_WAIT_FOR_ICON; _state = S_WAIT_FOR_ICON;
break; 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: case PACKET_TYPE_VERSION:
packetContentUnpack(packet->data, "i", &__runtimeData.protocolVersion); packetContentUnpack(packet->data, "i", &__runtimeData.protocolVersion);
// Do we need to update? // Do we need to update?

View file

@ -65,10 +65,11 @@ CREATE TABLE `files` (
`sha256` varchar(64) NOT NULL, `sha256` varchar(64) NOT NULL,
`modified` datetime NOT NULL, `modified` datetime NOT NULL,
`description` varchar(255) NOT NULL DEFAULT '', `description` varchar(255) NOT NULL DEFAULT '',
`authenticated` tinyint(1) NOT NULL DEFAULT 1,
`touched` tinyint(1) NOT NULL DEFAULT 0, `touched` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `pathIndex` (`path`) 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 */; /*!40101 SET character_set_client = @saved_cs_client */;
-- --
@ -81,33 +82,33 @@ DROP TABLE IF EXISTS `games`;
CREATE TABLE `games` ( CREATE TABLE `games` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`active` tinyint(1) NOT NULL DEFAULT 0, `active` tinyint(1) NOT NULL DEFAULT 0,
`title` varchar(255) DEFAULT NULL, `title` varchar(255) NOT NULL DEFAULT '',
`developer` varchar(255) DEFAULT NULL, `developer` varchar(255) NOT NULL DEFAULT '',
`publisher` varchar(255) DEFAULT NULL, `publisher` varchar(255) NOT NULL DEFAULT '',
`description` text DEFAULT NULL, `description` text NOT NULL DEFAULT '',
`releaseDate` datetime DEFAULT NULL, `releaseDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`stars` double DEFAULT NULL, `stars` double NOT NULL DEFAULT -1,
`starCount` int(11) DEFAULT NULL, `starCount` int(11) NOT NULL DEFAULT -1,
`rating` varchar(255) DEFAULT NULL, `rating` varchar(255) NOT NULL DEFAULT 'Not Rated.',
`series` varchar(255) DEFAULT NULL, `series` varchar(255) NOT NULL DEFAULT '',
`origin` varchar(255) DEFAULT NULL, `origin` varchar(255) NOT NULL DEFAULT '',
`region` varchar(255) DEFAULT NULL, `region` varchar(255) NOT NULL DEFAULT '',
`shortName` varchar(8) DEFAULT NULL, `shortName` varchar(8) NOT NULL,
`type` varchar(8) DEFAULT NULL, `type` varchar(8) NOT NULL,
`maxPlayers` int(11) DEFAULT 2, `maxPlayers` int(11) NOT NULL DEFAULT 2,
`joinable` tinyint(1) DEFAULT 0, `joinable` tinyint(1) NOT NULL DEFAULT 0,
`mobyGames` varchar(255) DEFAULT NULL, `mobyGames` varchar(255) NOT NULL,
`wiki` varchar(255) DEFAULT NULL, `wiki` varchar(255) NOT NULL,
`manual` varchar(255) DEFAULT NULL, `manual` varchar(255) NOT NULL,
`root` varchar(255) DEFAULT NULL, `root` varchar(255) NOT NULL,
`worksWith` varchar(255) DEFAULT NULL, `worksWith` varchar(255) NOT NULL,
`configSys` text DEFAULT NULL, `configSys` text NOT NULL,
`autoexecBat` text DEFAULT NULL, `autoexecBat` text NOT NULL,
`options` text DEFAULT NULL, `options` text NOT NULL,
`mods` text DEFAULT NULL, `mods` text NOT NULL,
`notes` text DEFAULT NULL, `notes` text NOT NULL,
`added` datetime DEFAULT NULL, `added` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` datetime DEFAULT NULL, `modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`touched` tinyint(1) NOT NULL DEFAULT 0, `touched` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `active_index` (`active`) KEY `active_index` (`active`)
@ -145,4 +146,4 @@ CREATE TABLE `users` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!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/packets.h \
$$SHARED/thirdparty/tiny-AES-c/aes.h \ $$SHARED/thirdparty/tiny-AES-c/aes.h \
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.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.h \
src/client/file.h \ src/client/file.h \
src/client/login.h \ src/client/login.h \
@ -78,7 +78,7 @@ SOURCES = \
$$SHARED/packet.c \ $$SHARED/packet.c \
$$SHARED/thirdparty/tiny-AES-c/aes.c \ $$SHARED/thirdparty/tiny-AES-c/aes.c \
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.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.c \
src/client/file.c \ src/client/file.c \
src/client/login.c \ src/client/login.c \

View file

@ -24,46 +24,49 @@
#include "file.h" #include "file.h"
static void clientApiFileFailed(ClientThreadT *client, PacketDecodeDataT *data);
static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *data); static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *data);
static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *data); static void clientApiFileRequestNext(ClientThreadT *client, PacketDecodeDataT *data);
void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) { static void clientApiFileFailed(ClientThreadT *client, PacketDecodeDataT *data) {
FileRequestsT request = 0;
PacketEncodeDataT encoded = { 0 }; PacketEncodeDataT encoded = { 0 };
uint8_t *packetData = NULL; uint8_t *packetData = NULL;
uint16_t length = 0; uint16_t length = 0;
// Must be logged in to do file operations. packetData = packetContentPack(&length, "i", FILE_RESPONSE_UNKNOWN);
if (client->authenticated) { // Build packet.
// Extract the request type. We get more data later. encoded.control = PACKET_CONTROL_DAT;
packetContentUnpack(data->data, "i", &request); 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: void clientApiFileRequest(ClientThreadT *client, PacketDecodeDataT *data) {
clientApiFileRequestNext(client, data); FileRequestsT request = 0;
break;
default: // Extract the request type. We get more data later.
// No idea what they want. 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);
break;
}
} // 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 buffer[1024] = { 0 };
char buffer2[2064] = { 0 }; char buffer2[2064] = { 0 };
uint32_t temp = 0; uint32_t temp = 0;
DbFileInfoT *info = NULL;
uint8_t mustAuth = 1;
// Is something still open? // Is something still open?
if (client->handle) { if (client->handle) {
@ -88,8 +93,19 @@ static void clientApiFileRequestCheck(ClientThreadT *client, PacketDecodeDataT *
// Extract the request. // Extract the request.
packetContentUnpack(data->data, "iss", &request, &sha256, &path); 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. // Look up the entry and compare SHA256.
dbFileSha256Get(path, shaInDB, 128);
if (strcasecmp(sha256, shaInDB) == 0) { if (strcasecmp(sha256, shaInDB) == 0) {
// File is already current on client. // File is already current on client.
temp = FILE_RESPONSE_OKAY; temp = FILE_RESPONSE_OKAY;

View file

@ -125,9 +125,9 @@ void consoleRun(void) {
} }
// Help. // Help.
if (!strcasecmp(command, "HELP") || !strcasecmp(command, "?")) { if (!strcasecmp(command, "HELP") || !strcasecmp(command, "?")) {
sendToConsole("HELP or ? - This message.\n"); sendToConsole("HELP or ? - This message.\n");
sendToConsole("SHUTDOWN - Stop the server.\n"); sendToConsole("SHUTDOWN - Stop the server.\n");
sendToConsole("UPDATE [what] - Update client data.\n"); sendToConsole("UPDATE - Update client data.\n");
commandOk = 1; commandOk = 1;
} }
// Shutdown. // Shutdown.
@ -137,7 +137,7 @@ void consoleRun(void) {
} }
// Update. // Update.
if (!strcasecmp(command, "UPDATE")) { if (!strcasecmp(command, "UPDATE")) {
update(p); update();
commandOk = 1; commandOk = 1;
} }
// Did we grok it? // Did we grok it?

View file

@ -22,7 +22,7 @@
#include <pthread.h> #include <pthread.h>
#include <crypt.h> #include <crypt.h>
#include "thirdparty/sha256.c/sha256.h" #include "thirdparty/SHA256/sha256.h"
#include "array.h" #include "array.h"
#include "console.h" #include "console.h"
@ -37,24 +37,12 @@
#define STATEMENT_MAX 2048 #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 MYSQL *_sql = NULL;
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
static DbFileInfoT *dbFileInfoGet(char *vpath); static void dbFileInfoSet(DbFileInfoT *info);
static void dbFileInfoRelease(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) { 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) { uint8_t dbDisconnect(void) {
if (_sql) { if (_sql) {
mysql_close(_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 statement[STATEMENT_MAX];
char *p = statement; char *p = statement;
MYSQL_RES *result = NULL; MYSQL_RES *result = NULL;
@ -110,7 +161,7 @@ static DbFileInfoT *dbFileInfoGet(char *vpath) {
count++; 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 += mysql_real_escape_string(_sql, p, vpath, strlen(vpath));
p += sprintf(p, "'"); p += sprintf(p, "'");
if (mysql_real_query(_sql, statement, p - statement) != 0) { if (mysql_real_query(_sql, statement, p - statement) != 0) {
@ -139,12 +190,13 @@ static DbFileInfoT *dbFileInfoGet(char *vpath) {
pthread_mutex_unlock(&_mutex); pthread_mutex_unlock(&_mutex);
return NULL; return NULL;
} }
info->id = atol(row[0]); info->id = atol(row[0]);
info->path = strdup(row[1]); info->path = strdup(row[1]);
info->length = atol(row[2]); info->length = atol(row[2]);
info->sha = strdup(row[3]); info->sha = strdup(row[3]);
info->modified = strdup(row[4]); info->modified = strdup(row[4]);
info->touched = atoi(row[5]); info->authenticated = atoi(row[5]);
info->touched = atoi(row[6]);
mysql_free_result(result); 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; DbFileInfoT *i = *info;
if (i) { if (i) {
@ -206,11 +258,11 @@ static void dbFileInfoSet(DbFileInfoT *info) {
static void dbFileSha256Create(char *file, char *buf) { static void dbFileSha256Create(char *file, char *buf) {
FILE *f = NULL; FILE *f = NULL;
char buffer[1024] = { 0 }; char buffer[1024] = { 0 };
char hex[3] = { 0 }; char hex[3] = { 0 };
size_t bytes = 0; size_t bytes = 0;
sha256_t hash = { 0 }; sha256_context hash = { 0 };
// buf has to be at least 65 bytes. // buf has to be at least 65 bytes.
buf[0] = 0; buf[0] = 0;
@ -220,29 +272,106 @@ static void dbFileSha256Create(char *file, char *buf) {
sha256_init(&hash); sha256_init(&hash);
while (bytes = fread(buffer, 1, sizeof(buffer), f), bytes > 0) { 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); fclose(f);
sha256_final(&hash, (unsigned char *)buffer); sha256_done(&hash, (uint8_t *)buffer);
for (bytes = 0; bytes < 32; bytes++) { for (bytes = 0; bytes < 32; bytes++) {
sprintf(hex, "%0x", (unsigned char)buffer[bytes]); sprintf(hex, "%0x", (uint8_t)buffer[bytes]);
strcat(buf, hex); strcat(buf, hex);
} }
buf[64] = 0; buf[64] = 0;
} }
uint8_t dbFileSha256Get(char *vpath, char *value, uint32_t max) { void dbGameRelease(DbGameT **game) {
DbFileInfoT *info = dbFileInfoGet(vpath); DbGameT *g = *game;
if (info) { if (g) {
strncpy(value, info->sha, max); DEL(g->title);
dbFileInfoRelease(&info); DEL(g->publisher);
return SUCCESS; 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) { uint8_t dbUpdateFileData(char *file, uint64_t len, char *time) {
DbFileInfoT *info = NULL; DbFileInfoT *info = NULL;
char prefix[1064] = { 0 }; char prefix[1064] = { 0 };

View file

@ -28,25 +28,63 @@
#define DB_CONFIG_ITEM_SIZE 1024 #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 *name;
char *data; 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 dbConnect(char *host, uint16_t port, char *database, char *user, char *password);
uint8_t dbDisconnect(void); void dbClientConfigRelease(DbClientConfigT **config);
uint8_t dbFileSha256Get(char *vpath, char *value, uint32_t max); DbClientConfigT **dbClientConfigGet(void);
uint8_t dbSettingsStringGet(char *host, char *key, char *value, uint32_t max); uint8_t dbDisconnect(void);
uint8_t dbSettingsValueGet(char *host, char *key, int32_t *value); DbFileInfoT *dbFileInfoGet(char *vpath);
uint8_t dbTableGet(char *which, DBTableT ***table); void dbFileInfoRelease(DbFileInfoT **info);
uint8_t dbUpdateFileData(char *file, uint64_t len, char *time); void dbGameRelease(DbGameT **game);
uint8_t dbUpdateFilesFinish(void); DbGameT **dbGamesGet(void);
uint8_t dbUpdateFilesStart(void); uint8_t dbSettingsStringGet(char *host, char *key, char *value, uint32_t max);
uint8_t dbUserCreate(char *first, char *last, char *user, char *pass, char *email); uint8_t dbSettingsValueGet(char *host, char *key, int32_t *value);
uint8_t dbUserEmailExists(char *email); uint8_t dbUpdateFileData(char *file, uint64_t len, char *time);
uint8_t dbUserLogin(char *user, char *password); uint8_t dbUpdateFilesFinish(void);
uint8_t dbUserNameExists(char *user); 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 #endif // DATABASE_H

View file

@ -31,87 +31,50 @@
#include "update.h" #include "update.h"
typedef void *(*UpdateThreadT)(void *);
static pthread_t _updateThreadHandle = { 0 }; static pthread_t _updateThreadHandle = { 0 };
static uint8_t _updateThreadRunning = 0; static uint8_t _updateThreadRunning = 0;
static uint8_t _updateAllRunning = 0;
static void *updateAll(void *data); static void *updateAll(void *path);
static void *updateConfig(void *data); static void updateConfig(void);
static void *updateFiles(void *path); static void updateFiles(void *path);
static int32_t updateFileEntry(const char *filepath, const struct stat *info, const int typeflag, struct FTW *pathinfo); 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) { void update(void) {
char *p = NULL;
pthread_attr_t updateThreadAttributes = { 0 }; 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) { if (_updateThreadRunning) {
consoleMessageQueue("An update is already running. Wait until it completes.\n\r"); consoleMessageQueue("An update is already running. Wait until it completes.\n\r");
return; 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. // Start update thread.
_updateThreadRunning = 1; _updateThreadRunning = 1;
if (pthread_attr_init(&updateThreadAttributes) != 0) utilDie("Unable to create update thread attributes.\n"); if (pthread_attr_init(&updateThreadAttributes) != 0) utilDie("Unable to create update thread attributes.\n");
pthread_attr_setdetachstate(&updateThreadAttributes, PTHREAD_CREATE_JOINABLE); 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) { static void *updateAll(void *data) {
(void)data; (void)data;
updateConfig(NULL); updateConfig();
updateGames();
updateFiles("/"); updateFiles("/");
updateGames(NULL);
pthread_exit(NULL); pthread_exit(NULL);
} }
static void *updateConfig(void *data) { static void updateConfig(void) {
DBTableT *record = NULL; DbClientConfigT *record = NULL;
DBTableT **table = NULL; char file[MAX_PATH] = { 0 };
char file[MAX_PATH] = { 0 }; FILE *f = NULL;
FILE *f = NULL; DbClientConfigT **config = NULL;
(void)data;
consoleMessageQueue("Updating client configuration data.\n"); consoleMessageQueue("Updating client configuration data.\n");
@ -119,28 +82,24 @@ static void *updateConfig(void *data) {
f = fopen(file, "wb"); f = fopen(file, "wb");
if (f) { if (f) {
// Fetch string table from DB. // Fetch string table from DB.
if (dbTableGet("client", &table) == SUCCESS) { config = dbClientConfigGet();
while (arrlen(table)) { if (config) {
record = table[0]; while (arrlen(config)) {
arrdel(table, 0); record = config[0];
arrdel(config, 0);
// Write to config file that is sent to the client. // Write to config file that is sent to the client.
fwrite(record->name, strlen(record->name) + 1, 1, f); fwrite(record->name, strlen(record->name) + 1, 1, f);
fwrite(record->data, strlen(record->data) + 1, 1, f); fwrite(record->data, strlen(record->data) + 1, 1, f);
DEL(record->name); dbClientConfigRelease(&record);
DEL(record->data);
DEL(record);
} }
arrfree(table); arrfree(config);
} }
fclose(f); 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 file[MAX_PATH] = { 0 };
char *path = (char *)data; char *path = (char *)data;
int32_t result = 0; int32_t result = 0;
@ -161,9 +120,6 @@ static void *updateFiles(void *data) {
result = nftw(file, updateFileEntry, 15, FTW_PHYS); result = nftw(file, updateFileEntry, 15, FTW_PHYS);
dbUpdateFilesFinish(); 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) { static void updateGames(void) {
(void)data; DbGameT **gameList = NULL;
DbGameT *game = NULL;
char file[MAX_PATH] = { 0 };
FILE *f = NULL;
uint8_t c = 0;
consoleMessageQueue("Updating client game database.\n"); consoleMessageQueue("Updating client game database.\n");
if (!_updateAllRunning) pthread_exit(NULL); snprintf(file, MAX_PATH, "%s/files/generated/games.dat", __settingsFile);
return NULL; 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 #define UPDATE_H
void update(char *params); void update(void);
#endif // UPDATE_H #endif // UPDATE_H

View file

@ -49,12 +49,10 @@ typedef enum PacketTypeE {
// Packets received by only the client: // Packets received by only the client:
PACKET_TYPE_FILE_RESPONSE, PACKET_TYPE_FILE_RESPONSE,
PACKET_TYPE_LOGIN_RESULT, PACKET_TYPE_LOGIN_RESULT,
PACKET_TYPE_NUMBER,
PACKET_TYPE_PING, PACKET_TYPE_PING,
PACKET_TYPE_PROCEED, PACKET_TYPE_PROCEED,
PACKET_TYPE_SERVER_SHUTDOWN, PACKET_TYPE_SERVER_SHUTDOWN,
PACKET_TYPE_SIGNUP_RESULT, PACKET_TYPE_SIGNUP_RESULT,
PACKET_TYPE_STRING,
// How many packet types do we recognize? // How many packet types do we recognize?
PACKET_TYPE_COUNT PACKET_TYPE_COUNT