Windows2003-3790/inetsrv/iis/svcs/smtp/server/pe_out.hxx
2020-09-30 16:53:55 +02:00

412 lines
10 KiB
C++

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name :
pe_out.hxx
Abstract:
This module defines the outbound protocol event classes
Author:
Keith Lau (KeithLau) 6/18/98
Project:
SMTP Server DLL
Revision History:
--*/
#ifndef _PE_OUT_HXX_
#define _PE_OUT_HXX_
#include "spinlock.h"
// =================================================================
// Define a structure to hold an outbound binding node
//
typedef struct _PE_BINDING_NODE
{
struct _PE_BINDING_NODE *pNext;
DWORD dwPriority;
DWORD dwFlags;
} PE_BINDING_NODE, *LPPE_BINDING_NODE;
//
// Flag indicating default binding (no sink)
//
#define PEBN_DEFAULT 0x00000001
// =================================================================
// Define a structue for a command node
// Each command node has a list of binding nodes
//
typedef struct _PE_COMMAND_NODE
{
struct _PE_COMMAND_NODE *pNext;
LPSTR pszCommandKeyword;
DWORD dwHighestPriority;
LPPE_BINDING_NODE pFirstBinding;
} PE_COMMAND_NODE, *LPPE_COMMAND_NODE;
// =================================================================
// Define a struct for a command queue entry.
//
typedef struct _OUTBOUND_COMMAND_Q_ENTRY
{
struct _OUTBOUND_COMMAND_Q_ENTRY *pNext;
DWORD dwFlags;
LPSTR pszFullCommand;
LPSTR pszCommandKeyword;
} OUTBOUND_COMMAND_Q_ENTRY, *LPOUTBOUND_COMMAND_Q_ENTRY;
//
// Some flag values for the queue entry
//
#define PECQ_PIPELINED 0x00000001
// =================================================================
// Fifo Queue, works as long as the first element is the link
//
// This also supports concurrent queue and dequeue as long as there
// is a single writer and a single reader.
//
class CFifoQueueOld
{
public:
CFifoQueueOld()
{
m_pHead = m_pTail = NULL;
m_dwCount = 0;
}
BOOL IsEmpty() { return((!m_pHead)?TRUE:FALSE); }
DWORD Length() { return(InterlockedExchangeAdd((PLONG)&m_dwCount, 0)); }
LPVOID Dequeue()
{
if (!m_pHead)
return(NULL);
LPVOID pTemp = InterlockedExchangePointer(&m_pHead, *(LPVOID *)m_pHead);
if (pTemp)
{
InterlockedCompareExchangePointer(&m_pTail, NULL, pTemp);
LONG lTemp = InterlockedDecrement((PLONG)&m_dwCount);
_ASSERT(lTemp >= 0);
}
return(pTemp);
}
BOOL Enqueue(LPVOID pItem)
{
_ASSERT(pItem);
if (!pItem)
return(FALSE);
*(LPVOID *)pItem = NULL;
if (InterlockedCompareExchangePointer(&m_pTail, pItem, NULL) == NULL)
InterlockedExchangePointer(&m_pHead, pItem);
else
*(LPVOID *)(InterlockedExchangePointer(&m_pTail, pItem)) = pItem;
InterlockedIncrement((PLONG)&m_dwCount);
return(TRUE);
}
private:
DWORD m_dwCount;
LPVOID m_pHead;
LPVOID m_pTail;
};
class CFifoQueue
{
public:
CFifoQueue()
{
m_pHead = m_pTail = NULL;
m_dwCount = 0;
InitializeSpinLock(&m_slock);
}
BOOL IsEmpty() { return((!m_pHead)?TRUE:FALSE); }
DWORD Length() { return(m_dwCount); }
LPVOID Dequeue()
{
LPVOID pRet;
AcquireSpinLock(&m_slock);
//
// Return the head of the list
//
pRet = m_pHead;
if(pRet) {
//
// Advance the head of the list
//
m_pHead = *((LPVOID *) m_pHead);
m_dwCount--;
_ASSERT(m_dwCount != (~0));
//
// If the list is now empty, set the tail to NULL
//
if(m_pHead == NULL)
m_pTail = NULL;
}
ReleaseSpinLock(&m_slock);
return(pRet);
}
BOOL Enqueue(LPVOID pItem)
{
_ASSERT(pItem);
if (!pItem)
return(FALSE);
//
// Initialize the item's next pointer to NULL
//
*(LPVOID *)pItem = NULL;
AcquireSpinLock(&m_slock);
//
// If the list is empty, initilize head and tail with the one
// element
//
if(m_pTail == NULL) {
_ASSERT(m_pHead == NULL);
m_pHead = m_pTail = pItem;
} else {
//
// Set the current tail's next pointer to the new item
//
*((LPVOID *) m_pTail) = pItem;
//
// Set the new tail
//
m_pTail = pItem;
}
m_dwCount++;
ReleaseSpinLock(&m_slock);
return(TRUE);
}
private:
SPIN_LOCK m_slock;
DWORD m_dwCount;
LPVOID m_pHead;
LPVOID m_pTail;
};
// =================================================================
// Generic bound buffer
//
class CBoundAppendBuffer
{
public:
CBoundAppendBuffer()
{
m_pBuffer = NULL;
m_dwLength = 0;
m_dwMaxLength = 0;
}
HRESULT SetBuffer(
LPSTR pBuffer,
DWORD dwMaxLength
)
{
if (!pBuffer || !dwMaxLength)
return(E_POINTER);
m_pBuffer = pBuffer;
*m_pBuffer = '\0';
m_dwLength = 1;
m_dwMaxLength = dwMaxLength;
return(S_OK);
}
HRESULT Append(
LPSTR pbAppendData,
DWORD dwDataSize,
DWORD *pdwNewSize
)
{
if (!m_pBuffer)
return(E_POINTER);
// If we have a buffer, the length should be > 0
_ASSERT(m_dwLength > 0);
//
// If the user is supplying a null terminated buffer, ignore
// their null termination (terminate it ourselves)
//
if((dwDataSize > 0) && (pbAppendData[dwDataSize - 1] == '\0'))
dwDataSize--;
if ((dwDataSize + m_dwLength) > m_dwMaxLength)
return(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
// We support a convention for NULL terminated strings
_ASSERT(m_pBuffer[m_dwLength - 1] == '\0');
// Copy data and update counters
CopyMemory(m_pBuffer + m_dwLength - 1, pbAppendData, dwDataSize);
m_dwLength += dwDataSize;
// Set the null termiantor
m_pBuffer[m_dwLength - 1] = '\0';
if (pdwNewSize)
*pdwNewSize = m_dwLength;
return(S_OK);
}
BOOL SetLength(DWORD dwLength)
{
if ((dwLength > m_dwMaxLength) ||
(dwLength <= 0))
return(FALSE);
m_dwLength = dwLength;
return(TRUE);
}
DWORD Length() { return(m_dwLength); }
DWORD MaxLength() { return(m_dwMaxLength); }
LPSTR Buffer() { return(m_pBuffer); }
void Reset()
{
m_dwLength = 0;
if (m_pBuffer)
{
*m_pBuffer = '\0';
m_dwLength = 1;
}
}
private:
LPSTR m_pBuffer;
DWORD m_dwLength;
DWORD m_dwMaxLength;
};
//
// Variable sized buffer. Supports append mode only
//
#define _DEFAULT_APPEND_BUFFER_SIZE 256
// =================================================================
// Generic growable buffer
//
class CAppendBuffer
{
public:
CAppendBuffer()
{
m_pBuffer = m_pbDefaultBuffer;
*m_pBuffer = '\0';
m_dwLength = 1;
m_dwMaxLength = _DEFAULT_APPEND_BUFFER_SIZE;
}
~CAppendBuffer()
{
if (m_pBuffer != m_pbDefaultBuffer)
delete [] m_pBuffer;
}
HRESULT Append(
LPSTR pbAppendData,
DWORD dwDataSize,
DWORD *pdwNewSize
)
{
LPSTR pbNew;
//
// If the user passes in a null terminated buffer, ignore
// their null termination
//
if((dwDataSize > 0) && (pbAppendData[dwDataSize - 1] == '\0'))
dwDataSize--;
if ((dwDataSize + m_dwLength) > m_dwMaxLength)
{
DWORD dwNewMax = m_dwMaxLength << 3;
// Grow buffer by factor of 8
// Keep growing the buffer if it's still not large enough
while( (dwNewMax != 0) && (dwNewMax < (dwDataSize + m_dwLength)) )
dwNewMax = dwNewMax << 1;
if(dwNewMax == 0) {
// We bit shifted right off the deep end. dwDataSize is > 2Gig
return(E_OUTOFMEMORY);
}
pbNew = new char[dwNewMax];
if (!pbNew)
return(E_OUTOFMEMORY);
// Copy existing stuff over
CopyMemory(pbNew, m_pBuffer, m_dwLength);
m_dwMaxLength = dwNewMax;
}
else
pbNew = m_pBuffer;
// We support a convention for NULL terminated strings
_ASSERT(m_dwLength > 0);
_ASSERT(m_pBuffer[m_dwLength - 1] == '\0');
// Copy data and update counters
CopyMemory(pbNew + m_dwLength - 1, pbAppendData, dwDataSize);
m_dwLength += dwDataSize;
// Set the NULL terminator
pbNew[m_dwLength - 1] = '\0';
if (pdwNewSize)
*pdwNewSize = m_dwLength;
// Release the old buffer
if (pbNew != m_pBuffer)
{
if (m_pBuffer != m_pbDefaultBuffer)
delete [] m_pBuffer;
m_pBuffer = pbNew;
}
return(S_OK);
}
DWORD Length() { return(m_dwLength); }
DWORD MaxLength() { return(m_dwMaxLength); }
LPSTR Buffer() { return(m_pBuffer); }
void Reset() { m_dwLength = 1; *m_pBuffer = '\0'; }
private:
LPSTR m_pBuffer;
DWORD m_dwLength;
DWORD m_dwMaxLength;
char m_pbDefaultBuffer[_DEFAULT_APPEND_BUFFER_SIZE];
};
#endif