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.

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