windows-nt/Source/XPSP1/NT/net/tapi/server/buffer.c
2020-09-26 16:20:57 +08:00

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