#include "precompile.h" #include "spShareMemoryBase.h" #include #include #ifdef RVC_OS_WIN #include #else #include #include #include #include #include #endif #include "sp_dir.h" #include #include #include #include #include #include "toolkit.h" #include "fileutil.h" #define MAX_ENTITY_NUM 20 #define ENTITY_LOCK_NAME "Entity_Connect_Lock" #define LOG_LOCK_NAME "Entity_Log_Lock" #ifdef RVC_OS_WIN #pragma data_seg("CONNECT_INFO") ENTITY_CONNECT_INFO m_connectInfo[MAX_ENTITY_NUM] = { ENTITY_CONNECT_INFO() }; int m_priorLink = -1; int m_infoInit = 0; #pragma data_seg() #pragma comment(linker,"/section:CONNECT_INFO,rws") #else std::mutex g_mutex_4_connctrl; std::mutex g_mutex_4_log; static toolkit_once_t once = TOOLKIT_ONCE_INIT; static char* shm_ptr = NULL; ENTITY_CONNECT_INFO* m_connectInfo = NULL; int* m_priorLinkPtr = NULL; int* m_infoInitPtr = NULL; #define SHM_SIZE (sizeof(ENTITY_CONNECT_INFO)*MAX_ENTITY_NUM+sizeof(int)+sizeof(int)) #define SHM_MODE 0666 static void share_memory_global_init(void) { int shm_id = -1; key_t key = ftok(".", 20); shm_id = shmget(key, SHM_SIZE, IPC_CREAT | SHM_MODE); if (shm_id == -1) { printf("shmget failed, errorno: %d\n", errno); } else { shm_ptr = (char*)shmat(shm_id, NULL, 0); if ((void*)shm_ptr == (void*)-1) { printf("shmat failed, errorno: %d\n", errno); } else { printf("shmat attached from %p\n", (void*)shm_ptr); m_connectInfo = (ENTITY_CONNECT_INFO*)shm_ptr; m_priorLinkPtr = (int*)(shm_ptr + sizeof(ENTITY_CONNECT_INFO) * MAX_ENTITY_NUM); m_infoInitPtr = (int*)(shm_ptr + sizeof(ENTITY_CONNECT_INFO) * MAX_ENTITY_NUM + sizeof(int)); *m_priorLinkPtr = -1; *m_infoInitPtr = 0; } } } #endif CMyLogFile m_log; BOOL connectControl::Lock(DWORD dwTime) { #ifdef RVC_OS_WIN if (!m_hLock) { std::string strLockName = ENTITY_LOCK_NAME; m_hLock = ::CreateMutex(NULL, FALSE, strLockName.c_str()); if (!m_hLock) return FALSE; } // whose priority is higher, when occupies this lock. DWORD dwRet = ::WaitForSingleObject(m_hLock, dwTime); return (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED); #else g_mutex_4_connctrl.lock(); #endif // RVC_OS_WIN } void connectControl::Unlock() { #ifdef RVC_OS_WIN if (m_hLock) ::ReleaseMutex(m_hLock); #else g_mutex_4_connctrl.unlock(); #endif // RVC_OS_WIN } connectControl::connectControl() :m_hLock(NULL) { #ifdef RVC_OS_WIN if (!m_infoInit) { for (int i = 0; i < MAX_ENTITY_NUM; i++) m_connectInfo[i].clear(); m_infoInit = 1; } #else if (m_infoInitPtr != NULL && *m_infoInitPtr == 0) { for (int i = 0; i < MAX_ENTITY_NUM; i++) m_connectInfo[i].clear(); *m_infoInitPtr = 1; } #endif // RVC_OS_WIN } connectControl::~connectControl() { #ifdef RVC_OS_WIN if (m_hLock != NULL) CloseHandle(m_hLock); #endif // RVC_OS_WIN } connectControl* connectControl::getInstance() { static connectControl* Instance = NULL; #ifdef RVC_OS_LINUX toolkit_once(&once, share_memory_global_init); #endif if (NULL == Instance) Instance = new connectControl(); return Instance; } int connectControl::getEntityNum() { int entityNum = 0; #ifdef RVC_OS_LINUX if (m_connectInfo == NULL) return 0; #endif for (int i = 0; i < MAX_ENTITY_NUM; i++) { if (0 != strlen(m_connectInfo[i].m_EntityName)) entityNum++; else break; } return entityNum; } int connectControl::getPriorLink(int lastLink) { static int diffTimes = 0; #ifdef RVC_OS_LINUX if (m_priorLinkPtr != NULL) { const int m_priorLink = *m_priorLinkPtr; #endif if (-1 == lastLink) return m_priorLink; else if (lastLink != m_priorLink) { int tempLink = (0 == ++diffTimes % 5) ? m_priorLink : lastLink; return tempLink; } #ifdef RVC_OS_LINUX } #endif return lastLink; } void connectControl::setLastLink(int link) { #ifdef RVC_OS_WIN if (-1 == link || -1 == m_priorLink) { m_priorLink = link; return; } else if (link != m_priorLink) { int entityNum = getEntityNum(); int diffNum = 0; for (int i = 0; i < entityNum; i++) { if (m_priorLink != m_connectInfo[i].m_lastLink) diffNum++; } if (diffNum > (entityNum / 2)) m_priorLink = link;//change prior Link when half of the connection links to another connection } #else if (m_priorLinkPtr != NULL) { if (-1 == link || -1 == *m_priorLinkPtr) { *m_priorLinkPtr = link; return; } else if (link != *m_priorLinkPtr) { int entityNum = getEntityNum(); int diffNum = 0; for (int i = 0; i < entityNum; i++) { if (*m_priorLinkPtr != m_connectInfo[i].m_lastLink) diffNum++; } if (diffNum > (entityNum / 2)) *m_priorLinkPtr = link;//change prior Link when half of the connection links to another connection } } #endif } bool connectControl::getSuccessDual(ENTITY_CONNECT_INFO *entityInfo) { if (NULL == entityInfo) return false; #ifdef RVC_OS_LINUX if (m_connectInfo == NULL) return false; #endif int entityNum = getEntityNum(); for (int i = 0; i < entityNum; i++) { if (1 == m_connectInfo[i].m_DualActive && -1 != m_connectInfo[i].m_currentLink) { memcpy(entityInfo, &(m_connectInfo[i]), sizeof(ENTITY_CONNECT_INFO)); return true; } } return false; } bool connectControl::getEntityInfo(const char *entityName, ENTITY_CONNECT_INFO *entityInfo) { #ifdef RVC_OS_LINUX if (m_connectInfo == NULL) return false; #endif if (NULL == entityName || NULL == entityInfo) return false; int entityNum = getEntityNum(); for (int i = 0; i < entityNum; i++) { if (!strcmp(entityName, m_connectInfo[i].m_EntityName)) { memcpy(entityInfo, &(m_connectInfo[i]), sizeof(ENTITY_CONNECT_INFO)); return true; } } return false; } bool connectControl::setEntityInfo(const ENTITY_CONNECT_INFO *entityInfo) { bool result = false; if (NULL == entityInfo) return result; #ifdef RVC_OS_LINUX std::lock_guard guard(g_mutex_4_connctrl); do { if (m_connectInfo == NULL) break; int entityNum = getEntityNum(); for (int i = 0; i < entityNum; i++) { if (!strcmp(entityInfo->m_EntityName, m_connectInfo[i].m_EntityName)) { m_connectInfo[i].setParam(entityInfo->m_EntityName , entityInfo->m_ServerIP, entityInfo->m_ServerPort, entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort, entityInfo->m_DualActive, entityInfo->m_currentLink); result = true; break; } } if (MAX_ENTITY_NUM == entityNum) { break; } m_connectInfo[entityNum].setParam(entityInfo->m_EntityName , entityInfo->m_ServerIP, entityInfo->m_ServerPort , entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort , entityInfo->m_DualActive, entityInfo->m_currentLink); result = true; } while (false); #else Lock(INFINITE); std::shared_ptr delLockFun((void*)0, [&](void*) { Unlock(); }); int entityNum = getEntityNum(); for (int i = 0; i < entityNum; i++) { if (!strcmp(entityInfo->m_EntityName, m_connectInfo[i].m_EntityName)) { m_connectInfo[i].setParam(entityInfo->m_EntityName, entityInfo->m_ServerIP, entityInfo->m_ServerPort, entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort, entityInfo->m_DualActive, entityInfo->m_currentLink); return true; } } if (MAX_ENTITY_NUM == entityNum) return false; m_connectInfo[entityNum].setParam(entityInfo->m_EntityName, entityInfo->m_ServerIP, entityInfo->m_ServerPort, entityInfo->m_Server_BackupIP, entityInfo->m_Server_BackupPort, entityInfo->m_DualActive, entityInfo->m_currentLink); result = true; #endif return result; } CMyLogFile::CMyLogFile() : m_cOutFile(NULL), m_hLock(nullptr) { } CMyLogFile::~CMyLogFile() { } void CMyLogFile::Output(const TCHAR *data) { if (NULL != m_cOutFile) m_cOutFile->write(data, strlen(data)); } bool checkDirExist(char *filePath) { if (!ExistsDirA(filePath)) { return CreateDirA(filePath, TRUE); } return true; //bool b = CreateDirectoryA(filePath, NULL); //if (b || (GetLastError() == ERROR_ALREADY_EXISTS)) // return true; //return false; } void CMyLogFile::Init() { if (!m_cOutFile) { char m_dirPath[_MAX_PATH] = ""; char tmp[MAX_PATH]; GetModuleFileNameA(NULL, tmp, MAX_PATH); *strrchr(tmp, SPLIT_SLASH) = 0; *strrchr(tmp, SPLIT_SLASH) = 0; *strrchr(tmp, SPLIT_SLASH) = 0; *strrchr(tmp, SPLIT_SLASH) = 0; *strrchr(tmp, SPLIT_SLASH) = 0; sprintf_s(m_dirPath, _MAX_PATH, "%s" SPLIT_SLASH_STR "rvc" SPLIT_SLASH_STR "dbg" SPLIT_SLASH_STR "DualActive", tmp); if (!checkDirExist(m_dirPath)) return; SYSTEMTIME cur; GetSystemTime(&cur); sprintf(m_dirPath, "%s" SPLIT_SLASH_STR "%4d%.2d%.2d.log", m_dirPath, cur.wYear, cur.wMonth, cur.wDay); m_cOutFile = new ofstream(m_dirPath, ios_base::app); if (m_cOutFile->is_open()) return; delete m_cOutFile; m_cOutFile = NULL; } } void CMyLogFile::Release() { if (NULL != m_cOutFile) { m_cOutFile->close(); delete m_cOutFile; m_cOutFile = NULL; } } BOOL CMyLogFile::Lock(DWORD dwTime) { #ifdef RVC_OS_WIN if (!m_hLock) { std::string strLockName = LOG_LOCK_NAME; m_hLock = ::CreateMutex(NULL, FALSE, strLockName.c_str()); if (!m_hLock) return FALSE; } DWORD dwRet = ::WaitForSingleObject(m_hLock, dwTime); return (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED); #else g_mutex_4_log.lock(); #endif // RVC_OS_WIN } void CMyLogFile::Unlock() { #ifdef RVC_OS_WIN if (m_hLock) ::ReleaseMutex(m_hLock); #else g_mutex_4_log.unlock(); #endif } bool CMyLogFile::GetRootDir(char *dirPath) { char pathbuf[1024] = ""; int pathlen = ::GetModuleFileNameA(NULL, pathbuf, 1024); int times = 0; while (pathlen > 0) { if (pathbuf[pathlen--] == SPLIT_SLASH) times++; if (2 == times) break; } pathbuf[++pathlen] = '\0'; memcpy(dirPath, pathbuf, (pathlen + 1 > 1024 ? 1024 : pathlen + 1)); return pathlen; } void CMyLogFile::PrintCurTime() { TCHAR dateString[256]; SYSTEMTIME cur; GetLocalTime(&cur); sprintf(dateString, "[%4d-%.2d-%.2d,%.2d:%.2d:%.2d][%u][%u] ", cur.wYear, cur.wMonth, cur.wDay, cur.wHour, cur.wMinute, cur.wSecond, GetCurrentProcessId(), #if defined(RVC_OS_WIN) GetCurrentThreadId()); #else GetCurrentThreadIdFromSys()); #endif //RVC_OS_WIN Output(dateString); } CMyLogFile& CMyLogFile::operator <<(unsigned int unVal) { strstream tmp; tmp << unVal; tmp << '\0'; TCHAR* output = tmp.str(); Output(output); tmp.freeze(false); return *this; } CMyLogFile& CMyLogFile::operator <<(long lVal) { strstream tmp; tmp << lVal; tmp << '\0'; TCHAR* output = tmp.str(); Output(output); tmp.freeze(false); return *this; } CMyLogFile& CMyLogFile::operator <<(const TCHAR* str) { Output(str); return *this; } CMyLogFile& CMyLogFile::operator <<(TCHAR tch) { TCHAR szCh[2]; szCh[0] = tch; szCh[1] = '\0'; Output(szCh); return *this; } CMyLogFile& CMyLogFile::operator <<(int nVal) { strstream tmp; tmp << nVal; tmp << '\0'; TCHAR* output = tmp.str(); Output(output); tmp.freeze(false); return *this; } CMyLogFile& CMyLogFile::operator <<(unsigned long ulVal) { strstream tmp; tmp << ulVal; tmp << '\0'; TCHAR* output = tmp.str(); Output(output); tmp.freeze(false); return *this; } CMyLogFile& CMyLogFile::operator <<(double dVal) { strstream tmp; tmp << dVal; tmp << '\0'; TCHAR* output = tmp.str(); Output(output); tmp.freeze(false); return *this; } #ifdef _WIN32 CMyLogFile& CMyLogFile::operator <<(u__int64_t unllVal) { strstream tmp; tmp << unllVal; tmp << '\0'; TCHAR* output = tmp.str(); Output(output); tmp.freeze(false); return *this; } #endif void CMyLogFile::LOGERROR(TCHAR* formatString, ...) { #ifdef RVC_OS_WIN Lock(INFINITE); Init(); __try { if (NULL != m_cOutFile && !m_cOutFile->is_open()) return; /* ** Insert the current time.. */ PrintCurTime(); /* ** Parse the format string and write to the file */ if (formatString == NULL) { /* ** No point in continuiing */ return; } va_list argList; /* ** Set va_list to the beginning of optional arguments */ va_start(argList, formatString); TCHAR* ptr = formatString; while (*ptr != '\0') { TCHAR* str = NULL; int nInteger = 0; unsigned int unInt = 0; long lLong = 0; unsigned long ulLong = 0; double dDoub = 0; u__int64_t ullLong = 0; if (*ptr == '%') { switch (*(ptr + 1)) { case 's': str = va_arg(argList, TCHAR*); if (NULL == str) break; *this << str; ptr++; break; case 'd': nInteger = va_arg(argList, int); *this << nInteger; ptr++; break; case 'u': unInt = va_arg(argList, unsigned int); *this << unInt; ptr++; break; case 'l': ptr++; if (*(ptr + 1) == 'd') { lLong = va_arg(argList, long); *this << lLong; ptr++; } else if (*(ptr + 1) == 'u') { ulLong = va_arg(argList, unsigned long); *this << ulLong; ptr++; } else if (*(ptr + 1) == 'q') { ullLong = va_arg(argList, u__int64_t); *this << ullLong; ptr++; } break; case 'f': dDoub = va_arg(argList, double); *this << dDoub; ptr++; break; default: *this << *ptr; } } // if(*ptr == '%') else { *this << *ptr; } /* ** Increment pointer.. */ ptr++; } va_end(argList); //va_end missing. *this << '\n'; } __finally { Release(); Unlock(); } #else std::lock_guard guard(g_mutex_4_log); Init(); do { if (NULL != m_cOutFile && !m_cOutFile->is_open()) break; PrintCurTime(); if (formatString == NULL) { break; } va_list argList; va_start(argList, formatString); TCHAR* ptr = formatString; while (*ptr != '\0') { TCHAR* str = NULL; int nInteger = 0; unsigned int unInt = 0; long lLong = 0; unsigned long ulLong = 0; double dDoub = 0; u__int64_t ullLong = 0; if (*ptr == '%') { switch (*(ptr + 1)) { case 's': str = va_arg(argList, TCHAR*); if (NULL == str) break; *this << str; ptr++; break; case 'd': nInteger = va_arg(argList, int); *this << nInteger; ptr++; break; case 'u': unInt = va_arg(argList, unsigned int); *this << unInt; ptr++; break; case 'l': ptr++; if (*(ptr + 1) == 'd') { lLong = va_arg(argList, long); *this << lLong; ptr++; } else if (*(ptr + 1) == 'u') { ulLong = va_arg(argList, unsigned long); *this << ulLong; ptr++; } else if (*(ptr + 1) == 'q') { ullLong = va_arg(argList, u__int64_t); *this << ullLong; ptr++; } break; case 'f': dDoub = va_arg(argList, double); *this << dDoub; ptr++; break; default: *this << *ptr; } } // if(*ptr == '%') else { *this << *ptr; } /* ** Increment pointer.. */ ptr++; } va_end(argList); //va_end missing. *this << '\n'; } while (false); Release(); #endif // RVC_OS_WIN }