From de52b32027749f511706b9587641c5794a07f440 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 2 Mar 2026 10:29:19 -0600 Subject: [PATCH] Fix dirtsand starting with dead auth daemon. Currently, if DirtSand starts and the auth daemon cannot connect to PostgreSQL, the auth daemon thread exits immediately but the server remains up. This leads to a situation where clients can patch but when they attempt to actually log in, they never get a response because the auth daemon never actually started. There are basically two ways to fix this. One way is to kill the whole process if the database isn't up. This would be workable, but the design of the system doesn't really support the individual daemons communicating back to the DirtSand process itself, except via hacks like `exit(1)`. Instead, I've opted to allow the auth daemon to try deferring initializaion. This allows us to centralize the database connection reset logic and remove all of the manual `check_postgres()` calls. --- AuthServ/AuthDaemon.cpp | 53 ++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/AuthServ/AuthDaemon.cpp b/AuthServ/AuthDaemon.cpp index e4204fd..c46ac69 100755 --- a/AuthServ/AuthDaemon.cpp +++ b/AuthServ/AuthDaemon.cpp @@ -25,6 +25,7 @@ #include #include #include +#include std::thread s_authDaemonThread; DS::MsgChannel s_authChannel; @@ -37,8 +38,6 @@ std::unordered_map s_globalStat void dm_auth_addacct(Auth_AddAcct* msg) { - check_postgres(s_postgres); - DS::PGresultRef result = DS::PQexecVA(s_postgres, "SELECT idx, \"AcctUuid\" FROM auth.\"Accounts\"" " WHERE LOWER(\"Login\")=LOWER($1)", @@ -103,8 +102,6 @@ void dm_auth_shutdown() void dm_auth_login(Auth_LoginInfo* info) { - check_postgres(s_postgres); - DEBUG_printf("[Auth] Login U:{} P:{} T:{} O:{}\n", info->m_acctName, info->m_passHash.toString(), info->m_token, info->m_os); @@ -270,7 +267,6 @@ void dm_auth_disconnect(Auth_ClientMessage* msg) AuthServer_Private* client = reinterpret_cast(msg->m_client); if (client->m_player.m_playerId) { // Mark player as offline - check_postgres(s_postgres); DS::PGresultRef result = DS::PQexecVA(s_postgres, "UPDATE vault.\"Nodes\" SET" " \"Int32_1\"=0, \"String64_1\"=''," @@ -293,8 +289,6 @@ void dm_auth_disconnect(Auth_ClientMessage* msg) void dm_auth_setPlayer(Auth_ClientMessage* msg) { - check_postgres(s_postgres); - AuthServer_Private* client = reinterpret_cast(msg->m_client); DS::PGresultRef result = DS::PQexecVA(s_postgres, "SELECT \"PlayerName\", \"AvatarShape\", \"Explorer\"" @@ -903,8 +897,6 @@ void dm_auth_acctFlags(Auth_AccountFlags* msg) void dm_auth_addAllPlayers(Auth_AddAllPlayers* msg) { - check_postgres(s_postgres); - if (v_has_node(msg->m_playerId, s_allPlayers)) { if (!v_unref_node(msg->m_playerId, s_allPlayers)) { SEND_REPLY(msg, DS::e_NetInternalError); @@ -1004,20 +996,8 @@ void dm_auth_update_globalSDL(Auth_UpdateGlobalSDL* msg) SEND_REPLY(msg, DS::e_NetInvalidParameter); } -void dm_authDaemon() +void dm_authInit() { - s_postgres = PQconnectdb(ST::format( - "host='{}' port='{}' user='{}' password='{}' dbname='{}'", - DS::Settings::DbHostname(), DS::Settings::DbPort(), - DS::Settings::DbUsername(), DS::Settings::DbPassword(), - DS::Settings::DbDbaseName()).c_str()); - if (PQstatus(s_postgres) != CONNECTION_OK) { - ST::printf(stderr, "Error connecting to postgres: {}", PQerrorMessage(s_postgres)); - PQfinish(s_postgres); - s_postgres = nullptr; - return; - } - if (!dm_vault_init()) { fputs("[Auth] Vault failed to initialize\n", stderr); return; @@ -1045,11 +1025,40 @@ void dm_authDaemon() PQ_PRINT_ERROR(s_postgres, UPDATE); // This doesn't block continuing... } +} + +void dm_authCheck(bool reconnect) +{ + if (reconnect) + check_postgres(s_postgres); + if (PQstatus(s_postgres) != CONNECTION_OK) + return; + + static std::once_flag s_authInit; + std::call_once(s_authInit, dm_authInit); +} + +void dm_authDaemon() +{ + s_postgres = PQconnectdb(ST::format( + "host='{}' port='{}' user='{}' password='{}' dbname='{}'", + DS::Settings::DbHostname(), DS::Settings::DbPort(), + DS::Settings::DbUsername(), DS::Settings::DbPassword(), + DS::Settings::DbDbaseName()).c_str()); + if (PQstatus(s_postgres) != CONNECTION_OK) + ST::printf(stderr, "Error connecting to postgres: {}", PQerrorMessage(s_postgres)); + + // If the connection to postgres was successful, initialize the vault here. + dm_authCheck(false); for ( ;; ) { DS::FifoMessage msg { -1, nullptr }; try { msg = s_authChannel.getMessage(); + + // We have a message from a client. Make sure the vault is ready. + dm_authCheck(true); + switch (msg.m_messageType) { case e_AuthShutdown: dm_auth_shutdown();