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.

1528 lines
35 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. wmsgclnt.hxx
  5. Abstract:
  6. Class definitions for the client side of the WMSG (RPC on LPC) protocol
  7. engine.
  8. Author:
  9. Steven Zeck (stevez) 12/17/91
  10. Revision History:
  11. 15-Dec-1992 mikemon
  12. Rewrote the majority of the code and added comments.
  13. ----mazharm Code fork from spcclnt.hxx to implement WMSG protocol
  14. 21-Dec-1995 tonychan
  15. Added Single Security Model
  16. 05-10-96 mazharm merged WMSG and LRPC into a single protocol
  17. Kamen Moutafov (kamenm) Jan-2000 Support for multiple transfer syntaxes
  18. --*/
  19. #ifndef __LPCCLNT_HXX__
  20. #define __LPCCLNT_HXX__
  21. class LRPC_CASSOCIATION;
  22. class LRPC_CCALL;
  23. NEW_SDICT(LRPC_CCALL);
  24. NEW_SDICT2(LRPC_CCALL, PVOID);
  25. NEW_SDICT(LRPC_CASSOCIATION);
  26. #define CONTEXT_CACHE_TIMEOUT 10000
  27. #define CACHE_CHECK_TIMEOUT 10000
  28. RPC_STATUS
  29. I_RpcParseSecurity (
  30. IN RPC_CHAR * NetworkOptions,
  31. OUT SECURITY_QUALITY_OF_SERVICE * SecurityQualityOfService
  32. ) ;
  33. class LRPC_CCONTEXT
  34. {
  35. public:
  36. LUID ModifiedId;
  37. ULONG SecurityContextId;
  38. BOOL DefaultLogonId;
  39. LRPC_CASSOCIATION *Association;
  40. int ContextKey;
  41. INTERLOCKED_INTEGER RefCount;
  42. BOOL fDeleteMe;
  43. private:
  44. DWORD Timestamp;
  45. public:
  46. LRPC_CCONTEXT (
  47. IN CLIENT_AUTH_INFO *pAuthInfo,
  48. IN ULONG MySecurityContextId,
  49. IN LRPC_CASSOCIATION *MyAssociation
  50. ) : RefCount(0)
  51. {
  52. ASSERT(pAuthInfo);
  53. DefaultLogonId = pAuthInfo->DefaultLogonId;
  54. FastCopyLUIDAligned(&ModifiedId, &pAuthInfo->ModifiedId);
  55. SecurityContextId = MySecurityContextId;
  56. Timestamp = GetTickCount();
  57. Association = MyAssociation;
  58. fDeleteMe = FALSE;
  59. }
  60. void
  61. UpdateTimestamp()
  62. {
  63. Timestamp = GetTickCount();
  64. }
  65. BOOL
  66. IsSecurityContextOld()
  67. {
  68. if (GetTickCount()-Timestamp > CONTEXT_CACHE_TIMEOUT)
  69. {
  70. return TRUE;
  71. }
  72. return FALSE;
  73. }
  74. BOOL IsUnused()
  75. {
  76. return (RefCount.GetInteger() == 0);
  77. }
  78. void AddReference();
  79. void RemoveReference();
  80. void Destroy();
  81. };
  82. class LRPC_BINDING_HANDLE : public BINDING_HANDLE
  83. /*++
  84. Class Description:
  85. Fields:
  86. Association - Contains a pointer to the association used by this
  87. binding handle. The association is used by an LRPC_MESSAGE to
  88. make a remote procedure call. Before the first remote procedure
  89. call is made using this binding handle, the association will
  90. be zero. When the first remote procedure call is made, an
  91. association will be found or created for use by this binding
  92. handle.
  93. DceBinding - Before the first remote procedure call for this binding
  94. handle, this will contain the DCE binding information necessary
  95. to create or find an association to be used by this binding handle.
  96. After we have an association, this field will be zero.
  97. BindingReferenceCount - Keeps track of the applications reference to
  98. this object and of the number of LRPC_CCALLS which reference this
  99. object.
  100. BindingMutex - This is used to serialize access to the Association and
  101. DceBinding fields of this object. We can not use the global mutex
  102. because resolving the endpoint may require that we make a remote
  103. procedure call to the endpoint mapper on another machine. We also
  104. serialize access to the reference count.
  105. ActiveCalls - THis is a dictionary of the active calls indexed by thread
  106. identifier and rpc interface information.
  107. --*/
  108. {
  109. friend class LRPC_CCALL;
  110. friend class LRPC_CASSOCIATION;
  111. private:
  112. LRPC_CASSOCIATION * CurrentAssociation;
  113. LRPC_CASSOCIATION_DICT SecAssociation;
  114. DCE_BINDING * DceBinding;
  115. // we do some magic when operating the BindingReferenceCount
  116. // to avoid taking a critical section. Here's an overview of
  117. // the synchronization on this variable. Normally, we do it
  118. // through interlocks in the common paths. The only two places
  119. // where we need to ensure atomicity of other changes in relation
  120. // to this variable is where we effectively reset the binding
  121. // handle, and where we need to ensure the refcount is 1 for
  122. // the duration of the reset. There we take the BindingMutex.
  123. // The mixing of interlocks and a critical section in this
  124. // particular case is not a problem, because the addition of
  125. // a refcount happens only in the AllocateCCall, where we hold
  126. // the mutex (and we interlock as well), so when we hold the
  127. // mutex we know that the refcount will not increase. When the
  128. // refcount is 1, we know that the refcount will not decrease
  129. // as well, because the only refcount is ours, and we control
  130. // that. Therefore, if the refcount is 1 when you hold the mutex
  131. // you know the interlocks will not introduce a race.
  132. INTERLOCKED_INTEGER BindingReferenceCount;
  133. int AuthInfoInitialized ;
  134. LRPC_CCALL_DICT RecursiveCalls;
  135. HANDLE StaticTokenHandle;
  136. BOOL EffectiveOnly;
  137. BOOL fDynamicEndpoint;
  138. public:
  139. LRPC_BINDING_HANDLE (
  140. OUT RPC_STATUS * Status
  141. );
  142. ~LRPC_BINDING_HANDLE (
  143. );
  144. virtual RPC_STATUS
  145. NegotiateTransferSyntax (
  146. IN OUT PRPC_MESSAGE Message
  147. );
  148. virtual RPC_STATUS
  149. GetBuffer (
  150. IN OUT PRPC_MESSAGE Message,
  151. IN UUID *ObjectUuid
  152. );
  153. virtual RPC_STATUS
  154. BindingCopy (
  155. OUT BINDING_HANDLE * * DestinationBinding,
  156. IN unsigned int MaintainContext
  157. );
  158. virtual RPC_STATUS
  159. BindingFree (
  160. );
  161. virtual RPC_STATUS
  162. PrepareBindingHandle (
  163. IN TRANS_INFO * TransportInformation,
  164. IN DCE_BINDING * DceBinding
  165. );
  166. virtual RPC_STATUS
  167. ToStringBinding (
  168. OUT RPC_CHAR * * StringBinding
  169. );
  170. virtual RPC_STATUS
  171. ResolveBinding (
  172. IN RPC_CLIENT_INTERFACE * RpcClientInterface
  173. );
  174. virtual RPC_STATUS
  175. BindingReset (
  176. );
  177. virtual RPC_STATUS
  178. InquireTransportType(
  179. OUT unsigned int * Type
  180. )
  181. {
  182. *Type = TRANSPORT_TYPE_LPC;
  183. return(RPC_S_OK);
  184. }
  185. inline ULONG
  186. GetIdentityTracking (
  187. void
  188. );
  189. void
  190. FreeCCall (
  191. IN LRPC_CCALL * CCall
  192. );
  193. int
  194. AddRecursiveCall (
  195. IN LRPC_CCALL * CCall
  196. );
  197. void
  198. RemoveRecursiveCall (
  199. IN int ActiveCallsKey
  200. );
  201. virtual RPC_STATUS
  202. SetAuthInformation (
  203. IN RPC_CHAR * ServerPrincipalName, OPTIONAL
  204. IN unsigned long AuthenticationLevel,
  205. IN unsigned long AuthenticationService,
  206. IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity, OPTIONAL
  207. IN unsigned long AuthorizationService, OPTIONAL
  208. IN SECURITY_CREDENTIALS * Credentials,
  209. IN unsigned long ImpersonationType,
  210. IN unsigned long IdentityTracking,
  211. IN unsigned long Capabilities,
  212. IN BOOL bAcquireNewCredentials = FALSE,
  213. IN ULONG AdditionalTransportCredentialsType = 0, OPTIONAL
  214. IN void *AdditionalCredentials = NULL OPTIONAL
  215. );
  216. int
  217. AddAssociation (
  218. IN LRPC_CASSOCIATION * Association
  219. );
  220. void
  221. RemoveAssociation (
  222. IN LRPC_CASSOCIATION * Association
  223. );
  224. virtual unsigned long
  225. MapAuthenticationLevel (
  226. IN unsigned long AuthenticationLevel
  227. );
  228. virtual CLIENT_AUTH_INFO *
  229. InquireAuthInformation (
  230. void
  231. );
  232. virtual RPC_STATUS
  233. ReAcquireCredentialsIfNecessary (
  234. void
  235. );
  236. BOOL
  237. CompareCredentials (
  238. IN LRPC_CCONTEXT *SecurityContext
  239. );
  240. void
  241. UpdateCredentials(
  242. IN BOOL fDefault,
  243. IN LUID *ModifiedId
  244. );
  245. virtual RPC_STATUS
  246. SetTransportOption( unsigned long option,
  247. ULONG_PTR optionValue );
  248. virtual RPC_STATUS
  249. InqTransportOption( unsigned long option,
  250. ULONG_PTR * pOptionValue );
  251. private:
  252. RPC_STATUS
  253. AllocateCCall (
  254. OUT LRPC_CCALL ** CCall,
  255. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
  256. IN OUT PRPC_MESSAGE Message
  257. );
  258. };
  259. inline RPC_STATUS
  260. LRPC_BINDING_HANDLE::ReAcquireCredentialsIfNecessary (
  261. )
  262. {
  263. LUID CurrentModifiedId;
  264. RPC_STATUS Status;
  265. ASSERT(ClientAuthInfo.IdentityTracking == RPC_C_QOS_IDENTITY_STATIC);
  266. Status = CaptureModifiedId(&CurrentModifiedId);
  267. if (Status == RPC_S_OK)
  268. {
  269. FastCopyLUIDAligned(&ClientAuthInfo.ModifiedId, &CurrentModifiedId);
  270. ClientAuthInfo.DefaultLogonId = FALSE;
  271. }
  272. else
  273. {
  274. ClientAuthInfo.DefaultLogonId = TRUE;
  275. }
  276. return RPC_S_OK;
  277. }
  278. inline void
  279. LRPC_BINDING_HANDLE::UpdateCredentials(
  280. IN BOOL fDefault,
  281. IN LUID *ModifiedId
  282. )
  283. {
  284. ASSERT(ClientAuthInfo.IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC);
  285. if (fDefault)
  286. {
  287. ClientAuthInfo.DefaultLogonId = TRUE;
  288. }
  289. else
  290. {
  291. FastCopyLUIDAligned(&ClientAuthInfo.ModifiedId, ModifiedId);
  292. ClientAuthInfo.DefaultLogonId = FALSE;
  293. }
  294. }
  295. inline BOOL
  296. LRPC_BINDING_HANDLE::CompareCredentials (
  297. IN LRPC_CCONTEXT *SecurityContext
  298. )
  299. {
  300. if (ClientAuthInfo.DefaultLogonId != SecurityContext->DefaultLogonId)
  301. {
  302. return FALSE;
  303. }
  304. if (ClientAuthInfo.DefaultLogonId)
  305. {
  306. return TRUE;
  307. }
  308. return FastCompareLUIDAligned(&ClientAuthInfo.ModifiedId,
  309. &SecurityContext->ModifiedId);
  310. }
  311. #pragma optimize ("t", on)
  312. inline CLIENT_AUTH_INFO *
  313. LRPC_BINDING_HANDLE::InquireAuthInformation (
  314. )
  315. /*++
  316. Return Value:
  317. If this binding handle is authenticated, then a pointer to its
  318. authentication and authorization information will be returned;
  319. otherwise, zero will be returned.
  320. --*/
  321. {
  322. if (AuthInfoInitialized == 0)
  323. {
  324. return 0;
  325. }
  326. return &ClientAuthInfo;
  327. }
  328. inline ULONG
  329. LRPC_BINDING_HANDLE::GetIdentityTracking (
  330. void
  331. )
  332. /*++
  333. Routine Description:
  334. Gets the effective identity tracking mode for this binding handle
  335. Return Value:
  336. The identity tracking mode
  337. --*/
  338. {
  339. if (AuthInfoInitialized == 0)
  340. {
  341. return RPC_C_QOS_IDENTITY_STATIC;
  342. }
  343. return ClientAuthInfo.IdentityTracking;
  344. }
  345. #pragma optimize("", on)
  346. inline void
  347. LRPC_BINDING_HANDLE::RemoveRecursiveCall (
  348. IN int RecursiveCallsKey
  349. )
  350. /*++
  351. Routine Description:
  352. A remote procedure call which had callbacks has completed. This means
  353. that we need to remove the call from the dictionary of active calls.
  354. --*/
  355. {
  356. BindingMutex.Request();
  357. RecursiveCalls.Delete(RecursiveCallsKey);
  358. BindingMutex.Clear();
  359. }
  360. class LRPC_BINDING : public MTSyntaxBinding
  361. {
  362. public:
  363. LRPC_BINDING (
  364. IN RPC_SYNTAX_IDENTIFIER *InterfaceId,
  365. IN TRANSFER_SYNTAX_STUB_INFO *TransferSyntaxInfo,
  366. IN int CapabilitiesBitmap
  367. ) : MTSyntaxBinding(InterfaceId, TransferSyntaxInfo, CapabilitiesBitmap),
  368. RefCount(1)
  369. {
  370. }
  371. inline void SetNextBinding(LRPC_BINDING *Next)
  372. {
  373. MTSyntaxBinding::SetNextBinding(Next);
  374. }
  375. inline LRPC_BINDING *GetNextBinding(void)
  376. {
  377. return (LRPC_BINDING *)(MTSyntaxBinding::GetNextBinding());
  378. }
  379. inline void AddReference (
  380. void
  381. )
  382. {
  383. RefCount.Increment();
  384. }
  385. inline void RemoveReference (
  386. void
  387. )
  388. {
  389. long ResultCount;
  390. ResultCount = RefCount.Decrement();
  391. ASSERT(ResultCount >= 0);
  392. // it is safe to delete. The entry should have
  393. // already been removed from the assoc dict
  394. if (ResultCount == 0)
  395. delete this;
  396. }
  397. private:
  398. CLIENT_AUTH_INFO * pAuthInfo;
  399. INTERLOCKED_INTEGER RefCount;
  400. };
  401. NEW_SDICT(LRPC_BINDING);
  402. NEW_SDICT(LRPC_CCONTEXT);
  403. class LRPC_CASSOCIATION : public REFERENCED_OBJECT
  404. /*++
  405. Class Description:
  406. Fields:
  407. DceBinding - Contains the DCE binding information used to create this
  408. association.
  409. AssociationDictKey - Contains the key of this association in the
  410. dictionary of associations. We need this for when we delete this
  411. association.
  412. Bindings - Contains the dictionary of interfaces for which this
  413. association has a binding to the server.
  414. CachedCCall - Contains a LRPC_CCALL cache with one object in it.
  415. This is to avoid having to allocate memory in the common case.
  416. CachedCCallFlag - If this flag is non-zero then CachedCCall is available.
  417. LpcClientPort - Contains the LPC port which we will use to make the
  418. remote procedure calls to the server. If we do not yet have a port
  419. setup, this field will be zero.
  420. AssociationMutex - Contains a mutex used to serialize access to opening
  421. and closing the LpcClientPort.
  422. --*/
  423. {
  424. friend class LRPC_CCALL;
  425. friend class LRPC_ADDRESS;
  426. friend class LRPC_CCONTEXT;
  427. private:
  428. DCE_BINDING * DceBinding;
  429. LRPC_BINDING_DICT Bindings;
  430. LRPC_CCALL_DICT FreeCCalls ;
  431. LRPC_CCALL_DICT2 ActiveCCalls ;
  432. HANDLE LpcClientPort;
  433. HANDLE LpcReceivePort ;
  434. MUTEX AssociationMutex;
  435. // N.B. Never use the IdentityTracking member of the association - it is not
  436. // valid. Use the one from the binding handle
  437. CLIENT_AUTH_INFO AssocAuthInfo;
  438. int AssociationDictKey;
  439. BOOL BackConnectionCreated ;
  440. LRPC_CCALL *CachedCCall ;
  441. BOOL CachedCCallFlag ;
  442. ULONG CallIdCounter;
  443. USHORT SequenceNumber;
  444. int DeletedContextCount;
  445. LRPC_CCONTEXT_DICT SecurityContextDict;
  446. BOOL DontLinger;
  447. union
  448. {
  449. struct
  450. {
  451. // TRUE if this is an association without binding handle
  452. // references to it (i.e. it is lingered), FALSE
  453. // otherwise. Protected by the LrpcMutex
  454. BOOL fAssociationLingered;
  455. // The timestamp for garbage collecting this item. Defined
  456. // only if fAssociationLingered == TRUE. Protected by the
  457. // LrpcMutex
  458. DWORD Timestamp;
  459. } Linger;
  460. // this arm of the union is used only during destruction - never use
  461. // it outside
  462. LRPC_CASSOCIATION *NextAssociation;
  463. };
  464. // in tick counts
  465. DWORD LastSecContextTrimmingTimestamp;
  466. long BindingHandleReferenceCount;
  467. public:
  468. LRPC_CASSOCIATION (
  469. IN DCE_BINDING * DceBinding,
  470. IN CLIENT_AUTH_INFO *pClientAuthInfo,
  471. USHORT MySequenceNumber,
  472. OUT RPC_STATUS * Status
  473. );
  474. virtual ~LRPC_CASSOCIATION (
  475. );
  476. inline void AddBindingHandleReference(void)
  477. {
  478. // make sure we don't create references out of thin air, unless we
  479. // resurrected a lingering association
  480. ASSERT((BindingHandleReferenceCount > 0) || Linger.fAssociationLingered);
  481. ASSERT(RefCount.GetInteger() > 0);
  482. #if DBG
  483. LrpcMutexVerifyOwned();
  484. #endif
  485. BindingHandleReferenceCount ++;
  486. LogEvent(SU_CASSOC, EV_INC, this, IntToPtr(ObjectType), BindingHandleReferenceCount, 1, 1);
  487. AddReference();
  488. }
  489. void RemoveBindingHandleReference (void);
  490. void Delete(void);
  491. RPC_CHAR *
  492. StringBindingCompose (
  493. IN RPC_UUID * Uuid OPTIONAL
  494. );
  495. int
  496. CompareWithDceBinding (
  497. IN DCE_BINDING * DceBinding,
  498. OUT BOOL *fOnlyEndpointDiffers
  499. );
  500. BOOL
  501. DoesBindingForInterfaceExist (
  502. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  503. );
  504. LRPC_CASSOCIATION *
  505. DuplicateAssociation (
  506. );
  507. RPC_STATUS
  508. AllocateCCall (
  509. IN LRPC_BINDING_HANDLE *BindingHandle,
  510. OUT LRPC_CCALL ** CCall,
  511. IN OUT PRPC_MESSAGE Message,
  512. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  513. );
  514. RPC_STATUS
  515. ActuallyAllocateCCall (
  516. OUT LRPC_CCALL ** CCall,
  517. IN LRPC_BINDING * Binding,
  518. IN BOOL IsBackConnectionNeeded,
  519. IN LRPC_BINDING_HANDLE * BindingHandle,
  520. IN LRPC_CCONTEXT *SecurityContext
  521. );
  522. RPC_STATUS
  523. ActuallyDoBinding (
  524. IN LRPC_BINDING_HANDLE *BindingHandle,
  525. IN BOOL IsBackConnectionNeeded,
  526. IN BOOL fAlterContextNeeded,
  527. IN BOOL fAlterSecurityContextNeeded,
  528. IN BOOL fDefaultLogonId,
  529. IN int NumberOfBindings,
  530. LRPC_BINDING *BindingsForThisInterface[],
  531. OUT LRPC_BINDING ** Binding,
  532. OUT LRPC_CCONTEXT **SecurityContext
  533. );
  534. RPC_STATUS
  535. OpenLpcPort (
  536. IN LRPC_BINDING_HANDLE *BindingHandle,
  537. IN BOOL fBindBack
  538. );
  539. void
  540. SetReceivePort (
  541. HANDLE Port
  542. );
  543. void
  544. ProcessResponse(
  545. IN LRPC_MESSAGE *LrpcMessage,
  546. IN OUT LRPC_MESSAGE **LrpcReplyMessage
  547. );
  548. void
  549. FreeCCall (
  550. IN LRPC_CCALL * CCall
  551. );
  552. friend LRPC_CASSOCIATION *
  553. FindOrCreateLrpcAssociation (
  554. IN DCE_BINDING * DceBinding,
  555. IN CLIENT_AUTH_INFO *pClientAuthInfo,
  556. IN RPC_CLIENT_INTERFACE *InterfaceInfo
  557. );
  558. friend void
  559. ShutdownLrpcClient (
  560. );
  561. void
  562. AbortAssociation (
  563. IN BOOL ServerAborted = 0
  564. );
  565. DCE_BINDING *
  566. DuplicateDceBinding (
  567. );
  568. void SetAddress(
  569. LRPC_ADDRESS *Address
  570. ) ;
  571. BOOL
  572. IsSupportedAuthInfo(
  573. IN CLIENT_AUTH_INFO * ClientAuthInfo
  574. );
  575. RPC_STATUS
  576. CreateBackConnection (
  577. IN LRPC_BINDING_HANDLE *BindingHandle
  578. ) ;
  579. void
  580. ProcessResponse (
  581. LRPC_MESSAGE LrpcMessage
  582. ) ;
  583. BOOL
  584. CacheNeedsTrimming()
  585. {
  586. AssociationMutex.VerifyOwned();
  587. #if DBG
  588. return TRUE;
  589. #else
  590. if (GetTickCount() - LastSecContextTrimmingTimestamp > CACHE_CHECK_TIMEOUT
  591. && SecurityContextDict.Size() > 4)
  592. {
  593. return TRUE;
  594. }
  595. return FALSE;
  596. #endif
  597. }
  598. void
  599. PrepareBindPacket(
  600. IN OUT LRPC_MESSAGE *LrpcMessage
  601. );
  602. inline void
  603. UpdateLastSecContextTrimmingTimestamp (
  604. void
  605. )
  606. {
  607. LastSecContextTrimmingTimestamp = GetTickCount();
  608. }
  609. inline RPC_CHAR *InqEndpoint(void)
  610. {
  611. return DceBinding->InqEndpoint();
  612. }
  613. static void
  614. LrpcDeleteLingeringAssociations (
  615. void
  616. );
  617. inline BOOL
  618. GetDontLingerState (
  619. void
  620. )
  621. {
  622. return DontLinger;
  623. }
  624. inline void
  625. SetDontLingerState (
  626. IN BOOL DontLinger
  627. )
  628. {
  629. ASSERT(DontLinger == TRUE);
  630. ASSERT(this->DontLinger == FALSE);
  631. this->DontLinger = DontLinger;
  632. }
  633. private:
  634. void
  635. CloseLpcClientPort (
  636. );
  637. inline BOOL
  638. PrepareForLoopbackTicklingIfNecessary (
  639. void
  640. )
  641. {
  642. LRPC_ADDRESS *CurrentAddress;
  643. // if we have IO completion threads, no need for
  644. // loopback tickling
  645. if (IocThreadStarted)
  646. return TRUE;
  647. CurrentAddress = LrpcAddressList;
  648. while (CurrentAddress)
  649. {
  650. if (CurrentAddress->PrepareForLoopbackTicklingIfNecessary())
  651. return TRUE;
  652. CurrentAddress = CurrentAddress->GetNextAddress();
  653. }
  654. return FALSE;
  655. }
  656. };
  657. inline void
  658. LRPC_CASSOCIATION::SetReceivePort(
  659. HANDLE Port
  660. )
  661. {
  662. LpcReceivePort = Port ;
  663. }
  664. inline RPC_CHAR *
  665. LRPC_CASSOCIATION::StringBindingCompose (
  666. IN RPC_UUID * Uuid OPTIONAL
  667. )
  668. /*++
  669. Routine Description:
  670. We will create a string binding from the DCE_BINDING which names this
  671. association.
  672. Arguments:
  673. Uuid - Optionally supplies a uuid to be included with the string binding.
  674. Return Value:
  675. The string binding will be returned, except if there is not enough
  676. memory, in which case, zero will be returned.
  677. --*/
  678. {
  679. return(DceBinding->StringBindingCompose(Uuid));
  680. }
  681. inline int
  682. LRPC_CASSOCIATION::CompareWithDceBinding (
  683. IN DCE_BINDING * DceBinding,
  684. OUT BOOL *fOnlyEndpointDiffers
  685. )
  686. /*++
  687. Routine Description:
  688. This routine compares the specified binding information with the
  689. binding information in this object without the security options,
  690. because the security settings have already been parsed and reflected
  691. in the auth info of the binding handle/association.
  692. Arguments:
  693. DceBinding - Supplies the binding information to compare against
  694. the binding information in this.
  695. fOnlyEndpointDiffers - if the return value is 0, this is undefined.
  696. If it is non-zero, and the dce bindings differ by endpoint only,
  697. this will be non-zero. Otherwise, it will be FALSE.
  698. Return Value:
  699. Zero will be returned if the specified binding information,
  700. DceBinding, is the same as in this. Otherwise, non-zero will be
  701. returned.
  702. --*/
  703. {
  704. return(this->DceBinding->CompareWithoutSecurityOptions(
  705. DceBinding,
  706. fOnlyEndpointDiffers
  707. ));
  708. }
  709. inline LRPC_CASSOCIATION *
  710. LRPC_CASSOCIATION::DuplicateAssociation (
  711. )
  712. /*++
  713. Routine Description:
  714. This method will be used by binding handles to duplicate themselves;
  715. this is how they will duplicate their associations.
  716. Note: This must be called only by the binding handle, since it will
  717. add a binding handle reference count.
  718. --*/
  719. {
  720. LrpcMutexRequest();
  721. AddBindingHandleReference();
  722. LrpcMutexClear();
  723. return(this);
  724. }
  725. inline DCE_BINDING *
  726. LRPC_CASSOCIATION::DuplicateDceBinding (
  727. )
  728. /*++
  729. Return Value:
  730. A copy of the binding used for this association will be returned.
  731. --*/
  732. {
  733. return(DceBinding->DuplicateDceBinding());
  734. }
  735. typedef struct tagDelayedPipeAckData
  736. {
  737. BOOL DelayedAckPipeNeeded;
  738. RPC_STATUS CurrentStatus;
  739. } DelayedPipeAckData;
  740. class LRPC_CCALL : public CCALL
  741. /*++
  742. Class Description:
  743. Fields:
  744. CurrentBindingHandle - Contains the binding handle which is being used
  745. to direct this remote procedure call. We need this in the case of
  746. callbacks.
  747. Association - Contains the association over which we will send the remote
  748. procedure call.
  749. PresentationContext - Contains the key to the bound interface. This
  750. will be sent to the server.
  751. CallAbortedFlag - Contains a flag indicating whether or not this call
  752. has been aborted. A non-zero value indicates that the call has been
  753. aborted.
  754. CallStack - Contains a count of the number of nested remote procedure
  755. calls. A value of zero indicates there are no nested remote
  756. procedure calls.
  757. RpcInterfaceInformation - This field contains the information about the
  758. interface being used for the remote procedure call. We need this
  759. so that we can dispatch callbacks and so that we can keep track of
  760. the active calls on a binding handle.
  761. Thread - Contains the thread which is making this remote procedure call.
  762. We need this so we can keep track of the active calls on a binding
  763. handle.
  764. MessageId - Contains an identifier used by LPC to identify the current
  765. remote procedure call.
  766. LrpcMessage - Contains the message which will be sent back and forth via
  767. LPC. This can contain a request, response, or a fault.
  768. BHActiveCallsKey - Contains the key for this call in the dictionary of
  769. active calls in the binding handle.
  770. ClientId - Contains the thread identifier of the thread waiting for
  771. a request or a response after sending a callback.
  772. RecursionCount - Contains the numbers of retries when a
  773. server crashes and we're trying to reconnect.
  774. --*/
  775. {
  776. friend class LRPC_CASSOCIATION;
  777. friend class LRPC_BINDING_HANDLE;
  778. private:
  779. CLIENT_AUTH_INFO AuthInfo;
  780. LRPC_BINDING_HANDLE * CurrentBindingHandle;
  781. LRPC_CASSOCIATION * Association;
  782. LRPC_MESSAGE *LrpcMessage;
  783. PRPC_MESSAGE RpcReplyMessage ;
  784. LRPC_MESSAGE *LpcReplyMessage ;
  785. ULONG RcvBufferLength ;
  786. BOOL Choked ;
  787. int RecursiveCallsKey;
  788. int FreeCallKey ;
  789. ULONG CallId ;
  790. CSHORT DataInfoOffset;
  791. ULONG MessageId;
  792. ULONG CallbackId;
  793. CLIENT_ID ClientId;
  794. LRPC_BINDING *Binding;
  795. THREAD_IDENTIFIER Thread;
  796. unsigned int CallAbortedFlag;
  797. int RecursionCount;
  798. EVENT SyncEvent ;
  799. LRPC_CCONTEXT *CurrentSecurityContext;
  800. MUTEX CallMutex ;
  801. ULONG MsgFlags ;
  802. // When a response to this call is processed on a server
  803. // thread, the server thread will lock down the call to
  804. // prevent it from disappearing and will then unlock
  805. // it when done. The locking will be done under the
  806. // AssociationMutex. Before the completion thread completes
  807. // a call, it must wait for the lock count to drop to
  808. // 0.
  809. // This is necessary to prevent races between abortive cancel
  810. // on the client side and the server responding.
  811. INTERLOCKED_INTEGER ResponseLockCount;
  812. // the thread id of the last process response we have
  813. // received. Note that last process response we receive
  814. // must be the one we use to complete the call. We need
  815. // this TID in order to prevent a deadlock where in
  816. // COM the call is freed on the thread that issued
  817. // the notification and the free code will wait
  818. // forever for the count to go to 0. Instead, if
  819. // the reponse lock count is 1, and the TID is
  820. // our TID, we mark the call as freed in the TEB and
  821. // proceed with freeing. The code in ProcessResponse
  822. // will check the TEB and won't touch the call if it
  823. // is marked as free
  824. DWORD LastProcessResponseTID;
  825. // LRPC stuff
  826. unsigned int CallStack;
  827. LRPC_MESSAGE *CachedLrpcMessage;
  828. // Pipe stuff
  829. int FirstFrag ;
  830. ULONG CurrentBufferLength ;
  831. BOOL BufferComplete ;
  832. ULONG NeededLength;
  833. // Async RPC stuff
  834. QUEUE BufferQueue ;
  835. BOOL fSendComplete;
  836. // Extended Error Info stuff
  837. // used in async calls only to hold
  838. // information b/n call failure and
  839. // RpcAsyncCompleteCall
  840. ExtendedErrorInfo *EEInfo;
  841. public:
  842. LRPC_CCALL (
  843. IN OUT RPC_STATUS * Status
  844. );
  845. ~LRPC_CCALL (
  846. );
  847. virtual RPC_STATUS
  848. NegotiateTransferSyntax (
  849. IN OUT PRPC_MESSAGE Message
  850. );
  851. virtual RPC_STATUS
  852. GetBuffer (
  853. IN OUT PRPC_MESSAGE Message,
  854. IN UUID *ObjectUuid = 0
  855. );
  856. virtual RPC_STATUS
  857. SendReceive (
  858. IN OUT PRPC_MESSAGE Message
  859. );
  860. virtual void
  861. FreeBuffer (
  862. IN PRPC_MESSAGE Message
  863. );
  864. virtual void
  865. FreePipeBuffer (
  866. IN PRPC_MESSAGE Message
  867. ) ;
  868. virtual RPC_STATUS
  869. ReallocPipeBuffer (
  870. IN PRPC_MESSAGE Message,
  871. IN unsigned int NewSize
  872. ) ;
  873. virtual RPC_STATUS
  874. Send (
  875. IN OUT PRPC_MESSAGE Message
  876. ) ;
  877. virtual RPC_STATUS
  878. Receive (
  879. IN PRPC_MESSAGE Message,
  880. IN unsigned int Size
  881. ) ;
  882. // Perform a send operationin a handle specific way
  883. // this API is used in conjunction with pipes
  884. virtual RPC_STATUS
  885. AsyncSend (
  886. IN OUT PRPC_MESSAGE Message
  887. ) ;
  888. // Perform a receive in a handle specific way
  889. // this API is used in conjunction with pipes
  890. virtual RPC_STATUS
  891. AsyncReceive (
  892. IN OUT PRPC_MESSAGE Message,
  893. IN unsigned int Size
  894. ) ;
  895. virtual RPC_STATUS
  896. CancelAsyncCall (
  897. IN BOOL fAbort
  898. );
  899. RPC_STATUS
  900. ActivateCall (
  901. IN LRPC_BINDING_HANDLE * BindingHandle,
  902. IN LRPC_BINDING *Binding,
  903. IN BOOL IsBackConnectionNeeded,
  904. IN LRPC_CCONTEXT *SecurityContext
  905. );
  906. void
  907. SetAssociation (
  908. IN LRPC_CASSOCIATION * Association
  909. );
  910. void
  911. SetPresentationContext (
  912. IN LRPC_BINDING * Binding
  913. );
  914. int
  915. SupportedPContext (
  916. IN LRPC_BINDING * Binding
  917. ) ;
  918. void
  919. AbortCCall (
  920. );
  921. int
  922. IsThisMyActiveCall (
  923. IN THREAD_IDENTIFIER Thread,
  924. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  925. );
  926. void SetRecursionCount(
  927. IN int Count
  928. );
  929. RPC_STATUS
  930. LrpcMessageToRpcMessage (
  931. IN LRPC_MESSAGE *LrpcMessage,
  932. OUT RPC_MESSAGE * RpcMessage,
  933. IN HANDLE LpcPort,
  934. IN BOOL IsReplyFromBackConnection OPTIONAL,
  935. OUT DelayedPipeAckData *AckData OPTIONAL
  936. );
  937. RPC_STATUS
  938. SendPipeAck (
  939. IN HANDLE LpcPort,
  940. IN LRPC_MESSAGE *LrpcResponse,
  941. IN RPC_STATUS CurrentStatus
  942. );
  943. void
  944. ServerAborted(
  945. IN OUT int *waitIterations
  946. ) ;
  947. LRPC_CASSOCIATION *
  948. InqAssociation (
  949. ) ;
  950. RPC_STATUS
  951. GetBufferDo (
  952. IN OUT PRPC_MESSAGE Message,
  953. IN unsigned long NewSize,
  954. IN int fDataValid
  955. ) ;
  956. void
  957. ProcessResponse (
  958. IN LRPC_MESSAGE *LrpcResponse
  959. ) ;
  960. RPC_STATUS
  961. GetCoalescedBuffer (
  962. IN PRPC_MESSAGE Message,
  963. IN BOOL BufferValid
  964. ) ;
  965. void
  966. SetCurrentSecurityContext(LRPC_CCONTEXT *CContext)
  967. {
  968. CurrentSecurityContext = CContext;
  969. }
  970. void
  971. CallFailed(
  972. IN RPC_STATUS Status
  973. )
  974. {
  975. AsyncStatus = Status;
  976. IssueNotification() ;
  977. }
  978. inline unsigned short GetOnTheWirePresentationContext(void)
  979. {
  980. return Binding->GetOnTheWirePresentationContext();
  981. }
  982. inline void SetPresentationContextFromPacket(unsigned short PresentContext)
  983. {
  984. Binding->SetPresentationContextFromPacket(PresentContext);
  985. }
  986. inline int GetPresentationContext (void)
  987. {
  988. return Binding->GetPresentationContext();
  989. }
  990. inline void SetPresentationContext (int PresentContext)
  991. {
  992. Binding->SetPresentationContext(PresentContext);
  993. }
  994. inline void SetObjectUuid(IN UUID *ObjectUuid)
  995. {
  996. if (ObjectUuid)
  997. {
  998. UuidSpecified = 1;
  999. RpcpMemoryCopy(&this->ObjectUuid, ObjectUuid, sizeof(UUID));
  1000. }
  1001. else if (CurrentBindingHandle->InqIfNullObjectUuid() == 0)
  1002. {
  1003. UuidSpecified = 1;
  1004. RpcpMemoryCopy(&this->ObjectUuid,
  1005. CurrentBindingHandle->InqPointerAtObjectUuid(),
  1006. sizeof(UUID));
  1007. }
  1008. else
  1009. {
  1010. UuidSpecified = 0;
  1011. }
  1012. }
  1013. void
  1014. LockCallFromResponse (
  1015. void
  1016. )
  1017. {
  1018. // make sure the lock count doesn't get too big. 200 is
  1019. // arbitrary number
  1020. ASSERT(ResponseLockCount.GetInteger() <= 200);
  1021. LogEvent(SU_CCALL, EV_INC, this, UlongToPtr(0x33), ResponseLockCount.GetInteger(), 1, 0);
  1022. ResponseLockCount.Increment();
  1023. LastProcessResponseTID = GetCurrentThreadId();
  1024. }
  1025. void
  1026. UnlockCallFromResponse (
  1027. void
  1028. )
  1029. {
  1030. // make sure the lock count doesn't get negative.
  1031. ASSERT(ResponseLockCount.GetInteger() > 0);
  1032. LogEvent(SU_CCALL, EV_DEC, this, UlongToPtr(0x33), ResponseLockCount.GetInteger(), 1, 0);
  1033. ResponseLockCount.Decrement();
  1034. }
  1035. BOOL
  1036. TryWaitForCallToBecomeUnlocked (
  1037. BOOL *fUnlocked
  1038. );
  1039. private:
  1040. inline BOOL
  1041. WaitForReply (
  1042. IN void *Context,
  1043. IN RPC_STATUS *Status
  1044. ) ;
  1045. void
  1046. FreeCCall (
  1047. );
  1048. void
  1049. ActuallyFreeBuffer (
  1050. IN void * Buffer
  1051. );
  1052. RPC_STATUS
  1053. MakeServerCopyResponse (
  1054. );
  1055. RPC_STATUS
  1056. SendRequest (
  1057. IN OUT PRPC_MESSAGE Message,
  1058. OUT BOOL *Shutup
  1059. ) ;
  1060. RPC_STATUS AutoRetryCall (IN OUT PRPC_MESSAGE Message, BOOL fFromSendReceive);
  1061. };
  1062. inline LRPC_CASSOCIATION *
  1063. LRPC_CCALL::InqAssociation (
  1064. )
  1065. {
  1066. return Association ;
  1067. }
  1068. inline RPC_STATUS
  1069. LRPC_CCALL::ActivateCall (
  1070. IN LRPC_BINDING_HANDLE * BindingHandle,
  1071. IN LRPC_BINDING *Binding,
  1072. IN BOOL IsBackConnectionNeeded,
  1073. IN LRPC_CCONTEXT *SecurityContext
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. When a LRPC_CCALL is allocated, the binding handle used to initiate the
  1078. call must be remembered so that we can update the binding handle if a
  1079. callback occurs. We also keep track of the interface information.
  1080. --*/
  1081. {
  1082. RPC_STATUS Status ;
  1083. CurrentBindingHandle = BindingHandle;
  1084. this->Binding = Binding;
  1085. CallAbortedFlag = 0;
  1086. CurrentBufferLength = 0;
  1087. CallStack = 0;
  1088. RecursionCount = 0;
  1089. LpcReplyMessage = 0;
  1090. pAsync = 0;
  1091. fSendComplete = 0;
  1092. CurrentSecurityContext = SecurityContext;
  1093. LastProcessResponseTID = 0;
  1094. if (IsBackConnectionNeeded)
  1095. {
  1096. NotificationIssued = -1;
  1097. FirstFrag = 1;
  1098. BufferComplete = 0;
  1099. Choked = 0;
  1100. NeededLength = 0;
  1101. AsyncStatus = RPC_S_ASYNC_CALL_PENDING ;
  1102. RcvBufferLength = 0;
  1103. CallingThread = ThreadSelf();
  1104. if (CallingThread == 0)
  1105. {
  1106. return RPC_S_OUT_OF_MEMORY;
  1107. }
  1108. }
  1109. else
  1110. {
  1111. CallingThread = 0;
  1112. }
  1113. Binding->AddReference();
  1114. return RPC_S_OK ;
  1115. }
  1116. inline void
  1117. LRPC_CCALL::SetAssociation (
  1118. IN LRPC_CASSOCIATION * Association
  1119. )
  1120. {
  1121. this->Association = Association;
  1122. }
  1123. inline void
  1124. LRPC_CCALL::SetRecursionCount(
  1125. IN int Count
  1126. )
  1127. {
  1128. RecursionCount = Count;
  1129. }
  1130. inline int
  1131. LRPC_CCALL::IsThisMyActiveCall (
  1132. IN THREAD_IDENTIFIER Thread,
  1133. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  1134. )
  1135. /*++
  1136. Return Value:
  1137. Non-zero will be returned if this call is the active call for this thread
  1138. on this interface.
  1139. --*/
  1140. {
  1141. if (this->Thread != Thread)
  1142. return 0;
  1143. return (!(RpcpMemoryCompare(&RpcInterfaceInformation->InterfaceId,
  1144. Binding->GetInterfaceId(), sizeof (RPC_SYNTAX_IDENTIFIER))));
  1145. }
  1146. inline int
  1147. LRPC_BINDING_HANDLE::AddRecursiveCall (
  1148. IN LRPC_CCALL * CCall
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This supplied remote procedure call needs to be put into the dictionary
  1153. of active remote procedure calls for this binding handle, because a
  1154. callback just arrived.
  1155. --*/
  1156. {
  1157. int RecursiveCallsKey;
  1158. CCall->Thread = GetThreadIdentifier();
  1159. BindingMutex.Request();
  1160. RecursiveCallsKey = RecursiveCalls.Insert(CCall);
  1161. BindingMutex.Clear();
  1162. return(RecursiveCallsKey);
  1163. }
  1164. inline void
  1165. LRPC_CCONTEXT::AddReference()
  1166. {
  1167. RefCount.Increment();
  1168. }
  1169. inline void
  1170. LRPC_CCONTEXT::RemoveReference()
  1171. {
  1172. LRPC_CASSOCIATION *MyAssociation = this->Association;
  1173. int LocalRefCount;
  1174. BOOL fLocalDeleteMe = FALSE;
  1175. LocalRefCount = RefCount.Decrement();
  1176. ASSERT(LocalRefCount >= 0);
  1177. if (LocalRefCount == 0)
  1178. {
  1179. // N.B. There is a race condition where the Destroy
  1180. // code may have deleted the this object once we
  1181. // decrement the refcount. We need to take
  1182. // the mutex and check whether the security
  1183. // dictionary is empty. If it is, we know we
  1184. // have been destroyed. If not, it is safe to check
  1185. // whether we are due for destruction
  1186. MyAssociation->AssociationMutex.Request();
  1187. if (MyAssociation->SecurityContextDict.Size() != 0)
  1188. {
  1189. if (fDeleteMe)
  1190. {
  1191. // assert that somebody else has deleted us - otherwise
  1192. // we leave stale entries in the dictionary and will AV
  1193. // eventually
  1194. ASSERT(MyAssociation->SecurityContextDict.Find(ContextKey) != this);
  1195. fLocalDeleteMe = TRUE;
  1196. }
  1197. }
  1198. MyAssociation->AssociationMutex.Clear();
  1199. if (fLocalDeleteMe)
  1200. delete this;
  1201. }
  1202. }
  1203. inline void
  1204. LRPC_CCONTEXT::Destroy()
  1205. {
  1206. Association->AssociationMutex.VerifyOwned();
  1207. //
  1208. // Not in the dictionary, but there may be references active
  1209. // delete this context when the references go down to 0
  1210. //
  1211. fDeleteMe = TRUE;
  1212. if (RefCount.GetInteger() == 0)
  1213. {
  1214. delete this;
  1215. }
  1216. }
  1217. #endif // __LPCCLNT_HXX__