mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
Cleanup of Sqlconnection
-moved all connectionstuff to a new class -moved sqlstring functions to an own file -do not give threads access to CSqlScore
This commit is contained in:
parent
c1df605c5a
commit
9ed66f7adc
|
@ -4,6 +4,7 @@
|
|||
#define ENGINE_SHARED_CONSOLE_H
|
||||
|
||||
#include <engine/console.h>
|
||||
#include <base/math.h>
|
||||
#include "memheap.h"
|
||||
|
||||
class CConsole : public IConsole
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,41 +4,24 @@
|
|||
#ifndef GAME_SERVER_SQLSCORE_H
|
||||
#define GAME_SERVER_SQLSCORE_H
|
||||
|
||||
#include <mysql_connection.h>
|
||||
|
||||
#include <cppconn/driver.h>
|
||||
#include <cppconn/exception.h>
|
||||
#include <cppconn/statement.h>
|
||||
|
||||
#include "sqlserver.h"
|
||||
#include "../score.h"
|
||||
|
||||
|
||||
class CSqlScore: public IScore
|
||||
{
|
||||
CGameContext *GameServer() { return m_pGameServer; }
|
||||
IServer *Server() { return m_pServer; }
|
||||
CSqlServer *SqlServer() { return &m_SqlServer; }
|
||||
|
||||
void Init();
|
||||
|
||||
CGameContext *m_pGameServer;
|
||||
IServer *m_pServer;
|
||||
|
||||
sql::Driver *m_pDriver;
|
||||
sql::Connection *m_pConnection;
|
||||
sql::Statement *m_pStatement;
|
||||
sql::ResultSet *m_pResults;
|
||||
CSqlServer m_SqlServer;
|
||||
|
||||
// copy of config vars
|
||||
const char* m_pDatabase;
|
||||
const char* m_pPrefix;
|
||||
const char* m_pUser;
|
||||
const char* m_pPass;
|
||||
const char* m_pIp;
|
||||
char m_aMap[64];
|
||||
int m_Port;
|
||||
|
||||
CGameContext *GameServer()
|
||||
{
|
||||
return m_pGameServer;
|
||||
}
|
||||
IServer *Server()
|
||||
{
|
||||
return m_pServer;
|
||||
}
|
||||
|
||||
static void MapInfoThread(void *pUser);
|
||||
static void MapVoteThread(void *pUser);
|
||||
|
@ -57,17 +40,6 @@ class CSqlScore: public IScore
|
|||
static void SaveTeamThread(void *pUser);
|
||||
static void LoadTeamThread(void *pUser);
|
||||
|
||||
void Init();
|
||||
|
||||
bool Connect();
|
||||
void Disconnect();
|
||||
|
||||
void FuzzyString(char *pString);
|
||||
// anti SQL injection
|
||||
void ClearString(char *pString, int size = 32);
|
||||
|
||||
void NormalizeMapname(char *pString);
|
||||
|
||||
public:
|
||||
|
||||
CSqlScore(CGameContext *pGameServer);
|
||||
|
@ -94,19 +66,38 @@ public:
|
|||
virtual void RandomUnfinishedMap(int ClientID, int stars);
|
||||
virtual void SaveTeam(int Team, const char* Code, int ClientID, const char* Server);
|
||||
virtual void LoadTeam(const char* Code, int ClientID);
|
||||
static void agoTimeToString(int agoTime, char agoString[]);
|
||||
};
|
||||
|
||||
struct CSqlMapData
|
||||
// generic implementation to provide sqlserver, gameserver and server
|
||||
struct CSqlData
|
||||
{
|
||||
CSqlScore *m_pSqlData;
|
||||
CSqlData(CSqlServer* pSqlServer) : m_pSqlServer(pSqlServer) {}
|
||||
|
||||
CGameContext* GameServer() { return ms_pGameServer; }
|
||||
IServer* Server() { return ms_pServer; }
|
||||
CPlayerData* PlayerData(int ID) { return &ms_pPlayerData[ID]; }
|
||||
const char* MapName() { return ms_pMap; }
|
||||
CSqlServer* SqlServer() { return m_pSqlServer; }
|
||||
|
||||
static CGameContext *ms_pGameServer;
|
||||
static IServer *ms_pServer;
|
||||
static CPlayerData *ms_pPlayerData;
|
||||
static const char *ms_pMap;
|
||||
CSqlServer *m_pSqlServer;
|
||||
};
|
||||
|
||||
struct CSqlMapData : CSqlData
|
||||
{
|
||||
CSqlMapData(CSqlServer* pSqlServer) : CSqlData(pSqlServer) {}
|
||||
|
||||
int m_ClientID;
|
||||
char m_aMap[128];
|
||||
};
|
||||
|
||||
struct CSqlScoreData
|
||||
struct CSqlScoreData : CSqlData
|
||||
{
|
||||
CSqlScore *m_pSqlData;
|
||||
CSqlScoreData(CSqlServer* pSqlServer) : CSqlData(pSqlServer) {}
|
||||
|
||||
int m_ClientID;
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
char m_aName[16]; // Don't edit this, or all your teeth will fall http://bugs.mysql.com/bug.php?id=50046
|
||||
|
@ -121,9 +112,10 @@ struct CSqlScoreData
|
|||
char m_aRequestingPlayer[MAX_NAME_LENGTH];
|
||||
};
|
||||
|
||||
struct CSqlTeamScoreData
|
||||
struct CSqlTeamScoreData : CSqlData
|
||||
{
|
||||
CSqlScore *m_pSqlData;
|
||||
CSqlTeamScoreData(CSqlServer* pSqlServer) : CSqlData(pSqlServer) {}
|
||||
|
||||
unsigned int m_Size;
|
||||
int m_aClientIDs[MAX_CLIENTS];
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
|
@ -139,20 +131,22 @@ struct CSqlTeamScoreData
|
|||
char m_aRequestingPlayer[MAX_NAME_LENGTH];
|
||||
};
|
||||
|
||||
struct CSqlTeamSave
|
||||
struct CSqlTeamSave : CSqlData
|
||||
{
|
||||
CSqlTeamSave(CSqlServer* pSqlServer) : CSqlData(pSqlServer) {}
|
||||
|
||||
int m_Team;
|
||||
int m_ClientID;
|
||||
char m_Code[128];
|
||||
char m_Server[5];
|
||||
CSqlScore *m_pSqlData;
|
||||
};
|
||||
|
||||
struct CSqlTeamLoad
|
||||
struct CSqlTeamLoad : CSqlData
|
||||
{
|
||||
CSqlTeamLoad(CSqlServer* pSqlServer) : CSqlData(pSqlServer) {}
|
||||
|
||||
char m_Code[128];
|
||||
int m_ClientID;
|
||||
CSqlScore *m_pSqlData;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
137
src/game/server/score/sql_string_helpers.h
Normal file
137
src/game/server/score/sql_string_helpers.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
#ifndef GAME_SERVER_SQL_STRING_HELPERS_H
|
||||
#define GAME_SERVER_SQL_STRING_HELPERS_H
|
||||
|
||||
#include <base/system.h>
|
||||
|
||||
void FuzzyString(char *pString)
|
||||
{
|
||||
char newString[32*4-1];
|
||||
int pos = 0;
|
||||
|
||||
for(int i=0;i<64;i++)
|
||||
{
|
||||
if(!pString[i])
|
||||
break;
|
||||
|
||||
newString[pos++] = pString[i];
|
||||
if (pString[i] != '\\' && str_utf8_isstart(pString[i+1]))
|
||||
newString[pos++] = '%';
|
||||
}
|
||||
|
||||
newString[pos] = '\0';
|
||||
strcpy(pString, newString);
|
||||
}
|
||||
|
||||
// anti SQL injection
|
||||
void ClearString(char *pString, int size = 32)
|
||||
{
|
||||
char *newString = (char *)malloc(size * 2 - 1);
|
||||
int pos = 0;
|
||||
|
||||
for(int i=0;i<size;i++)
|
||||
{
|
||||
if(pString[i] == '\\')
|
||||
{
|
||||
newString[pos++] = '\\';
|
||||
newString[pos++] = '\\';
|
||||
}
|
||||
else if(pString[i] == '\'')
|
||||
{
|
||||
newString[pos++] = '\\';
|
||||
newString[pos++] = '\'';
|
||||
}
|
||||
else if(pString[i] == '"')
|
||||
{
|
||||
newString[pos++] = '\\';
|
||||
newString[pos++] = '"';
|
||||
}
|
||||
else
|
||||
{
|
||||
newString[pos++] = pString[i];
|
||||
}
|
||||
}
|
||||
|
||||
newString[pos] = '\0';
|
||||
|
||||
strcpy(pString,newString);
|
||||
free(newString);
|
||||
}
|
||||
|
||||
void agoTimeToString(int agoTime, char agoString[])
|
||||
{
|
||||
char aBuf[20];
|
||||
int times[7] =
|
||||
{
|
||||
60 * 60 * 24 * 365 ,
|
||||
60 * 60 * 24 * 30 ,
|
||||
60 * 60 * 24 * 7,
|
||||
60 * 60 * 24 ,
|
||||
60 * 60 ,
|
||||
60 ,
|
||||
1
|
||||
};
|
||||
char names[7][6] =
|
||||
{
|
||||
"year",
|
||||
"month",
|
||||
"week",
|
||||
"day",
|
||||
"hour",
|
||||
"min",
|
||||
"sec"
|
||||
};
|
||||
|
||||
int seconds = 0;
|
||||
char name[6];
|
||||
int count = 0;
|
||||
int i = 0;
|
||||
|
||||
// finding biggest match
|
||||
for(i = 0; i<7; i++)
|
||||
{
|
||||
seconds = times[i];
|
||||
strcpy(name,names[i]);
|
||||
|
||||
count = floor((float)agoTime/(float)seconds);
|
||||
if(count != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(count == 1)
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%d %s", 1 , name);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "%d %ss", count , name);
|
||||
}
|
||||
strcat(agoString,aBuf);
|
||||
|
||||
if (i + 1 < 7)
|
||||
{
|
||||
// getting second piece now
|
||||
int seconds2 = times[i+1];
|
||||
char name2[6];
|
||||
strcpy(name2,names[i+1]);
|
||||
|
||||
// add second piece if it's greater than 0
|
||||
int count2 = floor((float)(agoTime - (seconds * count)) / (float)seconds2);
|
||||
|
||||
if (count2 != 0)
|
||||
{
|
||||
if(count2 == 1)
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), " and %d %s", 1 , name2);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), " and %d %ss", count2 , name2);
|
||||
}
|
||||
strcat(agoString,aBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
194
src/game/server/score/sqlserver.cpp
Normal file
194
src/game/server/score/sqlserver.cpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
#include <base/system.h>
|
||||
#include <engine/shared/protocol.h>
|
||||
#include <engine/shared/config.h>
|
||||
|
||||
#include "sqlserver.h"
|
||||
|
||||
|
||||
CSqlServer::CSqlServer(const char* pDatabase, const char* pPrefix, const char* pUser, const char* pPass, const char* pIp, int Port) :
|
||||
m_pDatabase(pDatabase),
|
||||
m_pPrefix(pPrefix),
|
||||
m_pUser(pUser),
|
||||
m_pPass(pPass),
|
||||
m_pIp(pIp),
|
||||
m_Port(Port)
|
||||
{
|
||||
m_pDriver = 0;
|
||||
m_pConnection = 0;
|
||||
m_pResults = 0;
|
||||
m_pStatement = 0;
|
||||
}
|
||||
|
||||
CSqlServer::~CSqlServer()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_pResults)
|
||||
delete m_pResults;
|
||||
if (m_pConnection)
|
||||
delete m_pConnection;
|
||||
dbg_msg("SQL", "SQL connection disconnected");
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
{
|
||||
dbg_msg("SQL", "ERROR: No SQL connection");
|
||||
}
|
||||
}
|
||||
|
||||
bool CSqlServer::Connect()
|
||||
{
|
||||
if (m_pDriver != NULL && m_pConnection != NULL)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Connect to specific database
|
||||
m_pConnection->setSchema(m_pDatabase);
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
|
||||
dbg_msg("SQL", aBuf);
|
||||
|
||||
dbg_msg("SQL", "ERROR: SQL connection failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_pDriver = 0;
|
||||
m_pConnection = 0;
|
||||
m_pStatement = 0;
|
||||
|
||||
sql::ConnectOptionsMap connection_properties;
|
||||
connection_properties["hostName"] = sql::SQLString(m_pIp);
|
||||
connection_properties["port"] = m_Port;
|
||||
connection_properties["userName"] = sql::SQLString(m_pUser);
|
||||
connection_properties["password"] = sql::SQLString(m_pPass);
|
||||
connection_properties["OPT_RECONNECT"] = true;
|
||||
|
||||
// Create connection
|
||||
m_pDriver = get_driver_instance();
|
||||
m_pConnection = m_pDriver->connect(connection_properties);
|
||||
|
||||
// Create Statement
|
||||
m_pStatement = m_pConnection->createStatement();
|
||||
|
||||
// Connect to specific database
|
||||
m_pConnection->setSchema(m_pDatabase);
|
||||
dbg_msg("SQL", "SQL connection established");
|
||||
return true;
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
|
||||
dbg_msg("SQL", aBuf);
|
||||
|
||||
dbg_msg("SQL", "ERROR: SQL connection failed");
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
// ...
|
||||
dbg_msg("SQL", "1 %s",ex.what());
|
||||
|
||||
}
|
||||
catch (const std::string& ex)
|
||||
{
|
||||
// ...
|
||||
dbg_msg("SQL", "2 %s",ex.c_str());
|
||||
}
|
||||
catch( int )
|
||||
{
|
||||
dbg_msg("SQL", "3 %s");
|
||||
}
|
||||
catch( float )
|
||||
{
|
||||
dbg_msg("SQL", "4 %s");
|
||||
}
|
||||
|
||||
catch( char[] )
|
||||
{
|
||||
dbg_msg("SQL", "5 %s");
|
||||
}
|
||||
|
||||
catch( char )
|
||||
{
|
||||
dbg_msg("SQL", "6 %s");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
dbg_msg("SQL", "Unknown Error cause by the MySQL/C++ Connector, my advice compile server_debug and use it");
|
||||
|
||||
dbg_msg("SQL", "ERROR: SQL connection failed");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSqlServer::Disconnect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CSqlServer::CreateTables()
|
||||
{
|
||||
try
|
||||
{
|
||||
char aBuf[1024];
|
||||
|
||||
// create database
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE DATABASE IF NOT EXISTS %s", m_pDatabase);
|
||||
m_pStatement->execute(aBuf);
|
||||
|
||||
// create tables
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_race (Map VARCHAR(128) BINARY NOT NULL, Name VARCHAR(%d) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , Time FLOAT DEFAULT 0, Server CHAR(4), cp1 FLOAT DEFAULT 0, cp2 FLOAT DEFAULT 0, cp3 FLOAT DEFAULT 0, cp4 FLOAT DEFAULT 0, cp5 FLOAT DEFAULT 0, cp6 FLOAT DEFAULT 0, cp7 FLOAT DEFAULT 0, cp8 FLOAT DEFAULT 0, cp9 FLOAT DEFAULT 0, cp10 FLOAT DEFAULT 0, cp11 FLOAT DEFAULT 0, cp12 FLOAT DEFAULT 0, cp13 FLOAT DEFAULT 0, cp14 FLOAT DEFAULT 0, cp15 FLOAT DEFAULT 0, cp16 FLOAT DEFAULT 0, cp17 FLOAT DEFAULT 0, cp18 FLOAT DEFAULT 0, cp19 FLOAT DEFAULT 0, cp20 FLOAT DEFAULT 0, cp21 FLOAT DEFAULT 0, cp22 FLOAT DEFAULT 0, cp23 FLOAT DEFAULT 0, cp24 FLOAT DEFAULT 0, cp25 FLOAT DEFAULT 0, KEY (Map, Name)) CHARACTER SET utf8 ;", m_pPrefix, MAX_NAME_LENGTH);
|
||||
executeSql(aBuf);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_teamrace (Map VARCHAR(128) BINARY NOT NULL, Name VARCHAR(%d) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, Time FLOAT DEFAULT 0, ID VARBINARY(16) NOT NULL, KEY Map (Map)) CHARACTER SET utf8 ;", m_pPrefix, MAX_NAME_LENGTH);
|
||||
executeSql(aBuf);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_maps (Map VARCHAR(128) BINARY NOT NULL, Server VARCHAR(32) BINARY NOT NULL, Mapper VARCHAR(128) BINARY NOT NULL, Points INT DEFAULT 0, Stars INT DEFAULT 0, Timestamp TIMESTAMP, UNIQUE KEY Map (Map)) CHARACTER SET utf8 ;", m_pPrefix);
|
||||
executeSql(aBuf);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_saves (Savegame TEXT CHARACTER SET utf8 BINARY NOT NULL, Map VARCHAR(128) BINARY NOT NULL, Code VARCHAR(128) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, Server CHAR(4), UNIQUE KEY (Map, Code)) CHARACTER SET utf8 ;", m_pPrefix);
|
||||
executeSql(aBuf);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_points (Name VARCHAR(%d) BINARY NOT NULL, Points INT DEFAULT 0, UNIQUE KEY Name (Name)) CHARACTER SET utf8 ;", m_pPrefix, MAX_NAME_LENGTH);
|
||||
executeSql(aBuf);
|
||||
|
||||
dbg_msg("SQL", "Tables were created successfully");
|
||||
}
|
||||
catch (sql::SQLException &e)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
|
||||
dbg_msg("SQL", aBuf);
|
||||
dbg_msg("SQL", "ERROR: Tables were NOT created");
|
||||
}
|
||||
}
|
||||
|
||||
void CSqlServer::executeSql(const char *pCommand)
|
||||
{
|
||||
m_pStatement->execute(pCommand);
|
||||
}
|
||||
|
||||
void CSqlServer::executeSqlQuery(const char *pQuery)
|
||||
{
|
||||
if (m_pResults)
|
||||
delete m_pResults;
|
||||
m_pResults = m_pStatement->executeQuery(pQuery);
|
||||
}
|
||||
|
||||
sql::ResultSet* CSqlServer::GetResults()
|
||||
{
|
||||
return m_pResults;
|
||||
}
|
||||
|
||||
const char* CSqlServer::GetPrefix()
|
||||
{
|
||||
return m_pPrefix;
|
||||
}
|
40
src/game/server/score/sqlserver.h
Normal file
40
src/game/server/score/sqlserver.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef GAME_SERVER_SQLSERVER_H
|
||||
#define GAME_SERVER_SQLSERVER_H
|
||||
|
||||
#include <mysql_connection.h>
|
||||
|
||||
#include <cppconn/driver.h>
|
||||
#include <cppconn/exception.h>
|
||||
#include <cppconn/statement.h>
|
||||
|
||||
class CSqlServer
|
||||
{
|
||||
public:
|
||||
CSqlServer(const char* pDatabase, const char* pPrefix, const char* pUser, const char* pPass, const char* pIp, int Port);
|
||||
~CSqlServer();
|
||||
|
||||
bool Connect();
|
||||
void Disconnect();
|
||||
void CreateTables();
|
||||
|
||||
void executeSql(const char* pCommand);
|
||||
void executeSqlQuery(const char* pQuery);
|
||||
sql::ResultSet* GetResults();
|
||||
|
||||
const char* GetPrefix();
|
||||
|
||||
private:
|
||||
sql::Driver *m_pDriver;
|
||||
sql::Connection *m_pConnection;
|
||||
sql::Statement *m_pStatement;
|
||||
sql::ResultSet *m_pResults;
|
||||
// copy of config vars
|
||||
const char* m_pDatabase;
|
||||
const char* m_pPrefix;
|
||||
const char* m_pUser;
|
||||
const char* m_pPass;
|
||||
const char* m_pIp;
|
||||
int m_Port;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue