//////////////////////////////////////////////////////////// // // buffer.c // // this modularizes some of the circular buffer functionality // ///////////////////////////////////////////////////////////// #include "windows.h" #include "assert.h" #include "tapi.h" #include "tspi.h" #include "utils.h" #include "..\client\client.h" #include "buffer.h" #define INVAL_KEY ((DWORD) 'LVNI') #if DBG extern BOOL gbBreakOnLeak; #define ServerAlloc( __size__ ) ServerAllocReal( __size__, __LINE__, __FILE__ ) LPVOID WINAPI ServerAllocReal( DWORD dwSize, DWORD dwLine, PSTR pszFile ); void MyRealAssert( DWORD dwLine, PSTR pszFile ); #define MyAssert( __exp__ ) { if ( !(__exp__) ) MyRealAssert (__LINE__, __FILE__); } #else #define ServerAlloc( __size__ ) ServerAllocReal( __size__ ) LPVOID WINAPI ServerAllocReal( DWORD dwSize ); #define MyAssert( __exp__ ) #endif VOID WINAPI ServerFree( LPVOID lp ); /////////////////////////////////////////////////////////////////////////////// // // PeekAsyncEventMsgFromQueue - peeks an ASYNCEVENTMSG from a circular buffer. // Places the next messge in the queue into the *ppMsg passed in. pdwID // is used for multiple calls to this function, to save the place in the // buffer. On the first call to this function, *pdwID must be 0. // // If the buffer needs to be critical sectioned, it is up to the calling // procedure to do that. // // PARAMETERS // pBufferInfo // [in] pointer to bufferinfo structure. this does not get modified // since we are just doing a peek message here. // ppCurrent // [in, out] pointer to the location in the buffer // where the last message was retrieved. When this function // is first called, *ppCurrent MUST be 0. *ppCurrent is filled in // if this function is successful. *ppCurrent can be passed to // subsequent calls to this function to retreive subsequent // messages. ppCurrent may not be NULL. // ppMsg // [in, out] pointer to pointer to ASYNCEVENTMSG. Preallocated - size // is in *pdwMsgSize. May be realloced if message is too big. // Uses ServerAlloc and ServerFree. // pdwMsgSize // [in, out] pointer to size of ppMsg. Can be modified if ppMsg is realloced. // // // RETURNS // TRUE if a message is copied to the buffer // // FALSE if a message is not copied to the buffer. // //////////////////////////////////////////////////////////////////////////////////// BOOL PeekAsyncEventMsgFromQueue( PBUFFERINFO pBufferInfo, PBYTE *ppCurrent, PASYNCEVENTMSG *ppMsg, DWORD *pdwMsgSize ) { DWORD dwBytesToEnd; DWORD dwMoveSize, dwMoveSizeWrapped; PBYTE pBufferEnd, pStart; PASYNCEVENTMSG pMsg; LOG((TL_TRACE, "Entering PeekAsyncEventMsgFromQueue")); MyAssert (ppCurrent); do_it: if (*ppCurrent) { pStart = *ppCurrent; } else { pStart = pBufferInfo->pDataOut; } pMsg = *ppMsg; pBufferEnd = pBufferInfo->pBuffer + pBufferInfo->dwTotalSize; MyAssert(pStart < pBufferEnd); MyAssert(pStart >= pBufferInfo->pBuffer); MyAssert(*pdwMsgSize >= sizeof(ASYNCEVENTMSG)); MyAssert(*ppMsg != NULL); if (pBufferInfo->dwUsedSize == 0) { LOG((TL_INFO, "GetAsyncEventMsg: dwUsedSize == 0")); return FALSE; } if ((pStart == pBufferInfo->pDataIn) || ((pStart == pBufferInfo->pBuffer) && (pBufferInfo->pDataIn == pBufferEnd))) { // gone through the whole buffer LOG((TL_TRACE, "PeekAsyncEventMsg: Gone through whole buffer")); return FALSE; } // Copy the fixed portion of the msg to the local buf // dwBytesToEnd is the number of bytes between the start // of copying and the end of the buffer dwBytesToEnd = pBufferEnd - pStart; // if dwBytesToEnd is greater than the fixed portion of // ASYNCEVENTMSG, just copy it // otherwise, the message wraps, so figure out where // it wraps. if (dwBytesToEnd >= sizeof (ASYNCEVENTMSG)) { dwMoveSize = sizeof (ASYNCEVENTMSG); dwMoveSizeWrapped = 0; } else { dwMoveSize = dwBytesToEnd; dwMoveSizeWrapped = sizeof (ASYNCEVENTMSG) - dwBytesToEnd; } CopyMemory (pMsg, pStart, dwMoveSize); pStart += dwMoveSize; if (dwMoveSizeWrapped) { CopyMemory( ((LPBYTE) pMsg) + dwMoveSize, pBufferInfo->pBuffer, dwMoveSizeWrapped ); pStart = pBufferInfo->pBuffer + dwMoveSizeWrapped; } // See if there's any extra data in this msg if (pMsg->dwTotalSize > sizeof (ASYNCEVENTMSG)) { BOOL bCopy = TRUE; LOG((TL_INFO, "GetAsyncEventMessage: Message > ASYNCEVENTMSG")); // See if we need to grow the msg buffer if (pMsg->dwTotalSize > *pdwMsgSize) { DWORD dwNewMsgSize = pMsg->dwTotalSize + 256; if ((pMsg = ServerAlloc (dwNewMsgSize))) { CopyMemory( pMsg, *ppMsg, sizeof(ASYNCEVENTMSG) ); ServerFree (*ppMsg); *ppMsg = pMsg; *pdwMsgSize = dwNewMsgSize; } else { return FALSE; } } // pStart has been moved to the end of the fixed portion // of the message. // dwBytesToEnd is the number of bytes between pStart and // the end of the buffer. dwBytesToEnd = pBufferEnd - pStart; // if dwBytesToEnd is greater than the size that we need // to copy... // otherwise, the copying wraps. if (dwBytesToEnd >= (pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG))) { dwMoveSize = pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG); dwMoveSizeWrapped = 0; } else { dwMoveSize = dwBytesToEnd; dwMoveSizeWrapped = (pMsg->dwTotalSize - sizeof (ASYNCEVENTMSG)) - dwBytesToEnd; } CopyMemory (pMsg + 1, pStart, dwMoveSize); pStart += dwMoveSize; if (dwMoveSizeWrapped) { CopyMemory( ((LPBYTE) (pMsg + 1)) + dwMoveSize, pBufferInfo->pBuffer, dwMoveSizeWrapped ); pStart = pBufferInfo->pBuffer + dwMoveSizeWrapped; } } *ppCurrent = pStart; // check to see if it is wrapping if (*ppCurrent >= pBufferEnd) { *ppCurrent = pBufferInfo->pBuffer; } if (pMsg->dwMsg == INVAL_KEY) { goto do_it; } return TRUE; } void RemoveAsyncEventMsgFromQueue( PBUFFERINFO pBufferInfo, PASYNCEVENTMSG pMsg, PBYTE *ppCurrent ) /*++ Removes a message retrieved by PeekAsyncEventMsgFromQueue. Basically, this function simply fixes up the pointers in the pBufferInfo structure to remove the message. --*/ { DWORD dwMsgSize; LPBYTE pBuffer = pBufferInfo->pBuffer; LPBYTE pBufferEnd = pBuffer + pBufferInfo->dwTotalSize; PASYNCEVENTMSG pMsgInBuf, pMsgXxx; dwMsgSize = pMsg->dwTotalSize; pMsgInBuf = (PASYNCEVENTMSG) ((*ppCurrent - dwMsgSize) >= pBuffer ? *ppCurrent - dwMsgSize : *ppCurrent + pBufferInfo->dwTotalSize - dwMsgSize ); if ((LPBYTE) pMsgInBuf == pBufferInfo->pDataOut) { // // This is the oldest msg in the ring buffer so we can easily // remove it. Then we'll loop checking each next message in the // queue & deleting those which have been invalidated, only // breaking out of the loop when there's no more msgs or we find // a msg that's not been invalidated. // do { if ((((LPBYTE) pMsgInBuf) + dwMsgSize) < pBufferEnd) { pBufferInfo->pDataOut = ((LPBYTE) pMsgInBuf) + dwMsgSize; } else { pBufferInfo->pDataOut = pBuffer + ((((LPBYTE) pMsgInBuf) + dwMsgSize) - pBufferEnd); } if ((pBufferInfo->dwUsedSize -= dwMsgSize) == 0) { break; } pMsgInBuf = (PASYNCEVENTMSG) pBufferInfo->pDataOut; if ((LPBYTE) &pMsgInBuf->dwMsg <= (pBufferEnd - sizeof (pMsgInBuf->dwMsg))) { if (pMsgInBuf->dwMsg != INVAL_KEY) { break; } } else { pMsgXxx = (PASYNCEVENTMSG) (pBuffer - (pBufferEnd - ((LPBYTE) pMsgInBuf))); if (pMsgXxx->dwMsg != INVAL_KEY) { break; } } dwMsgSize = pMsgInBuf->dwTotalSize; } while (1); } else { // // Msg is not the oldest in the ring buffer, so mark it as invalid // and it'll get cleaned up later // if ((LPBYTE) &pMsgInBuf->dwMsg <= (pBufferEnd - sizeof (pMsgInBuf->dwMsg))) { pMsgInBuf->dwMsg = INVAL_KEY; } else { pMsgXxx = (PASYNCEVENTMSG) (pBuffer - (pBufferEnd - ((LPBYTE) pMsgInBuf))); pMsgXxx->dwMsg = INVAL_KEY; } } } #if DBG void MyRealAssert( DWORD dwLine, PSTR pszFile ) { LOG((TL_ERROR, "Assert in %s at line # %d", pszFile, dwLine)); if (gbBreakOnLeak) { DebugBreak(); } } #endif