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.

432 lines
17 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: msgref.h
  5. //
  6. // Description: Definition of Queueing MsgRef object
  7. //
  8. // Author: mikeswa
  9. //
  10. // Copyright (C) 1997 Microsoft Corporation
  11. //
  12. //-----------------------------------------------------------------------------
  13. #ifndef _MSGREF_H_
  14. #define _MSGREF_H_
  15. #include "cmt.h"
  16. #include "baseobj.h"
  17. #include "bitmap.h"
  18. #include "domain.h"
  19. #include "aqueue.h"
  20. #include "aqroute.h"
  21. #include "qwiklist.h"
  22. #include "dcontext.h"
  23. #include <mailmsg.h>
  24. #include "msgguid.h"
  25. #include "aqutil.h"
  26. #include "aqadmsvr.h"
  27. #include <aqerr.h>
  28. #include <aqreg.h>
  29. class CDestMsgQueue;
  30. class CAQSvrInst;
  31. class CAQStats;
  32. // {34E2DCC8-C91A-11d2-A6B1-00C04FA3490A}
  33. static const GUID IID_CMsgRef =
  34. { 0x34e2dcc8, 0xc91a, 0x11d2, { 0xa6, 0xb1, 0x0, 0xc0, 0x4f, 0xa3, 0x49, 0xa } };
  35. //FLAGS that say which IMsg data we care about
  36. #define MSGREF_VALID_FLAGS (eMsgSize | eMsgArriveTime | eMsgPriority)
  37. //MsgRef signature
  38. #define MSGREF_SIG 'feRM'
  39. //max number of domains for CPool allocator
  40. #define MSGREF_STANDARD_DOMAINS 12
  41. //
  42. // Make sure the "standard" CPool size is
  43. // - large enough to accommidate any padding in the CPoolMsgRef struct
  44. // - QWORD alligned so 64-bit machines are happy
  45. //
  46. #define MSGREF_STANDARD_CPOOL_SIZE \
  47. (((sizeof(CPoolMsgRef) - sizeof(CMsgRef) + \
  48. CMsgRef::size(MSGREF_STANDARD_DOMAINS)) + 0x10) & ~0xF)
  49. //A Note about bitmaps
  50. //The Recips bitmap represents the responsible recipients for a destination,
  51. //or message request. 1 means that the tansport should attempt to deliver for
  52. //this connection.
  53. #ifdef DEBUG
  54. _declspec(selectany) DWORD g_cDbgMsgRefsCpoolAllocated = 0;
  55. _declspec(selectany) DWORD g_cDbgMsgRefsExchmemAllocated = 0;
  56. _declspec(selectany) DWORD g_cDbgMsgRefsCpoolFailed = 0;
  57. _declspec(selectany) DWORD g_cDbgMsgIdHashFailures = 0;
  58. _declspec(selectany) DWORD g_cDbgMsgRefsPendingRetryOnDelete = 0;
  59. #endif //DEBUG
  60. //define reserved message status codes ... should be in MESSAGE_STATUS_RESERVED
  61. #define MESSAGE_STATUS_LOCAL_DELIVERY 0x80000000
  62. #define MESSAGE_STATUS_DROP_DIRECTORY 0x40000000
  63. //---[ CMsgRef ]---------------------------------------------------------------
  64. //
  65. //
  66. // Hungarian: msgref, pmsgref
  67. //
  68. // Persistable message reference object used throughout advanced queuing
  69. //-----------------------------------------------------------------------------
  70. class CMsgRef :
  71. public IUnknown,
  72. public CBaseObject
  73. {
  74. public:
  75. static CPool s_MsgRefPool;
  76. //override the new operator
  77. void * operator new (size_t stIgnored,
  78. unsigned int cDomains); //Number of domains in message
  79. void * operator new (size_t stIgnored); //should not be used
  80. void operator delete(void *p, size_t size);
  81. CMsgRef(DWORD cDomains, IMailMsgQueueMgmt *pIMailMsg,
  82. IMailMsgProperties *pIMailMsgProperties, CAQSvrInst *paqinst,
  83. DWORD dwMessageType, GUID guidMessageRouter);
  84. ~CMsgRef();
  85. //perform initialization and determine the queues for this message.
  86. //A NULL Queue signifies local delivery
  87. HRESULT HrInitialize(
  88. IN IMailMsgRecipients *pIRecipList, //recipient interface for msg
  89. IN IMessageRouter *pIMessageRouter, //Router for this message
  90. IN DWORD dwMessageType,
  91. OUT DWORD *pcLocalRecips,
  92. OUT DWORD *pcRemoteRecips,
  93. OUT DWORD *pcQueues, //# of queues for this message
  94. OUT CDestMsgQueue **rgpdmqQueues); //array of queue ptrs
  95. //Get the effective priority of the message
  96. inline EffectivePriority PriGetPriority()
  97. {return (EffectivePriority) (MSGREF_PRI_MASK & m_dwDataFlags);};
  98. inline IMailMsgProperties *pimsgGetIMsg()
  99. {Assert(m_pIMailMsgProperties);m_pIMailMsgProperties->AddRef();return m_pIMailMsgProperties;};
  100. inline BOOL fIsMyMailMsg(IMailMsgProperties *pIMailMsgProperties)
  101. {return (pIMailMsgProperties == m_pIMailMsgProperties);};
  102. //get the size of the message content
  103. inline DWORD dwGetMsgSize()
  104. {return(m_cbMsgSize);};
  105. inline DWORD cGetNumDomains() {return(m_cDomains);};
  106. //get the size of the class (including all extras)
  107. inline size_t size()
  108. {return (size(m_cDomains));};
  109. //Return the delivery context needed for delivery over a given link
  110. //Do NOT free prgdwRecips... it will disappear with the AckMessage
  111. HRESULT HrPrepareDelivery(
  112. IN BOOL fLocal, //prepare for local domains as well
  113. IN BOOL fDelayDSN, //Check/Set DelayDSN bitmap
  114. IN CQuickList *pqlstQueues, //array of DestMsgQueues
  115. IN CDestMsgRetryQueue* pdmrq, //retry interface for message
  116. IN OUT CDeliveryContext *pdcntxt, //context that must be returned on Ack
  117. OUT DWORD *pcRecips, //#of recips to deliver
  118. OUT DWORD **prgdwRecips); //array of recip indexes
  119. //Acknowledge (non)delivery of a msg
  120. HRESULT HrAckMessage(
  121. IN CDeliveryContext *pdcntxt, //Delivery context of message
  122. IN MessageAck *pMsgAck); //Delivery status of message
  123. CAQMessageType *paqmtGetMessageType() {return &m_aqmtMessageType;};
  124. //size that can be used by new operator
  125. static inline size_t size(DWORD cDomains)
  126. {
  127. return (sizeof(CMsgRef) +
  128. (cDomains-1)*sizeof(CDestMsgQueue *) + //cDomains dmq ptrs
  129. (cDomains + 3) * (CMsgBitMap::size(cDomains)) + //bitmaps
  130. (cDomains*2) * sizeof(DWORD));
  131. };
  132. //Send Delay or NDR DSN's if the message has expired
  133. HRESULT HrSendDelayOrNDR(
  134. IN DWORD dwDSNOptions, //Flags for DSN generation
  135. IN CQuickList *pqlstQueues, //list of DestMsgQueues
  136. IN HRESULT hrStatus, //Status to Pass to DSN generation
  137. OUT DWORD *pdwDSNFlags); //description of what the result was
  138. //bit flag return values for HrSendDelayOrNDR
  139. enum
  140. {
  141. MSGREF_DSN_SENT_NDR = 0x00000001, //Message NDR-expired and NDR was sent
  142. MSGREF_DSN_SENT_DELAY = 0x00000002, //Message Delay-expired and Delay DSN was sent
  143. MSGREF_HANDLED = 0x00000004, //Message has been completely handled
  144. MSGREF_HAS_NOT_EXPIRED = 0x00000008, //Message younger than it's exipiration dates
  145. };
  146. //bit flag options for DSN generation
  147. enum
  148. {
  149. MSGREF_DSN_LOCAL_QUEUE = 0x00000001, //This is for a local queue
  150. MSGREF_DSN_SEND_DELAY = 0x00000002, //Allow Delay DSNs
  151. MSGREF_DSN_CHECK_IF_STALE = 0x00000004, //Force open handle to check if stale
  152. MSGREF_DSN_HAS_ROUTING_LOCK = 0x80000000, //This thread holds the routing lock
  153. };
  154. void SupersedeMsg();
  155. BOOL fMatchesQueueAdminFilter(CAQAdminMessageFilter *paqmf);
  156. HRESULT HrGetQueueAdminMsgInfo(MESSAGE_INFO *pMsgInfo,
  157. IQueueAdminAction *pIQueueAdminAction);
  158. HRESULT HrRemoveMessageFromQueue(CDestMsgQueue *pdmq);
  159. HRESULT HrQueueAdminNDRMessage(CDestMsgQueue *pdmq);
  160. void GlobalFreezeMessage();
  161. void GlobalThawMessage();
  162. BOOL fIsMsgFrozen() {return(MSGREF_MSG_FROZEN & m_dwDataFlags);};
  163. FILETIME *pftGetAge() {return &m_ftQueueEntry;};
  164. void RetryOnDelete();
  165. void PrepareForShutdown() {ReleaseMailMsg(FALSE);};
  166. //Checks if the message can be retried (the backing storage may
  167. //have been deleted).
  168. BOOL fShouldRetry();
  169. void GetStatsForMsg(IN OUT CAQStats *paqstat);
  170. void MarkQueueAsLocal(IN CDestMsgQueue *pdmq);
  171. void CountMessageInRemoteTotals();
  172. //
  173. // Determines if a message is a "problem" message. Currently this is based purely on the number
  174. // of failures per message, but we may wish to add more logic at a later time.
  175. //
  176. BOOL fIsProblemMsg()
  177. {return (g_cMsgFailuresBeforeMarkingMsgAsProblem &&
  178. (m_cTimesRetried >= g_cMsgFailuresBeforeMarkingMsgAsProblem));};
  179. public: //IUnknown
  180. STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvObj);
  181. STDMETHOD_(ULONG, AddRef)(void) {return CBaseObject::AddRef();};
  182. STDMETHOD_(ULONG, Release)(void) {return CBaseObject::Release();};
  183. protected:
  184. DWORD m_dwSignature;
  185. CAQSvrInst *m_paqinst;
  186. DWORD m_dwDataFlags; //private data flags
  187. DWORD m_cbMsgSize; //Size of message content in bytes
  188. FILETIME m_ftQueueEntry; //time that message was enqueued
  189. FILETIME m_ftLocalExpireDelay;
  190. FILETIME m_ftLocalExpireNDR;
  191. FILETIME m_ftRemoteExpireDelay;
  192. FILETIME m_ftRemoteExpireNDR;
  193. CAQMsgGuidListEntry *m_pmgle;
  194. DWORD m_cDomains; //number of DOMAINS this message is destined for
  195. CAQMessageType m_aqmtMessageType; //Message type
  196. IMailMsgQueueMgmt *m_pIMailMsgQM; //Reference to message Queue mgmt
  197. IMailMsgProperties *m_pIMailMsgProperties; //reference to message
  198. IMailMsgRecipients *m_pIMailMsgRecipients;
  199. DWORD m_cTimesRetried;
  200. DWORD m_dwMsgIdHash;
  201. volatile DWORD m_cInternalUsageCount;
  202. CDestMsgQueue *m_rgpdmqDomains[1]; //Actual size is m_cDomains
  203. static inline BOOL fIsStandardSize(DWORD cDomains)
  204. {
  205. return (MSGREF_STANDARD_DOMAINS >= cDomains);
  206. }
  207. HRESULT HrOneTimeInit();
  208. HRESULT HrPrvRetryMessage(CDeliveryContext *pdcntxt, DWORD dwMsgStatus);
  209. HRESULT HrPromoteMessageStatusToMailMsg(CDeliveryContext *pdcntxt,
  210. MessageAck *pMsgAck);
  211. HRESULT HrUpdateExtendedStatus(DWORD cbCurrentStatus,
  212. LPSTR szCurrentStatus,
  213. LPSTR *pszNewStatus);
  214. //private methods to get at "hidden" data.
  215. CMsgBitMap *pmbmapGetDomainBitmap(DWORD iDomain);
  216. CMsgBitMap *pmbmapGetHandled();
  217. CMsgBitMap *pmbmapGetPending();
  218. CMsgBitMap *pmbmapGetDSN();
  219. DWORD *pdwGetRecipIndexStart();
  220. void SetRecipIndex(DWORD iDomain, DWORD iLowRecip, DWORD iHighRecip);
  221. void GetRecipIndex(DWORD iDomain, DWORD *piLowRecip, DWORD *piHighRecip);
  222. void BounceUsageCount();
  223. static BOOL fBounceUsageCountCompletion(PVOID pvContext, DWORD dwStatus);
  224. void ReleaseAndBounceUsageOnMsgAck(DWORD dwMsgStatus);
  225. void ReleaseMailMsg(BOOL fForceRelease);
  226. void SyncBounceUsageCount(); //synchronous version of BounceUsageCount
  227. //Checks to see if the backing mailmsg has been deleted (or is about to
  228. //be deleted).
  229. BOOL fMailMsgMarkedForDeletion()
  230. {return ((MSGREF_MAILMSG_DELETE_PENDING | MSGREF_MAILMSG_DELETED) & m_dwDataFlags);};
  231. //Marks the mailmsg for deletion. MailMsg will be deleted when the usage
  232. //count drops.
  233. void MarkMailMsgForDeletion();
  234. //Used to make sure that calling thread is the only one that will call Delete()
  235. //on the MailMsg. Will set the MSGREF_MAILMSG_DELETED and call Delete().
  236. //Only called in ReleaseMailMsg() and InternalReleaseUsage(). The caller is
  237. //responsible for making sure that other threads are not reading the mailmsg or
  238. //have a usage count
  239. VOID ThreadSafeMailMsgDelete();
  240. //Internal versions of AddUsage/ReleaseUsage. Wraps the actual mailmsg calls, and
  241. //allows the CMsgRef to call delete on the MailMsg while there are still outstanding
  242. //references on it. Uses m_cInternalUsageCount to maintain a count.
  243. HRESULT InternalAddUsage();
  244. HRESULT InternalReleaseUsage();
  245. enum //bitmasks for private flags
  246. {
  247. MSGREF_VERSION_MASK = 0xE0000000,
  248. MSGREF_MSG_COUNTED_AS_REMOTE = 0x08000000,
  249. MSGREF_MSG_LOCAL_RETRY = 0x04000000,
  250. MSGREF_MSG_REMOTE_RETRY = 0x02000000,
  251. MSGREF_USAGE_COUNT_IN_USE = 0x01000000,
  252. MSGREF_SUPERSEDED = 0x00800000, //Msg has been superseed
  253. MSGREF_MSG_INIT = 0x00400000, //HrInitialize has been called
  254. MSGREF_MSG_FROZEN = 0x00200000,
  255. MSGREF_MSG_RETRY_ON_DELETE = 0x00100000,
  256. MSGREF_ASYNC_BOUNCE_PENDING = 0x00040000,
  257. MSGREF_MAILMSG_RELEASED = 0x00020000,
  258. MSGREF_MAILMSG_DELETE_PENDING = 0x00010000, //A delete is pending on this msg
  259. MSGREF_MAILMSG_DELETED = 0x00008000, //The backing store for the mailmsg
  260. //has been deleted.
  261. MSGREF_PRI_MASK = 0x0000000F,
  262. MSGREF_VERSION = 0x00000000,
  263. //used by allocators
  264. MSGREF_CPOOL_SIG_MASK = 0xFFFF0000,
  265. MSGREF_CPOOL_SIG = 0xC0070000,
  266. MSGREF_CPOOL_ALLOCATED = 0x00000001,
  267. MSGREF_STANDARD_SIZE = 0x00000002,
  268. };
  269. static DWORD s_cMsgsPendingBounceUsage;
  270. //Messages that have been marked pending delete, but have not been deleted
  271. static DWORD s_cCurrentMsgsPendingDelete;
  272. //Total number of messages that have been marked pending delete
  273. static DWORD s_cTotalMsgsPendingDelete;
  274. //Total number of messages that have been deleted after being marked
  275. //for delete pending
  276. static DWORD s_cTotalMsgsDeletedAfterPendingDelete;
  277. //Total number of messages that have had ::Deleted, but are still in
  278. //memory because someone has an outstanding reference to the msgref
  279. static DWORD s_cCurrentMsgsDeletedNotReleased;
  280. };
  281. //-----------------------------------------------------------------------------
  282. // Description:
  283. // Checks if the DSN HRESULT status is a fatal one, i.e. one for which an
  284. // NDR should be generated.
  285. //-----------------------------------------------------------------------------
  286. inline BOOL fIsFatalError(HRESULT hrStatus)
  287. {
  288. return
  289. ((AQUEUE_E_NDR_ALL == hrStatus) ||
  290. (AQUEUE_E_LOOPBACK_DETECTED == hrStatus) ||
  291. (AQUEUE_E_ACCESS_DENIED == hrStatus) ||
  292. (AQUEUE_E_MESSAGE_TOO_LARGE == hrStatus) ||
  293. (AQUEUE_E_SMTP_GENERIC_ERROR == hrStatus) ||
  294. (AQUEUE_E_QADMIN_NDR == hrStatus) ||
  295. (AQUEUE_E_NO_ROUTE == hrStatus));
  296. }
  297. //---[ CPoolMsgRef ]-----------------------------------------------------------
  298. //
  299. //
  300. // Description:
  301. // Struct used as a hidden wrapper for CMsgRef allocation... used
  302. // exclusively by the CMsgRef new and delete operators
  303. // Hungarian:
  304. // cpmsgref, pcpmsgref
  305. //
  306. //-----------------------------------------------------------------------------
  307. typedef struct _CPoolMsgRef
  308. {
  309. DWORD m_dwAllocationFlags;
  310. CMsgRef m_msgref;
  311. } CPoolMsgRef;
  312. //Cannot use default CMsgRef new operator
  313. inline void * CMsgRef::operator new(size_t stIgnored)
  314. {
  315. _ASSERT(0 && "Use new that specifies # of domains");
  316. return NULL;
  317. }
  318. inline void CMsgRef::operator delete(void *p, size_t size)
  319. {
  320. CPoolMsgRef *pcpmsgref = CONTAINING_RECORD(p, CPoolMsgRef, m_msgref);
  321. _ASSERT((pcpmsgref->m_dwAllocationFlags & MSGREF_CPOOL_SIG_MASK) == MSGREF_CPOOL_SIG);
  322. if (pcpmsgref->m_dwAllocationFlags & MSGREF_CPOOL_ALLOCATED)
  323. {
  324. s_MsgRefPool.Free((void *) pcpmsgref);
  325. }
  326. else
  327. {
  328. FreePv((void *) pcpmsgref);
  329. }
  330. }
  331. // Layout of private data bit fields
  332. // -------------------------------------
  333. // |332|2222222221111111111987654|3210|
  334. // |109|8765432109876543210 | |
  335. // -------------------------------------
  336. // | | | ^--- Effective routing priority (max 16)
  337. // | | | (Keep least significant so it can be
  338. // | | | used as an array index)
  339. // | | ^-------------------- General msgref flags
  340. // | ^---------------------------------- Version number
  341. //Actual data is variable-sized and extends beyond the class structure.
  342. //Use the public functions to access it. When persisting, be sure to persist
  343. //the entire thing (use size() to see how big it really is).
  344. // +----------+
  345. // | |
  346. // | | constant-size data structure CMsgRef
  347. // | |
  348. // +----------+
  349. // | |
  350. // | | m_cDomains CDestMsgQueue pointers - Tells which queues this
  351. // | | message is on.
  352. // +----------+
  353. // | | Handled bitmap \
  354. // | | Delivery pending bitmap >- bitmaps are variable sized
  355. // | | Delay DSN's sent bitmap / (up to 32 domains fit in a DWORD)
  356. // +----------+
  357. // | |
  358. // | | m_cDomains Domain responsibility bitmaps - used with
  359. // | | the concept of "compressed" queues... not fully supported yet
  360. // +----------+
  361. // | |
  362. // | | m_cDomains (x2) Recipient Index (start and stop... inclusive)
  363. // | |
  364. // +----------+
  365. #endif //_MSGREF_H_