Initial commit: server + serverfiles

This commit is contained in:
Game
2026-08-17 17:31:44 +00:00
commit ff1237686b
17389 changed files with 868929 additions and 0 deletions
+716
View File
@@ -0,0 +1,716 @@
#ifndef __WIN32__
#include <sys/time.h>
#endif
#include <cstdlib>
#include <cstring>
#include "AsyncSQL.h"
// TODO: Consider providing platform-independent mutex class.
#ifndef __WIN32__
#define MUTEX_LOCK(mtx) pthread_mutex_lock(mtx)
#define MUTEX_UNLOCK(mtx) pthread_mutex_unlock(mtx)
#else
#define MUTEX_LOCK(mtx) ::EnterCriticalSection(mtx)
#define MUTEX_UNLOCK(mtx) ::LeaveCriticalSection(mtx)
#endif
CAsyncSQL::CAsyncSQL()
: m_stHost(""), m_stUser(""), m_stPassword(""), m_stDB(""), m_stLocale(""),
m_iMsgCount(0), m_bEnd(false),
#ifndef __WIN32__
m_hThread(0),
#else
m_hThread(INVALID_HANDLE_VALUE),
#endif
m_mtxQuery(NULL), m_mtxResult(NULL),
m_iQueryFinished(0), m_ulThreadID(0), m_bConnected(false), m_iCopiedQuery(0),
m_iPort(0)
{
memset( &m_hDB, 0, sizeof(m_hDB) );
m_aiPipe[0] = 0;
m_aiPipe[1] = 0;
}
CAsyncSQL::~CAsyncSQL()
{
Quit();
Destroy();
}
void CAsyncSQL::Destroy()
{
if (m_hDB.host)
{
sys_log(0, "AsyncSQL: closing mysql connection.");
mysql_close(&m_hDB);
m_hDB.host = NULL;
}
if (m_mtxQuery)
{
#ifndef __WIN32__
pthread_mutex_destroy(m_mtxQuery);
#else
::DeleteCriticalSection(m_mtxQuery);
#endif
delete m_mtxQuery;
m_mtxQuery = NULL;
}
if (m_mtxResult)
{
#ifndef __WIN32__
pthread_mutex_destroy(m_mtxResult);
#else
::DeleteCriticalSection(m_mtxResult);
#endif
delete m_mtxResult;
m_mtxQuery = NULL;
}
}
#ifndef __WIN32__
void * AsyncSQLThread(void * arg)
#else
unsigned int __stdcall AsyncSQLThread(void* arg)
#endif
{
CAsyncSQL * pSQL = ((CAsyncSQL *) arg);
if (!pSQL->Connect())
return NULL;
pSQL->ChildLoop();
return NULL;
}
bool CAsyncSQL::QueryLocaleSet()
{
if (0 == m_stLocale.length())
{
sys_err("m_stLocale == 0");
return true;
}
else if (m_stLocale == "ascii")
{
sys_err("m_stLocale == ascii");
return true;
}
if (mysql_set_character_set(&m_hDB, m_stLocale.c_str()))
{
sys_err("cannot set locale %s by 'mysql_set_character_set', errno %u %s", m_stLocale.c_str(), mysql_errno(&m_hDB) , mysql_error(&m_hDB));
return false;
}
sys_log(0, "\t--mysql_set_character_set(%s)", m_stLocale.c_str());
return true;
}
bool CAsyncSQL::Connect()
{
if (0 == mysql_init(&m_hDB))
{
fprintf(stderr, "mysql_init failed\n");
return false;
}
//mysql_options(&m_hDB, MYSQL_SET_CHARSET_NAME, m_stLocale.c_str());
if (!m_stLocale.empty())
{
//mysql_options(&m_hDB, MYSQL_SET_CHARSET_DIR , " /usr/local/share/mysql/charsets/");
//mysql_options(&m_hDB, MYSQL_SET_CHARSET_DIR , "/usr/local/share/mysql/charsets");
//mysql_options(&m_hDB, MYSQL_SET_CHARSET_DIR , "/usr/local/share/mysql");
if (mysql_options(&m_hDB, MYSQL_SET_CHARSET_NAME, m_stLocale.c_str()) != 0)
{
fprintf(stderr, "mysql_option failed : MYSQL_SET_CHARSET_NAME %s ", mysql_error(&m_hDB));
}
}
if (!mysql_real_connect(&m_hDB, m_stHost.c_str(), m_stUser.c_str(), m_stPassword.c_str(), m_stDB.c_str(), m_iPort, NULL, CLIENT_MULTI_STATEMENTS))
{
fprintf(stderr, "mysql_real_connect: %s\n", mysql_error(&m_hDB));
return false;
}
my_bool reconnect = true;
if (0 != mysql_options(&m_hDB, MYSQL_OPT_RECONNECT, &reconnect))
fprintf(stderr, "mysql_option: %s\n", mysql_error(&m_hDB));
fprintf(stdout, "AsyncSQL: connected to %s (reconnect %d)\n", m_stHost.c_str(), reconnect);
// db cache는 common db의 LOCALE 테이블에서 locale을 알아오고, 이후 character set을 수정한다.
// 따라서 최초 Connection을 맺을 때에는 locale을 모르기 때문에 character set을 정할 수가 없음에도 불구하고,
// 강제로 character set을 euckr로 정하도록 되어있어 이 부분을 주석처리 하였다.
// (아래 주석을 풀면 mysql에 euckr이 안 깔려있는 디비에 접근할 수가 없다.)
//while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id(&m_hDB);
m_bConnected = true;
return true;
}
bool CAsyncSQL::Setup(CAsyncSQL * sql, bool bNoThread)
{
return Setup(sql->m_stHost.c_str(),
sql->m_stUser.c_str(),
sql->m_stPassword.c_str(),
sql->m_stDB.c_str(),
sql->m_stLocale.c_str(),
bNoThread,
sql->m_iPort);
}
bool CAsyncSQL::Setup(const char * c_pszHost, const char * c_pszUser, const char * c_pszPassword, const char * c_pszDB, const char * c_pszLocale, bool bNoThread, int iPort)
{
m_stHost = c_pszHost;
m_stUser = c_pszUser;
m_stPassword = c_pszPassword;
m_stDB = c_pszDB;
m_iPort = iPort;
if (c_pszLocale)
{
m_stLocale = c_pszLocale;
sys_log(0, "AsyncSQL: locale %s", m_stLocale.c_str());
}
if (!bNoThread)
{
/*
if (!mysql_thread_safe())//
{
fprintf(stderr, "FATAL ERROR!! mysql client library was not compiled with thread safety\n");
return false;
}
*/
#ifndef __WIN32__
m_mtxQuery = new pthread_mutex_t;
m_mtxResult = new pthread_mutex_t;
if (0 != pthread_mutex_init(m_mtxQuery, NULL))
{
perror("pthread_mutex_init");
exit(0);
}
if (0 != pthread_mutex_init(m_mtxResult, NULL))
{
perror("pthread_mutex_init");
exit(0);
}
pthread_create(&m_hThread, NULL, AsyncSQLThread, this);
#else
m_mtxQuery = new CRITICAL_SECTION;
m_mtxResult = new CRITICAL_SECTION;
::InitializeCriticalSection(m_mtxQuery);
::InitializeCriticalSection(m_mtxResult);
m_hThread = (HANDLE)::_beginthreadex(NULL, 0, AsyncSQLThread, this, 0, NULL);
if (m_hThread == INVALID_HANDLE_VALUE) {
perror("CAsyncSQL::Setup");
return false;
}
#endif
return true;
}
else
return Connect();
}
void CAsyncSQL::Quit()
{
m_bEnd = true;
m_sem.Release();
#ifndef __WIN32__
if (m_hThread)
{
pthread_join(m_hThread, NULL);
m_hThread = NULL;
}
#else
if (m_hThread != INVALID_HANDLE_VALUE) {
::WaitForSingleObject(m_hThread, INFINITE);
m_hThread = INVALID_HANDLE_VALUE;
}
#endif
}
SQLMsg * CAsyncSQL::DirectQuery(const char * c_pszQuery)
{
if (m_ulThreadID != mysql_thread_id(&m_hDB))
{
sys_err("MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id(&m_hDB);
}
SQLMsg * p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
if (mysql_real_query(&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
char buf[1024];
snprintf(buf, sizeof(buf),
"AsyncSQL::DirectQuery : mysql_query error: %s\nquery: %s",
mysql_error(&m_hDB), p->stQuery.c_str());
sys_err(buf);
p->uiSQLErrno = mysql_errno(&m_hDB);
}
p->Store();
return p;
}
void CAsyncSQL::AsyncQuery(const char * c_pszQuery)
{
SQLMsg * p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
PushQuery(p);
}
void CAsyncSQL::ReturnQuery(const char * c_pszQuery, void * pvUserData)
{
SQLMsg * p = new SQLMsg;
p->m_pkSQL = &m_hDB;
p->iID = ++m_iMsgCount;
p->stQuery = c_pszQuery;
p->bReturn = true;
p->pvUserData = pvUserData;
PushQuery(p);
}
void CAsyncSQL::PushResult(SQLMsg * p)
{
MUTEX_LOCK(m_mtxResult);
m_queue_result.push(p);
MUTEX_UNLOCK(m_mtxResult);
}
bool CAsyncSQL::PopResult(SQLMsg ** pp)
{
MUTEX_LOCK(m_mtxResult);
if (m_queue_result.empty())
{
MUTEX_UNLOCK(m_mtxResult);
return false;
}
*pp = m_queue_result.front();
m_queue_result.pop();
MUTEX_UNLOCK(m_mtxResult);
return true;
}
void CAsyncSQL::PushQuery(SQLMsg * p)
{
MUTEX_LOCK(m_mtxQuery);
m_queue_query.push(p);
//m_map_kSQLMsgUnfinished.insert(std::make_pair(p->iID, p));
m_sem.Release();
MUTEX_UNLOCK(m_mtxQuery);
}
bool CAsyncSQL::PeekQuery(SQLMsg ** pp)
{
MUTEX_LOCK(m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK(m_mtxQuery);
return false;
}
*pp = m_queue_query.front();
MUTEX_UNLOCK(m_mtxQuery);
return true;
}
bool CAsyncSQL::PopQuery(int iID)
{
MUTEX_LOCK(m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK(m_mtxQuery);
return false;
}
m_queue_query.pop();
//m_map_kSQLMsgUnfinished.erase(iID);
MUTEX_UNLOCK(m_mtxQuery);
return true;
}
bool CAsyncSQL::PeekQueryFromCopyQueue(SQLMsg ** pp)
{
if (m_queue_query_copy.empty())
return false;
*pp = m_queue_query_copy.front();
return true;
}
int CAsyncSQL::CopyQuery()
{
MUTEX_LOCK(m_mtxQuery);
if (m_queue_query.empty())
{
MUTEX_UNLOCK(m_mtxQuery);
return -1;
}
while (!m_queue_query.empty())
{
SQLMsg * p = m_queue_query.front();
m_queue_query_copy.push(p);
m_queue_query.pop();
}
//m_map_kSQLMsgUnfinished.erase(iID);
int count = m_queue_query_copy.size();
MUTEX_UNLOCK(m_mtxQuery);
return count;
}
bool CAsyncSQL::PopQueryFromCopyQueue()
{
if (m_queue_query_copy.empty())
{
return false;
}
m_queue_query_copy.pop();
//m_map_kSQLMsgUnfinished.erase(iID);
return true;
}
int CAsyncSQL::GetCopiedQueryCount()
{
return m_iCopiedQuery;
}
void CAsyncSQL::ResetCopiedQueryCount()
{
m_iCopiedQuery = 0;
}
void CAsyncSQL::AddCopiedQueryCount(int iCopiedQuery)
{
m_iCopiedQuery += iCopiedQuery;
}
DWORD CAsyncSQL::CountQuery()
{
return m_queue_query.size();
}
DWORD CAsyncSQL::CountResult()
{
return m_queue_result.size();
}
void __timediff(struct timeval *a, struct timeval *b, struct timeval *rslt)
{
if (a->tv_sec < b->tv_sec)
rslt->tv_sec = rslt->tv_usec = 0;
else if (a->tv_sec == b->tv_sec)
{
if (a->tv_usec < b->tv_usec)
rslt->tv_sec = rslt->tv_usec = 0;
else
{
rslt->tv_sec = 0;
rslt->tv_usec = a->tv_usec - b->tv_usec;
}
}
else
{ /* a->tv_sec > b->tv_sec */
rslt->tv_sec = a->tv_sec - b->tv_sec;
if (a->tv_usec < b->tv_usec)
{
rslt->tv_usec = a->tv_usec + 1000000 - b->tv_usec;
rslt->tv_sec--;
} else
rslt->tv_usec = a->tv_usec - b->tv_usec;
}
}
class cProfiler
{
public:
cProfiler()
{
m_nInterval = 0 ;
memset( &prev, 0, sizeof(prev) );
memset( &now, 0, sizeof(now) );
memset( &interval, 0, sizeof(interval) );
Start();
}
cProfiler(int nInterval = 100000)
{
m_nInterval = nInterval;
memset( &prev, 0, sizeof(prev) );
memset( &now, 0, sizeof(now) );
memset( &interval, 0, sizeof(interval) );
Start();
}
void Start()
{
gettimeofday (&prev , (struct timezone *) 0);
}
void Stop()
{
gettimeofday(&now, (struct timezone*) 0);
__timediff(&now, &prev, &interval);
}
bool IsOk()
{
if (interval.tv_sec > (m_nInterval / 1000000))
return false;
if (interval.tv_usec > m_nInterval)
return false;
return true;
}
struct timeval * GetResult() { return &interval; }
long GetResultSec() { return interval.tv_sec; }
long GetResultUSec() { return interval.tv_usec; }
private:
int m_nInterval;
struct timeval prev;
struct timeval now;
struct timeval interval;
};
void CAsyncSQL::ChildLoop()
{
cProfiler profiler(500000); // 0.5초
while (!m_bEnd)
{
m_sem.Wait();
int count = CopyQuery();
if (count <= 0)
continue;
AddCopiedQueryCount(count);
SQLMsg * p;
while (count--)
{
//시간 체크 시작
profiler.Start();
if (!PeekQueryFromCopyQueue(&p))
continue;
if (m_ulThreadID != mysql_thread_id(&m_hDB))
{
sys_err("MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id(&m_hDB);
}
if (mysql_real_query(&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
p->uiSQLErrno = mysql_errno(&m_hDB);
sys_err("AsyncSQL: query failed: %s (query: %s errno: %d)",
mysql_error(&m_hDB), p->stQuery.c_str(), p->uiSQLErrno);
switch (p->uiSQLErrno)
{
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_IPSOCK_ERROR:
case CR_UNKNOWN_HOST:
case CR_SERVER_GONE_ERROR:
case CR_CONN_HOST_ERROR:
case ER_NOT_KEYFILE:
case ER_CRASHED_ON_USAGE:
case ER_CANT_OPEN_FILE:
case ER_HOST_NOT_PRIVILEGED:
case ER_HOST_IS_BLOCKED:
case ER_PASSWORD_NOT_ALLOWED:
case ER_PASSWORD_NO_MATCH:
case ER_CANT_CREATE_THREAD:
case ER_INVALID_USE_OF_NULL:
m_sem.Release();
sys_err("AsyncSQL: retrying");
continue;
}
}
profiler.Stop();
// 0.5초 이상 걸렸으면 로그에 남기기
if (!profiler.IsOk())
sys_log(0, "[QUERY : LONG INTERVAL(OverSec %ld.%ld)] : %s",
profiler.GetResultSec(), profiler.GetResultUSec(), p->stQuery.c_str());
PopQueryFromCopyQueue();
if (p->bReturn)
{
p->Store();
PushResult(p);
}
else
delete p;
++m_iQueryFinished;
}
}
SQLMsg * p;
while (PeekQuery(&p))
{
if (m_ulThreadID != mysql_thread_id(&m_hDB))
{
sys_err("MySQL connection was reconnected. querying locale set");
while (!QueryLocaleSet());
m_ulThreadID = mysql_thread_id(&m_hDB);
}
if (mysql_real_query(&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
{
p->uiSQLErrno = mysql_errno(&m_hDB);
sys_err("AsyncSQL::ChildLoop : mysql_query error: %s:\nquery: %s",
mysql_error(&m_hDB), p->stQuery.c_str());
switch (p->uiSQLErrno)
{
case CR_SOCKET_CREATE_ERROR:
case CR_CONNECTION_ERROR:
case CR_IPSOCK_ERROR:
case CR_UNKNOWN_HOST:
case CR_SERVER_GONE_ERROR:
case CR_CONN_HOST_ERROR:
case ER_NOT_KEYFILE:
case ER_CRASHED_ON_USAGE:
case ER_CANT_OPEN_FILE:
case ER_HOST_NOT_PRIVILEGED:
case ER_HOST_IS_BLOCKED:
case ER_PASSWORD_NOT_ALLOWED:
case ER_PASSWORD_NO_MATCH:
case ER_CANT_CREATE_THREAD:
case ER_INVALID_USE_OF_NULL:
continue;
}
}
sys_log(0, "QUERY_FLUSH: %s", p->stQuery.c_str());
PopQuery(p->iID);
if (p->bReturn)
{
p->Store();
PushResult(p);
}
else
delete p;
++m_iQueryFinished;
}
}
int CAsyncSQL::CountQueryFinished()
{
return m_iQueryFinished;
}
void CAsyncSQL::ResetQueryFinished()
{
m_iQueryFinished = 0;
}
MYSQL * CAsyncSQL::GetSQLHandle()
{
return &m_hDB;
}
size_t CAsyncSQL::EscapeString(char* dst, size_t dstSize, const char *src, size_t srcSize)
{
if (0 == srcSize)
{
memset(dst, 0, dstSize);
return 0;
}
if (0 == dstSize)
return 0;
if (dstSize < srcSize * 2 + 1)
{
// \0이 안붙어있을 때를 대비해서 256 바이트만 복사해서 로그로 출력
char tmp[256];
size_t tmpLen = sizeof(tmp) > srcSize ? srcSize : sizeof(tmp); // 둘 중에 작은 크기
strlcpy(tmp, src, tmpLen);
sys_err("FATAL ERROR!! not enough buffer size (dstSize %u srcSize %u src%s: %s)",
dstSize, srcSize, tmpLen != srcSize ? "(trimmed to 255 characters)" : "", tmp);
dst[0] = '\0';
return 0;
}
return mysql_real_escape_string(GetSQLHandle(), dst, src, srcSize);
}
void CAsyncSQL2::SetLocale(const std::string & stLocale)
{
m_stLocale = stLocale;
QueryLocaleSet();
}
+210
View File
@@ -0,0 +1,210 @@
#ifndef __INC_METIN_II_ASYNCSQL_H__
#define __INC_METIN_II_ASYNCSQL_H__
#include "../libthecore/include/stdafx.h"
#include "../libthecore/include/log.h"
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <mysql/mysql.h>
#include <mysql/errmsg.h>
#include <mysql/mysqld_error.h>
#include "Semaphore.h"
#define QUERY_MAX_LEN 8192
typedef struct _SQLResult
{
_SQLResult()
: pSQLResult(NULL), uiNumRows(0), uiAffectedRows(0), uiInsertID(0)
{
}
~_SQLResult()
{
if (pSQLResult)
{
mysql_free_result(pSQLResult);
pSQLResult = NULL;
}
}
MYSQL_RES * pSQLResult;
uint32_t uiNumRows;
uint32_t uiAffectedRows;
uint32_t uiInsertID;
} SQLResult;
typedef struct _SQLMsg
{
_SQLMsg() : m_pkSQL(NULL), iID(0), uiResultPos(0), pvUserData(NULL), bReturn(false), uiSQLErrno(0)
{
}
~_SQLMsg()
{
std::vector<SQLResult *>::iterator first = vec_pkResult.begin();
std::vector<SQLResult *>::iterator past = vec_pkResult.end();
while (first != past)
delete *(first++);
vec_pkResult.clear();
}
void Store()
{
do
{
SQLResult * pRes = new SQLResult;
pRes->pSQLResult = mysql_store_result(m_pkSQL);
pRes->uiInsertID = mysql_insert_id(m_pkSQL);
pRes->uiAffectedRows = mysql_affected_rows(m_pkSQL);
if (pRes->pSQLResult)
{
pRes->uiNumRows = mysql_num_rows(pRes->pSQLResult);
}
else
{
pRes->uiNumRows = 0;
}
vec_pkResult.push_back(pRes);
} while (!mysql_next_result(m_pkSQL));
}
SQLResult * Get()
{
if (uiResultPos >= vec_pkResult.size())
return NULL;
return vec_pkResult[uiResultPos];
}
bool Next()
{
if (uiResultPos + 1 >= vec_pkResult.size())
return false;
++uiResultPos;
return true;
}
MYSQL * m_pkSQL;
int iID;
std::string stQuery;
std::vector<SQLResult *> vec_pkResult; // result º¤ÅÍ
unsigned int uiResultPos; // ÇöÀç result À§Ä¡
void * pvUserData;
bool bReturn;
unsigned int uiSQLErrno;
} SQLMsg;
class CAsyncSQL
{
public:
CAsyncSQL();
virtual ~CAsyncSQL();
void Quit();
bool Setup(const char * c_pszHost, const char * c_pszUser, const char * c_pszPassword, const char * c_pszDB, const char * c_pszLocale,
bool bNoThread = false, int iPort = 0);
bool Setup(CAsyncSQL * sql, bool bNoThread = false);
bool Connect();
bool IsConnected() { return m_bConnected; }
bool QueryLocaleSet();
void AsyncQuery(const char * c_pszQuery);
void ReturnQuery(const char * c_pszQuery, void * pvUserData);
SQLMsg * DirectQuery(const char * c_pszQuery);
DWORD CountQuery();
DWORD CountResult();
void PushResult(SQLMsg * p);
bool PopResult(SQLMsg ** pp);
void ChildLoop();
MYSQL * GetSQLHandle();
int CountQueryFinished();
void ResetQueryFinished();
size_t EscapeString(char* dst, size_t dstSize, const char *src, size_t srcSize);
protected:
void Destroy();
void PushQuery(SQLMsg * p);
bool PeekQuery(SQLMsg ** pp);
bool PopQuery(int iID);
bool PeekQueryFromCopyQueue(SQLMsg ** pp );
INT CopyQuery();
bool PopQueryFromCopyQueue();
public:
int GetCopiedQueryCount();
void ResetCopiedQueryCount();
void AddCopiedQueryCount( int iCopiedQuery );
//private:
protected:
MYSQL m_hDB;
std::string m_stHost;
std::string m_stUser;
std::string m_stPassword;
std::string m_stDB;
std::string m_stLocale;
int m_iMsgCount;
int m_aiPipe[2];
int m_iPort;
std::queue<SQLMsg *> m_queue_query;
std::queue<SQLMsg *> m_queue_query_copy;
//std::map<int, SQLMsg *> m_map_kSQLMsgUnfinished;
std::queue<SQLMsg *> m_queue_result;
volatile bool m_bEnd;
#ifndef __WIN32__
pthread_t m_hThread;
pthread_mutex_t * m_mtxQuery;
pthread_mutex_t * m_mtxResult;
#else
HANDLE m_hThread;
CRITICAL_SECTION* m_mtxQuery;
CRITICAL_SECTION* m_mtxResult;
#endif
CSemaphore m_sem;
int m_iQueryFinished;
unsigned long m_ulThreadID;
bool m_bConnected;
int m_iCopiedQuery;
};
class CAsyncSQL2 : public CAsyncSQL
{
public:
void SetLocale ( const std::string & stLocale );
};
#endif
+48
View File
@@ -0,0 +1,48 @@
AsyncSQL.o: AsyncSQL.cpp AsyncSQL.h ../libthecore/include/stdafx.h \
../libthecore/include/typedef.h ../libthecore/include/heart.h \
../libthecore/include/fdwatch.h ../libthecore/include/socket.h \
../libthecore/include/kstbl.h ../libthecore/include/hangul.h \
../libthecore/include/buffer.h ../libthecore/include/signal.h \
../libthecore/include/log.h ../libthecore/include/main.h \
../libthecore/include/utils.h ../libthecore/include/crypt.h \
../libthecore/include/memcpy.h /usr/local/include/mysql/mysql.h \
/usr/local/include/mysql/mariadb_com.h \
/usr/local/include/mysql/mariadb_version.h \
/usr/local/include/mysql/ma_list.h \
/usr/local/include/mysql/mariadb_ctype.h \
/usr/local/include/mysql/mariadb_stmt.h \
/usr/local/include/mysql/errmsg.h \
/usr/local/include/mysql/mysqld_error.h Semaphore.h
Semaphore.o: Semaphore.cpp stdafx.h ../libthecore/include/stdafx.h \
../libthecore/include/typedef.h ../libthecore/include/heart.h \
../libthecore/include/fdwatch.h ../libthecore/include/socket.h \
../libthecore/include/kstbl.h ../libthecore/include/hangul.h \
../libthecore/include/buffer.h ../libthecore/include/signal.h \
../libthecore/include/log.h ../libthecore/include/main.h \
../libthecore/include/utils.h ../libthecore/include/crypt.h \
../libthecore/include/memcpy.h AsyncSQL.h \
/usr/local/include/mysql/mysql.h \
/usr/local/include/mysql/mariadb_com.h \
/usr/local/include/mysql/mariadb_version.h \
/usr/local/include/mysql/ma_list.h \
/usr/local/include/mysql/mariadb_ctype.h \
/usr/local/include/mysql/mariadb_stmt.h \
/usr/local/include/mysql/errmsg.h \
/usr/local/include/mysql/mysqld_error.h Semaphore.h
Statement.o: Statement.cpp Statement.h AsyncSQL.h \
../libthecore/include/stdafx.h ../libthecore/include/typedef.h \
../libthecore/include/heart.h ../libthecore/include/fdwatch.h \
../libthecore/include/socket.h ../libthecore/include/kstbl.h \
../libthecore/include/hangul.h ../libthecore/include/buffer.h \
../libthecore/include/signal.h ../libthecore/include/log.h \
../libthecore/include/main.h ../libthecore/include/utils.h \
../libthecore/include/crypt.h ../libthecore/include/memcpy.h \
/usr/local/include/mysql/mysql.h \
/usr/local/include/mysql/mariadb_com.h \
/usr/local/include/mysql/mariadb_version.h \
/usr/local/include/mysql/ma_list.h \
/usr/local/include/mysql/mariadb_ctype.h \
/usr/local/include/mysql/mariadb_stmt.h \
/usr/local/include/mysql/errmsg.h \
/usr/local/include/mysql/mysqld_error.h Semaphore.h
Tellwait.o: Tellwait.cpp
+86
View File
@@ -0,0 +1,86 @@
#CXX = distcc i386-obrien-freebsd5-g++
PLATFORM = $(shell file /bin/ls | cut -d' ' -f3 | cut -d'-' -f1)
BSD_VERSION = $(shell uname -v 2>&1 | cut -d' ' -f2 | cut -d'.' -f1)
SVN_VERSION = $(shell svnversion -n -c . | cut -d':' -f2)
BIN = ./libsql.a
# ---------------------------------------------------------------------------
# ### LINUX-BLOCK-BEGIN (Makefile platform detection)
# FreeBSD takes the else branch, which is verbatim the original: CXX,
# GCC_VERSION, IFLAGS = -I/usr/local/include (where the FreeBSD MySQL port puts
# its headers) and the original CFLAGS.
# ---------------------------------------------------------------------------
UNAME_S := $(shell uname -s)
# 32-bit third-party tree; same relative convention as game/src/Makefile's
# "-I../../../extern/include", with the Linux subdirectory appended.
EXTERN_DIR ?= ../../../extern/Linux40250
ifeq ($(UNAME_S),Linux)
CXX = g++
GCC_VERSION = $(shell $(CC) --version 2>&1 | grep "(GCC)" | cut -d' ' -f3 | cut -d'.' -f1)
# AsyncSQL.h includes <mysql/mysql.h>, <mysql/errmsg.h> and
# <mysql/mysqld_error.h>. On FreeBSD those live under /usr/local/include; here
# they are the MariaDB Connector/C headers shipped with the 32-bit extern tree,
# so the include root is $(EXTERN_DIR)/include and the "mysql/" prefix in the
# sources resolves unchanged. MariaDB Connector/C still defines my_bool and
# still accepts MYSQL_OPT_RECONNECT, so AsyncSQL.cpp needs no source change.
IFLAGS = -I$(EXTERN_DIR)/include
CFLAGS = $(IFLAGS) -Wall -O2 -pipe -mtune=i686 -m32 -std=c++23 -D_GLIBCXX_USE_CXX11_ABI=1 -D_THREAD_SAFE -fno-exceptions
ARFLAGS_SQL = cr
# The checked-in Depend was generated on FreeBSD and names
# /usr/local/include/mysql/*.h by absolute path. Those files do not exist on
# Linux, so "sinclude Depend" makes gmake abort with
# "No rule to make target '/usr/local/include/mysql/mysql.h'".
# Use a separate, Linux-generated dependency file and leave the FreeBSD one
# exactly as it is. ("make dep" writes whichever file this platform uses.)
DEPFILE = Depend.linux
else
CXX = clang++-devel
GCC_VERSION = $(shell $(CC) --version 2>&1 | grep "(GCC)" | cut -d' ' -f3 | cut -d'.' -f1)
IFLAGS = -I/usr/local/include
CFLAGS = $(IFLAGS) -Wall -O2 -pipe -mtune=i686 -D_GLIBCXX_USE_CXX11_ABI=1 -D_THREAD_SAFE -fno-exceptions
ARFLAGS_SQL = cru
DEPFILE = Depend
endif
# ### LINUX-BLOCK-END (Makefile platform detection)
LIBS =
OBJFILES = AsyncSQL.o Semaphore.o Tellwait.o Statement.o
default:
$(MAKE) $(BIN)
$(BIN): $(OBJFILES)
ar $(ARFLAGS_SQL) $(BIN) $(OBJFILES) $(LIBS)
ranlib $(BIN)
chmod 700 $(BIN)
clean:
rm -f *.o
rm -f $(BIN)
dep:
touch $(DEPFILE)
$(CXX) $(CFLAGS) -MM *.cpp > $(DEPFILE)
$(OBJFILES):
$(CXX) $(CFLAGS) -c $<
sinclude $(DEPFILE)
+142
View File
@@ -0,0 +1,142 @@
#include "stdafx.h"
#include "Semaphore.h"
#ifndef __WIN32__
CSemaphore::CSemaphore() : m_hSem(NULL)
{
Initialize();
}
CSemaphore::~CSemaphore()
{
Destroy();
}
int CSemaphore::Initialize()
{
Clear();
m_hSem = new sem_t;
if (sem_init(m_hSem, 0, 0) == -1)
{
perror("sem_init");
return false;
}
return true;
}
void CSemaphore::Destroy()
{
Clear();
}
void CSemaphore::Clear()
{
if (m_hSem)
{
sem_destroy(m_hSem);
delete m_hSem;
}
m_hSem = NULL;
}
int CSemaphore::Wait()
{
if (!m_hSem)
return true;
int re = sem_wait(m_hSem);
if (re == -1)
{
if (errno == EINTR)
return Wait();
perror("sem_wait");
return false;
}
return true;
}
int CSemaphore::Release(int count)
{
if (!m_hSem)
return false;
for (int i = 0; i < count; ++i)
sem_post(m_hSem);
return true;
}
#else
CSemaphore::CSemaphore() : m_hSem(NULL)
{
Initialize();
}
CSemaphore::~CSemaphore()
{
Destroy();
}
int CSemaphore::Initialize()
{
Clear();
m_hSem = ::CreateSemaphore(NULL, 0, 32, NULL);
if (m_hSem == NULL) {
return false;
}
return true;
}
void CSemaphore::Destroy()
{
Clear();
}
void CSemaphore::Clear()
{
if (m_hSem == NULL) {
return;
}
::CloseHandle(m_hSem);
m_hSem = NULL;
}
int CSemaphore::Wait()
{
if (!m_hSem)
return true;
DWORD dwWaitResult = ::WaitForSingleObject(m_hSem, INFINITE);
switch (dwWaitResult) {
case WAIT_OBJECT_0:
return true;
default:
break;
}
return false;
}
int CSemaphore::Release(int count)
{
if (!m_hSem)
return false;
::ReleaseSemaphore(m_hSem, count, NULL);
return true;
}
#endif
+29
View File
@@ -0,0 +1,29 @@
#ifndef __INC_METIN_II_SEMAPHORE_H__
#define __INC_METIN_II_SEMAPHORE_H__
#ifndef __WIN32__
#include <semaphore.h>
#else
#endif
class CSemaphore
{
private:
#ifndef __WIN32__
sem_t * m_hSem;
#else
HANDLE m_hSem;
#endif
public:
CSemaphore();
~CSemaphore();
int Initialize();
void Clear();
void Destroy();
int Wait();
int Release(int count = 1);
};
#endif
+159
View File
@@ -0,0 +1,159 @@
#include "Statement.h"
#include <cstdlib>
#include <cstring>
CStmt::CStmt()
{
m_pkStmt = NULL;
m_uiParamCount = 0;
m_uiResultCount = 0;
iRows = 0;
m_puiParamLen = NULL;
}
CStmt::~CStmt()
{
Destroy();
}
void CStmt::Destroy()
{
if (m_pkStmt)
{
mysql_stmt_close(m_pkStmt);
m_pkStmt = NULL;
}
if (m_puiParamLen)
{
free(m_puiParamLen);
m_puiParamLen = NULL;
}
}
void CStmt::Error(const char * c_pszMsg)
{
sys_log(0, "SYSERR: %s: [%d] %s", c_pszMsg, mysql_stmt_errno(m_pkStmt), mysql_stmt_error(m_pkStmt));
}
bool CStmt::Prepare(CAsyncSQL * sql, const char * c_pszQuery)
{
m_pkStmt = mysql_stmt_init(sql->GetSQLHandle());
m_stQuery = c_pszQuery;
if (mysql_stmt_prepare(m_pkStmt, m_stQuery.c_str(), m_stQuery.length()))
{
Error("mysql_stmt_prepare");
return false;
}
int iParamCount = 0;
for (unsigned int i = 0; i < m_stQuery.length(); ++i)
if (c_pszQuery[i] == '?')
++iParamCount;
if (iParamCount)
{
m_vec_param.resize(iParamCount);
memset(&m_vec_param[0], 0, sizeof(MYSQL_BIND) * iParamCount);
m_puiParamLen = (long unsigned int *) calloc(iParamCount, sizeof(long unsigned int));
}
m_vec_result.resize(48);
memset(&m_vec_result[0], 0, sizeof(MYSQL_BIND) * 48);
if (mysql_stmt_bind_result(m_pkStmt, &m_vec_result[0]))
{
Error("mysql_stmt_bind_result");
return 0;
}
return true;
}
bool CStmt::BindParam(enum_field_types type, void * p, int iMaxLen)
{
if (m_uiParamCount >= m_vec_param.size())
{
sys_err("too many parameter in query: %s", m_stQuery.c_str());
return false;
}
MYSQL_BIND * bind = &m_vec_param[m_uiParamCount];
bind->buffer_type = type;
bind->buffer = (void *) p;
bind->buffer_length = iMaxLen;
bind->length = m_puiParamLen + m_uiParamCount;
if (++m_uiParamCount == m_vec_param.size())
{
if (mysql_stmt_bind_param(m_pkStmt, &m_vec_param[0]))
{
Error("mysql_stmt_bind_param");
return false;
}
}
return true;
}
bool CStmt::BindResult(enum_field_types type, void * p, int iMaxLen)
{
if (m_uiResultCount >= m_vec_result.size())
{
sys_err("too many result in query: %s", m_stQuery.c_str());
return false;
}
MYSQL_BIND * bind = &m_vec_result[m_uiResultCount++];
bind->buffer_type = type;
bind->buffer = (void *) p;
bind->buffer_length = iMaxLen;
return true;
}
int CStmt::Execute()
{
if (m_uiParamCount != m_vec_param.size())
{
sys_log(0, "Parameter not enough %d, expected %d query: %s", m_uiParamCount, m_vec_param.size(), m_stQuery.c_str());
return 0;
}
for (unsigned int i = 0; i < m_uiParamCount; ++i)
{
MYSQL_BIND * bind = &m_vec_param[i];
if (bind->buffer_type == MYSQL_TYPE_STRING)
{
*(m_puiParamLen + i) = strlen((const char *) bind->buffer);
sys_log(0, "param %d len %d buf %s", i, *m_puiParamLen, (const char *) bind->buffer);
}
}
if (mysql_stmt_execute(m_pkStmt))
{
Error("mysql_stmt_execute");
return 0;
}
if (mysql_stmt_store_result(m_pkStmt))
{
Error("mysql_store_result");
return 0;
}
iRows = mysql_stmt_num_rows(m_pkStmt);
return true;
}
bool CStmt::Fetch()
{
return !mysql_stmt_fetch(m_pkStmt);
}
+41
View File
@@ -0,0 +1,41 @@
#ifndef __INC_METIN_II_LIBSQL_STATEMENT_H__
#define __INC_METIN_II_LIBSQL_STATEMENT_H__
#include "AsyncSQL.h"
#include <string>
#include <vector>
class CStmt
{
public:
CStmt();
virtual ~CStmt();
bool Prepare(CAsyncSQL * sql, const char * c_pszQuery);
bool BindParam(enum_field_types type, void * p, int iMaxLen=0);
bool BindResult(enum_field_types type, void * p, int iMaxLen=0);
int Execute();
bool Fetch();
void Error(const char * c_pszMsg);
public:
int iRows;
private:
void Destroy();
MYSQL_STMT * m_pkStmt;
std::string m_stQuery;
std::vector<MYSQL_BIND> m_vec_param;
unsigned int m_uiParamCount;
long unsigned int * m_puiParamLen;
std::vector<MYSQL_BIND> m_vec_result;
unsigned int m_uiResultCount;
};
#endif
+87
View File
@@ -0,0 +1,87 @@
#ifndef __WIN32__
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static volatile sig_atomic_t sigflag;
/* set nonzero by signal handler */
static sigset_t newmask, oldmask, zeromask;
static void sig_usr(int signo) /* one signal handler for SIGUSR1 and SIGUSR2 */
{
sigflag = 1;
return;
}
void TELL_WAIT()
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
{
fprintf(stderr, "signal(SIGINT) error\n");
exit(1);
}
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
{
fprintf(stderr, "signal(SIGQUIT) error\n");
exit(1);
}
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGUSR1);
sigaddset(&newmask, SIGUSR2);
/* block SIGUSR1 and SIGUSR2, and save current signal mask */
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
{
fprintf(stderr, "SIG_BLOCK error\n");
exit(1);
}
}
void TELL_PARENT(pid_t pid)
{
kill(pid, SIGUSR2); /* tell parent we're done */
}
void WAIT_PARENT(void)
{
while (sigflag == 0)
sigsuspend(&zeromask); /* and wait for parent */
sigflag = 0;
/* reset signal mask to original value */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
{
fprintf(stderr, "SIG_SETMASK error\n");
exit(1);
}
}
void TELL_CHILD(pid_t pid)
{
kill(pid, SIGUSR1); /* tell child we're done */
}
void WAIT_CHILD(void)
{
while (sigflag == 0)
sigsuspend(&zeromask); /* and wait for child */
sigflag = 0;
/* reset signal mask to original value */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
{
fprintf(stderr, "SIG_SETMASK error\n");
exit(1);
}
}
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef __INC_METIN_II_TELLWAIT_H__
#define __INC_METIN_II_TELLWAIT_H__
#ifndef __WIN32__
extern void TELL_WAIT();
extern void WAIT_CHILD();
extern void TELL_CHILD(pid_t pid);
extern void WAIT_PARENT();
extern void TELL_PARENT(pid_t pid);
#endif
#endif
+210
View File
@@ -0,0 +1,210 @@
<?xml version="1.0" encoding="ks_c_5601-1987"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="libsql"
ProjectGUID="{3967853D-4E19-4548-AC3A-F6012B78E384}"
RootNamespace="libsql"
SccProjectName="SAK"
SccAuxPath="SAK"
SccLocalPath="SAK"
SccProvider="SAK"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(ProjectDir)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="$(ProjectDir)../libmysql/6.0.2/win32;$(ProjectDir)../../Extern/include;"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;__WIN32__;_USE_32BIT_TIME_T"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)\$(TargetName).pdb"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)\$(ProjectName)_d.lib"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(ProjectDir)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="$(ProjectDir)../libmysql/6.0.2/win32;../external"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;__WIN32__"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
ProgramDataBaseFileName="$(OutDir)\$(TargetName).pdb"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\AsyncSQL.cpp"
>
</File>
<File
RelativePath=".\Semaphore.cpp"
>
</File>
<File
RelativePath=".\Statement.cpp"
>
</File>
<File
RelativePath=".\Tellwait.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\AsyncSQL.h"
>
</File>
<File
RelativePath=".\libsql.h"
>
</File>
<File
RelativePath=".\Semaphore.h"
>
</File>
<File
RelativePath=".\Statement.h"
>
</File>
<File
RelativePath=".\stdafx.h"
>
</File>
<File
RelativePath=".\Tellwait.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+10
View File
@@ -0,0 +1,10 @@
""
{
"FILE_VERSION" = "9237"
"ENLISTMENT_CHOICE" = "NEVER"
"PROJECT_FILE_RELATIVE_PATH" = ""
"NUMBER_OF_EXCLUDED_FILES" = "0"
"ORIGINAL_PROJECT_FILE_PATH" = ""
"NUMBER_OF_NESTED_PROJECTS" = "0"
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
}
+1
View File
@@ -0,0 +1 @@
#include "AsyncSQL.h"
+2
View File
@@ -0,0 +1,2 @@
#include "../libthecore/include/stdafx.h"
#include "AsyncSQL.h"