402 lines
9.9 KiB
C
402 lines
9.9 KiB
C
|
////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// 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
|