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

320 lines
8.4 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: queue.hxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 01-05-96 Rohanp Created
//
//----------------------------------------------------------------------------
#ifndef __QUEUE_H__
#define __QUEUE_H__
const DWORD SMTP_QUEUE_TYPE = 0;
enum QUEUE_TYPE {LOCALQ, REMOTEQ, RETRYQ};
enum QUEUE_OPCODE {PROCESS_QUEUE, TERMINATE_QUEUE};
enum QUEUE_POSITION {QUEUE_TAIL, QUEUE_HEAD};
enum QUEUE_SIG {SIGNAL, NONSIGNAL};
// The PERSIST_QUEUE_ENTRY is the wrapper for the message in the queue,
// containing creation and last access time for messages, as well as
// Identifiers, flags, and retrys. Actual queue elements will be derived
// from PERSIST_QUEUE_ENTRY
//forward declaration
class PERSIST_QUEUE;
class SMTP_SERVER_INSTANCE;
class PERSIST_QUEUE_ENTRY
{
private:
QUEUE_OPCODE m_OpCode;
PERSIST_QUEUE * m_ParentQ;
SMTP_SERVER_INSTANCE * m_pInstance;
protected:
LONGLONG m_ExpireTime; // Time to delete object
LONGLONG m_LastAccess; // Time of last access
DWORD m_QueueId; // Unique ID
DWORD m_RefId; // Sub-ref ID for duplicates
DWORD m_Flags; // Flags
DWORD m_Retries; // Number of retries
public:
LIST_ENTRY m_QEntry; // List pointers
PERSIST_QUEUE_ENTRY(SMTP_SERVER_INSTANCE * pInstance)
{
m_OpCode = PROCESS_QUEUE;
m_ParentQ = NULL;
m_ExpireTime = (LONGLONG) 0;
m_LastAccess = (LONGLONG) 0;
m_QueueId = 0;
m_RefId = 0;
m_Flags = 0;
m_Retries = 0;
m_pInstance = pInstance;
}
SMTP_SERVER_INSTANCE * QuerySmtpInstance( VOID ) const
{ _ASSERT(m_pInstance != NULL); return m_pInstance; }
BOOL IsSmtpInstance( VOID ) const
{ return m_pInstance != NULL; }
VOID SetSmtpInstance( IN SMTP_SERVER_INSTANCE * pInstance )
{ _ASSERT(m_pInstance == NULL); m_pInstance = pInstance; }
void SetExpireTime(LONGLONG ExpireTime) {m_ExpireTime = ExpireTime;}
LONGLONG GetExpireTime (void) const{return m_ExpireTime;}
void SetLastAccessTime(LONGLONG LastTime) {m_LastAccess = LastTime;}
LONGLONG GetLastAccessTime(void) const {return m_LastAccess;}
void SetOpCode (QUEUE_OPCODE OpCode){m_OpCode = OpCode;}
void SetParentQ (PERSIST_QUEUE *ParentQ){m_ParentQ = ParentQ;}
PERSIST_QUEUE * GetParentQ (void)const {return m_ParentQ;}
QUEUE_OPCODE GetOpCode (void) const {return m_OpCode;}
LIST_ENTRY & QueryListEntry(void) {return ( m_QEntry);}
virtual void BeforeDelete(void){}
virtual ~PERSIST_QUEUE_ENTRY(){}
};
typedef PERSIST_QUEUE_ENTRY * PQUEUE_ENTRY;
//
// A PERSIST_QUEUE is the convenient abstraction to hold all of the messages that
// we're trying to deliver. Threads wait on the queue throught the m_QEvent handle.
// This thread is used to dispatch various entries as they become available
// either through magically appearing in the queue from somewhere else, or
// through the timeout (RetryInterval).
// All times in the queue are FILETIMES
//QHEADER is the part of the queue that will be written to disk.
//it is the header.
struct QHEADER
{
DWORD TypeOfEntry;
DWORD Entries; // Number of entries
DWORD Flags; // Flags
DWORD RetryInterval; // Retry interval for messages
DWORD StoreInterval; // Flush to store interval
LONGLONG LastStore; // Time of last store
};
class PERSIST_QUEUE
{
private :
QHEADER m_QData;
HANDLE m_QEvent; // Queue event
DWORD m_NumThreads;
HANDLE m_ThreadHandle[64]; // Thread handle
CRITICAL_SECTION m_CritSec; // Guard
LIST_ENTRY m_QHead; // List pointers
SMTP_SERVER_INSTANCE * m_ParentInst;
BOOL InitializeQueue(void);
public:
PERSIST_QUEUE (SMTP_SERVER_INSTANCE * pSmtpInst) //initialize stuff that can't fail
{
TraceFunctEnterEx((LPARAM)this, "PERSIST_QUEUE::PERSIST_QUEUE");
_ASSERT(pSmtpInst != NULL);
m_QEvent = NULL;
m_ParentInst = pSmtpInst;
m_NumThreads = 1;
//Init or critical section. This protects the queue
InitializeCriticalSection(&m_CritSec);
//Init the heaad of the queue
InitializeListHead(&m_QHead);
TraceFunctLeaveEx((LPARAM)this);
}
void SetNumThreads (DWORD NumThreads)
{
m_NumThreads = min(NumThreads, sizeof(m_ThreadHandle)/sizeof(m_ThreadHandle[0]));
}
virtual ~PERSIST_QUEUE ()
{
TraceFunctEnterEx((LPARAM)this, "~PERSIST_QUEUE");
//FlushQueueEvents();
if(m_QEvent != NULL)
CloseHandle(m_QEvent);
WaitForQThread();
DWORD Loop = 0;
for (Loop = 0; Loop < m_NumThreads; Loop++)
{
if(m_ThreadHandle[Loop] != NULL)
CloseHandle(m_ThreadHandle[Loop]);
}
DeleteCriticalSection (&m_CritSec);
TraceFunctLeaveEx((LPARAM)this);
}
void WaitForQThread(void)
{
DWORD WhichEvent;
WhichEvent = WaitForMultipleObjects(m_NumThreads, m_ThreadHandle, TRUE, INFINITE);
}
void SetQueueEvent(void)
{
_ASSERT(m_QEvent != NULL);
_ASSERT(m_ParentInst != NULL);
SetEvent(m_QEvent);
}
virtual PQUEUE_ENTRY PopQEntry(void)
{
PLIST_ENTRY plEntry = NULL;
PQUEUE_ENTRY pqEntry = NULL;
_ASSERT(m_ParentInst != NULL);
//get the first item off the queue
plEntry = RemoveHeadList (&m_QHead);
pqEntry = CONTAINING_RECORD(plEntry, PERSIST_QUEUE_ENTRY, m_QEntry);
//decrement the number of entries in the queue
--m_QData.Entries;
return pqEntry;
}
SMTP_SERVER_INSTANCE * GetParentInst(void)const {return m_ParentInst;}
void LockQ () {EnterCriticalSection (&m_CritSec);}
void UnLockQ() {LeaveCriticalSection (&m_CritSec);}
virtual void DropRetryCounter(void) {}
virtual void BumpRetryCounter(void) {}
virtual DWORD GetRetryMinutes(void) {return INFINITE;}
HANDLE GetQueueThreadHandle(void) const {return NULL;}
HANDLE GetQueueEventHandle(void) const {return m_QEvent;}
static PERSIST_QUEUE * CreateQueue(QUEUE_TYPE Qtype, SMTP_SERVER_INSTANCE * pSmtpInst);
LIST_ENTRY & QueryListHead(void) {return ( m_QHead);}
DWORD GetNumEntries(void) const {return m_QData.Entries;}
BOOL IsQueueEmpty(void) const {return IsListEmpty(&m_QHead);}
virtual BOOL ProcessQueueEvents(ISMTPConnection *pISMTPConnection);
virtual BOOL IsAtLeastOneValidUser (void){return TRUE;}
static DWORD WINAPI QueueThreadRoutine(void * ThisPtr);
void FlushQueueEvents(void);
/*++
Name :
PERSIST_QUEUE::InsertEntry
Description:
This function inserts an element into the queue.
It always inserts aat the tail
Arguments:
pEntry - Element to insert into the queue
Returns:
always TRUE
--*/
virtual BOOL InsertEntry(IN OUT PERSIST_QUEUE_ENTRY * pEntry, QUEUE_SIG Qsig = SIGNAL, QUEUE_POSITION Qpos = QUEUE_TAIL)
{
_ASSERT( pEntry != NULL);
_ASSERT(m_ParentInst != NULL);
//get the lock the protects the queue
LockQ();
//increment number of entries in the queue
++m_QData.Entries;
//Insert into the list of mail contexts.
if(Qpos == QUEUE_TAIL)
{
InsertTailList( &m_QHead, &pEntry->QueryListEntry());
}
else
{
InsertHeadList( &m_QHead, &pEntry->QueryListEntry());
}
if(Qsig == SIGNAL)
SetEvent (m_QEvent);
//release the lock and return
UnLockQ();
return TRUE;
}
/*++
Name :
PERSIST_QUEUE::RemoveEntry
Description:
This function deletes an entry from the queue
Arguments:
pEntry - Element to insert into the queue
Returns:
--*/
void RemoveEntry(IN OUT PERSIST_QUEUE_ENTRY * pEntry)
{
_ASSERT( pEntry != NULL);
_ASSERT(m_ParentInst != NULL);
LockQ();
//decrement number of entries in the queue
--m_QData.Entries;
// Remove from list of connections
RemoveEntryList( &pEntry->QueryListEntry());
UnLockQ();
}
};
typedef PERSIST_QUEUE * PQUEUE;
BOOL OpenQueueFile (char * FileName, char * InputBuffer, HANDLE* QFHandle, char * Sender);
HANDLE GetDuplicateMailQHandle (HANDLE QFileHandle);
#endif