|
|
//
// asyncctx.cpp -- This file contains the class implementation for:
// CAsyncLookupContext
//
// Created:
// Mar 4, 1997 -- Milan Shah (milans)
//
// Changes:
//
#include "precomp.h"
#include "simparray.cpp"
DWORD CBatchLdapConnection::m_nMaxSearchBlockSize = 0; DWORD CBatchLdapConnection::m_nMaxPendingSearches = 0; DWORD CBatchLdapConnection::m_nMaxConnectionRetries = 0;
//+----------------------------------------------------------------------------
//
// Function: CBatchLdapConnection::InitializeFromRegistry
//
// Synopsis: Static function that looks at registry to determine maximum
// number of queries that will be compressed into a single query.
// If the registry key does not exist or there is any other
// problem reading the key, the value defaults to
// MAX_SEARCH_BLOCK_SIZE
//
// Arguments: None
//
// Returns: Nothing.
//
//-----------------------------------------------------------------------------
VOID CBatchLdapConnection::InitializeFromRegistry() { HKEY hkey; DWORD dwErr, dwType, dwValue, cbValue;
dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, MAX_SEARCH_BLOCK_SIZE_KEY, &hkey);
if (dwErr == ERROR_SUCCESS) {
cbValue = sizeof(dwValue); dwErr = RegQueryValueEx( hkey, MAX_SEARCH_BLOCK_SIZE_VALUE, NULL, &dwType, (LPBYTE) &dwValue, &cbValue);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0 && dwValue < MAX_SEARCH_BLOCK_SIZE) {
InterlockedExchange((PLONG) &m_nMaxSearchBlockSize, (LONG)dwValue); }
cbValue = sizeof(dwValue); dwErr = RegQueryValueEx( hkey, MAX_PENDING_SEARCHES_VALUE, NULL, &dwType, (LPBYTE) &dwValue, &cbValue);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
InterlockedExchange((PLONG) &m_nMaxPendingSearches, (LONG)dwValue); }
cbValue = sizeof(dwValue); dwErr = RegQueryValueEx( hkey, MAX_CONNECTION_RETRIES_VALUE, NULL, &dwType, (LPBYTE) &dwValue, &cbValue);
if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
InterlockedExchange((PLONG) &m_nMaxConnectionRetries, (LONG)dwValue); }
RegCloseKey( hkey ); } if(m_nMaxSearchBlockSize == 0) m_nMaxSearchBlockSize = MAX_SEARCH_BLOCK_SIZE; if(m_nMaxPendingSearches == 0) m_nMaxPendingSearches = MAX_PENDING_SEARCHES; if(m_nMaxPendingSearches < m_nMaxSearchBlockSize) m_nMaxPendingSearches = m_nMaxSearchBlockSize; if(m_nMaxConnectionRetries == 0) m_nMaxConnectionRetries = MAX_CONNECTION_RETRIES; }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::operator new
//
// Synopsis: Allocate enough memory for this and the specified number
// of SEARCH_REQUEST structurers
//
// Arguments:
// size: Normal size of object
// dwNumRequests: Number of props desired in this object
//
// Returns: ptr to allocated memory or NULL
//
// History:
// jstamerj 1999/03/10 16:15:43: Created
//
//-------------------------------------------------------------
void * CSearchRequestBlock::operator new( size_t size, DWORD dwNumRequests) { DWORD dwSize; void *pmem; CSearchRequestBlock *pBlock;
//
// Calcualte size in bytes required
//
dwSize = size + (dwNumRequests*sizeof(SEARCH_REQUEST)) + (dwNumRequests*sizeof(ICategorizerItem *));
pmem = new BYTE[dwSize];
if(pmem) {
pBlock = (CSearchRequestBlock *)pmem; pBlock->m_dwSignature = SIGNATURE_CSEARCHREQUESTBLOCK; pBlock->m_cBlockSize = dwNumRequests;
pBlock->m_prgSearchRequests = (PSEARCH_REQUEST) ((PBYTE)pmem + size);
pBlock->m_rgpICatItems = (ICategorizerItem **) ((PBYTE)pmem + size + (dwNumRequests*sizeof(SEARCH_REQUEST)));
_ASSERT( (DWORD) ((PBYTE)pBlock->m_rgpICatItems + (dwNumRequests*sizeof(ICategorizerItem *)) - (PBYTE)pmem) == dwSize);
} return pmem; }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::~CSearchRequestBlock
//
// Synopsis: Release everything we have references to
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/11 18:45:59: Created
//
//-------------------------------------------------------------
CSearchRequestBlock::~CSearchRequestBlock() { DWORD dwCount; //
// Release all CCatAddrs
//
for(dwCount = 0; dwCount < DwNumBlockRequests(); dwCount++) {
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
preq->pCCatAddr->Release(); } //
// Release all the attr interfaces
//
for(dwCount = 0; dwCount < m_csaItemAttr.Size(); dwCount++) {
((ICategorizerItemAttributes **) m_csaItemAttr)[dwCount]->Release(); }
if(m_pISMTPServer) m_pISMTPServer->Release();
if(m_pISMTPServerEx) m_pISMTPServerEx->Release();
if(m_pICatParams) m_pICatParams->Release();
if(m_pszSearchFilter) delete m_pszSearchFilter;
if(m_pConn) m_pConn->Release();
_ASSERT(m_dwSignature == SIGNATURE_CSEARCHREQUESTBLOCK); m_dwSignature = SIGNATURE_CSEARCHREQUESTBLOCK_INVALID; }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::InsertSearchRequest
//
// Synopsis: Inserts a search request in this block. When the block
// is full, dispatch the block to LDAP before returning
//
// Arguments:
// pISMTPServer: ISMTPServer to use for triggering events
// pICatParams: ICategorizerParameters to use
// pCCatAddr: Address item for the search
// fnSearchCompletion: Async Completion routine
// ctxSearchCompletion: Context to pass to the async completion routine
// pszSearchFilter: Search filter to use
// pszDistinguishingAttribute: The distinguishing attribute for matching
// pszDistinguishingAttributeValue: above attribute's distinguishing value
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/11 13:12:20: Created.
//
//-------------------------------------------------------------
VOID CSearchRequestBlock::InsertSearchRequest( ISMTPServer *pISMTPServer, ICategorizerParameters *pICatParams, CCatAddr *pCCatAddr, LPSEARCHCOMPLETION fnSearchCompletion, CStoreListResolveContext *pslrc, LPSTR pszSearchFilter, LPSTR pszDistinguishingAttribute, LPSTR pszDistinguishingAttributeValue) { PSEARCH_REQUEST preq; DWORD dwIndex; HRESULT hr = S_OK;
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::InsertSearchRequest"); //
// Unset any existing HRSTATUS -- the status will be set again in
// the search completion
//
_VERIFY(SUCCEEDED( pCCatAddr->UnSetPropId( ICATEGORIZERITEM_HRSTATUS)));
m_pConn->IncrementPendingSearches();
preq = GetNextSearchRequest(&dwIndex);
_ASSERT(preq);
pCCatAddr->AddRef(); preq->pCCatAddr = pCCatAddr; preq->fnSearchCompletion = fnSearchCompletion; preq->pslrc = pslrc; preq->pszSearchFilter = pszSearchFilter; preq->pszDistinguishingAttribute = pszDistinguishingAttribute; preq->pszDistinguishingAttributeValue = pszDistinguishingAttributeValue;
m_rgpICatItems[dwIndex] = pCCatAddr;
if(dwIndex == 0) { //
// Use the first insertion's ISMTPServer
//
_ASSERT(m_pISMTPServer == NULL); m_pISMTPServer = pISMTPServer;
if(m_pISMTPServer) { m_pISMTPServer->AddRef();
hr = m_pISMTPServer->QueryInterface( IID_ISMTPServerEx, (LPVOID *) &m_pISMTPServerEx); if(FAILED(hr)) { m_pISMTPServerEx = NULL;; } else { m_CICatQueries.SetISMTPServerEx( m_pISMTPServerEx); m_CICatAsyncContext.SetISMTPServerEx( m_pISMTPServerEx); } }
_ASSERT(m_pICatParams == NULL); m_pICatParams = pICatParams; m_pICatParams->AddRef(); }
//
// Now dispatch this block if we are the last request to finish
//
if( (DWORD) (InterlockedIncrement((PLONG)&m_cBlockRequestsReadyForDispatch)) == m_cBlockSize) DispatchBlock();
CatFunctLeaveEx((LPARAM)this); }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::DispatchBlock
//
// Synopsis: Send the LDAP query for this search request block
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/11 15:00:44: Created.
// haozhang 2001/11/30 Fix for 193848
//-------------------------------------------------------------
VOID CSearchRequestBlock::DispatchBlock() { HRESULT hr = S_OK; CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::DispatchBlock");
m_pConn->RemoveSearchRequestBlockFromList(this);
//
// If the block is empty, we will delete it and bail out.
// We will AV down the road otherwise.
// This is an unintended result of fix of 193848.
//
if ( 0 == DwNumBlockRequests()) { DebugTrace((LPARAM)this, "DispatchBlock bailing out because the block is empty"); delete this; goto CLEANUP; }
//
// Build up the query string
//
hr = HrTriggerBuildQueries(); ERROR_CLEANUP_LOG("HrTriggerBuildQueryies"); //
// Send the query
//
hr = HrTriggerSendQuery(); ERROR_CLEANUP_LOG("HrTriggerSendQuery");
CLEANUP: if(FAILED(hr)) { CompleteBlockWithError(hr); delete this; } //
// this may be deleted, but that's okay; we're just tracing a user
// value
//
CatFunctLeaveEx((LPARAM)this); }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::HrTriggerBuildQueries
//
// Synopsis: Trigger the BuildQueries event
//
// Arguments:
// pCICatQueries: CICategorizerQueriesIMP object to use
//
// Returns:
// S_OK: Success
// error from dispatcher
//
// History:
// jstamerj 1999/03/11 19:03:29: Created.
//
//-------------------------------------------------------------
HRESULT CSearchRequestBlock::HrTriggerBuildQueries() { HRESULT hr = S_OK; EVENTPARAMS_CATBUILDQUERIES Params;
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerBuildQueries");
Params.pICatParams = m_pICatParams; Params.dwcAddresses = DwNumBlockRequests(); Params.rgpICatItems = m_rgpICatItems; Params.pICatQueries = &m_CICatQueries; Params.pfnDefault = HrBuildQueriesDefault; Params.pblk = this;
if(m_pISMTPServer) {
hr = m_pISMTPServer->TriggerServerEvent( SMTP_MAILTRANSPORT_CATEGORIZE_BUILDQUERIES_EVENT, &Params); if(FAILED(hr) && (hr != E_NOTIMPL)) { ERROR_LOG("m_pISMTPServer->TriggerServerEvent(buildquery)"); }
} else { hr = E_NOTIMPL; } if(hr == E_NOTIMPL) { //
// Events are disabled
//
hr = HrBuildQueriesDefault( S_OK, &Params); if(FAILED(hr)) { ERROR_LOG("HrBuildQueriesDefault"); } } //
// Make sure somebody really set the query string
//
if(SUCCEEDED(hr) && (m_pszSearchFilter == NULL)) {
hr = E_FAIL; ERROR_LOG("--no filter--"); }
DebugTrace((LPARAM)this, "returning hr %08lx",hr); CatFunctLeaveEx((LPARAM)this); return hr; }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::HrBuildQueriesDefault
//
// Synopsis: Default implementation of the build queries sink
//
// Arguments:
// hrStatus: Status of events so far
// pContext: Event params context
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/11 19:42:53: Created.
//
//-------------------------------------------------------------
HRESULT CSearchRequestBlock::HrBuildQueriesDefault( HRESULT HrStatus, PVOID pContext) { HRESULT hr = S_OK; PEVENTPARAMS_CATBUILDQUERIES pParams; DWORD cReqs, cOrTerms, idx, idxSecondToLastTerm, idxLastTerm; DWORD cbSearchFilter, rgcbSearchFilters[MAX_SEARCH_BLOCK_SIZE]; LPSTR pszSearchFilterNew; CSearchRequestBlock *pblk;
pParams = (PEVENTPARAMS_CATBUILDQUERIES)pContext; _ASSERT(pParams); pblk = (CSearchRequestBlock *)pParams->pblk; _ASSERT(pblk);
CatFunctEnterEx((LPARAM)pblk, "CSearchRequestBlock::HrBuildQueriesDefault");
cReqs = pblk->DwNumBlockRequests(); _ASSERT( cReqs > 0 );
cOrTerms = cReqs - 1; //
// Figure out the size of the composite search filter
//
cbSearchFilter = 0;
for (idx = 0; idx < cReqs; idx++) {
rgcbSearchFilters[idx] = strlen(pblk->m_prgSearchRequests[idx].pszSearchFilter);
cbSearchFilter += rgcbSearchFilters[idx]; }
cbSearchFilter += cOrTerms * (sizeof( "(| )" ) - 1); cbSearchFilter++; // Terminating NULL.
pszSearchFilterNew = new CHAR [cbSearchFilter];
if (pszSearchFilterNew != NULL) {
idxLastTerm = cReqs - 1; idxSecondToLastTerm = idxLastTerm - 1; //
// We special case the cReqs == 1
//
if (cReqs == 1) {
strcpy( pszSearchFilterNew, pblk->m_prgSearchRequests[0].pszSearchFilter);
} else { //
// The loop below builds up the block filter all the way up to the
// last term. For each term, it adds a "(| " to start a new OR
// term, then adds the OR term itself, then puts a space after the
// OR term. Also, it puts a matching ")" at the end of the
// search filter string being built up.
//
LPSTR szNextItem = &pszSearchFilterNew[0]; LPSTR szTerminatingParens = &pszSearchFilterNew[cbSearchFilter - 1 - (cReqs-1)];
pszSearchFilterNew[cbSearchFilter - 1] = 0;
for (idx = 0; idx <= idxSecondToLastTerm; idx++) {
strcpy( szNextItem, "(| " ); szNextItem += sizeof( "(| " ) - 1;
strcpy( szNextItem, pblk->m_prgSearchRequests[idx].pszSearchFilter); szNextItem += rgcbSearchFilters[idx]; *szNextItem++ = ' '; *szTerminatingParens++ = ')'; }
//
// Now, all that remains is to add in the last OR term
//
CopyMemory( szNextItem, pblk->m_prgSearchRequests[idxLastTerm].pszSearchFilter, rgcbSearchFilters[idxLastTerm]);
}
_ASSERT( ((DWORD) lstrlen(pszSearchFilterNew)) < cbSearchFilter );
//
// Save our generated filter string in ICategorizerQueries
//
hr = pblk->m_CICatQueries.SetQueryStringNoAlloc(pszSearchFilterNew);
// There's no good reason for that to fail...
_ASSERT(SUCCEEDED(hr));
} else {
hr = E_OUTOFMEMORY; ERROR_LOG_STATIC( "new CHAR[]", pblk, pblk->GetISMTPServerEx()); }
DebugTrace((LPARAM)pblk, "returning hr %08lx", hr); CatFunctLeaveEx((LPARAM)pblk); return hr; }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::HrTriggerSendQuery
//
// Synopsis: Trigger the SendQuery event
//
// Arguments:
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/11 20:18:02: Created.
//
//-------------------------------------------------------------
HRESULT CSearchRequestBlock::HrTriggerSendQuery() { HRESULT hr = S_OK; EVENTPARAMS_CATSENDQUERY Params;
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerSendQuery");
Params.pICatParams = m_pICatParams; Params.pICatQueries = &m_CICatQueries; Params.pICatAsyncContext = &m_CICatAsyncContext; Params.pIMailTransportNotify = NULL; // These should be set in CStoreParams
Params.pvNotifyContext = NULL; Params.hrResolutionStatus = S_OK; Params.pblk = this; Params.pfnDefault = HrSendQueryDefault; Params.pfnCompletion = HrSendQueryCompletion;
if(m_pISMTPServer) {
hr = m_pISMTPServer->TriggerServerEvent( SMTP_MAILTRANSPORT_CATEGORIZE_SENDQUERY_EVENT, &Params); if(FAILED(hr) && (hr != E_NOTIMPL)) { ERROR_LOG("m_pISMTPServer->TriggerServerEvent(sendquery)"); }
} else { hr = E_NOTIMPL; } if(hr == E_NOTIMPL) { //
// Events are disabled
// Heap allocation is required
//
PEVENTPARAMS_CATSENDQUERY pParams; pParams = new EVENTPARAMS_CATSENDQUERY; if(pParams == NULL) {
hr = E_OUTOFMEMORY; ERROR_LOG("new EVENTPARAMS_CATSENDQUERY");
} else { CopyMemory(pParams, &Params, sizeof(EVENTPARAMS_CATSENDQUERY)); HrSendQueryDefault( S_OK, pParams); hr = S_OK; } }
DebugTrace((LPARAM)this, "returning %08lx", (hr == MAILTRANSPORT_S_PENDING) ? S_OK : hr); CatFunctLeaveEx((LPARAM)this); return (hr == MAILTRANSPORT_S_PENDING) ? S_OK : hr; } // CSearchRequestBlock::HrTriggerSendQuery
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::HrSendQueryDefault
//
// Synopsis: The default sink function for the SendQuery event
//
// Arguments:
// hrStatus: status of the event so far
// pContext: Event params context
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/16 11:46:24: Created.
//
//-------------------------------------------------------------
HRESULT CSearchRequestBlock::HrSendQueryDefault( HRESULT HrStatus, PVOID pContext) { HRESULT hr = S_OK; PEVENTPARAMS_CATSENDQUERY pParams; CSearchRequestBlock *pBlock; LPWSTR *rgpszAttributes = NULL; ICategorizerParametersEx *pIPhatParams = NULL; ICategorizerRequestedAttributes *pIRequestedAttributes = NULL;
pParams = (PEVENTPARAMS_CATSENDQUERY) pContext; _ASSERT(pParams);
pBlock = (CSearchRequestBlock *) pParams->pblk; _ASSERT(pBlock); CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSendQueryDefault"); hr = pParams->pICatParams->QueryInterface( IID_ICategorizerParametersEx, (LPVOID *)&pIPhatParams);
if(FAILED(hr)) { ERROR_LOG_STATIC( "pParams->pICatParams->QueryInterface(IID_ICategorizerParametersEx", pBlock, pBlock->GetISMTPServerEx()); pIPhatParams = NULL; goto CLEANUP; }
hr = pIPhatParams->GetRequestedAttributes( &pIRequestedAttributes); ERROR_CLEANUP_LOG_STATIC( "pIPhatParams->GetRequestedAttributes", pBlock, pBlock->GetISMTPServerEx());
hr = pIRequestedAttributes->GetAllAttributesW( &rgpszAttributes); ERROR_CLEANUP_LOG_STATIC( "pIRequestedAttributes->GetAllAttributesW", pBlock, pBlock->GetISMTPServerEx());
hr = pBlock->m_pConn->AsyncSearch( pBlock->m_pConn->GetNamingContextW(), LDAP_SCOPE_SUBTREE, pBlock->m_pszSearchFilter, (LPCWSTR *)rgpszAttributes, 0, // Do not do a paged search
LDAPCompletion, pParams); ERROR_CLEANUP_LOG_STATIC( "pBlock->m_pConn->AsyncSearch", pBlock, pBlock->GetISMTPServerEx());
CLEANUP: if(FAILED(hr)) {
ErrorTrace((LPARAM)pBlock, "HrSendQueryDefault failing hr %08lx", hr); //
// Call the completion routine directly with the error
//
hr = pParams->pICatAsyncContext->CompleteQuery( pParams, // Query context
hr, // Status
0, // dwcResults
NULL, // rgpItemAttributes,
TRUE); // fFinalCompletion
//
// CompleteQuery should not fail
//
_ASSERT(SUCCEEDED(hr)); } if(pIRequestedAttributes) pIRequestedAttributes->Release(); if(pIPhatParams) pIPhatParams->Release();
CatFunctLeaveEx((LPARAM)pBlock); return MAILTRANSPORT_S_PENDING; } // CSearchRequestBlock::HrSendQueryDefault
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::LDAPCompletion
//
// Synopsis: Wrapper for the default processing completion of SendQuery
//
// Arguments: [ctx] -- Opaque pointer to EVENTPARAMS_SENDQUERY being
// completed
// [dwNumReults] -- The number of objects found
// [rgpICatItemAttributes] -- An array of
// ICategorizerItemAttributes; one per object found
// [hrStatus] -- The error code if the search request failed
// fFinalCompletion:
// FALSE: This is a completion for
// pending results; there will be another completion
// called with more results
// TRUE: This is the final completion call
//
//
// Returns: Nothing
//
// History:
// jstamerj 1999/03/16 12:23:54: Created
//
//-------------------------------------------------------------
VOID CSearchRequestBlock::LDAPCompletion( LPVOID ctx, DWORD dwNumResults, ICategorizerItemAttributes **rgpICatItemAttributes, HRESULT hrStatus, BOOL fFinalCompletion) { HRESULT hr; PEVENTPARAMS_CATSENDQUERY pParams; CSearchRequestBlock *pBlock;
pParams = (PEVENTPARAMS_CATSENDQUERY) ctx; _ASSERT(pParams);
pBlock = (CSearchRequestBlock *) pParams->pblk; _ASSERT(pBlock);
CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::LDAPCompletion");
if(FAILED(hrStatus)) { //
// Log async completion failure
//
hr = hrStatus; ERROR_LOG_STATIC( "async", pBlock, pBlock->GetISMTPServerEx()); }
//
// Call the normal sink completion routine
//
hr = pParams->pICatAsyncContext->CompleteQuery( pParams, // Query Context
hrStatus, // Status
dwNumResults, // dwcResults
rgpICatItemAttributes, // rgpItemAttributes
fFinalCompletion); // Is this the final completion for the query?
_ASSERT(SUCCEEDED(hr));
CatFunctLeaveEx((LPARAM)pBlock); }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::HrSendQueryCompletion
//
// Synopsis: The completion routine for the SendQuery event
//
// Arguments:
// hrStatus: status of the event so far
// pContext: Event params context
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/16 12:52:22: Created.
//
//-------------------------------------------------------------
HRESULT CSearchRequestBlock::HrSendQueryCompletion( HRESULT HrStatus, PVOID pContext) { HRESULT hr = S_OK; PEVENTPARAMS_CATSENDQUERY pParams; CSearchRequestBlock *pBlock;
pParams = (PEVENTPARAMS_CATSENDQUERY) pContext; _ASSERT(pParams);
pBlock = (CSearchRequestBlock *) pParams->pblk; _ASSERT(pBlock);
CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSendQueryCompletion");
//
// Log async failure
//
if(FAILED(HrStatus)) { hr = HrStatus; ERROR_LOG_STATIC( "async", pBlock, pBlock->GetISMTPServerEx()); }
pBlock->CompleteSearchBlock( pParams->hrResolutionStatus);
if(pBlock->m_pISMTPServer == NULL) { //
// Events are disabled
// We must free the eventparams
//
delete pParams; } //
// The purpose of this block is complete. Today is a good day to
// die!
// -- Lt. Commander Worf
//
delete pBlock;
CatFunctLeaveEx((LPARAM)pBlock); return S_OK; } // HrSendQueryCompletion
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::CompleteSearchBlock
//
// Synopsis: Completion routine when the SendQuery event is done
//
// Arguments:
// hrStatus: Resolution status
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/16 13:36:33: Created.
//
//-------------------------------------------------------------
VOID CSearchRequestBlock::CompleteSearchBlock( HRESULT hrStatus) { HRESULT hr = S_OK; HRESULT hrFetch, hrResult; DWORD dwCount; CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::CompleteSearchBlock");
hr = HrTriggerSortQueryResult(hrStatus); ERROR_CLEANUP_LOG("HrTriggerSortQueryResult"); //
// Check every ICategorizerItem
// If any one of them does not have an hrStatus set, set it to
// HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
//
for(dwCount = 0; dwCount < DwNumBlockRequests(); dwCount++) {
hrFetch = m_rgpICatItems[dwCount]->GetHRESULT( ICATEGORIZERITEM_HRSTATUS, &hrResult);
if(FAILED(hrFetch)) { _ASSERT(hrFetch == CAT_E_PROPNOTFOUND); _VERIFY(SUCCEEDED( m_rgpICatItems[dwCount]->PutHRESULT( ICATEGORIZERITEM_HRSTATUS, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)))); } }
CLEANUP: if(FAILED(hr)) {
ErrorTrace((LPARAM)this, "Failing block hr %08lx", hr); PutBlockHRESULT(hr); } //
// Call all the individual completion routines
//
CallCompletions();
CatFunctLeaveEx((LPARAM)this); } // CSearchRequestBlock::CompleteSearchBlock
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::PutBlockHRESULT
//
// Synopsis: Set the status of every ICatItem in the block to some hr
//
// Arguments:
// hr: Status to set
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/16 14:03:30: Created.
//
//-------------------------------------------------------------
VOID CSearchRequestBlock::PutBlockHRESULT( HRESULT hr) { DWORD dwCount;
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::PutBlockHRESULT"); DebugTrace((LPARAM)this, "hr = %08lx", hr);
for(dwCount = 0; dwCount < DwNumBlockRequests(); dwCount++) {
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]); //
// Set the error status
//
_VERIFY(SUCCEEDED(preq->pCCatAddr->PutHRESULT( ICATEGORIZERITEM_HRSTATUS, hr))); }
CatFunctLeaveEx((LPARAM)this); } // CSearchRequestBlock::PutBlockHRESULT
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::CallCompletions
//
// Synopsis: Call the completion routine of every item in the block
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/16 14:05:50: Created.
// dlongley 2001/10/23: Modified.
//
//-------------------------------------------------------------
VOID CSearchRequestBlock::CallCompletions() { DWORD dwCount;
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::CallCompletions");
//
// Get an Insertion context before calling completions so that
// newly inserted searches will be batched
//
for(dwCount = 0; dwCount < DwNumBlockRequests(); dwCount++) {
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
preq->pslrc->AddRef(); preq->pslrc->GetInsertionContext();
preq->fnSearchCompletion( preq->pCCatAddr, preq->pslrc, m_pConn); }
m_pConn->DecrementPendingSearches( DwNumBlockRequests());
for(dwCount = 0; dwCount < DwNumBlockRequests(); dwCount++) {
PSEARCH_REQUEST preq = &(m_prgSearchRequests[dwCount]);
preq->pslrc->ReleaseInsertionContext(); preq->pslrc->Release(); }
CatFunctLeaveEx((LPARAM)this); } // CSearchRequestBlock::CallCompletions
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::HrTriggerSortQueryResult
//
// Synopsis: Trigger the SortQueryResult event
//
// Arguments:
// hrStatus: Status of Resolution
//
// Returns:
// S_OK: Success
// error from the dispatcher
//
// History:
// jstamerj 1999/03/16 14:09:12: Created.
//
//-------------------------------------------------------------
HRESULT CSearchRequestBlock::HrTriggerSortQueryResult( HRESULT hrStatus) { HRESULT hr = S_OK; EVENTPARAMS_CATSORTQUERYRESULT Params;
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::HrTriggerSortQueryResult");
Params.pICatParams = m_pICatParams; Params.hrResolutionStatus = hrStatus; Params.dwcAddresses = DwNumBlockRequests(); Params.rgpICatItems = m_rgpICatItems; Params.dwcResults = m_csaItemAttr.Size(); Params.rgpICatItemAttributes = m_csaItemAttr; Params.pfnDefault = HrSortQueryResultDefault; Params.pblk = this;
if(m_pISMTPServer) {
hr = m_pISMTPServer->TriggerServerEvent( SMTP_MAILTRANSPORT_CATEGORIZE_SORTQUERYRESULT_EVENT, &Params); if(FAILED(hr) && (hr != E_NOTIMPL)) { ERROR_LOG("m_pISMTPServer->TriggerServerEvent"); } } else { hr = E_NOTIMPL; } if(hr == E_NOTIMPL) { //
// Events are disabled, call default processing
//
HrSortQueryResultDefault( S_OK, &Params); hr = S_OK; }
DebugTrace((LPARAM)this, "returning %08lx", hr); CatFunctLeaveEx((LPARAM)this); return hr; } // CSearchRequestBlock::HrTriggerSortQueryResult
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::HrSortQueryResultDefault
//
// Synopsis: Default sink for SortQueryResult -- match the objects found
// with the objects requested
//
// Arguments:
// hrStatus: Status of events
// pContext: Params context for this event
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/16 14:17:49: Created.
//
//-------------------------------------------------------------
HRESULT CSearchRequestBlock::HrSortQueryResultDefault( HRESULT hrStatus, PVOID pContext) { HRESULT hr = S_OK; PEVENTPARAMS_CATSORTQUERYRESULT pParams; CSearchRequestBlock *pBlock; DWORD dwAttrIndex, dwReqIndex; ATTRIBUTE_ENUMERATOR enumerator;
pParams = (PEVENTPARAMS_CATSORTQUERYRESULT) pContext; _ASSERT(pParams);
pBlock = (CSearchRequestBlock *) pParams->pblk; _ASSERT(pBlock);
CatFunctEnterEx((LPARAM)pBlock, "CSearchRequestBlock::HrSortQueryResultDefault"); DebugTrace((LPARAM)pBlock, "hrResolutionStatus %08lx, dwcResults %08lx", pParams->hrResolutionStatus, pParams->dwcResults);
if(FAILED(pParams->hrResolutionStatus)) { //
// Fail the entire block
//
pBlock->PutBlockHRESULT(pParams->hrResolutionStatus); goto CLEANUP; } //
// Resolution succeeded
// If dwcResults is not zero, then rgpICatItemAttrs can NOT be null
//
_ASSERT((pParams->dwcResults == 0) || (pParams->rgpICatItemAttributes != NULL));
//
// Loop through every rgpICatItemAttrs. For each
// ICategorizerItemAttributes, looking for a matching SEARCH_REQUEST
//
for(dwAttrIndex = 0; dwAttrIndex < pParams->dwcResults; dwAttrIndex++) { ICategorizerItemAttributes *pICatItemAttr = NULL; ICategorizerUTF8Attributes *pIUTF8 = NULL;
pICatItemAttr = pParams->rgpICatItemAttributes[dwAttrIndex]; LPCSTR pszLastDistinguishingAttribute = NULL; BOOL fEnumerating = FALSE;
hr = pICatItemAttr->QueryInterface( IID_ICategorizerUTF8Attributes, (LPVOID *) &pIUTF8); ERROR_CLEANUP_LOG_STATIC( "pICatItemAttr->QueryInterface", pBlock, pBlock->GetISMTPServerEx());
for(dwReqIndex = 0; dwReqIndex < pBlock->DwNumBlockRequests(); dwReqIndex++) { PSEARCH_REQUEST preq = &(pBlock->m_prgSearchRequests[dwReqIndex]); //#ifdef DEBUG
// WCHAR wszPreqDistinguishingAttributeValue[20];
//#else
WCHAR wszPreqDistinguishingAttributeValue[CAT_MAX_INTERNAL_FULL_EMAIL]; //#endif
LPWSTR pwszPreqDistinguishingAttributeValue = wszPreqDistinguishingAttributeValue; DWORD cPreqDistinguishingAttributeValue; DWORD rc;
//
// If we don't have a distinguishing attribute and
// distinguishing attribute value for this search
// request, we've no hope of matching it up
//
if((preq->pszDistinguishingAttribute == NULL) || (preq->pszDistinguishingAttributeValue == NULL)) continue;
// convert pszDistinguishingAttributeValue to unicode
cPreqDistinguishingAttributeValue = MultiByteToWideChar(CP_UTF8, 0, preq->pszDistinguishingAttributeValue, -1, pwszPreqDistinguishingAttributeValue, 0); if (cPreqDistinguishingAttributeValue > (sizeof(wszPreqDistinguishingAttributeValue) / sizeof(WCHAR)) ) { pwszPreqDistinguishingAttributeValue = new WCHAR[cPreqDistinguishingAttributeValue + 1]; if (pwszPreqDistinguishingAttributeValue == NULL) { hr = E_OUTOFMEMORY; ERROR_LOG_STATIC( "new WCHAR[]", pBlock, pBlock->GetISMTPServerEx()); continue; } } rc = MultiByteToWideChar(CP_UTF8, 0, preq->pszDistinguishingAttributeValue, -1, pwszPreqDistinguishingAttributeValue, cPreqDistinguishingAttributeValue); if (rc == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); ERROR_LOG_STATIC( "MultiByteToWideChar", pBlock, pBlock->GetISMTPServerEx()); continue; }
//
// Start an attribute value enumeration if necessary
//
if((pszLastDistinguishingAttribute == NULL) || (lstrcmpi(pszLastDistinguishingAttribute, preq->pszDistinguishingAttribute) != 0)) { if(fEnumerating) { pIUTF8->EndUTF8AttributeEnumeration(&enumerator); } hr = pIUTF8->BeginUTF8AttributeEnumeration( preq->pszDistinguishingAttribute, &enumerator); fEnumerating = SUCCEEDED(hr); pszLastDistinguishingAttribute = preq->pszDistinguishingAttribute; } else { //
// else just rewind our current enumeration
//
if(fEnumerating) _VERIFY(SUCCEEDED(pIUTF8->RewindUTF8AttributeEnumeration( &enumerator))); } //
// If we can't enumerate through the distinguishing
// attribute, there's no hope in matching up requests
//
if(!fEnumerating) continue;
//
// See if the distinguishing attribute value matches
//
LPSTR pszDistinguishingAttributeValue; hr = pIUTF8->GetNextUTF8AttributeValue( &enumerator, &pszDistinguishingAttributeValue); while(SUCCEEDED(hr)) { hr = wcsutf8cmpi(pwszPreqDistinguishingAttributeValue, pszDistinguishingAttributeValue); if (SUCCEEDED(hr)) { if(hr == S_OK) { DebugTrace((LPARAM)pBlock, "Matched dwAttrIndex %d with dwReqIndex %d", dwAttrIndex, dwReqIndex); pBlock->MatchItem( preq->pCCatAddr, pICatItemAttr); } hr = pIUTF8->GetNextUTF8AttributeValue( &enumerator, &pszDistinguishingAttributeValue); } else { ERROR_LOG_STATIC( "wcsutf8cmpi", pBlock, pBlock->GetISMTPServerEx()); } }
if (pwszPreqDistinguishingAttributeValue != wszPreqDistinguishingAttributeValue) { delete[] pwszPreqDistinguishingAttributeValue; } } //
// End any last enumeration going on
//
if(fEnumerating) pIUTF8->EndUTF8AttributeEnumeration(&enumerator); fEnumerating = FALSE; if(pIUTF8) { pIUTF8->Release(); pIUTF8 = NULL; } }
CLEANUP: CatFunctLeaveEx((LPARAM)pBlock); return S_OK; } // CSearchRequestBlock::HrSortQueryResultDefault
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::MatchItem
//
// Synopsis: Match a particular ICategorizerItem to a particular ICategorizerItemAttributes
// If already matched with an ICategorizerItemAttributes with an
// identical ID then set item status to CAT_E_MULTIPLE_MATCHES
// If already matched with an ICategorizerItemAttributes with a
// different ID then attempt aggregation
////
// Arguments:
// pICatItem: an ICategorizerItem
// pICatItemAttr: the matching attribute interface for pICatItem
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/16 14:36:45: Created.
//
//-------------------------------------------------------------
VOID CSearchRequestBlock::MatchItem( ICategorizerItem *pICatItem, ICategorizerItemAttributes *pICatItemAttr) { HRESULT hr = S_OK; ICategorizerItemAttributes *pICatItemAttr_Current = NULL;
CatFunctEnterEx((LPARAM)this, "CSearchRequestBlock::MatchItem");
_ASSERT(pICatItem); _ASSERT(pICatItemAttr); //
// Check to see if this item already has
// ICategorizerItemAttributes set
//
hr = pICatItem->GetICategorizerItemAttributes( ICATEGORIZERITEM_ICATEGORIZERITEMATTRIBUTES, &pICatItemAttr_Current); if(SUCCEEDED(hr)) { //
// This guy is already matched. Is the duplicate from the
// same resolver sink?
//
GUID GOriginal, GNew; GOriginal = pICatItemAttr_Current->GetTransportSinkID(); GNew = pICatItemAttr->GetTransportSinkID();
if(GOriginal == GNew) { //
// Two matches from the same resolver sink indicates that
// there are multiple matches for this object. This is an
// error.
//
//
// This guy is already matched -- the distinguishing attribute
// really wasn't distinguishing. Set error hrstatus.
//
LogAmbiguousEvent(pICatItem);
_VERIFY(SUCCEEDED( pICatItem->PutHRESULT( ICATEGORIZERITEM_HRSTATUS, CAT_E_MULTIPLE_MATCHES))); } else {
//
// We have multiple matches from different resolver
// sinks. Let's try to aggregate the new
// ICategorizerItemAttributes
//
hr = pICatItemAttr_Current->AggregateAttributes( pICatItemAttr);
if(FAILED(hr) && (hr != E_NOTIMPL)) { //
// Fail categorization for this item
//
ERROR_LOG("pICatItemAttr_Current->AggregateAttributes"); _VERIFY(SUCCEEDED( pICatItem->PutHRESULT( ICATEGORIZERITEM_HRSTATUS, hr))); } } } else { //
// Normal case -- set the ICategorizerItemAttribute property
// of ICategorizerItem
//
_VERIFY(SUCCEEDED( pICatItem->PutICategorizerItemAttributes( ICATEGORIZERITEM_ICATEGORIZERITEMATTRIBUTES, pICatItemAttr))); //
// Set hrStatus of this guy to success
//
_VERIFY(SUCCEEDED( pICatItem->PutHRESULT( ICATEGORIZERITEM_HRSTATUS, S_OK))); }
if(pICatItemAttr_Current) pICatItemAttr_Current->Release();
CatFunctLeaveEx((LPARAM)this); } // CSearchRequestBlock::MatchItem
//+------------------------------------------------------------
//
// Function: CBatchLdapConnection::HrInsertSearchRequest
//
// Synopsis: Insert a search request
//
// Arguments:
// pISMTPServer: ISMTPServer interface to use for triggering events
// pCCatAddr: Address item for the search
// fnSearchCompletion: Async Completion routine
// ctxSearchCompletion: Context to pass to the async completion routine
// pszSearchFilter: Search filter to use
// pszDistinguishingAttribute: The distinguishing attribute for matching
// pszDistinguishingAttributeValue: above attribute's distinguishing value
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/08 19:41:37: Created.
//
//-------------------------------------------------------------
HRESULT CBatchLdapConnection::HrInsertSearchRequest( ISMTPServer *pISMTPServer, ICategorizerParameters *pICatParams, CCatAddr *pCCatAddr, LPSEARCHCOMPLETION fnSearchCompletion, CStoreListResolveContext *pslrc, LPSTR pszSearchFilter, LPSTR pszDistinguishingAttribute, LPSTR pszDistinguishingAttributeValue) { HRESULT hr = S_OK; CSearchRequestBlock *pBlock;
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::HrInsertSearchRequest");
_ASSERT(m_cInsertionContext); _ASSERT(pCCatAddr); _ASSERT(fnSearchCompletion); _ASSERT(pszSearchFilter); _ASSERT(pszDistinguishingAttribute); _ASSERT(pszDistinguishingAttributeValue);
pBlock = GetSearchRequestBlock();
if(pBlock == NULL) {
ErrorTrace((LPARAM)this, "out of memory getting a search block"); hr = E_OUTOFMEMORY; ERROR_LOG_ADDR(pCCatAddr, "GetSearchRequestBlock"); goto CLEANUP; }
pBlock->InsertSearchRequest( pISMTPServer, pICatParams, pCCatAddr, fnSearchCompletion, pslrc, pszSearchFilter, pszDistinguishingAttribute, pszDistinguishingAttributeValue);
CLEANUP: DebugTrace((LPARAM)this, "Returning hr %08lx", hr); CatFunctLeaveEx((LPARAM)this); return hr; }
//+------------------------------------------------------------
//
// Function: CBatchLdapConnection::GetSearchRequestBlock
//
// Synopsis: Gets the next available search block with room
//
// Arguments: NONE
//
// Returns:
// NULL: Out of memory
// else, a search block object
//
// History:
// jstamerj 1999/03/08 19:41:37: Created.
// haozhang 2001/11/25 updated for 193848
//
//-------------------------------------------------------------
CSearchRequestBlock * CBatchLdapConnection::GetSearchRequestBlock() { HRESULT hr = E_FAIL; PLIST_ENTRY ple; CSearchRequestBlock *pBlock = NULL;
//
// Updated for fix of 193848
// We do two passes. In first one, we will go through the list
// and reserve a slot if available(then return). If we don't,
// we will created a new block and proceed with a second pass. In
// second pass, we will first insert the block to the list, then
// go through the list again to reserve a slot in the first
// avaiable block. The fix differs from previous version in that
// we will not simply reserve a slot in the new block we just
// created. Instead, we will go through the list again in case
// existing block still has room. Therefore, we avoided the
// core problem in which we reserve a slot on new block even
// though there is room in existing block.
//
AcquireSpinLock(&m_spinlock); //
// See if there is an insertion block with available slots
//
for(ple = m_listhead.Flink; (ple != &m_listhead) && (FAILED(hr)); ple = ple->Flink) {
pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock, m_listentry);
hr = pBlock->ReserveSlot(); }
ReleaseSpinLock(&m_spinlock);
if(SUCCEEDED(hr)) return pBlock;
//
// Create a new block
//
pBlock = new (m_nMaxSearchBlockSize) CSearchRequestBlock(this); if(pBlock) { AcquireSpinLock(&m_spinlock);
InsertTailList(&m_listhead, &(pBlock->m_listentry)); //
// Again,see if there is an insertion block with available slots
//
for(ple = m_listhead.Flink; (ple != &m_listhead) && (FAILED(hr)); ple = ple->Flink) {
pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock, m_listentry);
hr = pBlock->ReserveSlot(); } ReleaseSpinLock(&m_spinlock);
_ASSERT(SUCCEEDED(hr)); } return pBlock; }
//+------------------------------------------------------------
//
// Function: CSearchRequestBlock::LogAmbiguousEvent
//
// Synopsis: Eventlogs an ambiguous address error
//
// Arguments:
// pItem: ICatItem with ambig address
//
// Returns: Nothing
//
// History:
// jstamerj 2001/12/13 00:03:16: Created.
//
//-------------------------------------------------------------
VOID CSearchRequestBlock::LogAmbiguousEvent( IN ICategorizerItem *pItem) { HRESULT hr = S_OK; LPCSTR rgSubStrings[2]; CHAR szAddress[CAT_MAX_INTERNAL_FULL_EMAIL]; CHAR szAddressType[CAT_MAX_ADDRESS_TYPE_STRING];
CatFunctEnter("CIMstRecipListAddr::LogNDREvent");
//
// Get the address
//
hr = HrGetAddressStringFromICatItem( pItem, sizeof(szAddressType) / sizeof(szAddressType[0]), szAddressType, sizeof(szAddress) / sizeof(szAddress[0]), szAddress); if(FAILED(hr)) { //
// Still log an event, but use "unknown" for address type/string
//
lstrcpyn(szAddressType, "unknown", sizeof(szAddressType) / sizeof(szAddressType[0])); lstrcpyn(szAddress, "unknown", sizeof(szAddress) / sizeof(szAddress[0])); hr = S_OK; }
rgSubStrings[0] = szAddressType; rgSubStrings[1] = szAddress;
//
// Can we log an event?
//
if(GetISMTPServerEx() == NULL) { FatalTrace((LPARAM)0, "Unable to log ambiguous address event; NULL pISMTPServerEx"); for(DWORD dwIdx = 0; dwIdx < 2; dwIdx++) { if( rgSubStrings[dwIdx] != NULL ) { FatalTrace((LPARAM)0, "Event String %d: %s", dwIdx, rgSubStrings[dwIdx]); } } } else { CatLogEvent( GetISMTPServerEx(), CAT_EVENT_AMBIGUOUS_ADDRESS, 2, rgSubStrings, S_OK, szAddress, LOGEVENT_FLAG_PERIODIC, LOGEVENT_LEVEL_MINIMUM); } }
//+------------------------------------------------------------
//
// Function: CBatchLdapConnection::DispatchBlocks
//
// Synopsis: Dispatch all the blocks in a list
//
// Arguments:
// plisthead: List to dispatch
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/11 15:16:36: Created.
//
//-------------------------------------------------------------
VOID CBatchLdapConnection::DispatchBlocks( PLIST_ENTRY plisthead) { PLIST_ENTRY ple, ple_next; CSearchRequestBlock *pBlock;
for(ple = plisthead->Flink; ple != plisthead; ple = ple_next) {
ple_next = ple->Flink;
pBlock = CONTAINING_RECORD(ple, CSearchRequestBlock, m_listentry);
pBlock->DispatchBlock(); } }
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::CStoreListResolveContext
//
// Synopsis: Construct a CStoreListResolveContext object
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/22 12:16:08: Created.
//
//-------------------------------------------------------------
CStoreListResolveContext::CStoreListResolveContext( CEmailIDLdapStore<CCatAddr> *pStore) { CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::CStoreListResolveContext");
m_cRefs = 1; m_dwSignature = SIGNATURE_CSTORELISTRESOLVECONTEXT; m_pConn = NULL; m_fCanceled = FALSE; m_dwcRetries = 0; m_dwcCompletedLookups = 0; InitializeCriticalSectionAndSpinCount(&m_cs, 2000); m_pISMTPServer = NULL; m_pISMTPServerEx = NULL; m_pICatParams = NULL; m_dwcInsertionContext = 0; m_pStore = pStore;
CatFunctLeaveEx((LPARAM)this); } // CStoreListResolveContext::CStoreListResolveContext
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::~CStoreListResolveContext
//
// Synopsis: Destruct a list resolve context
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/22 12:18:01: Created.
//
//-------------------------------------------------------------
CStoreListResolveContext::~CStoreListResolveContext() { CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::~CStoreListResolveContext");
_ASSERT(m_dwSignature == SIGNATURE_CSTORELISTRESOLVECONTEXT); m_dwSignature = SIGNATURE_CSTORELISTRESOLVECONTEXT_INVALID;
if(m_pConn) m_pConn->Release();
if(m_pISMTPServer) m_pISMTPServer->Release();
if(m_pISMTPServerEx) m_pISMTPServerEx->Release();
if(m_pICatParams) m_pICatParams->Release();
DeleteCriticalSection(&m_cs);
CatFunctLeaveEx((LPARAM)this); } // CStoreListResolveContext::~CStoreListResolveContext
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::HrInitialize
//
// Synopsis: Initailize this object so that it is ready to handle lookups
//
// Arguments:
// pISMTPServer: ISMTPServer interface to use for triggering events
// pICatParams: ICatParams interface to use
//
// Note: All of these string buffers must remain valid for the
// lifetime of this object!
// pszAccount: LDAP account to use for binding
// pszPassword: LDAP password to use
// pszNamingContext: Naming context to use for searches
// pszHost: LDAP Host to connect to
// dwPort: LDAP TCP port to use
// bt: Method of LDAP bind to use
//
// Returns:
// S_OK: Success
// error from LdapConnectionCache
//
// History:
// jstamerj 1999/03/22 12:20:31: Created.
//
//-------------------------------------------------------------
HRESULT CStoreListResolveContext::HrInitialize( ISMTPServer *pISMTPServer, ICategorizerParameters *pICatParams) { HRESULT hr = S_OK; CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrInitialize");
_ASSERT(m_pISMTPServer == NULL); _ASSERT(m_pICatParams == NULL); _ASSERT(pICatParams != NULL);
if(pISMTPServer) { m_pISMTPServer = pISMTPServer; m_pISMTPServer->AddRef();
hr = m_pISMTPServer->QueryInterface( IID_ISMTPServerEx, (LPVOID *) &m_pISMTPServerEx); if(FAILED(hr)) { //
// Deal with error
//
m_pISMTPServerEx = NULL; hr = S_OK; }
} if(pICatParams) { m_pICatParams = pICatParams; m_pICatParams->AddRef(); }
hr = m_pStore->HrGetConnection( &m_pConn);
if(FAILED(hr)) { ERROR_LOG("m_pStore->HrGetConnection"); m_pConn = NULL; }
DebugTrace((LPARAM)this, "returning %08lx", hr); CatFunctLeaveEx((LPARAM)this); return hr; } // CStoreListResolveContext::HrInitialize
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::HrLookupEntryAsync
//
// Synopsis: Dispatch an async LDAP lookup
//
// Arguments:
// pCCatAddr: Address object to lookup
//
// Returns:
// S_OK: Success
// error from LdapConn
//
// History:
// jstamerj 1999/03/22 12:28:52: Created.
//
//-------------------------------------------------------------
HRESULT CStoreListResolveContext::HrLookupEntryAsync( CCatAddr *pCCatAddr) { HRESULT hr = S_OK; LPSTR pszSearchFilter = NULL; LPSTR pszDistinguishingAttribute = NULL; LPSTR pszDistinguishingAttributeValue = NULL; BOOL fTryAgain;
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrLookupEntryAsync");
//
// Addref the CCatAddr here, release after completion
//
pCCatAddr->AddRef();
hr = pCCatAddr->HrTriggerBuildQuery(); ERROR_CLEANUP_LOG_ADDR(pCCatAddr, "pCCatAddr->HrTriggerBuildQuery");
//
// Fetch the distinguishing attribute and distinguishing attribute
// value from pCCatAddr
//
pCCatAddr->GetStringAPtr( ICATEGORIZERITEM_LDAPQUERYSTRING, &pszSearchFilter); pCCatAddr->GetStringAPtr( ICATEGORIZERITEM_DISTINGUISHINGATTRIBUTE, &pszDistinguishingAttribute); pCCatAddr->GetStringAPtr( ICATEGORIZERITEM_DISTINGUISHINGATTRIBUTEVALUE, &pszDistinguishingAttributeValue);
//
// Check to see if anyone set a search filter
//
if(pszSearchFilter == NULL) {
HRESULT hrStatus; //
// If the status is unset, set it to CAT_E_NO_FILTER
//
hr = pCCatAddr->GetHRESULT( ICATEGORIZERITEM_HRSTATUS, &hrStatus);
if(FAILED(hr)) { ErrorTrace((LPARAM)this, "No search filter set"); ERROR_LOG_ADDR(pCCatAddr, "pCCatAddr->GetHRESULT(hrstatus) -- no filter");
_VERIFY(SUCCEEDED(pCCatAddr->PutHRESULT( ICATEGORIZERITEM_HRSTATUS, CAT_E_NO_FILTER))); } DebugTrace((LPARAM)this, "BuildQuery did not build a search filter"); //
// Call the completion directly
//
pCCatAddr->LookupCompletion(); pCCatAddr->Release(); hr = S_OK; goto CLEANUP; } if((pszDistinguishingAttribute == NULL) || (pszDistinguishingAttributeValue == NULL)) { ErrorTrace((LPARAM)this, "Distinguishing attribute not set"); ERROR_LOG_ADDR(pCCatAddr, "--no distinguishing attribute--"); hr = E_INVALIDARG; goto CLEANUP; } do {
fTryAgain = FALSE; CBatchLdapConnection *pConn;
pConn = GetConnection();
//
// Insert the search request into the CBatchLdapConnection
// object. We will use the email address as the distinguishing
// attribute
//
if(pConn == NULL) {
hr = CAT_E_DBCONNECTION; ERROR_LOG_ADDR(pCCatAddr, "GetConnection");
} else {
pConn->GetInsertionContext();
hr = pConn->HrInsertSearchRequest( m_pISMTPServer, m_pICatParams, pCCatAddr, CStoreListResolveContext::AsyncLookupCompletion, this, pszSearchFilter, pszDistinguishingAttribute, pszDistinguishingAttributeValue);
if(FAILED(hr)) { ERROR_LOG_ADDR(pCCatAddr, "pConn->HrInsertSearchRequest"); }
pConn->ReleaseInsertionContext();
} //
// If the above fails with CAT_E_TRANX_FAILED, it may be due
// to a stale connection. Attempt to reconnect.
//
if((hr == CAT_E_TRANX_FAILED) || (hr == CAT_E_DBCONNECTION)) {
HRESULT hrTryAgain = S_OK;
hrTryAgain = HrInvalidateConnectionAndRetrieveNewConnection(pConn); fTryAgain = SUCCEEDED(hrTryAgain);
if(FAILED(hrTryAgain)) { //
// Declare a new local called hr here because the
// ERROR_LOG macro uses it
//
HRESULT hr = hrTryAgain; ERROR_LOG_ADDR(pCCatAddr, "HrInvalidateConnectionAndRetrieveNewConnection"); } } if(pConn != NULL) pConn->Release();
} while(fTryAgain);
CLEANUP: if(FAILED(hr)) {
ErrorTrace((LPARAM)this, "failing hr %08lx", hr); pCCatAddr->Release(); }
CatFunctLeaveEx((LPARAM)this); return hr; } // CStoreListResolveContext::HrLookupEntryAsync
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::Cancel
//
// Synopsis: Cancels pending lookups
//
// Arguments: NONE
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/22 12:45:21: Created.
//
//-------------------------------------------------------------
VOID CStoreListResolveContext::Cancel() { CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::Cancel");
EnterCriticalSection(&m_cs);
m_fCanceled = TRUE; m_pConn->CancelAllSearches();
LeaveCriticalSection(&m_cs);
CatFunctLeaveEx((LPARAM)this); } // CStoreListResolveContext::HrCancel
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::AsyncLookupCompletion
//
// Synopsis: Handle completion of a CCatAddr from CSearchRequestBlock
//
// Arguments:
// pCCatAddr: the item being completed
// pConn: Connection object used to do the search
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/22 14:37:09: Created.
// dlongley 2001/10/23: Modified.
//
//-------------------------------------------------------------
VOID CStoreListResolveContext::AsyncLookupCompletion( CCatAddr *pCCatAddr, CStoreListResolveContext *pslrc, CBatchLdapConnection *pConn) { HRESULT hr = S_OK; HRESULT hrStatus; CSingleSearchReinsertionRequest *pCInsertionRequest = NULL;
CatFunctEnterEx((LPARAM)pslrc, "CStoreListResolveContext::AsyncLookupCompletion");
_ASSERT(pCCatAddr);
hr = pCCatAddr->GetHRESULT( ICATEGORIZERITEM_HRSTATUS, &hrStatus); _ASSERT(SUCCEEDED(hr));
if( SUCCEEDED(hrStatus) ) InterlockedIncrement((LPLONG) &(pslrc->m_dwcCompletedLookups));
if( (hrStatus == CAT_E_DBCONNECTION) && SUCCEEDED(pslrc->HrInvalidateConnectionAndRetrieveNewConnection(pConn))) { //
// Retry the search with the new connection
//
pCInsertionRequest = new CSingleSearchReinsertionRequest( pslrc, pCCatAddr);
if(!pCInsertionRequest) { hr = E_OUTOFMEMORY; ERROR_LOG_ADDR_STATIC( pCCatAddr, "new CSingleSearchReinsertionRequest", pslrc, pslrc->GetISMTPServerEx()); pCCatAddr->LookupCompletion();
} else {
hr = pslrc->HrInsertInsertionRequest(pCInsertionRequest); if(FAILED(hr)) { ERROR_LOG_ADDR_STATIC( pCCatAddr, "pslrc->HrInsertInsertionRequest", pslrc, pslrc->GetISMTPServerEx()); } //
// The insertion request destructor should call the lookup
// completion
//
pCInsertionRequest->Release(); }
} else {
pCCatAddr->LookupCompletion(); } pCCatAddr->Release(); // Release reference count addref'd in LookupEntryAsync
CatFunctLeaveEx((LPARAM)pslrc); } // CStoreListResolveContext::AsyncLookupCompletion
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection
//
// Synopsis: Invalidate our current connection and get a new connection
//
// Arguments:
// pConn: The old LDAP connection
// fCountAsRetry: Whether or not to increment the retry counter. We don't want to
// increment the retry counter in the case of a failed insertion request
// insertion, because that means that
//
// Returns:
// S_OK: Success
// CAT_E_MAX_RETRIES: Too many retries already
// or error from ldapconn
//
// History:
// jstamerj 1999/03/22 14:50:07: Created.
//
//-------------------------------------------------------------
HRESULT CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection( CBatchLdapConnection *pConn, BOOL fIncrementRetryCount) { HRESULT hr = S_OK; CCfgConnection *pNewConn = NULL; CCfgConnection *pOldConn = NULL; DWORD dwCount; DWORD dwcInsertionContext; DWORD dwcCompletedLookups; DWORD dwcRetries;
CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection");
DebugTrace((LPARAM)this, "pConn: %08lx", pConn);
EnterCriticalSection(&m_cs);
DebugTrace((LPARAM)this, "m_pConn: %08lx", (CBatchLdapConnection *)m_pConn);
if(pConn != m_pConn) {
DebugTrace((LPARAM)this, "Connection already invalidated"); //
// We have already invalidated this connection
//
LeaveCriticalSection(&m_cs); hr = S_OK; goto CLEANUP; }
DebugTrace((LPARAM)this, "Invalidating conn %08lx", (CBatchLdapConnection *)m_pConn);
pOldConn = m_pConn; pOldConn->Invalidate();
dwcCompletedLookups = (DWORD) InterlockedExchange((LPLONG) &m_dwcCompletedLookups, 0); if( fIncrementRetryCount ) {
if( dwcCompletedLookups > 0 ) {
InterlockedExchange((LPLONG) &m_dwcRetries, 0); dwcRetries = 0;
} else {
dwcRetries = (DWORD) InterlockedIncrement((LPLONG) &m_dwcRetries); }
} else {
dwcRetries = 0;
}
if( dwcRetries > CBatchLdapConnection::m_nMaxConnectionRetries ) {
LogSLRCFailure(CBatchLdapConnection::m_nMaxConnectionRetries, pOldConn->GetHostName());
ErrorTrace((LPARAM)this, "Over max retry limit");
LeaveCriticalSection(&m_cs);
pOldConn->CancelAllSearches();
hr = CAT_E_MAX_RETRIES; goto CLEANUP;
} else {
hr = m_pStore->HrGetConnection( &pNewConn);
if(FAILED(hr)) { LeaveCriticalSection(&m_cs); ERROR_LOG("m_pStore->HrGetConnection");
pOldConn->CancelAllSearches();
goto CLEANUP; }
LogSLRCFailover(dwcRetries, pOldConn->GetHostName(), pNewConn->GetHostName());
DebugTrace((LPARAM)this, "pNewConn: %08lx", pNewConn);
//
// Switch-a-roo
//
m_pConn = pNewConn;
DebugTrace((LPARAM)this, "m_dwcInsertionContext: %08lx", m_dwcInsertionContext); //
// Get insertion contexts on the new connection
//
dwcInsertionContext = m_dwcInsertionContext;
for(dwCount = 0; dwCount < dwcInsertionContext; dwCount++) {
pNewConn->GetInsertionContext(); } LeaveCriticalSection(&m_cs);
pOldConn->CancelAllSearches();
//
// Release insertion contexts on the old connection
//
for(dwCount = 0; dwCount < dwcInsertionContext; dwCount++) {
pOldConn->ReleaseInsertionContext(); }
pOldConn->Release(); } CLEANUP: DebugTrace((LPARAM)this, "returning %08lx", hr); CatFunctLeaveEx((LPARAM)this); return hr; } // CStoreListResolveContext::HrInvalidateConnectionAndRetrieveNewConnection
//+------------------------------------------------------------
//
// Function: CBatchLdapConnection::HrInsertInsertionRequest
//
// Synopsis: Queues an insertion request
//
// Arguments: pCInsertionRequest: the insertion context to queue up
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/03/24 16:51:10: Created.
//
//-------------------------------------------------------------
HRESULT CBatchLdapConnection::HrInsertInsertionRequest( CInsertionRequest *pCInsertionRequest) { HRESULT hr = S_OK;
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::HrInsertInsertionRequest");
//
// Add this thing to the queue and then call
// DecrementPendingSearches to dispatch available requests
//
pCInsertionRequest->AddRef(); if ( pCInsertionRequest->IsBatchable() ) GetInsertionContext();
AcquireSpinLock(&m_spinlock_insertionrequests);
if( IsValid() ) { InsertTailList(&m_listhead_insertionrequests, &(pCInsertionRequest->m_listentry_insertionrequest)); } else {
hr = CAT_E_DBCONNECTION; }
ReleaseSpinLock(&m_spinlock_insertionrequests);
if(hr == CAT_E_DBCONNECTION) {
ERROR_LOG("IsValid"); }
if( hr == S_OK ) {
DecrementPendingSearches(0); // Decrement zero searches
} else {
if ( pCInsertionRequest->IsBatchable() ) ReleaseInsertionContext(); pCInsertionRequest->Release(); }
CatFunctLeaveEx((LPARAM)this); return hr; } // CBatchLdapConnection::HrInsertInsertionRequest
//+------------------------------------------------------------
//
// Function: CBatchLdapConnection::DecrementPendingSearches
//
// Synopsis: Decrement the pending LDAP search count and issue
// searches if we are below MAX_PENDING_SEARCHES and items
// are left in the InsertionRequestQueue
//
// Arguments:
// dwcSearches: Amount to decrement by
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/24 17:09:38: Created.
//
//-------------------------------------------------------------
VOID CBatchLdapConnection::DecrementPendingSearches( DWORD dwcSearches) { HRESULT hr; DWORD dwcSearchesToDecrement = dwcSearches; DWORD dwcSearchesReserved; CInsertionRequest *pCInsertionRequest = NULL; BOOL fLoop = TRUE; CANCELNOTIFY cn; BOOL fDispatchBlocks = FALSE; DWORD dwMinimumRequiredSearches = 1;
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::DecrementPendingSearches");
//
// The module that calls us (CStoreListResolve) has a reference to
// us (obviously). However, it may release us when a search
// fails, for example inside of
// pCInsertionRequest->HrInsertSearches(). Since we need to
// continue to access member data in this situation, AddRef() here
// and Release() at the end of this function.
//
AddRef();
//
// Decrement the count first
//
AcquireSpinLock(&m_spinlock_insertionrequests); m_dwcPendingSearches -= dwcSearchesToDecrement; if (m_fDPS_Was_Here) { fLoop = FALSE; } else { m_fDPS_Was_Here = TRUE; } ReleaseSpinLock(&m_spinlock_insertionrequests); //
// Now dispatch any insertion requests we can dispatch
//
while(fLoop) {
pCInsertionRequest = NULL; AcquireSpinLock(&m_spinlock_insertionrequests);
if( IsValid() && (m_dwcPendingSearches < m_nMaxPendingSearches) && (!IsListEmpty(&m_listhead_insertionrequests)) ) {
dwcSearchesReserved = m_nMaxPendingSearches - m_dwcPendingSearches;
pCInsertionRequest = CONTAINING_RECORD( m_listhead_insertionrequests.Flink, CInsertionRequest, m_listentry_insertionrequest); _ASSERT(pCInsertionRequest); dwMinimumRequiredSearches = pCInsertionRequest->GetMinimumRequiredSearches(); _ASSERT(dwMinimumRequiredSearches > 0); if(dwMinimumRequiredSearches > m_nMaxPendingSearches) { dwMinimumRequiredSearches = m_nMaxPendingSearches; } if(m_dwcPendingSearches + dwMinimumRequiredSearches > m_nMaxPendingSearches) { pCInsertionRequest = NULL; fDispatchBlocks = TRUE; } else {
RemoveEntryList(m_listhead_insertionrequests.Flink); //
// Insert a cancel-Notify structure so that we know if we
// should cancel this insertion request (ie. not reinsert)
//
cn.hrCancel = S_OK; InsertTailList(&m_listhead_cancelnotifies, &(cn.le)); } } if(!pCInsertionRequest) { //
// There are no requests or no room to insert
// requests...Break out of the loop
//
fLoop = FALSE; m_fDPS_Was_Here = FALSE; } ReleaseSpinLock(&m_spinlock_insertionrequests);
if(pCInsertionRequest) { //
// Dispatch up to dwcSearchesReserved searches
//
hr = pCInsertionRequest->HrInsertSearches(dwcSearchesReserved);
if(FAILED(hr)) { if(FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))) {
ERROR_LOG("pCInsertionRequest->HrInsertSearches"); } pCInsertionRequest->NotifyDeQueue(hr);
if ( pCInsertionRequest->IsBatchable() ) ReleaseInsertionContext();
pCInsertionRequest->Release(); AcquireSpinLock(&m_spinlock_insertionrequests); //
// Remove the cancel notify
//
RemoveEntryList(&(cn.le)); ReleaseSpinLock(&m_spinlock_insertionrequests);
} else { //
// There is more work to be done in this block; insert it
// back into the queue
//
AcquireSpinLock(&m_spinlock_insertionrequests); //
// Remove the cancel notify
//
RemoveEntryList(&(cn.le));
//
// If we are NOT cancelling, then insert back into the queue
//
if(cn.hrCancel == S_OK) {
InsertHeadList(&m_listhead_insertionrequests, &(pCInsertionRequest->m_listentry_insertionrequest)); } ReleaseSpinLock(&m_spinlock_insertionrequests);
//
// If we are cancelling, then release this insertion request
//
if(cn.hrCancel != S_OK) { pCInsertionRequest->NotifyDeQueue(cn.hrCancel); if ( pCInsertionRequest->IsBatchable() ) ReleaseInsertionContext(); pCInsertionRequest->Release(); } } } } if(fDispatchBlocks) { //
// X5:197905. We call DispatchBlocks now to avoid a deadlock where
// there is a partially filled batch and there are batchable insertion
// requests in the queue that prevent it from being dispatched, but
// the next insertion request in the queue is not batchable and
// requires a minimum number of searches that is greater than the max
// pending will allow, given that some of the available searches are
// (dormantly) consumed by the partially filled batch.
//
LIST_ENTRY listhead_dispatch; AcquireSpinLock(&m_spinlock); //
// Remove all blocks from the insertion list and put them in the dispatch list
//
if(IsListEmpty(&m_listhead)) { //
// No blocks
//
ReleaseSpinLock(&m_spinlock); } else { InsertTailList(&m_listhead, &listhead_dispatch); RemoveEntryList(&m_listhead); InitializeListHead(&m_listhead);
ReleaseSpinLock(&m_spinlock); //
// Dispatch all the blocks
//
DispatchBlocks(&listhead_dispatch); } } Release(); CatFunctLeaveEx((LPARAM)this); } // CBatchLdapConnection::DecrementPendingSearches
//+------------------------------------------------------------
//
// Function: CBatchLdapConnection::CancelAllSearches
//
// Synopsis: Cancels all outstanding searches
//
// Arguments:
// hr: optinal reason for cancelling the searches
//
// Returns: NOTHING
//
// History:
// jstamerj 1999/03/25 11:44:30: Created.
//
//-------------------------------------------------------------
VOID CBatchLdapConnection::CancelAllSearches( HRESULT hr) { LIST_ENTRY listhead; PLIST_ENTRY ple; CInsertionRequest *pCInsertionRequest;
CatFunctEnterEx((LPARAM)this, "CBatchLdapConnection::CancelAllSearches");
_ASSERT(hr != S_OK);
AcquireSpinLock(&m_spinlock_insertionrequests); //
// Grab the list
//
if(!IsListEmpty(&m_listhead_insertionrequests)) {
CopyMemory(&listhead, &m_listhead_insertionrequests, sizeof(LIST_ENTRY)); listhead.Flink->Blink = &listhead; listhead.Blink->Flink = &listhead; InitializeListHead(&m_listhead_insertionrequests);
} else {
InitializeListHead(&listhead); } //
// Traverse the cancel notify list and set each hresult
//
for(ple = m_listhead_cancelnotifies.Flink; ple != &m_listhead_cancelnotifies; ple = ple->Flink) {
PCANCELNOTIFY pcn; pcn = CONTAINING_RECORD(ple, CANCELNOTIFY, le); pcn->hrCancel = hr; }
ReleaseSpinLock(&m_spinlock_insertionrequests);
CCachedLdapConnection::CancelAllSearches(hr);
for(ple = listhead.Flink; ple != &listhead; ple = listhead.Flink) {
pCInsertionRequest = CONTAINING_RECORD( ple, CInsertionRequest, m_listentry_insertionrequest);
RemoveEntryList(&(pCInsertionRequest->m_listentry_insertionrequest)); pCInsertionRequest->NotifyDeQueue(hr); if (pCInsertionRequest->IsBatchable() ) ReleaseInsertionContext(); pCInsertionRequest->Release(); }
CatFunctLeaveEx((LPARAM)this); } // CBatchLdapConnection::CancelAllSearches
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::GetConnection
//
// Synopsis: AddRef/return the current connection
//
// Arguments: NONE
//
// Returns: Connection pointer
//
// History:
// jstamerj 1999/06/21 12:14:50: Created.
//
//-------------------------------------------------------------
CCfgConnection * CStoreListResolveContext::GetConnection() { CCfgConnection *ret; EnterCriticalSection(&m_cs); ret = m_pConn; if(ret) ret->AddRef(); LeaveCriticalSection(&m_cs); return ret; } // CStoreListResolveContext::GetConnection
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::GetInsertionContext
//
// Synopsis:
//
// Arguments:
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/06/21 12:16:38: Created.
//
//-------------------------------------------------------------
VOID CStoreListResolveContext::GetInsertionContext() { EnterCriticalSection(&m_cs); InterlockedIncrement((PLONG) &m_dwcInsertionContext); m_pConn->GetInsertionContext(); LeaveCriticalSection(&m_cs); } // CStoreListResolveContext::GetInsertionContext
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::ReleaseInsertionContext
//
// Synopsis:
//
// Arguments:
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/06/21 12:16:48: Created.
//
//-------------------------------------------------------------
VOID CStoreListResolveContext::ReleaseInsertionContext() { EnterCriticalSection(&m_cs); InterlockedDecrement((PLONG) &m_dwcInsertionContext); m_pConn->ReleaseInsertionContext(); LeaveCriticalSection(&m_cs);
} // CStoreListResolveContext::ReleaseInsertionContext
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::HrInsertInsertionRequest
//
// Synopsis:
//
// Arguments:
//
// Returns:
// S_OK: Success
//
// History:
// jstamerj 1999/06/21 12:20:19: Created.
//
//-------------------------------------------------------------
HRESULT CStoreListResolveContext::HrInsertInsertionRequest( CInsertionRequest *pCInsertionRequest) { HRESULT hr = S_OK; BOOL fTryAgain; CatFunctEnterEx((LPARAM)this, "CStoreListResolveContext::HrInsertInsertionRequest");
do {
fTryAgain = FALSE; CBatchLdapConnection *pConn;
pConn = GetConnection();
//
// Insert the search request into the CBatchLdapConnection
// object. We will use the email address as the distinguishing
// attribute
//
if( pConn == NULL ) {
hr = CAT_E_DBCONNECTION; if(FAILED(hr)) { ERROR_LOG("GetConnection"); }
} else {
hr = m_pConn->HrInsertInsertionRequest(pCInsertionRequest); if(FAILED(hr)) { ERROR_LOG("m_pConn->HrInsertInsertionRequest"); } } //
// Attempt to reconnect.
//
if( hr == CAT_E_DBCONNECTION ) {
HRESULT hrTryAgain = S_OK;
hrTryAgain = HrInvalidateConnectionAndRetrieveNewConnection(pConn, FALSE); fTryAgain = SUCCEEDED(hrTryAgain);
if(FAILED(hrTryAgain)) { //
// Declare a new local called hr here because the
// ERROR_LOG macro uses it
//
HRESULT hr = hrTryAgain; ERROR_LOG("HrInvalidateConnectionAndRetrieveNewConnection"); } }
if(pConn != NULL) pConn->Release();
} while(fTryAgain);
CatFunctLeaveEx((LPARAM)this); return hr; } // CStoreListResolveContext::HrInsertInsertionRequest
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::LogSLRCFailure
//
// Synopsis: Log a failure for the SLRC (over max retry limit)
//
// Arguments:
// dwcRetries: Number of times we've retried
// pszHost: The last host that failed
//
// Returns: nothing
//
// History:
// jstamerj 2001/12/13 00:24:07: Created.
//
//-------------------------------------------------------------
VOID CStoreListResolveContext::LogSLRCFailure( IN DWORD dwcRetries, IN LPSTR pszHost) { LPCSTR rgSubStrings[2]; CHAR szRetries[32];
_snprintf(szRetries, sizeof(szRetries), "%d", dwcRetries);
rgSubStrings[0] = szRetries; rgSubStrings[1] = pszHost;
CatLogEvent( GetISMTPServerEx(), CAT_EVENT_SLRC_FAILURE, 2, rgSubStrings, S_OK, pszHost, LOGEVENT_FLAG_ALWAYS, LOGEVENT_LEVEL_FIELD_ENGINEERING); }
//+------------------------------------------------------------
//
// Function: CStoreListResolveContext::LogSLRCFailover
//
// Synopsis: Log a failover event
//
// Arguments:
// dwcRetries: Number of retires so far
// pszOldHost: Old LDAP host
// pszNewHost: New LDAP host
//
// Returns: nothing
//
// History:
// jstamerj 2001/12/13 00:24:18: Created.
//
//-------------------------------------------------------------
VOID CStoreListResolveContext::LogSLRCFailover( IN DWORD dwcRetries, IN LPSTR pszOldHost, IN LPSTR pszNewHost) { LPCSTR rgSubStrings[3]; CHAR szRetries[32];
_snprintf(szRetries, sizeof(szRetries), "%d", dwcRetries);
rgSubStrings[0] = pszOldHost; rgSubStrings[1] = pszNewHost; rgSubStrings[2] = szRetries;
CatLogEvent( GetISMTPServerEx(), CAT_EVENT_SLRC_FAILOVER, 3, rgSubStrings, S_OK, pszOldHost, LOGEVENT_FLAG_ALWAYS, LOGEVENT_LEVEL_FIELD_ENGINEERING); } //+------------------------------------------------------------
//
// Function: CSingleSearchReinsertionRequest::HrInsertSearches
//
// Synopsis: reinsert a request for a single search
//
// Arguments:
// dwcSearches: Number of searches we may insert
//
// Returns:
// S_OK: Success
// HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)
//
// History:
// dlongley 2001/10/22: Created.
//
//-------------------------------------------------------------
HRESULT CSingleSearchReinsertionRequest::HrInsertSearches( DWORD dwcSearches) { HRESULT hr = S_OK;
CatFunctEnterEx((LPARAM)this, "CSingleSearchReinsertionRequest::HrInsertSearches");
if( (m_dwcSearches == 0) && (dwcSearches > 0) ) {
hr = m_pslrc->HrLookupEntryAsync(m_pCCatAddr);
if(FAILED(hr)) { ERROR_LOG_ADDR(m_pCCatAddr, "m_pslrc->HrLookupEntryAsync"); m_hr = hr; } else { m_dwcSearches = 1; }
} if(SUCCEEDED(hr)) hr = (m_dwcSearches == 1 ? HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) : S_OK);
DebugTrace((LPARAM)this, "returning %08lx", hr); CatFunctLeaveEx((LPARAM)this); return hr; } // CSingleSearchReinsertionRequest::HrInsertSearches
//+------------------------------------------------------------
//
// Function: CSingleSearchReinsertionRequest::NotifyDeQueue
//
// Synopsis: Callback to notify us that our request is being removed
// from the store's queue
//
// Arguments: NONE
//
// Returns: NOTHING
//
// History:
// dlongley 2001/10/22: Created.
//
//-------------------------------------------------------------
VOID CSingleSearchReinsertionRequest::NotifyDeQueue( HRESULT hrReason) { HRESULT hr; CatFunctEnterEx((LPARAM)this, "CSingleSearchReinsertionRequest::NotifyDeQueue"); //
// If we still have things left to resolve, reinsert this
// insertion request
//
hr = hrReason; if( SUCCEEDED(m_hr) && (m_dwcSearches == 0) && !(m_pslrc->Canceled()) ) {
if( (hr == CAT_E_DBCONNECTION) || (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) ) {
hr = m_pslrc->HrInsertInsertionRequest(this); if(FAILED(hr)) { ERROR_LOG_ADDR(m_pCCatAddr, "m_pslrc->HrInsertInsertionRequest"); } } }
CatFunctLeaveEx((LPARAM)this); } // CSingleSearchReinsertionRequest::NotifyDeQueue
|