#include "stdafx.h" #include "SpBase.h" #include "SpTimer.h" #include "SpEntity.h" #include "SpModule.h" #ifdef WIN32 #include "SpBaseRoutine.h" #endif #include "SpMisc.h" #include "SpClientSessionFunction.h" #include "sockutil.h" #include "fileutil.h" #include "sp_shm.h" #include "sp_dbg_export.h" #include "sp_def.h" #include "sp_env.h" #include "DumpException.h" #ifdef _WIN32 #include "sp_checkEntity.h" #include #else #include #endif // _WIN32 #include #include #include #ifndef _WIN32 static SpModule* g_module = NULL; #endif //NOT _WIN32 SpModule *GetSpModule() { #ifdef _WIN32 SpModule *curModule = NULL; if (findThreadModule(GetCurrentThreadId(), (void **)&curModule)) return curModule; else { CSimpleStringA mod_name = TraceStack(); if (CSimpleStringA("") == mod_name) { return NULL; } SetthreadGroup(GetCurrentThreadId(), mod_name); if (findThreadModule(GetCurrentThreadId(), (void**)&curModule)) return curModule; } return NULL; #else return g_module; #endif //_WIN32 } #ifdef _WIN32 static LONG WINAPI SuppressError(struct _EXCEPTION_POINTERS* ExceptionInfo) { char tmp[MAX_PATH] = { '\0' }; char drivePath[_MAX_DRIVE] = {'\0'}; sp_dir_get_cur_drive(drivePath); wsprintfA(tmp, "%s\\rvc\\dmp\\expt.%s.%d.%d.log", drivePath, GetSpModule() ? GetSpModule()->get_mod()->cfg->name : "", GetCurrentThreadId(), GetCurrentProcessId()); HANDLE hLogFile = ::CreateFileA(tmp, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hLogFile != INVALID_HANDLE_VALUE) { DumpExceptionInfo(ExceptionInfo, hLogFile); FlushFileBuffers(hLogFile); SetEndOfFile(hLogFile); CloseHandle(hLogFile); } wsprintfA(tmp, "%s\\rvc\\dmp\\expt.%s.%d.%d.dmp", drivePath, GetSpModule() ? GetSpModule()->get_mod()->cfg->name : "", GetCurrentThreadId(), GetCurrentProcessId()); HANDLE hDumpFile = CreateFileA( tmp, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( ( hDumpFile != NULL ) && ( hDumpFile != INVALID_HANDLE_VALUE ) ) { MINIDUMP_EXCEPTION_INFORMATION mdei; mdei.ThreadId = GetCurrentThreadId(); mdei.ExceptionPointers = ExceptionInfo; mdei.ClientPointers = FALSE; MINIDUMP_TYPE mdt = MiniDumpWithIndirectlyReferencedMemory; BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, mdt, (ExceptionInfo != 0) ? &mdei : 0, 0, 0 ); CloseHandle( hDumpFile ); } Dbg("exit entity exception!"); ExitProcess(Error_Exception); // exit process to suppress reporting exception return EXCEPTION_EXECUTE_HANDLER; } static void DisableSetUnhandledExceptionFilter() { void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"), "SetUnhandledExceptionFilter"); if (addr) { DWORD dwOldFlag, dwTempFlag; unsigned char code[] = {0x33, 0xC0, 0xC2, 0x04, 0x00}; // xor eax,eax; ret 4; VirtualProtect(addr, sizeof(code), PAGE_READWRITE, &dwOldFlag); WriteProcessMemory(GetCurrentProcess(), addr, code, sizeof(code), NULL); VirtualProtect(addr, sizeof(code), dwOldFlag, &dwTempFlag); } } #endif //_WIN32 SPBASE_API void LogEvent(const SeverityLevelEnum eLevel,DWORD dwUserEventCode,const char *pszMessage) {//MAX string len < 1024 SpModule *pModule = GetSpModule(); if (pModule) { pModule->LogMessage(Log_Event, eLevel, 0, dwUserEventCode, pszMessage); } // write a copy in dbg log sp_dbg_info("Event: {%s}(uc=0x%X)", pszMessage, dwUserEventCode); } SPBASE_API void LogError(const SeverityLevelEnum eLevel, ErrorCodeEnum dwSysErrorCode,DWORD dwUserErrorCode,const char *pszMessage) { SpModule *pModule = GetSpModule(); if (pModule) { pModule->LogMessage(Log_Error, eLevel, dwSysErrorCode, dwUserErrorCode, pszMessage); } else sp_dbg_info("LogError failed!can not find the module"); // write a copy in dbg log sp_dbg_error("Error: {%s}(sc=0x%X, uc=0x%X)", pszMessage, dwSysErrorCode, dwUserErrorCode); } SPBASE_API void LogWarn(const SeverityLevelEnum eLevel, ErrorCodeEnum dwSysErrorCode,DWORD dwUserErrorCode, const char *pszMessage) { SpModule *pModule = GetSpModule(); if (pModule) { pModule->LogMessage(Log_Warning, eLevel, dwSysErrorCode, dwUserErrorCode, pszMessage); } // write a copy in dbg log sp_dbg_warn("Warn: {%s}(sc=0x%X, uc=0x%X)", pszMessage, dwSysErrorCode, dwUserErrorCode); } SPBASE_API void LogAssert(const char *pszMessage,const char *pszFile,const int nLine) { SpModule *pModule = GetSpModule(); if (pModule) { pModule->LogMessage(Log_Debug, Severity_Middle, 0, 0, CSimpleStringA::Format("assert fail: {%s}, file: {%s}, line: {%d}, stack: {%s}", pszMessage, _GetFileName(pszFile), nLine, #ifdef _WIN32 (const char*)DumpStack(2) #else "not implement, TODO:" #endif //_WIN32 )); } // write a copy in dbg log sp_dbg_debug("Assert fail: {%s}, file: {%s}, line: {%d}, stack: {%s}", pszMessage, _GetFileName(pszFile), nLine, #ifdef _WIN32 (const char*)DumpStack(2) #else "not implement, TODO:" #endif //_WIN32 ); } SPBASE_API void LogTrace(const char *pszMessage,const char *pszFile,const int nLine) { SpModule *pModule = GetSpModule(); if (pModule) { pModule->LogMessage(Log_Debug, Severity_None, 0, 0, pszMessage); } // write a copy in dbg log sp_dbg_debug("Trace: {%s}, file: {%s}, line: {%d}", pszMessage, _GetFileName(pszFile), nLine); } #include "log.h" #include extern "C" SPBASE_API void Dbg(const char *str, ...) { va_list arg; va_start(arg, str); vDbg(str, arg); va_end(arg); } extern "C" SPBASE_API void vDbg(const char *str, va_list list) { int n = _vscprintf(str, list); if (n > 1024) n = 1024; char *buf = (char*)_alloca(n+1); memset(buf, 0, n+1); /*write at most n bytes(including the terminating null byte '\0') to buf*/ vsnprintf(buf, n+1, str, list); // plus 1 to n, never changed code but the log lost one char [4/1/2020 16:25 Gifur] sp_dbg_debug("Debug: {%s}", buf); //打印到文件 //修改,不发出Log_Debug类消息 //SpModule* pModule = GetSpModule(); // if (pModule) // { // __try // { // SpEntity *pEntity = (SpEntity*)(getEntityResource()->m_Entity); // // if (pEntity != NULL) // { // auto pEntCfg = pEntity->get_cfg_ent(); // if (pEntCfg != NULL && pEntCfg->debug_level > 0) // { // pEntity->LogMessage(Log_Debug, Severity_None, -1, -1, buf); // } // } // } // __finally // { // // } // } } static bool RegistMain(HMODULE hModule,EntryRoutine Main, EntryRoutine Exit) { SpModule::SetEntryRoutine(Main, Exit); return true; } static HMODULE LoadModuleLibrary(sp_mod_t *mod) { sp_env_t *env = sp_get_env(); char tmp[MAX_PATH]; sp_dir_get_path(env->dir, SP_DIR_MODULE_BIN, mod->cfg->name, tmp, sizeof(tmp)); return LoadLibraryA(tmp); } /*It seems never been used anywhere.*/ SPBASE_API HINSTANCE SpLoadLibrary(const char *file) { sp_env_t *env = sp_get_env(); if (env) { char tmp[MAX_PATH]; sprintf(tmp, "%s" SPLIT_SLASH_STR "%s", env->dir->dep_path, file); return LoadLibraryA(tmp); } else { return NULL; } } /*only sphost would invoke it.*/ extern "C" SPBASE_API int __stdcall SpExit(const char* mod_name) { #ifdef _WIN32 Dbg("Do SpExit!"); SetthreadGroup(GetCurrentThreadId(), mod_name); CleanModuleThread(mod_name); sp_iom_stop(GetSpModule()->get_iom()); GetSpModule()->Term(); sp_shm_term(); sp_dbg_term(); sp_iom_destroy(GetSpModule()->get_iom()); delete GetSpModule(); //winsock_term(); FreeLibrary(getEntityResource()->m_Module); DestoryModuleInfo(mod_name); #else if (sp_shm_is_newalloc()) return 0; /*spshell*/ if (g_module) { delete g_module; g_module = nullptr; } #endif //_WIN32 return 0; } //static void SpExit(void) __attribute__((destructor)); extern "C" SPBASE_API int __stdcall SpRun(const char *mod_name, int epid, int range, int group) { ErrorCodeEnum Error = Error_Unexpect; if (!mod_name) { return Error_Bug; } if (epid == SP_INVALID_MOD_ID) { return Error_Bug; } #ifdef _WIN32 if (findModuleByName(mod_name)) //检测实体是否已创建 SpExit(mod_name); bool result = group == 0 ? CreateModuleInfo(ENTITY_SINGLE_GROUPNAME) : CreateModuleInfo(mod_name); //the SetthreadGroup routine would never return false, so the group variable must be not-zero if (!result || !SetthreadGroup(GetCurrentThreadId(), mod_name)) return Error_Duplication; #else if (g_module) { return Error_Duplication; } #endif //_WIN32 /*the log is separeted by {mod_name},so if there are gt one entity defined at one module, *the log about each brother entity also store in same log file. */ sp_dbg_init(mod_name); if (winsock_init() != 0) { return Error_NetBroken; } sp_dbg_info("==============SpRun(%s) start==============", mod_name); sp_dbg_info("process id: %d", GetCurrentProcessId()); void *hint_addr = sp_shm_init(range, FALSE); if (!hint_addr) { sp_dbg_warn("shm init failed! hint_addr: 0x%08x", hint_addr); return Error_Unexpect; } sp_dbg_info("shm init ok! hint_addr: 0x%08x", hint_addr); sp_env_t *env = sp_get_env(); if (!env) { sp_dbg_warn("module env object init failed!"); return Error_Unexpect; } sp_dbg_info("retrieve env object ok!"); sp_mod_t *mod = sp_mod_mgr_find_module_by_idx(env->mod_mgr, epid); if (!mod) { sp_dbg_warn("find shm module object failed!"); return Error_NotExist; } sp_dbg_info("find module %s id %d ok!", mod->cfg->name, mod->cfg->idx); sp_dbg_info("module %s file version: %d.%d.%d.%d", mod->cfg->name, mod->cfg->version.major, mod->cfg->version.minor, mod->cfg->version.revision, mod->cfg->version.build); SpInitUUID((WORD)mod->cfg->idx); sp_cfg_shell_module_t *cfg_mod = sp_cfg_get_module_by_idx(env->cfg, epid); if (!cfg_mod) { sp_dbg_warn("get module %s cfg object failed!", mod->cfg->name); return Error_Bug; } sp_dbg_info("find cfg module object %s id %d ok!", cfg_mod->name, cfg_mod->idx); #ifdef _WIN32 SetUnhandledExceptionFilter(&SuppressError); //DisableSetUnhandledExceptionFilter(); #endif //_WIN32 #ifdef _WIN32 SpModule* curModule = new SpModule(mod, cfg_mod); getEntityResource()->m_Module = LoadModuleLibrary(mod); if (!getEntityResource()->m_Module) { sp_dbg_warn("load module library %s failed! GetLastError = %d", mod->cfg->name, GetLastError()); goto on_error; } curModule->getEntryRoutine(&(getEntityResource()->m_pfMain), &(getEntityResource()->m_pfExit)); Error = curModule->Init(env->url); if (Error) { delete curModule; curModule = NULL; goto on_error; } #else g_module = new SpModule(mod, cfg_mod); HMODULE hModule = LoadModuleLibrary(mod); if (!hModule) { sp_dbg_warn("load module library %s failed! GetLastError = %d", mod->cfg->name, GetLastError()); goto on_error; } Error = g_module->Init(env->url); if (Error) { goto on_error; } #endif //_WIN32 sp_dbg_debug("before set thread priority"); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); sp_dbg_debug("after set thread priority"); #ifdef _WIN32 if (!SetSpModule(mod_name, curModule)) goto on_error; Error = curModule->Run(); curModule->Term(); FreeLibrary(getEntityResource()->m_Module); delete curModule; curModule = NULL; #else Error = g_module->Run(); g_module->Term(); #endif //_WIN32 sp_shm_term(); on_error: #ifndef _WIN32 if (hModule) { FreeLibrary(hModule); hModule = NULL; } if (g_module) { delete g_module; g_module = nullptr; } #endif //NOT _WIN32 return Error; } #define SPBASE_ERRNO_MAP(MAP) \ MAP(Error_Succeed, "Error_Succeed") \ MAP(Error_DataCheck, "Error_DataCheck") \ MAP(Error_Null, "Error_Null") \ MAP(Error_Param, "Error_Param") \ MAP(Error_Overflow, "Error_Overflow") \ MAP(Error_TooSmallBuffer, "Error_TooSmallBuffer") \ MAP(Error_NotIntegrated, "Error_NotIntegrated") \ MAP(Error_CheckSum, "Error_CheckSum") \ MAP(Error_TargetBeing, "Error_TargetBeing") \ MAP(Error_NoTarget, "Error_NoTarget") \ MAP(Error_NoDefine, "Error_NoDefine") \ MAP(Error_NotImpl, "Error_NotImpl") \ MAP(Error_NotExist, "Error_NotExist") \ MAP(Error_Duplication, "Error_Duplication") \ MAP(Error_Unregisted, "Error_Unregisted") \ MAP(Error_AlreadyExist, "Error_AlreadyExist") \ MAP(Error_MethodNotFound, "Error_MethodNotFound") \ MAP(Error_Redirect, "Error_Redirect") \ MAP(Error_BridgeNotBind, "Error_BridgeNotBind") \ MAP(Error_BridgeNotOK, "Error_BridgeNotOK") \ MAP(Error_NotSupport, "Error_NotSupport") \ MAP(Error_InvalidState, "Error_InvalidState") \ MAP(Error_NotInit, "Error_NotInit") \ MAP(Error_Paused, "Error_Paused") \ MAP(Error_Stoped, "Error_Stoped") \ MAP(Error_Losted, "Error_Losted") \ MAP(Error_Closed, "Error_Closed") \ MAP(Error_Accept, "Error_Accept") \ MAP(Error_Failed, "Error_Failed") \ MAP(Error_Busy, "Error_Busy") \ MAP(Error_TaskControl, "Error_TaskControl") \ MAP(Error_Pending, "Error_Pending") \ MAP(Error_Cancel, "Error_Cancel") \ MAP(Error_Break, "Error_Break") \ MAP(Error_NotMeetCondition, "Error_NotMeetCondition") \ MAP(Error_NoPrivilege, "Error_NoPrivilege") \ MAP(Error_MethodSignatureFailed, "Error_MethodSignatureFailed") \ MAP(Error_PeerAction, "Error_PeerAction") \ MAP(Error_PeerClose, "Error_PeerClose") \ MAP(Error_PeerIgnore, "Error_PeerIgnore") \ MAP(Error_PeerReject, "Error_PeerReject") \ MAP(Error_PeerDelay, "Error_PeerDelay") \ MAP(Error_Process, "Error_Process") \ MAP(Error_NetBroken, "Error_NetBroken") \ MAP(Error_UpdateFailed, "Error_UpdateFailed") \ MAP(Error_RegistryFailed, "Error_RegistryFailed") \ MAP(Error_IO, "Error_IO") \ MAP(Error_Readonly, "Error_Readonly") \ MAP(Error_TimeOut, "Error_TimeOut") \ MAP(Error_BlockTimeOut, "Error_BlockTimeOut") \ MAP(Error_ThreadTimeOut, "Error_ThreadTimeOut") \ MAP(Error_QueueTimeOut, "Error_QueueTimeOut") \ MAP(Error_ReplyTimeOut, "Error_ReplyTimeOut") \ MAP(Error_Hardware, "Error_Hardware") \ MAP(Error_DevLoadFileFailed, "Error_DevLoadFileFailed") \ MAP(Error_DevNotAvailable, "Error_DevNotAvailable") \ MAP(Error_DevAlreadyConnected, "Error_DevAlreadyConnected") \ MAP(Error_DevConnFailed, "Error_DevConnFailed") \ MAP(Error_DevCommFailed, "Error_DevCommFailed") \ MAP(Error_DevMedia, "Error_DevMedia") \ MAP(Error_EnvCamera, "Error_EnvCamera") \ MAP(Error_OptCamera, "Error_OptCamera") \ MAP(Error_AllCamera, "Error_AllCamera") \ MAP(Error_AudioIN, "Error_AudioIN") \ MAP(Error_AudioOut, "Error_AudioOut") \ MAP(Error_Debug, "Error_Debug") \ MAP(Error_Assert, "Error_Assert") \ MAP(Error_Trace, "Error_Trace") \ MAP(Error_Bug, "Error_Bug") \ MAP(Error_Unrecover, "Error_Unrecover") \ MAP(Error_Resource, "Error_Resource") \ MAP(Error_NewProcess, "Error_NewProcess") \ MAP(Error_FailVerify, "Error_FailVerify") \ MAP(Error_Block, "Error_Block") \ MAP(Error_Exception, "Error_Exception") \ MAP(Error_Unexpect, "Error_Unexpect") \ MAP(Error_IgnoreAll, "Error_IgnoreAll") #define SPBASE_ERRNO_IMPL_MAP(nErrCode, szErrMsg) \ case nErrCode : return szErrMsg; break; extern "C" SPBASE_API const char* SpStrError(ErrorCodeEnum errorCode) { static char szErrInfo[64]; switch (errorCode) { SPBASE_ERRNO_MAP(SPBASE_ERRNO_IMPL_MAP) default: break; } // multi-unsafe!!!! [Gifur@2020422] sprintf(szErrInfo, "Unkown ErrorCode(0x%08X)", errorCode); return szErrInfo; } #undef SPBASE_ERRNO_IMPL_MAP SPBASE_API CSimpleStringA GetSysErrMsg(int nErrCode) { char szBuf[2048] = {}; DWORD dwRet = FormatMessageA( FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, nErrCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szBuf, sizeof(szBuf)-1, NULL); char *p = strrchr(szBuf, '\r'); if (p != NULL) *p = ' '; p = strrchr(szBuf, '\n'); if (p != NULL) *p = ' '; return dwRet > 0 ? szBuf : CSimpleStringA::Format("get error message fail: %d", GetLastError()); } SPBASE_API const char *_GetFileName(const char *pszFilePath) { int i=strlen(pszFilePath); for( ; i>0 && pszFilePath[i-1]!=SPLIT_SLASH; i--)NULL; return pszFilePath+i; } #ifdef _WIN32 extern "C" BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { DisableThreadLibraryCalls(hModule); break; } case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; } #endif //_WIN32 ModuleBase::~ModuleBase() { #ifdef _WIN32 getEntityResource()->m_moduleBase = NULL; #else ModuleBase::s_pModuleInst = NULL; #endif //_WIN32 for (int i = 0; i < m_nEntityCount; ++i) { if (m_pEntityArray[i]) { #ifdef _WIN32 __try { delete m_pEntityArray[i]; } __finally { m_pEntityArray[i] = NULL; } #else delete m_pEntityArray[i]; m_pEntityArray[i] = NULL; #endif //_WIN32 } } m_nEntityCount = 0; } static ErrorCodeEnum __Init() { #ifdef _WIN32 ModuleBase* pThis = (ModuleBase*)(getEntityResource()->m_moduleBase); #else ModuleBase* pThis = ModuleBase::s_pModuleInst; #endif //_WIN32 _ASSERT(pThis); return pThis->Init(); } static ErrorCodeEnum __Exit() { #ifdef _WIN32 ModuleBase* pThis = (ModuleBase*)(getEntityResource()->m_moduleBase); #else ModuleBase* pThis = ModuleBase::s_pModuleInst; #endif //_WIN32 _ASSERT(pThis); return pThis->Exit(); } ErrorCodeEnum ModuleBase::Init() { ErrorCodeEnum Error = Error_Succeed; for (int i = 0; i < m_nEntityCount; ++i) { Error = RegistEntity(m_pEntityArray[i]); if (Error) break; } return Error; } ErrorCodeEnum ModuleBase::Exit() { ErrorCodeEnum Error = Error_Succeed; for (int i = 0; i < m_nEntityCount; ++i) { Error = UnregistEntity(m_pEntityArray[i]); if (Error) break; } return Error; } BOOL ModuleBase::DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) { bool ret = RegistMain(hInstance, &__Init, &__Exit); if (!ret) return FALSE; DisableThreadLibraryCalls(hInstance); m_hInstance = hInstance; } return TRUE; } ErrorCodeEnum ModuleBase::RegistEntity(CEntityBase *pEntity) { SpModule *pModule = GetSpModule(); if (!pModule) return Error_Null; return pModule->AddEntityBase(pEntity); } ErrorCodeEnum ModuleBase::UnregistEntity(CEntityBase *pEntity) { SpModule *pModule = GetSpModule(); return pModule->RemoveEntityBase(pEntity); } ErrorCodeEnum ModuleBase::GetRegistEntity(const char *pszEntityName,CSmartPointer &pEntity) { SpModule *pModule = GetSpModule(); return pModule->GetEntityBase(pszEntityName, pEntity); } #ifndef _WIN32 ModuleBase* ModuleBase::s_pModuleInst = NULL; #endif //NOT _WIN32 ModuleBase* ModuleBase::GetModuleBase() { #ifdef _WIN32 return (ModuleBase*)(getEntityResource()->m_moduleBase); #else return ModuleBase::s_pModuleInst; #endif //_WIN32 } ModuleBase::ModuleBase() :m_hInstance(NULL), m_nEntityCount(0) { #ifdef _WIN32 getEntityResource()->m_moduleBase = this; #else ModuleBase::s_pModuleInst = this; #endif //_WIN32 } CClientSessionBase::~CClientSessionBase() { if (m_pSessionFunction) { SpClientSessionFunction *pFunction = dynamic_cast(m_pSessionFunction); m_pSessionFunction = NULL; pFunction->DecrementRef(); } }