|
|
//+---------------------------------------------------------------------------
//
// 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 = NumThreads; }
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
|