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.

1612 lines
32 KiB

  1. /* ----------------------------------------------------------------------
  2. Module: ULS.DLL (Service Provider)
  3. File: sppqueue.cpp
  4. Content: This file contains the pending item/queue objects.
  5. History:
  6. 10/15/96 Chu, Lon-Chan [lonchanc]
  7. Created.
  8. Copyright (c) Microsoft Corporation 1996-1997
  9. ---------------------------------------------------------------------- */
  10. #include "ulsp.h"
  11. #include "spinc.h"
  12. // #define MEASURE_ENUM_USER_INFO 1
  13. ULONG g_uResponseTimeout = ILS_DEF_RESP_TIMEOUT;
  14. ULONG g_uResponsePollPeriod = ILS_DEF_RESP_POLL_PERIOD;
  15. SP_CResponseQueue *g_pRespQueue = NULL;
  16. SP_CRequestQueue *g_pReqQueue = NULL;
  17. SP_CRefreshScheduler *g_pRefreshScheduler = NULL;
  18. typedef BOOL (RESPONSE_HANDLER) ( HRESULT, SP_CResponse * );
  19. typedef LPARAM (REQUEST_HANDLER) ( MARSHAL_REQ * );
  20. extern RESPONSE_HANDLER *GetResponseHandler ( ULONG uNotifyMsg );
  21. extern REQUEST_HANDLER *GetRequestHandler ( ULONG uNotifyMsg );
  22. /* ---------- REQUEST QUEUE ----------- */
  23. MARSHAL_REQ *
  24. MarshalReq_Alloc (
  25. ULONG uNotifyMsg,
  26. ULONG cbSize,
  27. ULONG cParams )
  28. {
  29. // Align the chunk of data for each parameter on 4-byte boundary
  30. //
  31. cbSize += cParams * sizeof (DWORD);
  32. // Calculate the total size of marshal buffer
  33. //
  34. ULONG cbTotalSize = sizeof (MARSHAL_REQ) +
  35. cParams * sizeof (DWORD) +
  36. cbSize;
  37. // Allocate the marshal buffer
  38. //
  39. MARSHAL_REQ *p = (MARSHAL_REQ *) MemAlloc (cbTotalSize);
  40. if (p != NULL)
  41. {
  42. // p->next = NULL;
  43. p->cbTotalSize = cbTotalSize;
  44. p->pb = (BYTE *) ((ULONG_PTR) p + (cbTotalSize - cbSize));
  45. p->uRespID = GetUniqueNotifyID ();
  46. p->uNotifyMsg = uNotifyMsg;
  47. p->cParams = cParams;
  48. }
  49. return p;
  50. }
  51. HRESULT
  52. MarshalReq_SetParam (
  53. MARSHAL_REQ *p,
  54. ULONG nIndex,
  55. DWORD_PTR dwParam,
  56. ULONG cbParamSize )
  57. {
  58. if (p != NULL && nIndex < p->cParams)
  59. {
  60. MyAssert (p->aParams[nIndex] == 0); // not used before
  61. // If cbParamSize > 0, then
  62. // this means uParam is a pointer to a structure or
  63. // a pointer to a string
  64. //
  65. if (cbParamSize > 0)
  66. {
  67. // The pointer is now the one pointing to the new location
  68. //
  69. p->aParams[nIndex] = (DWORD_PTR) p->pb;
  70. // Copy the data chunk
  71. //
  72. CopyMemory (p->pb, (VOID *) dwParam, cbParamSize);
  73. // Make sure the data chunk is aligned on 4-byte boundary
  74. //
  75. if (cbParamSize & 0x3)
  76. {
  77. // Round it up
  78. //
  79. cbParamSize = (cbParamSize & (~0x3)) + 4;
  80. }
  81. // Adjust the running pointer
  82. //
  83. p->pb += cbParamSize;
  84. }
  85. else
  86. {
  87. // uParam can be an signed/unsigned integer,
  88. //
  89. p->aParams[nIndex] = dwParam;
  90. }
  91. }
  92. else
  93. {
  94. MyAssert (FALSE);
  95. }
  96. return S_OK;
  97. }
  98. DWORD_PTR
  99. MarshalReq_GetParam (
  100. MARSHAL_REQ *p,
  101. ULONG nIndex )
  102. {
  103. DWORD_PTR dwParam = 0;
  104. if (p != NULL && nIndex < p->cParams)
  105. {
  106. dwParam = p->aParams[nIndex];
  107. }
  108. else
  109. {
  110. MyAssert (FALSE);
  111. }
  112. return dwParam;
  113. }
  114. HRESULT
  115. MarshalReq_SetParamServer (
  116. MARSHAL_REQ *p,
  117. ULONG nIndex,
  118. SERVER_INFO *pServer,
  119. ULONG cbServer )
  120. {
  121. if (p != NULL && nIndex < p->cParams)
  122. {
  123. MyAssert (p->aParams[nIndex] == 0); // not used before
  124. MyAssert (cbServer > sizeof (SERVER_INFO));
  125. // The pointer is now the one pointing to the new location
  126. //
  127. p->aParams[nIndex] = (DWORD_PTR) p->pb;
  128. // Linearize the server info
  129. //
  130. IlsLinearizeServerInfo (p->pb, pServer);
  131. // Make sure the data chunk is aligned on 4-byte boundary
  132. //
  133. if (cbServer & 0x3)
  134. {
  135. // Round it up
  136. //
  137. cbServer = (cbServer & (~0x3)) + 4;
  138. }
  139. // Adjust the running pointer
  140. //
  141. p->pb += cbServer;
  142. }
  143. return S_OK;
  144. }
  145. SP_CRequestQueue::
  146. SP_CRequestQueue ( VOID )
  147. :
  148. m_ItemList (NULL),
  149. m_uCurrOpRespID (INVALID_RESP_ID)
  150. {
  151. // Create critical sections for thread safe access
  152. //
  153. ::MyInitializeCriticalSection (&m_csReqQ);
  154. ::MyInitializeCriticalSection (&m_csCurrOp);
  155. }
  156. SP_CRequestQueue::
  157. ~SP_CRequestQueue ( VOID )
  158. {
  159. // when this is called, the hidden window thread exited already.
  160. // this is assured in UlsLdap_Deinitialize().
  161. //
  162. WriteLock ();
  163. // Free all the items in this list
  164. //
  165. MARSHAL_REQ *p, *next;
  166. for (p = m_ItemList; p != NULL; p = next)
  167. {
  168. next = p->next;
  169. MemFree (p);
  170. }
  171. m_ItemList = NULL;
  172. WriteUnlock ();
  173. // Delete critical sections
  174. //
  175. ::MyDeleteCriticalSection (&m_csReqQ);
  176. ::MyDeleteCriticalSection (&m_csCurrOp);
  177. }
  178. HRESULT SP_CRequestQueue::
  179. Enter ( MARSHAL_REQ *p )
  180. {
  181. // Make sure we have valid pointers
  182. //
  183. if (p == NULL)
  184. {
  185. MyAssert (FALSE);
  186. return ILS_E_POINTER;
  187. }
  188. MyAssert (! MyIsBadWritePtr (p, p->cbTotalSize));
  189. MyAssert (p->next == NULL);
  190. MyAssert (p->uRespID != 0);
  191. WriteLock ();
  192. // Append the new request
  193. //
  194. p->next = NULL;
  195. if (m_ItemList == NULL)
  196. {
  197. m_ItemList = p;
  198. }
  199. else
  200. {
  201. for ( MARSHAL_REQ *prev = m_ItemList;
  202. prev->next != NULL;
  203. prev = prev->next)
  204. ;
  205. MyAssert (prev != NULL);
  206. prev->next = p;
  207. }
  208. WriteUnlock ();
  209. // Signal the internal request thread to pick up this request
  210. //
  211. SetEvent (g_hevNewRequest);
  212. return S_OK;
  213. }
  214. VOID SP_CRequestQueue::
  215. Schedule ( VOID )
  216. {
  217. MARSHAL_REQ *p;
  218. while (IsAnyReqInQueue () && ! g_fExitNow)
  219. {
  220. // Reset to null, we will use this as an indicator
  221. // to see if we need to process the request
  222. //
  223. p = NULL;
  224. // Lock request queue
  225. //
  226. WriteLock ();
  227. // Get a request to process
  228. //
  229. if (IsAnyReqInQueue ())
  230. {
  231. p = m_ItemList;
  232. m_ItemList = m_ItemList->next;
  233. }
  234. // We want to lock both request queue and CurrOp at the same time
  235. // because we cannot have a temporal window that either one can change.
  236. // Set CurrOp
  237. //
  238. if (p != NULL)
  239. {
  240. // Lock CurrOp
  241. //
  242. LockCurrOp ();
  243. // Set CurrOp
  244. //
  245. m_uCurrOpRespID = p->uRespID;
  246. // Unlock CurrOp
  247. //
  248. UnlockCurrOp ();
  249. }
  250. // Unlock request queue
  251. //
  252. WriteUnlock ();
  253. // Make sure we have something to process
  254. //
  255. if (p == NULL)
  256. {
  257. // Nothing to do any more
  258. //
  259. MyAssert (FALSE);
  260. break;
  261. }
  262. // Let's process the request
  263. //
  264. Dispatch (p);
  265. MemFree(p);
  266. }
  267. }
  268. HRESULT SP_CRequestQueue::
  269. Cancel ( ULONG uRespID )
  270. {
  271. HRESULT hr;
  272. MARSHAL_REQ *p, *next, *prev;
  273. // The locking order is always in
  274. // Lock(PendingOpQueue), Lock(RequestQueue), Lock (CurrOp)
  275. //
  276. WriteLock ();
  277. LockCurrOp ();
  278. if (m_uCurrOpRespID == uRespID)
  279. {
  280. // Invalidate the curr op.
  281. // When the curr op is done, then the request thread will remove it
  282. // from the pending op queue.
  283. //
  284. m_uCurrOpRespID = INVALID_RESP_ID;
  285. hr = S_OK;
  286. }
  287. else
  288. {
  289. // Look for the item with a matching response id
  290. //
  291. for (prev = NULL, p = m_ItemList; p != NULL; prev = p, p = next)
  292. {
  293. // Cache the next pointer
  294. //
  295. next = p->next;
  296. // See if the response id matches
  297. //
  298. if (p->uRespID == uRespID)
  299. {
  300. // It is a match
  301. //
  302. MyDebugMsg ((ZONE_REQ, "ULS: cancelled request(0x%lX) in ReqQ\r\n", p->uNotifyMsg));
  303. // Let's destroy this item
  304. //
  305. if (p == m_ItemList)
  306. {
  307. m_ItemList = next;
  308. }
  309. else
  310. {
  311. MyAssert (prev != NULL);
  312. prev->next = next;
  313. }
  314. // Free this structure
  315. //
  316. MemFree (p);
  317. // Get out of the loop
  318. //
  319. break;
  320. }
  321. } // for
  322. hr = (p == NULL) ? ILS_E_NOTIFY_ID : S_OK;
  323. } // else
  324. UnlockCurrOp ();
  325. WriteUnlock ();
  326. return hr;
  327. }
  328. VOID SP_CRequestQueue::
  329. Dispatch ( MARSHAL_REQ *p )
  330. {
  331. // Make sure we have a valid pointer
  332. //
  333. if (p == NULL)
  334. {
  335. MyAssert (FALSE);
  336. return;
  337. }
  338. // If it is keep alive, then do it
  339. //
  340. HRESULT hr;
  341. if (p->uNotifyMsg == WM_ILS_REFRESH)
  342. {
  343. // Keep alive handler
  344. //
  345. if (g_pRefreshScheduler != NULL)
  346. {
  347. ULONG uTTL = (ULONG) MarshalReq_GetParam (p, 0);
  348. hr = g_pRefreshScheduler->SendRefreshMessages (uTTL);
  349. }
  350. else
  351. {
  352. MyAssert (FALSE);
  353. }
  354. return;
  355. }
  356. // Locate the appropriate handler
  357. //
  358. REQUEST_HANDLER *pfn = ::GetRequestHandler (p->uNotifyMsg);
  359. if (pfn == NULL)
  360. {
  361. MyAssert (FALSE);
  362. return;
  363. }
  364. // Send the request to the server
  365. //
  366. MyDebugMsg ((ZONE_REQ, "ULS: sending request(0x%lX)\r\n", p->uNotifyMsg));
  367. ULONG uRespID = p->uRespID;
  368. LPARAM lParam = (*pfn) (p);
  369. MyDebugMsg ((ZONE_REQ, "ULS: sent request(0x%lX), lParam=0x%lX\r\n", p->uNotifyMsg, lParam));
  370. if (lParam != 0)
  371. {
  372. ::PostMessage (g_hWndNotify, p->uNotifyMsg, p->uRespID, lParam);
  373. return;
  374. }
  375. // BUGBUG: this is a workaround for a server bug which results in lost requests if several
  376. // are sent very quickly. Remove this Sleep() as soon as the bug is fixed!!!
  377. // Sleep(100);
  378. // Lock CurrOp again
  379. //
  380. LockCurrOp ();
  381. // Is this request cancelled
  382. //
  383. BOOL fCancelled = (m_uCurrOpRespID == INVALID_RESP_ID) ? TRUE : FALSE;
  384. // Clean up CurrOp
  385. //
  386. m_uCurrOpRespID = INVALID_RESP_ID;
  387. // Unlock CurrOp
  388. //
  389. UnlockCurrOp ();
  390. // If this request was cancelled, then remove it from the pending op queue
  391. //
  392. if (fCancelled)
  393. {
  394. // Redirect the call to the pending op queue object
  395. //
  396. if (g_pRespQueue != NULL)
  397. {
  398. g_pRespQueue->Cancel (uRespID);
  399. }
  400. else
  401. {
  402. MyAssert (FALSE);
  403. }
  404. }
  405. }
  406. /* ---------- RESPONSE ITEM ----------- */
  407. /* ---------- public methods ----------- */
  408. SP_CResponse::
  409. SP_CResponse ( VOID )
  410. :
  411. m_pSession (NULL), // Clean up session pointer
  412. m_pLdapMsg (NULL), // Clean up ldap msg pointer
  413. m_next (NULL) // Clean up the pointer to the next pending item
  414. {
  415. // Clean up pending info structure
  416. //
  417. ::ZeroMemory (&m_ri, sizeof (m_ri));
  418. // Fill in creation time
  419. //
  420. UpdateLastModifiedTime ();
  421. m_tcTimeout = g_uResponseTimeout;
  422. }
  423. SP_CResponse::
  424. ~SP_CResponse ( VOID )
  425. {
  426. // Release the session if needed
  427. //
  428. if (m_pSession != NULL)
  429. m_pSession->Disconnect ();
  430. // Free the ldap msg if needed
  431. //
  432. if (m_pLdapMsg != NULL)
  433. ::ldap_msgfree (m_pLdapMsg);
  434. // Free extended attribute name list
  435. //
  436. ::MemFree (m_ri.pszAnyAttrNameList);
  437. // Free protocol names to resolve
  438. //
  439. ::MemFree (m_ri.pszProtNameToResolve);
  440. }
  441. /* ---------- protected methods ----------- */
  442. VOID SP_CResponse::
  443. EnterResult ( LDAPMessage *pLdapMsg )
  444. {
  445. // Free the old ldap msg if needed
  446. //
  447. if (m_pLdapMsg != NULL)
  448. ::ldap_msgfree (m_pLdapMsg);
  449. // Keep the new ldap msg
  450. //
  451. m_pLdapMsg = pLdapMsg;
  452. }
  453. /* ---------- private methods ----------- */
  454. /* ---------- RESPONSE QUEUE ----------- */
  455. /* ---------- public methods ----------- */
  456. SP_CResponseQueue::
  457. SP_CResponseQueue ( VOID )
  458. :
  459. m_ItemList (NULL) // Clean up the item list
  460. {
  461. // Create a critical section for thread safe access
  462. //
  463. ::MyInitializeCriticalSection (&m_csRespQ);
  464. }
  465. SP_CResponseQueue::
  466. ~SP_CResponseQueue ( VOID )
  467. {
  468. // when this is called, the hidden window thread exited already.
  469. // this is assured in UlsLdap_Deinitialize().
  470. //
  471. WriteLock ();
  472. // Free all the items in this list
  473. //
  474. SP_CResponse *pItem, *next;
  475. for (pItem = m_ItemList; pItem != NULL; pItem = next)
  476. {
  477. next = pItem->GetNext ();
  478. delete pItem;
  479. }
  480. m_ItemList = NULL;
  481. WriteUnlock ();
  482. // Delete the critical section
  483. //
  484. ::MyDeleteCriticalSection (&m_csRespQ);
  485. }
  486. HRESULT SP_CResponseQueue::
  487. EnterRequest (
  488. SP_CSession *pSession,
  489. RESP_INFO *pInfo )
  490. {
  491. // Make sure we have valid pointers
  492. //
  493. if (pSession == NULL || pInfo == NULL)
  494. {
  495. MyAssert (FALSE);
  496. return ILS_E_POINTER;
  497. }
  498. // Sanity checks
  499. //
  500. MyAssert (! MyIsBadWritePtr (pInfo, sizeof (*pInfo)));
  501. MyAssert (! MyIsBadWritePtr (pSession, sizeof (*pSession)));
  502. MyAssert (pInfo->ld != NULL && pInfo->uMsgID[0] != INVALID_MSG_ID);
  503. MyAssert (pInfo->uRespID != 0);
  504. // Create a new pending item
  505. //
  506. SP_CResponse *pItem = new SP_CResponse;
  507. if (pItem == NULL)
  508. return ILS_E_MEMORY;
  509. // Remember the contents of pending info
  510. //
  511. pItem->EnterRequest (pSession, pInfo);
  512. WriteLock ();
  513. // If this is the first item on the list, then
  514. // let's start the timer
  515. //
  516. if (m_ItemList == NULL)
  517. ::SetTimer (g_hWndHidden, ID_TIMER_POLL_RESULT, g_uResponsePollPeriod, NULL);
  518. // Append the new pending op
  519. //
  520. pItem->SetNext (NULL);
  521. if (m_ItemList == NULL)
  522. {
  523. m_ItemList = pItem;
  524. }
  525. else
  526. {
  527. for ( SP_CResponse *prev = m_ItemList;
  528. prev->GetNext () != NULL;
  529. prev = prev->GetNext ())
  530. ;
  531. MyAssert (prev != NULL);
  532. prev->SetNext (pItem);
  533. }
  534. WriteUnlock ();
  535. return S_OK;
  536. }
  537. HRESULT SP_CResponseQueue::
  538. PollLdapResults ( LDAP_TIMEVAL *pTimeout )
  539. {
  540. MyAssert (pTimeout != NULL);
  541. SP_CResponse *pItem, *next, *prev;
  542. INT RetCode;
  543. RESP_INFO *pInfo;
  544. LDAPMessage *pLdapMsg;
  545. HRESULT hr;
  546. RESPONSE_HANDLER *pfn;
  547. ULONG uResultSetType;
  548. ::KillTimer (g_hWndHidden, ID_TIMER_POLL_RESULT); // avoid overrun
  549. WriteLock ();
  550. // Enumerate all the items to get available results for them
  551. //
  552. for (prev = NULL, pItem = m_ItemList; pItem != NULL; pItem = next)
  553. {
  554. // Cache the next pointer
  555. //
  556. next = pItem->GetNext ();
  557. // Get the pinding info structure
  558. //
  559. pInfo = pItem->GetRespInfo ();
  560. // Clean up ldap msg pointer
  561. //
  562. pLdapMsg = NULL;
  563. // Make sure ew have valid ld and msg id
  564. //
  565. MyAssert (pInfo->ld != NULL);
  566. MyAssert (pInfo->uMsgID[0] != INVALID_MSG_ID ||
  567. pInfo->uMsgID[1] != INVALID_MSG_ID);
  568. // Check integrity in pending info
  569. //
  570. MyAssert (pInfo->uRespID != 0);
  571. // Set the result set type
  572. //
  573. switch (pInfo->uNotifyMsg)
  574. {
  575. case WM_ILS_ENUM_CLIENTS:
  576. case WM_ILS_ENUM_CLIENTINFOS:
  577. #ifdef ENABLE_MEETING_PLACE
  578. case WM_ILS_ENUM_MEETINGS:
  579. case WM_ILS_ENUM_MEETINGINFOS:
  580. #endif
  581. uResultSetType = LDAP_MSG_RECEIVED; // partial result set
  582. break;
  583. default:
  584. uResultSetType = LDAP_MSG_ALL; // complete result set
  585. break;
  586. }
  587. #ifdef _DEBUG
  588. if (MyIsBadWritePtr (pInfo->ld, sizeof (*(pInfo->ld))))
  589. {
  590. MyDebugMsg ((ZONE_CONN, "ILS:: poll result, bad ld=0x%p\r\n", pInfo->ld));
  591. MyAssert (FALSE);
  592. }
  593. if (pInfo->ld != pItem->GetSession()->GetLd())
  594. {
  595. MyDebugMsg ((ZONE_CONN, "ILS:: poll result, inconsistent pInfo->ld=0x%p, pItem->pSession->ld=0x%p\r\n", pInfo->ld, pItem->GetSession()->GetLd()));
  596. MyAssert (FALSE);
  597. }
  598. #endif // _DEBUG
  599. // If primary msg id is valid
  600. //
  601. if (pInfo->uMsgID[0] != INVALID_MSG_ID)
  602. RetCode = ::ldap_result (pInfo->ld,
  603. pInfo->uMsgID[0],
  604. uResultSetType,
  605. pTimeout,
  606. &pLdapMsg);
  607. else
  608. // If secondary msg id is valid
  609. //
  610. if (pInfo->uMsgID[1] != INVALID_MSG_ID)
  611. RetCode = ::ldap_result (pInfo->ld,
  612. pInfo->uMsgID[1],
  613. uResultSetType,
  614. pTimeout,
  615. &pLdapMsg);
  616. // If timeout, ignore this item
  617. //
  618. if (RetCode == 0)
  619. {
  620. // Let's see if this item is expired
  621. //
  622. if (! pItem->IsExpired ())
  623. {
  624. // Not timed out, next please!
  625. //
  626. prev = pItem;
  627. continue;
  628. }
  629. // Timed out
  630. //
  631. hr = ILS_E_TIMEOUT;
  632. }
  633. // If error, delete this request item
  634. //
  635. if (RetCode == -1)
  636. {
  637. // Convert the error
  638. //
  639. hr = ::LdapError2Hresult (pInfo->ld->ld_errno);
  640. }
  641. else
  642. // If not timed out
  643. //
  644. if (RetCode != 0)
  645. {
  646. // It appears to be successful!
  647. //
  648. MyAssert (pLdapMsg != NULL);
  649. // Cache the ldap msg pointer
  650. pItem->EnterResult (pLdapMsg);
  651. // Get the ldap error code
  652. //
  653. hr = (pLdapMsg != NULL) ? ::LdapError2Hresult (pLdapMsg->lm_returncode) :
  654. S_OK;
  655. }
  656. // Get the result handler based on uNotifyMsg
  657. //
  658. pfn = ::GetResponseHandler (pInfo->uNotifyMsg);
  659. if (pfn == NULL)
  660. {
  661. prev = pItem;
  662. continue;
  663. }
  664. // Check integrity in pending info
  665. //
  666. MyAssert (pInfo->uRespID != 0);
  667. // Deal with the result or error
  668. //
  669. MyDebugMsg ((ZONE_RESP, "ULS: response(0x%lX), hr=0x%lX\r\n", pInfo->uNotifyMsg, hr));
  670. if ((*pfn) (hr, pItem))
  671. {
  672. // Let's destroy this item
  673. //
  674. if (pItem == m_ItemList)
  675. {
  676. m_ItemList = next;
  677. }
  678. else
  679. {
  680. MyAssert (prev != NULL);
  681. prev->SetNext (next);
  682. }
  683. delete pItem; // SP_CSession::Disconnect() and ldap_msgfree() will be called in destructor
  684. }
  685. else
  686. {
  687. // Let's keep this item around.
  688. // There are pending results coming in.
  689. //
  690. pItem->UpdateLastModifiedTime ();
  691. // Update the pointer
  692. //
  693. prev = pItem;
  694. }
  695. } // for
  696. // If there is no more items on the list, then stop the timer
  697. //
  698. if (m_ItemList != NULL)
  699. ::SetTimer (g_hWndHidden, ID_TIMER_POLL_RESULT, g_uResponsePollPeriod, NULL);
  700. WriteUnlock ();
  701. return S_OK;
  702. }
  703. HRESULT SP_CResponseQueue::
  704. Cancel ( ULONG uRespID )
  705. {
  706. SP_CResponse *pItem, *next, *prev;
  707. RESP_INFO *pInfo;
  708. BOOL fNeedCleanup = FALSE;
  709. WriteLock ();
  710. // Look for the item with a matching response id
  711. //
  712. for (prev = NULL, pItem = m_ItemList; pItem != NULL; prev = pItem, pItem = next)
  713. {
  714. // Cache the next pointer
  715. //
  716. next = pItem->GetNext ();
  717. // Get the pinding info structure
  718. //
  719. pInfo = pItem->GetRespInfo ();
  720. MyAssert (pInfo != NULL);
  721. // See if the response id matches
  722. //
  723. if (pInfo->uRespID == uRespID)
  724. {
  725. // It is a match
  726. //
  727. SP_CSession *pSession = pItem->GetSession ();
  728. MyAssert (pSession != NULL);
  729. // Make sure we have a valid ldap session
  730. //
  731. MyAssert (pInfo->ld != NULL);
  732. // If we are NOT in the request thread, then we need to marshal it
  733. // to the request thread!!! Exit and report success!!!
  734. //
  735. if (GetCurrentThreadId () != g_dwReqThreadID)
  736. {
  737. MyDebugMsg ((ZONE_RESP, "ULS: marshalling request(0x%lX) in RespQ\r\n", pInfo->uNotifyMsg));
  738. MARSHAL_REQ *pReq = MarshalReq_Alloc (WM_ILS_CANCEL, 0, 1);
  739. if (pReq != NULL)
  740. {
  741. MarshalReq_SetParam (pReq, 0, (DWORD) uRespID, 0);
  742. if (g_pReqQueue != NULL)
  743. {
  744. // This means that the locking order is
  745. // Lock(PendingOpQueue), Lock(RequestQueue)
  746. //
  747. g_pReqQueue->Enter (pReq);
  748. }
  749. else
  750. {
  751. MyAssert (FALSE);
  752. }
  753. }
  754. // Exit this loop
  755. //
  756. break;
  757. }
  758. // Indicate that we need to clean up item. Why?
  759. // because we should not have any network operation inside critical section.
  760. // this is to avoid any possible network blocking.
  761. //
  762. fNeedCleanup = TRUE;
  763. // Let's destroy this item
  764. //
  765. if (pItem == m_ItemList)
  766. {
  767. m_ItemList = next;
  768. }
  769. else
  770. {
  771. MyAssert (prev != NULL);
  772. prev->SetNext (next);
  773. }
  774. // Get out of the loop
  775. //
  776. break;
  777. } // if matched
  778. } // for
  779. // If there is no more items on the list, then stop the timer
  780. //
  781. if (m_ItemList == NULL)
  782. ::KillTimer (g_hWndHidden, ID_TIMER_POLL_RESULT);
  783. WriteUnlock ();
  784. if (fNeedCleanup && pItem != NULL)
  785. {
  786. MyDebugMsg ((ZONE_RESP, "ULS: cancelled request(0x%lX) in RespQ\r\n", pInfo->uNotifyMsg));
  787. // Get resp info pointer
  788. //
  789. pInfo = pItem->GetRespInfo ();
  790. MyAssert (pInfo != NULL);
  791. // Abandon the primary response if needed
  792. //
  793. if (pInfo->uMsgID[1] != INVALID_MSG_ID)
  794. ::ldap_abandon (pInfo->ld, pInfo->uMsgID[1]);
  795. // Abandon the secondary response if needed
  796. //
  797. if (pInfo->uMsgID[0] != INVALID_MSG_ID)
  798. ::ldap_abandon (pInfo->ld, pInfo->uMsgID[0]);
  799. // SP_CSession::Disconnect() and ldap_msgfree() will be called in destructor
  800. //
  801. delete pItem;
  802. }
  803. return ((pItem == NULL) ? ILS_E_NOTIFY_ID : S_OK);
  804. }
  805. /* ---------- protected methods ----------- */
  806. /* ---------- private methods ----------- */
  807. /* ==================== utilities ====================== */
  808. VOID
  809. FillDefRespInfo (
  810. RESP_INFO *pInfo,
  811. ULONG uRespID,
  812. LDAP *ld,
  813. ULONG uMsgID,
  814. ULONG u2ndMsgID )
  815. {
  816. // Clean up
  817. //
  818. ZeroMemory (pInfo, sizeof (*pInfo));
  819. // Cache the ldap session
  820. //
  821. pInfo->ld = ld;
  822. // Generate a unique notify id
  823. //
  824. pInfo->uRespID = uRespID;
  825. // Store the primary and seconary msg ids
  826. //
  827. pInfo->uMsgID[0] = uMsgID;
  828. pInfo->uMsgID[1] = u2ndMsgID;
  829. }
  830. /* ---------- REFRESH SCHEDULER ----------- */
  831. /* ---------- public methods ----------- */
  832. SP_CRefreshScheduler::
  833. SP_CRefreshScheduler ( VOID )
  834. :
  835. m_ListHead (NULL) // Initialize the item list
  836. {
  837. // Create a critical section for thread safe access
  838. //
  839. ::MyInitializeCriticalSection (&m_csRefreshScheduler);
  840. }
  841. SP_CRefreshScheduler::
  842. ~SP_CRefreshScheduler ( VOID )
  843. {
  844. WriteLock ();
  845. // Clean up the item list
  846. //
  847. REFRESH_ITEM *p, *next;
  848. for (p = m_ListHead; p != NULL; p = next)
  849. {
  850. next = p->next;
  851. MemFree (p);
  852. }
  853. m_ListHead = NULL;
  854. WriteUnlock ();
  855. // Delete the critical section
  856. //
  857. ::MyDeleteCriticalSection (&m_csRefreshScheduler);
  858. }
  859. HRESULT SP_CRefreshScheduler::
  860. SendRefreshMessages ( UINT uTimerID )
  861. {
  862. SP_CClient *pClient;
  863. #ifdef ENABLE_MEETING_PLACE
  864. SP_CMeeting *pMtg;
  865. #endif
  866. REFRESH_ITEM *prev, *curr;
  867. INT nIndex;
  868. // Lock the lists
  869. //
  870. ReadLock ();
  871. // Locate this object in the list
  872. //
  873. nIndex = TimerID2Index (uTimerID);
  874. for (prev = NULL, curr = m_ListHead;
  875. curr != NULL;
  876. curr = (prev = curr)->next)
  877. {
  878. if (curr->nIndex == nIndex)
  879. {
  880. // Find it. Let's send a refresh message for this object
  881. //
  882. switch (curr->ObjectType)
  883. {
  884. case CLIENT_OBJ:
  885. pClient = (SP_CClient *) curr->pObject;
  886. // Make sure this object is not deleted already
  887. //
  888. if (! MyIsBadWritePtr (pClient, sizeof (*pClient)) &&
  889. pClient->IsValidObject ())
  890. {
  891. // Make sure this object is valid and registered
  892. //
  893. if (pClient->IsRegistered ())
  894. {
  895. MyDebugMsg ((ZONE_KA, "KA: send refresh msg for client\r\n"));
  896. // Let's send a refresh message for this client object
  897. // and update the new ttl value
  898. //
  899. pClient->AddRef ();
  900. pClient->SendRefreshMsg ();
  901. curr->uTTL = pClient->GetTTL ();
  902. pClient->Release ();
  903. }
  904. }
  905. else
  906. {
  907. MyAssert (FALSE);
  908. }
  909. break;
  910. #ifdef ENABLE_MEETING_PLACE
  911. case MTG_OBJ:
  912. pMtg = (SP_CMeeting *) curr->pObject;
  913. // Make sure this object is not deleted already
  914. //
  915. if (! MyIsBadWritePtr (pMtg, sizeof (*pMtg)) &&
  916. pMtg->IsValidObject ())
  917. {
  918. // Make sure this object is valid and registered
  919. //
  920. if (pMtg->IsRegistered ())
  921. {
  922. MyDebugMsg ((ZONE_KA, "KA: send refresh msg for mtg\r\n"));
  923. // Let's send a refresh message for this user object
  924. // and update the new ttl value
  925. //
  926. pMtg->AddRef ();
  927. pMtg->SendRefreshMsg ();
  928. curr->uTTL = pMtg->GetTTL ();
  929. pMtg->Release ();
  930. }
  931. }
  932. else
  933. {
  934. MyAssert (FALSE);
  935. }
  936. break;
  937. #endif
  938. default:
  939. MyAssert (FALSE);
  940. break;
  941. }
  942. // Start the timer again and exit
  943. // Note that curr->uTTL is the new TTL value from the server
  944. // Also note that uTTL is in unit of minute
  945. //
  946. MyDebugMsg ((ZONE_KA, "KA: new ttl=%lu\r\n", curr->uTTL));
  947. ::SetTimer (g_hWndHidden, uTimerID, Minute2TickCount (curr->uTTL), NULL);
  948. break;
  949. } // if
  950. } // for
  951. ReadUnlock ();
  952. return S_OK;
  953. }
  954. HRESULT SP_CRefreshScheduler::
  955. EnterClientObject ( SP_CClient *pClient )
  956. {
  957. if (pClient == NULL)
  958. return ILS_E_POINTER;
  959. return EnterObject (CLIENT_OBJ, (VOID *) pClient, pClient->GetTTL ());
  960. }
  961. #ifdef ENABLE_MEETING_PLACE
  962. HRESULT SP_CRefreshScheduler::
  963. EnterMtgObject ( SP_CMeeting *pMtg )
  964. {
  965. if (pMtg == NULL)
  966. return ILS_E_POINTER;
  967. return EnterObject (MTG_OBJ, (VOID *) pMtg, pMtg->GetTTL ());
  968. }
  969. #endif
  970. VOID *SP_CRefreshScheduler::
  971. AllocItem ( BOOL fNeedLock )
  972. {
  973. REFRESH_ITEM *p, *curr, *prev;
  974. INT nIndex, nLargestIndex;
  975. BOOL fGotTheNewIndex;
  976. // Allocate the structure
  977. //
  978. p = (REFRESH_ITEM *) MemAlloc (sizeof (REFRESH_ITEM));
  979. if (p != NULL)
  980. {
  981. if (fNeedLock)
  982. WriteLock ();
  983. // Find out what should be the index for the new item
  984. //
  985. nLargestIndex = -1; // Yes, it is -1 for the case m_ListHead==NULL
  986. fGotTheNewIndex = FALSE;
  987. for (nIndex = 0, prev = NULL, curr = m_ListHead;
  988. curr != NULL;
  989. nIndex++, curr = (prev = curr)->next)
  990. {
  991. if (curr->nIndex > nIndex)
  992. {
  993. p->nIndex = nIndex;
  994. fGotTheNewIndex = TRUE;
  995. break;
  996. }
  997. nLargestIndex = curr->nIndex;
  998. }
  999. // Put the new item in the list in its appropriate position
  1000. //
  1001. if (fGotTheNewIndex)
  1002. {
  1003. if (prev == NULL)
  1004. {
  1005. // The new one must be the first one
  1006. //
  1007. MyAssert (p->nIndex == 0);
  1008. p->next = m_ListHead;
  1009. m_ListHead = p;
  1010. }
  1011. else
  1012. {
  1013. // The new one in the middle of the list
  1014. //
  1015. MyAssert (prev->nIndex < p->nIndex && p->nIndex < curr->nIndex);
  1016. MyAssert (prev->next == curr);
  1017. (prev->next = p)->next = curr;
  1018. }
  1019. }
  1020. else
  1021. {
  1022. MyAssert (m_ListHead == NULL || prev != NULL);
  1023. if (m_ListHead == NULL)
  1024. {
  1025. // The new one will be the only one in the list
  1026. //
  1027. p->nIndex = 0;
  1028. (m_ListHead = p)->next = NULL;
  1029. }
  1030. else
  1031. {
  1032. // The new one is at the end of the list
  1033. //
  1034. MyAssert (prev != NULL && prev->next == NULL && curr == NULL);
  1035. p->nIndex = nLargestIndex + 1;
  1036. (prev->next = p)->next = curr;
  1037. }
  1038. }
  1039. if (fNeedLock)
  1040. WriteUnlock ();
  1041. } // if (p != NULL)
  1042. return p;
  1043. }
  1044. HRESULT SP_CRefreshScheduler::
  1045. EnterObject ( PrivateObjType ObjectType, VOID *pObject, ULONG uInitialTTL )
  1046. {
  1047. HRESULT hr = S_OK;
  1048. WriteLock ();
  1049. // Enter this object to the list
  1050. //
  1051. REFRESH_ITEM *p = (REFRESH_ITEM *) AllocItem (FALSE);
  1052. if (p == NULL)
  1053. {
  1054. hr = ILS_E_MEMORY;
  1055. goto MyExit;
  1056. }
  1057. // Fill in fields
  1058. //
  1059. p->ObjectType = ObjectType;
  1060. p->pObject = pObject;
  1061. p->uTTL = uInitialTTL;
  1062. // Turn on the timer
  1063. // Note that uTTL is in unit of minutes...
  1064. //
  1065. ::SetTimer (g_hWndHidden, Index2TimerID (p->nIndex), Minute2TickCount (p->uTTL), NULL);
  1066. MyExit:
  1067. WriteUnlock ();
  1068. return hr;
  1069. }
  1070. HRESULT SP_CRefreshScheduler::
  1071. RemoveObject ( VOID *pObject )
  1072. {
  1073. REFRESH_ITEM *prev, *curr;
  1074. WriteLock ();
  1075. // Locate this object in the list
  1076. //
  1077. for (prev = NULL, curr = m_ListHead;
  1078. curr != NULL;
  1079. curr = (prev = curr)->next)
  1080. {
  1081. if (curr->pObject == pObject)
  1082. {
  1083. // Find it, let's kill the timer first
  1084. //
  1085. KillTimer (g_hWndHidden, Index2TimerID (curr->nIndex));
  1086. // Remove it from the list
  1087. //
  1088. if (prev == NULL)
  1089. {
  1090. // This one is the first one on the list
  1091. //
  1092. MyAssert (m_ListHead == curr);
  1093. m_ListHead = curr->next;
  1094. }
  1095. else
  1096. {
  1097. // This one is in the middle of the list
  1098. //
  1099. MyAssert (prev->next == curr);
  1100. prev->next = curr->next;
  1101. }
  1102. ::MemFree(curr);
  1103. // Exit the loop
  1104. //
  1105. break;
  1106. }
  1107. }
  1108. WriteUnlock ();
  1109. return (curr != NULL ? S_OK : S_FALSE);
  1110. }
  1111. extern BOOL NotifyGeneric ( HRESULT, SP_CResponse * );
  1112. extern BOOL NotifyRegister ( HRESULT, SP_CResponse * );
  1113. extern BOOL NotifyResolveClient ( HRESULT, SP_CResponse * );
  1114. extern BOOL NotifyEnumClients ( HRESULT, SP_CResponse * );
  1115. extern BOOL NotifyEnumClientInfos ( HRESULT, SP_CResponse * );
  1116. extern BOOL NotifyResolveProt ( HRESULT, SP_CResponse * );
  1117. extern BOOL NotifyEnumProts ( HRESULT, SP_CResponse * );
  1118. extern BOOL NotifyResolveMtg ( HRESULT, SP_CResponse * );
  1119. extern BOOL NotifyEnumMtgInfos ( HRESULT, SP_CResponse * );
  1120. extern BOOL NotifyEnumMtgs ( HRESULT, SP_CResponse * );
  1121. extern BOOL NotifyEnumAttendees ( HRESULT, SP_CResponse * );
  1122. extern LPARAM AsynReq_RegisterClient ( MARSHAL_REQ * );
  1123. extern LPARAM AsynReq_RegisterProtocol ( MARSHAL_REQ * );
  1124. extern LPARAM AsynReq_RegisterMeeting ( MARSHAL_REQ * );
  1125. extern LPARAM AsynReq_UnRegisterClient ( MARSHAL_REQ * );
  1126. extern LPARAM AsynReq_UnRegisterProt ( MARSHAL_REQ * );
  1127. extern LPARAM AsynReq_UnRegisterMeeting ( MARSHAL_REQ * );
  1128. extern LPARAM AsynReq_SetClientInfo ( MARSHAL_REQ * );
  1129. extern LPARAM AsynReq_SetProtocolInfo ( MARSHAL_REQ * );
  1130. extern LPARAM AsynReq_SetMeetingInfo ( MARSHAL_REQ * );
  1131. extern LPARAM AsynReq_EnumClientsEx ( MARSHAL_REQ * );
  1132. extern LPARAM AsynReq_EnumProtocols ( MARSHAL_REQ * );
  1133. extern LPARAM AsynReq_EnumMtgsEx ( MARSHAL_REQ * );
  1134. extern LPARAM AsynReq_EnumAttendees ( MARSHAL_REQ * );
  1135. extern LPARAM AsynReq_ResolveClient ( MARSHAL_REQ * );
  1136. extern LPARAM AsynReq_ResolveProtocol ( MARSHAL_REQ * );
  1137. extern LPARAM AsynReq_ResolveMeeting ( MARSHAL_REQ * );
  1138. extern LPARAM AsynReq_UpdateAttendees ( MARSHAL_REQ * );
  1139. extern LPARAM AsynReq_Cancel ( MARSHAL_REQ * );
  1140. typedef struct
  1141. {
  1142. #ifdef DEBUG
  1143. LONG nMsg;
  1144. #endif
  1145. RESPONSE_HANDLER *pfnRespHdl;
  1146. REQUEST_HANDLER *pfnReqHdl;
  1147. }
  1148. RES_HDL_TBL;
  1149. RES_HDL_TBL g_ResHdlTbl[] =
  1150. {
  1151. {
  1152. #ifdef DEBUG
  1153. WM_ILS_REGISTER_CLIENT,
  1154. #endif
  1155. NotifyRegister,
  1156. AsynReq_RegisterClient
  1157. },
  1158. {
  1159. #ifdef DEBUG
  1160. WM_ILS_UNREGISTER_CLIENT,
  1161. #endif
  1162. NotifyGeneric,
  1163. AsynReq_UnRegisterClient
  1164. },
  1165. {
  1166. #ifdef DEBUG
  1167. WM_ILS_SET_CLIENT_INFO,
  1168. #endif
  1169. NotifyGeneric,
  1170. AsynReq_SetClientInfo
  1171. },
  1172. {
  1173. #ifdef DEBUG
  1174. WM_ILS_RESOLVE_CLIENT,
  1175. #endif
  1176. NotifyResolveClient,
  1177. AsynReq_ResolveClient
  1178. },
  1179. {
  1180. #ifdef DEBUG
  1181. WM_ILS_ENUM_CLIENTS,
  1182. #endif
  1183. NotifyEnumClients,
  1184. AsynReq_EnumClientsEx
  1185. },
  1186. {
  1187. #ifdef DEBUG
  1188. WM_ILS_ENUM_CLIENTINFOS,
  1189. #endif
  1190. NotifyEnumClientInfos,
  1191. AsynReq_EnumClientsEx
  1192. },
  1193. {
  1194. #ifdef DEBUG
  1195. WM_ILS_REGISTER_PROTOCOL,
  1196. #endif
  1197. NotifyRegister,
  1198. AsynReq_RegisterProtocol
  1199. },
  1200. {
  1201. #ifdef DEBUG
  1202. WM_ILS_UNREGISTER_PROTOCOL,
  1203. #endif
  1204. NotifyGeneric,
  1205. AsynReq_UnRegisterProt
  1206. },
  1207. {
  1208. #ifdef DEBUG
  1209. WM_ILS_SET_PROTOCOL_INFO,
  1210. #endif
  1211. NotifyGeneric,
  1212. AsynReq_SetProtocolInfo
  1213. },
  1214. {
  1215. #ifdef DEBUG
  1216. WM_ILS_RESOLVE_PROTOCOL,
  1217. #endif
  1218. NotifyResolveProt,
  1219. AsynReq_ResolveProtocol
  1220. },
  1221. {
  1222. #ifdef DEBUG
  1223. WM_ILS_ENUM_PROTOCOLS,
  1224. #endif
  1225. NotifyEnumProts,
  1226. AsynReq_EnumProtocols
  1227. },
  1228. #ifdef ENABLE_MEETING_PLACE
  1229. {
  1230. #ifdef DEBUG
  1231. WM_ILS_REGISTER_MEETING,
  1232. #endif
  1233. NotifyRegister,
  1234. AsynReq_RegisterMeeting
  1235. },
  1236. {
  1237. #ifdef DEBUG
  1238. WM_ILS_UNREGISTER_MEETING,
  1239. #endif
  1240. NotifyGeneric,
  1241. AsynReq_UnRegisterMeeting
  1242. },
  1243. {
  1244. #ifdef DEBUG
  1245. WM_ILS_SET_MEETING_INFO,
  1246. #endif
  1247. NotifyGeneric,
  1248. AsynReq_SetMeetingInfo
  1249. },
  1250. {
  1251. #ifdef DEBUG
  1252. WM_ILS_RESOLVE_MEETING,
  1253. #endif
  1254. NotifyResolveMtg,
  1255. AsynReq_ResolveMeeting
  1256. },
  1257. {
  1258. #ifdef DEBUG
  1259. WM_ILS_ENUM_MEETINGINFOS,
  1260. #endif
  1261. NotifyEnumMtgInfos,
  1262. AsynReq_EnumMtgsEx
  1263. },
  1264. {
  1265. #ifdef DEBUG
  1266. WM_ILS_ENUM_MEETINGS,
  1267. #endif
  1268. NotifyEnumMtgs,
  1269. AsynReq_EnumMtgsEx
  1270. },
  1271. {
  1272. #ifdef DEBUG
  1273. WM_ILS_ADD_ATTENDEE,
  1274. #endif
  1275. NotifyGeneric,
  1276. AsynReq_UpdateAttendees
  1277. },
  1278. {
  1279. #ifdef DEBUG
  1280. WM_ILS_REMOVE_ATTENDEE,
  1281. #endif
  1282. NotifyGeneric,
  1283. AsynReq_UpdateAttendees
  1284. },
  1285. {
  1286. #ifdef DEBUG
  1287. WM_ILS_ENUM_ATTENDEES,
  1288. #endif
  1289. NotifyEnumAttendees,
  1290. AsynReq_EnumAttendees
  1291. },
  1292. #endif // ENABLE_MEETING_PLACE
  1293. {
  1294. #ifdef DEBUG
  1295. WM_ILS_CANCEL,
  1296. #endif
  1297. NULL,
  1298. AsynReq_Cancel
  1299. }
  1300. };
  1301. #ifdef DEBUG
  1302. VOID DbgValidateHandlerTable ( VOID )
  1303. {
  1304. MyAssert (ARRAY_ELEMENTS (g_ResHdlTbl) == WM_ILS_LAST_ONE - WM_ILS_ASYNC_RES + 1);
  1305. for (LONG i = 0; i < ARRAY_ELEMENTS (g_ResHdlTbl); i++)
  1306. {
  1307. if (g_ResHdlTbl[i].nMsg - WM_ILS_ASYNC_RES != i)
  1308. {
  1309. MyAssert (FALSE);
  1310. break;
  1311. }
  1312. }
  1313. }
  1314. #endif
  1315. RES_HDL_TBL *
  1316. GetHandlerTableEntry ( ULONG uNotifyMsg )
  1317. {
  1318. ULONG nIndex = uNotifyMsg - WM_ILS_ASYNC_RES;
  1319. if (nIndex > WM_ILS_LAST_ONE)
  1320. {
  1321. MyAssert (FALSE);
  1322. return NULL;
  1323. }
  1324. return &g_ResHdlTbl[nIndex];
  1325. }
  1326. RESPONSE_HANDLER *
  1327. GetResponseHandler ( ULONG uNotifyMsg )
  1328. {
  1329. RES_HDL_TBL *p = GetHandlerTableEntry (uNotifyMsg);
  1330. return ((p != NULL) ? p->pfnRespHdl : NULL);
  1331. }
  1332. REQUEST_HANDLER *
  1333. GetRequestHandler ( ULONG uNotifyMsg )
  1334. {
  1335. RES_HDL_TBL *p = GetHandlerTableEntry (uNotifyMsg);
  1336. return ((p != NULL) ? p->pfnReqHdl : NULL);
  1337. }
  1338.