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.

6137 lines
168 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. lpcclnt.cxx
  5. Abstract:
  6. Implementation of the RPC on LPC protocol engine for the client.
  7. Revision History:
  8. Mazhar Mohammed: Code fork from spcclnt.cxx, 08/02/95
  9. Tony Chan: Added Singled Security Model, 12/15/95
  10. Mazhar Mohammed Merged WMSG and LRPC into a single protocol 05-06-96
  11. Mazhar Mohammed Added Pipes Support
  12. Mazhar Mohammed Added support for Async RPC 08-14-96
  13. Kamen Moutafov (KamenM) Jan-2000 Support for multiple transfer syntaxes
  14. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 Support for cell debugging stuff
  15. Kamen Moutafov (KamenM) Mar-2000 Support for extended error info
  16. --*/
  17. #include <precomp.hxx>
  18. #include <rpcqos.h>
  19. #include <queue.hxx>
  20. #include <lpcpack.hxx>
  21. #include <hndlsvr.hxx>
  22. #include <lpcsvr.hxx>
  23. #include <ProtBind.hxx>
  24. #include <lpcclnt.hxx>
  25. #include <epmap.h>
  26. #include <CharConv.hxx>
  27. const SECURITY_IMPERSONATION_LEVEL RpcToNtImp[] =
  28. {
  29. // RPC_C_IMP_LEVEL_DEFAULT
  30. SecurityImpersonation,
  31. // RPC_C_IMP_LEVEL_ANONYMOUS
  32. SecurityAnonymous,
  33. // RPC_C_IMP_LEVEL_IDENTIFY
  34. SecurityIdentification,
  35. //RPC_C_IMP_LEVEL_IMPERSONATE
  36. SecurityImpersonation,
  37. //RPC_C_IMP_LEVEL_DELEGATE
  38. SecurityDelegation
  39. };
  40. const unsigned long NtToRpcImp[] =
  41. {
  42. //SecurityAnonymous,
  43. RPC_C_IMP_LEVEL_ANONYMOUS,
  44. //SecurityIdentification,
  45. RPC_C_IMP_LEVEL_IDENTIFY,
  46. // SecurityImpersonation,
  47. RPC_C_IMP_LEVEL_IMPERSONATE,
  48. //SecurityDelegation
  49. RPC_C_IMP_LEVEL_DELEGATE
  50. };
  51. SECURITY_IMPERSONATION_LEVEL
  52. MapRpcToNtImp (
  53. IN unsigned long ImpersonationType
  54. )
  55. {
  56. if (ImpersonationType <= RPC_C_IMP_LEVEL_DELEGATE)
  57. {
  58. return RpcToNtImp[ImpersonationType];
  59. }
  60. ASSERT(0) ;
  61. return SecurityImpersonation ;
  62. }
  63. unsigned long
  64. MapNtToRpcImp (
  65. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  66. )
  67. {
  68. if (ImpersonationLevel <= SecurityDelegation)
  69. {
  70. return NtToRpcImp[ImpersonationLevel];
  71. }
  72. ASSERT(0);
  73. return RPC_C_IMP_LEVEL_IMPERSONATE;
  74. }
  75. RPC_STATUS
  76. InitializeLrpcIfNecessary(
  77. ) ;
  78. RPC_STATUS
  79. InitializeAsyncLrpcIfNecessary (
  80. )
  81. /*++
  82. Routine Description:
  83. We need to perform the required initialization for Async RPC to
  84. work. If we currently don't have a listening thread. We need to
  85. add a note in the docs that if the app ever plans to start a
  86. listening thread on the client (ie: become a server),
  87. it should do it before it makes the first Async RPC call. This is
  88. not a requirement, it is just an effeciency consideration.
  89. Return Value:
  90. RPC_S_OK - Function succeeded
  91. RPC_S_OUT_OF_MEMORY - we ran out of memory
  92. --*/
  93. {
  94. RPC_STATUS Status;
  95. Status = InitializeLrpcIfNecessary();
  96. if (Status != RPC_S_OK)
  97. {
  98. #if DBG
  99. PrintToDebugger("LRPC: InitializeLrpcIfNecessary failed: %x\n", Status) ;
  100. #endif
  101. return RPC_S_OUT_OF_MEMORY ;
  102. }
  103. return GlobalLrpcServer->InitializeAsync();
  104. }
  105. LRPC_BINDING_HANDLE::LRPC_BINDING_HANDLE (
  106. OUT RPC_STATUS * Status
  107. ) : BINDING_HANDLE (Status),
  108. BindingReferenceCount(1)
  109. /*++
  110. Routine Description:
  111. We just allocate an LRPC_BINDING_HANDLE and initialize things so that
  112. we can use it later.
  113. Arguments:
  114. Status - Returns the result of initializing the binding mutex.
  115. --*/
  116. {
  117. BindingMutex.SetSpinCount(4000);
  118. ObjectType = LRPC_BINDING_HANDLE_TYPE;
  119. CurrentAssociation = 0;
  120. DceBinding = 0;
  121. AuthInfoInitialized = 0;
  122. StaticTokenHandle = 0;
  123. EffectiveOnly = TRUE;
  124. }
  125. LRPC_BINDING_HANDLE::~LRPC_BINDING_HANDLE (
  126. )
  127. /*++
  128. --*/
  129. {
  130. LRPC_CASSOCIATION *Association;
  131. DictionaryCursor cursor;
  132. if (SecAssociation.Size() != 0)
  133. {
  134. SecAssociation.Reset(cursor);
  135. while ((Association = SecAssociation.Next(cursor)) != 0)
  136. {
  137. if (Association != 0)
  138. {
  139. // take away from the bindinghandle dictionary
  140. RemoveAssociation(Association);
  141. // take away from the global dict
  142. Association->RemoveBindingHandleReference();
  143. }
  144. }
  145. }
  146. delete DceBinding;
  147. if (StaticTokenHandle)
  148. {
  149. CloseHandle(StaticTokenHandle);
  150. }
  151. }
  152. RPC_STATUS
  153. LRPC_BINDING_HANDLE::NegotiateTransferSyntax (
  154. IN OUT PRPC_MESSAGE Message
  155. )
  156. /*++
  157. Routine Description:
  158. Arguments:
  159. Message - Supplies the length of the buffer required, and returns the
  160. new buffer.
  161. Return Value:
  162. --*/
  163. {
  164. LRPC_CCALL * CCall;
  165. RPC_STATUS Status;
  166. int RetryCount = 0;
  167. static long nInitialized = -1 ;
  168. LRPC_CASSOCIATION *Association ;
  169. DictionaryCursor cursor;
  170. for (;;)
  171. {
  172. for (;;)
  173. {
  174. Status = AllocateCCall(&CCall, (RPC_CLIENT_INTERFACE *)
  175. Message->RpcInterfaceInformation,
  176. Message);
  177. if (Status != RPC_S_SERVER_UNAVAILABLE)
  178. {
  179. break;
  180. }
  181. if (!fDynamicEndpoint)
  182. {
  183. break;
  184. }
  185. // If we reach here, it means that we are iterating through the
  186. // list of endpoints obtained from the endpoint mapper.
  187. BindingMutex.Request() ;
  188. if (BindingReferenceCount.GetInteger() == 1)
  189. {
  190. if (SecAssociation.Size() != 0)
  191. {
  192. DceBinding = CurrentAssociation->DuplicateDceBinding();
  193. if(DceBinding == 0)
  194. {
  195. BindingMutex.Clear() ;
  196. return(RPC_S_OUT_OF_MEMORY);
  197. }
  198. CurrentAssociation = 0;
  199. DceBinding->MaybeMakePartiallyBound(
  200. (PRPC_CLIENT_INTERFACE)Message->RpcInterfaceInformation,
  201. InqPointerAtObjectUuid());
  202. if ( *InquireEpLookupHandle() != 0 )
  203. {
  204. EpFreeLookupHandle(*InquireEpLookupHandle());
  205. *InquireEpLookupHandle() = 0;
  206. }
  207. // remove references
  208. SecAssociation.Reset(cursor);
  209. while((Association = SecAssociation.Next(cursor)) != 0)
  210. {
  211. if (Association != 0)
  212. {
  213. // in the AssociationDict all DceBinding should be the same
  214. // may be we can take out this line. or remove ref
  215. // on the first Association
  216. RemoveAssociation(Association);
  217. Association->RemoveReference();
  218. }
  219. }
  220. }
  221. }
  222. BindingMutex.Clear() ;
  223. RetryCount ++;
  224. if (RetryCount > 2)
  225. {
  226. break;
  227. }
  228. RpcpPurgeEEInfo();
  229. }
  230. if (Status == RPC_S_OK)
  231. {
  232. break;
  233. }
  234. if (InqComTimeout() != RPC_C_BINDING_INFINITE_TIMEOUT)
  235. {
  236. return(Status);
  237. }
  238. if ((Status != RPC_S_SERVER_UNAVAILABLE)
  239. && (Status != RPC_S_SERVER_TOO_BUSY))
  240. {
  241. return(Status);
  242. }
  243. }
  244. Message->TransferSyntax = CCall->Binding->GetTransferSyntaxId();
  245. Message->Handle = CCall;
  246. return RPC_S_OK;
  247. }
  248. RPC_STATUS
  249. LRPC_BINDING_HANDLE::GetBuffer (
  250. IN OUT PRPC_MESSAGE Message,
  251. IN UUID *ObjectUuid
  252. )
  253. /*++
  254. Routine Description:
  255. Arguments:
  256. Message - Supplies the length of the buffer required, and returns the
  257. new buffer.
  258. Return Value:
  259. --*/
  260. {
  261. ASSERT(!"We should never be here - the binding handle cannot allocate a buffer");
  262. return RPC_S_INTERNAL_ERROR;
  263. }
  264. RPC_STATUS
  265. LRPC_BINDING_HANDLE::BindingCopy (
  266. OUT BINDING_HANDLE * * DestinationBinding,
  267. IN unsigned int MaintainContext
  268. )
  269. /*++
  270. Routine Description:
  271. We will make a copy of this binding handle in one of two ways, depending
  272. on whether on not this binding handle has an association.
  273. Arguments:
  274. DestinationBinding - Returns a copy of this binding handle.
  275. MaintainContext - Supplies a flag that indicates whether or not context
  276. is being maintained over this binding handle. A non-zero value
  277. indicates that context is being maintained.
  278. Return Value:
  279. RPC_S_OK - This binding handle has been successfully copied.
  280. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to make a copy
  281. of this binding handle.
  282. --*/
  283. {
  284. RPC_STATUS Status = RPC_S_OK;
  285. LRPC_BINDING_HANDLE * NewBindingHandle;
  286. CLIENT_AUTH_INFO * AuthInfo;
  287. LRPC_CASSOCIATION *SecAssoc;
  288. DictionaryCursor cursor;
  289. int Key;
  290. UNUSED(MaintainContext);
  291. NewBindingHandle = new LRPC_BINDING_HANDLE(&Status);
  292. if (NewBindingHandle == 0)
  293. {
  294. return(RPC_S_OUT_OF_MEMORY);
  295. }
  296. if (Status != RPC_S_OK)
  297. {
  298. delete NewBindingHandle;
  299. return(Status);
  300. }
  301. NewBindingHandle->fDynamicEndpoint = fDynamicEndpoint;
  302. if ((AuthInfo = InquireAuthInformation()) != 0)
  303. {
  304. Status = NewBindingHandle->SetAuthInformation(
  305. AuthInfo->ServerPrincipalName,
  306. AuthInfo->AuthenticationLevel,
  307. AuthInfo->AuthenticationService,
  308. NULL,
  309. AuthInfo->AuthorizationService,
  310. 0,
  311. AuthInfo->ImpersonationType,
  312. AuthInfo->IdentityTracking,
  313. AuthInfo->Capabilities
  314. );
  315. if (Status != RPC_S_OK)
  316. {
  317. ASSERT (Status == RPC_S_OUT_OF_MEMORY);
  318. delete NewBindingHandle;
  319. return(RPC_S_OUT_OF_MEMORY);
  320. }
  321. }
  322. BindingMutex.Request() ;
  323. if (SecAssociation.Size() == 0)
  324. {
  325. NewBindingHandle->DceBinding = DceBinding->DuplicateDceBinding();
  326. if (NewBindingHandle->DceBinding == 0)
  327. {
  328. BindingMutex.Clear() ;
  329. delete NewBindingHandle;
  330. return(RPC_S_OUT_OF_MEMORY);
  331. }
  332. }
  333. else
  334. {
  335. // copy all sec associations
  336. SecAssociation.Reset(cursor);
  337. while((SecAssoc = SecAssociation.Next(cursor)) != 0)
  338. {
  339. Key = NewBindingHandle->AddAssociation(SecAssoc);
  340. if (Key == -1)
  341. {
  342. BindingMutex.Clear() ;
  343. delete NewBindingHandle;
  344. return (RPC_S_OUT_OF_MEMORY);
  345. }
  346. SecAssoc->DuplicateAssociation();
  347. }
  348. // since the CurrentAssociation is in the SecAssociation dictionary,
  349. // it should have already been copied. Just assign it
  350. NewBindingHandle->CurrentAssociation = CurrentAssociation;
  351. }
  352. BindingMutex.Clear() ;
  353. *DestinationBinding = (BINDING_HANDLE *) NewBindingHandle;
  354. return(RPC_S_OK);
  355. }
  356. RPC_STATUS
  357. LRPC_BINDING_HANDLE::BindingFree (
  358. )
  359. /*++
  360. Routine Description:
  361. When the application is done with a binding handle, this routine will
  362. get called.
  363. Return Value:
  364. RPC_S_OK - This operation always succeeds.
  365. --*/
  366. {
  367. int LocalRefCount;
  368. LocalRefCount = BindingReferenceCount.Decrement();
  369. if (LocalRefCount == 0)
  370. {
  371. delete this;
  372. }
  373. return(RPC_S_OK);
  374. }
  375. RPC_STATUS
  376. LRPC_BINDING_HANDLE::PrepareBindingHandle (
  377. IN TRANS_INFO * TransportInformation,
  378. IN DCE_BINDING * DceBinding
  379. )
  380. /*++
  381. Routine Description:
  382. This method will be called just before a new binding handle is returned
  383. to the user. We just stack the binding information so that we can use
  384. it later when the first remote procedure call is made. At that time,
  385. we will actually bind to the interface.
  386. Arguments:
  387. TransportInformation - Unused.
  388. DceBinding - Supplies the binding information for this binding handle.
  389. --*/
  390. {
  391. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  392. RPC_STATUS Status;
  393. UNUSED(TransportInformation);
  394. if (DceBinding->InqNetworkOptions() != 0 &&
  395. DceBinding->InqNetworkOptions()[0] != 0)
  396. {
  397. Status = I_RpcParseSecurity(DceBinding->InqNetworkOptions(),
  398. &SecurityQualityOfService);
  399. if (Status != RPC_S_OK)
  400. {
  401. ASSERT(Status == RPC_S_INVALID_NETWORK_OPTIONS);
  402. return(Status);
  403. }
  404. Status = SetAuthInformation(NULL,
  405. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  406. RPC_C_AUTHN_WINNT,
  407. NULL,
  408. NULL,
  409. 0,
  410. MapNtToRpcImp(SecurityQualityOfService.ImpersonationLevel),
  411. SecurityQualityOfService.ContextTrackingMode,
  412. RPC_C_QOS_CAPABILITIES_DEFAULT,
  413. TRUE);
  414. if (Status != RPC_S_OK)
  415. {
  416. return Status;
  417. }
  418. EffectiveOnly = SecurityQualityOfService.EffectiveOnly;
  419. }
  420. this->DceBinding = DceBinding;
  421. fDynamicEndpoint = DceBinding->IsNullEndpoint();
  422. return RPC_S_OK;
  423. }
  424. RPC_STATUS
  425. LRPC_BINDING_HANDLE::ToStringBinding (
  426. OUT RPC_CHAR * * StringBinding
  427. )
  428. /*++
  429. Routine Description:
  430. We need to convert the binding handle into a string binding. If the
  431. handle is unbound, use the DceBinding directly, otherwise, get it from
  432. the association.
  433. Arguments:
  434. StringBinding - Returns the string representation of the binding
  435. handle.
  436. Return Value:
  437. RPC_S_OK - The binding handle has successfully been converted into a
  438. string binding.
  439. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate the
  440. string.
  441. --*/
  442. {
  443. if (CurrentAssociation == 0)
  444. {
  445. *StringBinding = DceBinding->StringBindingCompose(
  446. InqPointerAtObjectUuid());
  447. }
  448. else
  449. {
  450. *StringBinding = CurrentAssociation->StringBindingCompose(
  451. InqPointerAtObjectUuid());
  452. }
  453. if (*StringBinding == 0)
  454. {
  455. return(RPC_S_OUT_OF_MEMORY);
  456. }
  457. return(RPC_S_OK);
  458. }
  459. RPC_STATUS
  460. LRPC_BINDING_HANDLE::ResolveBinding (
  461. IN RPC_CLIENT_INTERFACE * RpcClientInterface
  462. )
  463. /*++
  464. Routine Description:
  465. We need to try and resolve the endpoint for this binding handle
  466. if necessary (the binding handle is partially-bound). If there is
  467. isn't a association allocated, call the binding management routines
  468. to do it.
  469. Arguments:
  470. RpcClientInterface - Supplies interface information to be used
  471. in resolving the endpoint.
  472. Return Value:
  473. RPC_S_OK - This binding handle is a full resolved binding handle.
  474. RPC_S_NO_ENDPOINT_FOUND - The endpoint can not be resolved.
  475. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to resolve
  476. the endpoint.
  477. EPT_S_NOT_REGISTERED - There are no more endpoints to be found
  478. for the specified combination of interface, network address,
  479. and lookup handle.
  480. EPT_S_CANT_PERFORM_OP - The operation failed due to misc. error e.g.
  481. unable to bind to the EpMapper.
  482. --*/
  483. {
  484. RPC_STATUS Status;
  485. if (CurrentAssociation == 0)
  486. {
  487. BindingMutex.Request();
  488. Status = DceBinding->ResolveEndpointIfNecessary(
  489. RpcClientInterface,
  490. InqPointerAtObjectUuid(),
  491. InquireEpLookupHandle(),
  492. FALSE,
  493. InqComTimeout(),
  494. INFINITE, // CallTimeout
  495. NULL // AuthInfo
  496. );
  497. BindingMutex.Clear();
  498. return(Status);
  499. }
  500. return(RPC_S_OK);
  501. }
  502. RPC_STATUS
  503. LRPC_BINDING_HANDLE::BindingReset (
  504. )
  505. /*++
  506. Routine Description:
  507. This routine will set the endpoint of this binding handle to zero,
  508. if possible. The binding handle will become partially bound as a
  509. result. If a remote procedure call has been made on this binding
  510. handle, it will fail as well.
  511. Return Value:
  512. RPC_S_OK - The binding handle has successfully been made partially
  513. bound.
  514. RPC_S_WRONG_KIND_OF_BINDING - The binding handle currently has remote
  515. procedure calls active.
  516. --*/
  517. {
  518. LRPC_CASSOCIATION *Association ;
  519. DictionaryCursor cursor;
  520. BindingMutex.Request() ;
  521. if (CurrentAssociation != 0)
  522. {
  523. if (BindingReferenceCount.GetInteger() != 1)
  524. {
  525. BindingMutex.Clear() ;
  526. return(RPC_S_WRONG_KIND_OF_BINDING);
  527. }
  528. DceBinding = CurrentAssociation->DuplicateDceBinding();
  529. if(DceBinding == 0)
  530. {
  531. BindingMutex.Clear() ;
  532. return(RPC_S_OUT_OF_MEMORY);
  533. }
  534. CurrentAssociation = 0;
  535. SecAssociation.Reset(cursor);
  536. while((Association = SecAssociation.Next(cursor)) != 0)
  537. {
  538. RemoveAssociation(Association);
  539. Association->RemoveBindingHandleReference();
  540. }
  541. }
  542. fDynamicEndpoint = TRUE;
  543. DceBinding->MakePartiallyBound();
  544. if (*InquireEpLookupHandle() != 0)
  545. {
  546. EpFreeLookupHandle(*InquireEpLookupHandle());
  547. *InquireEpLookupHandle() = 0;
  548. }
  549. BindingMutex.Clear() ;
  550. return(RPC_S_OK);
  551. }
  552. void
  553. LRPC_BINDING_HANDLE::FreeCCall (
  554. IN LRPC_CCALL * CCall
  555. )
  556. /*++
  557. Routine Description:
  558. This routine will get called to notify this binding handle that a remote
  559. procedure call on this binding handle has completed.
  560. Arguments:
  561. CCall - Supplies the remote procedure call which has completed.
  562. --*/
  563. {
  564. int LocalRefCount;
  565. CCall->InqAssociation()->FreeCCall(CCall);
  566. // do not touch the association beyond this. It could be freed.
  567. LocalRefCount = BindingReferenceCount.Decrement();
  568. if (LocalRefCount == 0)
  569. {
  570. delete this;
  571. }
  572. }
  573. RPC_STATUS
  574. LRPC_BINDING_HANDLE::AllocateCCall (
  575. OUT LRPC_CCALL ** CCall,
  576. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
  577. IN OUT PRPC_MESSAGE Message
  578. )
  579. /*++
  580. Routine Description:
  581. This method will allocate an LRPC_CCALL which has been bound to the
  582. interface specified by the interface information. First, we have got
  583. to see if we have an association for this binding. If not, we need
  584. to find or create one. Before we can find or create an association,
  585. we need to resolve the endpoint if necessary. Next we need to see
  586. if there is already an LRPC_CCALL allocated for this interface and
  587. thread. Otherwise, we need to ask the association to allocate a
  588. LRPC_CCALL for us.
  589. Arguments:
  590. CCall - Returns the allocated LRPC_CCALL which has been bound to
  591. the interface specified by the rpc interface information.
  592. RpcInterfaceInformation - Supplies information describing the
  593. interface to which we wish to bind.
  594. Return Value:
  595. --*/
  596. {
  597. RPC_STATUS Status;
  598. RPC_CHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  599. DWORD ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  600. BOOL Boolean;
  601. BOOL FoundSameAuthInfo = FALSE;
  602. LRPC_CASSOCIATION * Association;
  603. LRPC_CASSOCIATION *MyAssociation = NULL;
  604. DictionaryCursor cursor;
  605. int LocalRefCount;
  606. BindingMutex.Request();
  607. if (AuthInfoInitialized == 0)
  608. {
  609. Status = SetAuthInformation(NULL,
  610. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  611. RPC_C_AUTHN_WINNT,
  612. NULL,
  613. NULL,
  614. 0,
  615. RPC_C_IMP_LEVEL_IMPERSONATE,
  616. RPC_C_QOS_IDENTITY_DYNAMIC,
  617. RPC_C_QOS_CAPABILITIES_DEFAULT,
  618. TRUE);
  619. if (Status != RPC_S_OK)
  620. {
  621. BindingMutex.Clear();
  622. return Status;
  623. }
  624. }
  625. // First we need to check if there is already a call active for this
  626. // thread and interface. To make the common case quicker, we will check
  627. // to see if there are any calls in the dictionary first.
  628. if (RecursiveCalls.Size() != 0)
  629. {
  630. RecursiveCalls.Reset(cursor);
  631. while ((*CCall = RecursiveCalls.Next(cursor)) != 0)
  632. {
  633. if ((*CCall)->IsThisMyActiveCall(
  634. GetThreadIdentifier(),
  635. RpcInterfaceInformation) != 0)
  636. {
  637. BindingMutex.Clear();
  638. return(RPC_S_OK);
  639. }
  640. }
  641. }
  642. // To start off, see if the binding handle points to an association
  643. // yet. If not, we have got to get one.
  644. if (CurrentAssociation == 0)
  645. {
  646. // Before we even bother to find or create an association, lets
  647. // check to make sure that we are on the same machine as the server.
  648. ASSERT(DceBinding->InqNetworkAddress() != 0);
  649. if (DceBinding->InqNetworkAddress()[0] != 0)
  650. {
  651. Boolean = GetComputerName(ComputerName, &ComputerNameLength);
  652. #if DBG
  653. if (Boolean != TRUE)
  654. {
  655. PrintToDebugger("RPC : GetComputerName : %d\n",
  656. GetLastError());
  657. }
  658. #endif // DBG
  659. ASSERT(Boolean == TRUE);
  660. if (RpcpStringCompareInt(DceBinding->InqNetworkAddress(),
  661. ComputerName) != 0)
  662. {
  663. BindingMutex.Clear();
  664. RpcpErrorAddRecord(EEInfoGCRuntime,
  665. RPC_S_SERVER_UNAVAILABLE,
  666. EEInfoDLLRPC_BINDING_HANDLE__AllocateCCall10,
  667. DceBinding->InqNetworkAddress(),
  668. ComputerName);
  669. return(RPC_S_SERVER_UNAVAILABLE);
  670. }
  671. }
  672. if (DceBinding->IsNullEndpoint())
  673. {
  674. LrpcMutexRequest();
  675. MyAssociation = FindOrCreateLrpcAssociation(
  676. DceBinding,
  677. InquireAuthInformation(),
  678. RpcInterfaceInformation);
  679. LrpcMutexClear();
  680. // don't do anything in the both success and failure
  681. // case. In failure case we'll try full endpoint resolution
  682. // In success case, we leave FoundSameAuthInfo to be FALSE,
  683. // and the code below will figure out we have something
  684. // in MyAssociation and will do the housekeeping tasks
  685. // associated with finding an association
  686. ASSERT(DceBinding);
  687. }
  688. if (!MyAssociation)
  689. {
  690. Status = DceBinding->ResolveEndpointIfNecessary(
  691. RpcInterfaceInformation,
  692. InqPointerAtObjectUuid(),
  693. InquireEpLookupHandle(),
  694. FALSE,
  695. InqComTimeout(),
  696. INFINITE, // CallTimeout
  697. NULL // AuthInfo
  698. );
  699. if (Status != RPC_S_OK)
  700. {
  701. BindingMutex.Clear();
  702. RpcpErrorAddRecord(EEInfoGCRuntime,
  703. Status,
  704. EEInfoDLLRPC_BINDING_HANDLE__AllocateCCall20,
  705. RpcInterfaceInformation->InterfaceId.SyntaxGUID.Data1);
  706. return(Status);
  707. }
  708. }
  709. }
  710. else
  711. {
  712. if (CurrentAssociation->IsSupportedAuthInfo(
  713. InquireAuthInformation()) == TRUE)
  714. {
  715. MyAssociation = CurrentAssociation ;
  716. FoundSameAuthInfo = TRUE;
  717. }
  718. else
  719. {
  720. SecAssociation.Reset(cursor);
  721. while ((Association = SecAssociation.Next(cursor)) != 0)
  722. {
  723. if(Association->IsSupportedAuthInfo(
  724. InquireAuthInformation()) == TRUE)
  725. {
  726. MyAssociation = Association ;
  727. FoundSameAuthInfo = TRUE;
  728. break;
  729. }
  730. }
  731. }
  732. }
  733. if (FoundSameAuthInfo == FALSE)
  734. {
  735. // we have some association in the dictionary, check for security level
  736. if (DceBinding == 0)
  737. {
  738. SecAssociation.Reset(cursor);
  739. Association = SecAssociation.Next(cursor);
  740. // it will get deleted when Assoc goes
  741. DceBinding = Association->DuplicateDceBinding();
  742. if(DceBinding == 0)
  743. {
  744. BindingMutex.Clear() ;
  745. return(RPC_S_OUT_OF_MEMORY);
  746. }
  747. }
  748. // if we still haven't found the association
  749. // (may do so during the interface based search for
  750. // an endpoint).
  751. if (!MyAssociation)
  752. {
  753. LrpcMutexRequest();
  754. MyAssociation = FindOrCreateLrpcAssociation(
  755. DceBinding,
  756. InquireAuthInformation(),
  757. NULL);
  758. LrpcMutexClear();
  759. }
  760. if (CurrentAssociation == 0)
  761. {
  762. CurrentAssociation = MyAssociation ;
  763. }
  764. if (MyAssociation == 0)
  765. {
  766. BindingMutex.Clear();
  767. return(RPC_S_OUT_OF_MEMORY);
  768. }
  769. // The association now owns the DceBinding.
  770. DceBinding = 0;
  771. if((AddAssociation(MyAssociation)) == -1)
  772. {
  773. delete MyAssociation;
  774. if (CurrentAssociation == MyAssociation)
  775. {
  776. CurrentAssociation = 0;
  777. }
  778. BindingMutex.Clear();
  779. return (RPC_S_OUT_OF_MEMORY);
  780. }
  781. }
  782. BindingReferenceCount.Increment();
  783. BindingMutex.Clear();
  784. ASSERT(MyAssociation) ;
  785. Status = MyAssociation->AllocateCCall(
  786. this,
  787. CCall,
  788. Message,
  789. RpcInterfaceInformation);
  790. if (Status != RPC_S_OK)
  791. {
  792. LocalRefCount = BindingReferenceCount.Decrement();
  793. ASSERT(LocalRefCount != 0);
  794. }
  795. return(Status);
  796. }
  797. RPC_STATUS
  798. LRPC_BINDING_HANDLE::SetAuthInformation (
  799. IN RPC_CHAR * ServerPrincipalName, OPTIONAL
  800. IN unsigned long AuthenticationLevel,
  801. IN unsigned long AuthenticationService,
  802. IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity, OPTIONAL
  803. IN unsigned long AuthorizationService,
  804. IN SECURITY_CREDENTIALS * Credentials,
  805. IN unsigned long ImpersonationType,
  806. IN unsigned long IdentityTracking,
  807. IN unsigned long Capabilities,
  808. IN BOOL bAcquireNewCredentials,
  809. IN ULONG AdditionalTransportCredentialsType, OPTIONAL
  810. IN void *AdditionalCredentials OPTIONAL
  811. )
  812. /*++
  813. Routine Description:
  814. We set the authentication and authorization information in this binding
  815. handle.
  816. Arguments:
  817. ServerPrincipalName - Optionally supplies the server principal name.
  818. AuthenticationLevel - Supplies the authentication level to use.
  819. AuthenticationService - Supplies the authentication service to use.
  820. AuthIdentity - Optionally supplies the security context to use.
  821. AuthorizationService - Supplies the authorization service to use.
  822. AdditionalTransportCredentialsType - the type of additional credentials
  823. supplied in AdditionalCredentials. Not supported for LRPC.
  824. AdditionalCredentials - pointer to additional credentials if any. Not supported
  825. for LRPC.
  826. Return Value:
  827. RPC_S_OK - The supplied authentication and authorization information has
  828. been set in the binding handle.
  829. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  830. operation.
  831. RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
  832. not supported.
  833. RPC_S_UNKNOWN_AUTHN_LEVEL - The specified authentication level is
  834. not supported.
  835. RPC_S_INVALID_AUTH_IDENTITY - The specified security context (supplied
  836. by the auth identity argument) is invalid.
  837. RPC_S_UNKNOWN_AUTHZ_SERVICE - The specified authorization service is
  838. not supported.
  839. --*/
  840. {
  841. RPC_CHAR * NewString ;
  842. RPC_STATUS Status;
  843. SEC_WINNT_AUTH_IDENTITY *ntssp;
  844. HANDLE hToken;
  845. unsigned long MappedAuthenticationLevel;
  846. if ((AdditionalTransportCredentialsType != 0) || (AdditionalCredentials != NULL))
  847. return RPC_S_CANNOT_SUPPORT;
  848. if (AuthenticationLevel == RPC_C_AUTHN_LEVEL_DEFAULT)
  849. {
  850. AuthenticationLevel = RPC_C_AUTHN_LEVEL_CONNECT;
  851. }
  852. MappedAuthenticationLevel = MapAuthenticationLevel(AuthenticationLevel);
  853. if (AuthenticationLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
  854. {
  855. return(RPC_S_UNKNOWN_AUTHN_LEVEL);
  856. }
  857. ClientAuthInfo.AuthenticationLevel = MappedAuthenticationLevel;
  858. ClientAuthInfo.AuthenticationService = AuthenticationService;
  859. ClientAuthInfo.AuthIdentity = AuthIdentity;
  860. ClientAuthInfo.AuthorizationService = AuthorizationService;
  861. ClientAuthInfo.IdentityTracking = IdentityTracking;
  862. ClientAuthInfo.Capabilities = Capabilities;
  863. if (MappedAuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
  864. {
  865. ClientAuthInfo.ImpersonationType = RPC_C_IMP_LEVEL_ANONYMOUS;
  866. }
  867. else
  868. {
  869. ClientAuthInfo.ImpersonationType = ImpersonationType;
  870. }
  871. if (AuthenticationService == RPC_C_AUTHN_NONE)
  872. {
  873. AuthInfoInitialized = 0;
  874. return (RPC_S_OK);
  875. }
  876. if(AuthenticationService != RPC_C_AUTHN_WINNT)
  877. {
  878. return(RPC_S_UNKNOWN_AUTHN_SERVICE) ;
  879. }
  880. if (ARGUMENT_PRESENT(ServerPrincipalName) && *ServerPrincipalName)
  881. {
  882. NewString = DuplicateString(ServerPrincipalName);
  883. if ( NewString == 0 )
  884. {
  885. return(RPC_S_OUT_OF_MEMORY);
  886. }
  887. BindingMutex.Request();
  888. if ( ClientAuthInfo.ServerPrincipalName != 0 )
  889. {
  890. delete ClientAuthInfo.ServerPrincipalName;
  891. }
  892. ClientAuthInfo.ServerPrincipalName = NewString;
  893. BindingMutex.Clear();
  894. }
  895. if (IdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  896. {
  897. if (StaticTokenHandle)
  898. {
  899. CloseHandle(StaticTokenHandle);
  900. }
  901. if (OpenThreadToken (GetCurrentThread(),
  902. TOKEN_IMPERSONATE | TOKEN_QUERY,
  903. TRUE,
  904. &StaticTokenHandle) == FALSE)
  905. {
  906. StaticTokenHandle = 0;
  907. }
  908. Status = ReAcquireCredentialsIfNecessary();
  909. if (Status != RPC_S_OK)
  910. {
  911. return Status;
  912. }
  913. }
  914. AuthInfoInitialized = 1;
  915. return(RPC_S_OK);
  916. }
  917. unsigned long
  918. LRPC_BINDING_HANDLE::MapAuthenticationLevel (
  919. IN unsigned long AuthenticationLevel
  920. )
  921. /*++
  922. Routine Description:
  923. The connection oriented protocol module supports all authentication
  924. levels except for RPC_C_AUTHN_LEVEL_CALL. We just need to map it
  925. to RPC_C_AUTHN_LEVEL_PKT.
  926. --*/
  927. {
  928. UNUSED(this);
  929. if (AuthenticationLevel >= RPC_C_AUTHN_LEVEL_CONNECT)
  930. {
  931. return(RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
  932. }
  933. return(AuthenticationLevel);
  934. }
  935. inline int
  936. LRPC_BINDING_HANDLE::AddAssociation (
  937. IN LRPC_CASSOCIATION * Association
  938. )
  939. /*++
  940. Routine Description:
  941. This supplied remote procedure call needs to be put into the dictionary
  942. of association
  943. --*/
  944. {
  945. int err;
  946. BindingMutex.Request() ;
  947. err = SecAssociation.Insert(Association) ;
  948. BindingMutex.Clear() ;
  949. return(err);
  950. }
  951. inline void
  952. LRPC_BINDING_HANDLE::RemoveAssociation (
  953. IN LRPC_CASSOCIATION * Association
  954. )
  955. /*++
  956. Routine Description:
  957. Remove Association from BindingHandle, can keep a Key for Association because
  958. 1 association may be added to many BINDINGHANDLE::SecAssociationDict, 1 key per
  959. Association won't do the job. Therefore, we delete Association this way.
  960. Remember, there will be 5 Association in the SecAssoc the most, 1 per SecurityLevel
  961. --*/
  962. {
  963. BindingMutex.Request() ;
  964. SecAssociation.DeleteItemByBruteForce(Association);
  965. BindingMutex.Clear() ;
  966. }
  967. RPC_STATUS
  968. LRPC_BINDING_HANDLE::SetTransportOption( IN unsigned long option,
  969. IN ULONG_PTR optionValue )
  970. {
  971. if (option == RPC_C_OPT_DONT_LINGER)
  972. {
  973. if (CurrentAssociation == NULL)
  974. return RPC_S_WRONG_KIND_OF_BINDING;
  975. if (CurrentAssociation->GetDontLingerState())
  976. return RPC_S_WRONG_KIND_OF_BINDING;
  977. CurrentAssociation->SetDontLingerState((BOOL)optionValue);
  978. return RPC_S_OK;
  979. }
  980. else
  981. {
  982. return BINDING_HANDLE::SetTransportOption(option, optionValue);
  983. }
  984. }
  985. RPC_STATUS
  986. LRPC_BINDING_HANDLE::InqTransportOption( IN unsigned long option,
  987. OUT ULONG_PTR * pOptionValue )
  988. {
  989. if (option == RPC_C_OPT_DONT_LINGER)
  990. {
  991. if (CurrentAssociation == NULL)
  992. return RPC_S_WRONG_KIND_OF_BINDING;
  993. *pOptionValue = CurrentAssociation->GetDontLingerState();
  994. return RPC_S_OK;
  995. }
  996. else
  997. {
  998. return BINDING_HANDLE::InqTransportOption(option, pOptionValue);
  999. }
  1000. }
  1001. MTSyntaxBinding *CreateLrpcBinding(
  1002. IN RPC_SYNTAX_IDENTIFIER *InterfaceId,
  1003. IN TRANSFER_SYNTAX_STUB_INFO *TransferSyntaxInfo,
  1004. IN int CapabilitiesBitmap
  1005. )
  1006. {
  1007. return new LRPC_BINDING(InterfaceId,
  1008. TransferSyntaxInfo,
  1009. CapabilitiesBitmap);
  1010. }
  1011. // protected by the LrpcMutex
  1012. LRPC_CASSOCIATION_DICT * LrpcAssociationDict = 0;
  1013. long LrpcLingeredAssociations = 0;
  1014. unsigned long LrpcDestroyedAssociations = 0;
  1015. ULARGE_INTEGER LastDestroyedAssociationsBatchTimestamp;
  1016. LRPC_CASSOCIATION::LRPC_CASSOCIATION (
  1017. IN DCE_BINDING * DceBinding,
  1018. IN CLIENT_AUTH_INFO *pClientAuthInfo,
  1019. USHORT MySequenceNumber,
  1020. OUT RPC_STATUS * Status
  1021. ) : AssociationMutex(Status, 4000),
  1022. AssocAuthInfo(pClientAuthInfo, Status)
  1023. /*++
  1024. Routine Description:
  1025. This association will be initialized, so that it is ready to be
  1026. placed into the dictionary of associations.
  1027. Arguments:
  1028. DceBinding - Supplies the DCE_BINDING which will name this association.
  1029. Status - Returns the result of creating the association mutex.
  1030. --*/
  1031. {
  1032. ObjectType = LRPC_CASSOCIATION_TYPE;
  1033. this->DceBinding = DceBinding;
  1034. LpcClientPort = 0;
  1035. LpcReceivePort = 0;
  1036. BackConnectionCreated = 0;
  1037. CallIdCounter = 1;
  1038. SequenceNumber = MySequenceNumber;
  1039. Linger.fAssociationLingered = FALSE;
  1040. DeletedContextCount = 0;
  1041. BindingHandleReferenceCount = 1;
  1042. RefCount.SetInteger(2);
  1043. CachedCCall = NULL;
  1044. DontLinger = FALSE;
  1045. LastSecContextTrimmingTimestamp = 0;
  1046. if (*Status == RPC_S_OK)
  1047. {
  1048. CachedCCall = new LRPC_CCALL(Status);
  1049. if (*Status == RPC_S_OK)
  1050. {
  1051. if (CachedCCall == 0)
  1052. {
  1053. *Status = RPC_S_OUT_OF_MEMORY ;
  1054. return;
  1055. }
  1056. CachedCCall->SetAssociation(this);
  1057. CachedCCallFlag = 1;
  1058. }
  1059. }
  1060. }
  1061. LRPC_CASSOCIATION::~LRPC_CASSOCIATION (
  1062. )
  1063. {
  1064. LRPC_BINDING * Binding;
  1065. LRPC_CCALL * CCall ;
  1066. LRPC_CCONTEXT *SecurityContext;
  1067. DictionaryCursor cursor;
  1068. if (DceBinding != 0)
  1069. {
  1070. delete DceBinding;
  1071. }
  1072. Bindings.Reset(cursor);
  1073. while ((Binding = Bindings.RemoveNext(cursor)) != 0)
  1074. {
  1075. Binding->RemoveReference();
  1076. }
  1077. SecurityContextDict.Reset(cursor);
  1078. while (SecurityContext = SecurityContextDict.RemoveNext(cursor))
  1079. {
  1080. delete SecurityContext;
  1081. }
  1082. // delete all CCalls
  1083. ActiveCCalls.Reset(cursor) ;
  1084. while ((CCall = ActiveCCalls.Next(cursor, TRUE)) != 0)
  1085. {
  1086. delete CCall ;
  1087. }
  1088. if (CachedCCallFlag != 0)
  1089. {
  1090. delete CachedCCall;
  1091. }
  1092. FreeCCalls.Reset(cursor);
  1093. while ((CCall = FreeCCalls.Next(cursor)) != 0)
  1094. {
  1095. delete CCall;
  1096. }
  1097. CloseLpcClientPort();
  1098. }
  1099. RPC_STATUS
  1100. LRPC_CASSOCIATION::CreateBackConnection (
  1101. IN LRPC_BINDING_HANDLE *BindingHandle
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Ask the server to create a back connection to us. Used in
  1106. conjuction with Async RPC.
  1107. Return Value:
  1108. RPC_S_OK - Function succeeded
  1109. RPC_S_OUT_OF_MEMORY - we ran out of memory
  1110. --*/
  1111. {
  1112. #if defined(BUILD_WOW6432)
  1113. char LrpcMessageBuffer[sizeof(LRPC_BIND_BACK_MESSAGE) + 8];
  1114. char LrpcReplyBuffer[sizeof(LRPC_MESSAGE) + 8];
  1115. LRPC_BIND_BACK_MESSAGE *LrpcMessagePtr = (LRPC_BIND_BACK_MESSAGE *) AlignPtr8(LrpcMessageBuffer);
  1116. LRPC_MESSAGE *LrpcReplyPtr = (LRPC_MESSAGE *)AlignPtr8(LrpcReplyBuffer);
  1117. #else
  1118. LRPC_BIND_BACK_MESSAGE LrpcMessageBuffer;
  1119. LRPC_MESSAGE LrpcReplyBuffer;
  1120. LRPC_BIND_BACK_MESSAGE *LrpcMessagePtr = &LrpcMessageBuffer;
  1121. LRPC_MESSAGE *LrpcReplyPtr = &LrpcReplyBuffer;
  1122. #endif
  1123. NTSTATUS NtStatus ;
  1124. RPC_STATUS Status = RPC_S_OK;
  1125. if (BackConnectionCreated == 0)
  1126. {
  1127. Status = AssociationMutex.RequestSafe() ;
  1128. if (Status)
  1129. return Status;
  1130. if (BackConnectionCreated)
  1131. {
  1132. AssociationMutex.Clear() ;
  1133. return RPC_S_OK ;
  1134. }
  1135. if (LpcClientPort == 0)
  1136. {
  1137. Status = OpenLpcPort(BindingHandle, TRUE) ;
  1138. if (Status != RPC_S_OK)
  1139. {
  1140. AssociationMutex.Clear() ;
  1141. RpcpErrorAddRecord(EEInfoGCRuntime,
  1142. Status,
  1143. EEInfoDLLRPC_CASSOCIATION__CreateBackConnection10,
  1144. InqEndpoint());
  1145. return Status ;
  1146. }
  1147. }
  1148. else
  1149. {
  1150. LrpcGetEndpoint((RPC_CHAR *) LrpcMessagePtr->szPortName) ;
  1151. LrpcMessagePtr->LpcHeader.u1.s1.DataLength =
  1152. sizeof(LRPC_BIND_BACK_MESSAGE) - sizeof(PORT_MESSAGE);
  1153. LrpcMessagePtr->LpcHeader.u1.s1.TotalLength =
  1154. sizeof(LRPC_BIND_BACK_MESSAGE);
  1155. LrpcMessagePtr->LpcHeader.u2.ZeroInit = 0;
  1156. LrpcMessagePtr->MessageType = LRPC_MSG_BIND_BACK;
  1157. DWORD Key;
  1158. LPC_KEY *LpcKey = (LPC_KEY *) &Key;
  1159. LpcKey->SeqNumber = SequenceNumber;
  1160. LpcKey->AssocKey = (unsigned short) AssociationDictKey;
  1161. LrpcMessagePtr->AssocKey = Key;
  1162. NtStatus = NtRequestWaitReplyPort(LpcClientPort,
  1163. (PORT_MESSAGE *) LrpcMessagePtr,
  1164. (PORT_MESSAGE *) LrpcReplyPtr) ;
  1165. if (NT_ERROR(NtStatus))
  1166. {
  1167. AssociationMutex.Clear() ;
  1168. if (NtStatus == STATUS_NO_MEMORY)
  1169. {
  1170. Status = RPC_S_OUT_OF_MEMORY;
  1171. }
  1172. else if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  1173. {
  1174. Status = RPC_S_OUT_OF_RESOURCES;
  1175. }
  1176. else
  1177. {
  1178. VALIDATE(NtStatus)
  1179. {
  1180. STATUS_INVALID_PORT_HANDLE,
  1181. STATUS_INVALID_HANDLE,
  1182. STATUS_PORT_DISCONNECTED,
  1183. STATUS_LPC_REPLY_LOST
  1184. } END_VALIDATE;
  1185. Status = RPC_S_SERVER_UNAVAILABLE;
  1186. }
  1187. RpcpErrorAddRecord(EEInfoGCLPC,
  1188. Status,
  1189. EEInfoDLLRPC_CASSOCIATION__CreateBackConnection20,
  1190. NtStatus);
  1191. return (Status);
  1192. }
  1193. ASSERT(LrpcReplyPtr->Ack.MessageType == LRPC_MSG_ACK) ;
  1194. if (LrpcReplyPtr->Ack.RpcStatus != RPC_S_OK)
  1195. {
  1196. AssociationMutex.Clear() ;
  1197. RpcpErrorAddRecord(EEInfoGCRuntime,
  1198. LrpcReplyPtr->Ack.RpcStatus,
  1199. EEInfoDLLRPC_CASSOCIATION__CreateBackConnection30);
  1200. return LrpcReplyPtr->Ack.RpcStatus;
  1201. }
  1202. }
  1203. BackConnectionCreated = 1 ;
  1204. AssociationMutex.Clear() ;
  1205. }
  1206. return Status ;
  1207. }
  1208. void
  1209. LRPC_CASSOCIATION::RemoveBindingHandleReference (
  1210. void
  1211. )
  1212. {
  1213. BOOL fWillLinger = FALSE;
  1214. LRPC_CASSOCIATION *CurrentAssociation;
  1215. LRPC_CASSOCIATION *OldestAssociation = NULL;
  1216. DWORD OldestAssociationTimestamp;
  1217. DictionaryCursor cursor;
  1218. BOOL fEnableGarbageCollection = FALSE;
  1219. LrpcMutexRequest();
  1220. LogEvent(SU_CASSOC, EV_DEC, this, 0, BindingHandleReferenceCount, 1, 1);
  1221. BindingHandleReferenceCount --;
  1222. if (BindingHandleReferenceCount == 0)
  1223. {
  1224. if (LpcClientPort && IsGarbageCollectionAvailable() && (!DontLinger))
  1225. {
  1226. fWillLinger = PrepareForLoopbackTicklingIfNecessary();
  1227. if (fWillLinger)
  1228. {
  1229. if (LrpcLingeredAssociations >= MaxLrpcLingeredAssociations)
  1230. {
  1231. OldestAssociationTimestamp = ~(DWORD)0;
  1232. // need to walk the dictionary and clean up the oldest item
  1233. LrpcAssociationDict->Reset(cursor);
  1234. while ((CurrentAssociation = LrpcAssociationDict->Next(cursor)) != 0)
  1235. {
  1236. if (CurrentAssociation->Linger.fAssociationLingered)
  1237. {
  1238. // yes, if the tick count wraps around, we may make a
  1239. // suboptimal decision and destroy a newer lingering
  1240. // association. That's ok - it will be a slight perf hit once
  1241. // every ~47 days - it won't be a bug
  1242. if (OldestAssociationTimestamp > CurrentAssociation->Linger.Timestamp)
  1243. {
  1244. OldestAssociation = CurrentAssociation;
  1245. }
  1246. }
  1247. }
  1248. // there must be an oldest association here
  1249. ASSERT(OldestAssociation);
  1250. LrpcAssociationDict->Delete(OldestAssociation->AssociationDictKey);
  1251. OldestAssociation->AssociationDictKey = -1;
  1252. // no need to update LrpcLingeredAssociations - we removed one,
  1253. // but we add one, so the balance is the same
  1254. }
  1255. else
  1256. {
  1257. LrpcLingeredAssociations ++;
  1258. ASSERT(LrpcLingeredAssociations <= MaxLrpcLingeredAssociations);
  1259. }
  1260. Linger.Timestamp = GetTickCount() + gThreadTimeout;
  1261. Linger.fAssociationLingered = TRUE;
  1262. }
  1263. }
  1264. if (!fWillLinger)
  1265. {
  1266. LrpcDestroyedAssociations ++;
  1267. fEnableGarbageCollection = CheckIfGCShouldBeTurnedOn(
  1268. LrpcDestroyedAssociations,
  1269. NumberOfLrpcDestroyedAssociationsToSample,
  1270. DestroyedLrpcAssociationBatchThreshold,
  1271. &LastDestroyedAssociationsBatchTimestamp
  1272. );
  1273. Delete();
  1274. }
  1275. }
  1276. LrpcMutexClear();
  1277. if (fEnableGarbageCollection)
  1278. {
  1279. // ignore the return value - we'll make a best effort to
  1280. // create the thread, but if there's no memory, that's
  1281. // still ok as the garbage collection thread only
  1282. // provides better perf in this case
  1283. (void) CreateGarbageCollectionThread();
  1284. }
  1285. if (OldestAssociation)
  1286. {
  1287. #if defined (RPC_GC_AUDIT)
  1288. int Diff;
  1289. Diff = (int)(GetTickCount() - OldestAssociation->Linger.Timestamp);
  1290. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC association sync gc'ed %d ms after expire\n",
  1291. GetCurrentProcessId(), GetCurrentProcessId(), Diff);
  1292. #endif
  1293. OldestAssociation->Delete();
  1294. }
  1295. if (fWillLinger)
  1296. {
  1297. fWillLinger = GarbageCollectionNeeded(TRUE, gThreadTimeout);
  1298. if (fWillLinger == FALSE)
  1299. {
  1300. // uh-oh - we couldn't register for garbage collection - probably
  1301. // extremely low on memory. If nobody has picked us up in the meantime,
  1302. // delete this association. Otherwise, let it go - somebody is using
  1303. // it and we don't need to worry about gc'ing it. We also need to guard
  1304. // against the gc thread trying to do Delete on this also. If it does
  1305. // so, it will set the AssociationDictKey to -1 before it releases
  1306. // the mutex - therefore we can check for this. A gc thread cannot
  1307. // completely kill the object as we will hold one reference on it
  1308. LrpcMutexRequest();
  1309. if (AssociationDictKey != -1)
  1310. {
  1311. LrpcLingeredAssociations --;
  1312. ASSERT(LrpcLingeredAssociations >= 0);
  1313. if (Linger.fAssociationLingered)
  1314. Delete();
  1315. }
  1316. LrpcMutexClear();
  1317. }
  1318. #if defined (RPC_GC_AUDIT)
  1319. else
  1320. {
  1321. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC association lingered %X\n",
  1322. GetCurrentProcessId(), GetCurrentProcessId(), this);
  1323. }
  1324. #endif
  1325. }
  1326. // removing the reference should be the last thing to do. Otherwise we're racing
  1327. // with a gc thread which may kill the this pointer underneath us
  1328. REFERENCED_OBJECT::RemoveReference();
  1329. }
  1330. void LRPC_CASSOCIATION::Delete(void)
  1331. {
  1332. int MyCount;
  1333. if (SetDeletedFlag())
  1334. {
  1335. if (AssociationDictKey != -1)
  1336. {
  1337. LrpcMutexRequest();
  1338. LrpcAssociationDict->Delete(AssociationDictKey);
  1339. LrpcMutexClear();
  1340. }
  1341. REFERENCED_OBJECT::RemoveReference();
  1342. }
  1343. }
  1344. BOOL
  1345. LRPC_CASSOCIATION::DoesBindingForInterfaceExist (
  1346. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  1347. )
  1348. /*++
  1349. Routine Description:
  1350. Checks if an association supports a binding for this interface.
  1351. Arguments:
  1352. RpcInterfaceInformation - Supplies the interface information for
  1353. which we are looking for an osf binding object.
  1354. Return Value:
  1355. FALSE if it doesn't. Non-zero if it does.
  1356. --*/
  1357. {
  1358. LRPC_BINDING *Binding;
  1359. DictionaryCursor cursor;
  1360. BOOL fRetVal = FALSE;
  1361. BOOL fMutexTaken;
  1362. fMutexTaken = AssociationMutex.TryRequest();
  1363. if (!fMutexTaken)
  1364. return FALSE;
  1365. Bindings.Reset(cursor);
  1366. while ((Binding = Bindings.Next(cursor)) != 0)
  1367. {
  1368. // if we have a binding on the same interface,
  1369. // return TRUE
  1370. if (RpcpMemoryCompare(Binding->GetInterfaceId(),
  1371. &RpcInterfaceInformation->InterfaceId,
  1372. sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  1373. {
  1374. fRetVal = TRUE;
  1375. break;
  1376. }
  1377. }
  1378. AssociationMutex.Clear();
  1379. return fRetVal;
  1380. }
  1381. RPC_STATUS
  1382. LRPC_CASSOCIATION::AllocateCCall (
  1383. IN LRPC_BINDING_HANDLE *BindingHandle,
  1384. OUT LRPC_CCALL ** CCall,
  1385. IN OUT PRPC_MESSAGE Message,
  1386. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. This method will allocate an LRPC_CCALL which has been bound to the
  1391. interface specified by the interface information. This means that
  1392. first we need to find the presentation context corresponding to the
  1393. requested interface.
  1394. Arguments:
  1395. CCall - Returns the allocated LRPC_CCALL which has been bound to
  1396. the interface specified by the rpc interface information.
  1397. RpcInterfaceInformation - Supplies information describing the
  1398. interface to which we wish to bind.
  1399. Return Value:
  1400. --*/
  1401. {
  1402. LRPC_BINDING *SelectedBinding;
  1403. int RetryCount;
  1404. RPC_STATUS Status;
  1405. LRPC_CCONTEXT *SecurityContext;
  1406. BOOL fAlterSecurityContextNeeded = FALSE;
  1407. BOOL fAlterContextNeeded = FALSE;
  1408. LRPC_CCONTEXT *CurrentSecurityContext = NULL;
  1409. BOOL fUpdateCredentials = FALSE;
  1410. LUID CurrentModifiedId;
  1411. DictionaryCursor cursor;
  1412. LRPC_BINDING *BindingsForThisInterface[MaximumNumberOfTransferSyntaxes];
  1413. int NumberOfBindingsAvailable;
  1414. BOOL BindingCreated[MaximumNumberOfTransferSyntaxes];
  1415. int i;
  1416. int PreferredTransferSyntax;
  1417. int MatchingTransferSyntax;
  1418. BOOL IsBackConnectionNeeded = IsNonsyncMessage(Message);
  1419. RPC_STATUS CaptureStatus;
  1420. LRPC_BINDING *CurrentBinding;
  1421. BOOL fAssociationAborted = FALSE;
  1422. ULONG EffectiveIdentityTracking;
  1423. if (IsBackConnectionNeeded)
  1424. {
  1425. CLIENT_AUTH_INFO * AuthInfo;
  1426. AuthInfo = BindingHandle->InquireAuthInformation();
  1427. ASSERT(AuthInfo);
  1428. if (AuthInfo->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
  1429. {
  1430. CaptureStatus = CaptureModifiedId(&CurrentModifiedId);
  1431. fUpdateCredentials = TRUE;
  1432. }
  1433. }
  1434. Status = AssociationMutex.RequestSafe();
  1435. if (Status)
  1436. return Status;
  1437. if (fUpdateCredentials)
  1438. {
  1439. BindingHandle->UpdateCredentials((CaptureStatus != RPC_S_OK), &CurrentModifiedId);
  1440. }
  1441. RetryCount = 0;
  1442. EffectiveIdentityTracking = BindingHandle->GetIdentityTracking();
  1443. do
  1444. {
  1445. //
  1446. // We need to look at two things here. Presentation context
  1447. // and security context (in the async dynamic case only). If both match
  1448. // then we can allocate the call. Otherwise, we need to first bind
  1449. // in order to negotiate the interface/presentation context.
  1450. //
  1451. if (IsBackConnectionNeeded
  1452. || EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  1453. {
  1454. SecurityContextDict.Reset(cursor);
  1455. while (SecurityContext = SecurityContextDict.Next(cursor))
  1456. {
  1457. if (BindingHandle->CompareCredentials(SecurityContext))
  1458. {
  1459. CurrentSecurityContext = SecurityContext;
  1460. CurrentSecurityContext->AddReference();
  1461. CurrentSecurityContext->UpdateTimestamp();
  1462. break;
  1463. }
  1464. }
  1465. if (SecurityContext == 0)
  1466. {
  1467. fAlterSecurityContextNeeded = TRUE;
  1468. }
  1469. }
  1470. Status = MTSyntaxBinding::FindOrCreateBinding(RpcInterfaceInformation,
  1471. Message, &Bindings, CreateLrpcBinding, &NumberOfBindingsAvailable,
  1472. (MTSyntaxBinding **)BindingsForThisInterface, BindingCreated);
  1473. if (Status != RPC_S_OK)
  1474. {
  1475. goto Cleanup;
  1476. }
  1477. PreferredTransferSyntax = -1;
  1478. MatchingTransferSyntax = -1;
  1479. for (i = 0; i < NumberOfBindingsAvailable; i ++)
  1480. {
  1481. // do we support the preferred server
  1482. if (BindingsForThisInterface[i]->IsTransferSyntaxServerPreferred())
  1483. {
  1484. PreferredTransferSyntax = i;
  1485. break;
  1486. }
  1487. else if ((BindingCreated[i] == FALSE) && (MatchingTransferSyntax < 0))
  1488. {
  1489. MatchingTransferSyntax = i;
  1490. }
  1491. }
  1492. // is there a syntax preferred by the server
  1493. if (PreferredTransferSyntax >= 0)
  1494. {
  1495. // do we already support it (i.e. the binding was not created)
  1496. if (BindingCreated[PreferredTransferSyntax] == FALSE)
  1497. {
  1498. // then we're all set - just use it
  1499. fAlterContextNeeded = FALSE;
  1500. SelectedBinding = BindingsForThisInterface[PreferredTransferSyntax];
  1501. }
  1502. else
  1503. {
  1504. // we don't support it - negotiate it. We know this
  1505. // will succeed, because the server preferences
  1506. // are set. This should be hit in the auto-retry case only
  1507. fAlterContextNeeded = TRUE;
  1508. ASSERT(_NOT_COVERED_);
  1509. }
  1510. }
  1511. else
  1512. {
  1513. // no preferred syntax - any will do. Check if we found anything supported
  1514. if (MatchingTransferSyntax >= 0)
  1515. {
  1516. SelectedBinding = BindingsForThisInterface[MatchingTransferSyntax];
  1517. fAlterContextNeeded = FALSE;
  1518. }
  1519. else
  1520. {
  1521. fAlterContextNeeded = TRUE;
  1522. }
  1523. }
  1524. if (fAlterContextNeeded == FALSE)
  1525. {
  1526. if (IsBackConnectionNeeded)
  1527. {
  1528. Status = InitializeAsyncLrpcIfNecessary() ;
  1529. if (Status == RPC_S_OK)
  1530. {
  1531. Status = CreateBackConnection(BindingHandle);
  1532. }
  1533. if (Status != RPC_S_OK)
  1534. {
  1535. goto Cleanup;
  1536. }
  1537. }
  1538. }
  1539. if (fAlterContextNeeded || fAlterSecurityContextNeeded)
  1540. {
  1541. Status = ActuallyDoBinding(
  1542. BindingHandle,
  1543. IsBackConnectionNeeded,
  1544. fAlterContextNeeded,
  1545. fAlterSecurityContextNeeded,
  1546. BindingHandle->ClientAuthInfo.DefaultLogonId,
  1547. NumberOfBindingsAvailable,
  1548. BindingsForThisInterface,
  1549. &SelectedBinding,
  1550. &CurrentSecurityContext);
  1551. if (Status != RPC_S_SERVER_UNAVAILABLE)
  1552. {
  1553. fAssociationAborted = FALSE;
  1554. break;
  1555. }
  1556. // The server appears to have gone away, close the port and retry.
  1557. RetryCount++;
  1558. SelectedBinding = 0;
  1559. // both the creation in ActuallyDoBinding and the
  1560. // retrieval from the cache will add a refcount -
  1561. // remove it
  1562. if (CurrentSecurityContext)
  1563. {
  1564. CurrentSecurityContext->RemoveReference();
  1565. CurrentSecurityContext = NULL;
  1566. }
  1567. fAlterContextNeeded = TRUE;
  1568. if (IsBackConnectionNeeded
  1569. || EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  1570. {
  1571. fAlterSecurityContextNeeded = TRUE;
  1572. }
  1573. AbortAssociation();
  1574. if (RetryCount < 3)
  1575. {
  1576. RpcpPurgeEEInfo();
  1577. }
  1578. fAssociationAborted = TRUE;
  1579. }
  1580. else
  1581. {
  1582. Status = RPC_S_OK;
  1583. break;
  1584. }
  1585. } while(RetryCount < 3);
  1586. if (Status == RPC_S_OK)
  1587. {
  1588. ASSERT(SelectedBinding != 0);
  1589. Status = ActuallyAllocateCCall(
  1590. CCall,
  1591. SelectedBinding,
  1592. IsBackConnectionNeeded,
  1593. BindingHandle,
  1594. CurrentSecurityContext);
  1595. }
  1596. else
  1597. {
  1598. // if the association was aborted, the bindings were already removed from the
  1599. // dictionary - don't do it again
  1600. if (fAssociationAborted == FALSE)
  1601. {
  1602. // the binding failed - remove the created bindings from the dictionary
  1603. for (i = 0; i < NumberOfBindingsAvailable; i ++)
  1604. {
  1605. if (BindingCreated[i])
  1606. {
  1607. CurrentBinding = Bindings.Delete(BindingsForThisInterface[i]->GetPresentationContext());
  1608. ASSERT(CurrentBinding == BindingsForThisInterface[i]);
  1609. delete CurrentBinding;
  1610. }
  1611. }
  1612. }
  1613. }
  1614. Cleanup:
  1615. if (CurrentSecurityContext)
  1616. {
  1617. if (Status == RPC_S_OK)
  1618. {
  1619. (*CCall)->SetCurrentSecurityContext(CurrentSecurityContext);
  1620. }
  1621. else
  1622. {
  1623. // remove the added reference
  1624. CurrentSecurityContext->RemoveReference();
  1625. }
  1626. }
  1627. AssociationMutex.Clear();
  1628. return(Status);
  1629. }
  1630. RPC_STATUS
  1631. LRPC_CASSOCIATION::ActuallyAllocateCCall (
  1632. OUT LRPC_CCALL ** CCall,
  1633. IN LRPC_BINDING * Binding,
  1634. IN BOOL IsBackConnectionNeeded,
  1635. IN LRPC_BINDING_HANDLE * BindingHandle,
  1636. IN LRPC_CCONTEXT *SecurityContext
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. We need to allocate a LRPC_CCALL object for the call. We also need
  1641. to initialize it so that it specified the correct bound interface.
  1642. Arguments:
  1643. CCall - Returns the allocated LRPC_CCALL which has been bound to
  1644. the interface specified by the rpc interface information.
  1645. Binding - Supplies a representation of the interface to which the
  1646. remote procedure call is supposed to be directed.
  1647. Return Value:
  1648. RPC_S_OK - An LRPC_CCALL has been allocated and is ready to be used
  1649. to make a remote procedure call.
  1650. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
  1651. the LRPC_CALL object.
  1652. Notes:
  1653. The global mutex will be held when this routine is called.
  1654. --*/
  1655. {
  1656. RPC_STATUS Status = RPC_S_OK ;
  1657. DictionaryCursor cursor;
  1658. LRPC_CCALL *LocalCall;
  1659. THREAD *ThisThread;
  1660. if (CachedCCallFlag != 0)
  1661. {
  1662. LocalCall = CachedCCall ;
  1663. CachedCCallFlag = 0;
  1664. }
  1665. else
  1666. {
  1667. ThisThread = RpcpGetThreadPointer();
  1668. ASSERT(ThisThread);
  1669. if (ThisThread->GetCachedLrpcCall())
  1670. {
  1671. LocalCall = ThisThread->GetCachedLrpcCall();
  1672. ThisThread->SetCachedLrpcCall(NULL);
  1673. LocalCall->SetAssociation(this);
  1674. }
  1675. else
  1676. {
  1677. FreeCCalls.Reset(cursor) ;
  1678. while ((LocalCall = FreeCCalls.Next(cursor)) != 0)
  1679. {
  1680. FreeCCalls.Delete(LocalCall->FreeCallKey) ;
  1681. break;
  1682. }
  1683. }
  1684. if (LocalCall == 0)
  1685. {
  1686. LocalCall = new LRPC_CCALL(&Status);
  1687. if (LocalCall == 0)
  1688. {
  1689. return(RPC_S_OUT_OF_MEMORY);
  1690. }
  1691. if (Status != RPC_S_OK)
  1692. {
  1693. delete LocalCall ;
  1694. return Status ;
  1695. }
  1696. LocalCall->SetAssociation(this);
  1697. }
  1698. }
  1699. Status = LocalCall->ActivateCall(BindingHandle,
  1700. Binding,
  1701. IsBackConnectionNeeded,
  1702. SecurityContext);
  1703. if (Status != RPC_S_OK)
  1704. {
  1705. goto Cleanup;
  1706. }
  1707. if (IsBackConnectionNeeded)
  1708. {
  1709. if (ActiveCCalls.Insert(ULongToPtr(CallIdCounter), LocalCall) == -1)
  1710. {
  1711. Status = RPC_S_OUT_OF_MEMORY;
  1712. // remove the reference we added to this
  1713. // binding
  1714. Binding->RemoveReference();
  1715. goto Cleanup;
  1716. }
  1717. LocalCall->CallId = CallIdCounter++;
  1718. LogEvent(SU_CCALL, EV_START, LocalCall, this, LocalCall->CallId, 1, 0);
  1719. }
  1720. AddReference();
  1721. *CCall = LocalCall;
  1722. return(RPC_S_OK);
  1723. Cleanup:
  1724. if (LocalCall == CachedCCall)
  1725. {
  1726. CachedCCallFlag = 1;
  1727. }
  1728. else
  1729. {
  1730. delete LocalCall ;
  1731. }
  1732. return (Status) ;
  1733. }
  1734. void
  1735. LRPC_CASSOCIATION::PrepareBindPacket(LRPC_MESSAGE *LrpcMessage)
  1736. {
  1737. int MessageSize;
  1738. int NumContexts = 0;
  1739. LRPC_CCONTEXT *CContext;
  1740. LRPC_CCONTEXT *DeletedContext;
  1741. DictionaryCursor cursor;
  1742. SecurityContextDict.Reset(cursor);
  1743. while (NumContexts < MAX_LRPC_CONTEXTS)
  1744. {
  1745. CContext = SecurityContextDict.Next(cursor);
  1746. if (CContext)
  1747. {
  1748. if (CContext->IsUnused()
  1749. && CContext->IsSecurityContextOld())
  1750. {
  1751. LrpcMessage->Bind.OldSecurityContexts.SecurityContextId[NumContexts]
  1752. = CContext->SecurityContextId;
  1753. DeletedContext = SecurityContextDict.Delete(CContext->ContextKey);
  1754. ASSERT(DeletedContext == CContext);
  1755. NumContexts++;
  1756. delete CContext;
  1757. }
  1758. }
  1759. else
  1760. {
  1761. break;
  1762. }
  1763. }
  1764. UpdateLastSecContextTrimmingTimestamp();
  1765. MessageSize = sizeof(LRPC_BIND_MESSAGE)+NumContexts*sizeof(DWORD);
  1766. LrpcMessage->Bind.OldSecurityContexts.NumContexts = NumContexts;
  1767. LrpcMessage->LpcHeader.u1.s1.DataLength = (CSHORT) (MessageSize - sizeof(PORT_MESSAGE));
  1768. LrpcMessage->LpcHeader.u1.s1.TotalLength = (CSHORT) MessageSize;
  1769. }
  1770. RPC_STATUS
  1771. LRPC_CASSOCIATION::ActuallyDoBinding (
  1772. IN LRPC_BINDING_HANDLE *BindingHandle,
  1773. IN BOOL IsBackConnectionNeeded,
  1774. IN BOOL fAlterContextNeeded,
  1775. IN BOOL fAlterSecurityContextNeeded,
  1776. IN BOOL fDefaultLogonId,
  1777. IN int NumberOfBindings,
  1778. LRPC_BINDING *BindingsForThisInterface[],
  1779. OUT LRPC_BINDING ** Binding,
  1780. OUT LRPC_CCONTEXT **pSecurityContext
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. Arguments:
  1785. RpcInterfaceInformation - Supplies information describing the interface
  1786. to which we wish to bind.
  1787. Binding - Returns an object representing the binding to the interface
  1788. described by the first argument.
  1789. Return Value:
  1790. --*/
  1791. {
  1792. NTSTATUS NtStatus;
  1793. NTSTATUS MyNtStatus;
  1794. RPC_STATUS Status = RPC_S_OK;
  1795. int DictKey ;
  1796. HANDLE ImpersonationToken = 0;
  1797. BOOL fTokenAltered = 0;
  1798. int i;
  1799. LRPC_BIND_EXCHANGE *BindExchange;
  1800. int BindingForNDR20PresentationContext;
  1801. int BindingForNDR64PresentationContext;
  1802. int BindingForNDRTestPresentationContext;
  1803. int ChosenBindingIndex;
  1804. LRPC_BINDING *SelectedBinding;
  1805. LRPC_MESSAGE *LrpcMessage;
  1806. ULONG EffectiveIdentityTracking;
  1807. //
  1808. // To start with, see if we have an LPC port; if we dont, open one
  1809. // up.
  1810. //
  1811. //
  1812. // The AssociationMutex is held when this function is called
  1813. //
  1814. AssociationMutex.VerifyOwned();
  1815. if (IsBackConnectionNeeded)
  1816. {
  1817. Status = InitializeAsyncLrpcIfNecessary() ;
  1818. if (Status == RPC_S_OK)
  1819. {
  1820. Status = CreateBackConnection(BindingHandle) ;
  1821. }
  1822. if (Status != RPC_S_OK)
  1823. {
  1824. RpcpErrorAddRecord(EEInfoGCRuntime,
  1825. Status,
  1826. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding10,
  1827. InqEndpoint());
  1828. return Status ;
  1829. }
  1830. }
  1831. else
  1832. {
  1833. if (LpcClientPort == 0)
  1834. {
  1835. //
  1836. // we now need to bind explicitly
  1837. //
  1838. Status = OpenLpcPort(BindingHandle, FALSE);
  1839. ASSERT(fAlterContextNeeded == TRUE);
  1840. if (Status != RPC_S_OK)
  1841. {
  1842. RpcpErrorAddRecord(EEInfoGCRuntime,
  1843. Status,
  1844. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding20,
  1845. InqEndpoint());
  1846. return Status ;
  1847. }
  1848. }
  1849. }
  1850. LrpcMessage = (LRPC_MESSAGE *)AlignOnNaturalBoundary(
  1851. _alloca(PadToNaturalBoundary(sizeof(LRPC_MESSAGE) + 1) + sizeof(LRPC_MESSAGE)));
  1852. if (CacheNeedsTrimming())
  1853. {
  1854. PrepareBindPacket(LrpcMessage);
  1855. }
  1856. else
  1857. {
  1858. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_BIND_MESSAGE)
  1859. - sizeof(PORT_MESSAGE);
  1860. LrpcMessage->LpcHeader.u1.s1.TotalLength = sizeof(LRPC_BIND_MESSAGE);
  1861. LrpcMessage->Bind.OldSecurityContexts.NumContexts = 0;
  1862. }
  1863. BindExchange = &LrpcMessage->Bind.BindExchange;
  1864. // Otherwise, just go ahead and send the bind request message to the
  1865. // server, and then wait for the bind response.
  1866. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  1867. LrpcMessage->Bind.MessageType = LRPC_MSG_BIND;
  1868. if (fAlterContextNeeded)
  1869. {
  1870. SelectedBinding = *Binding = NULL;
  1871. ASSERT(NumberOfBindings > 0);
  1872. // all bindings have the same interface ID. Therefore, it is
  1873. // safe to use the first
  1874. RpcpMemoryCopy(&BindExchange->InterfaceId,
  1875. BindingsForThisInterface[0]->GetInterfaceId(),
  1876. sizeof(RPC_SYNTAX_IDENTIFIER));
  1877. BindExchange->Flags = NEW_PRESENTATION_CONTEXT_FLAG;
  1878. BindExchange->TransferSyntaxSet = 0;
  1879. BindingForNDR20PresentationContext = BindingForNDR64PresentationContext = -1;
  1880. ASSERT (NumberOfBindings <= MaximumNumberOfTransferSyntaxes);
  1881. for (i = 0; i < NumberOfBindings; i ++)
  1882. {
  1883. if (RpcpMemoryCompare(BindingsForThisInterface[i]->GetTransferSyntaxId(),
  1884. NDR20TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  1885. {
  1886. BindExchange->TransferSyntaxSet |= TS_NDR20_FLAG;
  1887. BindExchange->PresentationContext[0]
  1888. = BindingsForThisInterface[i]->GetOnTheWirePresentationContext();
  1889. BindingForNDR20PresentationContext = i;
  1890. }
  1891. else if (RpcpMemoryCompare(BindingsForThisInterface[i]->GetTransferSyntaxId(),
  1892. NDR64TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  1893. {
  1894. BindExchange->TransferSyntaxSet |= TS_NDR64_FLAG;
  1895. BindExchange->PresentationContext[1]
  1896. = BindingsForThisInterface[i]->GetOnTheWirePresentationContext();
  1897. BindingForNDR64PresentationContext = i;
  1898. }
  1899. else if (RpcpMemoryCompare(BindingsForThisInterface[i]->GetTransferSyntaxId(),
  1900. NDRTestTransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  1901. {
  1902. BindExchange->TransferSyntaxSet |= TS_NDRTEST_FLAG;
  1903. BindExchange->PresentationContext[2]
  1904. = BindingsForThisInterface[i]->GetOnTheWirePresentationContext();
  1905. BindingForNDRTestPresentationContext = i;
  1906. }
  1907. else
  1908. {
  1909. ASSERT(!"Unknown transfer syntax\n");
  1910. Status = RPC_S_UNSUPPORTED_TRANS_SYN;
  1911. goto Cleanup;
  1912. }
  1913. }
  1914. }
  1915. else
  1916. {
  1917. BindExchange->Flags = 0;
  1918. ASSERT(*Binding != NULL);
  1919. SelectedBinding = *Binding;
  1920. }
  1921. if (fAlterSecurityContextNeeded)
  1922. {
  1923. BindExchange->Flags |= NEW_SECURITY_CONTEXT_FLAG;
  1924. if (fDefaultLogonId)
  1925. BindExchange->Flags |= DEFAULT_LOGONID_FLAG;
  1926. EffectiveIdentityTracking = BindingHandle->GetIdentityTracking();
  1927. if (EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC)
  1928. {
  1929. if (OpenThreadToken (GetCurrentThread(),
  1930. TOKEN_IMPERSONATE | TOKEN_QUERY,
  1931. TRUE,
  1932. &ImpersonationToken) == FALSE)
  1933. {
  1934. ImpersonationToken = 0;
  1935. }
  1936. MyNtStatus = NtSetInformationThread(NtCurrentThread(),
  1937. ThreadImpersonationToken,
  1938. &(BindingHandle->StaticTokenHandle),
  1939. sizeof(HANDLE));
  1940. #if DBG
  1941. if (!NT_SUCCESS(MyNtStatus))
  1942. {
  1943. PrintToDebugger("RPC : NtSetInformationThread : %lx\n", MyNtStatus);
  1944. }
  1945. #endif // DBG
  1946. fTokenAltered = 1;
  1947. }
  1948. }
  1949. NtStatus = NtRequestWaitReplyPort(LpcClientPort,
  1950. (PORT_MESSAGE *) LrpcMessage,
  1951. (PORT_MESSAGE *) LrpcMessage) ;
  1952. if (fTokenAltered)
  1953. {
  1954. MyNtStatus = NtSetInformationThread(NtCurrentThread(),
  1955. ThreadImpersonationToken,
  1956. &ImpersonationToken,
  1957. sizeof(HANDLE));
  1958. #if DBG
  1959. if (!NT_SUCCESS(MyNtStatus))
  1960. {
  1961. PrintToDebugger("RPC : NtSetInformationThread : %lx\n", MyNtStatus);
  1962. }
  1963. #endif // DBG
  1964. if (ImpersonationToken)
  1965. {
  1966. CloseHandle(ImpersonationToken);
  1967. }
  1968. }
  1969. if (NT_SUCCESS(NtStatus))
  1970. {
  1971. ASSERT(LrpcMessage->Bind.MessageType == LRPC_BIND_ACK);
  1972. if (BindExchange->RpcStatus == RPC_S_OK)
  1973. {
  1974. if (fAlterSecurityContextNeeded &&
  1975. (IsBackConnectionNeeded
  1976. || EffectiveIdentityTracking == RPC_C_QOS_IDENTITY_STATIC))
  1977. {
  1978. //
  1979. // It is possible for the security context ID to be -1
  1980. // This will happen when the server is not able to open the token
  1981. //
  1982. *pSecurityContext = new LRPC_CCONTEXT(
  1983. BindingHandle->InquireAuthInformation(),
  1984. BindExchange->SecurityContextId,
  1985. this);
  1986. if (*pSecurityContext == 0)
  1987. {
  1988. Status = RPC_S_OUT_OF_MEMORY;
  1989. goto Cleanup;
  1990. }
  1991. if ((DictKey = SecurityContextDict.Insert(*pSecurityContext)) == -1)
  1992. {
  1993. delete *pSecurityContext;
  1994. *pSecurityContext = NULL;
  1995. Status = RPC_S_OUT_OF_MEMORY;
  1996. goto Cleanup;
  1997. }
  1998. (*pSecurityContext)->AddReference();
  1999. (*pSecurityContext)->ContextKey = DictKey;
  2000. }
  2001. if (fAlterContextNeeded)
  2002. {
  2003. ChosenBindingIndex = -1;
  2004. // which presentation context did the server pick?
  2005. if (BindExchange->TransferSyntaxSet & TS_NDR20_FLAG)
  2006. {
  2007. ASSERT(BindingForNDR20PresentationContext != -1);
  2008. // the server should choose only one transfer syntax
  2009. ASSERT((BindExchange->TransferSyntaxSet & ~TS_NDR20_FLAG) == 0);
  2010. ChosenBindingIndex = BindingForNDR20PresentationContext;
  2011. }
  2012. else if (BindExchange->TransferSyntaxSet & TS_NDR64_FLAG)
  2013. {
  2014. ASSERT(BindingForNDR64PresentationContext != -1);
  2015. // the server should choose only one transfer syntax
  2016. ASSERT((BindExchange->TransferSyntaxSet & ~TS_NDR64_FLAG) == 0);
  2017. ChosenBindingIndex = BindingForNDR64PresentationContext;
  2018. }
  2019. else if (BindExchange->TransferSyntaxSet & TS_NDRTEST_FLAG)
  2020. {
  2021. ASSERT(BindingForNDRTestPresentationContext != -1);
  2022. // the server should choose only one transfer syntax
  2023. ASSERT((BindExchange->TransferSyntaxSet & ~TS_NDRTEST_FLAG) == 0);
  2024. ChosenBindingIndex = BindingForNDRTestPresentationContext;
  2025. }
  2026. else
  2027. {
  2028. ASSERT(!"Server supplied invalid response");
  2029. }
  2030. if (ChosenBindingIndex < 0)
  2031. {
  2032. ASSERT(_NOT_COVERED_);
  2033. BindExchange->RpcStatus = RPC_S_UNSUPPORTED_TRANS_SYN;
  2034. }
  2035. else
  2036. {
  2037. // if we offered the server a choice of bindings and it
  2038. // exercised this choice, record its preferences
  2039. if (NumberOfBindings > 1)
  2040. {
  2041. BindingsForThisInterface[ChosenBindingIndex]->
  2042. TransferSyntaxIsServerPreferred();
  2043. for (i = 0; i < NumberOfBindings; i ++)
  2044. {
  2045. if (ChosenBindingIndex != i)
  2046. {
  2047. BindingsForThisInterface[i]->TransferSyntaxIsNotServerPreferred();
  2048. }
  2049. }
  2050. }
  2051. SelectedBinding = BindingsForThisInterface[ChosenBindingIndex];
  2052. }
  2053. }
  2054. }
  2055. else
  2056. {
  2057. if (BindExchange->Flags & EXTENDED_ERROR_INFO_PRESENT)
  2058. {
  2059. ExtendedErrorInfo *EEInfo;
  2060. ASSERT(IsBufferAligned(LrpcMessage->Bind.BindExchange.Buffer));
  2061. Status = UnpickleEEInfo(LrpcMessage->Bind.BindExchange.Buffer,
  2062. LrpcMessage->LpcHeader.u1.s1.DataLength
  2063. - BIND_NAK_PICKLE_BUFFER_OFFSET
  2064. + sizeof(PORT_MESSAGE),
  2065. &EEInfo);
  2066. if (Status == RPC_S_OK)
  2067. {
  2068. RpcpSetEEInfo(EEInfo);
  2069. }
  2070. RpcpErrorAddRecord(EEInfoGCRuntime,
  2071. BindExchange->RpcStatus,
  2072. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding30);
  2073. }
  2074. }
  2075. Status = BindExchange->RpcStatus;
  2076. ASSERT (Status != RPC_S_SERVER_UNAVAILABLE
  2077. && Status != RPC_S_ACCESS_DENIED) ;
  2078. }
  2079. else
  2080. {
  2081. Status = RPC_S_SERVER_UNAVAILABLE;
  2082. RpcpErrorAddRecord(EEInfoGCLPC,
  2083. Status,
  2084. EEInfoDLLRPC_CASSOCIATION__ActuallyDoBinding40,
  2085. NtStatus);
  2086. }
  2087. Cleanup:
  2088. *Binding = SelectedBinding;
  2089. return (Status);
  2090. }
  2091. void
  2092. LRPC_CASSOCIATION::ProcessResponse (
  2093. IN LRPC_MESSAGE *LrpcResponse,
  2094. IN OUT LRPC_MESSAGE **LrpcReplyMessage
  2095. )
  2096. /*++
  2097. Routine Description:
  2098. Process a response on the back connection.
  2099. Two types of responses can show up on the back connection:
  2100. 1. Responses from async calls.
  2101. Arguments:
  2102. LrpcResponse - Reply message.
  2103. Return Value:
  2104. RPC_S_OK - Function succeeded
  2105. RPC_S_OUT_OF_MEMORY - we ran out of memory
  2106. --*/
  2107. {
  2108. LRPC_CCALL *CCall ;
  2109. RPC_MESSAGE RpcMessage ;
  2110. THREAD *ThisThread;
  2111. LRPC_CCALL *ExistingCCall;
  2112. ULONG OriginalCallId;
  2113. ThisThread = RpcpGetThreadPointer();
  2114. ASSERT(ThisThread);
  2115. ASSERT(ThisThread->GetDestroyedWithOutstandingLocksFlag() == 0);
  2116. OriginalCallId = LrpcResponse->Rpc.RpcHeader.CallId;
  2117. AssociationMutex.Request() ;
  2118. CCall = ActiveCCalls.Find(ULongToPtr(OriginalCallId)) ;
  2119. if (CCall == 0)
  2120. {
  2121. AssociationMutex.Clear() ;
  2122. if (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
  2123. {
  2124. // There may be a server thread stuck waiting for the reply
  2125. // in which case we should treat this as a synchronous call
  2126. // and make sure the message is not dropped.
  2127. // We do this only if the buffer is server. If it is not,
  2128. // we don't do that, because the LPC response we received
  2129. // was datagram, and we can't send a response to a datagram.
  2130. // Note that this is not necessary either, since the response
  2131. // is from a server, and we don't have any use on the server
  2132. // for a fault to a response (it just gets dropped). If the
  2133. // buffer is server, we still need to do it to free
  2134. // the thread, because it is doing NtRequestWaitReplyPort,
  2135. // and this is blocking.
  2136. SetFaultPacket(LrpcResponse,
  2137. RPC_S_CALL_FAILED_DNE,
  2138. LrpcResponse->Rpc.RpcHeader.Flags | LRPC_SYNC_CLIENT,
  2139. NULL);
  2140. *LrpcReplyMessage = LrpcResponse;
  2141. }
  2142. return ;
  2143. }
  2144. CCall->LockCallFromResponse();
  2145. AssociationMutex.Clear() ;
  2146. CCall->ProcessResponse(LrpcResponse);
  2147. // if this call was destroyed with outstanding locks, don't
  2148. // touch it - just clear the flag
  2149. if (ThisThread->GetDestroyedWithOutstandingLocksFlag())
  2150. {
  2151. ThisThread->ClearDestroyedWithOutstandingLocksFlag();
  2152. }
  2153. else
  2154. {
  2155. AssociationMutex.Request() ;
  2156. // check if somebody has freed the call. If yes, don't do anything - the counter
  2157. // would have been reset
  2158. ExistingCCall = ActiveCCalls.Find(ULongToPtr(OriginalCallId));
  2159. if (ExistingCCall
  2160. && (ExistingCCall == CCall))
  2161. {
  2162. CCall->UnlockCallFromResponse();
  2163. }
  2164. AssociationMutex.Clear() ;
  2165. }
  2166. }
  2167. RPC_STATUS
  2168. LRPC_CASSOCIATION::OpenLpcPort (
  2169. IN LRPC_BINDING_HANDLE *BindingHandle,
  2170. IN BOOL fBindBack
  2171. )
  2172. /*++
  2173. Routine Description:
  2174. Arguments:
  2175. RpcInterfaceInformation - Supplies information describing the interface
  2176. to which we wish to bind.
  2177. Binding - Returns an object representing the binding to the interface
  2178. described by the first argument.
  2179. Return Value:
  2180. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  2181. operation.
  2182. Notes:
  2183. The global mutex will be held when this routine is called.
  2184. --*/
  2185. {
  2186. NTSTATUS NtStatus;
  2187. UNICODE_STRING UnicodeString;
  2188. RPC_CHAR * LpcPortName;
  2189. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  2190. RPC_STATUS Status;
  2191. LRPC_BIND_EXCHANGE BindExchange;
  2192. unsigned long BindExchangeLength = sizeof(LRPC_BIND_EXCHANGE);
  2193. DWORD LastError;
  2194. //
  2195. // Look at the network options and initialize the security quality
  2196. // of service appropriately.
  2197. //
  2198. SecurityQualityOfService.EffectiveOnly = (unsigned char) BindingHandle->EffectiveOnly;
  2199. SecurityQualityOfService.ContextTrackingMode =
  2200. SECURITY_DYNAMIC_TRACKING;
  2201. SecurityQualityOfService.ImpersonationLevel =
  2202. MapRpcToNtImp(AssocAuthInfo.ImpersonationType) ;
  2203. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2204. //
  2205. // Allocate and initialize the port name. We need to stick the
  2206. // LRPC_DIRECTORY_NAME on the front of the endpoint. This is for
  2207. // security reasons (so that anyone can create LRPC endpoints).
  2208. //
  2209. LpcPortName = new RPC_CHAR[
  2210. RpcpStringLength(DceBinding->InqEndpoint())
  2211. + RpcpStringLength(LRPC_DIRECTORY_NAME) + 1];
  2212. if (LpcPortName == 0)
  2213. {
  2214. return(RPC_S_OUT_OF_MEMORY);
  2215. }
  2216. RpcpMemoryCopy(LpcPortName, LRPC_DIRECTORY_NAME,
  2217. RpcpStringLength(LRPC_DIRECTORY_NAME) * sizeof(RPC_CHAR));
  2218. RpcpMemoryCopy(LpcPortName + RpcpStringLength(LRPC_DIRECTORY_NAME),
  2219. DceBinding->InqEndpoint(),
  2220. (RpcpStringLength(DceBinding->InqEndpoint()) + 1)
  2221. * sizeof(RPC_CHAR));
  2222. RtlInitUnicodeString(&UnicodeString, LpcPortName);
  2223. DWORD Key;
  2224. LPC_KEY *LpcKey = (LPC_KEY *) &Key;
  2225. LpcKey->SeqNumber = SequenceNumber;
  2226. LpcKey->AssocKey = (unsigned short) AssociationDictKey;
  2227. BindExchange.ConnectType = LRPC_CONNECT_REQUEST ;
  2228. BindExchange.AssocKey = Key;
  2229. if (fBindBack)
  2230. {
  2231. BindExchange.Flags = BIND_BACK_FLAG;
  2232. LrpcGetEndpoint((RPC_CHAR *) BindExchange.szPortName) ;
  2233. }
  2234. else
  2235. {
  2236. BindExchange.Flags = 0;
  2237. }
  2238. if (AssocAuthInfo.Capabilities == RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH
  2239. && AssocAuthInfo.ServerPrincipalName)
  2240. {
  2241. int i;
  2242. DWORD SizeofSID, DomainNameLen;
  2243. SID_NAME_USE eUse;
  2244. PSID pSID;
  2245. RPC_CHAR *pDomainName;
  2246. SizeofSID = sizeof(SID)+10*sizeof(ULONG);
  2247. DomainNameLen = 256 * sizeof(RPC_CHAR);
  2248. for (i = 0; i < 2; i++)
  2249. {
  2250. pSID = (PSID) new char[SizeofSID];
  2251. pDomainName = (RPC_CHAR *) new char[DomainNameLen];
  2252. if (pSID == 0 || pDomainName == 0)
  2253. {
  2254. delete pSID;
  2255. delete pDomainName;
  2256. delete LpcPortName;
  2257. return RPC_S_OUT_OF_MEMORY;
  2258. }
  2259. if (LookupAccountNameW (
  2260. NULL,
  2261. AssocAuthInfo.ServerPrincipalName,
  2262. pSID,
  2263. &SizeofSID,
  2264. pDomainName,
  2265. &DomainNameLen,
  2266. &eUse))
  2267. {
  2268. break;
  2269. }
  2270. delete pSID;
  2271. delete pDomainName;
  2272. LastError = GetLastError();
  2273. if (LastError != ERROR_INSUFFICIENT_BUFFER)
  2274. {
  2275. delete LpcPortName;
  2276. switch (LastError)
  2277. {
  2278. case ERROR_NONE_MAPPED:
  2279. Status = RPC_S_UNKNOWN_PRINCIPAL;
  2280. break;
  2281. case ERROR_ACCESS_DENIED:
  2282. case ERROR_TRUSTED_RELATIONSHIP_FAILURE:
  2283. Status = RPC_S_ACCESS_DENIED;
  2284. break;
  2285. default:
  2286. Status = RPC_S_OUT_OF_MEMORY;
  2287. }
  2288. RpcpErrorAddRecord(EEInfoGCRuntime,
  2289. Status,
  2290. EEInfoDLLRPC_CASSOCIATION__OpenLpcPort10,
  2291. LastError);
  2292. return Status;
  2293. }
  2294. }
  2295. delete pDomainName;
  2296. ASSERT(i < 2);
  2297. NtStatus = NtSecureConnectPort (
  2298. &LpcClientPort,
  2299. &UnicodeString,
  2300. &SecurityQualityOfService,
  2301. NULL,
  2302. pSID,
  2303. NULL,
  2304. NULL,
  2305. &BindExchange,
  2306. &BindExchangeLength);
  2307. delete pSID;
  2308. }
  2309. else
  2310. {
  2311. NtStatus = NtConnectPort(
  2312. &LpcClientPort,
  2313. &UnicodeString,
  2314. &SecurityQualityOfService,
  2315. NULL,
  2316. NULL,
  2317. NULL,
  2318. &BindExchange,
  2319. &BindExchangeLength);
  2320. }
  2321. delete LpcPortName;
  2322. if (NT_SUCCESS(NtStatus))
  2323. {
  2324. ASSERT(BindExchangeLength == sizeof(LRPC_BIND_EXCHANGE));
  2325. return(BindExchange.RpcStatus);
  2326. }
  2327. if (NtStatus == STATUS_PORT_CONNECTION_REFUSED)
  2328. {
  2329. if (BindExchange.Flags & SERVER_BIND_EXCH_RESP)
  2330. {
  2331. RpcpErrorAddRecord(EEInfoGCRuntime,
  2332. BindExchange.RpcStatus,
  2333. EEInfoDLLRPC_CASSOCIATION__OpenLpcPort20,
  2334. NtStatus);
  2335. return(BindExchange.RpcStatus);
  2336. }
  2337. // if the SERVER_BIND_EXCH_RESP flag is not set, the rejection
  2338. // comes from LPC. The only case where this can happen is if
  2339. // the server is not available.
  2340. RpcpErrorAddRecord(EEInfoGCRuntime,
  2341. RPC_S_SERVER_UNAVAILABLE,
  2342. EEInfoDLLRPC_CASSOCIATION__OpenLpcPort30,
  2343. NtStatus);
  2344. return(RPC_S_SERVER_UNAVAILABLE);
  2345. }
  2346. if (NtStatus == STATUS_NO_MEMORY)
  2347. {
  2348. Status = RPC_S_OUT_OF_MEMORY;
  2349. }
  2350. else if ((NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  2351. || (NtStatus == STATUS_QUOTA_EXCEEDED))
  2352. {
  2353. Status = RPC_S_OUT_OF_RESOURCES;
  2354. }
  2355. else if (NtStatus == STATUS_OBJECT_PATH_INVALID)
  2356. {
  2357. Status = RPC_S_INVALID_ENDPOINT_FORMAT;
  2358. }
  2359. else if (NtStatus == STATUS_ACCESS_DENIED
  2360. || NtStatus == STATUS_SERVER_SID_MISMATCH
  2361. || NtStatus == STATUS_BAD_IMPERSONATION_LEVEL)
  2362. {
  2363. Status = RPC_S_ACCESS_DENIED;
  2364. }
  2365. else
  2366. {
  2367. #if DBG
  2368. if (NtStatus != STATUS_OBJECT_NAME_NOT_FOUND)
  2369. {
  2370. PrintToDebugger("LRPC: NtConnectPort : %lx\n", NtStatus);
  2371. }
  2372. #endif // DBG
  2373. ASSERT(NtStatus == STATUS_OBJECT_NAME_NOT_FOUND);
  2374. Status = RPC_S_SERVER_UNAVAILABLE;
  2375. }
  2376. RpcpErrorAddRecord(EEInfoGCRuntime,
  2377. Status,
  2378. EEInfoDLLRPC_CASSOCIATION__OpenLpcPort40,
  2379. NtStatus);
  2380. return Status;
  2381. }
  2382. void
  2383. LRPC_CASSOCIATION::FreeCCall (
  2384. IN LRPC_CCALL * CCall
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. This routine will get called to notify this association that a remote
  2389. procedure call on this association has completed.
  2390. Arguments:
  2391. CCall - Supplies the remote procedure call which has completed.
  2392. --*/
  2393. {
  2394. LRPC_CCALL *DeletedCall;
  2395. BOOL fMutexTaken = FALSE;
  2396. ExtendedErrorInfo *LocalEEInfo;
  2397. LRPC_MESSAGE *LocalLrpcMessage;
  2398. THREAD *ThisThread;
  2399. BOOL fCacheToThread;
  2400. BOOL fOutstandingLocks = FALSE;
  2401. BOOL fUnlocked;
  2402. void *Buffer;
  2403. unsigned int BufferLength ;
  2404. if (CCall->CallId != (ULONG) -1)
  2405. {
  2406. // Try to take both resources, but if fail on the second, release
  2407. // the first and retry. There is a potential deadlock here, since
  2408. // another thread may have the call locked while holding the AssociationMutex,
  2409. // release the mutex, and try to take it again. This may happen in
  2410. // ProcessResponse()
  2411. while (TRUE)
  2412. {
  2413. AssociationMutex.Request();
  2414. fMutexTaken = TRUE;
  2415. LogEvent(SU_CCALL, EV_STOP, CCall, this, CCall->CallId, 1, 0);
  2416. if (CCall->AsyncStatus == RPC_S_CALL_CANCELLED)
  2417. {
  2418. // if the call was cancelled, there is a race condition
  2419. // where the server may still be sending us a response
  2420. // make sure we wait for any response already in the pipeline
  2421. // to go through
  2422. fOutstandingLocks = CCall->TryWaitForCallToBecomeUnlocked(&fUnlocked);
  2423. if (fUnlocked)
  2424. break;
  2425. else
  2426. {
  2427. AssociationMutex.Clear();
  2428. fMutexTaken = FALSE;
  2429. Sleep(10);
  2430. }
  2431. }
  2432. else
  2433. {
  2434. // this is not a cancel. It is possible that a response
  2435. // is still being processed. We zero out the counter now,
  2436. // and we will remove the element from the dictionary and
  2437. // reset its CallId (we're still inside the mutex). When
  2438. // the thread that processes the response is about to
  2439. // decrease the refcount, it will check whether the call is
  2440. // in the dictionary and whether it has the same call id.
  2441. // If yes, it won't touch the call.
  2442. CCall->ResponseLockCount.SetInteger(0);
  2443. break;
  2444. }
  2445. }
  2446. DeletedCall = ActiveCCalls.Delete(ULongToPtr(CCall->CallId));
  2447. ASSERT((DeletedCall == 0) || (CCall == DeletedCall));
  2448. CCall->CallId = (ULONG) -1;
  2449. }
  2450. LogEvent(SU_CCALL, EV_REMOVED, CCall, this, 0, 1, 2);
  2451. LogEvent(SU_CCALL, EV_REMOVED, CCall, this, 0, 1, 6);
  2452. if (CCall->BufferQueue.Size() != 0)
  2453. {
  2454. if (!fMutexTaken)
  2455. {
  2456. AssociationMutex.Request();
  2457. fMutexTaken = TRUE;
  2458. }
  2459. while ((Buffer = CCall->BufferQueue.TakeOffQueue(&BufferLength)) != 0)
  2460. {
  2461. CCall->ActuallyFreeBuffer(Buffer);
  2462. }
  2463. }
  2464. if (fMutexTaken)
  2465. {
  2466. LocalEEInfo = CCall->EEInfo;
  2467. CCall->EEInfo = NULL;
  2468. }
  2469. else
  2470. {
  2471. LocalEEInfo =
  2472. (ExtendedErrorInfo *)InterlockedExchangePointer((PVOID *)(&CCall->EEInfo), NULL);
  2473. }
  2474. if (LocalEEInfo != NULL)
  2475. {
  2476. FreeEEInfoChain(LocalEEInfo);
  2477. }
  2478. CCall->Binding->RemoveReference();
  2479. CCall->Binding = NULL;
  2480. if (CCall == CachedCCall)
  2481. {
  2482. CachedCCallFlag = 1 ;
  2483. }
  2484. else
  2485. {
  2486. if (fMutexTaken)
  2487. {
  2488. LocalLrpcMessage = CCall->LrpcMessage;
  2489. CCall->LrpcMessage = 0;
  2490. }
  2491. else
  2492. {
  2493. LocalLrpcMessage =
  2494. (LRPC_MESSAGE *)InterlockedExchangePointer((PVOID *)(&CCall->LrpcMessage), 0);
  2495. }
  2496. FreeMessage(LocalLrpcMessage);
  2497. ThisThread = RpcpGetThreadPointer();
  2498. ASSERT(ThisThread);
  2499. if (gfServerPlatform && (ThisThread->GetCachedLrpcCall() == NULL))
  2500. {
  2501. CCall->FreeCallKey = -1;
  2502. // set the association to NULL to toast anybody who tries to touch it
  2503. CCall->Association = NULL;
  2504. ThisThread->SetCachedLrpcCall(CCall);
  2505. }
  2506. else if (FreeCCalls.Size() < 64)
  2507. {
  2508. if (!fMutexTaken)
  2509. {
  2510. AssociationMutex.Request();
  2511. fMutexTaken = TRUE;
  2512. }
  2513. if ((CCall->FreeCallKey = FreeCCalls.Insert(CCall)) == -1)
  2514. {
  2515. delete CCall;
  2516. }
  2517. }
  2518. else
  2519. {
  2520. CCall->FreeCallKey = -1;
  2521. delete CCall;
  2522. }
  2523. }
  2524. if (fMutexTaken)
  2525. {
  2526. AssociationMutex.Clear();
  2527. }
  2528. if (fOutstandingLocks)
  2529. {
  2530. ThisThread = RpcpGetThreadPointer();
  2531. ASSERT(ThisThread);
  2532. ThisThread->SetDestroyedWithOutstandingLocksFlag();
  2533. }
  2534. RemoveReference();
  2535. }
  2536. LRPC_CASSOCIATION *
  2537. FindOrCreateLrpcAssociation (
  2538. IN DCE_BINDING * DceBinding,
  2539. IN CLIENT_AUTH_INFO *pClientAuthInfo,
  2540. IN RPC_CLIENT_INTERFACE *InterfaceInfo
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. This routine finds an existing association supporting the requested
  2545. DCE binding, or creates a new association which supports the
  2546. requested DCE binding. Ownership of the passed DceBinding passes
  2547. to this routine.
  2548. Arguments:
  2549. DceBinding - Supplies binding information; if an association is
  2550. returned the ownership of the DceBinding is passed
  2551. to the association.
  2552. Return Value:
  2553. An association which supports the requested binding will be returned.
  2554. Otherwise, zero will be returned, indicating insufficient memory.
  2555. --*/
  2556. {
  2557. LRPC_CASSOCIATION * Association;
  2558. RPC_STATUS Status = RPC_S_OK;
  2559. static USHORT SequenceNumber = 1;
  2560. DictionaryCursor cursor;
  2561. BOOL fOnlyEndpointDiffers;
  2562. int Result;
  2563. // First, we check for an existing association.
  2564. LrpcAssociationDict->Reset(cursor);
  2565. while ((Association = LrpcAssociationDict->Next(cursor)) != 0)
  2566. {
  2567. #if defined (RPC_GC_AUDIT)
  2568. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Comparing association to: %S, %S, %S\n",
  2569. GetCurrentProcessId(), GetCurrentProcessId(), Association->DceBinding->InqRpcProtocolSequence(),
  2570. Association->DceBinding->InqNetworkAddress(), Association->DceBinding->InqEndpoint());
  2571. #endif
  2572. Result = Association->CompareWithDceBinding(DceBinding, &fOnlyEndpointDiffers);
  2573. if ((Association->IsSupportedAuthInfo(pClientAuthInfo) == TRUE)
  2574. &&
  2575. (!Result
  2576. ||
  2577. (
  2578. fOnlyEndpointDiffers
  2579. && InterfaceInfo
  2580. && DceBinding->IsNullEndpoint()
  2581. && Association->DoesBindingForInterfaceExist(InterfaceInfo)
  2582. )
  2583. )
  2584. )
  2585. {
  2586. Association->AddBindingHandleReference();
  2587. if (Association->Linger.fAssociationLingered == TRUE)
  2588. {
  2589. #if defined (RPC_GC_AUDIT)
  2590. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC lingering association resurrected %X %S %S %S\n",
  2591. GetCurrentProcessId(), GetCurrentProcessId(), Association,
  2592. Association->DceBinding->InqRpcProtocolSequence(),
  2593. Association->DceBinding->InqNetworkAddress(),
  2594. Association->DceBinding->InqEndpoint());
  2595. #endif
  2596. LrpcLingeredAssociations --;
  2597. ASSERT(LrpcLingeredAssociations >= 0);
  2598. Association->Linger.fAssociationLingered = FALSE;
  2599. }
  2600. delete DceBinding;
  2601. return(Association);
  2602. }
  2603. }
  2604. // if asked to do short endpoint resolution, don't create new association
  2605. if (InterfaceInfo)
  2606. return NULL;
  2607. #if defined (RPC_GC_AUDIT)
  2608. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Creating association to: %S, %S, %S\n",
  2609. GetCurrentProcessId(), GetCurrentProcessId(), DceBinding->InqRpcProtocolSequence(),
  2610. DceBinding->InqNetworkAddress(), DceBinding->InqEndpoint());
  2611. #endif
  2612. SequenceNumber = (SequenceNumber+1) % (0x7FFF);
  2613. Association = new LRPC_CASSOCIATION(DceBinding,
  2614. pClientAuthInfo,
  2615. SequenceNumber,
  2616. &Status);
  2617. if ((Association != 0) && (Status == RPC_S_OK))
  2618. {
  2619. Association->AssociationDictKey = LrpcAssociationDict->Insert(Association);
  2620. if (Association->AssociationDictKey == -1)
  2621. {
  2622. Association->DceBinding = 0;
  2623. delete Association;
  2624. return(0);
  2625. }
  2626. return(Association);
  2627. }
  2628. else
  2629. {
  2630. if (Association != 0)
  2631. {
  2632. Association->DceBinding = 0;
  2633. delete Association;
  2634. }
  2635. return(0);
  2636. }
  2637. ASSERT(0);
  2638. return(0);
  2639. }
  2640. void
  2641. ShutdownLrpcClient (
  2642. )
  2643. /*++
  2644. Routine Description:
  2645. This routine will get called when the process which is using this dll
  2646. exits. We will go through and notify any servers that we are going
  2647. away.
  2648. --*/
  2649. {
  2650. LRPC_CASSOCIATION * Association;
  2651. DictionaryCursor cursor;
  2652. if (LrpcAssociationDict != 0)
  2653. {
  2654. LrpcAssociationDict->Reset(cursor);
  2655. while ((Association = LrpcAssociationDict->Next(cursor)) != 0)
  2656. {
  2657. Association->RemoveReference() ;
  2658. }
  2659. }
  2660. }
  2661. void
  2662. LRPC_CASSOCIATION::AbortAssociation (
  2663. IN BOOL ServerAborted
  2664. )
  2665. /*++
  2666. Routine Description:
  2667. This association needs to be aborted because a the server side of the
  2668. lpc port has been closed.
  2669. --*/
  2670. {
  2671. LRPC_BINDING * Binding;
  2672. LRPC_CCALL *CCall ;
  2673. LRPC_CCONTEXT *SecurityContext;
  2674. DictionaryCursor cursor;
  2675. AssociationMutex.Request();
  2676. LogEvent(SU_CASSOC, EV_ABORT, this, 0, ServerAborted, 1, 0);
  2677. CloseLpcClientPort();
  2678. Bindings.Reset(cursor);
  2679. while ((Binding = Bindings.RemoveNext(cursor)) != 0)
  2680. {
  2681. // RemoveReference will destroy the binding if its
  2682. // ref count reaches 0
  2683. Binding->RemoveReference();
  2684. }
  2685. SecurityContextDict.Reset(cursor);
  2686. while (SecurityContext = SecurityContextDict.RemoveNext(cursor))
  2687. {
  2688. SecurityContext->Destroy();
  2689. }
  2690. int waitIterations = 8;
  2691. if (ServerAborted)
  2692. {
  2693. ActiveCCalls.Reset(cursor);
  2694. while ((CCall = ActiveCCalls.Next(cursor, TRUE)) != 0)
  2695. {
  2696. CCall->ServerAborted(&waitIterations);
  2697. }
  2698. }
  2699. // nuke the free calls as well, because when we abort the association
  2700. // some information in them will be stale
  2701. FreeCCalls.Reset(cursor);
  2702. while ((CCall = FreeCCalls.Next(cursor)) != 0)
  2703. {
  2704. delete CCall;
  2705. }
  2706. AssociationMutex.Clear();
  2707. }
  2708. void
  2709. LRPC_CASSOCIATION::CloseLpcClientPort (
  2710. )
  2711. /*++
  2712. Routine Description:
  2713. The LpcClientPort will be closed (and a close message sent to the server).
  2714. --*/
  2715. {
  2716. NTSTATUS NtStatus;
  2717. if (LpcClientPort != 0)
  2718. {
  2719. NtStatus = NtClose(LpcClientPort);
  2720. #if DBG
  2721. if (!NT_SUCCESS(NtStatus))
  2722. {
  2723. PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
  2724. }
  2725. #endif // DBG
  2726. if (LpcReceivePort)
  2727. {
  2728. NtStatus = NtClose(LpcReceivePort) ;
  2729. #if DBG
  2730. if (!NT_SUCCESS(NtStatus))
  2731. {
  2732. PrintToDebugger("RPC : NtClose : %lx\n", NtStatus);
  2733. }
  2734. #endif
  2735. ASSERT(NT_SUCCESS(NtStatus));
  2736. }
  2737. LpcClientPort = 0;
  2738. LpcReceivePort = 0;
  2739. BackConnectionCreated = 0;
  2740. }
  2741. }
  2742. BOOL
  2743. LRPC_CASSOCIATION::IsSupportedAuthInfo(
  2744. IN CLIENT_AUTH_INFO * ClientAuthInfo
  2745. )
  2746. /*++
  2747. Routine Description:
  2748. Check if this association supports the needed auth info.
  2749. Arguments:
  2750. ClientAuthInfo - description
  2751. Return Value:
  2752. TRUE: it does
  2753. FALSE: it doesn't
  2754. --*/
  2755. {
  2756. if (!ClientAuthInfo)
  2757. {
  2758. if (AssocAuthInfo.ImpersonationType == RPC_C_IMP_LEVEL_IMPERSONATE)
  2759. {
  2760. return TRUE ;
  2761. }
  2762. return FALSE;
  2763. }
  2764. if ((ClientAuthInfo->AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE
  2765. && AssocAuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  2766. || (AssocAuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE
  2767. && ClientAuthInfo->AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE))
  2768. {
  2769. return(FALSE);
  2770. }
  2771. ASSERT(ClientAuthInfo->AuthenticationService == RPC_C_AUTHN_WINNT);
  2772. if (ClientAuthInfo->AuthorizationService
  2773. != AssocAuthInfo.AuthorizationService)
  2774. {
  2775. return(FALSE);
  2776. }
  2777. #if 0
  2778. if (ClientAuthInfo->IdentityTracking != AssocAuthInfo.IdentityTracking)
  2779. {
  2780. return(FALSE);
  2781. }
  2782. #endif
  2783. if (ClientAuthInfo->ImpersonationType != AssocAuthInfo.ImpersonationType)
  2784. {
  2785. return (FALSE) ;
  2786. }
  2787. if (ClientAuthInfo->ServerPrincipalName)
  2788. {
  2789. if (AssocAuthInfo.ServerPrincipalName == 0
  2790. || RpcpStringCompare(ClientAuthInfo->ServerPrincipalName,
  2791. AssocAuthInfo.ServerPrincipalName) != 0)
  2792. {
  2793. return FALSE;
  2794. }
  2795. }
  2796. return(TRUE);
  2797. }
  2798. LRPC_CCALL::LRPC_CCALL (
  2799. IN OUT RPC_STATUS *Status
  2800. ) : CallMutex(Status),
  2801. SyncEvent(Status, 0),
  2802. ResponseLockCount(0)
  2803. /*++
  2804. --*/
  2805. {
  2806. ObjectType = LRPC_CCALL_TYPE;
  2807. CurrentBindingHandle = 0;
  2808. Association = 0;
  2809. CallAbortedFlag = 0;
  2810. LrpcMessage = 0;
  2811. CachedLrpcMessage = 0;
  2812. FreeCallKey = -1;
  2813. CallId = (ULONG) -1;
  2814. EEInfo = NULL;
  2815. }
  2816. LRPC_CCALL::~LRPC_CCALL (
  2817. )
  2818. /*++
  2819. --*/
  2820. {
  2821. if (LrpcMessage)
  2822. {
  2823. FreeMessage(LrpcMessage) ;
  2824. }
  2825. if (CachedLrpcMessage)
  2826. {
  2827. FreeMessage(CachedLrpcMessage) ;
  2828. }
  2829. if (CallId != (ULONG) -1)
  2830. {
  2831. // the association mutex is currently held
  2832. Association->ActiveCCalls.Delete(ULongToPtr(CallId));
  2833. }
  2834. if (FreeCallKey != -1)
  2835. {
  2836. Association->FreeCCalls.Delete(FreeCallKey) ;
  2837. }
  2838. }
  2839. RPC_STATUS
  2840. LRPC_CCALL::NegotiateTransferSyntax (
  2841. IN OUT PRPC_MESSAGE Message
  2842. )
  2843. {
  2844. // just return the transfer syntax already negotiated in the binding
  2845. Message->TransferSyntax = Binding->GetTransferSyntaxId();
  2846. return RPC_S_OK;
  2847. }
  2848. RPC_STATUS
  2849. LRPC_CCALL::GetBuffer (
  2850. IN OUT PRPC_MESSAGE Message,
  2851. IN UUID *ObjectUuid
  2852. )
  2853. /*++
  2854. Routine Description:
  2855. We will allocate a buffer which will be used to either send a request
  2856. or receive a response.
  2857. ObjectUuid - Ignored
  2858. Arguments:
  2859. Message - Supplies the length of the buffer that is needed. The buffer
  2860. will be returned.
  2861. Return Value:
  2862. RPC_S_OK - A buffer has been successfully allocated. It will be of at
  2863. least the required length.
  2864. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate that
  2865. large a buffer.
  2866. --*/
  2867. {
  2868. RPC_STATUS Status;
  2869. SetObjectUuid(ObjectUuid);
  2870. if (LrpcMessage == 0)
  2871. {
  2872. LrpcMessage = AllocateMessage();
  2873. if (LrpcMessage == 0)
  2874. {
  2875. Status = RPC_S_OUT_OF_MEMORY;
  2876. goto Cleanup;
  2877. }
  2878. }
  2879. if (PARTIAL(Message))
  2880. {
  2881. CurrentBufferLength = (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
  2882. ? MINIMUM_PARTIAL_BUFFLEN:Message->BufferLength ;
  2883. Message->Buffer = RpcpFarAllocate(CurrentBufferLength);
  2884. if (Message->Buffer == 0)
  2885. {
  2886. CurrentBufferLength = 0 ;
  2887. Status = RPC_S_OUT_OF_MEMORY;
  2888. goto Cleanup;
  2889. }
  2890. }
  2891. else if (Message->BufferLength <= MAXIMUM_MESSAGE_BUFFER)
  2892. {
  2893. CurrentBufferLength = MAXIMUM_MESSAGE_BUFFER ;
  2894. // Uncomment to check for 16 byte alignment on 64 bit
  2895. // ASSERT(IsBufferAligned(LrpcMessage->Rpc.Buffer));
  2896. Message->Buffer = LrpcMessage->Rpc.Buffer;
  2897. LrpcMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_IMMEDIATE;
  2898. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  2899. LrpcMessage->LpcHeader.u1.s1.DataLength = (USHORT)
  2900. (Align4(Message->BufferLength) + sizeof(LRPC_RPC_HEADER));
  2901. return(RPC_S_OK);
  2902. }
  2903. else
  2904. {
  2905. CurrentBufferLength = Message->BufferLength ;
  2906. Message->Buffer = RpcpFarAllocate(Message->BufferLength);
  2907. if (Message->Buffer == 0)
  2908. {
  2909. Status = RPC_S_OUT_OF_MEMORY;
  2910. goto Cleanup;
  2911. }
  2912. }
  2913. LrpcMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_REQUEST;
  2914. LrpcMessage->Rpc.Request.CountDataEntries = 1;
  2915. LrpcMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  2916. LrpcMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  2917. LrpcMessage->LpcHeader.CallbackId = 0;
  2918. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  2919. LrpcMessage->LpcHeader.u2.s2.DataInfoOffset = sizeof(PORT_MESSAGE)
  2920. + sizeof(LRPC_RPC_HEADER);
  2921. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_RPC_HEADER)
  2922. + sizeof(PORT_DATA_INFORMATION);
  2923. Status = RPC_S_OK;
  2924. Cleanup:
  2925. if (Status != RPC_S_OK)
  2926. {
  2927. AbortCCall();
  2928. ASSERT(Status == RPC_S_OUT_OF_MEMORY);
  2929. }
  2930. return(Status);
  2931. }
  2932. RPC_STATUS
  2933. LpcError (
  2934. IN NTSTATUS NtStatus,
  2935. IN BOOL fDNE
  2936. )
  2937. {
  2938. if (NtStatus == STATUS_NO_MEMORY)
  2939. {
  2940. return(RPC_S_OUT_OF_MEMORY);
  2941. }
  2942. if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  2943. {
  2944. return(RPC_S_OUT_OF_RESOURCES);
  2945. }
  2946. VALIDATE(NtStatus)
  2947. {
  2948. STATUS_INVALID_PORT_HANDLE,
  2949. STATUS_INVALID_HANDLE,
  2950. STATUS_PORT_DISCONNECTED,
  2951. STATUS_LPC_REPLY_LOST
  2952. } END_VALIDATE;
  2953. if ((NtStatus != STATUS_LPC_REPLY_LOST) && fDNE)
  2954. {
  2955. return (RPC_S_CALL_FAILED_DNE) ;
  2956. }
  2957. return (RPC_S_CALL_FAILED);
  2958. }
  2959. RPC_STATUS
  2960. LRPC_CCALL::AsyncSend (
  2961. IN OUT PRPC_MESSAGE Message
  2962. )
  2963. /*++
  2964. Routine Description:
  2965. Send an async request. This request can be either partial or complete.
  2966. Arguments:
  2967. Message - contains the request.
  2968. Return Value:
  2969. RPC_S_OK - Function succeeded
  2970. RPC_S_OUT_OF_MEMORY - we ran out of memory
  2971. --*/
  2972. {
  2973. RPC_STATUS Status ;
  2974. NTSTATUS NtStatus ;
  2975. BOOL fRetVal ;
  2976. BOOL Shutup ;
  2977. ULONG_PTR fNonCausal;
  2978. ULONG AsyncStateFlags;
  2979. // If it is a small request, we send it here, otherwise, we
  2980. // use the helper function.
  2981. ASSERT(pAsync) ;
  2982. Status = CurrentBindingHandle->InqTransportOption(
  2983. RPC_C_OPT_BINDING_NONCAUSAL,
  2984. &fNonCausal);
  2985. ASSERT(Status == RPC_S_OK);
  2986. if (fNonCausal == 0)
  2987. {
  2988. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_CAUSAL;
  2989. }
  2990. if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  2991. {
  2992. LrpcMessage->LpcHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE)
  2993. + LrpcMessage->LpcHeader.u1.s1.DataLength;
  2994. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_REQUEST;
  2995. LrpcMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
  2996. LrpcMessage->Rpc.RpcHeader.PresentContext = GetOnTheWirePresentationContext();
  2997. if (CurrentSecurityContext)
  2998. {
  2999. LrpcMessage->Rpc.RpcHeader.SecurityContextId = CurrentSecurityContext->SecurityContextId;
  3000. }
  3001. else
  3002. {
  3003. LrpcMessage->Rpc.RpcHeader.SecurityContextId = -1;
  3004. }
  3005. ASSERT(CallId != (ULONG) -1);
  3006. LrpcMessage->Rpc.RpcHeader.CallId = CallId ;
  3007. if (UuidSpecified)
  3008. {
  3009. RpcpMemoryCopy(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  3010. &ObjectUuid, sizeof(UUID));
  3011. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_OBJECT_UUID;
  3012. }
  3013. NtStatus = NtRequestPort(Association->LpcClientPort,
  3014. (PORT_MESSAGE *) LrpcMessage) ;
  3015. if (NT_ERROR(NtStatus))
  3016. {
  3017. FreeCCall() ;
  3018. return LpcError(NtStatus, TRUE) ;
  3019. }
  3020. Status = RPC_S_OK;
  3021. }
  3022. else
  3023. {
  3024. AsyncStateFlags = pAsync->Flags;
  3025. Status = SendRequest(Message, &Shutup) ;
  3026. if ((AsyncStateFlags & RPC_C_NOTIFY_ON_SEND_COMPLETE) && !Shutup
  3027. && (Status == RPC_S_OK || Status == RPC_S_SEND_INCOMPLETE))
  3028. {
  3029. if (!IssueNotification(RpcSendComplete))
  3030. {
  3031. Status = RPC_S_OUT_OF_MEMORY ;
  3032. }
  3033. }
  3034. }
  3035. if (Status == RPC_S_OK)
  3036. {
  3037. CallMutex.Request();
  3038. if (AsyncStatus == RPC_S_CALL_FAILED)
  3039. {
  3040. LogEvent(SU_CCALL, EV_ABORT, this, (PVOID) 44, 44, 1, 0);
  3041. Status = RPC_S_CALL_FAILED;
  3042. CallMutex.Clear();
  3043. FreeCCall();
  3044. }
  3045. else
  3046. {
  3047. fSendComplete = 1;
  3048. CallMutex.Clear();
  3049. }
  3050. }
  3051. return(Status);
  3052. }
  3053. RPC_STATUS
  3054. LRPC_CCALL::AsyncReceive (
  3055. IN OUT PRPC_MESSAGE Message,
  3056. IN unsigned int Size
  3057. )
  3058. /*++
  3059. Routine Description:
  3060. Arguments:
  3061. Message - Contains the request. On return, it will contain the received buffer
  3062. and its length.
  3063. Size - Requested size.
  3064. Return Value:
  3065. RPC_S_OK - Function succeeded
  3066. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3067. --*/
  3068. {
  3069. RPC_STATUS Status;
  3070. int Extra = IsExtraMessage(Message);
  3071. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  3072. CallMutex.Request();
  3073. if (BufferComplete)
  3074. {
  3075. Status = GetCoalescedBuffer(Message, Extra);
  3076. }
  3077. else
  3078. {
  3079. if (PARTIAL(Message))
  3080. {
  3081. if (RcvBufferLength < Size)
  3082. {
  3083. if (NOTIFY(Message))
  3084. {
  3085. NeededLength = Size ;
  3086. }
  3087. Status = RPC_S_ASYNC_CALL_PENDING;
  3088. }
  3089. else
  3090. {
  3091. Status = GetCoalescedBuffer(Message, Extra);
  3092. }
  3093. }
  3094. else
  3095. {
  3096. Status = AsyncStatus;
  3097. ASSERT(Status != RPC_S_OK);
  3098. }
  3099. }
  3100. CallMutex.Clear();
  3101. if (Status == RPC_S_OK
  3102. || Status == RPC_S_ASYNC_CALL_PENDING)
  3103. {
  3104. return Status;
  3105. }
  3106. FreeCCall();
  3107. return Status;
  3108. }
  3109. RPC_STATUS
  3110. LRPC_CCALL::CancelAsyncCall (
  3111. IN BOOL fAbort
  3112. )
  3113. /*++
  3114. Function Name:CancelAsyncCall
  3115. Parameters:
  3116. fAbort - TRUE: the cancel is abortive, ie, the call completes immediately
  3117. FALSE: a cancel PDU is sent to the server, the call doesn't complete
  3118. until the server returns
  3119. Description:
  3120. Returns:
  3121. RPC_S_OK: The call was successfully cancelled
  3122. others - an error occured during the cancellation process
  3123. --*/
  3124. {
  3125. #if defined(BUILD_WOW6432)
  3126. char LrpcCancelMessageBuffer[sizeof(LRPC_MESSAGE) + 8];
  3127. LRPC_MESSAGE *LrpcCancelMessagePtr = (LRPC_MESSAGE *)AlignPtr8(LrpcCancelMessageBuffer);
  3128. #else
  3129. LRPC_MESSAGE LrpcCancelMessageBuffer;
  3130. LRPC_MESSAGE *LrpcCancelMessagePtr = &LrpcCancelMessageBuffer;
  3131. #endif
  3132. NTSTATUS NtStatus;
  3133. LogEvent(SU_CCALL, EV_ABORT, this, 0, fAbort, 1, 1);
  3134. //
  3135. // Notify the server that the call has been cancelled
  3136. //
  3137. LrpcCancelMessagePtr->LpcHeader.u1.s1.DataLength = sizeof(LRPC_RPC_MESSAGE)
  3138. - sizeof(PORT_MESSAGE);
  3139. LrpcCancelMessagePtr->LpcHeader.u1.s1.TotalLength = sizeof(LRPC_RPC_MESSAGE);
  3140. LrpcCancelMessagePtr->LpcHeader.u2.ZeroInit = 0;
  3141. ASSERT(CallId != (ULONG) -1);
  3142. LrpcCancelMessagePtr->Rpc.RpcHeader.CallId = CallId;
  3143. LrpcCancelMessagePtr->Rpc.RpcHeader.MessageType = LRPC_MSG_CANCEL;
  3144. NtStatus = NtRequestPort(Association->LpcClientPort,
  3145. (PORT_MESSAGE *) LrpcCancelMessagePtr) ;
  3146. // sending the notification to the server is a best effort. We ignore the
  3147. // result
  3148. if (fAbort)
  3149. {
  3150. //
  3151. // If the cancel was abortive, complete the call right away.
  3152. //
  3153. //
  3154. // We indicate completion. When the app calls RpcAsyncCompleteCall
  3155. // we will destroy the call. That is fine, even if the server
  3156. // hasn't replied yet, because if the server sends a reply to
  3157. // a call or an association that is not there, the client code
  3158. // is protected, and will simply free the packet.
  3159. //
  3160. CallFailed(RPC_S_CALL_CANCELLED);
  3161. }
  3162. return RPC_S_OK;
  3163. }
  3164. void
  3165. LRPC_CCALL::ProcessResponse(
  3166. IN LRPC_MESSAGE *LrpcResponse
  3167. )
  3168. /*++
  3169. Routine Description:
  3170. A buffer has just arrived, process it. If some other buffer is already
  3171. processing buffers, simply queue it and go away. Otherwise, does
  3172. the processing ourselves.
  3173. Arguments:
  3174. Message - Details on the arrived message
  3175. --*/
  3176. {
  3177. RPC_MESSAGE Message ;
  3178. RPC_STATUS Status ;
  3179. BOOL fRetVal = 0;
  3180. BOOL fFault2;
  3181. RPC_STATUS FaultStatus;
  3182. THREAD *ThisThread;
  3183. ExtendedErrorInfo *EEInfo;
  3184. DelayedPipeAckData AckData;
  3185. //
  3186. // So that abort will not issue a notification
  3187. //
  3188. fSendComplete = 0;
  3189. switch (LrpcResponse->Rpc.RpcHeader.MessageType)
  3190. {
  3191. case LRPC_MSG_FAULT:
  3192. if (LrpcResponse->Fault.RpcHeader.Flags & LRPC_EEINFO_PRESENT)
  3193. {
  3194. ThisThread = RpcpGetThreadPointer();
  3195. ASSERT(ThisThread);
  3196. ASSERT(ThisThread->GetEEInfo() == NULL);
  3197. Status = UnpickleEEInfo(LrpcResponse->Fault.Buffer,
  3198. LrpcResponse->Fault.LpcHeader.u1.s1.TotalLength
  3199. - sizeof(LRPC_FAULT_MESSAGE)
  3200. + sizeof(LrpcResponse->Fault.Buffer),
  3201. &EEInfo);
  3202. if (Status == RPC_S_OK)
  3203. {
  3204. this->EEInfo = EEInfo;
  3205. }
  3206. }
  3207. if (pAsync == 0)
  3208. {
  3209. AsyncStatus = LrpcResponse->Fault.RpcStatus ;
  3210. SyncEvent.Raise();
  3211. }
  3212. else
  3213. {
  3214. CallFailed(LrpcResponse->Fault.RpcStatus);
  3215. }
  3216. FreeMessage(LrpcResponse);
  3217. return ;
  3218. case LRPC_CLIENT_SEND_MORE:
  3219. if (pAsync
  3220. && (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
  3221. {
  3222. if (!IssueNotification(RpcSendComplete))
  3223. {
  3224. CallFailed(RPC_S_OUT_OF_MEMORY);
  3225. }
  3226. }
  3227. FreeMessage(LrpcResponse);
  3228. return;
  3229. }
  3230. ASSERT((LrpcResponse->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2)
  3231. || (LrpcResponse->Rpc.RpcHeader.MessageType == LRPC_MSG_RESPONSE));
  3232. if (LrpcResponse->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2)
  3233. {
  3234. fFault2 = TRUE;
  3235. FaultStatus = LrpcResponse->Fault2.RpcStatus;
  3236. }
  3237. else
  3238. fFault2 = FALSE;
  3239. Message.RpcFlags = 0;
  3240. AckData.DelayedAckPipeNeeded = FALSE;
  3241. Status = LrpcMessageToRpcMessage(LrpcResponse,
  3242. &Message,
  3243. Association->LpcReceivePort,
  3244. TRUE, // IsReplyFromBackConnection
  3245. &AckData
  3246. ) ;
  3247. if (fFault2 && (Status == RPC_S_OK))
  3248. {
  3249. ThisThread = RpcpGetThreadPointer();
  3250. ASSERT(ThisThread);
  3251. ASSERT(ThisThread->GetEEInfo() == NULL);
  3252. Status = UnpickleEEInfo((unsigned char *)Message.Buffer,
  3253. Message.BufferLength,
  3254. &EEInfo);
  3255. if (Status == RPC_S_OK)
  3256. {
  3257. this->EEInfo = EEInfo;
  3258. }
  3259. // else
  3260. // fall through the error case below, which will
  3261. // handle the failure properly
  3262. }
  3263. if ((Status != RPC_S_OK) || fFault2)
  3264. {
  3265. // remember to send delayed ack if any
  3266. if (AckData.DelayedAckPipeNeeded)
  3267. {
  3268. (void) SendPipeAck(Association->LpcReceivePort,
  3269. LrpcResponse,
  3270. AckData.CurrentStatus);
  3271. if ((Status != RPC_S_OK) && (Message.Buffer))
  3272. {
  3273. RpcpFarFree(Message.Buffer);
  3274. }
  3275. FreeMessage(LrpcResponse) ;
  3276. }
  3277. if (fFault2)
  3278. {
  3279. AsyncStatus = FaultStatus;
  3280. Status = FaultStatus;
  3281. }
  3282. else
  3283. AsyncStatus = Status ;
  3284. if (pAsync == 0)
  3285. {
  3286. SyncEvent.Raise();
  3287. }
  3288. else
  3289. {
  3290. CallFailed(Status);
  3291. }
  3292. return;
  3293. }
  3294. CallMutex.Request() ;
  3295. // we have taken the mutex - now we can send the ack
  3296. // The reason we need to wait for the mutex to be
  3297. // taken before we send the delayed ack for pipes is
  3298. // that once we send an ack, the server will send more
  3299. // data and these can race with this thread. To be
  3300. // safe, we need to take the mutex.
  3301. if (AckData.DelayedAckPipeNeeded)
  3302. {
  3303. Status = SendPipeAck(Association->LpcReceivePort,
  3304. LrpcResponse,
  3305. AckData.CurrentStatus);
  3306. FreeMessage(LrpcResponse) ;
  3307. if (Status != RPC_S_OK)
  3308. {
  3309. CallMutex.Clear();
  3310. if (Message.Buffer)
  3311. {
  3312. RpcpFarFree(Message.Buffer);
  3313. }
  3314. AsyncStatus = Status ;
  3315. if (pAsync == 0)
  3316. {
  3317. SyncEvent.Raise();
  3318. }
  3319. else
  3320. {
  3321. CallFailed(Status);
  3322. }
  3323. return;
  3324. }
  3325. }
  3326. if (COMPLETE(&Message))
  3327. {
  3328. BufferComplete = 1;
  3329. }
  3330. RcvBufferLength += Message.BufferLength ;
  3331. if (Message.BufferLength)
  3332. {
  3333. if (BufferQueue.PutOnQueue(Message.Buffer,
  3334. Message.BufferLength))
  3335. {
  3336. Status = RPC_S_OUT_OF_MEMORY ;
  3337. #if DBG
  3338. PrintToDebugger("RPC: PutOnQueue failed\n") ;
  3339. #endif
  3340. if (pAsync)
  3341. {
  3342. CallMutex.Clear();
  3343. CallFailed(Status);
  3344. return;
  3345. }
  3346. else
  3347. {
  3348. AsyncStatus = Status;
  3349. }
  3350. }
  3351. }
  3352. if (pAsync == 0)
  3353. {
  3354. CallMutex.Clear() ;
  3355. SyncEvent.Raise();
  3356. return;
  3357. }
  3358. if (BufferComplete)
  3359. {
  3360. AsyncStatus = RPC_S_OK;
  3361. CallMutex.Clear() ;
  3362. IssueNotification();
  3363. }
  3364. else
  3365. {
  3366. if (NeededLength > 0 && RcvBufferLength >= NeededLength)
  3367. {
  3368. CallMutex.Clear() ;
  3369. IssueNotification(RpcReceiveComplete);
  3370. }
  3371. else
  3372. {
  3373. CallMutex.Clear() ;
  3374. }
  3375. }
  3376. }
  3377. RPC_STATUS
  3378. LRPC_CCALL::GetCoalescedBuffer (
  3379. IN PRPC_MESSAGE Message,
  3380. IN BOOL BufferValid
  3381. )
  3382. /*++
  3383. Routine Description:
  3384. Remove buffers from the queue and coalesce them into a single buffer.
  3385. Arguments:
  3386. Message - on return this will contain the coalesced buffer, Message->BufferLength
  3387. gives us the length of the coalesced buffer.
  3388. BufferValid - Tells us if Message->Buffer is valid on entry.
  3389. Return Value:
  3390. RPC_S_OK - Function succeeded
  3391. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3392. --*/
  3393. {
  3394. void *NewBuffer, *Buffer ;
  3395. char *Current ;
  3396. unsigned int bufferlength ;
  3397. unsigned int TotalLength ;
  3398. LRPC_MESSAGE SendMore ;
  3399. NTSTATUS NtStatus ;
  3400. CallMutex.Request() ;
  3401. if (RcvBufferLength == 0)
  3402. {
  3403. if (BufferComplete)
  3404. {
  3405. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  3406. }
  3407. if (BufferValid == 0)
  3408. {
  3409. Message->Buffer = 0;
  3410. Message->BufferLength = 0;
  3411. }
  3412. CallMutex.Clear();
  3413. return RPC_S_OK;
  3414. }
  3415. BOOL fFillNewBuffer;
  3416. if (BufferValid)
  3417. {
  3418. TotalLength = RcvBufferLength + Message->BufferLength ;
  3419. NewBuffer = RpcpFarAllocate(TotalLength) ;
  3420. if (NewBuffer == 0)
  3421. {
  3422. CallMutex.Clear() ;
  3423. return RPC_S_OUT_OF_MEMORY;
  3424. }
  3425. RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength) ;
  3426. Current = (char *) NewBuffer + Message->BufferLength ;
  3427. fFillNewBuffer = 1;
  3428. }
  3429. else
  3430. {
  3431. TotalLength = RcvBufferLength ;
  3432. if (BufferQueue.Size() == 1)
  3433. {
  3434. Buffer = BufferQueue.TakeOffQueue(&bufferlength);
  3435. ASSERT(Buffer);
  3436. NewBuffer = Buffer;
  3437. ASSERT(TotalLength == bufferlength);
  3438. fFillNewBuffer = 0;
  3439. }
  3440. else
  3441. {
  3442. NewBuffer = RpcpFarAllocate(TotalLength) ;
  3443. if (NewBuffer == 0)
  3444. {
  3445. CallMutex.Clear() ;
  3446. return RPC_S_OUT_OF_MEMORY;
  3447. }
  3448. Current = (char *) NewBuffer;
  3449. fFillNewBuffer = 1;
  3450. }
  3451. }
  3452. if (fFillNewBuffer)
  3453. {
  3454. while ((Buffer = BufferQueue.TakeOffQueue(&bufferlength)) != 0)
  3455. {
  3456. RpcpMemoryCopy(Current, Buffer, bufferlength) ;
  3457. Current += bufferlength ;
  3458. ActuallyFreeBuffer(Buffer);
  3459. }
  3460. }
  3461. if (Message->Buffer)
  3462. {
  3463. ActuallyFreeBuffer(Message->Buffer);
  3464. }
  3465. Message->Buffer = NewBuffer ;
  3466. Message->BufferLength = TotalLength ;
  3467. RcvBufferLength = 0;
  3468. if (BufferComplete)
  3469. {
  3470. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  3471. }
  3472. else
  3473. {
  3474. if (Choked)
  3475. {
  3476. CallMutex.Clear() ;
  3477. //
  3478. // send a message to the server
  3479. // to start sending data again
  3480. //
  3481. SendMore.Rpc.RpcHeader.MessageType = LRPC_SERVER_SEND_MORE;
  3482. SendMore.LpcHeader.CallbackId = 0;
  3483. SendMore.LpcHeader.MessageId = 0;
  3484. SendMore.LpcHeader.u1.s1.DataLength =
  3485. sizeof(LRPC_MESSAGE) - sizeof(PORT_MESSAGE);
  3486. SendMore.LpcHeader.u1.s1.TotalLength = sizeof(LRPC_MESSAGE);
  3487. SendMore.LpcHeader.u2.ZeroInit = 0;
  3488. ASSERT(CallId != (ULONG) -1);
  3489. SendMore.Rpc.RpcHeader.CallId = CallId ;
  3490. NtStatus = NtRequestPort(Association->LpcClientPort,
  3491. (PORT_MESSAGE *) &SendMore) ;
  3492. if (!NT_SUCCESS(NtStatus))
  3493. {
  3494. return RPC_S_CALL_FAILED ;
  3495. }
  3496. return RPC_S_OK;
  3497. }
  3498. }
  3499. CallMutex.Clear() ;
  3500. return RPC_S_OK ;
  3501. }
  3502. void
  3503. LRPC_CCALL::ServerAborted (
  3504. IN OUT int *waitIterations
  3505. )
  3506. /*++
  3507. Routine Description:
  3508. The server has died, we need the call needs to reflect that, and
  3509. cleanup if possible.
  3510. --*/
  3511. {
  3512. if (pAsync)
  3513. {
  3514. int i;
  3515. for (;*waitIterations && AsyncStatus == RPC_S_ASYNC_CALL_PENDING; (*waitIterations)--)
  3516. {
  3517. Sleep(500);
  3518. }
  3519. LogEvent(SU_CCALL, EV_ABORT, this, (PVOID) 22, 22, 1, 0);
  3520. CallMutex.Request();
  3521. if (AsyncStatus == RPC_S_ASYNC_CALL_PENDING)
  3522. {
  3523. if (fSendComplete == 0)
  3524. {
  3525. AsyncStatus = RPC_S_CALL_FAILED;
  3526. CallMutex.Clear();
  3527. }
  3528. else
  3529. {
  3530. CallMutex.Clear();
  3531. CallFailed(RPC_S_CALL_FAILED);
  3532. }
  3533. }
  3534. else
  3535. {
  3536. CallMutex.Clear();
  3537. }
  3538. }
  3539. }
  3540. RPC_STATUS
  3541. LRPC_CCALL::SendReceive (
  3542. IN OUT PRPC_MESSAGE Message
  3543. )
  3544. /*++
  3545. Routine Description:
  3546. Arguments:
  3547. Message - Supplies the request and returns the response of a remote
  3548. procedure call.
  3549. Return Value:
  3550. RPC_S_OK - The remote procedure call completed successful.
  3551. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
  3552. remote procedure call.
  3553. RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to complete
  3554. the remote procedure call.
  3555. --*/
  3556. {
  3557. NTSTATUS NtStatus;
  3558. RPC_STATUS ExceptionCode, Status;
  3559. void * OriginalMessageBuffer;
  3560. LRPC_MESSAGE *SavedLrpcMessage = 0;
  3561. LRPC_MESSAGE *TmpLrpcMessage = 0;
  3562. int ActiveCallSetupFlag = 0;
  3563. void * TempBuffer;
  3564. ExtendedErrorInfo *EEInfo;
  3565. DebugClientCallInfo *ClientCallInfo;
  3566. DebugCallTargetInfo *CallTargetInfo;
  3567. CellTag ClientCallInfoCellTag;
  3568. CellTag CallTargetInfoCellTag;
  3569. THREAD *ThisThread = RpcpGetThreadPointer();
  3570. BOOL fDebugInfoSet = FALSE;
  3571. if (CallAbortedFlag != 0)
  3572. {
  3573. //
  3574. // Don't know if it is safe to free the buffer here
  3575. //
  3576. return(RPC_S_CALL_FAILED_DNE);
  3577. }
  3578. ASSERT(ThisThread);
  3579. // if either client side debugging is enabled or we are
  3580. // calling on a thread that has a scall dispatched
  3581. if ((IsClientSideDebugInfoEnabled() || ((ThisThread->Context) && IsServerSideDebugInfoEnabled())) && (RecursionCount == 0))
  3582. {
  3583. CStackAnsi AnsiString;
  3584. RPC_CHAR *Endpoint;
  3585. int EndpointLength;
  3586. if (!IsClientSideDebugInfoEnabled())
  3587. {
  3588. Status = SetDebugClientCallInformation(&ClientCallInfo, &ClientCallInfoCellTag,
  3589. &CallTargetInfo, &CallTargetInfoCellTag, Message, ThisThread->DebugCell,
  3590. ThisThread->DebugCellTag);
  3591. }
  3592. else
  3593. {
  3594. Status = SetDebugClientCallInformation(&ClientCallInfo, &ClientCallInfoCellTag,
  3595. &CallTargetInfo, &CallTargetInfoCellTag, Message, NULL, NULL);
  3596. }
  3597. if (Status != RPC_S_OK)
  3598. goto Cleanup;
  3599. ClientCallInfo->CallID = CallId;
  3600. Endpoint = Association->InqEndpoint();
  3601. EndpointLength = RpcpStringLength(Endpoint) + 1;
  3602. *(AnsiString.GetPAnsiString()) = (char *)_alloca(EndpointLength);
  3603. Status = AnsiString.Attach(Endpoint, EndpointLength, EndpointLength * 2);
  3604. // effectively ignore failure in the conversion
  3605. if (Status == RPC_S_OK)
  3606. {
  3607. strncpy(ClientCallInfo->Endpoint, AnsiString, sizeof(ClientCallInfo->Endpoint));
  3608. }
  3609. CallTargetInfo->ProtocolSequence = LRPC_TOWER_ID;
  3610. CallTargetInfo->TargetServer[0] = 0;
  3611. fDebugInfoSet = TRUE;
  3612. }
  3613. // NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
  3614. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  3615. if (CallStack == 0)
  3616. {
  3617. if (UuidSpecified)
  3618. {
  3619. RpcpMemoryCopy(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  3620. &ObjectUuid, sizeof(UUID));
  3621. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_OBJECT_UUID;
  3622. }
  3623. }
  3624. else
  3625. {
  3626. LrpcMessage->LpcHeader.u2.s2.Type = LPC_REQUEST;
  3627. LrpcMessage->LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  3628. LrpcMessage->LpcHeader.MessageId = MessageId;
  3629. LrpcMessage->LpcHeader.CallbackId = CallbackId;
  3630. }
  3631. LrpcMessage->LpcHeader.u1.s1.TotalLength = sizeof(PORT_MESSAGE)
  3632. + LrpcMessage->LpcHeader.u1.s1.DataLength;
  3633. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_REQUEST;
  3634. LrpcMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
  3635. LrpcMessage->Rpc.RpcHeader.PresentContext = GetOnTheWirePresentationContext();
  3636. if (CurrentSecurityContext)
  3637. {
  3638. LrpcMessage->Rpc.RpcHeader.SecurityContextId = CurrentSecurityContext->SecurityContextId;
  3639. }
  3640. else
  3641. {
  3642. LrpcMessage->Rpc.RpcHeader.SecurityContextId = -1;
  3643. }
  3644. TempBuffer = Message->Buffer;
  3645. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_SYNC_CLIENT | LRPC_NON_PIPE;
  3646. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  3647. (PORT_MESSAGE *) LrpcMessage,
  3648. (PORT_MESSAGE *) LrpcMessage);
  3649. if (NT_ERROR(NtStatus))
  3650. {
  3651. if (NtStatus == STATUS_NO_MEMORY)
  3652. {
  3653. Status = RPC_S_OUT_OF_MEMORY;
  3654. goto Cleanup;
  3655. }
  3656. if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  3657. {
  3658. Status = RPC_S_OUT_OF_RESOURCES;
  3659. goto Cleanup;
  3660. }
  3661. VALIDATE(NtStatus)
  3662. {
  3663. STATUS_INVALID_PORT_HANDLE,
  3664. STATUS_INVALID_HANDLE,
  3665. STATUS_PORT_DISCONNECTED,
  3666. STATUS_LPC_REPLY_LOST
  3667. } END_VALIDATE;
  3668. Association->AbortAssociation();
  3669. if ((CallStack == 0)
  3670. && (NtStatus != STATUS_LPC_REPLY_LOST))
  3671. {
  3672. //
  3673. // It's possible that the server stopped and has now restarted.
  3674. // We'll try re-binding and only fail if the new call fails.
  3675. //
  3676. // We can only retry if we are SURE that the server did not
  3677. // execute the request.
  3678. if (RecursionCount > 3)
  3679. {
  3680. // Prevent an infinite loop when GetBuffer returns ok but
  3681. // the SendReceive always fails.
  3682. Status = RPC_S_CALL_FAILED_DNE;
  3683. }
  3684. else
  3685. {
  3686. Status = AutoRetryCall(Message,
  3687. TRUE // fFromSendReceive
  3688. );
  3689. }
  3690. }
  3691. else
  3692. {
  3693. // In a callback and/or couldn't retry.
  3694. Status = RPC_S_CALL_FAILED;
  3695. }
  3696. Cleanup:
  3697. if (fDebugInfoSet)
  3698. {
  3699. FreeCell(CallTargetInfo, &CallTargetInfoCellTag);
  3700. FreeCell(ClientCallInfo, &ClientCallInfoCellTag);
  3701. }
  3702. ActuallyFreeBuffer(TempBuffer);
  3703. AbortCCall();
  3704. return Status;
  3705. }
  3706. // The message was sent and we got a reply okay.
  3707. ActuallyFreeBuffer(Message->Buffer);
  3708. for (;;)
  3709. {
  3710. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT)
  3711. {
  3712. if (LrpcMessage->Fault.RpcHeader.Flags & LRPC_EEINFO_PRESENT)
  3713. {
  3714. Status = UnpickleEEInfo(LrpcMessage->Fault.Buffer,
  3715. LrpcMessage->Fault.LpcHeader.u1.s1.TotalLength
  3716. - sizeof(LRPC_FAULT_MESSAGE)
  3717. + sizeof(LrpcMessage->Fault.Buffer),
  3718. &EEInfo);
  3719. if (Status == RPC_S_OK)
  3720. {
  3721. RpcpSetEEInfoForThread(ThisThread, EEInfo);
  3722. }
  3723. // else we just fall through and return an error code -
  3724. // this is best effort, so it's Ok
  3725. }
  3726. Status = LrpcMessage->Fault.RpcStatus;
  3727. break;
  3728. }
  3729. if ((LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_RESPONSE)
  3730. || (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2))
  3731. {
  3732. BOOL fFault2;
  3733. RPC_STATUS FaultStatus;
  3734. // remember if the message was fault2
  3735. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT2)
  3736. {
  3737. fFault2 = TRUE;
  3738. FaultStatus = LrpcMessage->Fault2.RpcStatus;
  3739. }
  3740. else
  3741. fFault2 = FALSE;
  3742. Status = LrpcMessageToRpcMessage(LrpcMessage,
  3743. Message,
  3744. Association->LpcClientPort,
  3745. FALSE, // IsReplyFromBackConnection
  3746. NULL // StatusIfDelayedAck
  3747. );
  3748. if (fFault2)
  3749. {
  3750. if (Status == RPC_S_OK)
  3751. {
  3752. Status = UnpickleEEInfo((unsigned char *)Message->Buffer,
  3753. Message->BufferLength,
  3754. &EEInfo);
  3755. if (Status == RPC_S_OK)
  3756. {
  3757. RpcpSetEEInfoForThread(ThisThread, EEInfo);
  3758. }
  3759. // else
  3760. // fall through to restoring the original status
  3761. }
  3762. // the status of the retrieval of
  3763. // the extended error info is irrelevant - we
  3764. // need to restore the original fault code
  3765. Status = FaultStatus;
  3766. }
  3767. break;
  3768. }
  3769. ASSERT(LrpcMessage->Rpc.RpcHeader.MessageType
  3770. == LRPC_MSG_CALLBACK);
  3771. CallStack += 1;
  3772. Status = RPC_S_OK;
  3773. if ((CallStack == 1)
  3774. && (ActiveCallSetupFlag == 0))
  3775. {
  3776. ClientId = MsgClientIdToClientId(LrpcMessage->LpcHeader.ClientId);
  3777. MessageId = LrpcMessage->LpcHeader.MessageId;
  3778. CallbackId = LrpcMessage->LpcHeader.CallbackId;
  3779. RecursiveCallsKey = CurrentBindingHandle->AddRecursiveCall(this);
  3780. if (RecursiveCallsKey == -1)
  3781. {
  3782. Status = RPC_S_OUT_OF_MEMORY;
  3783. }
  3784. else
  3785. {
  3786. ActiveCallSetupFlag = 1;
  3787. }
  3788. }
  3789. if (SavedLrpcMessage == 0)
  3790. {
  3791. // First callback, we may need to allocated a new LRPC_MESSAGE.
  3792. if (CachedLrpcMessage == 0)
  3793. {
  3794. CachedLrpcMessage = AllocateMessage() ;
  3795. }
  3796. if (CachedLrpcMessage == 0)
  3797. Status = RPC_S_OUT_OF_MEMORY;
  3798. }
  3799. if (Status == RPC_S_OK)
  3800. {
  3801. Status = LrpcMessageToRpcMessage(LrpcMessage,
  3802. Message,
  3803. Association->LpcClientPort,
  3804. FALSE, // IsReplyFromBackConnection
  3805. NULL // StatusIfDelayedAck
  3806. );
  3807. }
  3808. if (Status != RPC_S_OK)
  3809. {
  3810. ActuallyFreeBuffer(Message->Buffer);
  3811. LrpcMessage->Fault.RpcHeader.MessageType = LRPC_MSG_FAULT;
  3812. LrpcMessage->Fault.RpcStatus = LrpcMapRpcStatus(Status);
  3813. LrpcMessage->LpcHeader.u1.s1.DataLength =
  3814. sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
  3815. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  3816. sizeof(LRPC_FAULT_MESSAGE);
  3817. LrpcMessage->LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  3818. LrpcMessage->LpcHeader.MessageId = MessageId;
  3819. LrpcMessage->LpcHeader.CallbackId = CallbackId;
  3820. NtStatus = NtReplyWaitReplyPort(Association->LpcClientPort,
  3821. (PORT_MESSAGE *) LrpcMessage);
  3822. }
  3823. else
  3824. {
  3825. PRPC_DISPATCH_TABLE DispatchTableToUse;
  3826. OriginalMessageBuffer = Message->Buffer;
  3827. Message->TransferSyntax = Binding->GetTransferSyntaxId();
  3828. Message->ProcNum = LrpcMessage->Rpc.RpcHeader.ProcedureNumber;
  3829. if (SavedLrpcMessage == 0)
  3830. {
  3831. // First callback
  3832. ASSERT(CachedLrpcMessage != 0);
  3833. SavedLrpcMessage = LrpcMessage;
  3834. LrpcMessage = CachedLrpcMessage;
  3835. CachedLrpcMessage = 0;
  3836. }
  3837. else
  3838. {
  3839. // >First callback, LrpcMessage and SavedLrpcMessages swap roles
  3840. TmpLrpcMessage = SavedLrpcMessage;
  3841. SavedLrpcMessage = LrpcMessage;
  3842. LrpcMessage = TmpLrpcMessage;
  3843. }
  3844. Status = DispatchCallback((PRPC_DISPATCH_TABLE)
  3845. Binding->GetDispatchTable(),
  3846. Message,
  3847. &ExceptionCode);
  3848. if (OriginalMessageBuffer != SavedLrpcMessage->Rpc.Buffer)
  3849. {
  3850. ActuallyFreeBuffer(OriginalMessageBuffer);
  3851. }
  3852. if (Status != RPC_S_OK)
  3853. {
  3854. VALIDATE(Status)
  3855. {
  3856. RPC_P_EXCEPTION_OCCURED,
  3857. RPC_S_PROCNUM_OUT_OF_RANGE
  3858. } END_VALIDATE;
  3859. if (Status == RPC_P_EXCEPTION_OCCURED)
  3860. {
  3861. Status = LrpcMapRpcStatus(ExceptionCode);
  3862. }
  3863. LrpcMessage->Fault.RpcStatus = Status;
  3864. LrpcMessage->LpcHeader.u1.s1.DataLength =
  3865. sizeof(LRPC_FAULT_MESSAGE) - sizeof(PORT_MESSAGE);
  3866. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  3867. sizeof(LRPC_FAULT_MESSAGE);
  3868. LrpcMessage->Fault.RpcHeader.MessageType = LRPC_MSG_FAULT;
  3869. }
  3870. else
  3871. {
  3872. LrpcMessage->Rpc.RpcHeader.MessageType =
  3873. LRPC_MSG_RESPONSE;
  3874. if (LrpcMessage->Rpc.RpcHeader.Flags & LRPC_BUFFER_REQUEST)
  3875. {
  3876. Status = MakeServerCopyResponse();
  3877. if (Status != RPC_S_OK)
  3878. {
  3879. break;
  3880. }
  3881. }
  3882. }
  3883. LrpcMessage->LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  3884. LrpcMessage->LpcHeader.MessageId = MessageId;
  3885. LrpcMessage->LpcHeader.CallbackId = CallbackId;
  3886. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  3887. LrpcMessage->LpcHeader.u1.s1.DataLength + sizeof(PORT_MESSAGE);
  3888. NtStatus = NtReplyWaitReplyPort(Association->LpcClientPort,
  3889. (PORT_MESSAGE *) LrpcMessage);
  3890. RpcpPurgeEEInfo();
  3891. }
  3892. CallStack -= 1;
  3893. if (NT_ERROR(NtStatus))
  3894. {
  3895. if (NtStatus == STATUS_NO_MEMORY)
  3896. {
  3897. Status = RPC_S_OUT_OF_MEMORY;
  3898. }
  3899. else if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  3900. {
  3901. Status = RPC_S_OUT_OF_RESOURCES;
  3902. }
  3903. else
  3904. {
  3905. Association->AbortAssociation();
  3906. VALIDATE(NtStatus)
  3907. {
  3908. STATUS_INVALID_PORT_HANDLE,
  3909. STATUS_INVALID_HANDLE,
  3910. STATUS_PORT_DISCONNECTED,
  3911. STATUS_LPC_REPLY_LOST
  3912. } END_VALIDATE;
  3913. Status = RPC_S_CALL_FAILED;
  3914. }
  3915. break;
  3916. }
  3917. }
  3918. if (SavedLrpcMessage != 0)
  3919. {
  3920. if (CachedLrpcMessage != 0)
  3921. {
  3922. FreeMessage(CachedLrpcMessage) ;
  3923. }
  3924. CachedLrpcMessage = SavedLrpcMessage;
  3925. }
  3926. if (ActiveCallSetupFlag != 0)
  3927. {
  3928. CurrentBindingHandle->RemoveRecursiveCall(RecursiveCallsKey);
  3929. }
  3930. if (Status != RPC_S_OK)
  3931. {
  3932. if (CallStack == 0)
  3933. {
  3934. FreeCCall();
  3935. }
  3936. }
  3937. if (fDebugInfoSet)
  3938. {
  3939. FreeCell(CallTargetInfo, &CallTargetInfoCellTag);
  3940. FreeCell(ClientCallInfo, &ClientCallInfoCellTag);
  3941. }
  3942. return(Status);
  3943. }
  3944. RPC_STATUS
  3945. LRPC_CCALL::SendRequest (
  3946. IN OUT PRPC_MESSAGE Message,
  3947. OUT BOOL *Shutup
  3948. )
  3949. /*++
  3950. Routine Description:
  3951. Helper function used for sending async requests or pipe requests
  3952. Arguments:
  3953. Message - request message
  3954. Return Value:
  3955. RPC_S_OK - Function succeeded
  3956. RPC_S_OUT_OF_MEMORY - we ran out of memory
  3957. RPC_S_SEND_INCOMPLETE - we were unable to send the complete request.
  3958. --*/
  3959. {
  3960. NTSTATUS NtStatus;
  3961. RPC_STATUS ExceptionCode, Status;
  3962. void * OriginalMessageBuffer;
  3963. LRPC_MESSAGE *TmpLrpcMessage = 0;
  3964. void * TempBuffer;
  3965. LRPC_MESSAGE *LrpcReplyMessage ;
  3966. int RemainingLength = 0;
  3967. ASSERT((LrpcMessage->Rpc.RpcHeader.Flags
  3968. & LRPC_BUFFER_IMMEDIATE) == 0) ;
  3969. *Shutup = 0;
  3970. if (CallAbortedFlag != 0)
  3971. {
  3972. return(RPC_S_CALL_FAILED_DNE);
  3973. }
  3974. if (CallStack > 0)
  3975. {
  3976. return (RPC_S_CALL_FAILED);
  3977. }
  3978. if (PARTIAL(Message))
  3979. {
  3980. if (Message->BufferLength < MINIMUM_PARTIAL_BUFFLEN)
  3981. {
  3982. return (RPC_S_SEND_INCOMPLETE);
  3983. }
  3984. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_BUFFER_PARTIAL ;
  3985. if (NOT_MULTIPLE_OF_EIGHT(Message->BufferLength))
  3986. {
  3987. RemainingLength = Message->BufferLength & LOW_BITS ;
  3988. Message->BufferLength &= ~LOW_BITS ;
  3989. }
  3990. }
  3991. // NDR_DREP_ASCII | NDR_DREP_LITTLE_ENDIAN | NDR_DREP_IEEE
  3992. Message->DataRepresentation = 0x00 | 0x10 | 0x0000;
  3993. ASSERT(CallId != (ULONG) -1);
  3994. LrpcMessage->Rpc.RpcHeader.CallId = CallId ;
  3995. if (FirstFrag)
  3996. {
  3997. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_MSG_REQUEST;
  3998. }
  3999. else
  4000. {
  4001. LrpcMessage->Rpc.RpcHeader.MessageType = LRPC_PARTIAL_REQUEST;
  4002. }
  4003. LrpcMessage->LpcHeader.u1.s1.TotalLength =
  4004. sizeof(PORT_MESSAGE) + LrpcMessage->LpcHeader.u1.s1.DataLength;
  4005. LrpcMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  4006. LrpcMessage->Rpc.RpcHeader.ProcedureNumber = (unsigned short) Message->ProcNum;
  4007. LrpcMessage->Rpc.RpcHeader.PresentContext = GetOnTheWirePresentationContext();
  4008. if (CurrentSecurityContext)
  4009. {
  4010. LrpcMessage->Rpc.RpcHeader.SecurityContextId = CurrentSecurityContext->SecurityContextId;
  4011. }
  4012. else
  4013. {
  4014. LrpcMessage->Rpc.RpcHeader.SecurityContextId = -1;
  4015. }
  4016. if (UuidSpecified)
  4017. {
  4018. ASSERT(CallStack == 0) ;
  4019. RpcpMemoryCopy(&(LrpcMessage->Rpc.RpcHeader.ObjectUuid),
  4020. &ObjectUuid, sizeof(UUID));
  4021. LrpcMessage->Rpc.RpcHeader.Flags |= LRPC_OBJECT_UUID;
  4022. }
  4023. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  4024. (PORT_MESSAGE *) LrpcMessage,
  4025. (PORT_MESSAGE *) LrpcMessage);
  4026. if (NT_ERROR(NtStatus))
  4027. {
  4028. TempBuffer = Message->Buffer;
  4029. if (NtStatus == STATUS_NO_MEMORY)
  4030. {
  4031. Status = RPC_S_OUT_OF_MEMORY;
  4032. goto Cleanup;
  4033. }
  4034. if (NtStatus == STATUS_INSUFFICIENT_RESOURCES)
  4035. {
  4036. Status = RPC_S_OUT_OF_RESOURCES;
  4037. goto Cleanup;
  4038. }
  4039. VALIDATE(NtStatus)
  4040. {
  4041. STATUS_INVALID_PORT_HANDLE,
  4042. STATUS_INVALID_HANDLE,
  4043. STATUS_PORT_DISCONNECTED,
  4044. STATUS_LPC_REPLY_LOST
  4045. } END_VALIDATE;
  4046. if (pAsync)
  4047. {
  4048. ASSERT(RecursionCount == 0);
  4049. if (NtStatus != STATUS_LPC_REPLY_LOST)
  4050. {
  4051. Status = RPC_S_CALL_FAILED_DNE;
  4052. }
  4053. else
  4054. {
  4055. Status = RPC_S_CALL_FAILED;
  4056. }
  4057. goto Cleanup;
  4058. }
  4059. Association->AbortAssociation();
  4060. if ((NtStatus != STATUS_LPC_REPLY_LOST) && FirstFrag)
  4061. {
  4062. ASSERT(CallStack == 0) ;
  4063. //
  4064. // It's possible that the server stopped and has now restarted.
  4065. // We'll try re-binding and only fail if the new call fails.
  4066. //
  4067. // We can only retry if we are SURE that the server did not
  4068. // execute the request.
  4069. if (RecursionCount > 3)
  4070. {
  4071. // Prevent an infinite loop when GetBuffer returns ok but
  4072. // the SendReceive always fails.
  4073. Status = RPC_S_CALL_FAILED_DNE;
  4074. }
  4075. else
  4076. {
  4077. Status = AutoRetryCall(Message,
  4078. FALSE // fFromSendReceive
  4079. );
  4080. }
  4081. }
  4082. else
  4083. {
  4084. // In a callback and/or couldn't retry.
  4085. Status = RPC_S_CALL_FAILED;
  4086. }
  4087. Cleanup:
  4088. ActuallyFreeBuffer(TempBuffer);
  4089. AbortCCall();
  4090. return Status;
  4091. }
  4092. else
  4093. {
  4094. FirstFrag = 0;
  4095. }
  4096. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_ACK)
  4097. {
  4098. *Shutup = LrpcMessage->Ack.Shutup ;
  4099. if (PARTIAL(Message))
  4100. {
  4101. if (LrpcMessage->Ack.RpcStatus == RPC_S_OK)
  4102. {
  4103. if (RemainingLength)
  4104. {
  4105. RpcpMemoryMove(Message->Buffer,
  4106. (char *) Message->Buffer + Message->BufferLength,
  4107. RemainingLength) ;
  4108. Message->BufferLength = RemainingLength ;
  4109. return (RPC_S_SEND_INCOMPLETE) ;
  4110. }
  4111. return RPC_S_OK;
  4112. }
  4113. }
  4114. ActuallyFreeBuffer(Message->Buffer);
  4115. Message->Buffer = 0;
  4116. return LrpcMessage->Ack.RpcStatus ;
  4117. }
  4118. ActuallyFreeBuffer(Message->Buffer);
  4119. Message->Buffer = 0;
  4120. if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_RESPONSE)
  4121. {
  4122. ASSERT(!PARTIAL(Message)) ;
  4123. CurrentBufferLength = 0;
  4124. Status = LrpcMessageToRpcMessage(LrpcMessage,
  4125. Message,
  4126. Association->LpcClientPort,
  4127. FALSE, // IsReplyFromBackConnection
  4128. NULL // StatusIfDelayedAck
  4129. );
  4130. if (Status == RPC_S_OK
  4131. && COMPLETE(Message))
  4132. {
  4133. BufferComplete = 1;
  4134. }
  4135. Message->RpcFlags = 0;
  4136. // we have no out pipes
  4137. ASSERT(Status != RPC_S_OK || BufferComplete) ;
  4138. }
  4139. else if (LrpcMessage->Rpc.RpcHeader.MessageType == LRPC_MSG_FAULT)
  4140. {
  4141. CurrentBufferLength = 0;
  4142. Status = LrpcMessage->Fault.RpcStatus;
  4143. }
  4144. if (Status != RPC_S_OK)
  4145. {
  4146. ASSERT(CallStack == 0) ;
  4147. FreeCCall();
  4148. }
  4149. return Status ;
  4150. }
  4151. RPC_STATUS
  4152. LRPC_CCALL::AutoRetryCall (
  4153. IN OUT PRPC_MESSAGE Message,
  4154. BOOL fFromSendReceive
  4155. )
  4156. {
  4157. RPC_STATUS Status;
  4158. void *OldBuffer;
  4159. UUID *UuidToUse;
  4160. LRPC_CCALL *NewCall;
  4161. // any failure after this is unrelated
  4162. RpcpPurgeEEInfo();
  4163. OldBuffer = Message->Buffer;
  4164. Message->Handle = (RPC_BINDING_HANDLE) CurrentBindingHandle;
  4165. if (UuidSpecified)
  4166. {
  4167. UuidToUse = &ObjectUuid;
  4168. }
  4169. else
  4170. {
  4171. UuidToUse = 0;
  4172. }
  4173. Status = CurrentBindingHandle->NegotiateTransferSyntax(Message);
  4174. if (Status != RPC_S_OK)
  4175. goto CleanupAndReturn;
  4176. NewCall = ((LRPC_CCALL *)(Message->Handle));
  4177. Status = NewCall->GetBuffer(Message, UuidToUse);
  4178. if (Status != RPC_S_OK)
  4179. goto CleanupAndReturn;
  4180. ASSERT(Message->Buffer != OldBuffer);
  4181. RpcpMemoryCopy(Message->Buffer, OldBuffer,
  4182. Message->BufferLength);
  4183. // This CCALL should be freed,
  4184. // a new one was allocated in NegotiateTransferSyntax and is now being used.
  4185. ASSERT(NewCall != this);
  4186. NewCall->SetRecursionCount(RecursionCount + 1);
  4187. if (fFromSendReceive)
  4188. Status = NewCall->SendReceive(Message);
  4189. else
  4190. Status = NewCall->Send(Message);
  4191. // the caller has remembered the old buffer and call object,
  4192. // and will clean them up regardless of what we return - our
  4193. // job is simply to allocate a new call and buffer, and stick
  4194. // them in the Message
  4195. CleanupAndReturn:
  4196. if (Status == RPC_S_SERVER_UNAVAILABLE)
  4197. {
  4198. // Since we're retrying, if the server has gone missing,
  4199. // it just means that the call failed.
  4200. Status = RPC_S_CALL_FAILED_DNE;
  4201. }
  4202. return(Status);
  4203. }
  4204. RPC_STATUS
  4205. LRPC_CCALL::Send (
  4206. IN OUT PRPC_MESSAGE Message
  4207. )
  4208. /*++
  4209. Routine Description:
  4210. This rountine is used by pipes to send partila data...
  4211. Arguments:
  4212. Message - Supplies the request and returns the response of a remote
  4213. procedure call.
  4214. Return Value:
  4215. RPC_S_OK - The remote procedure call completed successful.
  4216. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
  4217. remote procedure call.
  4218. RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to complete
  4219. the remote procedure call.
  4220. --*/
  4221. {
  4222. RPC_STATUS Status ;
  4223. BOOL Shutup ;
  4224. Status = SendRequest(Message, &Shutup) ;
  4225. return(Status);
  4226. }
  4227. RPC_STATUS
  4228. LRPC_CCALL::Receive (
  4229. IN PRPC_MESSAGE Message,
  4230. IN unsigned int Size
  4231. )
  4232. /*++
  4233. Routine Description:
  4234. description
  4235. Arguments:
  4236. arg1 - description
  4237. Return Value:
  4238. RPC_S_OK - Function succeeded
  4239. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4240. --*/
  4241. {
  4242. int size = 0 ;
  4243. int BufferLength ;
  4244. int RequestedLength ;
  4245. RPC_STATUS Status ;
  4246. int ActualBufferLength = 0;
  4247. int Extra = IsExtraMessage(Message) ;
  4248. if (BufferComplete
  4249. && RcvBufferLength == 0)
  4250. {
  4251. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4252. return (RPC_S_OK) ;
  4253. }
  4254. // If you get here, it means that you have out pipe data.
  4255. //
  4256. // allocate a buffer big enough to hold the out data:
  4257. // if you have a partial receive, you can allocate the buffer up
  4258. // front and start receive data.
  4259. //
  4260. if (PARTIAL(Message))
  4261. {
  4262. if (Extra)
  4263. {
  4264. ActualBufferLength = Message->BufferLength ;
  4265. BufferLength = Message->BufferLength+Size ;
  4266. }
  4267. else
  4268. {
  4269. BufferLength = Size ;
  4270. }
  4271. }
  4272. else
  4273. {
  4274. if (Extra)
  4275. {
  4276. ActualBufferLength = Message->BufferLength ;
  4277. BufferLength = Message->BufferLength + MINIMUM_PARTIAL_BUFFLEN ;
  4278. }
  4279. else
  4280. {
  4281. BufferLength = MINIMUM_PARTIAL_BUFFLEN ;
  4282. }
  4283. }
  4284. Status = GetBufferDo(Message, BufferLength, Extra) ;
  4285. if (Status != RPC_S_OK)
  4286. {
  4287. FreeCCall();
  4288. return Status ;
  4289. }
  4290. RequestedLength = Message->BufferLength - ActualBufferLength;
  4291. while (!BufferComplete
  4292. && (!PARTIAL(Message) || (RcvBufferLength < Size)))
  4293. {
  4294. if (SyncEvent.Wait() == WAIT_FAILED)
  4295. {
  4296. return RPC_S_CALL_FAILED;
  4297. }
  4298. }
  4299. return GetCoalescedBuffer(Message, Extra);
  4300. }
  4301. void
  4302. LRPC_CCALL::FreeBuffer (
  4303. IN PRPC_MESSAGE Message
  4304. )
  4305. /*++
  4306. Routine Description:
  4307. We will free the supplied buffer.
  4308. Arguments:
  4309. Message - Supplies the buffer to be freed.
  4310. --*/
  4311. {
  4312. ActuallyFreeBuffer(Message->Buffer);
  4313. if (CallStack == 0)
  4314. {
  4315. FreeCCall();
  4316. }
  4317. }
  4318. void
  4319. LRPC_CCALL::FreePipeBuffer (
  4320. IN PRPC_MESSAGE Message
  4321. )
  4322. /*++
  4323. Routine Description:
  4324. description
  4325. Arguments:
  4326. arg1 - description
  4327. Return Value:
  4328. RPC_S_OK - Function succeeded
  4329. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4330. --*/
  4331. {
  4332. RpcpFarFree(Message->Buffer) ;
  4333. }
  4334. RPC_STATUS
  4335. LRPC_CCALL::GetBufferDo (
  4336. IN OUT PRPC_MESSAGE Message,
  4337. IN unsigned long NewSize,
  4338. IN int fDataValid
  4339. )
  4340. /*++
  4341. Routine Description:
  4342. description
  4343. Arguments:
  4344. arg1 - description
  4345. Return Value:
  4346. RPC_S_OK - Function succeeded
  4347. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4348. --*/
  4349. {
  4350. void *NewBuffer ;
  4351. int SizeToAlloc ;
  4352. if (NewSize < CurrentBufferLength)
  4353. {
  4354. Message->BufferLength = NewSize ;
  4355. }
  4356. else
  4357. {
  4358. SizeToAlloc = (NewSize < MINIMUM_PARTIAL_BUFFLEN) ?
  4359. MINIMUM_PARTIAL_BUFFLEN:NewSize ;
  4360. NewBuffer = RpcpFarAllocate(SizeToAlloc) ;
  4361. if (NewBuffer == 0)
  4362. {
  4363. RpcpFarFree(Message->Buffer) ;
  4364. CurrentBufferLength = 0;
  4365. Message->BufferLength = 0;
  4366. return RPC_S_OUT_OF_MEMORY ;
  4367. }
  4368. if (fDataValid && Message->BufferLength > 0)
  4369. {
  4370. RpcpMemoryCopy(NewBuffer,
  4371. Message->Buffer,
  4372. Message->BufferLength) ;
  4373. }
  4374. RpcpFarFree(Message->Buffer) ;
  4375. Message->Buffer = NewBuffer ;
  4376. Message->BufferLength = NewSize ;
  4377. CurrentBufferLength = SizeToAlloc ;
  4378. }
  4379. return RPC_S_OK ;
  4380. }
  4381. RPC_STATUS
  4382. LRPC_CCALL::ReallocPipeBuffer (
  4383. IN PRPC_MESSAGE Message,
  4384. IN unsigned int NewSize
  4385. )
  4386. /*++
  4387. Routine Description:
  4388. description
  4389. Arguments:
  4390. arg1 - description
  4391. Return Value:
  4392. RPC_S_OK - Function succeeded
  4393. RPC_S_OUT_OF_MEMORY - we ran out of memory
  4394. --*/
  4395. {
  4396. unsigned int SizeToAlloc ;
  4397. void *TempBuffer ;
  4398. if (LrpcMessage == 0)
  4399. {
  4400. LrpcMessage = AllocateMessage();
  4401. if (LrpcMessage == 0)
  4402. {
  4403. return(RPC_S_OUT_OF_MEMORY);
  4404. }
  4405. }
  4406. if (GetBufferDo(Message, NewSize, 1) != RPC_S_OK)
  4407. return RPC_S_OUT_OF_MEMORY ;
  4408. Message->BufferLength = NewSize ;
  4409. LrpcMessage->Rpc.RpcHeader.Flags = LRPC_BUFFER_REQUEST;
  4410. LrpcMessage->Rpc.Request.CountDataEntries = 1;
  4411. LrpcMessage->Rpc.Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  4412. LrpcMessage->Rpc.Request.DataEntries[0].Size = Message->BufferLength;
  4413. LrpcMessage->LpcHeader.CallbackId = 0;
  4414. LrpcMessage->LpcHeader.u2.ZeroInit = 0;
  4415. LrpcMessage->LpcHeader.u2.s2.DataInfoOffset = sizeof(PORT_MESSAGE)
  4416. + sizeof(LRPC_RPC_HEADER);
  4417. LrpcMessage->LpcHeader.u1.s1.DataLength = sizeof(LRPC_RPC_HEADER)
  4418. + sizeof(PORT_DATA_INFORMATION);
  4419. return (RPC_S_OK) ;
  4420. }
  4421. void
  4422. LRPC_CCALL::AbortCCall (
  4423. )
  4424. /*++
  4425. Routine Description:
  4426. This client call has failed, so we need to abort it. We may called
  4427. while nested in one or more callbacks.
  4428. --*/
  4429. {
  4430. LRPC_BINDING_HANDLE * BindingHandle;
  4431. CallAbortedFlag = 1;
  4432. if (CallStack == 0)
  4433. {
  4434. ASSERT(CurrentBindingHandle != 0);
  4435. BindingHandle = CurrentBindingHandle;
  4436. CurrentBindingHandle = 0;
  4437. BindingHandle->FreeCCall(this);
  4438. }
  4439. }
  4440. inline RPC_STATUS
  4441. LRPC_CCALL::LrpcMessageToRpcMessage (
  4442. IN LRPC_MESSAGE *LrpcResponse,
  4443. OUT RPC_MESSAGE * Message,
  4444. IN HANDLE LpcPort,
  4445. IN BOOL IsReplyFromBackConnection OPTIONAL,
  4446. OUT DelayedPipeAckData *AckData OPTIONAL
  4447. )
  4448. /*++
  4449. Routine Description:
  4450. We will convert from an LRPC_MESSAGE representation of a buffer (and
  4451. its length) to an RPC_MESSAGE representation.
  4452. Arguments:
  4453. LrpcResponse - the response we received from the server
  4454. RpcMessage - Returns the RPC_MESSAGE representation.
  4455. LpcPort - the association port on which we send data to the server
  4456. IsReplyFromBackConnection - non-zero if the reply is from back connection
  4457. AckData - if non-NULL, and the received data are pipe data, an
  4458. acknowledgement to a pipe response will be delayed, the current
  4459. status will be placed here, and it will be indicated the ack was
  4460. delayed. Also, if non-NULL, the caller must set
  4461. AckData->DelayedAckPipeNeeded to FALSE.
  4462. If NULL, any acknowledgement will be sent immediately.
  4463. --*/
  4464. {
  4465. NTSTATUS NtStatus;
  4466. SIZE_T NumberOfBytesRead;
  4467. #if defined(BUILD_WOW6432)
  4468. char CopyMessageBuffer[sizeof(LRPC_COPY_MESSAGE) + 8];
  4469. LRPC_COPY_MESSAGE *CopyMessagePtr = (LRPC_COPY_MESSAGE *) AlignPtr8(CopyMessageBuffer);
  4470. #else
  4471. LRPC_COPY_MESSAGE CopyMessageBuffer;
  4472. LRPC_COPY_MESSAGE *CopyMessagePtr = &CopyMessageBuffer;
  4473. #endif
  4474. RPC_STATUS Status = RPC_S_OK;
  4475. RPC_STATUS Status2;
  4476. BOOL fPartialResponse;
  4477. if (ARGUMENT_PRESENT(AckData))
  4478. {
  4479. ASSERT(AckData->DelayedAckPipeNeeded == FALSE);
  4480. }
  4481. if(LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  4482. {
  4483. Message->Buffer = LrpcResponse->Rpc.Buffer;
  4484. ASSERT(LrpcResponse->LpcHeader.u1.s1.DataLength
  4485. >= sizeof(LRPC_RPC_HEADER));
  4486. Message->BufferLength =
  4487. (unsigned int) LrpcResponse->LpcHeader.u1.s1.DataLength
  4488. - sizeof(LRPC_RPC_HEADER);
  4489. if ((LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_PARTIAL) == 0)
  4490. {
  4491. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4492. }
  4493. if (IsReplyFromBackConnection)
  4494. {
  4495. LpcReplyMessage = LrpcResponse ;
  4496. }
  4497. }
  4498. else if (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER)
  4499. {
  4500. if (IsReplyFromBackConnection == 0)
  4501. {
  4502. UINT BufferLength;
  4503. LPC_PVOID ServerBuffer;
  4504. ASSERT(LrpcMessage == LrpcResponse);
  4505. BufferLength = LrpcResponse->Rpc.Server.Length;
  4506. ServerBuffer = LrpcResponse->Rpc.Server.Buffer;
  4507. ASSERT(BufferLength < 0x80000000);
  4508. Message->BufferLength = BufferLength;
  4509. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4510. Message->Buffer = RpcpFarAllocate(BufferLength) ;
  4511. CopyMessagePtr->LpcHeader.u2.ZeroInit = 0;
  4512. CopyMessagePtr->Server.Buffer = ServerBuffer;
  4513. CopyMessagePtr->Server.Length = BufferLength;
  4514. if (Message->Buffer == 0)
  4515. {
  4516. CopyMessagePtr->RpcStatus = RPC_S_OUT_OF_MEMORY;
  4517. }
  4518. else
  4519. {
  4520. CopyMessagePtr->RpcStatus = RPC_S_OK;
  4521. CopyMessagePtr->Request.CountDataEntries = 1;
  4522. CopyMessagePtr->Request.DataEntries[0].Base = PtrToMsgPtr(Message->Buffer);
  4523. CopyMessagePtr->Request.DataEntries[0].Size = Message->BufferLength ;
  4524. CopyMessagePtr->LpcHeader.u2.s2.DataInfoOffset =
  4525. sizeof(PORT_MESSAGE) + sizeof(LRPC_RPC_HEADER);
  4526. }
  4527. CopyMessagePtr->LpcHeader.CallbackId = 0;
  4528. CopyMessagePtr->RpcHeader.Flags = LRPC_SYNC_CLIENT ;
  4529. CopyMessagePtr->LpcHeader.u1.s1.DataLength =
  4530. sizeof(LRPC_COPY_MESSAGE) - sizeof(PORT_MESSAGE);
  4531. CopyMessagePtr->LpcHeader.u1.s1.TotalLength =
  4532. sizeof(LRPC_COPY_MESSAGE);
  4533. CopyMessagePtr->RpcHeader.MessageType = LRPC_MSG_COPY;
  4534. CopyMessagePtr->IsPartial = 0 ;
  4535. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  4536. (PORT_MESSAGE *) CopyMessagePtr,
  4537. (PORT_MESSAGE *) CopyMessagePtr);
  4538. if ((NT_ERROR(NtStatus))
  4539. || (CopyMessagePtr->RpcStatus != RPC_S_OK))
  4540. {
  4541. RpcpFarFree(Message->Buffer);
  4542. return(RPC_S_OUT_OF_MEMORY);
  4543. }
  4544. }
  4545. else
  4546. {
  4547. fPartialResponse = FALSE;
  4548. if (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_PARTIAL)
  4549. {
  4550. fPartialResponse = TRUE;
  4551. CallMutex.Request() ;
  4552. if ((RcvBufferLength >= LRPC_THRESHOLD_SIZE))
  4553. {
  4554. Choked = 1;
  4555. }
  4556. CallMutex.Clear() ;
  4557. }
  4558. else
  4559. {
  4560. Message->RpcFlags |= RPC_BUFFER_COMPLETE ;
  4561. }
  4562. Message->BufferLength = (unsigned int)
  4563. LrpcResponse->Rpc.Request.DataEntries[0].Size ;
  4564. Message->Buffer = RpcpFarAllocate(
  4565. Message->BufferLength);
  4566. if (Message->Buffer != NULL)
  4567. {
  4568. NtStatus = NtReadRequestData(LpcPort,
  4569. (PORT_MESSAGE*) LrpcResponse,
  4570. 0,
  4571. Message->Buffer,
  4572. Message->BufferLength,
  4573. &NumberOfBytesRead) ;
  4574. if (NT_ERROR(NtStatus))
  4575. {
  4576. #if DBG
  4577. PrintToDebugger("LRPC: NtReadRequestData failed: %x\n", NtStatus) ;
  4578. #endif
  4579. Status = RPC_S_OUT_OF_MEMORY;
  4580. }
  4581. else
  4582. {
  4583. ASSERT(Message->BufferLength == NumberOfBytesRead);
  4584. }
  4585. }
  4586. else
  4587. {
  4588. Status = RPC_S_OUT_OF_MEMORY;
  4589. }
  4590. if (ARGUMENT_PRESENT(AckData) && fPartialResponse && (Status == RPC_S_OK))
  4591. {
  4592. // if pipe and delayed ack was asked for, and
  4593. // moreover the operation didn't fail
  4594. // just store the relevant data in the caller
  4595. // supplied data structure
  4596. AckData->DelayedAckPipeNeeded = TRUE;
  4597. AckData->CurrentStatus = Status;
  4598. }
  4599. else
  4600. {
  4601. Status2 = SendPipeAck(LpcPort,
  4602. LrpcResponse,
  4603. Status);
  4604. FreeMessage(LrpcResponse) ;
  4605. // if either operation failed, fail the whole function
  4606. // if both operations failed, the first one is considered
  4607. // the original failure and the error code from it is
  4608. // preserved
  4609. if ((Status == RPC_S_OK) && (Status2 != RPC_S_OK))
  4610. Status = Status2;
  4611. }
  4612. if ((Status != RPC_S_OK) && (Message->Buffer))
  4613. {
  4614. RpcpFarFree(Message->Buffer);
  4615. }
  4616. }
  4617. }
  4618. else
  4619. {
  4620. ASSERT((LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_IMMEDIATE)
  4621. || (LrpcResponse->Rpc.RpcHeader.Flags & LRPC_BUFFER_SERVER));
  4622. }
  4623. return(Status);
  4624. }
  4625. RPC_STATUS
  4626. LRPC_CCALL::SendPipeAck (
  4627. IN HANDLE LpcPort,
  4628. IN LRPC_MESSAGE *LrpcResponse,
  4629. IN RPC_STATUS CurrentStatus
  4630. )
  4631. /*++
  4632. Routine Description:
  4633. Sends an acknowledgement to the server.
  4634. Arguments:
  4635. LpcPort - the port to send the ack to.
  4636. LrpcResponse - the response that we received from the server
  4637. CurrentStatus - the status up to the moment. It will
  4638. be sent to the server.
  4639. Return Value:
  4640. The result of the operation. RPC_S_OK for success
  4641. or RPC_S_* for error.
  4642. --*/
  4643. {
  4644. unsigned char MessageType;
  4645. RPC_STATUS RpcStatus = RPC_S_OK;
  4646. NTSTATUS NtStatus;
  4647. MessageType = LrpcResponse->Rpc.RpcHeader.MessageType ;
  4648. LrpcResponse->Ack.MessageType = LRPC_MSG_ACK ;
  4649. LrpcResponse->Ack.Shutup = (short) Choked ;
  4650. LrpcResponse->Ack.RpcStatus = CurrentStatus;
  4651. LrpcResponse->LpcHeader.u1.s1.DataLength = sizeof(LRPC_ACK_MESSAGE)
  4652. - sizeof(PORT_MESSAGE) ;
  4653. LrpcResponse->LpcHeader.u1.s1.TotalLength =
  4654. sizeof(LRPC_ACK_MESSAGE) ;
  4655. // setup the reply message
  4656. NtStatus = NtReplyPort(LpcPort,
  4657. (PORT_MESSAGE *) LrpcResponse) ;
  4658. LrpcResponse->Rpc.RpcHeader.MessageType = MessageType ;
  4659. if (NT_ERROR(NtStatus))
  4660. {
  4661. #if DBG
  4662. PrintToDebugger("LRPC: NtReplyPort failed: %x\n", NtStatus) ;
  4663. #endif
  4664. RpcStatus = RPC_S_OUT_OF_MEMORY;
  4665. }
  4666. return RpcStatus;
  4667. }
  4668. BOOL
  4669. LRPC_CCALL::TryWaitForCallToBecomeUnlocked (
  4670. BOOL *fUnlocked
  4671. )
  4672. /*++
  4673. Routine Description:
  4674. Checks if a call is unlocked. If the lock count
  4675. becomes 0, or if the lock count becomes 1 and this thread
  4676. is the last one with a lock, the call is considered unlocked.
  4677. In this case *fUnlocked is set to TRUE. Otherwise it is set to FALSE.
  4678. Return Value:
  4679. If fUnlocked == TRUE:
  4680. TRUE - the call has 1 outstanding lock count and the
  4681. LastProcessResponseTID is our TID. This means that we're
  4682. called from ProcessResponse (indirectly - through COM as
  4683. they complete the call on the thread that issues the
  4684. notification). If we return TRUE, we have already taken
  4685. the lock down and the caller should not remove any locks
  4686. FALSE - the call has no outstanding locks
  4687. If fUnlocked == FALSE
  4688. Undefined
  4689. --*/
  4690. {
  4691. ULONG CurrentThreadId = GetCurrentThreadId();
  4692. if (ResponseLockCount.GetInteger() == 0)
  4693. {
  4694. *fUnlocked = TRUE;
  4695. return FALSE;
  4696. }
  4697. else if ((ResponseLockCount.GetInteger() == 1)
  4698. && (LastProcessResponseTID == CurrentThreadId))
  4699. {
  4700. // If our caller has an outstanding lock and we free the call
  4701. // with the lock held, zero out the count on their behalf.
  4702. // In our caller we will notify the ultimate caller so that it
  4703. // doesn't double take away the lock.
  4704. ResponseLockCount.SetInteger(0);
  4705. // the only outstanding lock is by us in our caller - process
  4706. // response. Indicate to the caller that only our lock is
  4707. // active and it has been taken down.
  4708. *fUnlocked = TRUE;
  4709. return TRUE;
  4710. }
  4711. *fUnlocked = FALSE;
  4712. // The return value is meaningless. Arbitrarily, return FALSE.
  4713. return FALSE;
  4714. }
  4715. void
  4716. LRPC_CCALL::FreeCCall (
  4717. )
  4718. /*++
  4719. Routine Description:
  4720. We are done with this client call. We need to notify the binding
  4721. handle we are done.
  4722. --*/
  4723. {
  4724. LRPC_BINDING_HANDLE * BindingHandle;
  4725. THREAD *Thread;
  4726. ASSERT(CurrentBindingHandle != 0);
  4727. BindingHandle = CurrentBindingHandle;
  4728. CurrentBindingHandle = 0;
  4729. if (CurrentSecurityContext)
  4730. {
  4731. CurrentSecurityContext->RemoveReference();
  4732. CurrentSecurityContext = 0;
  4733. }
  4734. // if async, and there is EEInfo,
  4735. // transfer the EEInfo from the call to
  4736. // the thread
  4737. if (EEInfo)
  4738. {
  4739. Thread = RpcpGetThreadPointer();
  4740. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  4741. Thread->SetEEInfo(EEInfo);
  4742. EEInfo = NULL;
  4743. }
  4744. BindingHandle->FreeCCall(this);
  4745. }
  4746. void
  4747. LRPC_CCALL::ActuallyFreeBuffer (
  4748. IN void * Buffer
  4749. )
  4750. /*++
  4751. Routine Description:
  4752. Actually free a message buffer.
  4753. Arguments:
  4754. Buffer - Supplies the message buffer to be freed.
  4755. --*/
  4756. {
  4757. if (LpcReplyMessage && (Buffer == LpcReplyMessage->Rpc.Buffer))
  4758. {
  4759. FreeMessage(LpcReplyMessage) ;
  4760. LpcReplyMessage = 0;
  4761. }
  4762. else
  4763. {
  4764. if ((Buffer != LrpcMessage->Rpc.Buffer)
  4765. && ((CachedLrpcMessage == 0)
  4766. || (Buffer != CachedLrpcMessage->Rpc.Buffer)))
  4767. {
  4768. RpcpFarFree(Buffer);
  4769. }
  4770. }
  4771. }
  4772. RPC_STATUS
  4773. LRPC_CCALL::MakeServerCopyResponse (
  4774. )
  4775. /*++
  4776. Routine Description:
  4777. NtReadRequestData only works if the client has made a request. The client
  4778. wants to send a large buffer back as a response. We need to make a request
  4779. to the server so that it will copy the data.
  4780. Return Value:
  4781. RPC_S_OK - The server successfully copied the data.
  4782. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
  4783. operation.
  4784. --*/
  4785. {
  4786. LRPC_PUSH_MESSAGE LrpcPushMessage;
  4787. NTSTATUS NtStatus;
  4788. LrpcPushMessage.LpcHeader.u1.s1.TotalLength =
  4789. sizeof(LRPC_PUSH_MESSAGE);
  4790. LrpcPushMessage.LpcHeader.u1.s1.DataLength =
  4791. sizeof(LRPC_PUSH_MESSAGE) - sizeof(PORT_MESSAGE);
  4792. LrpcPushMessage.LpcHeader.ClientId = ClientIdToMsgClientId(ClientId);
  4793. LrpcPushMessage.LpcHeader.MessageId = MessageId;
  4794. LrpcPushMessage.LpcHeader.CallbackId = CallbackId ;
  4795. LrpcPushMessage.LpcHeader.u2.s2.Type = LPC_REQUEST;
  4796. LrpcPushMessage.RpcHeader.MessageType = LRPC_MSG_PUSH;
  4797. LrpcPushMessage.Response.CountDataEntries = 1;
  4798. LrpcPushMessage.Response.DataEntries[0] =
  4799. LrpcMessage->Rpc.Request.DataEntries[0];
  4800. LrpcPushMessage.LpcHeader.u2.s2.DataInfoOffset = sizeof(PORT_MESSAGE)
  4801. + sizeof(LRPC_RPC_HEADER);
  4802. NtStatus = NtRequestWaitReplyPort(Association->LpcClientPort,
  4803. (PORT_MESSAGE *) &LrpcPushMessage,
  4804. (PORT_MESSAGE *) &LrpcPushMessage);
  4805. if (NT_ERROR(NtStatus))
  4806. {
  4807. // Assume that when the client tries to send the response it will
  4808. // fail as well, so just claim that everything worked.
  4809. #if DBG
  4810. if ((NtStatus != STATUS_NO_MEMORY)
  4811. && (NtStatus != STATUS_INSUFFICIENT_RESOURCES))
  4812. {
  4813. PrintToDebugger("RPC : NtRequestWaitReplyPort : %lx\n", NtStatus);
  4814. ASSERT(0);
  4815. }
  4816. #endif // DBG
  4817. return(RPC_S_OK);
  4818. }
  4819. VALIDATE(LrpcPushMessage.RpcStatus)
  4820. {
  4821. RPC_S_OK,
  4822. RPC_S_OUT_OF_MEMORY
  4823. } END_VALIDATE;
  4824. return(LrpcPushMessage.RpcStatus);
  4825. }
  4826. BINDING_HANDLE *
  4827. LrpcCreateBindingHandle (
  4828. )
  4829. /*++
  4830. Routine Description:
  4831. We just need to create a new LRPC_BINDING_HANDLE. This routine is a
  4832. proxy for the new constructor to isolate the other modules.
  4833. --*/
  4834. {
  4835. LRPC_BINDING_HANDLE * BindingHandle;
  4836. RPC_STATUS Status = RPC_S_OK;
  4837. Status = InitializeLrpcIfNecessary() ;
  4838. if (Status != RPC_S_OK)
  4839. {
  4840. return 0 ;
  4841. }
  4842. BindingHandle = new LRPC_BINDING_HANDLE(&Status);
  4843. if (Status != RPC_S_OK)
  4844. {
  4845. delete BindingHandle;
  4846. return(0);
  4847. }
  4848. return(BindingHandle);
  4849. }
  4850. void
  4851. LRPC_CASSOCIATION::LrpcDeleteLingeringAssociations (
  4852. void
  4853. )
  4854. /*++
  4855. Routine Description:
  4856. Will attempt to clean up lingering LRPC associations.
  4857. Return Value:
  4858. --*/
  4859. {
  4860. BOOL fMutexTaken;
  4861. LRPC_CASSOCIATION *CurrentAssociation;
  4862. LRPC_CASSOCIATION *NextAssociation;
  4863. LRPC_CASSOCIATION *FirstAssociation;
  4864. DictionaryCursor cursor;
  4865. DWORD CurrentTickCount;
  4866. int Diff;
  4867. // if there are no lrpc associations, return
  4868. if (!GlobalLrpcServer)
  4869. return;
  4870. fMutexTaken = LrpcMutexTryRequest();
  4871. if (!fMutexTaken)
  4872. {
  4873. // we couldn't cleanup anything - restore the flag
  4874. if (!GarbageCollectionRequested)
  4875. GarbageCollectionRequested = TRUE;
  4876. return;
  4877. }
  4878. FirstAssociation = NULL;
  4879. CurrentTickCount = GetTickCount();
  4880. // need to walk the dictionary and clean up all associations with
  4881. // expired timeouts
  4882. LrpcAssociationDict->Reset(cursor);
  4883. while ((CurrentAssociation = LrpcAssociationDict->Next(cursor)) != 0)
  4884. {
  4885. if (CurrentAssociation->Linger.fAssociationLingered)
  4886. {
  4887. // this will work even for wrapped tick count
  4888. Diff = (int)(CurrentTickCount - CurrentAssociation->Linger.Timestamp);
  4889. if (Diff > 0)
  4890. {
  4891. #if defined (RPC_GC_AUDIT)
  4892. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) LRPC association gc'ed %d ms after expire\n",
  4893. GetCurrentProcessId(), GetCurrentProcessId(), Diff);
  4894. #endif
  4895. // enlink the expired associations to a list - we'll clean it up
  4896. // later
  4897. CurrentAssociation->NextAssociation = FirstAssociation;
  4898. FirstAssociation = CurrentAssociation;
  4899. LrpcAssociationDict->Delete(CurrentAssociation->AssociationDictKey);
  4900. // indicate to the other threads (needed once we release the mutex)
  4901. // that this association is being cleaned up and they cannot call
  4902. // Delete on it
  4903. CurrentAssociation->AssociationDictKey = -1;
  4904. LrpcLingeredAssociations --;
  4905. }
  4906. else
  4907. {
  4908. // this item hasn't expired yet - update the first gc time, and
  4909. // raise the GarbageCollectionRequested flag if necessary
  4910. if ((int)(CurrentAssociation->Linger.Timestamp - NextOneTimeCleanup) < 0)
  4911. {
  4912. // there is a race between this thread and threads calling
  4913. // GarbageCollectionNeeded. Those threads may overwrite the
  4914. // value we're about to write, which can result in delayed
  4915. // garbage collection for this value - that's ok.
  4916. NextOneTimeCleanup = CurrentAssociation->Linger.Timestamp;
  4917. }
  4918. if (!GarbageCollectionRequested)
  4919. GarbageCollectionRequested = TRUE;
  4920. }
  4921. }
  4922. }
  4923. LrpcMutexClear();
  4924. // destroy the associations at our leasure
  4925. CurrentAssociation = FirstAssociation;
  4926. while (CurrentAssociation != NULL)
  4927. {
  4928. NextAssociation = CurrentAssociation->NextAssociation;
  4929. CurrentAssociation->Delete();
  4930. CurrentAssociation = NextAssociation;
  4931. }
  4932. }
  4933. int
  4934. InitializeRpcProtocolLrpc (
  4935. )
  4936. /*++
  4937. Routine Description:
  4938. For each process, this routine will be called once. All initialization
  4939. will be done here.
  4940. Return Value:
  4941. Zero will be returned if initialization completes successfully,
  4942. otherwise, non-zero will be returned.
  4943. --*/
  4944. {
  4945. LrpcAssociationDict = new LRPC_CASSOCIATION_DICT;
  4946. if (LrpcAssociationDict == 0)
  4947. {
  4948. return(1);
  4949. }
  4950. return(0);
  4951. }
  4952. RPC_STATUS
  4953. LrpcMapRpcStatus (
  4954. IN RPC_STATUS Status
  4955. )
  4956. /*++
  4957. Routine Description:
  4958. Some NTSTATUS codes need to be mapped into RPC_STATUS codes before being
  4959. returned as a fault code. We take care of doing that mapping in this
  4960. routine.
  4961. --*/
  4962. {
  4963. switch (Status)
  4964. {
  4965. case STATUS_INTEGER_DIVIDE_BY_ZERO :
  4966. return(RPC_S_ZERO_DIVIDE);
  4967. case STATUS_ACCESS_VIOLATION :
  4968. case STATUS_ILLEGAL_INSTRUCTION :
  4969. return(RPC_S_ADDRESS_ERROR);
  4970. case STATUS_FLOAT_DIVIDE_BY_ZERO :
  4971. return(RPC_S_FP_DIV_ZERO);
  4972. case STATUS_FLOAT_UNDERFLOW :
  4973. return(RPC_S_FP_UNDERFLOW);
  4974. case STATUS_FLOAT_OVERFLOW :
  4975. return(RPC_S_FP_OVERFLOW);
  4976. }
  4977. return(Status);
  4978. }