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.

981 lines
31 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: aqutil.cpp
  5. //
  6. // Description:
  7. //
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. // 7/20/98 - MikeSwa Created
  12. //
  13. // Copyright (C) 1998 Microsoft Corporation
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "aqprecmp.h"
  17. #include "aqutil.h"
  18. //---[ HrIncrementIMailMsgUsageCount ]-------------------------------------------
  19. //
  20. //
  21. // Description:
  22. // Calls IMailMsgQueueMgmt::AddUsage. Handles calling QueryInterface
  23. // for the right interface
  24. // Parameters:
  25. // pIUnknown - ptr to IUknown for MailMsg
  26. // Returns:
  27. // S_OK on success
  28. // History:
  29. // 7/20/98 - MikeSwa Created
  30. //
  31. //-----------------------------------------------------------------------------
  32. HRESULT HrIncrementIMailMsgUsageCount(IUnknown *pIUnknown)
  33. {
  34. TraceFunctEnterEx((LPARAM) pIUnknown, "HrIncrementIMailMsgUsageCount");
  35. HRESULT hr = S_OK;
  36. IMailMsgQueueMgmt *pIMailMsgQueueMgmt = NULL;
  37. _ASSERT(pIUnknown);
  38. hr = pIUnknown->QueryInterface(IID_IMailMsgQueueMgmt, (PVOID *) &pIMailMsgQueueMgmt);
  39. _ASSERT(SUCCEEDED(hr) && "QueryInterface for IID_IMailMsgQueueMgmt FAILED");
  40. if (FAILED(hr))
  41. goto Exit;
  42. hr = pIMailMsgQueueMgmt->AddUsage();
  43. if (FAILED(hr))
  44. goto Exit;
  45. Exit:
  46. if (pIMailMsgQueueMgmt)
  47. pIMailMsgQueueMgmt->Release();
  48. TraceFunctLeave();
  49. return hr;
  50. }
  51. //---[ HrReleaseIMailMsgUsageCount ]-------------------------------------------
  52. //
  53. //
  54. // Description:
  55. // Calls IMailMsgQueueMgmt::ReleaseUsage. Handles calling QueryInterface
  56. // for the right interface
  57. // Parameters:
  58. // pIUnknown - ptr to IUknown for MailMsg
  59. // Returns:
  60. // S_OK on success
  61. // History:
  62. // 7/20/98 - MikeSwa Created
  63. //
  64. //-----------------------------------------------------------------------------
  65. HRESULT HrReleaseIMailMsgUsageCount(IUnknown *pIUnknown)
  66. {
  67. TraceFunctEnterEx((LPARAM) pIUnknown, "HrReleaseIMailMsgUsageCount");
  68. HRESULT hr = S_OK;
  69. IMailMsgQueueMgmt *pIMailMsgQueueMgmt = NULL;
  70. _ASSERT(pIUnknown);
  71. hr = pIUnknown->QueryInterface(IID_IMailMsgQueueMgmt, (PVOID *) &pIMailMsgQueueMgmt);
  72. _ASSERT(SUCCEEDED(hr) && "QueryInterface for IID_IMailMsgQueueMgmt FAILED");
  73. if (FAILED(hr))
  74. goto Exit;
  75. hr = pIMailMsgQueueMgmt->ReleaseUsage();
  76. if (FAILED(hr))
  77. goto Exit;
  78. Exit:
  79. if (pIMailMsgQueueMgmt)
  80. pIMailMsgQueueMgmt->Release();
  81. TraceFunctLeave();
  82. return hr;
  83. }
  84. //---[ HrDeleteIMailMsg ]------------------------------------------------------
  85. //
  86. //
  87. // Description:
  88. // Deletes a Msg and releases its usage count
  89. // Parameters:
  90. // pIUnknown Ptr to mailmsg
  91. // Returns:
  92. // S_OK on success
  93. // History:
  94. // 7/21/98 - MikeSwa Created
  95. //
  96. //-----------------------------------------------------------------------------
  97. HRESULT HrDeleteIMailMsg(IUnknown *pIUnknown)
  98. {
  99. TraceFunctEnterEx((LPARAM) pIUnknown, "HrDeleteIMailMsg");
  100. HRESULT hr = S_OK;
  101. IMailMsgQueueMgmt *pIMailMsgQueueMgmt = NULL;
  102. _ASSERT(pIUnknown);
  103. hr = pIUnknown->QueryInterface(IID_IMailMsgQueueMgmt, (PVOID *) &pIMailMsgQueueMgmt);
  104. _ASSERT(SUCCEEDED(hr) && "QueryInterface for IID_IMailMsgQueueMgmt FAILED");
  105. if (FAILED(hr))
  106. goto Exit;
  107. hr = pIMailMsgQueueMgmt->Delete(NULL);
  108. if (FAILED(hr))
  109. goto Exit;
  110. Exit:
  111. if (pIMailMsgQueueMgmt)
  112. pIMailMsgQueueMgmt->Release();
  113. TraceFunctLeave();
  114. return hr;
  115. }
  116. //---[ HrWalkMailMsgQueueForShutdown ]------------------------------------------
  117. //
  118. //
  119. // Description:
  120. // Function to walk an IMailMsg queue at shutdown and clear out all of the
  121. // IMailMsgs
  122. // Parameters:
  123. // IN pIMailMsgProperties //ptr to data on queue
  124. // IN PVOID pvContext //list of queues to prepare for DSN
  125. // OUT BOOL *pfContinue, //TRUE if we should continue
  126. // OUT BOOL *pfDelete); //TRUE if item should be deleted
  127. // Returns:
  128. // S_OK
  129. // History:
  130. // 7/20/98 - MikeSwa Created
  131. // 7/7/99 - Added async shutdown
  132. //-----------------------------------------------------------------------------
  133. HRESULT HrWalkMailMsgQueueForShutdown(IN IMailMsgProperties *pIMailMsgProperties,
  134. IN PVOID pvContext, OUT BOOL *pfContinue,
  135. OUT BOOL *pfDelete)
  136. {
  137. TraceFunctEnterEx((LPARAM) pIMailMsgProperties, "HrWalkMailMsgQueueForShutdown");
  138. Assert(pfContinue);
  139. Assert(pfDelete);
  140. HRESULT hrTmp = S_OK;
  141. CAQSvrInst *paqinst = (CAQSvrInst *) pvContext;
  142. _ASSERT(pIMailMsgProperties);
  143. _ASSERT(paqinst);
  144. *pfContinue = TRUE;
  145. *pfDelete = TRUE;
  146. //call server stop hint function
  147. paqinst->ServerStopHintFunction();
  148. //Add to queue so async thread will have final release and the associated I/O
  149. pIMailMsgProperties->AddRef();
  150. paqinst->HrQueueWorkItem(pIMailMsgProperties, fMailMsgShutdownCompletion);
  151. TraceFunctLeave();
  152. return S_OK;
  153. }
  154. //---[ fMailMsgShutdownCompletion ]---------------------------------------------
  155. //
  156. //
  157. // Description:
  158. // CAsyncWorkQueue completion function to allow multi-threaded shutdown
  159. // of a MailMsgQueue
  160. // Parameters:
  161. // IN pvContext - A mailmsg to release
  162. // IN dwStatus - The status passed in by the async work queue
  163. // Returns:
  164. // TRUE always
  165. // History:
  166. // 7/7/99 - MikeSwa Created
  167. //
  168. //-----------------------------------------------------------------------------
  169. BOOL fMailMsgShutdownCompletion(PVOID pvContext, DWORD dwStatus)
  170. {
  171. IMailMsgProperties *pIMailMsgProperties = (IMailMsgProperties *) pvContext;
  172. HRESULT hr = S_OK;
  173. IMailMsgQueueMgmt *pIMailMsgQueueMgmt = NULL;
  174. _ASSERT(pIMailMsgProperties);
  175. if (!pIMailMsgProperties)
  176. goto Exit;
  177. //Bounce the usage count to force this thread to do any necessary commits
  178. hr = pIMailMsgProperties->QueryInterface(IID_IMailMsgQueueMgmt,
  179. (PVOID *) &pIMailMsgQueueMgmt);
  180. _ASSERT(SUCCEEDED(hr) && "QueryInterface for IID_IMailMsgQueueMgmt FAILED");
  181. if (FAILED(hr))
  182. goto Exit;
  183. hr = pIMailMsgQueueMgmt->ReleaseUsage();
  184. if (FAILED(hr))
  185. goto Exit;
  186. hr = pIMailMsgQueueMgmt->AddUsage();
  187. if (FAILED(hr))
  188. goto Exit;
  189. Exit:
  190. if (pIMailMsgProperties)
  191. pIMailMsgProperties->Release();
  192. if (pIMailMsgQueueMgmt)
  193. pIMailMsgQueueMgmt->Release();
  194. return TRUE;
  195. }
  196. //---[ HrWalkMsgRefQueueForShutdown ]--------------------------------
  197. //
  198. //
  199. // Description:
  200. // Function to walk a queue containing msgrefs at shutdown and
  201. // clear out all of the IMailMsgs
  202. // Parameters:
  203. // IN CMsgRef pmsgref, //ptr to data on queue
  204. // IN PVOID pvContext //list of queues to prepare for DSN
  205. // OUT BOOL *pfContinue, //TRUE if we should continue
  206. // OUT BOOL *pfDelete); //TRUE if item should be deleted
  207. // Returns:
  208. // S_OK - *always*
  209. // History:
  210. // 7/20/98 - MikeSwa Created
  211. // 7/7/99 - MikeSwa Added async shutdown
  212. //-----------------------------------------------------------------------------
  213. HRESULT HrWalkMsgRefQueueForShutdown(IN CMsgRef *pmsgref,
  214. IN PVOID pvContext, OUT BOOL *pfContinue,
  215. OUT BOOL *pfDelete)
  216. {
  217. TraceFunctEnterEx((LPARAM) pmsgref, "HrWalkMsgRefQueueForShutdown");
  218. Assert(pfContinue);
  219. Assert(pfDelete);
  220. CAQSvrInst *paqinst = (CAQSvrInst *) pvContext;
  221. _ASSERT(pmsgref);
  222. _ASSERT(paqinst);
  223. *pfContinue = TRUE;
  224. *pfDelete = TRUE;
  225. //call server stop hint function
  226. if (paqinst)
  227. paqinst->ServerStopHintFunction();
  228. //Add to queue so async thread will have final release and the associated I/O
  229. pmsgref->AddRef();
  230. paqinst->HrQueueWorkItem(pmsgref, fMsgRefShutdownCompletion);
  231. TraceFunctLeave();
  232. return S_OK;
  233. }
  234. //---[ fMsgRefShutdownCompletion ]---------------------------------------------
  235. //
  236. //
  237. // Description:
  238. // CAsyncWorkQueue completion function to allow multi-threaded shutdown
  239. // of a MailMsgQueue
  240. // Parameters:
  241. // IN pvContext - A mailmsg to release
  242. // IN dwStatus - The status passed in by the async work queue
  243. // Returns:
  244. // TRUE always
  245. // History:
  246. // 7/7/99 - MikeSwa Created
  247. //
  248. //-----------------------------------------------------------------------------
  249. BOOL fMsgRefShutdownCompletion(PVOID pvContext, DWORD dwStatus)
  250. {
  251. CMsgRef *pmsgref = (CMsgRef *) pvContext;
  252. _ASSERT(pmsgref);
  253. if (!pmsgref)
  254. return TRUE;
  255. //Call prepare to shutdown to force async threads to be the ones
  256. //doing that actual IO
  257. pmsgref->PrepareForShutdown();
  258. pmsgref->Release();
  259. return TRUE;
  260. }
  261. //---[ CalcDMTPerfCountersIteratorFn ]-----------------------------------------
  262. //
  263. //
  264. // Description:
  265. // Iterator function used to walk the DMT and generate the perf counters
  266. // we are interested in.
  267. // Parameters:
  268. // IN pvContext - pointer to context (current total of pending msgs)
  269. // IN pvData - CDomainEntry for the given domain
  270. // IN fWildcardData - TRUE if data is a wildcard entry (ignored)
  271. // OUT pfContinue - TRUE if iterator should continue to the next entry
  272. // OUT pfDelete - TRUE if entry should be deleted
  273. // Returns:
  274. // -
  275. // History:
  276. // 7/29/98 - MikeSwa Created
  277. // 7/31/98 - MikeSwa Modified (Added link state counters)
  278. // 9/22/98 - MikeSwa Changed from domain flags to link flags
  279. //
  280. // Note:
  281. // Currently the status is stored on the domain entry (and not the link).
  282. // At some point we will have to differentiate this, and add flags to
  283. // the link. In this funciton the cLinkCount variable is a temporary
  284. // workaround.
  285. //-----------------------------------------------------------------------------
  286. VOID CalcDMTPerfCountersIteratorFn(PVOID pvContext, PVOID pvData,
  287. BOOL fWildcard, BOOL *pfContinue,
  288. BOOL *pfDelete)
  289. {
  290. TraceFunctEnterEx((LPARAM) pvData, "CalcMsgsPendingRetryIteratorFn");
  291. CDomainEntry *pdentry = (CDomainEntry *) pvData;
  292. AQPerfCounters *pAQPerfCounters = (AQPerfCounters *) pvContext;
  293. CLinkMsgQueue *plmq = NULL;
  294. CDomainEntryLinkIterator delit;
  295. DWORD cRetryMsgsOnCurrentLink = 0;
  296. DWORD dwLinkStateFlags = 0;
  297. HRESULT hr = S_OK;
  298. BOOL fLinkEnabled = TRUE;
  299. _ASSERT(pvContext);
  300. _ASSERT(pvData);
  301. _ASSERT(pfContinue);
  302. _ASSERT(pfDelete);
  303. _ASSERT(sizeof(AQPerfCounters) == pAQPerfCounters->cbVersion);
  304. //Always continue, and never delete
  305. *pfContinue = TRUE;
  306. *pfDelete = FALSE;
  307. hr = delit.HrInitialize(pdentry);
  308. if (FAILED(hr))
  309. goto Exit;
  310. while (plmq = delit.plmqGetNextLinkMsgQueue(plmq))
  311. {
  312. dwLinkStateFlags = plmq->dwGetLinkState();
  313. fLinkEnabled = TRUE;
  314. // msgs on the retry queue should be added to remote retry queue counter
  315. cRetryMsgsOnCurrentLink = plmq->cGetRetryMsgCount();
  316. if (!(LINK_STATE_RETRY_ENABLED & dwLinkStateFlags))
  317. {
  318. //Link is pending retry
  319. fLinkEnabled = FALSE;
  320. // also add #of msgs NOT on retry queue
  321. cRetryMsgsOnCurrentLink += plmq->cGetTotalMsgCount();
  322. }
  323. pAQPerfCounters->cCurrentMsgsPendingRemoteRetry += cRetryMsgsOnCurrentLink;
  324. if (!(LINK_STATE_SCHED_ENABLED & dwLinkStateFlags))
  325. {
  326. //Link is pending a scheduled connection
  327. fLinkEnabled = FALSE;
  328. pAQPerfCounters->cCurrentRemoteNextHopLinksPendingScheduling++;
  329. }
  330. if (LINK_STATE_PRIV_CONFIG_TURN_ETRN & dwLinkStateFlags)
  331. {
  332. //Link is a TURN/ETRN link
  333. if (!((LINK_STATE_PRIV_ETRN_ENABLED | LINK_STATE_PRIV_TURN_ENABLED)
  334. & dwLinkStateFlags))
  335. fLinkEnabled = FALSE; //link is not currently being serviced
  336. pAQPerfCounters->cCurrentRemoteNextHopLinksPendingTURNETRN++;
  337. }
  338. if (LINK_STATE_ADMIN_HALT & dwLinkStateFlags)
  339. {
  340. //Link is currently frozen by admin
  341. fLinkEnabled = FALSE;
  342. pAQPerfCounters->cCurrentRemoteNextHopLinksFrozenByAdmin++;
  343. }
  344. if (fLinkEnabled)
  345. {
  346. //There are no flags set that indicate this link is not enabled
  347. pAQPerfCounters->cCurrentRemoteNextHopLinksEnabled++;
  348. }
  349. }
  350. Exit:
  351. if (plmq)
  352. plmq->Release();
  353. TraceFunctLeave();
  354. }
  355. //---[ dwInterlockedSetBits ]--------------------------------------------------
  356. //
  357. //
  358. // Description:
  359. // Set bits in a DWORD in a thread sate manner
  360. // Parameters:
  361. // IN pdwTarget Ptr to DWORD to modify
  362. // IN dwFlagMask bits to set
  363. // Returns:
  364. // Original value
  365. // History:
  366. // 8/3/98 - MikeSwa Created
  367. //
  368. //-----------------------------------------------------------------------------
  369. DWORD dwInterlockedSetBits(DWORD *pdwTarget, DWORD dwFlagMask)
  370. {
  371. DWORD dwChk;
  372. DWORD dwTmp;
  373. _ASSERT(pdwTarget);
  374. do
  375. {
  376. dwChk = *pdwTarget;
  377. dwTmp = dwChk | dwFlagMask;
  378. if (dwChk == dwTmp) //no work to be done
  379. break;
  380. } while (InterlockedCompareExchange((PLONG) pdwTarget,
  381. (LONG) dwTmp,
  382. (LONG) dwChk) != (LONG) dwChk);
  383. return dwChk;
  384. }
  385. //---[ dwInterlockedUnsetBits ]------------------------------------------------
  386. //
  387. //
  388. // Description:
  389. // Unset bits in a DWORD in a thread sate manner
  390. // Parameters:
  391. // IN pdwTarget Ptr to DWORD to modify
  392. // IN dwFlagMask bits to unset
  393. // Returns:
  394. // Original value
  395. // History:
  396. // 8/3/98 - MikeSwa Created
  397. //
  398. //-----------------------------------------------------------------------------
  399. DWORD dwInterlockedUnsetBits(DWORD *pdwTarget, DWORD dwFlagMask)
  400. {
  401. DWORD dwChk;
  402. DWORD dwTmp;
  403. _ASSERT(pdwTarget);
  404. do
  405. {
  406. dwChk = *pdwTarget;
  407. dwTmp = dwChk & ~dwFlagMask;
  408. if (dwChk == dwTmp) //no work to be done
  409. break;
  410. } while (InterlockedCompareExchange((PLONG) pdwTarget,
  411. (LONG) dwTmp,
  412. (LONG) dwChk) != (LONG) dwChk);
  413. return dwChk;
  414. }
  415. //---[ HrWalkPreLocalQueueForDSN ]---------------------------------------------
  416. //
  417. //
  418. // Description:
  419. // Function to walk the pre-local delivery queue for DSN generation
  420. // Parameters:
  421. // IN CMsgRef pmsgref ptr to data on queue
  422. // IN PVOID pvContext ptr to CAQSvrInst
  423. // OUT BOOL *pfContinue TRUE if we should continue
  424. // OUT BOOL *pfDelete TRUE if item should be deleted
  425. // Returns:
  426. // S_OK on success
  427. // History:
  428. // 8/14/98 - MikeSwa Created
  429. //
  430. //-----------------------------------------------------------------------------
  431. HRESULT HrWalkPreLocalQueueForDSN(IN CMsgRef *pmsgref, IN PVOID pvContext,
  432. OUT BOOL *pfContinue, OUT BOOL *pfDelete)
  433. {
  434. TraceFunctEnterEx((LPARAM) pmsgref, "HrWalkPreLocalQueueForDSN");
  435. HRESULT hr = S_OK;
  436. DWORD dwDSNFlags = 0;
  437. CLinkMsgQueue *plmq = NULL;
  438. BOOL fShutdownLock = FALSE;
  439. CAQStats aqstats;
  440. CAQSvrInst *paqinst = (CAQSvrInst *)pvContext;
  441. _ASSERT(pfContinue);
  442. _ASSERT(pfDelete);
  443. _ASSERT(paqinst);
  444. *pfContinue = TRUE; //always keep walking queue
  445. *pfDelete = FALSE; //keep message in queue unless we NDR it
  446. if (!paqinst)
  447. goto Exit;
  448. if (!paqinst->fTryShutdownLock())
  449. {
  450. //If we got a shutdown hint...we should bail
  451. *pfContinue = FALSE;
  452. goto Exit;
  453. }
  454. fShutdownLock = TRUE;
  455. hr = pmsgref->HrSendDelayOrNDR(CMsgRef::MSGREF_DSN_LOCAL_QUEUE |
  456. CMsgRef::MSGREF_DSN_SEND_DELAY,
  457. NULL, AQUEUE_E_MSG_EXPIRED, &dwDSNFlags);
  458. if (FAILED(hr))
  459. {
  460. ErrorTrace((LPARAM) pmsgref, "ERROR: HrSendDelayOrNDR failed - hr 0x%08X", hr);
  461. goto Exit;
  462. }
  463. //We need to remove this message from the queue
  464. if ((CMsgRef::MSGREF_DSN_SENT_NDR | CMsgRef::MSGREF_HANDLED) & dwDSNFlags)
  465. {
  466. *pfDelete = TRUE;
  467. //Update relevant counters
  468. paqinst->DecPendingLocal();
  469. //
  470. // Get local link and update stats
  471. //
  472. plmq = paqinst->pdmtGetDMT()->plmqGetLocalLink();
  473. if (plmq)
  474. {
  475. pmsgref->GetStatsForMsg(&aqstats);
  476. plmq->HrNotify(&aqstats, FALSE);
  477. }
  478. }
  479. Exit:
  480. if (fShutdownLock)
  481. paqinst->ShutdownUnlock();
  482. if (plmq)
  483. plmq->Release();
  484. TraceFunctLeave();
  485. return hr;
  486. }
  487. //---[ HrReGetMessageType ]-----------------------------------------------------
  488. //
  489. //
  490. // Description:
  491. // Regets the message type after a retry failure
  492. // Parameters:
  493. // IN pIMailMsgProperties Message we are interested in
  494. // IN pIMessageRouter Router for that message
  495. // IN OUT pdwMessageType Old/New message type for the message
  496. // Returns:
  497. // S_OK on success
  498. // Passes through errors from ReleaseMessageType & GetMessageType
  499. // History:
  500. // 9/14/98 - MikeSwa Created
  501. //
  502. //-----------------------------------------------------------------------------
  503. HRESULT HrReGetMessageType(IN IMailMsgProperties *pIMailMsgProperties,
  504. IN IMessageRouter *pIMessageRouter,
  505. IN OUT DWORD *pdwMessageType)
  506. {
  507. TraceFunctEnterEx((LPARAM) pIMailMsgProperties, "HrReGetMessageType");
  508. HRESULT hr = S_OK;
  509. //$$REVIEW - we might not have to get a new message type here... we
  510. //might only need it on a specific error code returned by HrInitialize.
  511. //Get New Messagetype... in case that changed
  512. hr = pIMessageRouter->ReleaseMessageType(*pdwMessageType, 1);
  513. if (FAILED(hr))
  514. {
  515. _ASSERT(SUCCEEDED(hr) && "ReleaseMessageType failed... may leak message types");
  516. ErrorTrace((LPARAM) pIMailMsgProperties,
  517. "ERROR: ReleaseMessageType failed! - hr 0x%08X", hr);
  518. hr = S_OK; //we are about to retry anyway
  519. }
  520. hr = pIMessageRouter->GetMessageType(pIMailMsgProperties, pdwMessageType);
  521. if (FAILED(hr))
  522. {
  523. ErrorTrace((LPARAM) pIMailMsgProperties,
  524. "ERROR: Unable to re-get message type - HR 0x%08X", hr);
  525. goto Exit; //we cannot recover from this
  526. }
  527. Exit:
  528. TraceFunctLeave();
  529. return hr;
  530. }
  531. //Used to guarantee uniqueue files names
  532. DWORD g_cUniqueueFileNames = 0;
  533. //---[ GetUniqueFileName ]-----------------------------------------------------
  534. //
  535. //
  536. // Description:
  537. // Creates a uniqueue file name
  538. // Parameters:
  539. // pft Ptr to current filetime
  540. // szFileBuffer Buffer to put string into... should be
  541. // at least UNIQUEUE_FILENAME_BUFFER_SIZE
  542. // szExtension Extension for file name... if longer than three chars,
  543. // you will need to increase the size of szFileBuffer
  544. // accordingly.
  545. // Returns:
  546. // -
  547. // History:
  548. // 10/9/98 - MikeSwa Created
  549. //
  550. //-----------------------------------------------------------------------------
  551. void GetUniqueFileName(IN FILETIME *pft, IN LPSTR szFileBuffer,
  552. IN LPSTR szExtension)
  553. {
  554. DWORD cbFileNameSize = 0;
  555. DWORD cUnique = InterlockedIncrement((PLONG) &g_cUniqueueFileNames);
  556. SYSTEMTIME systime;
  557. _ASSERT(szFileBuffer);
  558. _ASSERT(szExtension);
  559. FileTimeToSystemTime(pft, &systime);
  560. cbFileNameSize = wsprintf(
  561. szFileBuffer,
  562. "%05.5x%02.2d%02.2d%02.2d%02.2d%02.2d%04.4d%08X.%s",
  563. systime.wMilliseconds,
  564. systime.wSecond, systime.wMinute, systime.wHour,
  565. systime.wDay, systime.wMonth, systime.wYear,
  566. cUnique, szExtension);
  567. //Assert that are constant is big enough
  568. //By default... allow room for ".eml" extension
  569. _ASSERT((cbFileNameSize + 4 - lstrlen(szExtension)) < UNIQUEUE_FILENAME_BUFFER_SIZE);
  570. }
  571. //---[ HrLinkAllDomains ]-------------------------------------------------------
  572. //
  573. //
  574. // Description:
  575. // Ultility function to link all domains together for recipient enumeration
  576. // (primarly used to NDR an entire message).
  577. //
  578. // Parameters:
  579. // pIMailMsgProperties IMailMsgProperties to link domains together for
  580. // Returns:
  581. // S_OK on success
  582. // History:
  583. // 10/14/98 - MikeSwa Created
  584. //
  585. //-----------------------------------------------------------------------------
  586. HRESULT HrLinkAllDomains(IN IMailMsgProperties *pIMailMsgProperties)
  587. {
  588. TraceFunctEnterEx((LPARAM) pIMailMsgProperties, "HrLinkAllDomains");
  589. HRESULT hr = S_OK;
  590. DWORD cDomains = 0;
  591. DWORD iCurrentDomain = 1;
  592. IMailMsgRecipients *pIMailMsgRecipients = NULL;
  593. _ASSERT(pIMailMsgProperties);
  594. hr = pIMailMsgProperties->QueryInterface(IID_IMailMsgRecipients,
  595. (void **) &pIMailMsgRecipients);
  596. _ASSERT(SUCCEEDED(hr) && "QueryInterface for IID_IMailMsgRecipients failed");
  597. if (FAILED(hr))
  598. goto Exit;
  599. hr = pIMailMsgRecipients->DomainCount(&cDomains);
  600. if (FAILED(hr))
  601. {
  602. ErrorTrace((LPARAM) pIMailMsgProperties, "ERROR: Unable to get DomainCount - hr 0x%08X", hr);
  603. goto Exit;
  604. }
  605. //Set up domain list for all domains
  606. for (iCurrentDomain = 1; iCurrentDomain < cDomains; iCurrentDomain++)
  607. {
  608. hr = pIMailMsgRecipients->SetNextDomain(iCurrentDomain-1, iCurrentDomain,
  609. FLAG_OVERWRITE_EXISTING_LINKS);
  610. if (FAILED(hr))
  611. {
  612. ErrorTrace((LPARAM) pIMailMsgProperties, "ERROR: SetNextDomain Failed - hr 0x%08X", hr);
  613. goto Exit;
  614. }
  615. }
  616. //handle single domain case
  617. if (1 == cDomains)
  618. {
  619. hr = pIMailMsgRecipients->SetNextDomain(0, 0, FLAG_SET_FIRST_DOMAIN);
  620. if (FAILED(hr))
  621. {
  622. ErrorTrace((LPARAM) pIMailMsgProperties, "ERROR: SetNextDomain Failed for single domain- hr 0x%08X", hr);
  623. goto Exit;
  624. }
  625. }
  626. Exit:
  627. if (pIMailMsgRecipients)
  628. pIMailMsgRecipients->Release();
  629. TraceFunctLeave();
  630. return hr;
  631. }
  632. //Parses a GUID from a string... returns TRUE on success
  633. //---[ fAQParseGuidString ]----------------------------------------------------
  634. //
  635. //
  636. // Description:
  637. // Attempts to parse a GUID from a string of hex digits..
  638. // Can handle punctuation, spaces and even leading "0x"'s.
  639. // Parameters:
  640. // IN szGuid String to parse GUID from
  641. // IN cbGuid Max size of GUID string buffer
  642. // OUT guidID GUID parsed from string
  643. // Returns:
  644. // TRUE if a guid value could be parsed from the string
  645. // FALSE if a guid value could not be parsed from the string
  646. // History:
  647. // 10/15/98 - MikeSwa Created
  648. //
  649. //-----------------------------------------------------------------------------
  650. BOOL fAQParseGuidString(LPSTR szGuid, DWORD cbGuid, GUID *pguid)
  651. {
  652. const DWORD NO_SUCH_VALUE = 0xFF;
  653. BOOL fParsed = FALSE;
  654. BOOL fLastCharZero = FALSE; //Used to handle "0x"
  655. DWORD *pdwGuid = (DWORD *) pguid;
  656. DWORD cDigits = 0;
  657. DWORD dwValue = NO_SUCH_VALUE;
  658. LPSTR szCurrent = szGuid;
  659. LPSTR szStop = szGuid + cbGuid/sizeof(CHAR);
  660. //Use DWORD array to populate GUID
  661. *pdwGuid = 0;
  662. while ((szStop > szCurrent) && (*szCurrent))
  663. {
  664. dwValue = NO_SUCH_VALUE;
  665. if (('0' <= *szCurrent) && ('9' >= *szCurrent))
  666. dwValue = *szCurrent-'0';
  667. else if (('a' <= *szCurrent) && ('f' >= *szCurrent))
  668. dwValue = 10 + *szCurrent-'a';
  669. else if (('A' <= *szCurrent) && ('F' >= *szCurrent))
  670. dwValue = 10 + *szCurrent-'A';
  671. else if (fLastCharZero &&
  672. (('x' == *szCurrent) || ('X' == *szCurrent)))
  673. {
  674. //back out last shift (we don't have to subtract anything, since
  675. //the value was zero).
  676. _ASSERT(cDigits);
  677. if (0 == (cDigits % 8)) //happened when we changed DWORDs
  678. pdwGuid--;
  679. else
  680. *pdwGuid /= 16; //undo last shift
  681. cDigits--;
  682. }
  683. //Set flag for handling 0x sequence
  684. if (0 != dwValue)
  685. fLastCharZero = FALSE;
  686. else
  687. fLastCharZero = TRUE;
  688. //In all string guid representations... a valid hex number is at least
  689. //2 characters long... so 0x0 should be mapped to 0x00 and 0xa should
  690. //be mapped to 0x0a. Check and see if such a situation is happening
  691. if ((NO_SUCH_VALUE == dwValue) && (0 != (cDigits % 2)) &&
  692. (',' == *szCurrent))
  693. {
  694. //undo last add and shift. The next if clause will re-write
  695. //the last value in at the proper point
  696. *pdwGuid /= 16;
  697. dwValue = *pdwGuid & 0x0000000F;
  698. *pdwGuid &= 0xFFFFFFF0;
  699. *pdwGuid *= 16;
  700. }
  701. //Add value to GUID if hex character
  702. if (NO_SUCH_VALUE != dwValue)
  703. {
  704. *pdwGuid += dwValue;
  705. if (0 == (++cDigits % 8))
  706. {
  707. //We have reached a DWORD boundary... move on
  708. if (32 == cDigits)
  709. {
  710. //quit when we have enough
  711. fParsed = TRUE;
  712. break;
  713. }
  714. pdwGuid++;
  715. *pdwGuid = 0;
  716. }
  717. else
  718. *pdwGuid *= 16;
  719. }
  720. szCurrent++;
  721. }
  722. //Handle ending 0xa (should be 0x0a) digits
  723. if (!fParsed && (31 == cDigits))
  724. {
  725. dwValue = *pdwGuid & 0x000000FF;
  726. _ASSERT(!(dwValue & 0x0000000F));
  727. *pdwGuid &= 0xFFFFFF00;
  728. dwValue /= 16;
  729. *pdwGuid += dwValue;
  730. fParsed = TRUE;
  731. }
  732. return fParsed;
  733. }
  734. //---[ InterlockedAddSubtractULARGE ]------------------------------------------
  735. //
  736. //
  737. // Description:
  738. // Performs "interlocked" Add/Subtract on ULARGE_INTEGER structures.
  739. //
  740. // Uses s_slUtilityData to synchronize if neccessary.
  741. // Parameters:
  742. // IN puliValue ULARGE to modify
  743. // IN puliNew ULARGE to modify value with
  744. // IN fAdd TRUE if we are adding new value
  745. // FALSE if we are subtracting
  746. // Returns:
  747. // -
  748. // History:
  749. // 11/2/98 - MikeSwa Created
  750. //
  751. //-----------------------------------------------------------------------------
  752. void InterlockedAddSubtractULARGE(ULARGE_INTEGER *puliValue,
  753. ULARGE_INTEGER *puliNew, BOOL fAdd)
  754. {
  755. _ASSERT(puliValue);
  756. _ASSERT(puliNew);
  757. ULARGE_INTEGER uliTmp = {0};
  758. BOOL fDone = FALSE;
  759. DWORD dwTmp = 0;
  760. DWORD dwHighPart = 0;
  761. DWORD dwLowPart = 0;
  762. static CShareLockNH s_slUtilityData; //Used to synchronize global updates of ULONG
  763. s_slUtilityData.ShareLock();
  764. BOOL fShareLock = TRUE; //FALSE implies Exclusive lock
  765. while (!fDone)
  766. {
  767. uliTmp.QuadPart = puliValue->QuadPart;
  768. dwHighPart = uliTmp.HighPart;
  769. dwLowPart = uliTmp.LowPart;
  770. if (fAdd)
  771. uliTmp.QuadPart += puliNew->QuadPart; //add volume
  772. else
  773. uliTmp.QuadPart -= puliNew->QuadPart;
  774. //First see of the high part needs updating
  775. if (dwHighPart != uliTmp.HighPart)
  776. {
  777. if (fShareLock)
  778. {
  779. //This only happens every 4GB of data per queue..
  780. //which means we shouldn't be hitting this lock that
  781. //often
  782. s_slUtilityData.ShareUnlock();
  783. s_slUtilityData.ExclusiveLock();
  784. fShareLock = FALSE;
  785. //Go back to top of loop and re-get data
  786. continue;
  787. }
  788. //At this point it is just safe for us to update the values
  789. puliValue->QuadPart = uliTmp.QuadPart;
  790. }
  791. else if (dwLowPart != uliTmp.LowPart)
  792. {
  793. //Only need to update the low DWORD
  794. dwTmp = (DWORD) InterlockedCompareExchange(
  795. (PLONG) &(puliValue->LowPart),
  796. (LONG) uliTmp.LowPart,
  797. (LONG) dwLowPart);
  798. if (dwLowPart != dwTmp)
  799. continue; //update failed
  800. }
  801. fDone = TRUE;
  802. }
  803. if (fShareLock)
  804. s_slUtilityData.ShareUnlock();
  805. else
  806. s_slUtilityData.ExclusiveUnlock();
  807. }
  808. //---[ HrValidateMessageContent ]----------------------------------------------
  809. //
  810. //
  811. // Description:
  812. // Validates a message based on its content handle. If the backing store
  813. // has been deleted, and the handle is not cached, we should detect this.
  814. // Parameters:
  815. // pIMailMsgProperties - MailMsg to validate
  816. // Returns:
  817. // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) Message belongs to this store
  818. // driver but is no longer valid
  819. // other error code from store driver interface or mailmsg
  820. // History:
  821. // 4/13/2000 - MikeSwa Created
  822. //
  823. //-----------------------------------------------------------------------------
  824. HRESULT HrValidateMessageContent(IMailMsgProperties *pIMailMsgProperties)
  825. {
  826. TraceFunctEnterEx((LPARAM) pIMailMsgProperties, "HrValidateMessageContent");
  827. IMailMsgBind *pBindInterface = NULL;
  828. PFIO_CONTEXT pIMsgFileHandle = NULL;
  829. HRESULT hr = S_OK;
  830. //
  831. // Attempt to query interface for the binding interface
  832. //
  833. hr = pIMailMsgProperties->QueryInterface(IID_IMailMsgBind,
  834. (void **)&pBindInterface);
  835. if (FAILED(hr) || !pBindInterface)
  836. {
  837. ErrorTrace((LPARAM) pIMailMsgProperties,
  838. "Unable to QI for IID_IMailMsgBind - hr 0x%08X", hr);
  839. goto Exit;
  840. }
  841. //
  842. // Request the PFIO_CONTEXT for this message
  843. //
  844. hr = pBindInterface->GetBinding(&pIMsgFileHandle, NULL);
  845. DebugTrace((LPARAM) pIMailMsgProperties,
  846. "GetBinding return hr - 0x%08X", hr);
  847. Exit:
  848. if (pBindInterface)
  849. {
  850. pBindInterface->ReleaseContext();
  851. pBindInterface->Release();
  852. }
  853. TraceFunctLeave();
  854. return hr;
  855. }