|
|
////////////////////////////////////////////////////////////
//
// 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
|