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.
613 lines
17 KiB
613 lines
17 KiB
//
|
|
// asyncctx.h -- This file contains the class definitions for:
|
|
// CSearchRequestBlock
|
|
// CBatchLdapConnection
|
|
// CBatchLdapConnectionCache
|
|
// CStoreListResolveContext
|
|
// CSingleSearchReinsertionRequest
|
|
//
|
|
// Created:
|
|
// Feb 19, 1997 -- Milan Shah (milans)
|
|
//
|
|
// Changes:
|
|
// jstamerj 1999/03/16 15:29:20: Heavily modified to batch requests
|
|
// togethor across multiple message
|
|
// categorizations
|
|
// jstamerj 1999/03/22 12:44:01: Modified to support throttling via a
|
|
// queue of CInsertionRequest objects
|
|
//
|
|
// dlongley 2001/10/22: Added CSingleSearchReinsertionRequest to force
|
|
// abandoned and reissued searches to be throttled
|
|
// via the CInsertionRequest object queue
|
|
//
|
|
|
|
#ifndef _ASYNCCTX_H_
|
|
#define _ASYNCCTX_H_
|
|
|
|
#include "ldapconn.h"
|
|
#include "ccataddr.h"
|
|
#include "simparray.h"
|
|
#include "icatqueries.h"
|
|
#include "icatasync.h"
|
|
|
|
class CBatchLdapConnectionCache;
|
|
class CCfgConnection;
|
|
template <class T> class CEmailIDLdapStore;
|
|
|
|
//
|
|
// The MCIS3 LDAP server beta 1 does not correctly handle queries with more
|
|
// than 4 legs in an OR clause. Because of this, we need to limit our search
|
|
// query compression on a configurable basis. The global value,
|
|
// nMaxSearchBlockSize constrains how many searches will be compressed into
|
|
// a single search. The value is read from the registry key
|
|
// szMaxSearchBlockSize. If it is not present, it defaults to
|
|
// MAX_SEARCH_BLOCK_SIZE.
|
|
//
|
|
|
|
#define MAX_SEARCH_BLOCK_SIZE_KEY "System\\CurrentControlSet\\Services\\SMTPSVC\\Parameters"
|
|
|
|
#define MAX_SEARCH_BLOCK_SIZE_VALUE "MaxSearchBlockSize"
|
|
#define MAX_SEARCH_BLOCK_SIZE 20
|
|
|
|
#define MAX_PENDING_SEARCHES_VALUE "MaxPendingSearches"
|
|
#define MAX_PENDING_SEARCHES 60
|
|
|
|
#define MAX_CONNECTION_RETRIES_VALUE "MaxConnectionRetries"
|
|
#define MAX_CONNECTION_RETRIES 20
|
|
|
|
class CBatchLdapConnectionCache;
|
|
class CBatchLdapConnection;
|
|
class CStoreListResolveContext;
|
|
|
|
typedef VOID (*LPFNLIST_COMPLETION)(VOID *lpContext);
|
|
|
|
typedef VOID (*LPSEARCHCOMPLETION)(
|
|
CCatAddr *pCCatAddr,
|
|
CStoreListResolveContext *pslrc,
|
|
CBatchLdapConnection *pConn);
|
|
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// Class CSearchRequestBlock
|
|
//
|
|
//------------------------------------------------------------
|
|
CatDebugClass(CSearchRequestBlock)
|
|
{
|
|
private:
|
|
typedef struct _SearchRequest {
|
|
CCatAddr *pCCatAddr;
|
|
LPSEARCHCOMPLETION fnSearchCompletion;
|
|
CStoreListResolveContext *pslrc;
|
|
LPSTR pszSearchFilter;
|
|
LPSTR pszDistinguishingAttribute;
|
|
LPSTR pszDistinguishingAttributeValue;
|
|
} SEARCH_REQUEST, *PSEARCH_REQUEST;
|
|
|
|
#define SIGNATURE_CSEARCHREQUESTBLOCK (DWORD)'lBRS'
|
|
#define SIGNATURE_CSEARCHREQUESTBLOCK_INVALID (DWORD)'lBRX'
|
|
|
|
public:
|
|
void * operator new(size_t size, DWORD dwNumRequests);
|
|
|
|
CSearchRequestBlock(
|
|
CBatchLdapConnection *pConn);
|
|
|
|
~CSearchRequestBlock();
|
|
|
|
VOID InsertSearchRequest(
|
|
ISMTPServer *pISMTPServer,
|
|
ICategorizerParameters *pICatParams,
|
|
CCatAddr *pCCatAddr,
|
|
LPSEARCHCOMPLETION fnSearchCompletion,
|
|
CStoreListResolveContext *pslrc,
|
|
LPSTR pszSearchFilter,
|
|
LPSTR pszDistinguishingAttribute,
|
|
LPSTR pszDistinguishingAttributeValue);
|
|
|
|
VOID DispatchBlock();
|
|
|
|
HRESULT ReserveSlot()
|
|
{
|
|
if( ((DWORD)InterlockedIncrement((PLONG)&m_cBlockRequestsReserved)) > m_cBlockSize)
|
|
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
|
else
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT AddResults(
|
|
DWORD dwNumResults,
|
|
ICategorizerItemAttributes **rgpItemAttributes)
|
|
{
|
|
HRESULT hr;
|
|
hr = m_csaItemAttr.AddArray(
|
|
dwNumResults,
|
|
rgpItemAttributes);
|
|
|
|
if(SUCCEEDED(hr)) {
|
|
//
|
|
// AddRef all the interfaces we hold
|
|
//
|
|
for(DWORD dwCount = 0; dwCount < dwNumResults; dwCount++) {
|
|
|
|
rgpItemAttributes[dwCount]->AddRef();
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
private:
|
|
PSEARCH_REQUEST GetNextSearchRequest(DWORD *pdwIndex)
|
|
{
|
|
*pdwIndex = InterlockedIncrement((PLONG)&m_cBlockRequestsAllocated) - 1;
|
|
_ASSERT(*pdwIndex < m_cBlockSize);
|
|
|
|
return &(m_prgSearchRequests[*pdwIndex]);
|
|
}
|
|
|
|
VOID CompleteBlockWithError(HRESULT hr)
|
|
{
|
|
PutBlockHRESULT(hr);
|
|
CallCompletions();
|
|
}
|
|
|
|
static VOID LDAPCompletion(
|
|
LPVOID ctx,
|
|
DWORD dwNumResults,
|
|
ICategorizerItemAttributes **rgpICatItemAttributes,
|
|
HRESULT hrStatus,
|
|
BOOL fFinalCompletion);
|
|
|
|
HRESULT HrTriggerBuildQueries();
|
|
HRESULT HrTriggerSendQuery();
|
|
|
|
static HRESULT HrBuildQueriesDefault(
|
|
HRESULT HrStatus,
|
|
PVOID pContext);
|
|
|
|
static HRESULT HrSendQueryDefault(
|
|
HRESULT HrStatus,
|
|
PVOID pContext);
|
|
|
|
static HRESULT HrSendQueryCompletion(
|
|
HRESULT HrStatus,
|
|
PVOID pContext);
|
|
|
|
VOID CompleteSearchBlock(
|
|
HRESULT hrStatus);
|
|
|
|
HRESULT HrTriggerSortQueryResult(
|
|
HRESULT hrStatus);
|
|
|
|
static HRESULT HrSortQueryResultDefault(
|
|
HRESULT hrStatus,
|
|
PVOID pContext);
|
|
|
|
VOID PutBlockHRESULT(
|
|
HRESULT hr);
|
|
|
|
VOID CallCompletions();
|
|
|
|
VOID MatchItem(
|
|
ICategorizerItem *pICatItem,
|
|
ICategorizerItemAttributes *pICatItemAttr);
|
|
|
|
DWORD DwNumBlockRequests()
|
|
{
|
|
return m_cBlockRequestsReadyForDispatch;
|
|
}
|
|
|
|
ISMTPServerEx * GetISMTPServerEx()
|
|
{
|
|
return m_pISMTPServerEx;
|
|
}
|
|
VOID LogAmbiguousEvent(ICategorizerItem *pItem);
|
|
|
|
DWORD m_dwSignature;
|
|
ISMTPServer *m_pISMTPServer;
|
|
ISMTPServerEx *m_pISMTPServerEx;
|
|
ICategorizerParameters *m_pICatParams;
|
|
DWORD m_cBlockRequestsReserved;
|
|
DWORD m_cBlockRequestsAllocated;
|
|
DWORD m_cBlockRequestsReadyForDispatch;
|
|
DWORD m_cBlockSize;
|
|
LIST_ENTRY m_listentry;
|
|
PSEARCH_REQUEST m_prgSearchRequests;
|
|
ICategorizerItem **m_rgpICatItems;
|
|
CBatchLdapConnection *m_pConn;
|
|
LPSTR m_pszSearchFilter;
|
|
CICategorizerQueriesIMP m_CICatQueries;
|
|
CICategorizerAsyncContextIMP m_CICatAsyncContext;
|
|
CSimpArray<ICategorizerItemAttributes *> m_csaItemAttr;
|
|
|
|
friend class CBatchLdapConnection;
|
|
friend class CICategorizerAsyncContextIMP;
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// Class CBatchLdapConnection
|
|
//
|
|
//------------------------------------------------------------
|
|
class CBatchLdapConnection :
|
|
public CLdapConnectionCache::CCachedLdapConnection
|
|
{
|
|
private:
|
|
#define SIGNATURE_CBATCHLDAPCONN (DWORD)'oCLB'
|
|
#define SIGNATURE_CBATCHLDAPCONN_INVALID (DWORD)'oCLX'
|
|
|
|
public:
|
|
CBatchLdapConnection(
|
|
LPSTR szHost,
|
|
DWORD dwPort,
|
|
LPSTR szNamingContext,
|
|
LPSTR szAccount,
|
|
LPSTR szPassword,
|
|
LDAP_BIND_TYPE bt,
|
|
CLdapConnectionCache *pCache) :
|
|
CCachedLdapConnection(
|
|
szHost,
|
|
dwPort,
|
|
szNamingContext,
|
|
szAccount,
|
|
szPassword,
|
|
bt,
|
|
pCache)
|
|
{
|
|
m_dwSignature = SIGNATURE_CBATCHLDAPCONN;
|
|
m_pInsertionBlock = NULL;
|
|
InitializeListHead(&m_listhead);
|
|
InitializeSpinLock(&m_spinlock);
|
|
m_cInsertionContext = 0;
|
|
if(m_nMaxSearchBlockSize == 0)
|
|
InitializeFromRegistry();
|
|
InitializeSpinLock(&m_spinlock_insertionrequests);
|
|
m_dwcPendingSearches = 0;
|
|
m_fDPS_Was_Here = FALSE;
|
|
InitializeListHead(&m_listhead_insertionrequests);
|
|
InitializeListHead(&m_listhead_cancelnotifies);
|
|
}
|
|
|
|
~CBatchLdapConnection()
|
|
{
|
|
_ASSERT(m_dwSignature == SIGNATURE_CBATCHLDAPCONN);
|
|
m_dwSignature = SIGNATURE_CBATCHLDAPCONN_INVALID;
|
|
_ASSERT(m_dwcPendingSearches == 0);
|
|
}
|
|
|
|
CLdapConnection *GetConnection()
|
|
{
|
|
return( this );
|
|
}
|
|
|
|
VOID GetInsertionContext()
|
|
{
|
|
AcquireSpinLock(&m_spinlock);
|
|
m_cInsertionContext++;
|
|
ReleaseSpinLock(&m_spinlock);
|
|
}
|
|
|
|
VOID ReleaseInsertionContext()
|
|
{
|
|
AcquireSpinLock(&m_spinlock);
|
|
if((--m_cInsertionContext) == 0) {
|
|
|
|
LIST_ENTRY listhead_dispatch;
|
|
//
|
|
// Remove all blocks from the insertion list and put them in the dispatch list
|
|
//
|
|
if(IsListEmpty(&m_listhead)) {
|
|
// No blocks
|
|
ReleaseSpinLock(&m_spinlock);
|
|
|
|
InitializeListHead(&listhead_dispatch);
|
|
|
|
} else {
|
|
|
|
CopyMemory(&listhead_dispatch, &m_listhead, sizeof(LIST_ENTRY));
|
|
listhead_dispatch.Blink->Flink = &listhead_dispatch;
|
|
listhead_dispatch.Flink->Blink = &listhead_dispatch;
|
|
InitializeListHead(&m_listhead);
|
|
|
|
ReleaseSpinLock(&m_spinlock);
|
|
//
|
|
// Dispatch all the blocks
|
|
//
|
|
DispatchBlocks(&listhead_dispatch);
|
|
}
|
|
|
|
} else {
|
|
|
|
ReleaseSpinLock(&m_spinlock);
|
|
}
|
|
}
|
|
|
|
HRESULT HrInsertSearchRequest(
|
|
ISMTPServer *pISMTPServer,
|
|
ICategorizerParameters *pICatParams,
|
|
CCatAddr *pCCatAddr,
|
|
LPSEARCHCOMPLETION fnSearchCompletion,
|
|
CStoreListResolveContext *pslrc,
|
|
LPSTR pszSearchFilter,
|
|
LPSTR pszDistinguishingAttribute,
|
|
LPSTR pszDistinguishingAttributeValue);
|
|
|
|
static VOID InitializeFromRegistry();
|
|
|
|
VOID IncrementPendingSearches(DWORD dw = 1)
|
|
{
|
|
AcquireSpinLock(&m_spinlock_insertionrequests);
|
|
m_dwcPendingSearches += dw;
|
|
ReleaseSpinLock(&m_spinlock_insertionrequests);
|
|
}
|
|
VOID DecrementPendingSearches(DWORD dwcSearches = 1);
|
|
|
|
HRESULT HrInsertInsertionRequest(
|
|
CInsertionRequest *pCInsertionRequest);
|
|
|
|
VOID CancelAllSearches(
|
|
HRESULT hr = HRESULT_FROM_WIN32(ERROR_CANCELLED));
|
|
|
|
private:
|
|
CSearchRequestBlock *GetSearchRequestBlock();
|
|
|
|
VOID RemoveSearchRequestBlockFromList(
|
|
CSearchRequestBlock *pBlock)
|
|
{
|
|
AcquireSpinLock(&m_spinlock);
|
|
RemoveEntryList(&(pBlock->m_listentry));
|
|
ReleaseSpinLock(&m_spinlock);
|
|
}
|
|
|
|
VOID DispatchBlocks(PLIST_ENTRY listhead);
|
|
|
|
public:
|
|
static DWORD m_nMaxConnectionRetries;
|
|
|
|
private:
|
|
static DWORD m_nMaxSearchBlockSize;
|
|
static DWORD m_nMaxPendingSearches;
|
|
|
|
DWORD m_dwSignature;
|
|
LIST_ENTRY m_listhead;
|
|
SPIN_LOCK m_spinlock;
|
|
LONG m_cInsertionContext;
|
|
CSearchRequestBlock *m_pInsertionBlock;
|
|
|
|
SPIN_LOCK m_spinlock_insertionrequests;
|
|
DWORD m_dwcPendingSearches;
|
|
DWORD m_dwcReservedSearches;
|
|
LIST_ENTRY m_listhead_insertionrequests;
|
|
|
|
typedef struct _tagCancelNotify {
|
|
LIST_ENTRY le;
|
|
HRESULT hrCancel;
|
|
} CANCELNOTIFY, *PCANCELNOTIFY;
|
|
// This list is also protected by m_spinlock_insertionrequests
|
|
LIST_ENTRY m_listhead_cancelnotifies;
|
|
|
|
CExShareLock m_cancellock;
|
|
BOOL m_fDPS_Was_Here;
|
|
|
|
friend class CSearchRequestBlock;
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// class CBatchLdapConnectionCache
|
|
//
|
|
//------------------------------------------------------------
|
|
class CBatchLdapConnectionCache :
|
|
public CLdapConnectionCache
|
|
{
|
|
public:
|
|
CBatchLdapConnectionCache(
|
|
ISMTPServerEx *pISMTPServerEx) :
|
|
CLdapConnectionCache(pISMTPServerEx)
|
|
{
|
|
}
|
|
HRESULT GetConnection(
|
|
CBatchLdapConnection **ppConn,
|
|
LPSTR szHost,
|
|
DWORD dwPort,
|
|
LPSTR szNamingContext,
|
|
LPSTR szAccount,
|
|
LPSTR szPassword,
|
|
LDAP_BIND_TYPE bt,
|
|
PVOID pCreateContext = NULL)
|
|
{
|
|
return CLdapConnectionCache::GetConnection(
|
|
(CLdapConnection **)ppConn,
|
|
szHost,
|
|
dwPort,
|
|
szNamingContext,
|
|
szAccount,
|
|
szPassword,
|
|
bt,
|
|
pCreateContext);
|
|
}
|
|
|
|
CCachedLdapConnection *CreateCachedLdapConnection(
|
|
LPSTR szHost,
|
|
DWORD dwPort,
|
|
LPSTR szNamingContext,
|
|
LPSTR szAccount,
|
|
LPSTR szPassword,
|
|
LDAP_BIND_TYPE bt,
|
|
PVOID pCreateContext)
|
|
{
|
|
CCachedLdapConnection *pret;
|
|
pret = new CBatchLdapConnection(
|
|
szHost,
|
|
dwPort,
|
|
szNamingContext,
|
|
szAccount,
|
|
szPassword,
|
|
bt,
|
|
this);
|
|
|
|
if(pret)
|
|
if(FAILED(pret->HrInitialize())) {
|
|
pret->Release();
|
|
pret = NULL;
|
|
}
|
|
return pret;
|
|
}
|
|
};
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// class CStoreListResolveContext
|
|
//
|
|
//------------------------------------------------------------
|
|
CatDebugClass(CStoreListResolveContext)
|
|
{
|
|
public:
|
|
CStoreListResolveContext(CEmailIDLdapStore<CCatAddr> *pStore);
|
|
~CStoreListResolveContext();
|
|
|
|
VOID AddRef()
|
|
{
|
|
InterlockedIncrement((PLONG) &m_cRefs);
|
|
}
|
|
|
|
VOID Release()
|
|
{
|
|
if( InterlockedDecrement((PLONG) &m_cRefs) == 0 )
|
|
delete this;
|
|
}
|
|
|
|
HRESULT HrInitialize(
|
|
ISMTPServer *pISMTPServer,
|
|
ICategorizerParameters *pICatParams);
|
|
|
|
HRESULT HrLookupEntryAsync(
|
|
CCatAddr *pCCatAddr);
|
|
VOID Cancel();
|
|
|
|
CCfgConnection *GetConnection();
|
|
|
|
VOID GetInsertionContext();
|
|
VOID ReleaseInsertionContext();
|
|
HRESULT HrInsertInsertionRequest(
|
|
CInsertionRequest *pCInsertionRequest);
|
|
|
|
ISMTPServerEx * GetISMTPServerEx()
|
|
{
|
|
return m_pISMTPServerEx;
|
|
}
|
|
|
|
BOOL Canceled() {
|
|
return m_fCanceled;
|
|
}
|
|
|
|
HRESULT HrInvalidateConnectionAndRetrieveNewConnection(
|
|
CBatchLdapConnection *pConn,
|
|
BOOL fIncrementRetryCount = TRUE);
|
|
|
|
private:
|
|
static VOID AsyncLookupCompletion(
|
|
CCatAddr *pCCatAddr,
|
|
CStoreListResolveContext *pslrc,
|
|
CBatchLdapConnection *pConn);
|
|
|
|
VOID LogSLRCFailover(
|
|
IN DWORD dwcRetries,
|
|
IN LPSTR pszOldHost,
|
|
IN LPSTR pszNewHost);
|
|
|
|
VOID LogSLRCFailure(
|
|
IN DWORD dwcRetries,
|
|
IN LPSTR pszHost);
|
|
|
|
private:
|
|
#define SIGNATURE_CSTORELISTRESOLVECONTEXT (DWORD)'CRLS'
|
|
#define SIGNATURE_CSTORELISTRESOLVECONTEXT_INVALID (DWORD)'XRLS'
|
|
|
|
DWORD m_cRefs;
|
|
DWORD m_dwSignature;
|
|
CCfgConnection *m_pConn;
|
|
|
|
CRITICAL_SECTION m_cs;
|
|
DWORD m_dwcInsertionContext;
|
|
BOOL m_fCanceled;
|
|
DWORD m_dwcRetries;
|
|
DWORD m_dwcCompletedLookups;
|
|
ISMTPServer *m_pISMTPServer;
|
|
ISMTPServerEx *m_pISMTPServerEx;
|
|
ICategorizerParameters *m_pICatParams;
|
|
CEmailIDLdapStore<CCatAddr> *m_pStore;
|
|
};
|
|
|
|
|
|
inline CSearchRequestBlock::CSearchRequestBlock(
|
|
CBatchLdapConnection *pConn) :
|
|
m_CICatQueries( &m_pszSearchFilter )
|
|
{
|
|
_ASSERT(m_dwSignature == SIGNATURE_CSEARCHREQUESTBLOCK);
|
|
m_pISMTPServer = NULL;
|
|
m_pISMTPServerEx = NULL;
|
|
m_pICatParams = NULL;
|
|
m_pszSearchFilter = NULL;
|
|
m_cBlockRequestsReserved = 0;
|
|
m_cBlockRequestsAllocated = 0;
|
|
m_cBlockRequestsReadyForDispatch = 0;
|
|
m_pConn = pConn;
|
|
m_pConn->AddRef();
|
|
}
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// class CSingleSearchReinsertionRequest
|
|
//
|
|
//------------------------------------------------------------
|
|
CatDebugClass(CSingleSearchReinsertionRequest),
|
|
public CInsertionRequest
|
|
{
|
|
public:
|
|
HRESULT HrInsertSearches(
|
|
DWORD dwcSearches);
|
|
|
|
VOID NotifyDeQueue(
|
|
HRESULT hr);
|
|
|
|
#define SIGNATURE_CSingleSearchReinsertionRequest (DWORD)'qRIS'
|
|
#define SIGNATURE_CSingleSearchReinsertionRequest_INVALID (DWORD)'XRIS'
|
|
|
|
CSingleSearchReinsertionRequest(
|
|
CStoreListResolveContext *pslrc,
|
|
CCatAddr *pCCatAddr)
|
|
{
|
|
m_dwSignature = SIGNATURE_CSingleSearchReinsertionRequest;
|
|
m_hr = S_OK;
|
|
m_dwcSearches = 0;
|
|
|
|
m_pslrc = pslrc;
|
|
|
|
m_pCCatAddr = pCCatAddr;
|
|
m_pCCatAddr->AddRef();
|
|
}
|
|
~CSingleSearchReinsertionRequest()
|
|
{
|
|
if(!m_dwcSearches)
|
|
m_pCCatAddr->LookupCompletion();
|
|
|
|
m_pCCatAddr->Release();
|
|
|
|
_ASSERT(m_dwSignature == SIGNATURE_CSingleSearchReinsertionRequest);
|
|
m_dwSignature = SIGNATURE_CSingleSearchReinsertionRequest_INVALID;
|
|
}
|
|
ISMTPServerEx *GetISMTPServerEx()
|
|
{
|
|
return m_pslrc->GetISMTPServerEx();
|
|
}
|
|
|
|
private:
|
|
DWORD m_dwSignature;
|
|
HRESULT m_hr;
|
|
DWORD m_dwcSearches;
|
|
CStoreListResolveContext *m_pslrc;
|
|
CCatAddr *m_pCCatAddr;
|
|
};
|
|
|
|
#endif _ASYNCCTX_H_
|