You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
411 lines
10 KiB
411 lines
10 KiB
/*++
|
|
|
|
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
|
|
|