410 lines
11 KiB
C++
410 lines
11 KiB
C++
#include "stdafx.h"
|
|
#include "BotIPC.h"
|
|
#include "Logger.h"
|
|
|
|
|
|
void BotInfo_Initialize( BOT_INFO *b, const wchar_t *charName, unsigned int charOid, unsigned int classId, int level )
|
|
{
|
|
memset( b, 0, sizeof(BOT_INFO) );
|
|
wcsncpy( b->charName, charName, 127 ); b->charName[127] = 0;
|
|
b->classId = classId;
|
|
b->level = level;
|
|
b->charOid = charOid;
|
|
b->isMaster = b->isSlave = false;
|
|
b->assistEnable = b->followEnable = false;
|
|
b->processId = GetCurrentProcessId();
|
|
}
|
|
|
|
LONG BotIPC_ExceptionHandler( const char *funcName, LPEXCEPTION_POINTERS ep )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC: ExceptionHandler invoked from function [%s]: exc: 0x%08X at 0x%p\n",
|
|
funcName,
|
|
ep->ExceptionRecord->ExceptionCode,
|
|
ep->ExceptionRecord->ExceptionAddress );
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
|
|
|
|
int BotIPC::s_refCount = 0;
|
|
BotIPC *BotIPC::s_instance = NULL;
|
|
|
|
BotIPC *BotIPC::getInstance()
|
|
{
|
|
if( !BotIPC::s_instance )
|
|
{
|
|
BotIPC::s_instance = new BotIPC();
|
|
BotIPC::s_refCount++;
|
|
log_error( LOG_DEBUG, "BotIPC: instance created\n" );
|
|
}
|
|
return BotIPC::s_instance;
|
|
}
|
|
|
|
|
|
void BotIPC::freeInstance()
|
|
{
|
|
if( BotIPC::s_instance )
|
|
{
|
|
BotIPC::s_refCount--;
|
|
if( BotIPC::s_refCount == 0 )
|
|
{
|
|
delete BotIPC::s_instance;
|
|
BotIPC::s_instance = NULL;
|
|
log_error( LOG_DEBUG, "BotIPC: instance deleted\n" );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BotIPC::BotIPC()
|
|
{
|
|
#ifdef _DEBUG
|
|
log_error( LOG_DEBUG, "BotIPC: one bot info size : %u\n", sizeof(BOT_INFO) );
|
|
log_error( LOG_DEBUG, "BotIPC: shared mem size : %u\n", sizeof(BOT_IPC_DESCRIPTOR) );
|
|
#endif
|
|
iAmCreator = false;
|
|
isLocked = false;
|
|
hMutex = hMapping = NULL;
|
|
map = NULL;
|
|
// try to open mutex
|
|
hMutex = OpenMutex( SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, BOTIPC_MUTEX_NAME );
|
|
if( !hMutex )
|
|
{
|
|
DWORD le = GetLastError();
|
|
if( le != ERROR_FILE_NOT_FOUND )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::BotIPC(): OpenMutex() failed: %u\n", le );
|
|
ErrorLogger_LogLastError( "OpenMutex()", le );
|
|
return;
|
|
}
|
|
log_error( LOG_DEBUG, "BotIPC::BotIPC(): mutex not exists, creating...\n" );
|
|
hMutex = CreateMutex( NULL, FALSE, BOTIPC_MUTEX_NAME );
|
|
if( !hMutex )
|
|
{
|
|
ErrorLogger_LogLastError( "CreateMutex() failed!", GetLastError() );
|
|
return;
|
|
}
|
|
}
|
|
// try to open file mapping
|
|
hMapping = OpenFileMapping( FILE_MAP_READ | FILE_MAP_WRITE, FALSE, BOTIPC_MAPPING_NAME );
|
|
if( !hMapping )
|
|
{
|
|
DWORD le = GetLastError();
|
|
if( le != ERROR_FILE_NOT_FOUND )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::BotIPC(): OpenFileMapping() failed: %u\n", le );
|
|
ErrorLogger_LogLastError( "OpenFileMapping()", le );
|
|
return;
|
|
}
|
|
log_error( LOG_DEBUG, "BotIPC::BotIPC(): file mapping not exists, creating...\n" );
|
|
hMapping = CreateFileMapping( INVALID_HANDLE_VALUE, // page file
|
|
NULL, PAGE_READWRITE | SEC_COMMIT, 0,
|
|
sizeof(BOT_IPC_DESCRIPTOR), BOTIPC_MAPPING_NAME );
|
|
if( !hMapping )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::BotIPC(): CreateFileMapping() failed!\n", le );
|
|
ErrorLogger_LogLastError( "v()", GetLastError() );
|
|
return;
|
|
}
|
|
iAmCreator = true;
|
|
}
|
|
map = MapViewOfFile( hMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(BOT_IPC_DESCRIPTOR) );
|
|
if( !map )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::BotIPC(): MapViewOfFile() failed!" );
|
|
ErrorLogger_LogLastError( "MapViewOfFile()", GetLastError() );
|
|
}
|
|
//
|
|
BOT_IPC_DESCRIPTOR *desc = (BOT_IPC_DESCRIPTOR *)map;
|
|
if( iAmCreator ) // we created shmem, init it
|
|
{
|
|
Lock(); // lock reads/writes
|
|
desc->dwSize = sizeof(BOT_IPC_DESCRIPTOR);
|
|
desc->dwCreatorPid = GetCurrentProcessId();
|
|
desc->uBotCount = 0; // no BOT_INFO structures while
|
|
int i = 0;
|
|
while( i<BOT_IPC_MAX_BOTS ) desc->bot[i++].charOid = 0;
|
|
LockRelease(); // unlock
|
|
log_error( LOG_OK, "BotIPC: created shared mem!\n" );
|
|
}
|
|
else
|
|
{
|
|
log_error( LOG_DEBUG, "BotIPC: opened existing shared mem, creator PID: %u; number of bots: %u\n",
|
|
desc->dwCreatorPid, desc->uBotCount );
|
|
}
|
|
ErrorLogger_FlushLogFile();
|
|
}
|
|
|
|
|
|
BotIPC::~BotIPC()
|
|
{
|
|
if( map )
|
|
{
|
|
if( !UnmapViewOfFile( map ) ) ErrorLogger_LogLastError( "UnmapViewOfFile()", GetLastError() );
|
|
map = NULL;
|
|
log_error( LOG_DEBUG, "BotIPC::~BotIPC(): shared memory view unmapped\n" );
|
|
}
|
|
if( hMutex )
|
|
{
|
|
LockRelease();
|
|
CloseHandle( hMutex );
|
|
hMutex = NULL;
|
|
log_error( LOG_DEBUG, "BotIPC::~BotIPC(): mutex closed\n" );
|
|
}
|
|
if( hMapping )
|
|
{
|
|
CloseHandle( hMapping );
|
|
hMapping = NULL;
|
|
log_error( LOG_DEBUG, "BotIPC::~BotIPC(): mapping closed\n" );
|
|
}
|
|
iAmCreator = false;
|
|
isLocked = false;
|
|
}
|
|
|
|
|
|
BOT_IPC_DESCRIPTOR *BotIPC::getDescriptor()
|
|
{
|
|
if( !map )
|
|
{
|
|
log_error( LOG_WARNING, "BotIPC::getDescriptor(): failed, because shared mem is not mapped!\n" );
|
|
return NULL;
|
|
}
|
|
return (BOT_IPC_DESCRIPTOR *)map;
|
|
}
|
|
|
|
|
|
bool BotIPC::amICreator() const
|
|
{
|
|
return iAmCreator;
|
|
}
|
|
|
|
|
|
|
|
int BotIPC::addBotInfo( const BOT_INFO *b )
|
|
{
|
|
if( !b ) return false;
|
|
BOT_IPC_DESCRIPTOR *d = getDescriptor();
|
|
if( !d ) return -1;
|
|
if( !Lock() ) return -1;
|
|
int added_idx = -1;
|
|
__try
|
|
{
|
|
if( d->uBotCount < BOT_IPC_MAX_BOTS )
|
|
{
|
|
// find unused bot info slot
|
|
int i;
|
|
for( i=0; i<BOT_IPC_MAX_BOTS; i++ ) if( d->bot[i].charOid == 0 ) { added_idx = i; break; }
|
|
if( added_idx == -1 )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::addBotInfo(): ERROR: cannot find free slot to add!\n" );
|
|
}
|
|
else
|
|
{
|
|
memcpy( (void *)&(d->bot[added_idx]), (const void *)b, sizeof(BOT_INFO) );
|
|
d->uBotCount++; // new one bot added
|
|
}
|
|
}
|
|
else
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::addBotInfo(): failed beacuse mex bot count (%d) reached!\n", BOT_IPC_MAX_BOTS );
|
|
}
|
|
}
|
|
__except( BotIPC_ExceptionHandler( "addBotInfo()", GetExceptionInformation() ) ) {}
|
|
LockRelease();
|
|
return added_idx;
|
|
}
|
|
|
|
|
|
bool BotIPC::getBotInfo( int index, BOT_INFO *b )
|
|
{
|
|
if( !b ) return false;
|
|
if( index<0 || index>=BOT_IPC_MAX_BOTS )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::getBotInfo( index = %d ): invalid index\n", index );
|
|
return false;
|
|
}
|
|
BOT_IPC_DESCRIPTOR *d = getDescriptor();
|
|
if( !d )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::getBotInfo( index = %d ): shared mem not mapped!\n", index );
|
|
return false;
|
|
}
|
|
if( !Lock() ) return false;
|
|
__try
|
|
{
|
|
BOT_INFO *src = &(d->bot[index]);
|
|
memcpy( (void *)b, (const void *)src, sizeof(BOT_INFO) );
|
|
}
|
|
__except( BotIPC_ExceptionHandler( "getBotInfo()", GetExceptionInformation() ) ) {}
|
|
LockRelease();
|
|
return true;
|
|
}
|
|
|
|
|
|
bool BotIPC::setBotInfo( int index, const BOT_INFO *b )
|
|
{
|
|
if( !b ) return false;
|
|
if( index<0 || index>=BOT_IPC_MAX_BOTS )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::setBotInfo(): invalid index %d\n", index );
|
|
return false;
|
|
}
|
|
BOT_IPC_DESCRIPTOR *d = getDescriptor();
|
|
if( !d )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::setBotInfo(): shared mem not mapped!\n" );
|
|
return false;
|
|
}
|
|
if( !Lock() ) return false;
|
|
__try
|
|
{
|
|
BOT_INFO *dst = &(d->bot[index]);
|
|
memcpy( (void *)dst, (const void *)b, sizeof(BOT_INFO) );
|
|
}
|
|
__except( BotIPC_ExceptionHandler( "setBotInfo()", GetExceptionInformation() ) ) {}
|
|
LockRelease();
|
|
return true;
|
|
}
|
|
|
|
|
|
bool BotIPC::delBot( int index )
|
|
{
|
|
if( index<0 || index>=BOT_IPC_MAX_BOTS )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::delBot( int index = %d ): invalid index\n", index );
|
|
return false;
|
|
}
|
|
BOT_IPC_DESCRIPTOR *d = getDescriptor();
|
|
if( !d )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::delBot(): shared mem not mapped!\n" );
|
|
return false;
|
|
}
|
|
if( !Lock() ) return false;
|
|
bool ret = false;
|
|
__try
|
|
{
|
|
if( d->bot[index].charOid > 0 )
|
|
{
|
|
d->bot[index].charOid = 0;
|
|
ret = true;
|
|
}
|
|
else
|
|
{
|
|
ret = true;
|
|
log_error( LOG_WARNING, "BotIPC::delBot( %d ): charOid is already 0!\n", index );
|
|
}
|
|
}
|
|
__except( BotIPC_ExceptionHandler( "delBot()", GetExceptionInformation() ) ) {}
|
|
LockRelease();
|
|
return ret;
|
|
}
|
|
|
|
|
|
void BotIPC::delAllMyProcessBots()
|
|
{
|
|
log_error( LOG_DEBUG, "BotIPC::delAllMyProcessBots(): start\n" );
|
|
BOT_IPC_DESCRIPTOR *d = getDescriptor();
|
|
if( !d )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::delAllMyProcessBots(): shared mem not mapped!\n" );
|
|
return;
|
|
}
|
|
if( !Lock() )
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC::delAllMyProcessBots(): Lock failed!\n" );
|
|
ErrorLogger_FlushLogFile();
|
|
return;
|
|
}
|
|
int index = 0;
|
|
unsigned int myPid = GetCurrentProcessId();
|
|
int nFreed = 0;
|
|
__try
|
|
{
|
|
for( index=0; index<BOT_IPC_MAX_BOTS; index++ )
|
|
{
|
|
if( d->bot[index].processId == myPid )
|
|
{
|
|
d->bot[index].charOid = 0;
|
|
nFreed++;
|
|
log_error( LOG_DEBUG, "BotIPC::delAllMyProcessBots(): deleted bot index %d\n", index );
|
|
}
|
|
}
|
|
}
|
|
__except( BotIPC_ExceptionHandler( "delAllMyProcessBots()", GetExceptionInformation() ) ) {}
|
|
LockRelease();
|
|
log_error( LOG_DEBUG, "BotIPC::delAllMyProcessBots(): deleted %d my bots\n", nFreed );
|
|
}
|
|
|
|
void BotIPC::dumpToLog()
|
|
{
|
|
BOT_IPC_DESCRIPTOR *d = getDescriptor();
|
|
if( !d ) return;
|
|
if( !Lock() ) return;
|
|
__try
|
|
{
|
|
int idx;
|
|
log_error( LOG_DEBUG, "===== BotIPC::dumpToLog() =====\n" );
|
|
for( idx = 0; idx < BOT_IPC_MAX_BOTS; idx++ )
|
|
{
|
|
if( d->bot[idx].charOid > 0 )
|
|
{
|
|
log_error( LOG_DEBUG, "Bot %d: char: %S lvl %d (class %d %s) [isSlave: %d] [isMaster: %d]\n",
|
|
idx, d->bot[idx].charName, d->bot[idx].level, d->bot[idx].classId,
|
|
L2Data_getClass( d->bot[idx].classId ),
|
|
(int)d->bot[idx].isSlave, (int)d->bot[idx].isMaster );
|
|
}
|
|
}
|
|
log_error( LOG_DEBUG, "===== BotIPC::dumpToLog() END =====\n" );
|
|
}
|
|
__except( BotIPC_ExceptionHandler( "dumpToLog()", GetExceptionInformation() ) ) {}
|
|
LockRelease();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool BotIPC::Lock()
|
|
{
|
|
if( !hMutex ) return false;
|
|
if( isLocked ) return true;
|
|
DWORD wait_res = WaitForSingleObject( hMutex, 1000 );
|
|
if( wait_res == WAIT_OBJECT_0 )
|
|
{
|
|
isLocked = true;
|
|
return true;
|
|
}
|
|
// error handle
|
|
DWORD le = GetLastError();
|
|
log_error( LOG_ERROR, "BotIPC lock failed!!! possible fatal error, may need restarting all radars/bots!\n" );
|
|
switch( wait_res )
|
|
{
|
|
case WAIT_TIMEOUT: log_error( LOG_ERROR, "BotIPC lock: wait_res: WAIT_TIMEOUT!\n" ); break;
|
|
case WAIT_ABANDONED:
|
|
{
|
|
log_error( LOG_ERROR, "BotIPC lock: wait res: WAIT_TIMEOUT!\n" );
|
|
// but in this case we own mutex
|
|
log_error( LOG_WARNING, "Mutex wait abandoned, but now we own mutex... all OK\n" );
|
|
isLocked = true;
|
|
return true;
|
|
} break;
|
|
default: log_error( LOG_ERROR, "BotIPC lock: wait res: unk %u!\n", wait_res ); break;
|
|
}
|
|
ErrorLogger_LogLastError( "BotIPC lock: last error was: ", le );
|
|
return false;
|
|
}
|
|
|
|
void BotIPC::LockRelease()
|
|
{
|
|
if( !hMutex ) return;
|
|
if( !isLocked ) return;
|
|
if( !ReleaseMutex( hMutex ) )
|
|
{
|
|
log_error( LOG_WARNING, "BotIPC::LockRelease(): ReleaseMutex failed (not owner?)\n" );
|
|
ErrorLogger_LogLastError( "ReleaseMutex()", GetLastError() );
|
|
}
|
|
isLocked = false;
|
|
}
|
|
|