diff --git a/src/engine/server.h b/src/engine/server.h index e2909065c..daaf95369 100644 --- a/src/engine/server.h +++ b/src/engine/server.h @@ -165,6 +165,11 @@ public: virtual void GetClientAddr(int ClientID, NETADDR *pAddr) = 0; virtual int* GetIdMap(int ClientID) = 0; + +#if defined (CONF_SQL) + virtual class CSqlServer *SqlServer() = 0; + virtual class CSqlServer **SqlMasterServers() = 0; +#endif }; class IGameServer : public IInterface diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index ae5647ab0..e7dd9dd29 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -302,6 +302,10 @@ CServer::CServer() m_pGameServer = 0; +#if defined (CONF_SQL) + m_pSqlServer = 0; +#endif + m_CurrentGameTick = 0; m_RunServer = 1; @@ -321,6 +325,11 @@ CServer::CServer() m_ServerInfoNumRequests = 0; m_ServerInfoHighLoad = false; +#if defined (CONF_SQL) + for (int i = 0; i < MAX_SQLMASTERS; i++) + m_apMasterSqlServers[i] = 0; +#endif + Init(); } @@ -1650,6 +1659,14 @@ int CServer::Run() str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); +#if defined (CONF_SQL) + m_pSqlServer = new CSqlServer(g_Config.m_SvSqlDatabase, g_Config.m_SvSqlPrefix, g_Config.m_SvSqlUser, g_Config.m_SvSqlPw, g_Config.m_SvSqlIp, g_Config.m_SvSqlPort); + + // create tables + if(g_Config.m_SvSqlCreateTables) + m_pSqlServer->CreateTables(); +#endif + GameServer()->OnInit(); str_format(aBuf, sizeof(aBuf), "version %s", GameServer()->NetVersion()); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); @@ -1815,6 +1832,16 @@ int CServer::Run() if(m_pCurrentMapData) mem_free(m_pCurrentMapData); + +#if defined (CONF_SQL) + if (m_pSqlServer) + delete m_pSqlServer; + + for (int i = 0; i < MAX_SQLMASTERS; i++) + if (m_apMasterSqlServers[i]) + delete m_apMasterSqlServers[i]; +#endif + return 0; } @@ -1990,6 +2017,51 @@ void CServer::ConLogout(IConsole::IResult *pResult, void *pUser) } } +#if defined (CONF_SQL) + +void CServer::ConAddSqlMaster(IConsole::IResult *pResult, void *pUserData) +{ + CServer *pSelf = (CServer *)pUserData; + + if (pResult->NumArguments() != 6) + { + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "6 arguments are required"); + return; + } + + for (int i = 0; i < MAX_SQLMASTERS; i++) + { + if (!pSelf->m_apMasterSqlServers[i]) + { + pSelf->m_apMasterSqlServers[i] = new CSqlServer(pResult->GetString(0), pResult->GetString(1), pResult->GetString(2), pResult->GetString(3), pResult->GetString(4), pResult->GetInteger(5)); + + if(g_Config.m_SvSqlMastersCreateTables) + pSelf->m_apMasterSqlServers[i]->CreateTables(); + + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "Added new sqlmasterserver: %d: DB: '%s' Prefix: '%s' User: '%s' Pass: '%s' IP: '%s' Port: %d", i, pSelf->m_apMasterSqlServers[i]->GetDatabase(), pSelf->m_apMasterSqlServers[i]->GetPrefix(), pSelf->m_apMasterSqlServers[i]->GetUser(), pSelf->m_apMasterSqlServers[i]->GetPass(), pSelf->m_apMasterSqlServers[i]->GetIP(), pSelf->m_apMasterSqlServers[i]->GetPort()); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); + return; + } + } + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "failed to add new sqlmaster: limit of sqlmasters reached"); +} + +void CServer::ConDumpSqlMaster(IConsole::IResult *pResult, void *pUserData) +{ + CServer *pSelf = (CServer *)pUserData; + + for (int i = 0; i < MAX_SQLMASTERS; i++) + if (pSelf->m_apMasterSqlServers[i]) + { + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "SQL-Master %d: DB: '%s' Prefix: '%s' User: '%s' Pass: '%s' IP: '%s' Port: %d", i, pSelf->m_apMasterSqlServers[i]->GetDatabase(), pSelf->m_apMasterSqlServers[i]->GetPrefix(), pSelf->m_apMasterSqlServers[i]->GetUser(), pSelf->m_apMasterSqlServers[i]->GetPass(), pSelf->m_apMasterSqlServers[i]->GetIP(), pSelf->m_apMasterSqlServers[i]->GetPort()); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); + } +} + +#endif + void CServer::ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) { pfnCallback(pResult, pCallbackUserData); @@ -2119,6 +2191,13 @@ void CServer::RegisterCommands() Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "Reload the map"); +#if defined (CONF_SQL) + + Console()->Register("add_sqlmaster", "sssssi", CFGFLAG_SERVER, ConAddSqlMaster, this, "add a sqlmasterserver "); + Console()->Register("dump_sqlmaster", "", CFGFLAG_SERVER, ConDumpSqlMaster, this, "dumps all sqlmasterservers"); + +#endif + Console()->Chain("sv_name", ConchainSpecialInfoupdate, this); Console()->Chain("password", ConchainSpecialInfoupdate, this); diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 0d11e591c..58ef62280 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -17,6 +17,10 @@ #include #include +#if defined (CONF_SQL) + #include +#endif + class CSnapIDPool { enum @@ -75,6 +79,12 @@ class CServer : public IServer class IGameServer *m_pGameServer; class IConsole *m_pConsole; class IStorage *m_pStorage; + +#if defined (CONF_SQL) + CSqlServer* m_pSqlServer; + CSqlServer* m_apMasterSqlServers[MAX_SQLMASTERS]; +#endif + public: class IGameServer *GameServer() { return m_pGameServer; } class IConsole *Console() { return m_pConsole; } @@ -268,6 +278,13 @@ public: static void ConStopRecord(IConsole::IResult *pResult, void *pUser); static void ConMapReload(IConsole::IResult *pResult, void *pUser); static void ConLogout(IConsole::IResult *pResult, void *pUser); + +#if defined (CONF_SQL) + // console commands for sqlmasters + static void ConAddSqlMaster(IConsole::IResult *pResult, void *pUserData); + static void ConDumpSqlMaster(IConsole::IResult *pResult, void *pUserData); +#endif + static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainCommandAccessUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); @@ -296,6 +313,11 @@ public: void RestrictRconOutput(int ClientID) { m_RconRestrict = ClientID; } virtual int* GetIdMap(int ClientID); + +#if defined (CONF_SQL) + CSqlServer *SqlServer() { return m_pSqlServer; } + CSqlServer **SqlMasterServers() { return m_apMasterSqlServers; } +#endif }; #endif diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index c26af646e..758d7d063 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -229,6 +229,7 @@ MACRO_CONFIG_INT(SvSaveGames, sv_savegames, 1, 0, 1, CFGFLAG_SERVER, "Enables sa MACRO_CONFIG_INT(SvSaveGamesDelay, sv_savegames_delay, 60, 0, 10000, CFGFLAG_SERVER, "Delay in seconds for loading a savegame") MACRO_CONFIG_INT(SvUseSQLMasters, sv_use_sqlmasters, 0, 0, 1, CFGFLAG_SERVER, "Redirects all writes to the specified masterservers") +MACRO_CONFIG_INT(SvSqlMastersCreateTables, sv_sqlmasters_create_tables, 0, 0, 1, CFGFLAG_SERVER, "Try to create the SQL tables when starting") #endif MACRO_CONFIG_INT(SvDDRaceRules, sv_ddrace_rules, 1, 0, 1, CFGFLAG_SERVER, "Whether the default mod rules are displayed or not") diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp index df20e4a6f..f004d26dc 100644 --- a/src/game/server/score/sql_score.cpp +++ b/src/game/server/score/sql_score.cpp @@ -24,24 +24,17 @@ CSqlServer *CSqlData::ms_pSqlServer = 0; CSqlServer **CSqlData::ms_pMasterSqlServers = 0; CSqlScore::CSqlScore(CGameContext *pGameServer) : m_pGameServer(pGameServer), - m_pServer(pGameServer->Server()), - m_SqlServer(g_Config.m_SvSqlDatabase, g_Config.m_SvSqlPrefix, g_Config.m_SvSqlUser, g_Config.m_SvSqlPw, g_Config.m_SvSqlIp, g_Config.m_SvSqlPort) + m_pServer(pGameServer->Server()) { str_copy(m_aMap, g_Config.m_SvMap, sizeof(m_aMap)); ClearString(m_aMap); - for (int i = 0; i < MAX_SQLMASTERS; i++) - m_apMasterSqlServers[i] = 0; - CSqlData::ms_pGameServer = m_pGameServer; CSqlData::ms_pServer = m_pServer; CSqlData::ms_pPlayerData = PlayerData(0); CSqlData::ms_pMap = m_aMap; - CSqlData::ms_pSqlServer = &m_SqlServer; - CSqlData::ms_pMasterSqlServers = m_apMasterSqlServers; - - GameServer()->Console()->Register("add_sqlmaster", "sssssi", CFGFLAG_SERVER, ConAddSqlMaster, this, "add a sqlmasterserver "); - GameServer()->Console()->Register("dump_sqlmaster", "", CFGFLAG_SERVER, ConDumpSqlMaster, this, "dumps all sqlmasterservers"); + CSqlData::ms_pSqlServer = SqlServer(); + CSqlData::ms_pMasterSqlServers = SqlMasterServers(); if(gs_SqlLock == 0) gs_SqlLock = lock_create(); @@ -53,50 +46,6 @@ CSqlScore::~CSqlScore() { lock_wait(gs_SqlLock); lock_unlock(gs_SqlLock); - for (int i = 0; i < MAX_SQLMASTERS; i++) - if (m_apMasterSqlServers[i]) - delete m_apMasterSqlServers[i]; -} - -void CSqlScore::ConAddSqlMaster(IConsole::IResult *pResult, void *pUserData) -{ - CSqlScore *pSelf = (CSqlScore *)pUserData; - - if (pResult->NumArguments() != 6) - { - pSelf->GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "6 arguments are required"); - return; - } - - for (int i = 0; i < MAX_SQLMASTERS; i++) - { - if (!pSelf->m_apMasterSqlServers[i]) - pSelf->m_apMasterSqlServers[i] = new CSqlServer(pResult->GetString(0), pResult->GetString(1), pResult->GetString(2), pResult->GetString(3), pResult->GetString(4), pResult->GetInteger(5)); - - if(g_Config.m_SvSqlCreateTables) - { - pSelf->m_apMasterSqlServers[i]->Connect(); - pSelf->m_apMasterSqlServers[i]->CreateTables(); - pSelf->m_apMasterSqlServers[i]->Disconnect(); - } - - pSelf->GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "Added new sqlmasterserver"); - return; - } - pSelf->GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "failed to add new sqlmaster: limit of sqlmasters reached"); -} - -void CSqlScore::ConDumpSqlMaster(IConsole::IResult *pResult, void *pUserData) -{ - CSqlScore *pSelf = (CSqlScore *)pUserData; - - for (int i = 0; i < MAX_SQLMASTERS; i++) - if (pSelf->m_apMasterSqlServers[i]) - { - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "SQL-Master %d: DB: '%s' Prefix: '%s' User: '%s' Pass: '%s' IP: '%s' Port: %d", i, pSelf->m_apMasterSqlServers[i]->GetDatabase(), pSelf->m_apMasterSqlServers[i]->GetPrefix(), pSelf->m_apMasterSqlServers[i]->GetUser(), pSelf->m_apMasterSqlServers[i]->GetPass(), pSelf->m_apMasterSqlServers[i]->GetIP(), pSelf->m_apMasterSqlServers[i]->GetPort()); - pSelf->GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - } } // create tables... should be done only once @@ -108,10 +57,6 @@ void CSqlScore::Init() try { char aBuf[1024]; - // create tables - if(g_Config.m_SvSqlCreateTables) - SqlServer()->CreateTables(); - // get the best time str_format(aBuf, sizeof(aBuf), "SELECT Time FROM %s_race WHERE Map='%s' ORDER BY `Time` ASC LIMIT 0, 1;", SqlServer()->GetPrefix(), m_aMap); SqlServer()->executeSqlQuery(aBuf); @@ -322,9 +267,7 @@ void CSqlScore::SaveTeamScoreThread(void *pUser) pData->SqlServer()->Disconnect(); } else - { dbg_msg("SQL", "ERROR: Could not connect to SQL-Server"); - } delete pData; @@ -586,10 +529,7 @@ void CSqlScore::SaveScoreThread(void *pUser) pData->SqlServer()->Disconnect(); } else - { dbg_msg("SQL", "ERROR: Could not connect to SQL-Server"); - pData->GameServer()->SendChatTarget(pData->m_ClientID, "ERROR: Could NOT connect to SQL-server, this rank is lost."); - } delete pData; diff --git a/src/game/server/score/sql_score.h b/src/game/server/score/sql_score.h index d8cf2de62..c891b9a84 100644 --- a/src/game/server/score/sql_score.h +++ b/src/game/server/score/sql_score.h @@ -9,25 +9,18 @@ #include "sql_server.h" #include "../score.h" -enum -{ - MAX_SQLMASTERS=10 -}; - class CSqlScore: public IScore { CGameContext *GameServer() { return m_pGameServer; } IServer *Server() { return m_pServer; } - CSqlServer *SqlServer() { return &m_SqlServer; } + inline CSqlServer *SqlServer() { return m_pServer->SqlServer(); } + inline CSqlServer **SqlMasterServers() { return m_pServer->SqlMasterServers(); } void Init(); CGameContext *m_pGameServer; IServer *m_pServer; - CSqlServer m_SqlServer; - CSqlServer* m_apMasterSqlServers[MAX_SQLMASTERS]; - char m_aMap[64]; static void MapInfoThread(void *pUser); @@ -47,10 +40,6 @@ class CSqlScore: public IScore static void SaveTeamThread(void *pUser); static void LoadTeamThread(void *pUser); - // console commands for sqlmasters - static void ConAddSqlMaster(IConsole::IResult *pResult, void *pUserData); - static void ConDumpSqlMaster(IConsole::IResult *pResult, void *pUserData); - public: CSqlScore(CGameContext *pGameServer); @@ -101,9 +90,12 @@ struct CSqlData if (SqlMasterServer(i) && SqlMasterServer(i)->Connect()) { m_pSqlServer = SqlMasterServer(i); - break; + return; } + if (SqlMasterServer(i)) + dbg_msg("SQL", "Warning: Unable to connect to sqlmaster %d ('%s'), trying next...", i, SqlMasterServer(i)->GetIP()); } + dbg_msg("SQL", "ERROR: No sqlmasterservers available"); } else if (!SqlServer()->Connect()) m_pSqlServer = 0; diff --git a/src/game/server/score/sql_server.cpp b/src/game/server/score/sql_server.cpp index e4d2b6761..82efdc276 100644 --- a/src/game/server/score/sql_server.cpp +++ b/src/game/server/score/sql_server.cpp @@ -38,7 +38,7 @@ CSqlServer::~CSqlServer() } } -bool CSqlServer::Connect() +bool CSqlServer::Connect(bool CreateDatabase) { if (m_pDriver != NULL && m_pConnection != NULL) { @@ -79,9 +79,9 @@ bool CSqlServer::Connect() // Create Statement m_pStatement = m_pConnection->createStatement(); - if (g_Config.m_SvSqlCreateTables) + if (CreateDatabase) { - char aBuf[256]; + char aBuf[128]; // create database str_format(aBuf, sizeof(aBuf), "CREATE DATABASE IF NOT EXISTS %s", m_aDatabase); m_pStatement->execute(aBuf); @@ -147,6 +147,9 @@ void CSqlServer::Disconnect() void CSqlServer::CreateTables() { + if (!Connect(true)) + return; + try { char aBuf[1024]; @@ -176,6 +179,8 @@ void CSqlServer::CreateTables() dbg_msg("SQL", aBuf); dbg_msg("SQL", "ERROR: Tables were NOT created"); } + + Disconnect(); } void CSqlServer::executeSql(const char *pCommand) diff --git a/src/game/server/score/sql_server.h b/src/game/server/score/sql_server.h index 0b9dfd8a5..8b25a04ca 100644 --- a/src/game/server/score/sql_server.h +++ b/src/game/server/score/sql_server.h @@ -7,13 +7,18 @@ #include #include +enum +{ + MAX_SQLMASTERS=10 +}; + class CSqlServer { public: CSqlServer(const char* pDatabase, const char* pPrefix, const char* pUser, const char* pPass, const char* pIp, int Port); ~CSqlServer(); - bool Connect(); + bool Connect(bool CreateDatabase = false); void Disconnect(); void CreateTables(); @@ -35,7 +40,7 @@ private: sql::Connection *m_pConnection; sql::Statement *m_pStatement; sql::ResultSet *m_pResults; - + // copy of config vars char m_aDatabase[64]; char m_aPrefix[64];