diff --git a/.gitignore b/.gitignore index 3617c3f..a8aebb8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ connectionStrings.config .kdev4/ .idea/ cmake-build-*/ -*.db-journal \ No newline at end of file +*.db-journal +scape.db \ No newline at end of file diff --git a/resources/server/config.ini b/resources/server/config.ini index 35d4c35..91d88cb 100644 --- a/resources/server/config.ini +++ b/resources/server/config.ini @@ -1,7 +1,7 @@ [General] Run Master = true Master Host = localhost -Master Port = 5050 +Master Port = 5051 [Defaults] ; amount of threads to start with (never close) @@ -22,19 +22,19 @@ Max Total = -1 Tolerance = -1 [Master to Client] -Port = 5050 +Port = 5051 [Master to Slave] -Port = 8008 +Port = 8018 [Slave] -Port = 9000 +Port = 9010 Name = Test Server 1 [Slave] -Port = 9001 +Port = 9011 Name = Test Server 2 [Slave] -Port = 9002 +Port = 9012 Name = Test Server 3 \ No newline at end of file diff --git a/src/server/db/_init_sql.hpp b/src/server/db/_init_sql.hpp index 9902a82..b9bcff4 100644 --- a/src/server/db/_init_sql.hpp +++ b/src/server/db/_init_sql.hpp @@ -3,7 +3,7 @@ #include -const char* _mem_db_sql = +const std::vector _mem_db_sql = { "CREATE TABLE `SERVER_LIST` (" "`ID` INTEGER PRIMARY KEY AUTOINCREMENT," "`NAME` TEXT NOT NULL," @@ -12,50 +12,52 @@ const char* _mem_db_sql = "`PORT` INTEGER NOT NULL," "`USERS` INTEGER NOT NULL DEFAULT 0," "`MAX_USERS` INTEGER NOT NULL DEFAULT 0" - ");\n" + ");", "CREATE TABLE `USER_KEYS` (" "`ID` INTEGER," "`SECRET` BLOB NOT NULL UNIQUE," "PRIMARY KEY(`ID`)" - ");\n"; + ");", +}; -const char* _hard_db_init_migration_sql = +const std::vector _hard_db_init_migration_sql = { "CREATE TABLE `MIGRATIONS` (" "`ID` INTEGER NOT NULL," "`SQL_HASH` TEXT NOT NULL," "`DATE_RAN` INTEGER NOT NULL," "PRIMARY KEY(`ID`)" - ") WITHOUT ROWID;\n"; + ") WITHOUT ROWID;", +}; -const std::vector _hard_db_sql = { - /** START MIGRATION 0 **/ - "CREATE TABLE `SERVER_LICENSES` (" - "`KEY_ID` TEXT NOT NULL PRIMARY KEY AUTOINCREMENT," - "`SECRET` BLOB NOT NULL," - "`ALLOWANCE` INTEGER NOT NULL DEFAULT 0" - ");\n" +const std::vector> _hard_db_sql = { + { /** START MIGRATION 0 **/ + "CREATE TABLE `SERVER_LICENSES` (" + "`KEY_ID` INTEGER PRIMARY KEY AUTOINCREMENT," + "`SECRET` BLOB NOT NULL," + "`ALLOWANCE` INTEGER NOT NULL DEFAULT 0" + ");", - "CREATE UNIQUE INDEX `UIX_SERVER_LICENSES` ON `SERVER_LICENSES` (" - "`KEY_ID`, `SECRET`" - ");\n" + "CREATE UNIQUE INDEX `UIX_SERVER_LICENSES` ON `SERVER_LICENSES` (" + "`KEY_ID`, `SECRET`" + ");", - "CREATE TABLE `USERS` (" - "`ID` INTEGER PRIMARY KEY AUTOINCREMENT," - "`USERNAME` TEXT NOT NULL," - "`PASS_HASH` TEXT NOT NULL," - "`EMAIL` TEXT NOT NULL," - "`ACTIVATED` INTEGER NOT NULL DEFAULT 0," - "`JOINED` INTEGER NOT NULL" - ");\n" + "CREATE TABLE `USERS` (" + "`ID` INTEGER PRIMARY KEY AUTOINCREMENT," + "`USERNAME` TEXT NOT NULL," + "`PASS_HASH` TEXT NOT NULL," + "`EMAIL` TEXT NOT NULL," + "`ACTIVATED` INTEGER NOT NULL DEFAULT 0," + "`JOINED` INTEGER NOT NULL" + ");", - "CREATE TABLE `ACTIVATION_CODES` (" - "`USER_ID` INTEGER NOT NULL UNIQUE," - "`CODE` TEXT NOT NULL," - "`CREATED` INTEGER NOT NULL," - "PRIMARY KEY(`USER_ID`)" - ") WITHOUT ROWID;\n", - /** END MIGRATION 0 **/ + "CREATE TABLE `ACTIVATION_CODES` (" + "`USER_ID` INTEGER NOT NULL UNIQUE," + "`CODE` TEXT NOT NULL," + "`CREATED` INTEGER NOT NULL," + "PRIMARY KEY(`USER_ID`)" + ") WITHOUT ROWID;", + }, /** END MIGRATION 0 **/ }; #endif \ No newline at end of file diff --git a/src/server/db/database.cpp b/src/server/db/database.cpp index 37237a6..3b5f19b 100644 --- a/src/server/db/database.cpp +++ b/src/server/db/database.cpp @@ -14,7 +14,8 @@ bool sosc::db::init_databases(std::string* error) { _ctx.ready = true; sqlite3_open(":memory:", &_ctx.mem_db); - sqlite3_exec(_ctx.mem_db, _mem_db_sql, nullptr, nullptr, nullptr); + for(const auto& query : _mem_db_sql) + sqlite3_exec(_ctx.mem_db, query, nullptr, nullptr, nullptr); sqlite3_open(SOSC_RESC("scape.db").c_str(), &_ctx.hard_db); @@ -22,7 +23,8 @@ bool sosc::db::init_databases(std::string* error) { "SELECT COUNT(*) FROM SQLITE_MASTER WHERE TBL_NAME = 'MIGRATIONS'" ); if(migrationsExist == 0) - db::Query::NonQuery(_hard_db_init_migration_sql); + for(const auto& query : _hard_db_init_migration_sql) + db::Query::NonQuery(query); int32_t lastMig = db::Query::ScalarInt32("SELECT MAX(ID) FROM MIGRATIONS"); if(lastMig > _hard_db_sql.size()) { @@ -39,9 +41,11 @@ bool sosc::db::init_databases(std::string* error) { ); Query getMigration("SELECT SQL_HASH FROM MIGRATIONS WHERE ID = ?"); for(id = 0; id < _hard_db_sql.size(); ++id) { - getMigration.BindInt32(id, 0); - + getMigration.Reset(); + getMigration.BindInt32(id, 1); std::string hash = getMigration.ScalarText(); + std::string local_hash = ""; + if(hash.empty()) { if(id < lastMig) { if(error != nullptr) @@ -50,13 +54,20 @@ bool sosc::db::init_databases(std::string* error) { return false; } - Query::NonQuery(_hard_db_sql[id]); + for(const auto& query : _hard_db_sql[id]) { + Query::NonQuery(query); + local_hash += cgc::sha1(query); + } - insertMigration.BindInt32(id, 0); - insertMigration.BindText(cgc::sha1(_hard_db_sql[id]), 1); + insertMigration.Reset(); + insertMigration.BindInt32(id, 1); + insertMigration.BindText(cgc::sha1(local_hash), 2); insertMigration.NonQuery(); } else { - if(hash != cgc::sha1(_hard_db_sql[id])) { + for(const auto& query : _hard_db_sql[id]) + local_hash += cgc::sha1(query); + + if(hash != cgc::sha1(local_hash)) { if(error != nullptr) *error = "HARD DB: MIGRATION SQL HASH MISMATCH"; _ctx.ready = false; @@ -338,7 +349,7 @@ bool sosc::db::ResultSet::Step() { else if(result == SQLITE_DONE) return false; else - throw std::string(sqlite3_errmsg(this->query->database)); + throw std::runtime_error(sqlite3_errmsg(this->query->database)); } double sosc::db::ResultSet::GetDouble(int column) { diff --git a/src/server/hosts/master_client.cpp b/src/server/hosts/master_client.cpp index 3371015..6b4dfc3 100644 --- a/src/server/hosts/master_client.cpp +++ b/src/server/hosts/master_client.cpp @@ -42,19 +42,19 @@ void sosc::MasterClientPool::SetupQueries(db::Queries *queries) { queries->push_back(new db::Query( "INSERT OR IGNORE INTO `USER_KEYS` " "(`ID`, `SECRET`) VALUES (?, RANDOMBLOB(128))" - )); + , DB_USE_MEMORY)); #define QRY_USER_GET_KEY 6 queries->push_back(new db::Query( "SELECT `SECRET` FROM `USER_KEYS` " "WHERE `ID` = ?" - )); + , DB_USE_MEMORY)); #define QRY_USER_CHECK_KEY 7 queries->push_back(new db::Query( "SELECT COUNT(*) FROM `USER_KEYS` " "WHERE `ID` = ? AND `SECRET` = ?" - )); + , DB_USE_MEMORY)); } /** MASTERCLIENT CODE **/ @@ -99,13 +99,13 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) { db::ResultSet* results = nullptr; db::Query* query = this->queries->at(QRY_USER_NAME_EXISTS); query->Reset(); - query->BindText(pck[0], 0); + query->BindText(pck[0], 1); if(query->ScalarInt32() == 0) return LoginError(0x101); query = this->queries->at(QRY_USER_GET_PWD_HASH); query->Reset(); - query->BindText(pck[0], 0); + query->BindText(pck[0], 1); results = query->GetResults(); results->Step(); @@ -115,12 +115,12 @@ bool sosc::MasterClient::ProcessLogin(Packet &pck) { query = this->queries->at(QRY_USER_GENERATE_KEY); query->Reset(); - query->BindInt64(user_id, 0); + query->BindInt64(user_id, 1); query->NonQuery(); query = this->queries->at(QRY_USER_GET_KEY); query->Reset(); - query->BindInt64(user_id, 0); + query->BindInt64(user_id, 1); auto secret = query->ScalarBlob(); this->sock.Send(Packet(kLoginResponse, {"\1", secret})); @@ -148,21 +148,21 @@ bool sosc::MasterClient::ProcessRegistration(Packet &pck) { db::Query* query = this->queries->at(QRY_USER_NAME_REG_CHECK); query->Reset(); - query->BindText(pck[0], 0); + query->BindText(pck[0], 1); if(query->ScalarInt32() > 0) return RegistrationError(0x100); query = this->queries->at(QRY_USER_MAIL_REG_CHECK); query->Reset(); - query->BindText(pck[2], 0); + query->BindText(pck[2], 1); if(query->ScalarInt32() > 0) return RegistrationError(0x101); query = this->queries->at(QRY_USER_REGISTER); query->Reset(); - query->BindText(pck[0], 0); - query->BindText(cgc::bcrypt_hash(pck[1]), 1); - query->BindText(pck[2], 2); + query->BindText(pck[0], 1); + query->BindText(cgc::bcrypt_hash(pck[1]), 2); + query->BindText(pck[2], 3); query->NonQuery(); this->sock.Send(Packet(kRegisterResponse, {"\1", 0x000})); diff --git a/src/server/hosts/master_intra.cpp b/src/server/hosts/master_intra.cpp index 59fbcf2..2706714 100644 --- a/src/server/hosts/master_intra.cpp +++ b/src/server/hosts/master_intra.cpp @@ -110,8 +110,8 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) { db::Query* query = this->queries->at(QRY_LICENSE_CHECK); query->Reset(); - query->BindText(pck[2], 0); - query->BindBlob(pck[3], 1); + query->BindText(pck[2], 1); + query->BindBlob(pck[3], 2); if(query->ScalarInt32() == 0) return AuthenticationFailure(packetId, 0x101); @@ -120,11 +120,11 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) { int limit; query = this->queries->at(QRY_LICENSE_LIMIT); query->Reset(); - query->BindText(pck[2], 0); + query->BindText(pck[2], 1); if((limit = query->ScalarInt32()) != 0) { query = this->queries->at(QRY_LICENSE_ACTIVE_COUNT); query->Reset(); - query->BindText(pck[2], 0); + query->BindText(pck[2], 1); if(query->ScalarInt32() < limit) { _ctx.license_check_mtx.unlock(); return AuthenticationFailure(packetId, 0x102); @@ -133,10 +133,10 @@ bool sosc::MasterIntra::Authentication(sosc::Packet& pck) { query = this->queries->at(QRY_SERVER_LIST_ADD); query->Reset(); - query->BindText(pck[0], 0); - query->BindText(pck[2], 1); - query->BindText(this->sock.GetIpAddress(), 2); - query->BindInt32(net::ntohv(pck[1]), 3); + query->BindText(pck[0], 1); + query->BindText(pck[2], 2); + query->BindText(this->sock.GetIpAddress(), 3); + query->BindInt32(net::ntohv(pck[1]), 4); query->NonQuery(); query = this->queries->at(QRY_SERVER_LIST_GET_ID); @@ -179,7 +179,7 @@ bool sosc::MasterIntra::StatusUpdate(sosc::Packet &pck) { db::Query* query = this->queries->at(QRY_LICENSE_VERIFY); query->Reset(); - query->BindText(this->license, 0); + query->BindText(this->license, 1); if(query->ScalarInt32() == 0) return this->NotAuthorized(packetId); @@ -188,8 +188,8 @@ bool sosc::MasterIntra::StatusUpdate(sosc::Packet &pck) { query = this->queries->at(QRY_SERVER_LIST_MODIFY); query->Reset(); - query->BindInt32(net::ntohv(pck[0]), 0); - query->BindInt32(net::ntohv(pck[1]), 1); + query->BindInt32(net::ntohv(pck[0]), 1); + query->BindInt32(net::ntohv(pck[1]), 2); query->BindInt32(this->server_id, 2); query->NonQuery(); return true; diff --git a/src/server/main.cpp b/src/server/main.cpp index 7d2535a..e564e29 100644 --- a/src/server/main.cpp +++ b/src/server/main.cpp @@ -96,7 +96,7 @@ int main(int argc, char **argv) { }) }); } catch(const std::exception& e) { - std::cout << e.what() << std::endl; + std::cerr << e.what() << std::endl; return -1; } @@ -107,27 +107,33 @@ int main(int argc, char **argv) { if(!config->HasSection("master to client") || !config->HasSection("master to slave")) { - std::cout << "'MASTER TO CLIENT' and 'MASTER TO SLAVE' sections " + std::cerr << "'MASTER TO CLIENT' and 'MASTER TO SLAVE' sections " << "must exist if 'RUN MASTER' is true." << std::endl; return -1; } if(!db::init_databases(nullptr)) { - std::cout << "Could not initialized master database."; + std::cerr << "Could not initialized master database."; return -1; } configure_poolinfo(&info, (*config)["master to slave"][0]); _ctx.master_intra = new master_intra_ctx; - master_intra_start( - (uint16_t)(*config)["master to slave"]["port"], info - ); + if(!master_intra_start( + (uint16_t)(*config)["master to slave"]["port"], info)) + { + std::cerr << "Could not start master-slave server." << std::endl; + return -1; + } configure_poolinfo(&info, (*config)["master to client"][0]); _ctx.master_client = new master_client_ctx; - master_client_start( - (uint16_t)(*config)["master to client"]["port"], info - ); + if(!master_client_start( + (uint16_t)(*config)["master to client"]["port"], info)) + { + std::cerr << "Could not start master-client server." << std::endl; + return -1; + } } if(config->HasSection("slave")) { @@ -136,10 +142,13 @@ int main(int argc, char **argv) { for(int i = 0; i < _ctx.slave_count; ++i) { configure_poolinfo(&info, (*config)["slave"][i]); - slave_start( + if(!slave_start( (uint16_t)(*config)["slave"][i]["port"], - info, _ctx.slaves + i - ); + info, _ctx.slaves + i)) + { + std::cerr << "Could not start slave server." << std::endl; + return -1; + } } } @@ -158,6 +167,7 @@ int main(int argc, char **argv) { master_intra_stop(); for(int i = 0; i < _ctx.slave_count; ++i) slave_stop(_ctx.slaves + i); + delete[] _ctx.slaves; return 0; } @@ -215,7 +225,8 @@ void master_intra_stop() { return; _ctx.master_intra->server.Close(); - _ctx.master_intra->thread.join(); + if(_ctx.master_intra->thread.joinable()) + _ctx.master_intra->thread.join(); _ctx.master_intra->pool.Stop(); delete _ctx.master_intra; @@ -227,7 +238,8 @@ void master_client_stop() { return; _ctx.master_client->server.Close(); - _ctx.master_client->thread.join(); + if(_ctx.master_client->thread.joinable()) + _ctx.master_client->thread.join(); _ctx.master_client->pool.Stop(); delete _ctx.master_client; @@ -239,8 +251,7 @@ void slave_stop(slave_ctx* ctx) { return; ctx->server.Close(); - ctx->thread.join(); + if(ctx->thread.joinable()) + ctx->thread.join(); ctx->pool.Stop(); - - delete ctx; } \ No newline at end of file diff --git a/src/web/script.js b/src/web/script.js index 74a3a7f..12d8abf 100644 --- a/src/web/script.js +++ b/src/web/script.js @@ -185,7 +185,7 @@ function parse(data) { } function conn_open() { - ws = new WebSocket("wss://localhost:8008"); + ws = new WebSocket("wss://localhost:5050"); ws.binaryType = "arraybuffer"; ws.onopen = function (e) {