Leaked source code of windows server 2003
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.

1144 lines
44 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: aqinst.h
  5. //
  6. // Description:
  7. // CAQSvrInst is a central dispatcher class for Advanced Queuing. It
  8. // coordinates shutdown and exposes the following COM interfaces:
  9. // - IAdvQueue
  10. // - IAdvQueueConfig
  11. //
  12. // Owner: mikeswa
  13. //
  14. // History:
  15. // 9/3/98 - MikeSwa - changed from legacy name catmsgq.h & CCatMsgQueue
  16. //
  17. // Copyright (C) 1997, 1998 Microsoft Corporation
  18. //
  19. //-----------------------------------------------------------------------------
  20. #ifndef __AQINST_H__
  21. #define __AQINST_H__
  22. #include "cmt.h"
  23. #include <rwnew.h>
  24. #include "baseobj.h"
  25. #include "aqueue.h"
  26. #include "domcfg.h"
  27. #include "domain.h"
  28. #include "smtpseo.h"
  29. #include "smproute.h"
  30. #include "qwiktime.h"
  31. #include "dsnsink.h"
  32. #include "asyncq.h"
  33. #include "msgrefadm.h"
  34. #include "mailadmq.h"
  35. #include "shutdown.h"
  36. #include "refstr.h"
  37. #include "msgguid.h"
  38. #include "aqdbgcnt.h"
  39. #include "aqnotify.h"
  40. #include "defdlvrq.h"
  41. #include "failmsgq.h"
  42. #include "asncwrkq.h"
  43. #include "tran_evntlog.h"
  44. #include "aqreg.h"
  45. #include "..\aqdisp\seomgr.h"
  46. //-- *** LOCKS IN AQUEUE *** --------------------------------------------------
  47. //
  48. // NOTE: General comment on locks in aqueue.
  49. //
  50. // In general, we use CShareLockNH as our locking mechanism. These locks are
  51. // Reader/Writer locks with TryEnter semantics and the performance feature
  52. // that they use less than 1 handle per lock (~1 handle per thread).
  53. //
  54. // Shutdown is handled by using these locks. Each class that serves as an
  55. // entrypoint for external threads (CAsyncQueue & CConnMgr) inherits from
  56. // CSyncShutdown. At shutdown, this classes lock is aquired EXCLUSIVE, and
  57. // to protect operations from shutdown, a this classes lock is aquired SHARED
  58. // for the duration of the opertaion. Getting the shutdown sharelock either
  59. // success or fails without blocking (aquiring the EXCLUSIVE shutdown lock is
  60. // the only blocking call).
  61. //
  62. // The only other global lock is the virtual server instance routing lock.
  63. // This is acquired shared for all operations at the same level the exclusive
  64. // lock is aquired. This is acquired exlusively *only* for router changes
  65. // caused by IRouterReset::ResetRoutes.
  66. //
  67. // If other classes have data which needs to be protected, they will have a
  68. // m_slPrivateData sharelock. Any operation that needs to read data in a
  69. // thread-safe manner, should aquire the m_slPrivateData SHARED. Any
  70. // operation that needs to write data that is accessable by multiple threads
  71. // should aquire that object's m_slPrivateData lock EXCLUSIVE.
  72. //
  73. // Some objects (CFifoQueue for example) require more than one lock to avoid
  74. // contention. These objects will have locks that are descriptive of that
  75. // particular locks functions. CFifoQueue, for example, uses m_slHead and
  76. // m_slTail to respectively protect the head and tail of the queue.
  77. //
  78. //-----------------------------------------------------------------------------
  79. // forward declarations to avoid #include nightmares
  80. class CLinkMsgQueue;
  81. class CConnMgr;
  82. class CAQStats;
  83. class CDSNParams;
  84. class CMsgRef;
  85. #define MEMBER_OK(pStruct, Member) \
  86. (((LONG) (pStruct)->cbVersion) >= ( ((BYTE *) &((pStruct)->Member)) - ((BYTE *) pStruct)))
  87. //For Service callback function
  88. typedef void (*PSRVFN)(PVOID);
  89. //CatMsgQueue Signature
  90. #define CATMSGQ_SIG ' QMC'
  91. //Total number of IMsgs in the system (all virtual servers)
  92. _declspec(selectany) DWORD g_cIMsgInSystem = 0;
  93. //List of virtual servers used by debugger extensions
  94. _declspec(selectany) LIST_ENTRY g_liVirtualServers = {&g_liVirtualServers, &g_liVirtualServers};
  95. //Sharelock used to access global virtual servers
  96. _declspec(selectany) CShareLockNH *g_pslGlobals = NULL;
  97. //Setup defaults
  98. const DWORD g_cMaxConnections = 10000; //Maximum # of total connections allocated
  99. const DWORD g_cMaxLinkConnections = 10; //Maximum # of connections per link
  100. const DWORD g_cMinMessagesPerConnection = 20; //There must be this many messages
  101. //per addional connection that is
  102. //allocated for a link
  103. const DWORD g_cMaxMessagesPerConnection = 20; //We server atmost these many messages per connection
  104. const DWORD g_dwConnectionWaitMilliseconds = 3600000;
  105. const DWORD g_dwRetryThreshold = 3; // Till 3 consecutive failures we treat it as glitch;
  106. const DWORD g_dwFirstTierRetrySeconds = (15 * 60); // retry a failure in 15 minutes
  107. const DWORD g_dwSecondTierRetrySeconds = (60 * 60); // retry a failure in 60 minutes
  108. const DWORD g_dwThirdTierRetrySeconds = (12 * 60 * 60); // retry a failure in 12 hrs
  109. const DWORD g_dwFourthTierRetrySeconds = (24 * 60 * 60); // retry a failure in 24 hrs
  110. const DWORD g_dwRetriesBeforeDelay = 5;
  111. const DWORD g_dwDelayIntervalsBeforeNDR = 2;
  112. const DWORD g_dwDelayExpireMinutes = g_dwRetriesBeforeDelay*g_dwFirstTierRetrySeconds/(60);
  113. const DWORD g_dwNDRExpireMinutes = g_dwDelayIntervalsBeforeNDR*g_dwDelayExpireMinutes;
  114. //
  115. // Additional message failure codes that should move to aqueue.idl.
  116. //
  117. #define MESSAGE_FAILURE_CAT (MESSAGE_FAILURE_BAD_PICKUP_DIR_FILE+1)
  118. //---[ eAQFailure ]-------------------------------------------------------------
  119. //
  120. //
  121. // Description:
  122. // Enum used to desribe failure scenarios that will require special handling
  123. // Hungarian:
  124. // eaqf
  125. //
  126. //-----------------------------------------------------------------------------
  127. typedef enum eAQFailure_
  128. {
  129. AQ_FAILURE_CANNOT_NDR_UNRESOLVED_RECIPS = 0,
  130. AQ_FAILURE_PREROUTING_FAILED,
  131. AQ_FAILURE_PRECAT_RETRY,
  132. AQ_FAILURE_POSTCAT_EVENT,
  133. AQ_FAILURE_NO_RESOURCES,
  134. AQ_FAILURE_NDR_OF_DSN,
  135. AQ_FAILURE_NO_RECIPS,
  136. AQ_FAILURE_PENDING_DEFERRED_DELIVERY,
  137. AQ_FAILURE_PROCESSING_DEFERRED_DELIVERY,
  138. AQ_FAILURE_MSGREF_RETRY,
  139. AQ_FAILURE_FREE_TO_RESUSE,
  140. AQ_FAILURE_INTERNAL_ASYNCQ,
  141. AQ_FAILURE_NUM_SITUATIONS //always keep this as last
  142. } eAQFailure;
  143. _declspec(selectany) DWORD g_cTotalAQFailures = 0;
  144. _declspec(selectany) DWORD g_cAQFailureSituations = AQ_FAILURE_NUM_SITUATIONS;
  145. _declspec(selectany) DWORD g_rgcAQFailures[AQ_FAILURE_NUM_SITUATIONS] = {0};
  146. //---[ CAQSvrInst ]------------------------------------------------------------
  147. //
  148. //
  149. // Hungarian: aqinst, paqinst
  150. //
  151. // Legacy Hungarian: cmq, pcmq (from old CCatMsgQueue object)
  152. //
  153. // Provides an interface definition for the enqueuing/acking categorized
  154. // messages Also provides an interface for creating link queues.
  155. //
  156. // Only one of these objects exist per virtual server... it is used a
  157. // co-ordinating object used to handle an orderly shutdown.
  158. //
  159. //-----------------------------------------------------------------------------
  160. class CAQSvrInst :
  161. public CBaseObject,
  162. public CSyncShutdown,
  163. public IAdvQueue,
  164. public IAdvQueueConfig,
  165. public IAdvQueueAdmin,
  166. public IMailTransportRoutingEngine,
  167. public IMailTransportRouterReset,
  168. public IAdvQueueDomainType,
  169. public IAQNotify,
  170. public IMailTransportRouterSetLinkState,
  171. public IAQServerEvent
  172. {
  173. protected:
  174. DWORD m_dwSignature;
  175. LIST_ENTRY m_liVirtualServers;
  176. DWORD m_dwServerInstance; //Virtual server instance
  177. //Useful signatures that include flavor and verision information
  178. DWORD m_cbClasses;
  179. DWORD m_dwFlavorSignature;
  180. //Total counts used for counting totals of messages that have passed
  181. //through the system. Very useful for determing which component has
  182. //dropped a message after a stress run.
  183. LONG m_cTotalMsgsQueued; //Total # of messages on dest queues (after fanout)
  184. LONG m_cMsgsAcked; //Total # of messages that have been acknowledged
  185. LONG m_cMsgsAckedRetry; //Total # of messages acked with retry all
  186. LONG m_cMsgsDeliveredLocal; //Total # of messages delivered to local store
  187. DWORD m_cMsgsAckedRetryLocal; //Total # of messages msgs that have been ack'd retry
  188. //Current system state counters
  189. DWORD m_cCurrentMsgsSubmitted; //# total msgs in system
  190. DWORD m_cCurrentMsgsPendingCat; //# Msgs that have not be categorized
  191. DWORD m_cCurrentMsgsPendingRouting; //# Msgs that have not been routed.
  192. DWORD m_cCurrentMsgsPendingDelivery; //# Msgs pending remote delivery
  193. DWORD m_cCurrentMsgsPendingLocal; //# Msgs pending local delivery
  194. DWORD m_cCurrentMsgsPendingLocalRetry; //# Msgs pending local retries
  195. DWORD m_cCurrentMsgsPendingRetry; //# Msgs with unsuccessful attempts
  196. DWORD m_cCurrentQueueMsgInstances; //# of msgs instances pending
  197. //remote deliver (>= #msgs)
  198. DWORD m_cCurrentRemoteDestQueues; //# of DestMsgQueues created
  199. DWORD m_cCurrentRemoteNextHops; //# of Next Hop links created
  200. DWORD m_cCurrentRemoteNextHopsEnabled; //# of links that can have connections
  201. DWORD m_cCurrentRemoteNextHopsPendingRetry; //# of links pending retry
  202. DWORD m_cCurrentRemoteNextHopsPendingSchedule; //# of links pending schedule
  203. DWORD m_cCurrentRemoteNextHopsFrozenByAdmin; //# of links frozen by admin
  204. DWORD m_cTotalMsgsSubmitted; //# of messages submitted to AQ
  205. DWORD m_cTotalExternalMsgsSubmitted; //# of messages submitted to AQ externally
  206. DWORD m_cCurrentMsgsPendingSubmitEvent; //# of messages in submission event
  207. DWORD m_cCurrentMsgsPendingPreCatEvent; //# of messages in PreCat event
  208. DWORD m_cCurrentMsgsPendingPostCatEvent; //# of messages in PostCat event
  209. DWORD m_cDelayedDSNs; //# of DSN's that contain action:delayed
  210. DWORD m_cNDRs; //# of DSN's that contain action:failed
  211. DWORD m_cDeliveredDSNs; //# of DSN's that contain action:delivered
  212. DWORD m_cRelayedDSNs; //# of DSN's that contain action:relayed
  213. DWORD m_cExpandedDSNs; //# of DSN's that contain action:expanded
  214. DWORD m_cDMTRetries;
  215. DWORD m_cSupersededMsgs;
  216. DWORD m_cTotalMsgsTURNETRNDelivered;
  217. DWORD m_cTotalMsgsBadmailed;
  218. DWORD m_cCatMsgCalled;
  219. DWORD m_cCatCompletionCalled;
  220. DWORD m_cBadmailNoRecipients;
  221. DWORD m_cBadmailHopCountExceeded;
  222. DWORD m_cBadmailFailureGeneral;
  223. DWORD m_cBadmailBadPickupFile;
  224. DWORD m_cBadmailEvent;
  225. DWORD m_cBadmailNdrOfDsn;
  226. DWORD m_cTotalDSNFailures;
  227. DWORD m_cCurrentMsgsInLocalDelivery;
  228. DWORD m_cTotalResetRoutes;
  229. DWORD m_cCurrentPendingResetRoutes;
  230. DWORD m_cCurrentMsgsPendingSubmit;
  231. CAQMsgGuidList m_mglSupersedeIDs;
  232. CShareLockInst m_slPrivateData; //read/write lock for global config into
  233. CDomainMappingTable m_dmt; //ptr to domain mapping table
  234. CConnMgr *m_pConnMgr;
  235. CDomainConfigTable m_dct;
  236. ISMTPServer *m_pISMTPServer;
  237. ISMTPServerEx *m_pISMTPServerEx;
  238. ISMTPServerAsync *m_pISMTPServerAsync;
  239. HANDLE m_hCat;
  240. CAQQuickTime m_qtTime; //exposes interfaces for getting expire times
  241. CDSNGenerator m_dsnsink;
  242. //Global config data
  243. DWORD m_cMinMessagesPerConnection;
  244. DWORD m_cMaxMessagesPerConnection;
  245. DWORD m_dwConnectionWaitMilliseconds;
  246. //retry related
  247. DWORD m_dwFirstTierRetrySeconds; //Threshold failure retry interval
  248. DWORD m_dwDelayExpireMinutes;
  249. DWORD m_dwNDRExpireMinutes;
  250. DWORD m_dwLocalDelayExpireMinutes;
  251. DWORD m_dwLocalNDRExpireMinutes;
  252. //Counters used to for local and cat retry
  253. DWORD m_cLocalRetriesPending;
  254. DWORD m_cCatRetriesPending;
  255. DWORD m_cRoutingRetriesPending;
  256. DWORD m_cSubmitRetriesPending;
  257. DWORD m_dwInitMask; //used to keep track of who has been init'd
  258. IMessageRouter *m_pIMessageRouterDefault;
  259. CRefCountedString *m_prstrDefaultDomain;
  260. CRefCountedString *m_prstrBadMailDir;
  261. CRefCountedString *m_prstrCopyNDRTo;
  262. CRefCountedString *m_prstrServerFQDN;
  263. //DSN Options
  264. DWORD m_dwDSNOptions;
  265. DWORD m_dwDSNLanguageID;
  266. CAsyncAdminMailMsgQueue m_asyncqPreCatQueue;
  267. CAsyncAdminMsgRefQueue m_asyncqPreLocalDeliveryQueue;
  268. CAsyncAdminMailMsgQueue m_asyncqPostDSNQueue;
  269. CAsyncAdminMailMsgQueue m_asyncqPreRoutingQueue;
  270. CAsyncAdminMailMsgQueue m_asyncqPreSubmissionQueue;
  271. CDebugCountdown m_dbgcnt;
  272. //Flags used to describe what has been initialized
  273. IMailTransportRouterReset *m_pIRouterReset; //pointer to router reset implementation
  274. //Queue and counter for deferred delivery
  275. CAQDeferredDeliveryQueue m_defq;
  276. DWORD m_cCurrentMsgsPendingDeferredDelivery;
  277. //Failed Msg Queue
  278. CFailedMsgQueue m_fmq;
  279. DWORD m_cCurrentResourceFailedMsgsPendingRetry;
  280. //Work queue used to do async work items
  281. CAsyncWorkQueue m_aqwWorkQueue;
  282. BOOL m_fMailMsgReportsNumHandles;
  283. typedef enum _eCMQInitFlags
  284. {
  285. CMQ_INIT_OK = 0x80000000,
  286. CMQ_INIT_DMT = 0x00000001,
  287. CMQ_INIT_DCT = 0x00000002,
  288. CMQ_INIT_CONMGR = 0x00000004,
  289. CMQ_INIT_LINKQ = 0x00000008,
  290. CMQ_INIT_DSN = 0x00000010,
  291. CMQ_INIT_PRECATQ = 0x00000020,
  292. CMQ_INIT_PRELOCQ = 0x00000040,
  293. CMQ_INIT_POSTDSNQ = 0x00000080,
  294. CMQ_INIT_ROUTER_RESET = 0x00000100,
  295. CMQ_INIT_ROUTINGQ = 0x00000200,
  296. CMQ_INIT_WORKQ = 0x00000400,
  297. CMQ_INIT_SUBMISSIONQ = 0x00000800,
  298. CMQ_INIT_MSGQ = 0x80000000,
  299. } eCMQInitFlags;
  300. CSMTPSeoMgr m_CSMTPSeoMgr;
  301. public:
  302. CAQSvrInst(DWORD dwServerInstance,
  303. ISMTPServer *pISMTPServer);
  304. ~CAQSvrInst();
  305. HRESULT HrInitialize(
  306. IN LPSTR szUserName = NULL,
  307. IN LPSTR szDomainName = NULL,
  308. IN LPSTR szPassword = NULL,
  309. IN PSRVFN pServiceStatusFn = NULL,
  310. IN PVOID pvServiceContext = NULL);
  311. HRESULT HrDeinitialize();
  312. //publicly accessable member values
  313. //MUST wrap in fTryShutdownLock - ShutdownUnlock
  314. CDomainMappingTable *pdmtGetDMT() {AssertShutdownLockAquired();return &m_dmt;};
  315. CAQMsgGuidList *pmglGetMsgGuidList() {AssertShutdownLockAquired(); return &m_mglSupersedeIDs;};
  316. HRESULT HrGetIConnectionManager(OUT IConnectionManager **ppIConnectionManager);
  317. //Public Methods exposed through events (or some other mechanism)
  318. // This function queues a categorized message for remote/local delivery
  319. BOOL fRouteAndQueueMsg(IN IMailMsgProperties *pIMailMsg);
  320. //Acknowledge the message ref.
  321. //There should be one Ack for every dequeue from a link.
  322. HRESULT HrAckMsg(MessageAck *pMsgAck, BOOL fLocal = FALSE);
  323. //methods to (un)map domain names to ids.
  324. HRESULT HrGetDomainMapping(
  325. IN LPSTR szDomainName, //Domain name
  326. OUT CDomainMapping *pdmap); //resulting domain mapping
  327. HRESULT HrGetDomainName(
  328. IN CDomainMapping *pdmap, //Domain mapping
  329. OUT LPSTR *pszDomainName); //resolved domain name
  330. //Pass notifications off to Connection Manager
  331. HRESULT HrNotify(IN CAQStats *paqstats, BOOL fAdd);
  332. //Expose ability to get internal Domain Info to internal components
  333. HRESULT HrGetInternalDomainInfo(IN DWORD cbDomainNameLength,
  334. IN LPSTR szDomainName,
  335. OUT CInternalDomainInfo **ppDomainInfo);
  336. HRESULT HrGetDefaultDomainInfo(OUT CInternalDomainInfo **ppDomainInfo);
  337. //Get Domain Entry from DMT
  338. HRESULT HrGetDomainEntry(IN DWORD cbDomainNameLength,
  339. IN LPSTR szDomainName,
  340. OUT CDomainEntry **ppdentry);
  341. // jstamerj 980607 21:41:25: The completion routine of the
  342. // submission event trigger
  343. HRESULT SubmissionEventCompletion(
  344. HRESULT hrStatus,
  345. PEVENTPARAMS_SUBMISSION pParams);
  346. // jstamerj 1998/11/24 19:53:24: Fire off the PreCat event
  347. VOID TriggerPreCategorizeEvent(IN IMailMsgProperties *pIMailMsgProperties);
  348. // jstamerj 1998/11/24 19:54:23: Completion routine of the pre-cat event
  349. HRESULT PreCatEventCompletion(IN HRESULT hrStatus, IN PEVENTPARAMS_PRECATEGORIZE pParams);
  350. // jstamerj 980610 12:24:29: Called from HrPreCatEventCompletion
  351. HRESULT SubmitMessageToCategorizer(IN IMailMsgProperties *pIMailMsgProperties);
  352. // jstamerj 980616 22:06:45: Called from CatCompletion
  353. void TriggerPostCategorizeEvent(IUnknown *pIMsg, IUnknown **rgpIMsg);
  354. // jstamerj 980616 22:07:18: triggers a post-cat event for one message
  355. HRESULT TriggerPostCategorizeEventOneMsg(IUnknown *pIMsg);
  356. // jstamerj 980616 22:07:54: Handles post-cat event completions
  357. HRESULT PostCategorizationEventCompletion(HRESULT hrStatus, PEVENTPARAMS_POSTCATEGORIZE pParams);
  358. // 11/17/98 - MikeSwa added for CDO badmail/abort delivery
  359. // returns S_FALSE if message has been completely handled.
  360. HRESULT SetNextMsgStatus(IN DWORD dwCurrentStatus,
  361. IN IMailMsgProperties *pIMailMsgProperties);
  362. //Called by async completion to PreCat Queue
  363. BOOL fPreCatQueueCompletion(IMailMsgProperties *pIMailMsgProperties);
  364. //Called by async completion to PreCat Queue
  365. BOOL fPreLocalDeliveryQueueCompletion(CMsgRef *pmsgref);
  366. //Used to restart async queues after failures
  367. void AsyncQueueRetry(DWORD dwQueueID);
  368. //Called to Set message submission time duing SubmitMessage and HrInternalSubmitMessage
  369. HRESULT HrSetSubmissionTimeIfNecessary(IMailMsgProperties *pIMailMsgProperties);
  370. //Called to calculate expire times for messages that are not stamped (most messages)
  371. void CalcExpireTimeNDR(FILETIME ftSubmission, BOOL fLocal, FILETIME *pftExpire);
  372. void CalcExpireTimeDelay(FILETIME ftSubmission, BOOL fLocal, FILETIME *pftExpire);
  373. //API to keep counters in sync
  374. inline DWORD cIncMsgsInSystem(); //returns total of all virtual servers
  375. inline void DecMsgsInSystem(BOOL fWasRetriedRemote = FALSE, BOOL fWasRemote = FALSE,
  376. BOOL fWasRetriedLocal = FALSE);
  377. //Called by Msgref on first message retry
  378. inline void IncRetryCount(BOOL fLocal);
  379. //Called by DestMsgQueue to describe message fanout
  380. inline void IncQueueMsgInstances();
  381. inline void DecQueueMsgInstances();
  382. //Used to keep track of the number of queues/next hops
  383. inline void IncDestQueueCount();
  384. inline void DecDestQueueCount();
  385. inline DWORD cGetDestQueueCount();
  386. inline void IncNextHopCount();
  387. inline void DecNextHopCount();
  388. //Called by functions walk pre-local queue for NDRs
  389. inline void DecPendingLocal();
  390. inline void DecPendingSubmit()
  391. {InterlockedDecrement((PLONG)&m_cCurrentMsgsPendingSubmit);};
  392. inline void DecPendingCat()
  393. {InterlockedDecrement((PLONG)&m_cCurrentMsgsPendingCat);};
  394. inline void DecPendingRouting()
  395. {InterlockedDecrement((PLONG)&m_cCurrentMsgsPendingRouting);};
  396. inline void IncTURNETRNDelivered();
  397. //aszafer 1/28/00
  398. //used to decide start/stop throttling handles
  399. DWORD cCountMsgsForHandleThrottling(IN IMailMsgProperties *pIMailMsgProperties);
  400. //Functions to call into the specifc hash tables to iterate over subdomains
  401. //
  402. HRESULT HrIterateDMTSubDomains(IN LPSTR szDomainName,
  403. IN DWORD cbDomainNameLength,
  404. IN DOMAIN_ITR_FN pfn,
  405. IN PVOID pvContext) ;
  406. HRESULT HrIterateDCTSubDomains(IN LPSTR szDomainName,
  407. IN DWORD cbDomainNameLength,
  408. IN DOMAIN_ITR_FN pfn,
  409. IN PVOID pvContext);
  410. //Calls that allow access to time objects
  411. inline void GetExpireTime(
  412. IN DWORD cMinutesExpireTime,
  413. IN OUT FILETIME *pftExpireTime,
  414. IN OUT DWORD *pdwExpireContext); //if non-zero, will use last time
  415. inline BOOL fInPast(IN FILETIME *pftExpireTime, IN OUT DWORD *pdwExpireContext);
  416. HRESULT HrTriggerDSNGenerationEvent(CDSNParams *pdsnparams, BOOL fHasRoutingLock);
  417. HRESULT HrNDRUnresolvedRecipients(IMailMsgProperties *pIMailMsgProperties,
  418. IMailMsgRecipients *pIMailMsgRecipients);
  419. //friend functions that can be used as completion functions
  420. friend HRESULT CatCompletion(HRESULT hrCatResult, PVOID pContext, IUnknown *pIMsg,
  421. IUnknown **rgpIMsg);
  422. //Expose server start/stop hint functions
  423. inline VOID ServerStartHintFunction();
  424. inline VOID ServerStopHintFunction();
  425. //function used to handle badmail
  426. void HandleBadMail(IN IMailMsgProperties *pIMailMsgProperties,
  427. IN BOOL fUseIMailMsgProperties,
  428. IN LPSTR szFileName,
  429. IN HRESULT hrReason,
  430. BOOL fHasRoutingLock);
  431. //Function to handle some sort of system failure that would cause
  432. //messages/data to be lost if unhandled
  433. void HandleAQFailure(eAQFailure eaqfFailureSituation,
  434. HRESULT hr, IMailMsgProperties *pIMailMsgProperties);
  435. //Stub call for logging an event
  436. void LogAQEvent(HRESULT hrEventReason, CMsgRef *pmsgref,
  437. IMailMsgProperties *pIMailMsgProperties,
  438. LPSTR szFileName);
  439. //Routing lock should be grabbed before accessing queues (after shutdown)
  440. void RoutingShareLock() {m_slPrivateData.ShareLock();};
  441. BOOL fTryRoutingShareLock() {return m_slPrivateData.TryShareLock();};
  442. void RoutingShareUnlock() {m_slPrivateData.ShareUnlock();};
  443. HRESULT SetCallbackTime(IN PSRVFN pCallbackFn,
  444. IN PVOID pvContext,
  445. IN DWORD dwCallbackMinutes);
  446. HRESULT SetCallbackTime(IN PSRVFN pCallbackFn,
  447. IN PVOID pvContext,
  448. IN FILETIME *pft);
  449. void DecPendingDeferred()
  450. {InterlockedDecrement((PLONG) &m_cCurrentMsgsPendingDeferredDelivery);};
  451. void DecPendingFailed()
  452. {InterlockedDecrement((PLONG) &m_cCurrentResourceFailedMsgsPendingRetry);};
  453. void QueueMsgForLocalDelivery(CMsgRef *pmsgref, BOOL fLocalLink);
  454. HRESULT HrInternalSubmitMessage(IMailMsgProperties *pIMailMsgProperties);
  455. //Get string for default domain
  456. CRefCountedString *prstrGetDefaultDomain();
  457. //Completion Function called by MsgCat
  458. static HRESULT CatCompletion(HRESULT hrCatResult, PVOID pContext,
  459. IUnknown *pImsg, IUnknown **rgpImsg);
  460. #define AQLD_SIG 'LDAQ'
  461. // completion object called by local delivery
  462. class CAQLocalDeliveryNotify :
  463. public IMailMsgNotify,
  464. public CBaseObject
  465. {
  466. public:
  467. CAQLocalDeliveryNotify(PVOID pContext, CMsgRef *pmsgref) {
  468. TraceFunctEnter("CAQLocalDeliveryNotify::CAQLocalDeliveryNotify");
  469. m_hr = E_FAIL;
  470. m_fCalledCompletion = FALSE;
  471. m_pContext = pContext;
  472. _ASSERT(pmsgref);
  473. m_pmsgref = pmsgref;
  474. m_pmsgref->AddRef();
  475. m_pIMsg = pmsgref ? pmsgref->pimsgGetIMsg() : NULL;
  476. ZeroMemory(&m_msgack, sizeof(MessageAck));
  477. m_msgack.dwMsgStatus = MESSAGE_STATUS_ALL_DELIVERED;
  478. m_msgack.pvMsgContext = (DWORD *) &m_dcntxtLocal;
  479. DebugTrace(0, "new(this=0x%x)\n", this);
  480. }
  481. ~CAQLocalDeliveryNotify() {
  482. TraceFunctEnter("CAQLocalDeliveryNotify::~CAQLocalDeliveryNotify");
  483. DebugTrace(0, "delete(this=0x%x)\n", this);
  484. if (m_pIMsg) {
  485. m_pIMsg->Release();
  486. m_pIMsg = NULL;
  487. }
  488. if (m_pmsgref) {
  489. m_pmsgref->Release();
  490. m_pmsgref = NULL;
  491. }
  492. }
  493. // allocators
  494. void *operator new(size_t stIgnored) {
  495. return s_pool.Alloc();
  496. }
  497. void operator delete(void *p, size_t size) {
  498. s_pool.Free(p);
  499. }
  500. // IMailMsgNotify
  501. HRESULT __stdcall Notify(HRESULT hr) {
  502. m_hr = hr;
  503. CAQSvrInst::LDCompletion(m_hr, m_pContext, m_pmsgref, this);
  504. m_fCalledCompletion = TRUE;
  505. return S_OK;
  506. }
  507. // IUnknown
  508. HRESULT __stdcall QueryInterface( const IID& iid, VOID** ppv )
  509. {
  510. if ( iid == IID_IUnknown ) {
  511. *ppv = static_cast<IMailMsgNotify*>(this);
  512. } else if ( iid == IID_IMailMsgNotify ) {
  513. *ppv = static_cast<IMailMsgNotify*>(this);
  514. } else {
  515. *ppv = NULL;
  516. return E_NOINTERFACE;
  517. }
  518. reinterpret_cast<IUnknown*>(*ppv)->AddRef();
  519. return S_OK;
  520. }
  521. STDMETHOD_(ULONG, AddRef)(void) {
  522. TraceFunctEnter("CAQLocalDeliveryNotify::AddRef");
  523. DebugTrace(0, "add(this=0x%x)\n", this);
  524. TraceFunctLeave();
  525. return CBaseObject::AddRef();
  526. };
  527. STDMETHOD_(ULONG, Release)(void) {
  528. TraceFunctEnter("CAQLocalDeliveryNotify::Release");
  529. DebugTrace(0, "rel(this=0x%x)\n", this);
  530. TraceFunctLeave();
  531. return CBaseObject::Release();
  532. };
  533. // accessors
  534. CDeliveryContext *pdcntxtGetDeliveryContext() {
  535. return &m_dcntxtLocal;
  536. }
  537. MessageAck *pmsgackGetMsgAck() {
  538. return &m_msgack;
  539. }
  540. IMailMsgProperties *pimsgGetIMsg() {
  541. return m_pIMsg;
  542. }
  543. CMsgRef *pmsgrefGetMsgRef() {
  544. return m_pmsgref;
  545. }
  546. BOOL fNotCalledCompletion() {
  547. return !m_fCalledCompletion;
  548. }
  549. private:
  550. IMailMsgProperties *m_pIMsg;
  551. HRESULT m_hr;
  552. PVOID m_pContext;
  553. CMsgRef *m_pmsgref;
  554. CDeliveryContext m_dcntxtLocal;
  555. MessageAck m_msgack;
  556. BOOL m_fCalledCompletion;
  557. public:
  558. static CPool s_pool;
  559. };
  560. void UpdateLDCounters(CMsgRef *pmsgref);
  561. // local delivery completion function
  562. static void LDCompletion(HRESULT hrLDResult,
  563. PVOID pContext,
  564. CMsgRef *pmsgref,
  565. CAQLocalDeliveryNotify *pLDNotify);
  566. //Handle the details of retrying after local delivery failure
  567. void HandleLocalRetry(CMsgRef *pmsgref);
  568. //Handles details of post-cat DSN generation
  569. void HandleCatFailure(IUnknown *pIUnknown, HRESULT hrCatResult);
  570. //Handle the details of retrying after cat failure
  571. void HandleCatRetryOneMessage(IUnknown *pIUnknown);
  572. HRESULT HrGetLocalQueueAdminQueue(IQueueAdminQueue **ppIQueueAdminQueue);
  573. HRESULT HrQueueFromQueueID(QUEUELINK_ID *pqlQueueId,
  574. IQueueAdminQueue **ppIQueueAdminQueue);
  575. HRESULT HrLinkFromLinkID(QUEUELINK_ID *pqlLinkID,
  576. IQueueAdminLink **ppIQueueAdminLink);
  577. BOOL fIsLocalQueueAdminAction(IQueueAdminAction *pIQueueAdminAction);
  578. inline HRESULT HrQueueWorkItem(PVOID pvData,
  579. PASYNC_WORK_QUEUE_FN pfnCompletion);
  580. static BOOL fResetRoutesNextHopCompletion(PVOID pvThis, DWORD dwStatus);
  581. static BOOL fPreSubmissionQueueCompletionWrapper(
  582. IMailMsgProperties *pIMailMsgProperties,
  583. PVOID pvContext);
  584. BOOL fShouldRetryMessage(IMailMsgProperties *pIMailMsgProperties,
  585. BOOL fShouldBounceUsageIfRetry = TRUE);
  586. VOID ScheduleInternalRetry(DWORD dwLinkType);
  587. STDMETHOD(TriggerServerEvent) (
  588. DWORD dwEventID,
  589. PVOID pvContext)
  590. {
  591. return m_CSMTPSeoMgr.HrTriggerServerEvent(dwEventID, pvContext);
  592. }
  593. void LogResetRouteEvent( DWORD dwObainLock,
  594. DWORD dwWaitLock,
  595. DWORD dwQueue);
  596. HRESULT HrInternalQueueFromQueueID(QUEUELINK_ID *pqlQueueId,
  597. IQueueAdminQueue **ppIQueueAdminQueue);
  598. // DSN Submission methods
  599. HRESULT HrAllocBoundMessage(
  600. OUT IMailMsgProperties **ppMsg,
  601. OUT PFIO_CONTEXT *phContext);
  602. HRESULT HrSubmitDSN(
  603. IN CDSNParams *pdsnparams,
  604. IN DWORD dwDSNAction,
  605. IN DWORD cRecipsDSNd,
  606. IN IMailMsgProperties *pDSNMsg);
  607. //Routing interface used internal to AQ components
  608. public:
  609. //Fires MAIL_TRANSPORT_ON_GET_ROUTER_FOR_MESSAGE_EVENT
  610. HRESULT HrTriggerGetMessageRouter(
  611. IN IMailMsgProperties *pIMailMsg,
  612. OUT IMessageRouter **pIMessageRouter);
  613. HRESULT HrTriggerLogEvent(
  614. IN DWORD idMessage,
  615. IN WORD idCategory,
  616. IN WORD cSubstrings,
  617. IN LPCSTR *rgszSubstrings,
  618. IN WORD wType,
  619. IN DWORD errCode,
  620. IN WORD iDebugLevel,
  621. IN LPCSTR szKey,
  622. IN DWORD dwOptions,
  623. IN DWORD iMessageString = 0xffffffff,
  624. IN HMODULE hModule = NULL);
  625. private:
  626. HRESULT HrTriggerInitRouter();
  627. //IUnknown
  628. public:
  629. STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvObj);
  630. STDMETHOD_(ULONG, AddRef)(void) {return CBaseObject::AddRef();};
  631. STDMETHOD_(ULONG, Release)(void) {return CBaseObject::Release();};
  632. //IAdvQueue
  633. public:
  634. STDMETHOD(SubmitMessage)(IN IMailMsgProperties *pIMailMsgProperties);
  635. STDMETHOD(HandleFailedMessage)(IN IMailMsgProperties *pIMailMsgProperties,
  636. IN BOOL fUseIMailMsgProperties,
  637. IN LPSTR szFileName,
  638. IN DWORD dwFailureReason,
  639. IN HRESULT hrFailureCode);
  640. //IAdvQueueConfig
  641. public:
  642. STDMETHOD(SetConfigInfo)(IN AQConfigInfo *pAQConfigInfo);
  643. STDMETHOD(SetDomainInfo)(IN DomainInfo *pDomainInfo);
  644. STDMETHOD(GetDomainInfo)(IN DWORD cbDomainNameLength,
  645. IN CHAR szDomainName[],
  646. IN OUT DomainInfo *pDomainInfo,
  647. OUT DWORD **ppvDomainContext);
  648. STDMETHOD(ReleaseDomainInfo)(IN DWORD *pvDomainContext);
  649. STDMETHOD(GetPerfCounters)(OUT AQPerfCounters *pAQPerfCounters,
  650. OUT CATPERFBLOCK *pCatPerfCounters);
  651. STDMETHOD(ResetPerfCounters)();
  652. STDMETHOD(StartConfigUpdate)();
  653. STDMETHOD(FinishConfigUpdate)();
  654. //IMailTransportRoutingEngine
  655. public:
  656. STDMETHOD(GetMessageRouter)(
  657. IN IMailMsgProperties *pIMailMsg,
  658. IN IMessageRouter *pICurrentMessageRouter,
  659. OUT IMessageRouter **ppIMessageRouter);
  660. //IMailTransportRouterReset
  661. public:
  662. STDMETHOD(ResetRoutes)(
  663. IN DWORD dwResetType);
  664. //IAdvQueueDomainType
  665. public:
  666. STDMETHOD(GetDomainInfoFlags)(
  667. IN LPSTR szDomainName,
  668. DWORD *pdwDomainInfoFlags);
  669. // IAdvQueueAdmin
  670. public:
  671. STDMETHOD(ApplyActionToLinks)(
  672. LINK_ACTION laAction);
  673. STDMETHOD(ApplyActionToMessages)(
  674. QUEUELINK_ID *pqlQueueLinkId,
  675. MESSAGE_FILTER *pmfMessageFilter,
  676. MESSAGE_ACTION maMessageAction,
  677. DWORD *pcMsgs);
  678. STDMETHOD(GetQueueInfo)(
  679. QUEUELINK_ID *pqlQueueId,
  680. QUEUE_INFO *pqiQueueInfo);
  681. STDMETHOD(GetLinkInfo)(
  682. QUEUELINK_ID *pqlLinkId,
  683. LINK_INFO *pliLinkInfo,
  684. HRESULT *phrLinkDiagnostic);
  685. STDMETHOD(SetLinkState)(
  686. QUEUELINK_ID *pqlLinkId,
  687. LINK_ACTION la);
  688. STDMETHOD(GetLinkIDs)(
  689. DWORD *pcLinks,
  690. QUEUELINK_ID *rgLinks);
  691. STDMETHOD(GetQueueIDs)(
  692. QUEUELINK_ID *pqlLinkId,
  693. DWORD *pcQueues,
  694. QUEUELINK_ID *rgQueues);
  695. STDMETHOD(GetMessageProperties)(
  696. QUEUELINK_ID *pqlQueueLinkId,
  697. MESSAGE_ENUM_FILTER *pmfMessageEnumFilter,
  698. DWORD *pcMsgs,
  699. MESSAGE_INFO *rgMsgs);
  700. STDMETHOD(QuerySupportedActions)(
  701. QUEUELINK_ID *pqlQueueLinkId,
  702. DWORD *pdwSupportedActions,
  703. DWORD *pdwSupportedFilterFlags);
  704. public: //IMailTransportRouterSetLinkState
  705. STDMETHOD(SetLinkState)(
  706. IN LPSTR szLinkDomainName,
  707. IN GUID guidRouterGUID,
  708. IN DWORD dwScheduleID,
  709. IN LPSTR szConnectorName,
  710. IN DWORD dwSetLinkState,
  711. IN DWORD dwUnSetLinkState,
  712. IN FILETIME *pftNextScheduledConnection,
  713. IN IMessageRouter *pMessageRouter);
  714. };
  715. //*** inline counter functions
  716. //---[ CAQSvrInst::cIncMsgsInSystem ]----------------------------------------
  717. //
  718. //
  719. // Description:
  720. // Used to increment the global and virtual server msg counts. Returns
  721. // the global count for resource management purposes.
  722. // Parameters:
  723. // -
  724. // Returns:
  725. // DWORD - Global # of Msgs in system
  726. //
  727. //-----------------------------------------------------------------------------
  728. DWORD CAQSvrInst::cIncMsgsInSystem()
  729. {
  730. InterlockedIncrement((PLONG) &m_cCurrentMsgsSubmitted);
  731. return (InterlockedIncrement((PLONG) &g_cIMsgInSystem));
  732. };
  733. //---[ CAQSvrInst::DecMsgsInSystem ]-----------------------------------------
  734. //
  735. //
  736. // Description:
  737. // Decrements the global and virtual server message counts. Also
  738. // decrements the pending retry count if needed.
  739. // Parameters:
  740. // fWasRetriedRemote - TRUE if msg was retried remotely and retry count needs
  741. // to be decremented.
  742. // fWasRemote - TRUE if message was being delivered remotely
  743. // fWasRetriedLocal - TRUE if counted towards m_cCurrentMsgsPendingLocalRetry
  744. // Returns:
  745. // -
  746. //
  747. //-----------------------------------------------------------------------------
  748. void CAQSvrInst::DecMsgsInSystem(BOOL fWasRetriedRemote, BOOL fWasRemote,
  749. BOOL fWasRetriedLocal)
  750. {
  751. InterlockedDecrement((PLONG) &g_cIMsgInSystem);
  752. InterlockedDecrement((PLONG) &m_cCurrentMsgsSubmitted);
  753. if (fWasRetriedRemote)
  754. InterlockedDecrement((PLONG) &m_cCurrentMsgsPendingRetry);
  755. if (fWasRemote)
  756. InterlockedDecrement((PLONG) &m_cCurrentMsgsPendingDelivery);
  757. if (fWasRetriedLocal)
  758. InterlockedDecrement((PLONG) &m_cCurrentMsgsPendingLocalRetry);
  759. };
  760. //---[ CAQSvrInst::IncRetryCount ]-------------------------------------------
  761. //
  762. //
  763. // Description:
  764. // Used by MsgRef the first time a Message is ack'd with a non-success
  765. // code.
  766. // Parameters:
  767. // BOOL fLocal TRUE if message is local
  768. // Returns:
  769. // -
  770. //
  771. //-----------------------------------------------------------------------------
  772. void CAQSvrInst::IncRetryCount(BOOL fLocal)
  773. {
  774. if (fLocal)
  775. InterlockedIncrement((PLONG) &m_cCurrentMsgsPendingLocalRetry);
  776. else
  777. InterlockedIncrement((PLONG) &m_cCurrentMsgsPendingRetry);
  778. };
  779. //---[ CAQSvrInst::[Inc|Dec]QueueMsgInstances ]------------------------------
  780. //
  781. //
  782. // Description:
  783. // Increments/decrements a count of the total number of message instances
  784. // queued for remote delivery. Because a message may be put in more than
  785. // one queue, the steady state of this count will be at least as large as
  786. // the number of messages. However, this count reflects messages that
  787. // are currently on the queues and does *not* count messages that are
  788. // currently being attempted by SMTP (which m_cCurrentMsgsPendingDelivery)
  789. // *does* count.
  790. //
  791. // Used by DestMsgQueues.
  792. // Parameters:
  793. // -
  794. // Returns:
  795. // -
  796. //
  797. //-----------------------------------------------------------------------------
  798. void CAQSvrInst::IncQueueMsgInstances()
  799. {
  800. InterlockedIncrement((PLONG) &m_cCurrentQueueMsgInstances);
  801. };
  802. void CAQSvrInst::DecQueueMsgInstances()
  803. {
  804. InterlockedDecrement((PLONG) &m_cCurrentQueueMsgInstances);
  805. };
  806. //---[ Queue/NextHop Counter API ]---------------------------------------------
  807. //
  808. //
  809. // Description:
  810. // Used to increment/decrement Queue and NextHop counters
  811. // Parameters:
  812. //
  813. // Returns:
  814. //
  815. //
  816. //-----------------------------------------------------------------------------
  817. void CAQSvrInst::IncDestQueueCount()
  818. {
  819. InterlockedIncrement((PLONG) &m_cCurrentRemoteDestQueues);
  820. };
  821. void CAQSvrInst::DecDestQueueCount()
  822. {
  823. InterlockedDecrement((PLONG) &m_cCurrentRemoteDestQueues);
  824. };
  825. DWORD CAQSvrInst::cGetDestQueueCount()
  826. {
  827. return m_cCurrentRemoteDestQueues;
  828. }
  829. void CAQSvrInst::IncNextHopCount()
  830. {
  831. InterlockedIncrement((PLONG) &m_cCurrentRemoteNextHops);
  832. };
  833. void CAQSvrInst::DecNextHopCount()
  834. {
  835. InterlockedDecrement((PLONG) &m_cCurrentRemoteNextHops);
  836. };
  837. //---[ CAQSvrInst::DecPendingLocal ]-----------------------------------------
  838. //
  839. //
  840. // Description:
  841. // Called by function walking pre-local delivery queue when a message
  842. // is being expired.
  843. // Parameters:
  844. // -
  845. // Returns:
  846. // -
  847. // History:
  848. // 8/14/98 - MikeSwa Created
  849. //
  850. //-----------------------------------------------------------------------------
  851. void CAQSvrInst::DecPendingLocal()
  852. {
  853. _ASSERT(CATMSGQ_SIG == m_dwSignature);
  854. InterlockedDecrement((PLONG) &m_cCurrentMsgsPendingLocal);
  855. };
  856. //---[ CAQSvrInst::IncTURNETRNDelivered ]--------------------------------------
  857. //
  858. //
  859. // Description:
  860. // Used to keep track of the # of TURN/ETRN messages delivered.
  861. // Parameters:
  862. // -
  863. // Returns:
  864. // -
  865. // History:
  866. // 10/27/98 - MikeSwa Created
  867. //
  868. //-----------------------------------------------------------------------------
  869. void CAQSvrInst::IncTURNETRNDelivered()
  870. {
  871. InterlockedIncrement((PLONG) &m_cTotalMsgsTURNETRNDelivered);
  872. }
  873. //---[ CAQSvrInst::GetExpireTime ]-------------------------------------------
  874. //
  875. //
  876. // Description:
  877. // Get the expriation time for cMinutesExpireTime from now.
  878. // Parameters:
  879. // IN cMinutesExpireTime # of minutes in future to set time
  880. // IN OUT pftExpireTime Filetime to store new expire time
  881. // IN OUT pdwExpireContext If non-zero will use the same tick count
  882. // as previous calls (saves call to GetTickCount)
  883. // Returns:
  884. // -
  885. // History:
  886. // 7/11/98 - MikeSwa Created
  887. //
  888. //-----------------------------------------------------------------------------
  889. void CAQSvrInst::GetExpireTime(
  890. IN DWORD cMinutesExpireTime,
  891. IN OUT FILETIME *pftExpireTime,
  892. IN OUT DWORD *pdwExpireContext)
  893. {
  894. m_qtTime.GetExpireTime(cMinutesExpireTime, pftExpireTime, pdwExpireContext);
  895. }
  896. //---[ CAQSvrInst::fInPast ]-------------------------------------------------
  897. //
  898. //
  899. // Description:
  900. // Determines if a given file time has already happened
  901. // Parameters:
  902. // IN pftExpireTime FILETIME with expiration
  903. // IN OUT pdwExpireContext If non-zero will use the same tick count
  904. // as previous calls (saves call to GetTickCount)
  905. // Returns:
  906. // TRUE if expire time is in the past
  907. // FALSE if expire time is in the future
  908. // History:
  909. // 7/11/98 - MikeSwa Created
  910. // Note:
  911. // You should NOT use the same context used to get the FILETIME, because
  912. // it will always return FALSE
  913. //
  914. //-----------------------------------------------------------------------------
  915. BOOL CAQSvrInst::fInPast(IN FILETIME *pftExpireTime,
  916. IN OUT DWORD *pdwExpireContext)
  917. {
  918. return m_qtTime.fInPast(pftExpireTime, pdwExpireContext);
  919. }
  920. //---[ ServerStartHintFunction & ServerStartHintFunction ]---------------------
  921. //
  922. //
  923. // Description:
  924. // Functions for telling the Service control manager that we are
  925. // starting/stopping the service.
  926. //
  927. // These functions are often called by functions that have been passed
  928. // the CAQSvrInst ptr as a PVOID context, so it makes sense to check
  929. // and assert on our signature here.
  930. // Parameters:
  931. // -
  932. // Returns:
  933. // -
  934. // History:
  935. // 7/22/98 - MikeSwa Created
  936. //
  937. //-----------------------------------------------------------------------------
  938. VOID CAQSvrInst::ServerStartHintFunction()
  939. {
  940. _ASSERT(CATMSGQ_SIG == m_dwSignature);
  941. if (m_pISMTPServer)
  942. m_pISMTPServer->ServerStartHintFunction();
  943. }
  944. VOID CAQSvrInst::ServerStopHintFunction()
  945. {
  946. _ASSERT(CATMSGQ_SIG == m_dwSignature);
  947. if (fShutdownSignaled())
  948. {
  949. m_dbgcnt.ResetCountdown();
  950. //Only call stop hint if shutdown has been signalled
  951. if (m_pISMTPServer)
  952. m_pISMTPServer->ServerStopHintFunction();
  953. }
  954. }
  955. //---[ CAQSvrInst::HrQueueWorkItem ]-------------------------------------------
  956. //
  957. //
  958. // Description:
  959. // Thin wrapper to queue item to async work queue
  960. // Parameters:
  961. // pvData Data to pass to completion function
  962. // pfnCompletion Completion function
  963. // Returns:
  964. // S_OK on success
  965. // failure code from CAsyncWorkQueue
  966. // History:
  967. // 3/9/99 - MikeSwa Created
  968. // 7/7/99 - MikeSwa - will work during shutdown to allow multithreaded
  969. // shutdown work.
  970. //
  971. //-----------------------------------------------------------------------------
  972. HRESULT CAQSvrInst::HrQueueWorkItem(PVOID pvData,
  973. PASYNC_WORK_QUEUE_FN pfnCompletion)
  974. {
  975. return m_aqwWorkQueue.HrQueueWorkItem(pvData, pfnCompletion);
  976. }
  977. #endif // __AQINST_H__