/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: utils.h Abstract: Author: mquinton 06-30-98 Notes: Revision History: --*/ #ifndef __UTILS_H__ #define __UTILS_H__ #ifdef TRACELOG #include //#include //#include extern BOOL g_bLoggingEnabled; #define MAXDEBUGSTRINGLENGTH 1024 #define TL_ERROR ((DWORD)0x00010000 | TRACE_USE_MASK) #define TL_WARN ((DWORD)0x00020000 | TRACE_USE_MASK) #define TL_INFO ((DWORD)0x00040000 | TRACE_USE_MASK) #define TL_TRACE ((DWORD)0x00080000 | TRACE_USE_MASK) #define TL_EVENT ((DWORD)0x00100000 | TRACE_USE_MASK) BOOL TRACELogRegister(LPCTSTR szName); void TRACELogDeRegister(); void TRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR DbgMessage, IN ...); void TRACELogPrint(IN DWORD dwDbgLevel, HRESULT hr, IN LPCSTR lpszFormat, IN ...); extern char *TraceLevel(DWORD dwDbgLevel); extern void TAPIFormatMessage(HRESULT hr, LPVOID lpMsgBuf); #define TRACELOGREGISTER(arg) TRACELogRegister(arg) #define TRACELOGDEREGISTER() g_bLoggingEnabled?TRACELogDeRegister():0 #define LOG(arg) g_bLoggingEnabled?TRACELogPrint arg:0 #define STATICLOG(arg) g_bLoggingEnabled?StaticTRACELogPrint arg:0 extern char sg_szTraceName[100]; extern DWORD sg_dwTracingToDebugger; extern DWORD sg_dwDebuggerMask; extern DWORD sg_dwTraceID; #define DECLARE_DEBUG_ADDREF_RELEASE(x) \ void LogDebugAddRef(DWORD dw) \ { TRACELogPrint(TL_INFO, "%s::AddRef() = %d - this %lx", _T(#x), dw, this); } \ void LogDebugRelease(DWORD dw) \ { TRACELogPrint(TL_INFO, "%s::Release() = %d - this %lx", _T(#x), dw, this); } #define DECLARE_TRACELOG_CLASS(x) \ void TRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ va_list arglist; \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] (%p) %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ this, \ _T(#x)); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ lstrcatA (szTraceBuf, "\n"); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] (%p) %s::%s", TraceLevel(dwDbgLevel), this, _T(#x), lpszFormat); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ } \ \ void TRACELogPrint(IN DWORD dwDbgLevel,IN HRESULT hr, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ LPVOID lpMsgBuf = NULL; \ va_list arglist; \ \ TAPIFormatMessage(hr, &lpMsgBuf); \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] (%p) %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ this, \ _T(#x) \ ); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ wsprintfA(&szTraceBuf[lstrlenA(szTraceBuf)], \ " Returned[%lx] %s\n", \ hr, \ lpMsgBuf); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] (%p) %s::%s Returned[%lx] %s", TraceLevel(dwDbgLevel), this, _T(#x), lpszFormat,hr, lpMsgBuf ); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ \ if(lpMsgBuf != NULL) \ { \ LocalFree( lpMsgBuf ); \ } \ } \ \ static void StaticTRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ va_list arglist; \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ _T(#x)); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ lstrcatA (szTraceBuf, "\n"); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] %s::%s", TraceLevel(dwDbgLevel), _T(#x), lpszFormat); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ } \ \ static void StaticTRACELogPrint(IN DWORD dwDbgLevel,IN HRESULT hr, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ LPVOID lpMsgBuf = NULL; \ va_list arglist; \ \ TAPIFormatMessage(hr, &lpMsgBuf); \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ _T(#x) \ ); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ wsprintfA(&szTraceBuf[lstrlenA(szTraceBuf)], \ " Returned[%lx] %s\n", \ hr, \ lpMsgBuf); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] %s::%s Returned[%lx] %s", TraceLevel(dwDbgLevel), _T(#x), lpszFormat,hr, lpMsgBuf ); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ \ if(lpMsgBuf != NULL) \ { \ LocalFree( lpMsgBuf ); \ } \ } #else // TRACELOG not defined #define TRACELOGREGISTER(arg) #define TRACELOGDEREGISTER() #define LOG(arg) #define STATICLOG(arg) #define DECLARE_DEBUG_ADDREF_RELEASE(x) #define DECLARE_TRACELOG_CLASS(x) #endif // TRACELOG class CAsyncRequestReply { private: HANDLE hRepliedSemaphore; DWORD dwID; BOOL bReply; HRESULT hResult; public: DECLARE_TRACELOG_CLASS(CAsyncRequestReply) CAsyncRequestReply(DWORD id, BOOL b, HRESULT hr) { if( (hRepliedSemaphore = CreateSemaphore(NULL,0,1,NULL)) == NULL ) { LOG((TL_INFO, "create CAsyncRequest - CreateSemaphore failed")); hResult = E_OUTOFMEMORY; } else { dwID = id; bReply = b; hResult = hr; LOG((TL_INFO, "create CAsyncRequest %d ",dwID)); } } ~CAsyncRequestReply() { LOG((TL_INFO, "delete CAsyncRequest %d ",dwID)); if( NULL != hRepliedSemaphore ) { CloseHandle(hRepliedSemaphore); } } inline DWORD getID() {return dwID;}; inline BOOL IsReply() {return bReply;}; inline HRESULT getResult() {return hResult;}; inline void setResult(HRESULT hr) {hResult = hr;}; HRESULT wait() { LOG((TL_INFO, "wait CAsyncRequest %d ",dwID)); extern DWORD gdwTapi2AsynchronousCallTimeout; DWORD rc = WaitForSingleObject(hRepliedSemaphore, gdwTapi2AsynchronousCallTimeout); switch (rc) { case WAIT_ABANDONED: LOG((TL_ERROR, "wait CAsyncRequest %d WaitForSingle object returned WAIT_ABANDONED",dwID)); hResult = TAPIERR_REQUESTFAILED; break; case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: LOG((TL_WARN, "wait CAsyncRequest %d WaitForSingle object returned WAIT_TIMEOUT",dwID)); // -1 won't overlap with any value that may be returned from tapi2 calls. hResult = -1; break; case WAIT_FAILED: { DWORD nLastError = GetLastError(); LOG((TL_ERROR, "wait CAsyncRequest %d WaitForSingle object returned WAIT_FAILED, LastError = %d", dwID, nLastError)); hResult = TAPIERR_REQUESTFAILED; break; } default: break; } return hResult; } void signal() { LOG((TL_INFO, "signal CAsyncRequest %d ",dwID)); ReleaseSemaphore(hRepliedSemaphore, 1, NULL); } }; typedef list RequestReplyList; class CAsyncReplyList { public: DECLARE_TRACELOG_CLASS(CAsyncReplyList) private: RequestReplyList replyList; CRITICAL_SECTION csReply; CAsyncRequestReply *find(DWORD dwID) { RequestReplyList::iterator i; CAsyncRequestReply *pResult = NULL; // walk list searching for match i = replyList.begin(); // iterate over current replies while ( i != replyList.end() ) { // found it if ((*i)->getID() == dwID ) { pResult = *i; break; } i++; } //returning pointer to matching entry or NULL return pResult; } public: CAsyncReplyList() {InitializeCriticalSection( &csReply );}; ~CAsyncReplyList() { FreeList(); DeleteCriticalSection( &csReply ); } void FreeList() { RequestReplyList::iterator i; EnterCriticalSection( &csReply ); // walk list deleting entries i = replyList.begin(); while ( i != replyList.end() ) delete *i++; replyList.clear(); LeaveCriticalSection( &csReply ); }; void remove(CAsyncRequestReply *a) { EnterCriticalSection( &csReply ); replyList.remove(a); LeaveCriticalSection( &csReply ); } CAsyncRequestReply *addRequest(DWORD id) { CAsyncRequestReply *pReply; EnterCriticalSection( &csReply ); // Check list to see if we're already on the list ( i.e. the response LINE_REPLY got here before us) pReply = find(id); if (pReply == NULL || !pReply->IsReply()) { // No so we got here before the reply, create a new request entry on the list pReply = new CAsyncRequestReply(id, FALSE, 0); if (NULL == pReply) { LOG((TL_ERROR, "Could not alloc for CAsyncRequestReply")); } else if( pReply->getResult() == E_OUTOFMEMORY ) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addRequest - Create Semaphore failed")); } else { try { replyList.push_back(pReply); } catch(...) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addRequest- failed - because of alloc failure")); } } } // Else, the reply comes before me, remove it from the list else { replyList.remove (pReply); } LeaveCriticalSection( &csReply ); return pReply; } CAsyncRequestReply *addReply(DWORD id, HRESULT hr) { CAsyncRequestReply *pReply; EnterCriticalSection( &csReply ); // Check list to see if we have a matching entry pReply = find(id); if (pReply == NULL || pReply->IsReply()) { // No so we got here before the request returned, create a new entry on the list pReply = new CAsyncRequestReply(id, TRUE, hr); if (NULL == pReply) { LOG((TL_ERROR, "Could not alloc for CAsyncRequestReply")); } else if( pReply->getResult() == E_OUTOFMEMORY ) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addReply - Create Semaphore failed")); } else { try { replyList.push_back(pReply); } catch(...) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addReply- failed - because of alloc failure")); } } } else { // Use the existing entry, set its return code & signal to the waiting request code pReply->setResult(hr); replyList.remove (pReply); } LeaveCriticalSection( &csReply ); return pReply; } }; //////////////////////////////////////////////////////////////////// // // Class CRetryQueue // Maintains queue of Async messages for retry. // Typically these relate to calls not yet entered in the call hash- // table, such that findCallObject failed. These are reprocessed // once the call is entered & the ghAsyncRetryQueueEvent event is // signalled. // // Added criticalsection - thread safe now // //////////////////////////////////////////////////////////////////// class CRetryQueue { typedef struct _tagRetryQueueEntry { DWORD dwRetryCount; PASYNCEVENTMSG pMessage; } RETRY_QUEUE_ENTRY, *PRETRY_QUEUE_ENTRY; typedef list RetryQueueListType; #define MAX_REQUEUE_TRIES 3 private: RetryQueueListType m_RetryQueueList; CRITICAL_SECTION m_cs; // // is the queue open for new entries? // BOOL m_bAcceptNewEntries; private: // // requeue the entry that failed processing. don't do this if the queue is // closed. // void RequeueEvent(PRETRY_QUEUE_ENTRY pQueueEntry); public: DECLARE_TRACELOG_CLASS(CRetryQueue) CRetryQueue() :m_bAcceptNewEntries(FALSE) { InitializeCriticalSection( &m_cs ); } ~CRetryQueue(); void Lock(){ EnterCriticalSection( &m_cs ); } void Unlock(){ LeaveCriticalSection( &m_cs ); } BOOL QueueEvent(PASYNCEVENTMSG pEvent); BOOL DequeueEvent(PRETRY_QUEUE_ENTRY * ppEvent); void ProcessQueue(); void RemoveNewCallHub(DWORD); inline BOOL ItemsInQueue() { BOOL bReturn; Lock(); bReturn = !m_RetryQueueList.empty(); Unlock(); return bReturn; } // // after this function returns, the queue will accept new entries // void OpenForNewEntries(); // // new entries will be denied after this function returns // void CloseForNewEntries(); }; #define MAXCACHEENTRIES 5 #define BUFFERTYPE_ADDRCAP 1 #define BUFFERTYPE_LINEDEVCAP 2 #define BUFFERTYPE_PHONECAP 3 typedef struct { UINT_PTR pObject; LPVOID pBuffer; } CACHEENTRY; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // CStructCache // // A simple class to cache TAPI structures in tapi3.dll // // This implementation has an array of CACHEENTRY structures. Each // CACHEENTRY structure has 2 member: // pObject - the object that currently owns the buffer // pBuffer - the buffer // // The array is a fixed size, which is set when the class is initialized // The memory for the buffers is allocated during initialization as // well. It is possible that a buffer gets realloced (replaced) // at some time. // // This implementation assumes that the object that owns the buffer // uses it's critical sections correctly. That is, it is locked when // SetXxxBuffer is called, and it is locked when getting and using // a buffer If not, the buffer can disapper from the object at any time. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ class CStructCache { private: CRITICAL_SECTION m_cs; DWORD m_dwType; DWORD m_dwMaxEntries; DWORD m_dwUsedEntries; CACHEENTRY m_aEntries[MAXCACHEENTRIES]; public: DECLARE_TRACELOG_CLASS(CStructCache) CStructCache() { int iCount; InitializeCriticalSection( &m_cs ); for( iCount=0; iCount class CTObjectArray { private: T * m_aT; int m_nSize; int m_nUsed; public: DECLARE_TRACELOG_CLASS(CTObjectArray) CTObjectArray() : m_aT(NULL), m_nSize(0), m_nUsed(0){} ~CTObjectArray() {} int GetSize() const { return m_nUsed; } BOOL Add(T& t) { if(m_nSize == m_nUsed) { T * aT; int nNewSize; nNewSize = (m_nSize == 0) ? 1 : (m_nSize * 2); aT = (T*) ClientAlloc (nNewSize * sizeof(T)); if(aT == NULL) { return FALSE; } CopyMemory( aT, m_aT, m_nUsed * sizeof(T) ); ClientFree( m_aT ); m_aT = aT; m_nSize = nNewSize; } m_aT[m_nUsed] = t; t->AddRef(); m_nUsed++; return TRUE; } BOOL Remove(T& t) { int nIndex = Find(t); if(nIndex == -1) return FALSE; return RemoveAt(nIndex); } BOOL RemoveAt(int nIndex) { m_aT[nIndex]->Release(); if(nIndex != (m_nUsed - 1)) { MoveMemory( (void*)&m_aT[nIndex], (void*)&m_aT[nIndex + 1], (m_nUsed - (nIndex + 1)) * sizeof(T) ); } m_nUsed--; return TRUE; } void Shutdown() { if( NULL != m_aT ) { int index; for (index = 0; index < m_nUsed; index++) { m_aT[index]->Release(); } ClientFree(m_aT); m_aT = NULL; m_nUsed = 0; m_nSize = 0; } } T& operator[] (int nIndex) const { _ASSERTE(nIndex >= 0 && nIndex < m_nUsed); return m_aT[nIndex]; } int Find(T& t) const { for(int i = 0; i < m_nUsed; i++) { if(m_aT[i] == t) return i; } return -1; // not found } }; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // CArray - based on from CSimpleArray from atl // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template class CTArray { private: T * m_aT; int m_nSize; int m_nUsed; public: DECLARE_TRACELOG_CLASS(CTArray) CTArray() : m_aT(NULL), m_nSize(0), m_nUsed(0){} ~CTArray() {} int GetSize() const { return m_nUsed; } BOOL Add(T& t) { if(m_nSize == m_nUsed) { T * aT; int nNewSize; nNewSize = (m_nSize == 0) ? 1 : (m_nSize * 2); aT = (T*) ClientAlloc (nNewSize * sizeof(T)); if(aT == NULL) { return FALSE; } CopyMemory( aT, m_aT, m_nUsed * sizeof(T) ); ClientFree( m_aT ); m_aT = aT; m_nSize = nNewSize; } m_aT[m_nUsed] = t; m_nUsed++; return TRUE; } BOOL Remove(T& t) { int nIndex = Find(t); if(nIndex == -1) return FALSE; return RemoveAt(nIndex); } BOOL RemoveAt(int nIndex) { if(nIndex != (m_nUsed - 1)) { MoveMemory( (void*)&m_aT[nIndex], (void*)&m_aT[nIndex + 1], (m_nUsed - (nIndex + 1)) * sizeof(T) ); } m_nUsed--; return TRUE; } void Shutdown() { if( NULL != m_aT ) { int index; ClientFree(m_aT); m_aT = NULL; m_nUsed = 0; m_nSize = 0; } } T& operator[] (int nIndex) const { _ASSERTE(nIndex >= 0 && nIndex < m_nUsed); return m_aT[nIndex]; } int Find(T& t) const { for(int i = 0; i < m_nUsed; i++) { if(m_aT[i] == t) return i; } return -1; // not found } }; #endif // __UTILS_H__