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.

1685 lines
33 KiB

  1. /*++ b
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. dgclnt.hxx
  5. Abstract:
  6. This file contains the definitions used by the datagram client.
  7. Revision History:
  8. NT 3.5 was the first version shipped, supporting IPX and UDP. (connieh)
  9. NT 3.51 added secure calls over NTLM and DEC Kerberos. (jroberts)
  10. NT 4.0 added sliding window, larger packet sizes, cancels. (jroberts)
  11. NT 5.0 added asynchronous calls and SSL/PCT security. (jroberts)
  12. --*/
  13. #ifndef __DGCLNT_HXX__
  14. #define __DGCLNT_HXX__
  15. class DG_CCALL;
  16. typedef DG_CCALL * PDG_CCALL;
  17. class DG_CCONNECTION;
  18. typedef DG_CCONNECTION * PDG_CCONNECTION;
  19. class DG_CASSOCIATION;
  20. typedef DG_CASSOCIATION * PDG_CASSOCIATION;
  21. class DG_BINDING_HANDLE;
  22. typedef DG_BINDING_HANDLE * PDG_BINDING_HANDLE;
  23. class INTERFACE_AND_OBJECT_LIST
  24. {
  25. public:
  26. inline
  27. INTERFACE_AND_OBJECT_LIST(
  28. )
  29. {
  30. Head = 0;
  31. Cache1Available = TRUE;
  32. Cache2Available = TRUE;
  33. }
  34. ~INTERFACE_AND_OBJECT_LIST(
  35. );
  36. BOOL
  37. Insert(
  38. void * Interface,
  39. RPC_UUID * Object
  40. );
  41. BOOL
  42. Find(
  43. void * Interface,
  44. RPC_UUID * Object
  45. );
  46. BOOL
  47. Delete(
  48. void * Interface,
  49. RPC_UUID * Object
  50. );
  51. private:
  52. #define MAX_ELEMENTS 10
  53. struct INTERFACE_AND_OBJECT
  54. {
  55. INTERFACE_AND_OBJECT * Next;
  56. void * Interface;
  57. RPC_UUID Object;
  58. inline void
  59. Update(
  60. void * a_Interface,
  61. RPC_UUID * a_Object
  62. )
  63. {
  64. Interface = a_Interface;
  65. Object = *a_Object;
  66. }
  67. };
  68. INTERFACE_AND_OBJECT * Head;
  69. unsigned Cache1Available : 1;
  70. unsigned Cache2Available : 1;
  71. INTERFACE_AND_OBJECT Cache1;
  72. INTERFACE_AND_OBJECT Cache2;
  73. };
  74. class DG_CCONNECTION : public DG_COMMON_CONNECTION
  75. {
  76. public:
  77. long TimeStamp;
  78. DG_CCONNECTION * Next;
  79. boolean CallbackCompleted;
  80. boolean fServerSupportsAsync;
  81. boolean fSecurePacketReceived;
  82. boolean ServerResponded;
  83. boolean fBusy;
  84. boolean InConnectionTable;
  85. signed char AckPending;
  86. boolean AckOrphaned;
  87. boolean PossiblyRunDown;
  88. boolean fAutoReconnect;
  89. boolean fError;
  90. DWORD ThreadId;
  91. PDG_BINDING_HANDLE BindingHandle;
  92. int AssociationKey;
  93. PDG_CASSOCIATION Association;
  94. PDG_CCALL CurrentCall;
  95. //--------------------------------------------------------------------
  96. DG_CCALL * AllocateCall();
  97. inline void
  98. AddCallToCache(
  99. PDG_CCALL Call
  100. );
  101. RPC_STATUS
  102. BeginCall(
  103. IN PDG_CCALL Call
  104. );
  105. void
  106. EndCall(
  107. IN PDG_CCALL Call
  108. );
  109. long DecrementRefCount();
  110. long DecrementRefCountAndKeepMutex();
  111. void
  112. IncrementRefCount(
  113. void
  114. );
  115. inline int
  116. IsSupportedAuthInfo(
  117. IN const CLIENT_AUTH_INFO * ClientAuthInfo
  118. );
  119. RPC_STATUS
  120. DealWithAuthCallback(
  121. IN void * InToken,
  122. IN long InTokenLengh,
  123. OUT void * OutToken,
  124. OUT long MaxOutTokenLength,
  125. OUT long * OutTokenLength
  126. );
  127. RPC_STATUS
  128. DealWithAuthMore(
  129. IN long Index,
  130. OUT void * OutToken,
  131. OUT long MaxOutTokenLength,
  132. OUT long * OutTokenLength
  133. );
  134. DG_CCONNECTION(
  135. IN PDG_CASSOCIATION a_Association,
  136. IN const CLIENT_AUTH_INFO * AuthInfo,
  137. IN OUT RPC_STATUS * pStatus
  138. );
  139. ~DG_CCONNECTION();
  140. void PostDelayedAck();
  141. void SendDelayedAck();
  142. void CancelDelayedAck(
  143. BOOL Flush = FALSE
  144. );
  145. inline void UpdateAssociation();
  146. RPC_STATUS
  147. UpdateServerAddress(
  148. IN DG_PACKET * Packet,
  149. IN DG_TRANSPORT_ADDRESS Address
  150. );
  151. void EnableOverlappedCalls();
  152. unsigned long
  153. GetSequenceNumber()
  154. {
  155. return LowestActiveSequence;
  156. }
  157. unsigned long
  158. GetLowestActiveSequence()
  159. {
  160. return LowestActiveSequence;
  161. }
  162. RPC_STATUS WillNextCallBeQueued();
  163. RPC_STATUS MaybeTransmitNextCall();
  164. DG_CCALL *
  165. FindIdleCalls(
  166. long CurrentTime
  167. );
  168. void
  169. DispatchPacket(
  170. PDG_PACKET Packet,
  171. void * Address
  172. );
  173. inline unsigned long CurrentSequenceNumber();
  174. virtual RPC_STATUS
  175. SealAndSendPacket(
  176. IN DG_ENDPOINT * SourceEndpoint,
  177. IN DG_TRANSPORT_ADDRESS RemoteAddress,
  178. IN UNALIGNED NCA_PACKET_HEADER * Header,
  179. IN unsigned long BufferOffset
  180. );
  181. RPC_STATUS
  182. VerifyPacket(
  183. IN DG_PACKET * Packet
  184. );
  185. static inline DG_CCONNECTION *
  186. FromHashNode(
  187. IN UUID_HASH_TABLE_NODE * Node
  188. )
  189. {
  190. return CONTAINING_RECORD( Node, DG_CCONNECTION, ActivityNode );
  191. }
  192. inline void *
  193. operator new(
  194. IN size_t ObjectLength,
  195. IN const RPC_DATAGRAM_TRANSPORT * Transport
  196. );
  197. void WaitForNoReferences()
  198. {
  199. while (ReferenceCount)
  200. {
  201. Sleep(10);
  202. }
  203. fBusy = FALSE;
  204. }
  205. RPC_STATUS
  206. TransferCallsToNewConnection(
  207. PDG_CCALL FirstCall,
  208. PDG_CCONNECTION NewConnection
  209. );
  210. const CLIENT_AUTH_INFO *
  211. InqAuthInfo()
  212. {
  213. return &AuthInfo;
  214. }
  215. BOOL MutexTryRequest()
  216. {
  217. BOOL result = Mutex.TryRequest();
  218. if (result)
  219. {
  220. LogEvent( SU_MUTEX, EV_INC, this, 0, 0, TRUE, 1);
  221. }
  222. return result;
  223. }
  224. void MutexRequest()
  225. {
  226. Mutex.Request();
  227. LogEvent( SU_MUTEX, EV_INC, this, 0, 0, TRUE, 1);
  228. #ifdef CHECK_MUTEX_INVERSION
  229. ThreadSelf()->ConnectionMutexHeld = this;
  230. #endif
  231. }
  232. void MutexClear()
  233. {
  234. LogEvent( SU_MUTEX, EV_DEC, this, 0, 0, TRUE, 1);
  235. Mutex.Clear();
  236. #ifdef CHECK_MUTEX_INVERSION
  237. ThreadSelf()->ConnectionMutexHeld = 0;
  238. #endif
  239. }
  240. private:
  241. CLIENT_AUTH_INFO AuthInfo;
  242. DELAYED_ACTION_NODE DelayedAckTimer;
  243. unsigned SecurityContextId;
  244. long LastScavengeTime;
  245. unsigned CachedCallCount;
  246. PDG_CCALL CachedCalls;
  247. PDG_CCALL ActiveCallHead;
  248. PDG_CCALL ActiveCallTail;
  249. //--------------------------------------------------------------------
  250. RPC_STATUS InitializeSecurityContext();
  251. unsigned char * SecurityBuffer;
  252. long SecurityBufferLength;
  253. public:
  254. long LastCallbackTime;
  255. };
  256. NEW_SDICT(DG_CCONNECTION);
  257. inline void *
  258. DG_CCONNECTION::operator new(
  259. IN size_t ObjectLength,
  260. IN const RPC_DATAGRAM_TRANSPORT * Transport
  261. )
  262. {
  263. return new char[ObjectLength + Transport->AddressSize];
  264. }
  265. inline void
  266. DG_CCONNECTION::IncrementRefCount()
  267. {
  268. Mutex.VerifyOwned();
  269. ++ReferenceCount;
  270. LogEvent(SU_CCONN, EV_INC, this, 0, ReferenceCount, TRUE);
  271. }
  272. class DG_CCALL : public CCALL, public DG_PACKET_ENGINE
  273. {
  274. friend RPC_STATUS DG_CCONNECTION::WillNextCallBeQueued();
  275. public:
  276. //
  277. // The call's Next pointer is NOT_ACTIVE until the call is added
  278. // to a connection's active call list.
  279. //
  280. #define DG_CCALL_NOT_ACTIVE ((DG_CCALL *) (~0))
  281. long TimeStamp;
  282. DG_CCALL * Next;
  283. DG_CCALL * Previous;
  284. boolean LastSendTimedOut;
  285. boolean CancelPending;
  286. boolean CancelComplete;
  287. boolean AutoReconnectOk;
  288. //-----------------------------------------------
  289. DG_CCALL(
  290. IN PDG_CCONNECTION Connection,
  291. OUT RPC_STATUS * pStatus
  292. );
  293. virtual
  294. ~DG_CCALL();
  295. RPC_STATUS
  296. DispatchPacket(
  297. PDG_PACKET Packet
  298. );
  299. inline void IncrementRefCount();
  300. long DecrementRefCount();
  301. long DecrementRefCountAndKeepMutex();
  302. //------------------------------------------------
  303. //
  304. // implementations of CCALL virtual functions
  305. //
  306. virtual RPC_STATUS
  307. NegotiateTransferSyntax (
  308. IN OUT PRPC_MESSAGE Message
  309. )
  310. {
  311. // datagrams don't support multiple syntax
  312. // negotiation. They always return the transfer
  313. // syntax the stub prefers
  314. return RPC_S_OK;
  315. }
  316. virtual RPC_STATUS
  317. GetBuffer (
  318. IN OUT PRPC_MESSAGE Message,
  319. IN UUID *ObjectUuid = 0
  320. );
  321. virtual RPC_STATUS
  322. SendReceive (
  323. IN OUT PRPC_MESSAGE Message
  324. );
  325. virtual RPC_STATUS
  326. Send(
  327. PRPC_MESSAGE Message
  328. );
  329. virtual RPC_STATUS
  330. Receive(
  331. PRPC_MESSAGE Message,
  332. unsigned MinimumSize
  333. );
  334. virtual RPC_STATUS
  335. AsyncSend(
  336. PRPC_MESSAGE Message
  337. );
  338. virtual RPC_STATUS
  339. AsyncReceive(
  340. PRPC_MESSAGE Message,
  341. unsigned MinimumSize
  342. );
  343. virtual void
  344. FreeBuffer (
  345. IN PRPC_MESSAGE Message
  346. );
  347. virtual void
  348. FreePipeBuffer (
  349. IN PRPC_MESSAGE Message
  350. ) ;
  351. virtual RPC_STATUS
  352. ReallocPipeBuffer (
  353. IN PRPC_MESSAGE Message,
  354. IN unsigned int NewSize
  355. ) ;
  356. virtual BOOL
  357. IssueNotification (
  358. IN RPC_ASYNC_EVENT Event
  359. ) ;
  360. virtual void
  361. FreeAPCInfo (
  362. IN RPC_APC_INFO *pAPCInfo
  363. ) ;
  364. RPC_STATUS
  365. CancelAsyncCall (
  366. IN BOOL fAbort
  367. );
  368. void SendAck();
  369. virtual RPC_STATUS
  370. Cancel(
  371. void * ThreadHandle
  372. );
  373. virtual unsigned TestCancel();
  374. void ExecuteDelayedSend();
  375. RPC_STATUS SendSomeFragments();
  376. inline RPC_STATUS
  377. GetInitialBuffer(
  378. IN OUT RPC_MESSAGE * Message,
  379. IN UUID *MyObjectUuid
  380. );
  381. inline void
  382. SwitchConnection(
  383. PDG_CCONNECTION NewConnection
  384. );
  385. BOOL IsBroadcast()
  386. {
  387. if (BasePacketFlags & RPC_NCA_FLAGS_BROADCAST)
  388. {
  389. return TRUE;
  390. }
  391. return FALSE;
  392. }
  393. RPC_STATUS
  394. ProcessFaultOrRejectData(
  395. PDG_PACKET Packet
  396. );
  397. BOOL
  398. InProgress()
  399. {
  400. if (AsyncStatus == RPC_S_ASYNC_CALL_PENDING)
  401. {
  402. return TRUE;
  403. }
  404. return FALSE;
  405. }
  406. private:
  407. enum DG_CLIENT_STATE
  408. {
  409. CallInit = 0x900,
  410. CallQuiescent,
  411. CallSend,
  412. CallSendReceive,
  413. CallReceive,
  414. CallCancellingSend,
  415. CallComplete
  416. };
  417. DG_CLIENT_STATE State;
  418. DG_CLIENT_STATE PreviousState;
  419. PRPC_CLIENT_INTERFACE InterfacePointer;
  420. PDG_CCONNECTION Connection;
  421. DELAYED_ACTION_NODE TransmitTimer;
  422. // unused
  423. unsigned WorkingCount;
  424. unsigned UnansweredRequestCount;
  425. long ReceiveTimeout;
  426. unsigned long PipeReceiveSize;
  427. long TimeoutLimit;
  428. long LastReceiveTime;
  429. long CancelTime;
  430. boolean StaticArgsSent;
  431. boolean AllArgsSent;
  432. boolean _unused;
  433. boolean ForceAck;
  434. long DelayedSendPending;
  435. // Extended Error Info stuff
  436. // used in async calls only to hold
  437. // information b/n call failure and
  438. // RpcAsyncCompleteCall
  439. ExtendedErrorInfo *EEInfo;
  440. //--------------------------------------------------------------------
  441. RPC_STATUS
  442. BeforeSendReceive(
  443. PRPC_MESSAGE Message
  444. );
  445. RPC_STATUS
  446. AfterSendReceive(
  447. PRPC_MESSAGE Message,
  448. RPC_STATUS Status
  449. );
  450. RPC_STATUS
  451. MaybeSendReceive(
  452. IN OUT PRPC_MESSAGE Message
  453. );
  454. void
  455. BuildNcaPacketHeader(
  456. OUT PNCA_PACKET_HEADER pNcaPacketHeader,
  457. IN OUT PRPC_MESSAGE Message
  458. );
  459. RPC_STATUS AttemptAutoReconnect();
  460. BOOL CheckForCancelTimeout();
  461. void PostDelayedSend();
  462. void CancelDelayedSend();
  463. void SendDelayedAck();
  464. RPC_STATUS
  465. SendFragment(
  466. PRPC_MESSAGE pMessage,
  467. PNCA_PACKET_HEADER pBaseHeader
  468. );
  469. RPC_STATUS SendQuit();
  470. RPC_STATUS SendPing();
  471. RPC_STATUS ReceiveSinglePacket();
  472. //-----------------------------------------------
  473. RPC_STATUS
  474. DealWithNocall(
  475. PDG_PACKET pPacket
  476. );
  477. RPC_STATUS
  478. DealWithFault(
  479. PDG_PACKET pPacket
  480. );
  481. RPC_STATUS
  482. DealWithReject(
  483. PDG_PACKET pPacket
  484. );
  485. RPC_STATUS
  486. DealWithWorking(
  487. PDG_PACKET pPacket
  488. );
  489. RPC_STATUS
  490. DealWithResponse(
  491. PDG_PACKET pPacket
  492. );
  493. RPC_STATUS
  494. DealWithFack(
  495. PDG_PACKET pPacket
  496. );
  497. RPC_STATUS
  498. DealWithQuack(
  499. PDG_PACKET pPacket
  500. );
  501. RPC_STATUS
  502. DealWithTimeout();
  503. RPC_STATUS
  504. DealWithRequest(
  505. IN PDG_PACKET Packet,
  506. IN DG_TRANSPORT_ADDRESS RemoteAddress
  507. );
  508. void IncreaseReceiveTimeout();
  509. RPC_STATUS
  510. MapErrorCode(
  511. RPC_STATUS Status
  512. );
  513. RPC_STATUS
  514. GetEndpoint(
  515. DWORD EndpointFlags
  516. );
  517. void
  518. SetState(
  519. IN DG_CLIENT_STATE NewState
  520. )
  521. {
  522. if (NewState != State)
  523. {
  524. LogEvent(SU_CCALL, EV_STATE, this, 0, NewState);
  525. }
  526. PreviousState = State;
  527. State = NewState;
  528. }
  529. };
  530. class DG_CASSOCIATION : public GENERIC_OBJECT
  531. {
  532. friend class DG_ASSOCIATION_TABLE;
  533. public:
  534. RPC_DATAGRAM_TRANSPORT * TransportInterface;
  535. unsigned long ServerBootTime;
  536. unsigned long ServerDataRep;
  537. unsigned CurrentPduSize;
  538. unsigned RemoteWindowSize;
  539. boolean fServerSupportsAsync;
  540. boolean fLoneBindingHandle;
  541. enum
  542. {
  543. BROADCAST = 0x100,
  544. UNRESOLVEDEP = 0x200
  545. };
  546. //----------------------------------------------------------
  547. DG_CASSOCIATION(
  548. IN RPC_DATAGRAM_TRANSPORT * a_Transport,
  549. IN LONG a_AssociationFlag,
  550. IN DCE_BINDING * a_DceBinding,
  551. IN BOOL a_Unique,
  552. IN OUT RPC_STATUS * pStatus
  553. );
  554. ~DG_CASSOCIATION();
  555. RPC_STATUS
  556. SendPacket(
  557. IN DG_ENDPOINT Endpoint,
  558. IN PNCA_PACKET_HEADER Header,
  559. IN unsigned SecurityTrailerLength = 0
  560. );
  561. virtual RPC_STATUS
  562. ToStringBinding (
  563. OUT RPC_CHAR * * StringBinding,
  564. IN RPC_UUID * ObjectUuid
  565. );
  566. void IncrementRefCount();
  567. void DecrementRefCount();
  568. int
  569. CompareWithBinding(
  570. IN PDG_BINDING_HANDLE pBinding
  571. );
  572. BOOL
  573. ComparePartialBinding(
  574. IN PDG_BINDING_HANDLE pBinding,
  575. void * Interface
  576. );
  577. BOOL
  578. AddInterface(
  579. void * InterfaceInformation,
  580. RPC_UUID * ObjectUuid
  581. );
  582. BOOL
  583. RemoveInterface(
  584. void * InterfaceInformation,
  585. RPC_UUID * ObjectUuid
  586. );
  587. RPC_STATUS
  588. AllocateCall(
  589. IN PDG_BINDING_HANDLE BindingHandle,
  590. IN const CLIENT_AUTH_INFO * AuthInfo,
  591. OUT PDG_CCALL * ppCall,
  592. IN BOOL fAsync
  593. );
  594. void
  595. ReleaseCall(
  596. IN PDG_CCALL Call
  597. );
  598. PDG_CCONNECTION
  599. AllocateConnection(
  600. IN PDG_BINDING_HANDLE BindingHandle,
  601. IN const CLIENT_AUTH_INFO * AuthInfo,
  602. IN DWORD ThreadId,
  603. IN BOOL fAsync,
  604. OUT RPC_STATUS * pStatus
  605. );
  606. void
  607. ReleaseConnection(
  608. IN PDG_CCONNECTION Call
  609. );
  610. void
  611. DeleteIdleConnections(
  612. long CurrentTime
  613. );
  614. RPC_STATUS
  615. UpdateAssociationWithAddress(
  616. PDG_PACKET Packet,
  617. void * Address
  618. );
  619. BOOL SendKeepAlive();
  620. DCE_BINDING * DuplicateDceBinding ();
  621. void SetErrorFlag () { fErrorFlag = TRUE; }
  622. void ClearErrorFlag() { fErrorFlag = FALSE; }
  623. BOOL ErrorFlag () { return fErrorFlag; }
  624. DG_TRANSPORT_ADDRESS
  625. InqServerAddress ()
  626. {
  627. return ServerAddress;
  628. }
  629. void
  630. CopyServerAddress(
  631. IN DG_TRANSPORT_ADDRESS Destination
  632. );
  633. inline void *
  634. operator new(
  635. IN size_t ObjectLength,
  636. IN const RPC_DATAGRAM_TRANSPORT * Transport
  637. );
  638. BOOL IsAckPending();
  639. void FlushAcks();
  640. void IncrementBindingRefCount(
  641. unsigned ContextHandleRef
  642. );
  643. void DecrementBindingRefCount(
  644. unsigned ContextHandleRef
  645. );
  646. void VerifyNotLocked()
  647. {
  648. Mutex.VerifyNotOwned();
  649. }
  650. BOOL LockOwnedByMe()
  651. {
  652. return Mutex.OwnedByMe();
  653. }
  654. private:
  655. void MutexRequest()
  656. {
  657. #ifdef CHECK_MUTEX_INVERSION
  658. if (!Mutex.OwnedByMe() )
  659. {
  660. DG_CCONNECTION * conn = (DG_CCONNECTION *) ThreadSelf()->ConnectionMutexHeld;
  661. ASSERT( 0 == conn || conn->ThreadId == GetCurrentThreadId() );
  662. }
  663. #endif
  664. Mutex.Request();
  665. }
  666. void MutexClear()
  667. {
  668. Mutex.Clear();
  669. }
  670. INTERLOCKED_INTEGER ReferenceCount;
  671. MUTEX Mutex;
  672. LONG AssociationFlag;
  673. boolean fErrorFlag;
  674. DCE_BINDING * pDceBinding;
  675. long LastScavengeTime;
  676. DG_TRANSPORT_ADDRESS ServerAddress;
  677. DG_CCONNECTION_DICT ActiveConnections;
  678. DG_CCONNECTION_DICT InactiveConnections;
  679. INTERFACE_AND_OBJECT_LIST InterfaceAndObjectDict;
  680. RPC_CHAR * ResolvedEndpoint;
  681. long BindingHandleReferences;
  682. long InternalTableIndex;
  683. DG_BINDING_HANDLE * KeepAliveHandle;
  684. public:
  685. long LastReceiveTime;
  686. };
  687. inline DCE_BINDING *
  688. DG_CASSOCIATION::DuplicateDceBinding (
  689. )
  690. {
  691. CLAIM_MUTEX lock( Mutex );
  692. ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) );
  693. return(pDceBinding->DuplicateDceBinding());
  694. }
  695. inline
  696. void
  697. DG_CASSOCIATION::IncrementRefCount(
  698. void
  699. )
  700. {
  701. ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) );
  702. long Count = ReferenceCount.Increment();
  703. LogEvent(SU_CASSOC, EV_INC, this, 0, Count);
  704. }
  705. inline void *
  706. DG_CASSOCIATION::operator new(
  707. IN size_t ObjectLength,
  708. IN const RPC_DATAGRAM_TRANSPORT * Transport
  709. )
  710. {
  711. return new char[ObjectLength + 2 * Transport->AddressSize];
  712. }
  713. class DG_ASSOCIATION_TABLE
  714. {
  715. public:
  716. BOOL fCasUuidReady;
  717. UUID CasUuid;
  718. //--------------------------------------------------------------------
  719. typedef LONG HINT;
  720. DG_ASSOCIATION_TABLE(
  721. RPC_STATUS * pStatus
  722. );
  723. ~DG_ASSOCIATION_TABLE()
  724. {
  725. if (Associations != InitialAssociations)
  726. delete Associations;
  727. }
  728. HINT
  729. MakeHint(
  730. DCE_BINDING * pDceBinding
  731. );
  732. RPC_STATUS
  733. Add(
  734. DG_CASSOCIATION * Association
  735. );
  736. DG_CASSOCIATION *
  737. Find(
  738. DG_BINDING_HANDLE * Binding,
  739. RPC_CLIENT_INTERFACE * Interface,
  740. BOOL fContextHandle,
  741. BOOL fPartial,
  742. BOOL fReconnect
  743. );
  744. void
  745. Delete(
  746. DG_CASSOCIATION * Association
  747. );
  748. BOOL
  749. DeleteIdleEntries(
  750. long CurrentTime
  751. );
  752. BOOL
  753. SendContextHandleKeepalives();
  754. void
  755. IncrementContextHandleCount(
  756. DG_CASSOCIATION * Association
  757. );
  758. void
  759. DecrementContextHandleCount(
  760. DG_CASSOCIATION * Association
  761. );
  762. long
  763. GetContextHandleCount(
  764. DG_CASSOCIATION * Association
  765. );
  766. void
  767. UpdateTimeStamp(
  768. DG_CASSOCIATION * Association
  769. );
  770. void LockExclusive()
  771. {
  772. Mutex.LockExclusive();
  773. }
  774. void UnlockExclusive()
  775. {
  776. Mutex.UnlockExclusive();
  777. }
  778. private:
  779. struct NODE
  780. {
  781. DG_CASSOCIATION * Association;
  782. HINT Hint;
  783. BOOL fBusy;
  784. long ContextHandleCount;
  785. long TimeStamp;
  786. };
  787. enum
  788. {
  789. INITIAL_ARRAY_LENGTH = 4,
  790. MINIMUM_IDLE_ENTRIES = 10
  791. };
  792. CSharedLock Mutex;
  793. NODE * Associations;
  794. LONG AssociationsLength;
  795. NODE InitialAssociations[ INITIAL_ARRAY_LENGTH ];
  796. long PreviousFreedCount;
  797. };
  798. extern DG_ASSOCIATION_TABLE * ActiveAssociations;
  799. inline void
  800. DG_CASSOCIATION::IncrementBindingRefCount(
  801. unsigned ContextHandleRef
  802. )
  803. {
  804. ASSERT( ContextHandleRef <= 1 );
  805. // ASSERT( ContextHandleReferences < 100 );
  806. // ASSERT( BindingHandleReferences < 100 );
  807. ++BindingHandleReferences;
  808. if (ContextHandleRef)
  809. {
  810. ActiveAssociations->IncrementContextHandleCount(this);
  811. }
  812. IncrementRefCount();
  813. }
  814. inline void
  815. DG_CASSOCIATION::DecrementBindingRefCount(
  816. unsigned ContextHandleRef
  817. )
  818. {
  819. ASSERT( ContextHandleRef <= 1 );
  820. ASSERT( BindingHandleReferences > 0 );
  821. if (ContextHandleRef)
  822. {
  823. ActiveAssociations->DecrementContextHandleCount(this);
  824. }
  825. // ASSERT( ContextHandleReferences >= 0 );
  826. if (0 == --BindingHandleReferences)
  827. {
  828. FlushAcks();
  829. }
  830. DecrementRefCount();
  831. }
  832. class DG_BINDING_HANDLE : public BINDING_HANDLE
  833. /*++
  834. Class Description:
  835. This class represents a handle pointing at a particular server/endpoint.
  836. Fields:
  837. pDceBinding - Until a DG_CASSOCIATION is found (or created) for this
  838. binding handle, pDceBinding will point at the appropriate DCE_BINDING.
  839. Mutex - Protects this binding handle.
  840. ReferenceCount - Number of DG_CCALLs currently associated with this
  841. binding handle.
  842. DecrementReferenceCount - Decrements the reference count to this binding
  843. handle. If the reference count hits 0, the binding handle is deleted.
  844. DisassociateFromServer - If this is a BH that we couldnt
  845. successfully use, tear down the association
  846. --*/
  847. {
  848. public:
  849. DCE_BINDING * pDceBinding;
  850. DWORD EndpointFlags;
  851. DG_BINDING_HANDLE(
  852. IN OUT RPC_STATUS * RpcStatus
  853. );
  854. //
  855. // This is not a general-purpose constructor.
  856. // The context handle keep-alive code uses it.
  857. //
  858. DG_BINDING_HANDLE(
  859. IN PDG_CASSOCIATION Association,
  860. IN DCE_BINDING * DceBinding,
  861. IN OUT RPC_STATUS * RpcStatus
  862. );
  863. ~DG_BINDING_HANDLE();
  864. virtual RPC_STATUS
  865. NegotiateTransferSyntax (
  866. IN OUT PRPC_MESSAGE Message
  867. )
  868. {
  869. // datagrams don't support multiple syntax
  870. // negotiation. They always return the transfer
  871. // syntax the stub prefers
  872. return RPC_S_OK;
  873. }
  874. RPC_STATUS
  875. GetBuffer (
  876. IN OUT PRPC_MESSAGE Message,
  877. IN UUID *ObjectUuid
  878. );
  879. RPC_STATUS
  880. BindingCopy (
  881. OUT BINDING_HANDLE * * DestinationBinding,
  882. IN unsigned int MaintainContext
  883. );
  884. RPC_STATUS BindingFree ();
  885. PDG_CCONNECTION
  886. GetReplacementConnection(
  887. PDG_CCONNECTION OldConnection,
  888. PRPC_CLIENT_INTERFACE Interface
  889. );
  890. RPC_STATUS
  891. PrepareBindingHandle (
  892. IN TRANS_INFO * TransportInterface,
  893. IN DCE_BINDING * DceBinding
  894. );
  895. RPC_STATUS
  896. ToStringBinding (
  897. OUT RPC_CHAR * * StringBinding
  898. );
  899. RPC_STATUS
  900. ResolveBinding (
  901. IN RPC_CLIENT_INTERFACE * RpcClientInterface
  902. );
  903. RPC_STATUS
  904. BindingReset ();
  905. virtual RPC_STATUS
  906. InquireTransportType(
  907. OUT unsigned int * Type
  908. )
  909. {
  910. *Type = TRANSPORT_TYPE_DG;
  911. return(RPC_S_OK);
  912. }
  913. inline void IncrementRefCount()
  914. {
  915. long Count = ReferenceCount.Increment();
  916. LogEvent(SU_HANDLE, EV_INC, this, 0, Count);
  917. }
  918. void DecrementRefCount();
  919. void
  920. FreeCall(
  921. DG_CCALL * Call
  922. );
  923. void DisassociateFromServer();
  924. unsigned long
  925. MapAuthenticationLevel (
  926. IN unsigned long AuthenticationLevel
  927. );
  928. BOOL
  929. SetTransportAuthentication(
  930. IN unsigned long ulAuthenticationLevel,
  931. IN unsigned long ulAuthenticationService,
  932. OUT RPC_STATUS *pStatus
  933. );
  934. inline BOOL
  935. IsDynamic()
  936. {
  937. return fDynamicEndpoint;
  938. }
  939. RPC_STATUS
  940. SetTransportOption(
  941. IN unsigned long option,
  942. IN ULONG_PTR optionValue
  943. );
  944. RPC_STATUS
  945. InqTransportOption(
  946. IN unsigned long option,
  947. OUT ULONG_PTR * pOptionValue
  948. );
  949. void MutexRequest()
  950. {
  951. #ifdef CHECK_MUTEX_INVERSION
  952. if (!BindingMutex.OwnedByMe() )
  953. {
  954. DG_CCONNECTION * conn = (DG_CCONNECTION *) ThreadSelf()->ConnectionMutexHeld;
  955. ASSERT( 0 == conn || conn->ThreadId == GetCurrentThreadId() );
  956. if (Association)
  957. {
  958. if (Association->LockOwnedByMe() == FALSE)
  959. {
  960. Association->VerifyNotLocked();
  961. }
  962. }
  963. }
  964. #endif
  965. BindingMutex.Request();
  966. }
  967. void MutexClear()
  968. {
  969. BindingMutex.Clear();
  970. }
  971. private:
  972. TRANS_INFO * TransportObject;
  973. RPC_DATAGRAM_TRANSPORT *TransportInterface;
  974. DG_CASSOCIATION * Association;
  975. INTERLOCKED_INTEGER ReferenceCount;
  976. boolean fDynamicEndpoint;
  977. unsigned fContextHandle;
  978. RPC_STATUS
  979. FindOrCreateAssociation(
  980. IN const PRPC_CLIENT_INTERFACE Interface,
  981. IN BOOL fReconnect,
  982. IN BOOL fBroadcast
  983. );
  984. };
  985. inline DG_BINDING_HANDLE::DG_BINDING_HANDLE(
  986. IN OUT RPC_STATUS * pStatus
  987. )
  988. : BINDING_HANDLE (pStatus),
  989. Association (0),
  990. ReferenceCount(1),
  991. pDceBinding (0),
  992. fContextHandle(0),
  993. EndpointFlags (0)
  994. /*++
  995. Routine Description:
  996. The constructor for DG_BINDING_HANDLE. This object represents a
  997. binding to a server. Most of the important members
  998. are set in DG_BINDING_HANDLE::PrepareBindingHandle.
  999. --*/
  1000. {
  1001. ObjectType = DG_BINDING_HANDLE_TYPE;
  1002. LogEvent(SU_HANDLE, EV_CREATE, this);
  1003. }
  1004. inline DG_BINDING_HANDLE::DG_BINDING_HANDLE(
  1005. IN PDG_CASSOCIATION a_Association,
  1006. IN DCE_BINDING * a_DceBinding,
  1007. IN OUT RPC_STATUS * a_pStatus
  1008. )
  1009. : BINDING_HANDLE(a_pStatus),
  1010. Association (a_Association),
  1011. ReferenceCount(1),
  1012. pDceBinding (a_DceBinding),
  1013. fContextHandle(0),
  1014. EndpointFlags (0)
  1015. /*++
  1016. Routine Description:
  1017. The constructor for DG_BINDING_HANDLE. This is a quick and dirty constructor;
  1018. in particular it does not clone the DCE_BINDING.
  1019. --*/
  1020. {
  1021. ObjectType = DG_BINDING_HANDLE_TYPE;
  1022. LogEvent(SU_HANDLE, EV_CREATE, this, 0, *a_pStatus);
  1023. if (0 != *a_pStatus)
  1024. {
  1025. Association = 0;
  1026. }
  1027. }
  1028. inline DG_BINDING_HANDLE::~DG_BINDING_HANDLE()
  1029. /*++
  1030. Routine Description:
  1031. Destructor for the DG_BINDING_HANDLE. Let the association know we aren't
  1032. using it anymore; this may cause it to be deleted.
  1033. Arguments:
  1034. <none>
  1035. Return Value:
  1036. <none>
  1037. --*/
  1038. {
  1039. LogEvent(SU_HANDLE, EV_DELETE, this);
  1040. if (Association != 0)
  1041. {
  1042. Association->DecrementBindingRefCount(fContextHandle);
  1043. }
  1044. delete pDceBinding;
  1045. }
  1046. inline void
  1047. DG_BINDING_HANDLE::DecrementRefCount()
  1048. {
  1049. long Count = ReferenceCount.Decrement();
  1050. LogEvent(SU_HANDLE, EV_DEC, this, 0, Count, TRUE);
  1051. if (Count == 0)
  1052. {
  1053. delete this;
  1054. }
  1055. }
  1056. class DG_CLIENT_CALLBACK : public MESSAGE_OBJECT
  1057. {
  1058. public:
  1059. DG_PACKET * Request;
  1060. DG_CCONNECTION * Connection;
  1061. DG_ENDPOINT * LocalEndpoint;
  1062. DG_TRANSPORT_ADDRESS RemoteAddress;
  1063. //--------------------------------------------------------------------
  1064. inline DG_CLIENT_CALLBACK()
  1065. {
  1066. ObjectType = DG_CALLBACK_TYPE;
  1067. Request = 0;
  1068. }
  1069. inline ~DG_CLIENT_CALLBACK()
  1070. {
  1071. if (Request)
  1072. {
  1073. Request->Free(FALSE);
  1074. }
  1075. }
  1076. virtual RPC_STATUS
  1077. NegotiateTransferSyntax (
  1078. IN OUT PRPC_MESSAGE Message
  1079. )
  1080. {
  1081. // datagrams don't support multiple syntax
  1082. // negotiation. They always return the transfer
  1083. // syntax the stub prefers
  1084. return RPC_S_OK;
  1085. }
  1086. virtual RPC_STATUS
  1087. GetBuffer(
  1088. IN OUT PRPC_MESSAGE Message,
  1089. IN UUID *ObjectUuid
  1090. );
  1091. virtual void
  1092. FreeBuffer(
  1093. IN OUT PRPC_MESSAGE Message
  1094. );
  1095. // not really implemented
  1096. virtual RPC_STATUS
  1097. SendReceive (
  1098. IN OUT PRPC_MESSAGE Message
  1099. );
  1100. virtual RPC_STATUS
  1101. Send(
  1102. PRPC_MESSAGE Message
  1103. );
  1104. virtual RPC_STATUS
  1105. AsyncSend(
  1106. PRPC_MESSAGE Message
  1107. );
  1108. virtual RPC_STATUS
  1109. Receive(
  1110. PRPC_MESSAGE Message,
  1111. unsigned MinimumSize
  1112. );
  1113. virtual RPC_STATUS
  1114. SetAsyncHandle (
  1115. IN RPC_ASYNC_STATE * hAsync
  1116. );
  1117. virtual BOOL
  1118. IsSyncCall ()
  1119. {
  1120. return FALSE;
  1121. }
  1122. inline void
  1123. SendPacket(
  1124. NCA_PACKET_HEADER * Header
  1125. )
  1126. {
  1127. unsigned Frag = (Header->PacketType << 16) | Header->GetFragmentNumber();
  1128. LogEvent( SU_CCONN, EV_PKT_OUT, Connection, 0, Frag);
  1129. LocalEndpoint->TransportInterface->Send(
  1130. &LocalEndpoint->TransportEndpoint,
  1131. RemoteAddress,
  1132. 0,
  1133. 0,
  1134. Header,
  1135. sizeof(NCA_PACKET_HEADER) + Header->GetPacketBodyLen(),
  1136. 0,
  1137. 0
  1138. );
  1139. }
  1140. };
  1141. typedef DG_CLIENT_CALLBACK * PDG_CLIENT_CALLBACK;
  1142. class CLIENT_ACTIVITY_TABLE : private UUID_HASH_TABLE
  1143. {
  1144. public:
  1145. inline
  1146. CLIENT_ACTIVITY_TABLE(
  1147. RPC_STATUS * pStatus
  1148. )
  1149. : UUID_HASH_TABLE(pStatus)
  1150. {
  1151. }
  1152. inline
  1153. ~CLIENT_ACTIVITY_TABLE(
  1154. )
  1155. {
  1156. }
  1157. PDG_CCONNECTION
  1158. Lookup(
  1159. RPC_UUID * Uuid
  1160. );
  1161. inline RPC_STATUS
  1162. Add(
  1163. PDG_CCONNECTION Connection
  1164. );
  1165. inline RPC_STATUS
  1166. Remove(
  1167. PDG_CCONNECTION Connection
  1168. );
  1169. };
  1170. RPC_STATUS
  1171. CLIENT_ACTIVITY_TABLE::Add(
  1172. PDG_CCONNECTION Connection
  1173. )
  1174. {
  1175. ASSERT( !Connection->InConnectionTable );
  1176. Connection->InConnectionTable = TRUE;
  1177. unsigned Hash = MakeHash(&Connection->ActivityNode.Uuid);
  1178. RequestHashMutex(Hash);
  1179. UUID_HASH_TABLE::Add(&Connection->ActivityNode);
  1180. ReleaseHashMutex(Hash);
  1181. return RPC_S_OK;
  1182. }
  1183. RPC_STATUS
  1184. CLIENT_ACTIVITY_TABLE::Remove(
  1185. PDG_CCONNECTION Connection
  1186. )
  1187. {
  1188. if( !Connection->InConnectionTable )
  1189. {
  1190. return RPC_S_OK;
  1191. }
  1192. Connection->InConnectionTable = FALSE;
  1193. unsigned Hash = MakeHash(&Connection->ActivityNode.Uuid);
  1194. RequestHashMutex(Hash);
  1195. UUID_HASH_TABLE::Remove(&Connection->ActivityNode);
  1196. ReleaseHashMutex(Hash);
  1197. return RPC_S_OK;
  1198. }
  1199. class ENDPOINT_MANAGER
  1200. {
  1201. public:
  1202. ENDPOINT_MANAGER(
  1203. IN OUT RPC_STATUS * pStatus
  1204. );
  1205. DG_ENDPOINT *
  1206. RequestEndpoint(
  1207. IN RPC_DATAGRAM_TRANSPORT * TransportInterface,
  1208. IN BOOL Async,
  1209. IN DWORD Flags
  1210. );
  1211. void
  1212. ReleaseEndpoint(
  1213. IN DG_ENDPOINT * Endpoint
  1214. );
  1215. BOOL
  1216. DeleteIdleEndpoints(
  1217. long CurrentTime
  1218. );
  1219. private:
  1220. #define DG_TRANSPORT_COUNT 2
  1221. MUTEX Mutex;
  1222. DWORD LastScavengeTime;
  1223. DG_ENDPOINT_STATS Stats;
  1224. DG_ENDPOINT * AsyncEndpoints[DG_TRANSPORT_COUNT];
  1225. DG_ENDPOINT * Endpoints;
  1226. };
  1227. //------------------------------------------------------------------------
  1228. inline void
  1229. DG_CCONNECTION::AddCallToCache(
  1230. PDG_CCALL Call
  1231. )
  1232. {
  1233. Mutex.VerifyOwned();
  1234. Call->Next = CachedCalls;
  1235. CachedCalls = Call;
  1236. LogEvent(SU_CCALL, EV_STOP, Call, this, Call->GetSequenceNumber() );
  1237. #ifdef DEBUGRPC
  1238. PDG_CCALL Node = ActiveCallHead;
  1239. while (Node)
  1240. {
  1241. ASSERT( Node != Call );
  1242. Node = Node->Next;
  1243. }
  1244. #endif
  1245. }
  1246. void
  1247. DG_CCONNECTION::UpdateAssociation(
  1248. )
  1249. {
  1250. Association->CurrentPduSize = CurrentPduSize;
  1251. Association->RemoteWindowSize = RemoteWindowSize;
  1252. }
  1253. unsigned long
  1254. DG_CCONNECTION::CurrentSequenceNumber()
  1255. {
  1256. return CurrentCall->GetSequenceNumber();
  1257. }
  1258. inline void DG_CCALL::IncrementRefCount()
  1259. {
  1260. ++ReferenceCount;
  1261. LogEvent(SU_CCALL, EV_INC, this, 0, ReferenceCount);
  1262. }
  1263. inline void
  1264. DG_CCALL::SwitchConnection(
  1265. PDG_CCONNECTION NewConnection
  1266. )
  1267. {
  1268. Connection = NewConnection;
  1269. ReadConnectionInfo(NewConnection, 0);
  1270. ActivityHint = 0xffff;
  1271. pSavedPacket->Header.ServerBootTime = NewConnection->Association->ServerBootTime;
  1272. pSavedPacket->Header.ActivityHint = ActivityHint;
  1273. }
  1274. RPC_STATUS
  1275. StandardPacketChecks(
  1276. PDG_PACKET Packet
  1277. );
  1278. #endif // if __DGCLNT_HXX__