Source code of Windows XP (NT5)
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.

984 lines
27 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name:
  4. OrClnt.cxx
  5. Abstract:
  6. Object resolver client side class implementations. CClientOxid, CClientOid,
  7. CClientSet classes are implemented here.
  8. Author:
  9. Mario Goertzel [MarioGo]
  10. Revision History:
  11. MarioGo 04-03-95 Combined many smaller .cxx files
  12. MarioGo 01-05-96 Locally unique IDs
  13. --*/
  14. #include<or.hxx>
  15. extern
  16. error_status_t
  17. ComplexPingInternal(
  18. IN handle_t hRpc,
  19. IN SETID *pSetId,
  20. IN USHORT SequenceNum,
  21. IN ULONG cAddToSet,
  22. IN ULONG cDelFromSet,
  23. IN OID AddToSet[],
  24. IN OID DelFromSet[],
  25. OUT USHORT *pPingBackoffFactor
  26. );
  27. class CTestBindingPPing : public CParallelPing
  28. {
  29. public:
  30. CTestBindingPPing(WCHAR *pBindings) :
  31. _pBindings(pBindings)
  32. {}
  33. BOOL NextCall(PROTSEQINFO *pProtseqInfo)
  34. {
  35. if (*_pBindings)
  36. {
  37. pProtseqInfo->pvUserInfo = _pBindings;
  38. pProtseqInfo->hRpc = TestBindingGetHandle(_pBindings);
  39. _pBindings = OrStringSearch(_pBindings, 0) + 1;
  40. return TRUE;
  41. }
  42. else
  43. {
  44. return FALSE;
  45. }
  46. }
  47. void ReleaseCall(PROTSEQINFO *pProtseqInfo)
  48. {
  49. if (pProtseqInfo->hRpc)
  50. {
  51. RpcBindingFree(&pProtseqInfo->hRpc);
  52. }
  53. }
  54. private:
  55. WCHAR * _pBindings;
  56. };
  57. //
  58. // CClientOid methods
  59. //
  60. CClientOid::~CClientOid()
  61. {
  62. ASSERT(gpClientLock->HeldExclusive());
  63. ASSERT(!In());
  64. ASSERT(Out());
  65. ASSERT(_pOxid);
  66. ASSERT(_pSet);
  67. _pOxid->Release();
  68. _pSet->Release();
  69. gpClientOidTable->Remove(this);
  70. }
  71. //
  72. // CClientOxid methods.
  73. //
  74. ORSTATUS
  75. CClientOxid::GetInfo(
  76. IN BOOL fApartment,
  77. OUT OXID_INFO *pInfo
  78. )
  79. /*++
  80. Routine Description:
  81. Returns the OXID_INFO structure for this oxid.
  82. The gpClientLock is held and there should also be
  83. a reference held by the calling routine upon entry to
  84. this method.
  85. Arguments:
  86. fApartment - TRUE iif the client is apartment model.
  87. pInfo - Will contain the standard info, a single _expanded_
  88. string binding and complete security bindings.
  89. MIDL_user_allocated.
  90. Return Value:
  91. OR_NOMEM - Unable to allocate a parameter.
  92. OR_OK - Normally.
  93. --*/
  94. {
  95. USHORT protseq;
  96. PWSTR pwstrT;
  97. ORSTATUS status = OR_OK;
  98. DUALSTRINGARRAY *psa;
  99. ASSERT(dsaValid(_oxidInfo.psa));
  100. if (0 == _wProtseq)
  101. {
  102. // Local server
  103. protseq = ID_LPC;
  104. pwstrT = FindMatchingProtseq(protseq, _oxidInfo.psa->aStringArray);
  105. ASSERT(pwstrT != 0);
  106. if (0 != pwstrT)
  107. {
  108. psa =
  109. GetStringBinding(pwstrT,
  110. _oxidInfo.psa->aStringArray + _oxidInfo.psa->wSecurityOffset);
  111. if (0 == psa)
  112. {
  113. status = OR_NOMEM;
  114. }
  115. }
  116. else
  117. {
  118. status = OR_BADOXID;
  119. }
  120. }
  121. else
  122. {
  123. // Remote server, find a string binding to use.
  124. psa = 0;
  125. PWSTR pwstrBinding = 0;
  126. // First, check if there is a known good binding to use.
  127. if (_iStringBinding != 0xFFFF)
  128. {
  129. pwstrBinding = &_oxidInfo.psa->aStringArray[_iStringBinding];
  130. }
  131. else
  132. {
  133. pwstrT = NULL;
  134. if (_pMachineName)
  135. {
  136. pwstrT = FindMatchingProtseq(_pMachineName,
  137. _wProtseq,
  138. _oxidInfo.psa->aStringArray);
  139. }
  140. if (pwstrT)
  141. {
  142. pwstrBinding = pwstrT;
  143. _iStringBinding = (USHORT)(pwstrT - _oxidInfo.psa->aStringArray);
  144. }
  145. else
  146. {
  147. // no stringbinding for the Protseq and machine name we succeeded on
  148. // previously. Ping all these guys in parallel and see if any work
  149. CTestBindingPPing ping(_oxidInfo.psa->aStringArray);
  150. gpClientLock->UnlockExclusive();
  151. RPC_STATUS status = ping.Ping();
  152. gpClientLock->LockExclusive();
  153. if (status == RPC_S_OK)
  154. {
  155. pwstrBinding = (WCHAR*) ping.GetWinner()->pvUserInfo;
  156. _iStringBinding = (USHORT)(pwstrBinding - _oxidInfo.psa->aStringArray);
  157. }
  158. ping.Reset();
  159. }
  160. }
  161. if (0 != pwstrBinding)
  162. {
  163. // Found a binding
  164. ASSERT(pwstrBinding == &_oxidInfo.psa->aStringArray[_iStringBinding]);
  165. psa = GetStringBinding(pwstrBinding,
  166. _oxidInfo.psa->aStringArray + _oxidInfo.psa->wSecurityOffset);
  167. if (0 == psa)
  168. {
  169. status = OR_NOMEM;
  170. }
  171. }
  172. else
  173. {
  174. KdPrintEx((DPFLTR_DCOMSS_ID,
  175. DPFLTR_WARNING_LEVEL,
  176. "OR: Unable to find a binding for oxid %p (to %S)\n",
  177. this,
  178. _oxidInfo.psa->aStringArray + 1));
  179. if (status == OR_OK)
  180. status = OR_BADOXID;
  181. }
  182. }
  183. if (status == OR_OK)
  184. {
  185. // copy all the data into the OXID_INFO
  186. memcpy(pInfo, &_oxidInfo, sizeof(_oxidInfo));
  187. pInfo->psa = psa;
  188. }
  189. return(status);
  190. }
  191. ORSTATUS
  192. CClientOxid::UpdateInfo(OXID_INFO *pInfo)
  193. {
  194. DUALSTRINGARRAY *pdsaT;
  195. ASSERT(pInfo);
  196. ASSERT(gpClientLock->HeldExclusive());
  197. if (pInfo->psa)
  198. {
  199. ASSERT(dsaValid(pInfo->psa));
  200. pdsaT = new(sizeof(USHORT) * pInfo->psa->wNumEntries) DUALSTRINGARRAY;
  201. if (!pdsaT)
  202. {
  203. return(OR_NOMEM);
  204. }
  205. dsaCopy(pdsaT, pInfo->psa);
  206. delete _oxidInfo.psa;
  207. }
  208. else
  209. {
  210. pdsaT = _oxidInfo.psa;
  211. }
  212. // copy in the new data
  213. memcpy(&_oxidInfo, pInfo, sizeof(_oxidInfo));
  214. _oxidInfo.psa = pdsaT;
  215. ASSERT(dsaValid(_oxidInfo.psa));
  216. return(OR_OK);
  217. }
  218. void
  219. CClientOxid::Reference()
  220. /*++
  221. Routine Description:
  222. As as CReferencedObject::Reference except that it knows to
  223. pull the oxid out of the plist when the refcount was 0.
  224. Arguments:
  225. None
  226. Return Value:
  227. None
  228. --*/
  229. {
  230. BOOL fRemove = (this->References() == 0);
  231. // We may remove something from a PList more then once;
  232. // it won't hurt anything. This avoids trying to remove
  233. // more often then necessary.
  234. this->CReferencedObject::Reference();
  235. if (fRemove)
  236. {
  237. CPListElement * t = Remove();
  238. ASSERT(t == &this->_plist || t == 0);
  239. }
  240. }
  241. DWORD
  242. CClientOxid::Release()
  243. /*++
  244. Routine Description:
  245. Overrides CReferencedObject::Release since OXIDs must wait for
  246. a timeout period before being deleted.
  247. Arguments:
  248. None
  249. Return Value:
  250. 0 - object fully released.
  251. non-zero - object nt fully released by you.
  252. --*/
  253. {
  254. ASSERT(gpClientLock->HeldExclusive());
  255. LONG c = CReferencedObject::Dereference();
  256. if (c == 0)
  257. {
  258. Insert();
  259. }
  260. ASSERT(c >= 0);
  261. return(c);
  262. }
  263. //
  264. // CClientSet methods
  265. //
  266. ORSTATUS
  267. CClientSet::RegisterObject(CClientOid *pOid)
  268. /*++
  269. Routine Description:
  270. Adds a new oid to the set of oids owned by this set.
  271. Arguments:
  272. pOid - A pointer to the OID to add to the set. The caller gives
  273. his reference to this set.
  274. Return Value:
  275. None
  276. --*/
  277. {
  278. ORSTATUS status;
  279. ASSERT(gpClientLock->HeldExclusive());
  280. ASSERT(_blistOids.Member(pOid) == FALSE);
  281. status = _blistOids.Insert(pOid);
  282. if (status == OR_OK)
  283. {
  284. ObjectUpdate(pOid);
  285. _cFailedPings = 0;
  286. }
  287. VALIDATE((status, OR_NOMEM, 0));
  288. return(status);
  289. }
  290. ORSTATUS
  291. CClientSet::PingServer()
  292. /*++
  293. Routine Description:
  294. Performs a nice simple ping of the remote set.
  295. Note:
  296. Exactly and only one thread may call this method on
  297. a given instance of a CClientSet at a time.
  298. No lock held when called.
  299. Overview of state transitions on a CClientOid during
  300. a complex ping:
  301. In() Out() Actions before ping; after ping
  302. FALSE FALSE A ; C A U
  303. FALSE TRUE R ; R U
  304. TRUE FALSE N ; N
  305. TRUE TRUE R ; C R U
  306. Before:
  307. A - Added to list of IDs to be added.
  308. N - Ignored
  309. R - Added to list of IDs to be removed.
  310. // States may change during the call.
  311. After:
  312. C - Check if ping call was successful. If not, skip next action.
  313. R - If the Out() state is still TRUE, remove it.
  314. N - ignored
  315. A - Set In() state to TRUE
  316. U - If Out() state changed during the call, set _fChange.
  317. If three pings fail in a row, all Out()==TRUE OIDs are
  318. actually Released() and no new pings are made until ObjectUpdate()
  319. is called again.
  320. Arguments:
  321. None
  322. Return Value:
  323. OR_OK - Pinged okay
  324. OR_NOMEM - Resource allocation failed
  325. OR_I_PARTIAL_UPDATE - Pinged okay, but more pings
  326. are needed to fully update the remote set.
  327. Other - Error from RPC.
  328. --*/
  329. {
  330. ORSTATUS status;
  331. ULONG cAdds = 0;
  332. ULONG cDels = 0;
  333. ULONG i;
  334. WCHAR* pPrincipal = NULL;
  335. WCHAR* pMachineNameFromBindings = NULL;
  336. #ifndef _CHICAGO_
  337. CToken *pToken;
  338. if (_fSecure)
  339. {
  340. pToken = (CToken *)Id2();
  341. ASSERT(pToken != 0);
  342. pToken->Impersonate();
  343. }
  344. #endif
  345. if (_fChange)
  346. {
  347. USHORT wBackoffFactor;
  348. OID *aAdds = 0;
  349. OID *aDels = 0;
  350. CClientOid **apoidAdds;
  351. CClientOid **apoidDels = 0;
  352. CClientOid *pOid;
  353. gpClientLock->LockShared();
  354. // Since we own a shared lock, nobody can modify the contents
  355. // of the set or change the references on an OID in the set
  356. // while we do this calculation.
  357. ASSERT(_fChange);
  358. _fChange = FALSE;
  359. DWORD debugSize = _blistOids.Size();
  360. ASSERT(debugSize);
  361. CBListIterator oids(&_blistOids);
  362. while (pOid = (CClientOid *)oids.Next())
  363. {
  364. if (pOid->Out() == FALSE)
  365. {
  366. if (pOid->In() == FALSE)
  367. {
  368. // Referenced and not in set, add it.
  369. cAdds++;
  370. }
  371. }
  372. else
  373. {
  374. // Not referenced, remove it.
  375. cDels++;
  376. }
  377. }
  378. ASSERT(debugSize == _blistOids.Size());
  379. oids.Reset(&_blistOids);
  380. DWORD cbAlloc = (sizeof(OID) * (cAdds + cDels)) +
  381. (sizeof(CClientOid*) * (cAdds + cDels));
  382. PVOID pvMem;
  383. // Alloc no more than 16k on the stack.
  384. if (cbAlloc < 0x4000)
  385. {
  386. pvMem = NULL;
  387. aAdds = (OID *) alloca(cbAlloc);
  388. }
  389. else
  390. {
  391. pvMem = PrivMemAlloc(cbAlloc);
  392. aAdds = (OID *) pvMem;
  393. }
  394. if (!aAdds)
  395. {
  396. gpClientLock->UnlockShared();
  397. if (_fSecure)
  398. {
  399. pToken = (CToken *)Id2();
  400. ASSERT(pToken != 0);
  401. pToken->Revert();
  402. }
  403. return OR_NOMEM;
  404. }
  405. apoidAdds = (CClientOid **) ( aAdds + cAdds);
  406. aDels = (OID *)( apoidAdds + cAdds);
  407. apoidDels = (CClientOid **)(aDels + cDels);
  408. DWORD debugAdds = cAdds;
  409. DWORD debugDels = cDels;
  410. cAdds = cDels = 0;
  411. while (pOid = (CClientOid *)oids.Next())
  412. {
  413. if (pOid->Out() == FALSE)
  414. {
  415. if (pOid->In() == FALSE)
  416. {
  417. // Referenced and not yet added
  418. aAdds[cAdds] = pOid->Id();
  419. apoidAdds[cAdds] = pOid;
  420. cAdds++;
  421. }
  422. }
  423. else
  424. {
  425. aDels[cDels] = pOid->Id();
  426. apoidDels[cDels] = pOid;
  427. cDels++;
  428. }
  429. }
  430. ASSERT(debugSize == _blistOids.Size());
  431. ASSERT(debugAdds == cAdds);
  432. ASSERT(debugDels == cDels);
  433. gpClientLock->UnlockShared();
  434. KdPrintEx((DPFLTR_DCOMSS_ID,
  435. DPFLTR_INFO_LEVEL,
  436. "OR: Pinging set %p on %S, (%d, %d)\n",
  437. this,
  438. _pMid->PrintableName(),
  439. cAdds,
  440. cDels));
  441. // Allocate a connection if needed
  442. if ( FALSE == _pMid->IsLocal()
  443. && 0 == _hServer )
  444. {
  445. _hServer = _pMid->GetBinding();
  446. if (!_hServer)
  447. {
  448. _iBinding = 0;
  449. status = OR_NOMEM;
  450. }
  451. else
  452. {
  453. if (_pMid->IsSecure())
  454. {
  455. // set security on the binding handle.
  456. _fSecure = TRUE;
  457. RPC_SECURITY_QOS qos;
  458. pMachineNameFromBindings = ExtractMachineName( _pMid->GetStringBinding() );
  459. if (pMachineNameFromBindings)
  460. {
  461. pPrincipal = new WCHAR[lstrlenW(pMachineNameFromBindings) +
  462. (sizeof(RPCSS_SPN_PREFIX) / sizeof(WCHAR)) + 1];
  463. if (pPrincipal)
  464. {
  465. lstrcpyW(pPrincipal, RPCSS_SPN_PREFIX);
  466. lstrcatW(pPrincipal, pMachineNameFromBindings);
  467. }
  468. delete pMachineNameFromBindings;
  469. }
  470. USHORT wAuthnSvc = _pMid->GetAuthnSvc();
  471. if (wAuthnSvc == RPC_C_AUTHN_GSS_NEGOTIATE)
  472. _pAuthIdentity = (COAUTHIDENTITY*) ComputeSvcList( _pMid->GetStrings() );
  473. if ( (wAuthnSvc == RPC_C_AUTHN_GSS_NEGOTIATE) && !_pAuthIdentity)
  474. {
  475. _fSecure = FALSE;
  476. status = OR_NOMEM;
  477. }
  478. else
  479. {
  480. qos.Version = RPC_C_SECURITY_QOS_VERSION;
  481. qos.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT;
  482. qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  483. qos.ImpersonationType = RPC_C_IMP_LEVEL_IDENTIFY;
  484. // AuthnSvc is unsigned long and 0xFFFF will get 0 extended
  485. status = RpcBindingSetAuthInfoEx(_hServer,
  486. pPrincipal,
  487. RPC_C_AUTHN_LEVEL_CONNECT,
  488. wAuthnSvc != 0xFFFF ? wAuthnSvc
  489. : RPC_C_AUTHN_DEFAULT,
  490. _pAuthIdentity,
  491. 0,
  492. &qos);
  493. if (status != RPC_S_OK)
  494. _fSecure = FALSE;
  495. }
  496. delete pPrincipal;
  497. }
  498. else
  499. {
  500. _fSecure = FALSE;
  501. status = OR_OK;
  502. }
  503. }
  504. }
  505. else
  506. {
  507. status = OR_OK;
  508. }
  509. if (OR_OK == status)
  510. {
  511. if (_pMid->IsLocal())
  512. {
  513. // For local pings, do it all in one call.
  514. for (;;)
  515. {
  516. _sequence++;
  517. status = ComplexPingInternal(
  518. _hServer,
  519. &_setid,
  520. _sequence,
  521. cAdds,
  522. cDels,
  523. aAdds,
  524. aDels,
  525. &wBackoffFactor
  526. );
  527. if (status == OR_BADSET)
  528. {
  529. // Restart loop, allocating new set
  530. ASSERT(_setid);
  531. _sequence = 0;
  532. _setid = 0;
  533. continue;
  534. }
  535. else if (status == OR_BADOID)
  536. {
  537. // This is really okay, all Dels must be deleted,
  538. // and if the add failed now, it will always fail.
  539. KdPrintEx((DPFLTR_DCOMSS_ID,
  540. DPFLTR_WARNING_LEVEL,
  541. "OR: Client specified unknown OID(s). %p %p %p\n",
  542. this,
  543. aAdds,
  544. apoidAdds));
  545. status = OR_OK;
  546. }
  547. break;
  548. }
  549. }
  550. else
  551. {
  552. //
  553. // _ComplexPing is typed as taking USHORT's for the count of Adds and
  554. // Dels -- astoundingly there are people in the world who seem to be
  555. // using more object references than a USHORT can hold. Rather than
  556. // changing the protocol, we separate the adds\dels into USHRT_MAX
  557. // size chunks.
  558. //
  559. // However, this is not necessary for local pings, which is why that case
  560. // is handled separately above.
  561. //
  562. const ULONG MAX_PING_CHUNK_SIZE = USHRT_MAX;
  563. ULONG cAddsTotal = 0;
  564. ULONG cDelsTotal = 0;
  565. ULONG cCallsNeeded;
  566. cCallsNeeded = max((ULONG)ceil((double)cAdds / (double)MAX_PING_CHUNK_SIZE),
  567. (ULONG)ceil((double)cDels / (double)MAX_PING_CHUNK_SIZE));
  568. // Loop the necessary # of times. Certain conditions can cause us
  569. // re-start the loop, eg security errors, or bad set errors.
  570. for (i = 0; i < cCallsNeeded; i++)
  571. {
  572. // Figure out how many adds\dels we are doing on this
  573. // iteration. Remember that the # of adds\dels are
  574. // independent of each other.
  575. USHORT cAddsPerCall;
  576. USHORT cDelsPerCall;
  577. OID* pAddsPerCall;
  578. OID* pDelsPerCall;
  579. if (cAddsTotal < cAdds)
  580. {
  581. // More adds to do.
  582. cAddsPerCall = (USHORT)(min(cAdds - (i * MAX_PING_CHUNK_SIZE),
  583. MAX_PING_CHUNK_SIZE));
  584. }
  585. else
  586. cAddsPerCall = 0; // done with adds
  587. if (cDelsTotal < cDels)
  588. {
  589. // More dels to do.
  590. cDelsPerCall = (USHORT)(min(cDels - (i * MAX_PING_CHUNK_SIZE),
  591. MAX_PING_CHUNK_SIZE));
  592. }
  593. else
  594. cDelsPerCall = 0; // done with dels
  595. // Setup pointers
  596. pAddsPerCall = (cAddsPerCall > 0) ?
  597. aAdds + (i * MAX_PING_CHUNK_SIZE) : NULL;
  598. pDelsPerCall = (cDelsPerCall > 0) ?
  599. aDels + (i * MAX_PING_CHUNK_SIZE) : NULL;
  600. ASSERT(_hServer);
  601. ASSERT((cAddsPerCall > 0) || (cDelsPerCall > 0));
  602. ASSERT(pAddsPerCall || pDelsPerCall);
  603. // Update totals
  604. cAddsTotal += cAddsPerCall;
  605. cDelsTotal += cDelsPerCall;
  606. _sequence++;
  607. status = ComplexPing(
  608. _hServer,
  609. &_setid,
  610. _sequence,
  611. cAddsPerCall,
  612. cDelsPerCall,
  613. pAddsPerCall,
  614. pDelsPerCall,
  615. &wBackoffFactor
  616. );
  617. if (status == OR_OK)
  618. {
  619. // Keep going -- might have more chunks to process
  620. }
  621. else if (status == OR_BADOID)
  622. {
  623. // This is really okay, all Dels must be deleted,
  624. // and if the add failed now, it will always fail.
  625. KdPrintEx((DPFLTR_DCOMSS_ID,
  626. DPFLTR_WARNING_LEVEL,
  627. "OR: Client specified unknown OID(s). %p %p %p\n",
  628. this,
  629. aAdds,
  630. apoidAdds));
  631. status = OR_OK;
  632. }
  633. else if (status == OR_NOMEM
  634. || status == RPC_S_OUT_OF_RESOURCES
  635. || status == RPC_S_SERVER_TOO_BUSY)
  636. {
  637. // On these errors we quit immediately. No retry attempts
  638. // even if there are further chunks to process.
  639. break;
  640. }
  641. else if (status == RPC_S_ACCESS_DENIED ||
  642. status == RPC_S_SEC_PKG_ERROR)
  643. {
  644. _fSecure = FALSE;
  645. status = RpcBindingSetAuthInfo(_hServer,
  646. 0,
  647. RPC_C_AUTHN_LEVEL_NONE,
  648. RPC_C_AUTHN_NONE,
  649. 0,
  650. 0);
  651. if (status == RPC_S_OK)
  652. {
  653. // Restart loop using unsecure calls
  654. i = -1; // restart loop from beginning
  655. cAddsTotal = 0;
  656. cDelsTotal = 0;
  657. }
  658. }
  659. else if (status == OR_BADSET)
  660. {
  661. // Set invalid; reallocate (don't free the binding).
  662. ASSERT(_setid);
  663. KdPrintEx((DPFLTR_DCOMSS_ID,
  664. DPFLTR_WARNING_LEVEL,
  665. "OR: Set %p invalid; recreating..\n",
  666. this));
  667. _setid = 0;
  668. _sequence = 0;
  669. cAddsTotal = 0;
  670. cDelsTotal = 0;
  671. i = -1; // reset loop
  672. }
  673. else
  674. {
  675. // Assume communication failure, free binding, and exit the
  676. // loop (we'll re-allocate a new binding on the next ping)
  677. RPC_STATUS mystatus = RpcBindingFree(&_hServer);
  678. ASSERT(mystatus == RPC_S_OK && _hServer == 0);
  679. _sequence--;
  680. break;
  681. }
  682. }
  683. }
  684. }
  685. pToken->Revert();
  686. gpClientLock->LockExclusive();
  687. this->Reference(); // Keep set alive until we finish
  688. if (status == OR_OK)
  689. {
  690. // Success, process the adds
  691. for (i = 0; i < cAdds; i++)
  692. {
  693. pOid = apoidAdds[i];
  694. pOid->Added();
  695. if (FALSE != pOid->Out())
  696. {
  697. // NOT referenced now, make sure it gets deleted next period.
  698. ObjectUpdate(pOid);
  699. }
  700. }
  701. // Process deletes.
  702. for (i = 0; i < cDels; i++)
  703. {
  704. pOid = apoidDels[i];
  705. pOid->Deleted();
  706. if (FALSE != pOid->Out())
  707. {
  708. // Well what do you yah know, we can _finally_ delete an oid.
  709. CClientOid *pT = (CClientOid *)_blistOids.Remove(pOid);
  710. ASSERT(pT == pOid);
  711. DWORD t = pOid->Release();
  712. ASSERT(t == 0);
  713. }
  714. else
  715. {
  716. // We deleted from the set but now somebody is referencing it.
  717. // Make sure we re-add it next time.
  718. ObjectUpdate(pOid);
  719. }
  720. }
  721. _cFailedPings = 0;
  722. }
  723. else
  724. {
  725. _fChange = TRUE;
  726. }
  727. DWORD c = this->Release();
  728. if (c)
  729. {
  730. ASSERT(_blistOids.Size());
  731. this->Insert();
  732. }
  733. else
  734. {
  735. ASSERT(cAdds == 0 && cDels != 0);
  736. }
  737. // Set (this) pointer maybe invalid
  738. gpClientLock->UnlockExclusive();
  739. if (pvMem)
  740. PrivMemFree(pvMem);
  741. }
  742. else
  743. {
  744. KdPrintEx((DPFLTR_DCOMSS_ID,
  745. DPFLTR_INFO_LEVEL,
  746. "OR: Pinging set %p on %S.\n",
  747. this,
  748. _pMid->PrintableName()));
  749. ASSERT(_setid != 0);
  750. if (_pMid->IsLocal())
  751. {
  752. ASSERT(_cFailedPings == 0);
  753. ASSERT(_hServer == 0);
  754. status = _SimplePing(0, &_setid);
  755. ASSERT(status == OR_OK);
  756. }
  757. else
  758. {
  759. ASSERT(_hServer);
  760. if (_cFailedPings <= 3)
  761. {
  762. status = SimplePing(_hServer, &_setid);
  763. if (status != OR_OK)
  764. {
  765. _cFailedPings++;
  766. if (_cFailedPings > 3)
  767. {
  768. KdPrintEx((DPFLTR_DCOMSS_ID,
  769. DPFLTR_WARNING_LEVEL,
  770. "OR: Server %S (set %p) has failed 3 pings...\n",
  771. _pMid->PrintableName(),
  772. this));
  773. }
  774. }
  775. else
  776. {
  777. _cFailedPings = 0;
  778. }
  779. }
  780. else
  781. {
  782. status = OR_OK;
  783. }
  784. }
  785. this->Insert();
  786. pToken->Revert();
  787. }
  788. // Set (this) maybe invalid.
  789. #if DBG
  790. if (status != OR_OK)
  791. {
  792. KdPrintEx((DPFLTR_DCOMSS_ID,
  793. DPFLTR_WARNING_LEVEL,
  794. "OR: ping %p failed %d\n",
  795. this,
  796. status));
  797. }
  798. #endif
  799. return(status);
  800. }