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.

2036 lines
49 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. Process.cxx
  5. Abstract:
  6. Process objects represent local clients and servers. These
  7. objects live as context handles.
  8. There are relatively few of these objects in the universe.
  9. Author:
  10. Mario Goertzel [MarioGo]
  11. Revision History:
  12. MarioGo 02-20-95 Bits 'n pieces
  13. Ronans 20-02-97 UseProtseqIfNeeded modified for custom endpoints
  14. Ronans 20-02-97 Added custom endpoints stuff to process object
  15. TarunA 09-Nov-98 Added process handle
  16. --*/
  17. #include <or.hxx>
  18. CRITICAL_SECTION gcsFastProcessLock;
  19. extern HRESULT FreeSPIFromCProcess(void** ppSCMProcessInfo);
  20. const DWORD BINDINGUPDATESTUFF_SIG = 0xFEDCBA01;
  21. typedef struct _BINDINGS_UPDATE_CALLBACK_STUFF
  22. {
  23. DWORD dwSig; // see BINDINGUPDATESTUFF_SIG above
  24. // housekeeping stuff
  25. CProcess* pProcess; // has reference while call is in-flight
  26. RPC_BINDING_HANDLE hBinding;
  27. RPC_ASYNC_STATE async;
  28. // out and in-out params
  29. DWORD64 dwBindingsID;
  30. DUALSTRINGARRAY* pdsaNewBindings;
  31. DUALSTRINGARRAY* pdsaNewSecurity;
  32. } BINDINGS_UPDATE_CALLBACK_STUFF;
  33. const DWORD ASYNCRUNDOWNOID_SIG = 0xFEDCBA02;
  34. typedef struct _ASYNCRUNDOWNOID_STUFF
  35. {
  36. DWORD dwSig; // see ASYNCRUNDOWNOID_SIG above
  37. // housekeeping stuff
  38. CProcess* pProcess; // has reference while call is in-flight
  39. CServerOxid* pOxid; // has reference while call is in-flight
  40. RPC_BINDING_HANDLE hBinding;
  41. RPC_ASYNC_STATE async;
  42. // We keep these for when we process the return
  43. ULONG cOids;
  44. CServerOid* aOids[MAX_OID_RUNDOWNS_PER_CALL];
  45. // The ORPC params are reference pointers, so they must
  46. // stay alive for the life of the call
  47. ORPCTHIS orpcthis;
  48. LOCALTHIS localthis;
  49. ORPCTHAT orpcthat;
  50. INT callIDHint; // need to free this on return
  51. // in-out or out params.
  52. BYTE aRundownStatus[MAX_OID_RUNDOWNS_PER_CALL];
  53. } ASYNCRUNDOWNOID_STUFF;
  54. void
  55. CProcess::Rundown()
  56. /*++
  57. Routine Description:
  58. The client process has rundown. This means there are no more
  59. client refernces which means we are free to clean things up
  60. as long as server OXIDs still holding references won't get
  61. upset. They all use the server lock when accessing the process.
  62. Arguments:
  63. None
  64. Return Value:
  65. None
  66. --*/
  67. {
  68. ORSTATUS status;
  69. gpServerLock->LockExclusive();
  70. ASSERT(_cClientReferences == 0);
  71. KdPrintEx((DPFLTR_DCOMSS_ID,
  72. DPFLTR_INFO_LEVEL,
  73. "OR: Rundown of %p: %d oxids, %d oids and %d roxids left\n",
  74. this,
  75. _blistOxids.Size(),
  76. _blistOids.Size()));
  77. // Release any OXIDs owned by this process. This may destroy the OXID.
  78. // This will release this CProcess, but won't release the last reference as
  79. // the client process still owns one.
  80. if (_blistOxids.Size())
  81. {
  82. CServerOxid *poxid;
  83. CBListIterator oxids(&_blistOxids);
  84. while (poxid = (CServerOxid *)oxids.Next())
  85. {
  86. gpServerOxidTable->Remove(poxid);
  87. poxid->ProcessRelease();
  88. }
  89. }
  90. // Release any OIDs is use by this processes.
  91. // Do this now, rather then waiting for the last server oid
  92. // owned by this process to get invalidated and rundown.
  93. gpClientLock->LockExclusive();
  94. // *** Both client and server lock held here. ***
  95. if (_blistOids.Size())
  96. {
  97. CClientOid *poid;
  98. CBListIterator oids(&_blistOids);
  99. while (poid = (CClientOid *)oids.Next())
  100. {
  101. ASSERT(NULL != poid->GetClientOxid());
  102. poid->GetClientOxid()->Release();
  103. poid->ClientRelease();
  104. }
  105. }
  106. // Cleanup other process state. Note: it is important that the
  107. // release of the process and token handle never happen any later
  108. // than rundown time. If the process handle is released any later, you
  109. // will see bugs like "can't recompile my com server" after they run
  110. // it once. If the token handle is released any later, you will get
  111. // security bugs from the NT security folks since we will hold onto
  112. // the logged-on user's token until many minutes after logoff.
  113. //
  114. // Ask me how I know this...
  115. //
  116. if (_hProcHandle)
  117. {
  118. CloseHandle(_hProcHandle);
  119. _hProcHandle = NULL;
  120. }
  121. if (_pToken)
  122. {
  123. _pToken->Release();
  124. _pToken = 0;
  125. }
  126. // Free the cached SCMProcessInfo if we have one
  127. FreeSPIFromCProcess(&_pSCMProcessInfo);
  128. // Flip the rundown and dirty bit
  129. _dwFlags |= (PROCESS_RUNDOWN & PROCESS_SPI_DIRTY);
  130. gpClientLock->UnlockExclusive();
  131. // Done, release the clients' reference, this may actually delete this
  132. // process. (If an OXID still exists and has OIDs it will not be deleted
  133. // until the OIDs all rundown).
  134. this->Release();
  135. // The this pointer maybe invalid now.
  136. gpServerLock->UnlockExclusive();
  137. }
  138. CProcess::CProcess(
  139. IN CToken*& pToken,
  140. IN WCHAR *pwszWinstaDesktop,
  141. IN DWORD procID,
  142. IN DWORD dwFlags,
  143. OUT ORSTATUS &status
  144. ) :
  145. _blistOxids(4),
  146. _blistOids(16),
  147. _listClasses()
  148. /*++
  149. Routine Description:
  150. Initalized a process object, members and add it to the
  151. process list.
  152. Arguments:
  153. pToken - The clients token. We assume we have a reference.
  154. pwszWinstaDesktop - The client's windowstation/desktop string.
  155. procID - The client's process ID.
  156. status - Sometimes the C'tor can fail with OR_NOMEM.
  157. Return Value:
  158. None
  159. --*/
  160. {
  161. _cClientReferences = 1;
  162. _hProcess = NULL;
  163. _fCacheFree = FALSE;
  164. _pdsaLocalBindings = NULL;
  165. _pdsaRemoteBindings = NULL;
  166. _pToken = NULL;
  167. _pwszWinstaDesktop = NULL;
  168. _pScmProcessReg = NULL;
  169. _pvRunAsHandle = NULL;
  170. _procID = 0;
  171. _fLockValid = FALSE;
  172. _hProcHandle = NULL;
  173. _dwFlags = PROCESS_SPI_DIRTY; // always start out dirty
  174. _pSCMProcessInfo = NULL;
  175. _ulClasses = 0;
  176. _dwCurrentBindingsID = 0;
  177. _dwAsyncUpdatesOutstanding = 0;
  178. // Set 64 bit flag if so indicated
  179. if (dwFlags & CONNECT_FLAGS_64BIT)
  180. _dwFlags |= PROCESS_64BIT;
  181. // Store time of object creation. Note that this is in UTC time.
  182. GetSystemTimeAsFileTime(&_ftCreated);
  183. // Generate a unique guid to represent this process
  184. UuidCreate(&_guidProcessIdentifier);
  185. // ronans - entries for custom protseqs from server
  186. // not used for clients
  187. _fReadCustomProtseqs = FALSE;
  188. _pdsaCustomProtseqs = NULL;
  189. status = OR_OK;
  190. if ( pwszWinstaDesktop == NULL )
  191. {
  192. status = OR_BADPARAM;
  193. }
  194. if (status == OR_OK)
  195. {
  196. status = RtlInitializeCriticalSection(&_csCallbackLock);
  197. _fLockValid = (status == STATUS_SUCCESS);
  198. }
  199. if (status == STATUS_SUCCESS)
  200. {
  201. gpProcessListLock->LockExclusive();
  202. status = gpProcessList->Insert(this);
  203. gpProcessListLock->UnlockExclusive();
  204. }
  205. if (status == OR_OK)
  206. {
  207. _pwszWinstaDesktop = new WCHAR[OrStringLen(pwszWinstaDesktop)+1];
  208. if (! _pwszWinstaDesktop)
  209. status = OR_NOMEM;
  210. else
  211. OrStringCopy(_pwszWinstaDesktop, pwszWinstaDesktop);
  212. }
  213. if (status == OR_OK)
  214. {
  215. _pToken = pToken;
  216. pToken = NULL; // We've taken the token
  217. }
  218. _procID = procID;
  219. #if DBG
  220. _cRundowns = 0;
  221. #endif
  222. }
  223. CProcess::~CProcess(void)
  224. // You probably should be looking in the ::Rundown method.
  225. // This process object stays alive until the last server oxid dies.
  226. {
  227. ASSERT(gpServerLock->HeldExclusive());
  228. ASSERT(_hProcHandle == 0);
  229. ASSERT(_pSCMProcessInfo == 0);
  230. delete _pdsaLocalBindings;
  231. delete _pdsaRemoteBindings;
  232. MIDL_user_free( _pdsaCustomProtseqs );
  233. delete _pwszWinstaDesktop;
  234. if (_fLockValid)
  235. DeleteCriticalSection(&_csCallbackLock);
  236. if (_hProcess)
  237. {
  238. RPC_STATUS status = RpcBindingFree(&_hProcess);
  239. ASSERT(status == RPC_S_OK);
  240. ASSERT(_hProcess == 0);
  241. }
  242. #ifndef _CHICAGO_
  243. extern void RunAsRelease(void*);
  244. RunAsRelease(_pvRunAsHandle);
  245. #endif // _CHICAGO_
  246. return;
  247. }
  248. //
  249. // SetSCMProcessInfo
  250. //
  251. // Swaps our old cached SCMProcessInfo* for a new one.
  252. //
  253. HRESULT CProcess::SetSCMProcessInfo(void* pSPI)
  254. {
  255. ASSERT(gpServerLock->HeldExclusive());
  256. ASSERT(!(_dwFlags & PROCESS_RUNDOWN));
  257. if (_dwFlags & PROCESS_RUNDOWN)
  258. return E_UNEXPECTED;
  259. FreeSPIFromCProcess(&_pSCMProcessInfo);
  260. // set the new one
  261. _pSCMProcessInfo = pSPI;
  262. // this means we're no longer dirty
  263. _dwFlags &= ~PROCESS_SPI_DIRTY;
  264. return S_OK;
  265. }
  266. void CProcess::SetProcessReadyState(DWORD dwState)
  267. {
  268. ASSERT(_pScmProcessReg);
  269. gpServerLock->LockExclusive();
  270. _pScmProcessReg->ReadinessStatus = dwState;
  271. // we're now dirty
  272. _dwFlags |= PROCESS_SPI_DIRTY;
  273. gpServerLock->UnlockExclusive();
  274. }
  275. void CProcess::Retire()
  276. {
  277. // A process can (or should be) only retired once
  278. ASSERT(!IsRetired());
  279. // Mark ourselves as retired
  280. _dwFlags |= (PROCESS_RETIRED | PROCESS_SPI_DIRTY);
  281. }
  282. void CProcess::SetRunAsHandle(void *pvRunAsHandle)
  283. {
  284. ASSERT(!_pvRunAsHandle);
  285. _pvRunAsHandle = pvRunAsHandle;
  286. }
  287. BOOL CProcess::SetProcessHandle(HANDLE hProcHandle, DWORD dwLaunchedPID)
  288. {
  289. /*++
  290. Routine Description:
  291. Store the handle of the process only if the process launched by
  292. us and the process registering back are the same. Otherwise
  293. we might kill a process not launched by us on receiving certain
  294. error conditions (notably RPC_E_SERVERFAULT)
  295. Arguments:
  296. hProcHandle - Handle of the process launched
  297. dwLaunchedPID - PID of the process launched
  298. Return Value:
  299. TRUE - If handle is set
  300. FALSE - otherwise
  301. --*/
  302. if (dwLaunchedPID == _procID)
  303. {
  304. _hProcHandle = hProcHandle;
  305. return TRUE;
  306. }
  307. return FALSE;
  308. }
  309. RPC_STATUS
  310. CProcess::ProcessBindings(
  311. IN DUALSTRINGARRAY *pdsaStringBindings,
  312. IN DUALSTRINGARRAY *pdsaSecurityBindings
  313. )
  314. /*++
  315. Routine Description:
  316. Updates the string and optionally the security
  317. bindings associated with this process.
  318. Arguments:
  319. psaStringBindings - The expanded string bindings of the process
  320. psaSecurityBindings - compressed security bindings of the process.
  321. If NULL, the current security bindings are reused.
  322. Environment:
  323. Server lock held during call or called from an OXID with an extra
  324. reference owned by the process and keeping this process alive.
  325. Return Value:
  326. OR_NOMEM - unable to allocate storage for the new string arrays.
  327. OR_OK - normally.
  328. --*/
  329. {
  330. CMutexLock lock(&gcsFastProcessLock);
  331. USHORT wSecSize;
  332. PWSTR pwstrSecPointer;
  333. // NULL security bindings means we should use the existing bindings.
  334. if (0 == pdsaSecurityBindings)
  335. {
  336. ASSERT(_pdsaLocalBindings);
  337. wSecSize = _pdsaLocalBindings->wNumEntries - _pdsaLocalBindings->wSecurityOffset;
  338. pwstrSecPointer = _pdsaLocalBindings->aStringArray
  339. + _pdsaLocalBindings->wSecurityOffset;
  340. }
  341. else
  342. {
  343. wSecSize = pdsaSecurityBindings->wNumEntries - pdsaSecurityBindings->wSecurityOffset;
  344. pwstrSecPointer = &pdsaSecurityBindings->aStringArray[pdsaSecurityBindings->wSecurityOffset];
  345. }
  346. DUALSTRINGARRAY *pdsaT = CompressStringArrayAndAddIPAddrs(pdsaStringBindings);
  347. if (!pdsaT)
  348. {
  349. return(OR_NOMEM);
  350. }
  351. // ignore security on string binding parameter
  352. pdsaT->wNumEntries = pdsaT->wSecurityOffset;
  353. DUALSTRINGARRAY *pdsaResult = new((pdsaT->wNumEntries + wSecSize) * sizeof(WCHAR)) DUALSTRINGARRAY;
  354. if (0 == pdsaResult)
  355. {
  356. delete pdsaT;
  357. return(OR_NOMEM);
  358. }
  359. pdsaResult->wNumEntries = pdsaT->wNumEntries + wSecSize;
  360. pdsaResult->wSecurityOffset = pdsaT->wSecurityOffset;
  361. OrMemoryCopy(pdsaResult->aStringArray,
  362. pdsaT->aStringArray,
  363. pdsaT->wSecurityOffset*sizeof(WCHAR));
  364. OrMemoryCopy(pdsaResult->aStringArray + pdsaResult->wSecurityOffset,
  365. pwstrSecPointer,
  366. wSecSize*sizeof(WCHAR));
  367. ASSERT(dsaValid(pdsaResult));
  368. delete pdsaT;
  369. delete _pdsaLocalBindings;
  370. _pdsaLocalBindings = pdsaResult;
  371. delete _pdsaRemoteBindings;
  372. _pdsaRemoteBindings = 0;
  373. return(RPC_S_OK);
  374. }
  375. DUALSTRINGARRAY *
  376. CProcess::GetLocalBindings(void)
  377. // Server lock held or called within an
  378. // OXID with an extra reference.
  379. {
  380. CMutexLock lock(&gcsFastProcessLock);
  381. if (0 == _pdsaLocalBindings)
  382. {
  383. return(0);
  384. }
  385. DUALSTRINGARRAY *T = (DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY)
  386. + sizeof(USHORT) * _pdsaLocalBindings->wNumEntries);
  387. if (0 != T)
  388. {
  389. dsaCopy(T, _pdsaLocalBindings);
  390. }
  391. return(T);
  392. }
  393. DUALSTRINGARRAY *
  394. CProcess::GetRemoteBindings(void)
  395. // Server lock held.
  396. {
  397. CMutexLock lock(&gcsFastProcessLock);
  398. ORSTATUS Status;
  399. if (0 == _pdsaRemoteBindings)
  400. {
  401. if (0 == _pdsaLocalBindings)
  402. {
  403. return(0);
  404. }
  405. Status = ConvertToRemote(_pdsaLocalBindings, &_pdsaRemoteBindings);
  406. if (Status != OR_OK)
  407. {
  408. ASSERT(Status == OR_NOMEM);
  409. return(0);
  410. }
  411. ASSERT(dsaValid(_pdsaRemoteBindings));
  412. }
  413. DUALSTRINGARRAY *T = (DUALSTRINGARRAY *)MIDL_user_allocate(sizeof(DUALSTRINGARRAY)
  414. + sizeof(USHORT) * _pdsaRemoteBindings->wNumEntries);
  415. if (0 != T)
  416. {
  417. dsaCopy(T, _pdsaRemoteBindings);
  418. }
  419. ASSERT(dsaValid(T));
  420. return(T);
  421. }
  422. ORSTATUS
  423. CProcess::AddOxid(CServerOxid *pOxid)
  424. {
  425. ASSERT(gpServerLock->HeldExclusive());
  426. pOxid->Reference();
  427. ASSERT(_blistOxids.Member(pOxid) == FALSE);
  428. ORSTATUS status = _blistOxids.Insert(pOxid);
  429. if (status != OR_OK)
  430. {
  431. pOxid->ProcessRelease();
  432. return(status);
  433. }
  434. gpServerOxidTable->Add(pOxid);
  435. return(OR_OK);
  436. }
  437. BOOL
  438. CProcess::RemoveOxid(CServerOxid *poxid)
  439. {
  440. ASSERT(gpServerLock->HeldExclusive());
  441. CServerOxid *pit = (CServerOxid *)_blistOxids.Remove(poxid);
  442. if (pit)
  443. {
  444. ASSERT(pit == poxid);
  445. gpServerOxidTable->Remove(poxid);
  446. poxid->ProcessRelease();
  447. return(TRUE);
  448. }
  449. return(FALSE);
  450. }
  451. BOOL
  452. CProcess::IsOwner(CServerOxid *poxid)
  453. {
  454. ASSERT(gpServerLock->HeldExclusive());
  455. return(_blistOxids.Member(poxid));
  456. }
  457. ORSTATUS
  458. CProcess::AddOid(CClientOid *poid)
  459. /*++
  460. Routine Description:
  461. Adds a new oid to the list of OIDs owned by this process and
  462. increments the reference count of the associated OXID
  463. Arguments:
  464. poid - the oid to add. It's reference is transferred to this
  465. function. If this function fails, it must dereference the oid.
  466. The caller passed a client reference to this process. The
  467. process must eventually call ClientRelease() on the parameter.
  468. Return Value:
  469. OR_OK - normally
  470. OR_NOMEM - out of memory.
  471. --*/
  472. {
  473. ORSTATUS status;
  474. ASSERT(gpClientLock->HeldExclusive());
  475. status = _blistOids.Insert(poid);
  476. if (status != OR_OK)
  477. {
  478. ASSERT(status == OR_NOMEM);
  479. poid->ClientRelease();
  480. }
  481. else
  482. {
  483. ASSERT(NULL != poid->GetClientOxid());
  484. poid->GetClientOxid()->Reference();
  485. }
  486. return(status);
  487. }
  488. CClientOid *
  489. CProcess::RemoveOid(CClientOid *poid)
  490. /*++
  491. Routine Description:
  492. Removes an OID from this list of OID in use by this process.
  493. Arguments:
  494. poid - The OID to remove.
  495. Return Value:
  496. non-zero - the pointer actually remove. (ASSERT(retval == poid))
  497. It will be released by the process before return,
  498. so you should not use the pointer unless you know you
  499. have another reference.
  500. 0 - not in the list
  501. --*/
  502. {
  503. ASSERT(gpClientLock->HeldExclusive());
  504. CClientOid *pit = (CClientOid *)_blistOids.Remove(poid);
  505. if (pit)
  506. {
  507. ASSERT(pit == poid);
  508. pit->ClientRelease();
  509. ASSERT(NULL != poid->GetClientOxid());
  510. poid->GetClientOxid()->Release();
  511. return(pit);
  512. }
  513. return(0);
  514. }
  515. void
  516. CProcess::AddClassReg(GUID & Guid, DWORD Reg)
  517. {
  518. CClassReg * pReg;
  519. pReg = new CClassReg( Guid, Reg );
  520. if (pReg)
  521. {
  522. gpServerLock->LockExclusive();
  523. _listClasses.Insert( pReg );
  524. // flip the dirty bit
  525. _dwFlags |= PROCESS_SPI_DIRTY;
  526. _ulClasses++;
  527. gpServerLock->UnlockExclusive();
  528. }
  529. }
  530. void
  531. CProcess::RemoveClassReg(DWORD Reg)
  532. {
  533. CClassReg * pReg;
  534. gpServerLock->LockExclusive();
  535. pReg = (CClassReg *)_listClasses.First();
  536. while ( (pReg != NULL) && (pReg->_Reg != Reg) )
  537. pReg = (CClassReg *)pReg->Next();
  538. if (pReg)
  539. {
  540. (void)_listClasses.Remove( pReg );
  541. delete pReg;
  542. // flip the dirty bit
  543. _dwFlags |= PROCESS_SPI_DIRTY;
  544. _ulClasses--;
  545. }
  546. gpServerLock->UnlockExclusive();
  547. }
  548. void
  549. CProcess::Cleanup()
  550. {
  551. SCMProcessCleanup(this);
  552. }
  553. void
  554. CProcess::RevokeClassRegs()
  555. {
  556. if (_pScmProcessReg)
  557. {
  558. // This is a unified surrogate (COM+) server
  559. SCMRemoveRegistration(_pScmProcessReg);
  560. _pScmProcessReg = NULL;
  561. }
  562. // This is for legacy local or custom surrogate servers -- however,
  563. // nothing prevents someone from calling CoRegisterClassObject in
  564. // user code even in a COM+ (surrogate) server
  565. CClassReg * pReg;
  566. // This is only called during rundown so we don't have to take a lock.
  567. while ( (pReg = (CClassReg *)_listClasses.First()) != 0 )
  568. {
  569. (void)_listClasses.Remove((CListElement *)pReg);
  570. SCMRemoveRegistration( this,
  571. pReg->_Guid,
  572. pReg->_Reg );
  573. delete pReg;
  574. }
  575. }
  576. void CProcess::SetProcessReg(ScmProcessReg *pProcessReg)
  577. /*++
  578. Routine Description:
  579. Called by SCM to set COM+ process registration.
  580. This is also used as a cache during the startup protocol
  581. to query and set the readiness state of the server process.
  582. There is exactly one such registration per COM+ server process.
  583. CODEWORK: these should be inlined
  584. Arguments:
  585. registration struct
  586. Return Value:
  587. none.
  588. --*/
  589. {
  590. gpServerLock->LockExclusive();
  591. _pScmProcessReg = pProcessReg;
  592. gpServerLock->UnlockExclusive();
  593. }
  594. ScmProcessReg* CProcess::GetProcessReg()
  595. /*++
  596. Routine Description:
  597. Called by SCM to lookup COM+ process registration.
  598. Arguments:
  599. None
  600. Return Value:
  601. registration struct, if any.
  602. --*/
  603. {
  604. gpServerLock->LockShared();
  605. ScmProcessReg *pResult = _pScmProcessReg;
  606. gpServerLock->UnlockShared();
  607. return pResult;
  608. }
  609. ScmProcessReg*
  610. CProcess::RemoveProcessReg()
  611. /*++
  612. Routine Description:
  613. Called by SCM when COM+ process revokes its activator registration.
  614. Arguments:
  615. None
  616. Return Value:
  617. none.
  618. --*/
  619. {
  620. gpServerLock->LockExclusive();
  621. ScmProcessReg *pResult = _pScmProcessReg;
  622. // Even if this process was a new-style surrogate process, _pScmProcessReg
  623. // may already be NULL here. See bug 26676. So we don't assert anymore
  624. // that _pScmProcessReg is non-NULL.
  625. // ASSERT(_pScmProcessReg);
  626. _pScmProcessReg = NULL;
  627. gpServerLock->UnlockExclusive();
  628. return pResult;
  629. }
  630. void CProcess::RevokeProcessReg()
  631. /*++
  632. Routine Description:
  633. Called during rundown to let SCM know that the COM+ process has died.
  634. CODEWORK: This needs to be defined.
  635. Arguments:
  636. None
  637. Return Value:
  638. none.
  639. --*/
  640. {
  641. }
  642. RPC_BINDING_HANDLE
  643. CProcess::GetBindingHandle(
  644. void
  645. )
  646. /*++
  647. Routine Description:
  648. If necessary, this function allocates a binding handle
  649. back to process. It used either mswmsg or ncalrpc depending
  650. on the apartmentness of the process.
  651. Arguments:
  652. None
  653. Return Value:
  654. Binding Handle, NULL if no valid handle.
  655. --*/
  656. {
  657. RPC_STATUS status;
  658. CMutexLock lock(&gcsFastProcessLock);
  659. // Find ncalrpc binding.
  660. PWSTR pwstr = _pdsaLocalBindings->aStringArray;
  661. while (*pwstr)
  662. {
  663. if (*pwstr == ID_LPC)
  664. {
  665. break;
  666. }
  667. pwstr = OrStringSearch(pwstr, 0) + 1;
  668. }
  669. if (*pwstr == 0)
  670. {
  671. KdPrintEx((DPFLTR_DCOMSS_ID,
  672. DPFLTR_WARNING_LEVEL,
  673. "OR: Unable to find ncalrpc binding to server: %p %p\n",
  674. _pdsaLocalBindings,
  675. this));
  676. ASSERT(0);
  677. return NULL;
  678. }
  679. return GetBinding(pwstr);
  680. }
  681. void
  682. CProcess::EnsureRealBinding(
  683. void
  684. )
  685. /*++
  686. Routine Description:
  687. If necessary, this function allocates a binding handle
  688. back to process.
  689. Note: Called with the server lock held -OR- from an OXID
  690. with and extra reference which keeps this process alive.
  691. Arguments:
  692. None
  693. Return Value:
  694. None
  695. --*/
  696. {
  697. CMutexLock lock(&gcsFastProcessLock);
  698. if (0 == _hProcess)
  699. {
  700. _hProcess = GetBindingHandle();
  701. _fCacheFree = TRUE;
  702. }
  703. }
  704. RPC_BINDING_HANDLE
  705. CProcess::AllocateBinding(
  706. void
  707. )
  708. /*++
  709. Routine Description:
  710. Allocates a unique binding handle for a call back
  711. to the process. This binding handle will not be
  712. used by another thread until it is freed.
  713. Arguments:
  714. None
  715. Return Value:
  716. 0 - failure
  717. non-zero - a binding handle to use.
  718. --*/
  719. {
  720. EnsureRealBinding();
  721. if (_hProcess == 0)
  722. {
  723. return(0);
  724. }
  725. CMutexLock lock(&gcsFastProcessLock);
  726. ASSERT(_hProcess);
  727. if (_fCacheFree)
  728. {
  729. _fCacheFree = FALSE;
  730. return(_hProcess);
  731. }
  732. RPC_BINDING_HANDLE h;
  733. RPC_STATUS status;
  734. status = RpcBindingCopy(_hProcess, &h);
  735. if (status != RPC_S_OK)
  736. {
  737. return(0);
  738. }
  739. return(h);
  740. }
  741. void
  742. CProcess::FreeBinding(
  743. IN RPC_BINDING_HANDLE hBinding
  744. )
  745. /*++
  746. Routine Description:
  747. Frees a binding back to the process.
  748. Arguments:
  749. hBinding - A binding back to the process previously
  750. allocated with AllocateBinding().
  751. Return Value:
  752. None
  753. --*/
  754. {
  755. if (hBinding == _hProcess)
  756. {
  757. _fCacheFree = TRUE;
  758. }
  759. else
  760. {
  761. RPC_STATUS status = RpcBindingFree(&hBinding);
  762. ASSERT(status == RPC_S_OK);
  763. }
  764. }
  765. RPC_STATUS
  766. CProcess::RundownOids(
  767. IN CServerOxid* pOwningOxid,
  768. IN ULONG cOids,
  769. IN CServerOid* aOids[]
  770. )
  771. /*++
  772. Routine Description:
  773. Issues an async call to the process which will rundown the OIDs.
  774. This is called from an OXID which will be kept alive during the
  775. whole call. Multiple calls maybe made to this function by
  776. one or more OXIDs at the same time. The callback itself is
  777. an ORPC call, ie is must have THIS and THAT pointers.
  778. Arguments:
  779. pOwningOxid - oxid that owns the specified oids. This oxid should
  780. be registered from this process.
  781. cOids - The number of entries in aOids and afRundownOk
  782. aOids - An array of CServerOid's to rundown. The OIDs must
  783. all be owned by pOwningOxid. The caller will have already
  784. called SetRundown(TRUE) on each one.
  785. Return Value:
  786. RPC_S_OK - the async call was issued successfully
  787. other -- error occurred. call was not issued.
  788. --*/
  789. {
  790. ULONG i;
  791. error_status_t status = OR_OK;
  792. RPC_BINDING_HANDLE hBinding;
  793. OID aScalarOids[MAX_OID_RUNDOWNS_PER_CALL];
  794. ASSERT(cOids > 0 && aOids);
  795. ASSERT(cOids <= MAX_OID_RUNDOWNS_PER_CALL);
  796. ASSERT(IsOwner(pOwningOxid));
  797. // Callers must be aware that the lock will be released upon return
  798. ASSERT(gpServerLock->HeldExclusive());
  799. gpServerLock->UnlockExclusive();
  800. // This process will be held alive by the OXID calling
  801. // us since it has an extra reference.
  802. //
  803. // Allocate async structure and zero it out
  804. //
  805. ASYNCRUNDOWNOID_STUFF* pArgs = new ASYNCRUNDOWNOID_STUFF;
  806. if (!pArgs)
  807. return OR_NOMEM;
  808. ZeroMemory(pArgs, sizeof(ASYNCRUNDOWNOID_STUFF));
  809. //
  810. // Initialize async structure
  811. //
  812. pArgs->dwSig = ASYNCRUNDOWNOID_SIG;
  813. pArgs->pProcess = this; // will take ref below after issuing call
  814. pArgs->pOxid = pOwningOxid; // will take ref below after issuing call
  815. pArgs->cOids = cOids;
  816. CopyMemory(pArgs->aOids, aOids, cOids * sizeof(CServerOid*));
  817. //
  818. // Fill in the numeric oid values
  819. //
  820. ZeroMemory(aScalarOids, sizeof(OID) * MAX_OID_RUNDOWNS_PER_CALL);
  821. for (i = 0; i < cOids; i++)
  822. {
  823. ASSERT(pArgs->aOids[i]);
  824. ASSERT(pArgs->aOids[i]->IsRunningDown());
  825. ASSERT(pArgs->aOids[i]->GetOxid() == pOwningOxid);
  826. aScalarOids[i] = pArgs->aOids[i]->Id();
  827. }
  828. //
  829. // Allocate binding handle
  830. //
  831. status = OR_NOMEM; // assume no mem
  832. hBinding = AllocateBinding();
  833. if (hBinding)
  834. {
  835. IPID ipidUnk = pOwningOxid->GetIPID();
  836. status = RpcBindingSetObject(hBinding, &ipidUnk);
  837. if (status == RPC_S_OK)
  838. {
  839. status = RpcAsyncInitializeHandle(&(pArgs->async),
  840. sizeof(pArgs->async));
  841. }
  842. }
  843. //
  844. // Check for errors
  845. //
  846. if (status != RPC_S_OK)
  847. {
  848. if (hBinding) FreeBinding(hBinding);
  849. delete pArgs;
  850. return status;
  851. }
  852. //
  853. // Save the binding handle
  854. //
  855. pArgs->hBinding = hBinding;
  856. //
  857. // Init parts of the RPC_ASYNC_STATE struct that we care about
  858. //
  859. pArgs->async.UserInfo = pArgs;
  860. pArgs->async.Event = RpcCallComplete;
  861. pArgs->async.NotificationType = RpcNotificationTypeCallback;
  862. pArgs->async.u.NotificationRoutine = CProcess::AsyncRundownReturnNotification;
  863. //
  864. // Initialize other params
  865. //
  866. pArgs->orpcthis.version.MajorVersion = COM_MAJOR_VERSION;
  867. pArgs->orpcthis.version.MinorVersion = COM_MINOR_VERSION;
  868. pArgs->orpcthis.flags = ORPCF_LOCAL;
  869. pArgs->orpcthis.reserved1 = 0;
  870. pArgs->orpcthis.extensions = NULL;
  871. pArgs->callIDHint = AllocateCallId(pArgs->orpcthis.cid);
  872. pArgs->localthis.dwClientThread = 0;
  873. pArgs->localthis.dwFlags = LOCALF_NONE;
  874. pArgs->orpcthat.flags = 0;
  875. pArgs->orpcthat.extensions = 0;
  876. //
  877. // Take an extra reference on the owning oxid and ourself.
  878. // These references will be released either on the call
  879. // return notification, or on the failure path below.
  880. //
  881. pOwningOxid->Reference();
  882. this->Reference(); // non-client ref, will not stop rundown
  883. //
  884. // Finally, issue the call. Note that this is an async call
  885. // from our perspective, but is a synchronous ORPC call from
  886. // the server's perspective.
  887. //
  888. status = RawRundownOid(
  889. &(pArgs->async),
  890. pArgs->hBinding,
  891. &(pArgs->orpcthis),
  892. &(pArgs->localthis),
  893. &(pArgs->orpcthat),
  894. pArgs->cOids,
  895. aScalarOids,
  896. pArgs->aRundownStatus
  897. );
  898. if (status != RPC_S_OK)
  899. {
  900. // Call failed, so cleanup before returning. Caller will
  901. // handle the failure semantics for the oids.
  902. FreeBinding(pArgs->hBinding);
  903. FreeCallId(pArgs->callIDHint);
  904. delete pArgs;
  905. //
  906. // Must hold gpServerLock in order to call Release.
  907. //
  908. ASSERT(!gpServerLock->HeldExclusive());
  909. gpServerLock->LockExclusive();
  910. pOwningOxid->Release();
  911. this->Release();
  912. gpServerLock->UnlockExclusive();
  913. ASSERT(!gpServerLock->HeldExclusive());
  914. }
  915. return status;
  916. }
  917. void
  918. CProcess::RundownOidNotify(RPC_BINDING_HANDLE hBinding,
  919. CServerOxid* pOwningOxid,
  920. ULONG cOids,
  921. CServerOid* aOids[],
  922. BYTE aRundownStatus[],
  923. HRESULT hrReturn)
  924. /*++
  925. Routine Description:
  926. This is the callback notification function that is invoked when
  927. async oid rundown calls are completed.
  928. Arguments:
  929. hBinding -- binding handle used to make the call
  930. pOwningOxid -- owning oxid of the oids we tried to rundown.
  931. cOids -- count of oids
  932. aOids -- array of oids
  933. aRundownStatus -- array of individual status rundowns for each oid
  934. hrReturn -- return value from the function
  935. Return Value:
  936. void
  937. --*/
  938. {
  939. ULONG i;
  940. error_status_t status = OR_OK;
  941. ASSERT(hBinding);
  942. ASSERT(pOwningOxid);
  943. ASSERT((cOids > 0) && aOids && aRundownStatus);
  944. //
  945. // Free the binding
  946. //
  947. FreeBinding(hBinding);
  948. //
  949. // If destination oxid\apartment was not found, mark all
  950. // oids for rundown.
  951. //
  952. if (hrReturn == RPC_E_DISCONNECTED)
  953. {
  954. KdPrintEx((DPFLTR_DCOMSS_ID,
  955. DPFLTR_WARNING_LEVEL,
  956. "OR: Rundown returned disconnected\n"));
  957. for (i = 0; i < cOids; i++)
  958. {
  959. aRundownStatus[i] = ORS_OK_TO_RUNDOWN;
  960. }
  961. hrReturn = RPC_S_OK;
  962. }
  963. //
  964. // In case of any other error, don't rundown the oids
  965. //
  966. if (hrReturn != RPC_S_OK)
  967. {
  968. for (i = 0; i < cOids; i++)
  969. {
  970. aRundownStatus[i] = ORS_DONTRUNDOWN;
  971. }
  972. }
  973. //
  974. // Notify the server oxid of the results
  975. //
  976. gpServerLock->LockExclusive();
  977. pOwningOxid->ProcessRundownResults(
  978. cOids,
  979. aOids,
  980. aRundownStatus
  981. );
  982. gpServerLock->UnlockExclusive();
  983. return;
  984. }
  985. void RPC_ENTRY
  986. CProcess::AsyncRundownReturnNotification(
  987. IN RPC_ASYNC_STATE* pAsync,
  988. IN void* pContext,
  989. IN RPC_ASYNC_EVENT Event
  990. )
  991. /*++
  992. Routine Description:
  993. This is the callback notification function that is invoked when
  994. async rundown calls are completed. It unpacks the necessary
  995. stuff from the async args struct, forwards them on to
  996. RundownOidNotify, and does other necessary cleanup.
  997. Arguments:
  998. pAsync -- pointer to the async rpc state struct
  999. pContext -- rpc thingy, we ignore it
  1000. Event -- rpc thingy, we ignore it
  1001. Return Value:
  1002. void
  1003. --*/
  1004. {
  1005. RPC_STATUS status;
  1006. HRESULT hrRetVal;
  1007. ASYNCRUNDOWNOID_STUFF* pArgs;
  1008. pArgs = (ASYNCRUNDOWNOID_STUFF*)
  1009. (((char*)pAsync) - offsetof(ASYNCRUNDOWNOID_STUFF, async));
  1010. ASSERT(pArgs->async.UserInfo = pArgs);
  1011. ASSERT(pArgs->dwSig == ASYNCRUNDOWNOID_SIG);
  1012. ASSERT(pArgs->hBinding);
  1013. ASSERT(pArgs->pProcess);
  1014. ASSERT(pArgs->pOxid);
  1015. ASSERT(pArgs->cOids > 0);
  1016. //
  1017. // Free the call id
  1018. //
  1019. FreeCallId(pArgs->callIDHint);
  1020. // Complete the call. Since we've asked for a direct callback upon
  1021. // completion, we should never get back RPC_S_ASYNC_CALL_PENDING, so
  1022. // we assert on this. hrRetVal is not necessarily S_OK.
  1023. status = RpcAsyncCompleteCall(&(pArgs->async), &hrRetVal);
  1024. ASSERT(status != RPC_S_ASYNC_CALL_PENDING);
  1025. //
  1026. // Notify the process object that the call has returned
  1027. //
  1028. pArgs->pProcess->RundownOidNotify(
  1029. pArgs->hBinding, // process frees the binding
  1030. pArgs->pOxid,
  1031. pArgs->cOids,
  1032. pArgs->aOids,
  1033. pArgs->aRundownStatus,
  1034. (status == RPC_S_OK) ? hrRetVal : status
  1035. );
  1036. //
  1037. // Cleanup other stuff from the call
  1038. //
  1039. if (status == RPC_S_OK && pArgs->orpcthat.extensions)
  1040. {
  1041. for (ULONG i = 0; i < pArgs->orpcthat.extensions->size; i++)
  1042. {
  1043. MIDL_user_free(pArgs->orpcthat.extensions->extent[i]);
  1044. }
  1045. MIDL_user_free(pArgs->orpcthat.extensions->extent);
  1046. MIDL_user_free(pArgs->orpcthat.extensions);
  1047. }
  1048. //
  1049. // Release the references on ourselves and the server
  1050. // oxid. Must hold gpServerLock while calling Release.
  1051. //
  1052. gpServerLock->LockExclusive();
  1053. pArgs->pProcess->Release();
  1054. pArgs->pOxid->Release();
  1055. gpServerLock->UnlockExclusive();
  1056. delete pArgs;
  1057. return;
  1058. }
  1059. ORSTATUS
  1060. CProcess::UseProtseqIfNeeded(
  1061. IN USHORT cClientProtseqs,
  1062. IN USHORT aClientProtseqs[]
  1063. )
  1064. {
  1065. ORSTATUS status;
  1066. RPC_BINDING_HANDLE hBinding;
  1067. UUID NullUuid = {0};
  1068. USHORT wProtseqTowerId;
  1069. KdPrintEx((DPFLTR_DCOMSS_ID,
  1070. DPFLTR_WARNING_LEVEL,
  1071. "OR: UseProtseqIfNeeded ==> %d\n",
  1072. cClientProtseqs));
  1073. // This process will be held alive by the OXID calling
  1074. // us since it has an extra reference.
  1075. CMutexLock callback(&_csCallbackLock);
  1076. CMutexLock process(&gcsFastProcessLock);
  1077. // Another thread may have used the protseq in the mean time.
  1078. ASSERT(_pdsaLocalBindings);
  1079. KdPrintEx((DPFLTR_DCOMSS_ID,
  1080. DPFLTR_WARNING_LEVEL,
  1081. "OR: FindMatchingProtSeq from local bindings\n"));
  1082. // ronans - initially _pdsaLocalBindings will hold bindings which have been set
  1083. // by when the server called ServerAllocateOxidAndOids .. usually only local
  1084. // protseqs LRPC or WMSG at that point.
  1085. wProtseqTowerId = FindMatchingProtseq(cClientProtseqs,
  1086. aClientProtseqs,
  1087. _pdsaLocalBindings->aStringArray
  1088. );
  1089. if (0 != wProtseqTowerId)
  1090. {
  1091. KdPrintEx((DPFLTR_DCOMSS_ID,
  1092. DPFLTR_WARNING_LEVEL,
  1093. "OR: Found protseq in local bindings\n"));
  1094. return(OR_OK);
  1095. }
  1096. // No protseq shared between the client and the OXIDs' server.
  1097. // Find a matching protseq.
  1098. // check if its a solitary local protocol sequence LRPC or WMSG
  1099. if (cClientProtseqs == 1 && IsLocal(aClientProtseqs[0]))
  1100. {
  1101. // if so - get it
  1102. wProtseqTowerId = aClientProtseqs[0];
  1103. ASSERT(wProtseqTowerId);
  1104. }
  1105. else
  1106. // we have multiple protseqs - presumed to be nonlocal
  1107. {
  1108. // ensure we have custom protseq information
  1109. if (!_fReadCustomProtseqs)
  1110. {
  1111. // use local temporary to avoid holding process lock
  1112. DUALSTRINGARRAY *pdsaCustomProtseqs = NULL;
  1113. // we'll only try this once - so set the flag now to avoid
  1114. // race conditions
  1115. _fReadCustomProtseqs = TRUE;
  1116. process.Unlock();
  1117. hBinding = AllocateBinding();
  1118. if (0 == hBinding)
  1119. return(OR_NOMEM);
  1120. status = RpcBindingSetObject(hBinding, &NullUuid);
  1121. // get the information from the Object server
  1122. if (status == RPC_S_OK)
  1123. {
  1124. status = ::GetCustomProtseqInfo(hBinding,cMyProtseqs, aMyProtseqs, &pdsaCustomProtseqs);
  1125. KdPrintEx((DPFLTR_DCOMSS_ID,
  1126. DPFLTR_WARNING_LEVEL,
  1127. "GetCustomProtseqInfo - status : %ld\n",
  1128. status));
  1129. }
  1130. // relock the process object
  1131. process.Lock();
  1132. if (status == RPC_S_OK)
  1133. {
  1134. if (pdsaCustomProtseqs)
  1135. {
  1136. ASSERT(dsaValid(pdsaCustomProtseqs));
  1137. }
  1138. _pdsaCustomProtseqs = pdsaCustomProtseqs;
  1139. }
  1140. FreeBinding(hBinding);
  1141. }
  1142. USHORT i,j;
  1143. // if there is custom protseq information - scan it for a match
  1144. if (_pdsaCustomProtseqs)
  1145. {
  1146. KdPrintEx((DPFLTR_DCOMSS_ID,
  1147. DPFLTR_WARNING_LEVEL,
  1148. "OR: Using custom protseq information\n"));
  1149. wProtseqTowerId = FindMatchingProtseq(cClientProtseqs,
  1150. aClientProtseqs,
  1151. _pdsaCustomProtseqs->aStringArray);
  1152. if (wProtseqTowerId)
  1153. {
  1154. ASSERT(FALSE == IsLocal(wProtseqTowerId));
  1155. }
  1156. }
  1157. else
  1158. // we don't have custom protseqs so use
  1159. // the standard ones
  1160. {
  1161. KdPrintEx((DPFLTR_DCOMSS_ID,
  1162. DPFLTR_WARNING_LEVEL,
  1163. "OR: Using standard protseq information\n"));
  1164. for (i = 0; i < cClientProtseqs && wProtseqTowerId == 0; i++)
  1165. {
  1166. for (j = 0; j < cMyProtseqs; j++)
  1167. {
  1168. if (aMyProtseqs[j] == aClientProtseqs[i])
  1169. {
  1170. ASSERT(FALSE == IsLocal(aMyProtseqs[j]));
  1171. wProtseqTowerId = aMyProtseqs[j];
  1172. break;
  1173. }
  1174. }
  1175. }
  1176. }
  1177. }
  1178. if (0 == wProtseqTowerId)
  1179. {
  1180. // No shared protseq, must be a bug since the client managed to call us.
  1181. ASSERT(0 && "No shared protseq, must be a bug since the client managed to call us");
  1182. #if DBG
  1183. if (cClientProtseqs == 0)
  1184. KdPrintEx((DPFLTR_DCOMSS_ID,
  1185. DPFLTR_WARNING_LEVEL,
  1186. "OR: Client OR not configured to use remote protseqs\n"));
  1187. else
  1188. KdPrintEx((DPFLTR_DCOMSS_ID,
  1189. DPFLTR_WARNING_LEVEL,
  1190. "OR: Client called on an unsupported protocol:"
  1191. "%d %p %p \n",
  1192. cClientProtseqs,
  1193. aClientProtseqs,
  1194. aMyProtseqs));
  1195. #endif
  1196. return(OR_NOSERVER);
  1197. }
  1198. process.Unlock();
  1199. DUALSTRINGARRAY *pdsaBinding = 0;
  1200. DUALSTRINGARRAY *pdsaSecurity = 0;
  1201. hBinding = AllocateBinding();
  1202. if (0 == hBinding)
  1203. {
  1204. return(OR_NOMEM);
  1205. }
  1206. status = RpcBindingSetObject(hBinding, &NullUuid);
  1207. if (status == RPC_S_OK)
  1208. {
  1209. status = ::UseProtseq(hBinding,
  1210. wProtseqTowerId,
  1211. &pdsaBinding,
  1212. &pdsaSecurity);
  1213. }
  1214. KdPrintEx((DPFLTR_DCOMSS_ID,
  1215. DPFLTR_WARNING_LEVEL,
  1216. "OR: Lazy use protseq: %S (from towerid) in process %p - %d\n",
  1217. GetProtseq(wProtseqTowerId),
  1218. this,
  1219. status));
  1220. // Update this process' state to include the new bindings.
  1221. if (!dsaValid(pdsaBinding))
  1222. {
  1223. if (pdsaBinding)
  1224. {
  1225. KdPrintEx((DPFLTR_DCOMSS_ID,
  1226. DPFLTR_WARNING_LEVEL,
  1227. "OR: Use protseq returned an invalid dsa: %p\n",
  1228. pdsaBinding));
  1229. }
  1230. status = OR_NOMEM;
  1231. }
  1232. else
  1233. {
  1234. ASSERT(_pdsaLocalBindings);
  1235. ASSERT(status == RPC_S_OK);
  1236. status = ProcessBindings(pdsaBinding, pdsaSecurity);
  1237. }
  1238. if (pdsaBinding != NULL)
  1239. MIDL_user_free(pdsaBinding);
  1240. if (pdsaSecurity != NULL)
  1241. MIDL_user_free(pdsaSecurity);
  1242. FreeBinding(hBinding);
  1243. return(status);
  1244. }
  1245. ORSTATUS CProcess::UpdateResolverBindings(DWORD64 dwBindingsID, DUALSTRINGARRAY* pdsaResolverBindings)
  1246. /*++
  1247. Routine Description:
  1248. This function does the work of calling back into the server process
  1249. to tell it to update its local OR bindings. It also updates our
  1250. cached local\remote bindings for this process object.
  1251. Arguments:
  1252. dwBindingsID -- unique id of pdsaResolverBindings. We use this
  1253. to resolve what to do when async calls arrive\return in an
  1254. out-of-order fashion.
  1255. pdsaResolverBindings -- ptr to the new resolver bindings
  1256. Return Value:
  1257. OR_OK -- success
  1258. OR_NOMEM -- out of memory
  1259. other -- unexpected error
  1260. --*/
  1261. {
  1262. ORSTATUS status;
  1263. RPC_BINDING_HANDLE hBinding;
  1264. UUID NullUuid = {0};
  1265. DUALSTRINGARRAY* pdsaBinding = NULL;
  1266. DUALSTRINGARRAY* pdsaSecurity = NULL;
  1267. BINDINGS_UPDATE_CALLBACK_STUFF* pArgs = NULL;
  1268. // undone figure out why we need this callback lock thingy
  1269. CMutexLock callback(&_csCallbackLock);
  1270. if (dwBindingsID <= _dwCurrentBindingsID)
  1271. {
  1272. // The supplied bindings are the same or older than
  1273. // what we already have, so ignore them.
  1274. return OR_OK;
  1275. }
  1276. // if the server has not yet called _ServerAllocateOxidAndOids
  1277. // then we will not yet have cached binding info for them, and
  1278. // hence will be unable to construct a binding handle. In
  1279. // this case we simply do not update that process. If this
  1280. // happens we will give them the new bindings later, if and
  1281. // when they do call _SAOAO.
  1282. if (!_pdsaLocalBindings)
  1283. {
  1284. _dwFlags |= PROCESS_NEEDSBINDINGS;
  1285. return OR_OK;
  1286. }
  1287. pArgs = new BINDINGS_UPDATE_CALLBACK_STUFF;
  1288. if (!pArgs)
  1289. return OR_NOMEM;
  1290. ZeroMemory(pArgs, sizeof(BINDINGS_UPDATE_CALLBACK_STUFF));
  1291. // Allocate binding. We must hold onto the binding handle
  1292. // until the async call has completed.
  1293. status = OR_NOMEM;
  1294. hBinding = AllocateBinding();
  1295. if (hBinding)
  1296. {
  1297. status = RpcBindingSetObject(hBinding, &NullUuid);
  1298. if (status == RPC_S_OK)
  1299. {
  1300. status = RpcAsyncInitializeHandle(&(pArgs->async), sizeof(pArgs->async));
  1301. }
  1302. }
  1303. // Check for errors
  1304. if (status != RPC_S_OK)
  1305. {
  1306. if (hBinding) FreeBinding(hBinding);
  1307. delete pArgs;
  1308. return status;
  1309. }
  1310. // Init parts of the RPC_ASYNC_STATE struct that we care about
  1311. pArgs->async.UserInfo = pArgs;
  1312. pArgs->async.Event = RpcCallComplete;
  1313. pArgs->async.NotificationType = RpcNotificationTypeCallback;
  1314. pArgs->async.u.NotificationRoutine = CProcess::AsyncRpcNotification;
  1315. // Init other stuff
  1316. pArgs->dwSig = BINDINGUPDATESTUFF_SIG;
  1317. pArgs->pProcess = this;
  1318. pArgs->dwBindingsID = dwBindingsID;
  1319. pArgs->hBinding = hBinding;
  1320. // Take a non-client reference (will not stop rundown) on
  1321. // ourselves, to be owned implicitly by the async call
  1322. this->Reference();
  1323. // Issue async call
  1324. status = ::UpdateResolverBindings(
  1325. &(pArgs->async),
  1326. _hProcess,
  1327. pdsaResolverBindings,
  1328. &(pArgs->dwBindingsID),
  1329. &(pArgs->pdsaNewBindings),
  1330. &(pArgs->pdsaNewSecurity));
  1331. if (status != RPC_S_OK)
  1332. {
  1333. // If we get anything other than RPC_S_OK back, that
  1334. // means we will not receive a call completion notif-
  1335. // ication. So, we need to cleanup everything up
  1336. // right here in that case.
  1337. FreeBinding(hBinding);
  1338. this->Release();
  1339. delete pArgs;
  1340. }
  1341. else
  1342. {
  1343. DWORD dwAUO = (DWORD)InterlockedIncrement((PLONG)&_dwAsyncUpdatesOutstanding);
  1344. // This assert is somewhat arbitrary, if it fires there are
  1345. // one of two things wrong: 1) the machine is so totally
  1346. // overstressed that the async calls are piling up and are not
  1347. // getting enough cpu time to complete; or 2) more likely, the
  1348. // process in question is deadlocked somehow.
  1349. ASSERT(dwAUO < 5000);
  1350. }
  1351. return status;
  1352. }
  1353. void
  1354. CProcess::BindingsUpdateNotify(RPC_BINDING_HANDLE hBinding,
  1355. DWORD64 dwBindingsID,
  1356. DUALSTRINGARRAY* pdsaNewBindings,
  1357. DUALSTRINGARRAY* pdsaSecBindings)
  1358. /*++
  1359. Routine Description:
  1360. Private helper function. This function is used to process a
  1361. successful return from an async call to the process to update
  1362. the bindings.
  1363. Arguments:
  1364. hBinding -- binding handle used to make the call. We now own it,
  1365. either to keep or to cleanup.
  1366. dwBindingsID -- unique id of the updated bindings. We use this
  1367. to resolve what to do when async calls arrive\return in an
  1368. out-of-order fashion.
  1369. pdsaNewBindings -- new bindings in use by the process. We now own
  1370. it, either to keep or to cleanup
  1371. pdsaSecBindings -- new security bindings in use by the process. We
  1372. now own it, either to keep or to cleanup.
  1373. Return Value:
  1374. void
  1375. --*/
  1376. {
  1377. RPC_STATUS status;
  1378. CMutexLock callback(&_csCallbackLock);
  1379. // Always free the binding
  1380. FreeBinding(hBinding);
  1381. // Only process the out-params if they contain newer bindings
  1382. // than what we currently have cached.
  1383. if ((dwBindingsID > _dwCurrentBindingsID) &&
  1384. pdsaNewBindings &&
  1385. pdsaSecBindings)
  1386. {
  1387. // The process has the right bindings, so update our counter
  1388. // no matter what happens in ProcessBindings.
  1389. _dwCurrentBindingsID = dwBindingsID;
  1390. status = ProcessBindings(pdsaNewBindings, pdsaSecBindings);
  1391. }
  1392. // Cleanup allocated out-params
  1393. if (pdsaNewBindings != NULL)
  1394. MIDL_user_free(pdsaNewBindings);
  1395. if (pdsaSecBindings != NULL)
  1396. MIDL_user_free(pdsaSecBindings);
  1397. InterlockedDecrement((PLONG)&_dwAsyncUpdatesOutstanding);
  1398. return;
  1399. }
  1400. void RPC_ENTRY
  1401. CProcess::AsyncRpcNotification(RPC_ASYNC_STATE* pAsync,
  1402. void* pContext,
  1403. RPC_ASYNC_EVENT Event)
  1404. /*++
  1405. Routine Description:
  1406. RPC calls this static function when an async call to a server
  1407. process returns.
  1408. Arguments:
  1409. pAsync -- pointer to the async rpc state struct
  1410. pContext -- rpc thingy, we ignore it
  1411. Return Value:
  1412. void
  1413. --*/
  1414. {
  1415. RPC_STATUS status;
  1416. HRESULT hrRetVal;
  1417. BINDINGS_UPDATE_CALLBACK_STUFF* pArgs;
  1418. pArgs = (BINDINGS_UPDATE_CALLBACK_STUFF*)
  1419. (((char*)pAsync) - offsetof(BINDINGS_UPDATE_CALLBACK_STUFF, async));
  1420. ASSERT(pArgs->async.UserInfo = pArgs);
  1421. ASSERT(pArgs->dwSig == BINDINGUPDATESTUFF_SIG);
  1422. ASSERT(pArgs->hBinding);
  1423. ASSERT(pArgs->pProcess);
  1424. ASSERT(pArgs->dwBindingsID > 0);
  1425. // Complete the call. Since we've asked for a direct callback upon
  1426. // completion, we should never get back RPC_S_ASYNC_CALL_PENDING, so
  1427. // we assert on this. Otherwise, both RPC and the server need to
  1428. // return success before we do further processing.
  1429. status = RpcAsyncCompleteCall(&(pArgs->async), &hrRetVal);
  1430. ASSERT(status != RPC_S_ASYNC_CALL_PENDING);
  1431. if ((status == RPC_S_OK) && (hrRetVal == S_OK))
  1432. {
  1433. // Deliver notification to process object. Process may have
  1434. // already been rundown, that's okay. BindingsUpdateNotify will
  1435. // own/cleanup the params, see code.
  1436. pArgs->pProcess->BindingsUpdateNotify(pArgs->hBinding,
  1437. pArgs->dwBindingsID,
  1438. pArgs->pdsaNewBindings,
  1439. pArgs->pdsaNewSecurity);
  1440. }
  1441. gpServerLock->LockExclusive();
  1442. // This may be the last release on the process object
  1443. pArgs->pProcess->Release();
  1444. gpServerLock->UnlockExclusive();
  1445. delete pArgs;
  1446. return;
  1447. }
  1448. CBList *gpProcessList = 0;
  1449. CProcess *
  1450. ReferenceProcess(
  1451. IN PVOID key,
  1452. IN BOOL fNotContext)
  1453. /*++
  1454. Routine Description:
  1455. Used to find a CProcess and get a reference on it
  1456. Arguments:
  1457. key - The dword key of the process allocated in _Connect.
  1458. fNotContext - Normally the key is stored as a context handle
  1459. which means locking is unnecessary. There is an extra
  1460. refernce which is released buring context rundown which
  1461. means managers using the key as a context handle
  1462. a) Don't need to lock the process and
  1463. b) Don't need to call ReleaseProcess()
  1464. Return Value:
  1465. 0 - invalid key
  1466. non-zero - The process.
  1467. --*/
  1468. {
  1469. ASSERT(gpProcessList != 0);
  1470. CProcess *pProcess;
  1471. gpProcessListLock->LockShared();
  1472. if (gpProcessList->Member(key) == FALSE)
  1473. {
  1474. gpProcessListLock->UnlockShared();
  1475. return(0);
  1476. }
  1477. pProcess = (CProcess *)key;
  1478. if (fNotContext)
  1479. {
  1480. pProcess->ClientReference();
  1481. }
  1482. gpProcessListLock->UnlockShared();
  1483. return(pProcess);
  1484. }
  1485. void ReleaseProcess(CProcess *pProcess)
  1486. /*++
  1487. Routine Description:
  1488. Releases a pProcess object. This should only be called when
  1489. a process object has been referenced with the fNotContext == TRUE.
  1490. Arguments:
  1491. pProcess - the process to release. May actually be deleted.
  1492. Return Value:
  1493. None
  1494. --*/
  1495. {
  1496. gpProcessListLock->LockExclusive();
  1497. if (pProcess->ClientRelease() == 0)
  1498. {
  1499. // Process has been completly released the process,
  1500. // we'll remove it from the list now since we
  1501. // already have the lock. It may not have been added,
  1502. // so this may fail.
  1503. PVOID t = gpProcessList->Remove(pProcess);
  1504. ASSERT(t == pProcess || t == 0);
  1505. gpProcessListLock->UnlockExclusive();
  1506. // The client process owns one real reference which will be
  1507. // released in Rundown().
  1508. pProcess->Rundown();
  1509. }
  1510. else
  1511. {
  1512. gpProcessListLock->UnlockExclusive();
  1513. }
  1514. }