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.

8052 lines
188 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1992 - 1999
  3. Module Name:
  4. dgclnt.cxx
  5. Abstract:
  6. This is the client side of datagram rpc.
  7. Author:
  8. Jeff Roberts
  9. Revisions:
  10. Jeff Roberts (jroberts) 9-30-1996
  11. Began asynchronous call support.
  12. Began to remove DOS and Win16 support.
  13. --*/
  14. #include <precomp.hxx>
  15. #include <conv.h>
  16. #include <convc.h>
  17. #include <epmap.h>
  18. #include <dgpkt.hxx>
  19. #include <spseal.h>
  20. #include <locks.hxx>
  21. #include <dgclnt.hxx>
  22. /*
  23. There are a lot of mutexes in this architecture. All these objects are
  24. protected by mutexes:
  25. DG_BINDING_HANDLE
  26. DG_CASSOCIATION
  27. DG_CLIENT_ADDRESS_TABLE
  28. DG_CCONNECTION
  29. DG_ASSOCIATION_TABLE (exclusive access)
  30. In many cases it is necessary to acquire multiple mutexes at a time. To avoid
  31. deadlock, multiple mutexes must be taken in the order they are listed above.
  32. For most of the code's history this ordering was not articulated, so there is
  33. no macro to help enforce it. It's just a good idea.
  34. */
  35. //
  36. // If you #define INTRODUCE_ERRORS then you can get the client and server
  37. // to drop or delay some packets. Here are the environment variables that
  38. // control this behavior:
  39. //
  40. // set ServerDelayRate=xxx where xxx is a percentage 0..100
  41. // set ServerDelayTime=xxx where xxx is the number of msec to delay
  42. // set ServerDropRate=xxx where xxx is a percentage 0..100
  43. //
  44. // set ClientDelayRate=xxx where xxx is a percentage 0..100
  45. // set ClientDelayTime=xxx where xxx is the number of msec to delay
  46. // set ClientDropRate=xxx where xxx is a percentage 0..100
  47. //
  48. #define IDLE_CCALL_LIFETIME (30 * 1000)
  49. #define IDLE_CCALL_SWEEP_INTERVAL (30 * 1000)
  50. //#define IDLE_CCONNECTION_LIFETIME (5 * 60 * 1000)
  51. //#define IDLE_CCONNECTION_SWEEP_INTERVAL (1 * 60 * 1000)
  52. //#define IDLE_CASSOCIATION_LIFETIME (10 * 60 * 1000)
  53. #define IDLE_CCONNECTION_LIFETIME (2 * 60 * 1000)
  54. #define IDLE_CCONNECTION_SWEEP_INTERVAL ( 30 * 1000)
  55. #define IDLE_CASSOCIATION_LIFETIME ( 30 * 1000)
  56. #define GLOBAL_SCAVENGER_INTERVAL (30 * 1000)
  57. #define IDLE_ENDPOINT_LIFETIME (30 * 1000)
  58. #define PENALTY_BOX_DURATION (10 * 1000)
  59. #define CXT_HANDLE_KEEPALIVE_INTERVAL (20 * 1000)
  60. #define CXT_HANDLE_SWEEP_INTERVAL (10 * 1000)
  61. //
  62. // endpoint flags
  63. //
  64. // in rpcdce.h:
  65. // #define RPC_C_USE_INTERNET_PORT 0x1
  66. // #define RPC_C_USE_INTRANET_PORT 0x2
  67. // calls with the maybe attribute are banished to a separate endpoint
  68. //
  69. #define PORT_FOR_MAYBE_CALLS (0x1000)
  70. // if a call fails or sends an ACK, there is a chance that an ICMP will be sent
  71. // and we don't want it sitting in the port buffer when the next call uses the endpoint.
  72. //
  73. #define PENALTY_BOX (0x0800)
  74. //-------------------------------------------------------------------
  75. DG_ASSOCIATION_TABLE * ActiveAssociations;
  76. CLIENT_ACTIVITY_TABLE * ClientConnections;
  77. ENDPOINT_MANAGER * EndpointManager;
  78. DELAYED_ACTION_TABLE * DelayedProcedures;
  79. long GlobalScavengerTimeStamp;
  80. DELAYED_ACTION_NODE * GlobalScavengerTimer;
  81. DELAYED_ACTION_NODE * ContextHandleTimer;
  82. LONG ClientConnectionCount = 0;
  83. LONG ClientCallCount = 0;
  84. //-------------------------------------------------------------------
  85. void
  86. ContextHandleProc(
  87. void * arg
  88. );
  89. void
  90. DelayedAckFn(
  91. void * parm
  92. );
  93. void
  94. DelayedSendProc(
  95. void * parm
  96. );
  97. RPC_STATUS
  98. DispatchCallbackRequest(
  99. DG_CLIENT_CALLBACK * CallbackObject
  100. );
  101. int
  102. InitializeRpcProtocolDgClient();
  103. //--------------------------------------------------------------------
  104. void
  105. EnableGlobalScavenger()
  106. {
  107. DelayedProcedures->Add(GlobalScavengerTimer, GLOBAL_SCAVENGER_INTERVAL + (5 * 1000), FALSE);
  108. }
  109. void
  110. GlobalScavengerProc(
  111. void * Arg
  112. )
  113. {
  114. long CurrentTime = PtrToLong( Arg );
  115. if (!CurrentTime)
  116. {
  117. CurrentTime = GetTickCount();
  118. }
  119. if (CurrentTime - GlobalScavengerTimeStamp <= 0)
  120. {
  121. return;
  122. }
  123. GlobalScavengerTimeStamp = CurrentTime;
  124. boolean Continue = FALSE;
  125. Continue |= DG_PACKET::DeleteIdlePackets(CurrentTime);
  126. Continue |= ActiveAssociations->DeleteIdleEntries(CurrentTime);
  127. Continue |= EndpointManager->DeleteIdleEndpoints(CurrentTime);
  128. if (Continue)
  129. {
  130. EnableGlobalScavenger();
  131. }
  132. }
  133. #ifdef INTRODUCE_ERRORS
  134. long ServerDelayTime;
  135. long ServerDelayRate;
  136. long ServerDropRate;
  137. long ClientDelayTime;
  138. long ClientDelayRate;
  139. long ClientDropRate;
  140. #endif
  141. int
  142. InitializeRpcProtocolDgClient ()
  143. /*++
  144. Routine Description:
  145. This routine initializes the datagram protocol.
  146. Arguments:
  147. <none>
  148. Return Value:
  149. 0 if successfull, 1 if not.
  150. --*/
  151. {
  152. RPC_STATUS Status = RPC_S_OK;
  153. //
  154. // Don't take the global mutex if we can help it.
  155. //
  156. if (ProcessStartTime)
  157. {
  158. return 0;
  159. }
  160. RequestGlobalMutex();
  161. if (!ProcessStartTime)
  162. {
  163. Status = DG_PACKET::Initialize();
  164. if (Status != RPC_S_OK)
  165. {
  166. goto abend;
  167. }
  168. DelayedProcedures = new DELAYED_ACTION_TABLE(&Status);
  169. if (!DelayedProcedures)
  170. {
  171. Status = RPC_S_OUT_OF_MEMORY;
  172. }
  173. if (Status != RPC_S_OK)
  174. {
  175. goto abend;
  176. }
  177. GlobalScavengerTimer = new DELAYED_ACTION_NODE(GlobalScavengerProc, 0);
  178. if (!GlobalScavengerTimer)
  179. {
  180. goto abend;
  181. }
  182. GlobalScavengerTimeStamp = GetTickCount();
  183. ContextHandleTimer = new DELAYED_ACTION_NODE(ContextHandleProc, 0);
  184. if (!ContextHandleTimer)
  185. {
  186. goto abend;
  187. }
  188. ClientConnections = new CLIENT_ACTIVITY_TABLE(&Status);
  189. if (!ClientConnections)
  190. {
  191. Status = RPC_S_OUT_OF_MEMORY;
  192. }
  193. if (Status != RPC_S_OK)
  194. {
  195. goto abend;
  196. }
  197. ActiveAssociations = new DG_ASSOCIATION_TABLE(&Status);
  198. if (!ActiveAssociations)
  199. {
  200. Status = RPC_S_OUT_OF_MEMORY;
  201. }
  202. if (Status != RPC_S_OK)
  203. {
  204. goto abend;
  205. }
  206. EndpointManager = new ENDPOINT_MANAGER(&Status);
  207. if (!EndpointManager)
  208. {
  209. Status = RPC_S_OUT_OF_MEMORY;
  210. }
  211. if (Status != RPC_S_OK)
  212. {
  213. goto abend;
  214. }
  215. //
  216. // Server boot time is represented as the number of seconds
  217. // since 1/1/1970. It must increase with each boot of the server.
  218. //
  219. LARGE_INTEGER CurrentTime;
  220. NTSTATUS Nt_Status;
  221. Nt_Status = NtQuerySystemTime(&CurrentTime);
  222. ASSERT( NT_SUCCESS(Nt_Status) );
  223. RtlTimeToSecondsSince1980(&CurrentTime, &ProcessStartTime);
  224. ProcessStartTime += (60 * 60 * 24 * 365 * 10);
  225. #ifdef INTRODUCE_ERRORS
  226. char EnvBuffer[64];
  227. if (GetEnvironmentVariableA("ServerDelayTime", EnvBuffer, 64))
  228. {
  229. ::ServerDelayTime = atol(EnvBuffer);
  230. }
  231. if (GetEnvironmentVariableA("ServerDelayRate", EnvBuffer, 64))
  232. {
  233. ::ServerDelayRate = atol(EnvBuffer);
  234. }
  235. if (GetEnvironmentVariableA("ServerDropRate", EnvBuffer, 64))
  236. {
  237. ::ServerDropRate = atol(EnvBuffer);
  238. }
  239. if (GetEnvironmentVariableA("ClientDelayTime", EnvBuffer, 64))
  240. {
  241. ::ClientDelayTime = atol(EnvBuffer);
  242. }
  243. if (GetEnvironmentVariableA("ClientDelayRate", EnvBuffer, 64))
  244. {
  245. ::ClientDelayRate = atol(EnvBuffer);
  246. }
  247. if (GetEnvironmentVariableA("ClientDropRate", EnvBuffer, 64))
  248. {
  249. ::ClientDropRate = atol(EnvBuffer);
  250. }
  251. #endif
  252. }
  253. ClearGlobalMutex();
  254. return 0;
  255. //--------------------------------------------------------------------
  256. abend:
  257. delete EndpointManager;
  258. EndpointManager = 0;
  259. delete ActiveAssociations;
  260. ActiveAssociations = 0;
  261. delete ClientConnections;
  262. ClientConnections = 0;
  263. delete GlobalScavengerTimer;
  264. GlobalScavengerTimer = 0;
  265. delete DelayedProcedures;
  266. DelayedProcedures = 0;
  267. ClearGlobalMutex();
  268. return 1;
  269. }
  270. BINDING_HANDLE *
  271. DgCreateBindingHandle ()
  272. /*++
  273. Routine Description:
  274. Pseudo-constructor for creating a dg binding handle. It is done in a
  275. separate function so that the calling routine doesn't have to know
  276. any protocol-specific information.
  277. Arguments:
  278. <none>
  279. Return Value:
  280. A DG_BINDING_HANDLE, if successful, otherwise 0 (indicating out of mem)
  281. --*/
  282. {
  283. RPC_STATUS Status = RPC_S_OK;
  284. BINDING_HANDLE * Binding;
  285. Binding = new DG_BINDING_HANDLE(&Status);
  286. if (Status != RPC_S_OK)
  287. {
  288. delete Binding;
  289. return 0;
  290. }
  291. return Binding;
  292. }
  293. void
  294. DG_CASSOCIATION::FlushAcks(
  295. )
  296. {
  297. PDG_CCONNECTION Connection;
  298. DictionaryCursor cursor;
  299. MutexRequest();
  300. ActiveConnections.Reset(cursor);
  301. while (Connection = ActiveConnections.Next(cursor))
  302. {
  303. // If an ACK is pending, send it.
  304. //
  305. Connection->CancelDelayedAck( TRUE );
  306. }
  307. ASSERT( ReferenceCount.GetInteger() > 0 );
  308. MutexClear();
  309. }
  310. void
  311. DG_CASSOCIATION::DecrementRefCount()
  312. /*++
  313. Routine Description:
  314. Decrements the ref count to an association. If the ref count hits zero,
  315. the association is marked for deletion.
  316. It is possible for the count to go to zero just as another thread is
  317. scavenging the association table. This would be a rare occurence, and
  318. should cause no ill effect.
  319. --*/
  320. {
  321. ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) );
  322. ActiveAssociations->UpdateTimeStamp( this );
  323. long Count = ReferenceCount.Decrement();
  324. LogEvent(SU_CASSOC, EV_DEC, this, 0, Count);
  325. if (0 == Count)
  326. {
  327. LogEvent(SU_CASSOC, EV_STOP, this);
  328. EnableGlobalScavenger();
  329. }
  330. }
  331. RPC_STATUS
  332. DG_CASSOCIATION::UpdateAssociationWithAddress(
  333. PDG_PACKET Packet,
  334. DG_TRANSPORT_ADDRESS NewAddress
  335. )
  336. {
  337. ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) );
  338. long OldAssociationFlags;
  339. if (!AssociationFlag)
  340. {
  341. return RPC_S_OK;
  342. }
  343. if (Packet->Header.PacketType != DG_FACK &&
  344. Packet->Header.PacketType != DG_WORKING &&
  345. Packet->Header.PacketType != DG_RESPONSE &&
  346. Packet->Header.PacketType != DG_FAULT )
  347. {
  348. return RPC_S_OK;
  349. }
  350. OldAssociationFlags = InterlockedExchange(&AssociationFlag, 0);
  351. if (0 == OldAssociationFlags)
  352. {
  353. return RPC_S_OK;
  354. }
  355. LogEvent(SU_CASSOC, EV_RESOLVED, this, 0, OldAssociationFlags);
  356. CLAIM_MUTEX Lock( Mutex );
  357. //
  358. // Save the updated network address + endpoint.
  359. //
  360. RPC_STATUS Status;
  361. char * SecondAddress;
  362. SecondAddress = (char *) (this + 1);
  363. SecondAddress += TransportInterface->AddressSize;
  364. //
  365. // The only flags we handle here are UNRESOLVEDEP and BROADCAST.
  366. //
  367. ASSERT( 0 == (OldAssociationFlags & ~(UNRESOLVEDEP | BROADCAST)) );
  368. if (OldAssociationFlags & BROADCAST)
  369. {
  370. RPC_STATUS Status = RPC_S_OK;
  371. DCE_BINDING * OldDceBinding = 0;
  372. DCE_BINDING * NewDceBinding = 0;
  373. RPC_CHAR * ObjectUuid = 0;
  374. RPC_CHAR * AddressString = (RPC_CHAR *) _alloca(TransportInterface->AddressStringSize * sizeof(RPC_CHAR));
  375. RPC_CHAR * EndpointString = pDceBinding->InqEndpoint();
  376. Status = TransportInterface->QueryAddress(NewAddress, AddressString);
  377. if ( Status != RPC_S_OK )
  378. {
  379. LogError(SU_CASSOC, EV_STATUS, this, 0, Status);
  380. SetErrorFlag();
  381. return Status;
  382. }
  383. if (OldAssociationFlags & UNRESOLVEDEP)
  384. {
  385. Status = TransportInterface->QueryEndpoint(NewAddress, ResolvedEndpoint);
  386. if ( Status != RPC_S_OK )
  387. {
  388. LogError(SU_CASSOC, EV_STATUS, this, 0, Status);
  389. SetErrorFlag();
  390. return Status;
  391. }
  392. EndpointString = ResolvedEndpoint;
  393. }
  394. ObjectUuid = pDceBinding->ObjectUuidCompose( &Status );
  395. if ( Status != RPC_S_OK )
  396. {
  397. LogError(SU_CASSOC, EV_STATUS, this, 0, Status);
  398. SetErrorFlag();
  399. return Status;
  400. }
  401. NewDceBinding = new DCE_BINDING( ObjectUuid,
  402. pDceBinding->InqRpcProtocolSequence(),
  403. AddressString,
  404. EndpointString,
  405. pDceBinding->InqNetworkOptions(),
  406. &Status
  407. );
  408. RpcpFarFree( ObjectUuid );
  409. if (Status || !NewDceBinding)
  410. {
  411. delete NewDceBinding;
  412. LogError(SU_CASSOC, EV_STATUS, this, 0, Status);
  413. SetErrorFlag();
  414. return Status;
  415. }
  416. OldDceBinding = pDceBinding;
  417. pDceBinding = NewDceBinding;
  418. delete OldDceBinding;
  419. }
  420. else if (OldAssociationFlags & UNRESOLVEDEP)
  421. {
  422. //
  423. // We have resolved a dynamic endpoint; update the endpoint in the DCE_BINDING.
  424. //
  425. Status = TransportInterface->QueryEndpoint(NewAddress, ResolvedEndpoint);
  426. if ( Status != RPC_S_OK )
  427. {
  428. LogError(SU_CASSOC, EV_STATUS, this, 0, Status);
  429. SetErrorFlag();
  430. return Status;
  431. }
  432. pDceBinding->AddEndpoint(ResolvedEndpoint);
  433. ResolvedEndpoint = 0;
  434. }
  435. else
  436. {
  437. ASSERT( 0 );
  438. }
  439. RpcpMemoryCopy( SecondAddress, NewAddress, TransportInterface->AddressSize );
  440. ServerAddress = SecondAddress;
  441. return RPC_S_OK;
  442. }
  443. RPC_STATUS
  444. DG_BINDING_HANDLE::FindOrCreateAssociation(
  445. IN const PRPC_CLIENT_INTERFACE Interface,
  446. IN BOOL fReconnect,
  447. IN BOOL fBroadcast
  448. )
  449. {
  450. RPC_STATUS Status;
  451. BOOL fPartial = FALSE;
  452. LONG AssociationFlag = 0;
  453. if (fBroadcast)
  454. {
  455. AssociationFlag = DG_CASSOCIATION::BROADCAST;
  456. }
  457. //
  458. // Check to see if we need to resolve this endpoint.
  459. //
  460. Status = pDceBinding->ResolveEndpointIfNecessary(
  461. Interface,
  462. InqPointerAtObjectUuid(),
  463. InquireEpLookupHandle(),
  464. TRUE, //UseEpMapper Ep If Necessary
  465. InqComTimeout(),
  466. INFINITE, // CallTimeout
  467. NULL // AuthInfo
  468. );
  469. if (Status == RPC_P_EPMAPPER_EP)
  470. {
  471. AssociationFlag |= DG_CASSOCIATION::UNRESOLVEDEP;
  472. fPartial = TRUE;
  473. Status = 0;
  474. }
  475. if (Status)
  476. {
  477. return Status;
  478. }
  479. //
  480. // A binding with the UNIQUE option set should maintain its own association,
  481. // never sharing with other binding handles. This is used by the Wolfpack
  482. // cluster software to manage connections themselves.
  483. //
  484. ULONG_PTR fUnique;
  485. Status = InqTransportOption(RPC_C_OPT_UNIQUE_BINDING, &fUnique);
  486. ASSERT(Status == RPC_S_OK);
  487. if (fUnique == 0 && fBroadcast == FALSE)
  488. {
  489. //
  490. // Look for a matching association.
  491. //
  492. ASSERT( Association == 0 );
  493. Association = ActiveAssociations->Find( this, Interface, fContextHandle, fPartial, fReconnect );
  494. if (Association)
  495. {
  496. return 0;
  497. }
  498. }
  499. //
  500. // Create a matching association.
  501. //
  502. ASSERT(pDceBinding);
  503. DCE_BINDING * NewDceBinding = pDceBinding->DuplicateDceBinding();
  504. if (!NewDceBinding)
  505. {
  506. return RPC_S_OUT_OF_MEMORY;
  507. }
  508. Association = new (TransportInterface) DG_CASSOCIATION( TransportInterface,
  509. AssociationFlag,
  510. NewDceBinding,
  511. (BOOL) fUnique,
  512. &Status
  513. );
  514. if (Association == 0)
  515. {
  516. Status = RPC_S_OUT_OF_MEMORY;
  517. }
  518. if (Status)
  519. {
  520. delete Association;
  521. Association = 0;
  522. return Status;
  523. }
  524. //
  525. // Other threads using this binding handle for the same interface
  526. // will reuse this association instead of creating a new one.
  527. //
  528. Association->AddInterface(Interface, InqPointerAtObjectUuid());
  529. return 0;
  530. }
  531. RPC_STATUS
  532. DG_BINDING_HANDLE::SetTransportOption( IN unsigned long option,
  533. IN ULONG_PTR optionValue )
  534. /*++
  535. Routine Description:
  536. Set the binding specific transport option to the optionValue.
  537. Arguments:
  538. option -- Option to set (transport specific).
  539. optionValue -- New value for option.
  540. Return Value: RPC_S_OK
  541. RPC_S_CANNOT_SUPPORT
  542. RPC_S_ARG_INVALID
  543. RPC_S_OUT_OF_MEMORY
  544. --*/
  545. {
  546. RPC_STATUS Status = RPC_S_OK;
  547. if (option >= RPC_C_OPT_BINDING_NONCAUSAL)
  548. {
  549. //
  550. // This option can be changed only before a call is made.
  551. //
  552. if (option == RPC_C_OPT_UNIQUE_BINDING && Association != NULL)
  553. {
  554. return RPC_S_WRONG_KIND_OF_BINDING;
  555. }
  556. return BINDING_HANDLE::SetTransportOption(option, optionValue);
  557. }
  558. if ( (TransportInterface) && (TransportInterface->OptionsSize > 0) )
  559. {
  560. if (pvTransportOptions == NULL)
  561. {
  562. pvTransportOptions = (void*)I_RpcAllocate(TransportInterface->OptionsSize);
  563. if (pvTransportOptions == NULL)
  564. {
  565. return RPC_S_OUT_OF_MEMORY;
  566. }
  567. Status = TransportInterface->InitOptions(pvTransportOptions);
  568. }
  569. if (Status == RPC_S_OK)
  570. {
  571. Status = TransportInterface->SetOption(pvTransportOptions,option,optionValue);
  572. }
  573. }
  574. else
  575. {
  576. Status = RPC_S_CANNOT_SUPPORT;
  577. }
  578. return Status;
  579. }
  580. RPC_STATUS
  581. DG_BINDING_HANDLE::InqTransportOption( IN unsigned long option,
  582. OUT ULONG_PTR *pOptionValue )
  583. /*++
  584. Routine Description:
  585. Get the value of a transport specific binding option.
  586. Arguments:
  587. option -- Option to inquire.
  588. pOptionValue - Place to return the current value.
  589. Return Value: RPC_S_OK
  590. RPC_S_CANNOT_SUPPORT
  591. RPC_S_ARG_INVALID
  592. RPC_S_OUT_OF_MEMORY
  593. --*/
  594. {
  595. RPC_STATUS Status = RPC_S_OK;
  596. if (option >= RPC_C_OPT_BINDING_NONCAUSAL)
  597. {
  598. return BINDING_HANDLE::InqTransportOption(option, pOptionValue);
  599. }
  600. if ( (TransportInterface) && (TransportInterface->OptionsSize > 0) )
  601. {
  602. if (pvTransportOptions == NULL)
  603. {
  604. pvTransportOptions = (void*)I_RpcAllocate(TransportInterface->OptionsSize);
  605. if (pvTransportOptions == NULL)
  606. return RPC_S_OUT_OF_MEMORY;
  607. Status = TransportInterface->InitOptions(pvTransportOptions);
  608. }
  609. if (Status == RPC_S_OK)
  610. Status = TransportInterface->InqOption(pvTransportOptions,option,pOptionValue);
  611. }
  612. else
  613. Status = RPC_S_CANNOT_SUPPORT;
  614. return Status;
  615. }
  616. RPC_STATUS
  617. DG_BINDING_HANDLE::GetBuffer (
  618. IN OUT PRPC_MESSAGE Message,
  619. IN UUID *ObjectUuid
  620. )
  621. /*++
  622. Routine Description:
  623. This is the routine that is called to initiate an rpc. At this point,
  624. the client stub is allocating memory to place the parameters into. Ask our
  625. association for a DG_CCALL object to transact this call on then send
  626. the buffer request off to that DG_CCALL.
  627. Arguments:
  628. Message - The RPC_MESSAGE structure associated with this call.
  629. Return Value:
  630. RPC_S_OUT_OF_MEMORY
  631. RPC_S_OK
  632. Revision History:
  633. --*/
  634. {
  635. BOOL fBroadcast = FALSE;
  636. RPC_STATUS Status;
  637. LogEvent( SU_HANDLE, EV_PROC, this, 0, 'G' + (('e' + (('t' + ('B' << 8)) << 8)) << 8));
  638. if (Message->RpcFlags & (RPC_NCA_FLAGS_MAYBE | RPC_NCA_FLAGS_BROADCAST))
  639. {
  640. Message->RpcFlags |= RPC_NCA_FLAGS_IDEMPOTENT;
  641. }
  642. if (Message->RpcFlags & RPC_BUFFER_ASYNC)
  643. {
  644. Status = TransportObject->CreateThread();
  645. if (Status != RPC_S_OK)
  646. {
  647. return Status;
  648. }
  649. }
  650. if (Message->RpcFlags & RPC_NCA_FLAGS_BROADCAST)
  651. {
  652. fBroadcast = TRUE;
  653. }
  654. MutexRequest();
  655. ASSERT(pDceBinding != 0);
  656. //
  657. // Have we already determined the association for this binding handle?
  658. //
  659. if (Association == 0)
  660. {
  661. Status = FindOrCreateAssociation( (PRPC_CLIENT_INTERFACE) Message->RpcInterfaceInformation, FALSE, fBroadcast );
  662. if (Status)
  663. {
  664. MutexClear();
  665. LogError(SU_HANDLE, EV_STATUS, this, 0, Status);
  666. return (Status);
  667. }
  668. }
  669. {
  670. const CLIENT_AUTH_INFO * AuthInfo = InquireAuthInformation();
  671. if ( AuthInfo &&
  672. AuthInfo->AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE &&
  673. AuthInfo->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC )
  674. {
  675. Status = ReAcquireCredentialsIfNecessary();
  676. if (Status != RPC_S_OK)
  677. {
  678. MutexClear();
  679. LogError(SU_HANDLE, EV_STATUS, this, 0, Status);
  680. return (Status);
  681. }
  682. }
  683. }
  684. // Here's the deal, Sparky:
  685. // association refcount = (# of binding handles with a pointer to it)
  686. // + (# of the association's connections in use)
  687. // connection refcount = (# of the connection's CCALLs in use)
  688. // binding refcount = (# of connections with a pointer to it)
  689. PDG_CCALL Call = 0;
  690. const CLIENT_AUTH_INFO * AuthInfo;
  691. if (Message->RpcFlags & RPC_NCA_FLAGS_MAYBE)
  692. {
  693. AuthInfo = 0;
  694. }
  695. else
  696. {
  697. AuthInfo = InquireAuthInformation();
  698. }
  699. Status = Association->AllocateCall( this, AuthInfo, &Call, (Message->RpcFlags & RPC_BUFFER_ASYNC) ? TRUE : FALSE );
  700. MutexClear();
  701. if (Status != RPC_S_OK)
  702. {
  703. LogError(SU_HANDLE, EV_STATUS, this, 0, Status);
  704. return Status;
  705. }
  706. return Call->GetInitialBuffer(Message, ObjectUuid);
  707. }
  708. BOOL
  709. DG_CASSOCIATION::SendKeepAlive()
  710. /*++
  711. Routine Description:
  712. This calls convc_indy() to tell the server to keep the association's
  713. context handles alive. The NT server code does not register the convc interface,
  714. since the mere fact of activity on a connection keeps the connection, and therefore
  715. the association group, alive.
  716. Return Value:
  717. TRUE if successful
  718. FALSE if not
  719. --*/
  720. {
  721. RPC_STATUS status = 0;
  722. LogEvent(SU_CASSOC, EV_ACK, this);
  723. if (!KeepAliveHandle)
  724. {
  725. MutexRequest();
  726. if (!KeepAliveHandle)
  727. {
  728. DCE_BINDING * NewDceBinding;
  729. NewDceBinding = pDceBinding->DuplicateDceBinding();
  730. if (!NewDceBinding)
  731. {
  732. MutexClear();
  733. return FALSE;
  734. }
  735. KeepAliveHandle = new DG_BINDING_HANDLE(this, NewDceBinding, &status);
  736. if (status)
  737. {
  738. delete KeepAliveHandle;
  739. delete NewDceBinding;
  740. MutexClear();
  741. return FALSE;
  742. }
  743. if (!KeepAliveHandle)
  744. {
  745. delete NewDceBinding;
  746. MutexClear();
  747. return FALSE;
  748. }
  749. IncrementBindingRefCount( FALSE );
  750. }
  751. MutexClear();
  752. }
  753. RpcTryExcept
  754. {
  755. _convc_indy( KeepAliveHandle, &ActiveAssociations->CasUuid );
  756. }
  757. RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) )
  758. {
  759. // don't care
  760. #ifdef DBG
  761. DbgPrint("RPC: exception 0x%x in context-handle keep-alive\n", RpcExceptionCode());
  762. #endif
  763. }
  764. RpcEndExcept;
  765. return TRUE;
  766. }
  767. PDG_CCONNECTION
  768. DG_CASSOCIATION::AllocateConnection(
  769. IN PDG_BINDING_HANDLE BindingHandle,
  770. IN const CLIENT_AUTH_INFO * AuthInfo,
  771. IN DWORD ThreadId,
  772. IN BOOL fAsync,
  773. OUT RPC_STATUS * pStatus
  774. )
  775. {
  776. if (!ThreadId)
  777. {
  778. ThreadId = GetCurrentThreadId();
  779. }
  780. boolean fStacking = FALSE;
  781. RPC_STATUS Status = RPC_S_OK;
  782. PDG_CCONNECTION Connection = 0;
  783. PDG_CCONNECTION BusyConnection;
  784. DictionaryCursor cursor;
  785. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 0 ), this, Connection );
  786. long StartTime = GetTickCount();
  787. retry:
  788. BusyConnection = 0;
  789. MutexRequest();
  790. //
  791. // Multiple async calls from the same thread should all use a single
  792. // connection unless the binding handle is marked "non-causal".
  793. // A synchronous call from the same thread should use a different
  794. // connection.
  795. //
  796. // A connection waiting to send a delayed ACK is still marked active,
  797. // but we want to reuse it anyway.
  798. //
  799. // The plan, therefore, is to search first for an active connection if
  800. // the call is async and causal, then search for a connection that is
  801. // inactive except for a delayed ack, then search for an idle connection.
  802. //
  803. if (fAsync)
  804. {
  805. ULONG_PTR fNonCausal;
  806. Status = BindingHandle->InqTransportOption(
  807. RPC_C_OPT_BINDING_NONCAUSAL,
  808. &fNonCausal);
  809. ASSERT(Status == RPC_S_OK);
  810. if (fNonCausal == 0)
  811. {
  812. fStacking = TRUE;
  813. }
  814. }
  815. //
  816. // Search for a connection handling this thread's async calls.
  817. //
  818. if (fStacking)
  819. {
  820. ActiveConnections.Reset(cursor);
  821. while (Connection = ActiveConnections.Next(cursor))
  822. {
  823. BusyConnection = Connection;
  824. if ( Connection->BindingHandle != BindingHandle ||
  825. Connection->ThreadId != ThreadId )
  826. {
  827. continue;
  828. }
  829. //
  830. // The app may have changed the security info since the other
  831. // calls were submitted.
  832. //
  833. if (FALSE == fLoneBindingHandle &&
  834. FALSE == Connection->IsSupportedAuthInfo(AuthInfo))
  835. {
  836. continue;
  837. }
  838. Connection->MutexRequest();
  839. if (Connection->fBusy)
  840. {
  841. // The connection is in a transitional state and is unavailable right now.
  842. // If this is a Unique binding handle, retry. Otherwise keep looking.
  843. //
  844. Connection->MutexClear();
  845. if (fLoneBindingHandle)
  846. {
  847. LogError(SU_CASSOC, EV_PROC, this, (void *) 4, 'R' + (('e' + (('t' + ('r' << 8)) << 8)) << 8));
  848. MutexClear();
  849. Sleep(1);
  850. goto retry;
  851. }
  852. continue;
  853. }
  854. if ( Connection->BindingHandle != BindingHandle ||
  855. Connection->ThreadId != ThreadId )
  856. {
  857. Connection->MutexClear();
  858. continue;
  859. }
  860. MutexClear();
  861. //
  862. // Add a reference for the new call to come.
  863. //
  864. Connection->IncrementRefCount();
  865. Connection->CancelDelayedAck();
  866. return Connection;
  867. }
  868. }
  869. //
  870. // Search for a connection that is waiting on a delayed ack.
  871. //
  872. ActiveConnections.Reset(cursor);
  873. while (Connection = ActiveConnections.Next(cursor))
  874. {
  875. BusyConnection = Connection;
  876. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 1 ), this, Connection );
  877. if (!Connection->AckPending)
  878. {
  879. continue;
  880. }
  881. if (FALSE == fLoneBindingHandle &&
  882. FALSE == Connection->IsSupportedAuthInfo(AuthInfo))
  883. {
  884. continue;
  885. }
  886. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 2 ), this, Connection );
  887. Connection->MutexRequest();
  888. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 3 ), this, Connection );
  889. if (Connection->fBusy)
  890. {
  891. // The connection is in a transitional state and is unavailable right now.
  892. // If this is a Unique binding handle, retry. Otherwise keep looking.
  893. //
  894. Connection->MutexClear();
  895. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 4 ), this, Connection );
  896. if (fLoneBindingHandle)
  897. {
  898. LogError(SU_CASSOC, EV_PROC, this, (void *) 5, 'R' + (('e' + (('t' + ('r' << 8)) << 8)) << 8));
  899. MutexClear();
  900. Sleep(1);
  901. goto retry;
  902. }
  903. continue;
  904. }
  905. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 5 ), this, Connection );
  906. if (!Connection->AckPending)
  907. {
  908. Connection->MutexClear();
  909. continue;
  910. }
  911. DG_BINDING_HANDLE * OldHandle = Connection->BindingHandle;
  912. Connection->BindingHandle = BindingHandle;
  913. Connection->ThreadId = ThreadId;
  914. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 6 ), this, Connection );
  915. #ifdef DBG
  916. //
  917. // debugging code for clustering
  918. //
  919. if (fLoneBindingHandle)
  920. {
  921. DG_CCONNECTION * SecondConnection = 0;
  922. //
  923. // See if a valid inactive connection exists, This could cause trouble, too.
  924. //
  925. InactiveConnections.Reset(cursor);
  926. SecondConnection = InactiveConnections.Next(cursor);
  927. if (SecondConnection &&
  928. SecondConnection->fError == FALSE)
  929. {
  930. DbgPrint("RPC: failure of unique-handle semantics (2)\n");
  931. DbgBreakPoint();
  932. }
  933. }
  934. #endif
  935. MutexClear();
  936. //
  937. // Add a reference for the call to come. This prevents the conn from
  938. // accidentally being moved to the inactive list.
  939. //
  940. Connection->IncrementRefCount();
  941. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 7 ), this, Connection );
  942. //
  943. // Must cancel the delayed ACK before releasing the mutex, so other threads
  944. // can't pick it up like this thread did.
  945. //
  946. Connection->CancelDelayedAck();
  947. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_CONN, 8 ), this, Connection );
  948. if (OldHandle != Connection->BindingHandle)
  949. {
  950. Connection->MutexClear();
  951. BindingHandle->IncrementRefCount();
  952. OldHandle->DecrementRefCount();
  953. Connection->MutexRequest();
  954. }
  955. return Connection;
  956. }
  957. //
  958. // Search for an idle connection with matching security info.
  959. //
  960. InactiveConnections.Reset(cursor);
  961. while (0 != (Connection = InactiveConnections.Next(cursor)))
  962. {
  963. BusyConnection = Connection;
  964. if (Connection->fError)
  965. {
  966. continue;
  967. }
  968. if (fLoneBindingHandle ||
  969. Connection->IsSupportedAuthInfo(AuthInfo))
  970. {
  971. LogEvent(SU_CCONN, EV_START, Connection, this);
  972. ASSERT( FALSE == Connection->fAutoReconnect );
  973. ASSERT( FALSE == Connection->fError );
  974. InactiveConnections.Delete(Connection->AssociationKey);
  975. Connection->AssociationKey = ActiveConnections.Insert(Connection);
  976. if (-1 == Connection->AssociationKey)
  977. {
  978. MutexClear();
  979. *pStatus = RPC_S_OUT_OF_MEMORY;
  980. delete Connection;
  981. return 0;
  982. }
  983. IncrementRefCount();
  984. ASSERT( FALSE == Connection->fBusy );
  985. Connection->MutexRequest();
  986. Connection->BindingHandle = BindingHandle;
  987. Connection->ThreadId = ThreadId;
  988. ClientConnections->Add(Connection);
  989. MutexClear();
  990. BindingHandle->IncrementRefCount();
  991. //
  992. // Add a reference for the call to come.
  993. //
  994. Connection->IncrementRefCount();
  995. return Connection;
  996. }
  997. }
  998. //
  999. // Unique handles have special semantics.
  1000. //
  1001. if (fLoneBindingHandle && BusyConnection)
  1002. {
  1003. if (BindingHandle == KeepAliveHandle)
  1004. {
  1005. LogEvent(SU_CASSOC, EV_PROC, this, (void *) 1, 'R' + (('e' + (('t' + ('r' << 8)) << 8)) << 8));
  1006. //
  1007. // Keep-alive was begun just as the app thread began using the handle.
  1008. // Don't bother executing the keep-alive.
  1009. //
  1010. MutexClear();
  1011. *pStatus = RPC_S_CALL_IN_PROGRESS;
  1012. return 0;
  1013. }
  1014. ASSERT( BusyConnection->BindingHandle );
  1015. if (BusyConnection->BindingHandle == KeepAliveHandle)
  1016. {
  1017. LogEvent(SU_CASSOC, EV_PROC, this, (void *) 2, 'R' + (('e' + (('t' + ('r' << 8)) << 8)) << 8));
  1018. #if 0
  1019. if (GetTickCount() - StartTime > 10*1000)
  1020. {
  1021. DbgPrint("RPC: keep-alive tied up a connection for > 10 seconds\n");
  1022. DbgBreakPoint();
  1023. }
  1024. #endif
  1025. //
  1026. // App thread began a call just as the keep-alive thread was finishing one.
  1027. // Wait for the keep-alive to finish.
  1028. //
  1029. MutexClear();
  1030. Sleep(1);
  1031. goto retry;
  1032. }
  1033. //
  1034. // Two app threads contending, or the current connection is closing.
  1035. //
  1036. if (BusyConnection->fBusy)
  1037. {
  1038. LogError(SU_CASSOC, EV_PROC, this, (void *) 6, 'R' + (('e' + (('t' + ('r' << 8)) << 8)) << 8));
  1039. MutexClear();
  1040. Sleep(1);
  1041. goto retry;
  1042. }
  1043. //
  1044. // Create a new connection.
  1045. //
  1046. LogEvent(SU_CASSOC, EV_PROC, this, (void *) 3, 'R' + (('e' + (('t' + ('r' << 8)) << 8)) << 8));
  1047. #ifdef DBG
  1048. //
  1049. // If it's in use, it should be doing something.
  1050. //
  1051. if ( FALSE == BusyConnection->fError &&
  1052. BusyConnection->TimeStamp != 0 &&
  1053. (GetTickCount() - BusyConnection->TimeStamp) > 60000)
  1054. {
  1055. DbgPrint("RPC: failure of unique-handle semantics (3)\n");
  1056. DbgBreakPoint();
  1057. }
  1058. #endif
  1059. }
  1060. //
  1061. // Create a new connection and add it to the active conn list.
  1062. // Increment the refcount here to avoid having the assoc deleted
  1063. // while we are tied up.
  1064. //
  1065. IncrementRefCount();
  1066. MutexClear();
  1067. Connection = new (TransportInterface) DG_CCONNECTION(this, AuthInfo, &Status);
  1068. if (!Connection)
  1069. {
  1070. Status = RPC_S_OUT_OF_MEMORY;
  1071. }
  1072. if (Status != RPC_S_OK)
  1073. {
  1074. DecrementRefCount();
  1075. delete Connection;
  1076. *pStatus = Status;
  1077. return 0;
  1078. }
  1079. Connection->BindingHandle = BindingHandle;
  1080. Connection->ThreadId = ThreadId;
  1081. MutexRequest();
  1082. Connection->MutexRequest();
  1083. LogEvent(SU_CCONN, EV_START, Connection, this);
  1084. Connection->AssociationKey = ActiveConnections.Insert(Connection);
  1085. MutexClear();
  1086. if (-1 == Connection->AssociationKey)
  1087. {
  1088. DecrementRefCount();
  1089. // don't have to release the connection mutex because we are deleting it
  1090. delete Connection;
  1091. *pStatus = RPC_S_OUT_OF_MEMORY;
  1092. return 0;
  1093. }
  1094. BindingHandle->IncrementRefCount();
  1095. ClientConnections->Add(Connection);
  1096. //
  1097. // Add a reference for the call in progress.
  1098. //
  1099. Connection->IncrementRefCount();
  1100. return Connection;
  1101. }
  1102. RPC_STATUS
  1103. DG_CASSOCIATION::AllocateCall(
  1104. IN PDG_BINDING_HANDLE BindingHandle,
  1105. IN const CLIENT_AUTH_INFO * AuthInfo,
  1106. OUT PDG_CCALL * ppCall,
  1107. IN BOOL fAsync
  1108. )
  1109. {
  1110. RPC_STATUS Status = 0;
  1111. PDG_CCONNECTION Connection;
  1112. Connection = AllocateConnection(BindingHandle, AuthInfo, 0, fAsync, &Status);
  1113. if (!Connection)
  1114. {
  1115. return Status;
  1116. }
  1117. *ppCall = Connection->AllocateCall();
  1118. if (!*ppCall)
  1119. {
  1120. return RPC_S_OUT_OF_MEMORY;
  1121. }
  1122. return RPC_S_OK;
  1123. }
  1124. void
  1125. DG_CASSOCIATION::ReleaseConnection(
  1126. IN PDG_CCONNECTION Connection
  1127. )
  1128. {
  1129. DG_BINDING_HANDLE * MyHandle;
  1130. LogEvent(SU_CCONN, EV_STOP, Connection, this);
  1131. ClientConnections->Remove(Connection);
  1132. int Key;
  1133. MutexRequest();
  1134. ActiveConnections.Delete(Connection->AssociationKey);
  1135. Connection->AssociationKey = InactiveConnections.Insert(Connection);
  1136. Key = Connection->AssociationKey;
  1137. Connection->WaitForNoReferences();
  1138. MyHandle = Connection->BindingHandle;
  1139. Connection->BindingHandle = 0;
  1140. MutexClear();
  1141. if (MyHandle)
  1142. {
  1143. MyHandle->DecrementRefCount();
  1144. }
  1145. if (-1 == Key)
  1146. {
  1147. Connection->CancelDelayedAck();
  1148. delete Connection;
  1149. }
  1150. DecrementRefCount();
  1151. }
  1152. DG_CCALL *
  1153. DG_CCONNECTION::AllocateCall()
  1154. /*++
  1155. Description:
  1156. Provides a DG_CCALL to use. The connection mutex is cleared on exit.
  1157. --*/
  1158. {
  1159. DG_CCALL * Call = 0;
  1160. RPC_STATUS Status = RPC_S_OK;
  1161. Mutex.VerifyOwned();
  1162. ASSERT( !AckPending );
  1163. ASSERT( ReferenceCount );
  1164. if (CachedCalls)
  1165. {
  1166. Call = CachedCalls;
  1167. CachedCalls = CachedCalls->Next;
  1168. MutexClear();
  1169. }
  1170. else
  1171. {
  1172. MutexClear();
  1173. Call = new DG_CCALL(this, &Status);
  1174. if (!Call)
  1175. {
  1176. Status = RPC_S_OUT_OF_MEMORY;
  1177. }
  1178. if (Status != RPC_S_OK)
  1179. {
  1180. delete Call;
  1181. MutexRequest();
  1182. DecrementRefCount();
  1183. return 0;
  1184. }
  1185. }
  1186. Call->IncrementRefCount();
  1187. Call->Cancelled = FALSE;
  1188. Call->CancelPending = FALSE;
  1189. LogEvent(SU_CCALL, EV_START, Call, this);
  1190. return Call;
  1191. }
  1192. RPC_STATUS
  1193. DG_BINDING_HANDLE::BindingFree (
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. Implements RpcBindingFree for dg binding handles.
  1198. Arguments:
  1199. <none>
  1200. Return Value:
  1201. RPC_S_OK
  1202. --*/
  1203. {
  1204. LogEvent( SU_HANDLE, EV_PROC, this, 0, 'F' + (('r' + (('e' + ('e' << 8)) << 8)) << 8), TRUE);
  1205. if (!ThreadSelf())
  1206. {
  1207. return RPC_S_OUT_OF_MEMORY;
  1208. }
  1209. // Flush the delayed ack on any connection using this handle.
  1210. //
  1211. if (Association)
  1212. {
  1213. PDG_CASSOCIATION TempAssociation;
  1214. MutexRequest();
  1215. TempAssociation = Association;
  1216. Association = 0;
  1217. MutexClear();
  1218. if (TempAssociation != 0)
  1219. {
  1220. TempAssociation->DecrementBindingRefCount(fContextHandle);
  1221. }
  1222. }
  1223. //
  1224. // Decrement the ref count. If the count has hit zero, this call will
  1225. // delete this.
  1226. //
  1227. DecrementRefCount();
  1228. return RPC_S_OK;
  1229. }
  1230. RPC_STATUS
  1231. DG_BINDING_HANDLE::PrepareBindingHandle (
  1232. IN TRANS_INFO * a_TransportInterface,
  1233. IN DCE_BINDING * DceBinding
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. Serves as an auxiliary constructor for DG_BINDING_HANDLE. This is called
  1238. to initialize stuff after the DG_BINDING_HANDLE has been constructed.
  1239. Arguments:
  1240. TransportInterface - pointer to the DG_CLIENT_TRANSPORT object that this
  1241. DG_BINDING_HANDLE is active on.
  1242. DceBinding - Pointer to the DCE_BINDING that we are associated with.
  1243. Return Value:
  1244. none
  1245. --*/
  1246. {
  1247. ASSERT(pDceBinding == 0);
  1248. Association = 0;
  1249. pDceBinding = DceBinding;
  1250. TransportObject = a_TransportInterface;
  1251. TransportInterface = (RPC_DATAGRAM_TRANSPORT *) a_TransportInterface->InqTransInfo();
  1252. RPC_CHAR * Endpoint = pDceBinding->InqEndpoint();
  1253. if (!Endpoint || Endpoint[0] == 0)
  1254. {
  1255. fDynamicEndpoint = TRUE;
  1256. }
  1257. else
  1258. {
  1259. fDynamicEndpoint = FALSE;
  1260. }
  1261. return RPC_S_OK;
  1262. }
  1263. RPC_STATUS
  1264. DG_BINDING_HANDLE::ToStringBinding (
  1265. OUT RPC_CHAR __RPC_FAR * __RPC_FAR * StringBinding
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. We need to convert the binding handle into a string binding.
  1270. Arguments:
  1271. StringBinding - Returns the string representation of the binding
  1272. handle.
  1273. Return Value:
  1274. RPC_S_OK
  1275. RPC_S_OUT_OF_MEMORY
  1276. <return from DG_CASSOCIATION::ToStringBinding>
  1277. --*/
  1278. {
  1279. CLAIM_MUTEX Lock( BindingMutex );
  1280. if (Association == 0)
  1281. {
  1282. *StringBinding = pDceBinding->StringBindingCompose(
  1283. InqPointerAtObjectUuid()
  1284. );
  1285. if (*StringBinding == 0)
  1286. {
  1287. return RPC_S_OUT_OF_MEMORY;
  1288. }
  1289. return RPC_S_OK;
  1290. }
  1291. else
  1292. {
  1293. return Association->ToStringBinding(
  1294. StringBinding,
  1295. InqPointerAtObjectUuid()
  1296. );
  1297. }
  1298. }
  1299. RPC_STATUS
  1300. DG_BINDING_HANDLE::ResolveBinding (
  1301. IN RPC_CLIENT_INTERFACE __RPC_FAR * RpcClientInterface
  1302. )
  1303. /*++
  1304. Routine Description:
  1305. Resolve this binding.
  1306. Arguments:
  1307. RpcClientInterface - Interface info used to resolve the endpoint.
  1308. Return Value:
  1309. RPC_S_OK
  1310. <return from DCE_BINDING::ResolveEndpointIfNecessary>
  1311. --*/
  1312. {
  1313. CLAIM_MUTEX Lock( BindingMutex );
  1314. LogEvent( SU_HANDLE, EV_RESOLVED, this, Association );
  1315. if ( Association == 0 )
  1316. {
  1317. RPC_STATUS Status;
  1318. Status = pDceBinding->ResolveEndpointIfNecessary(
  1319. RpcClientInterface,
  1320. InqPointerAtObjectUuid(),
  1321. InquireEpLookupHandle(),
  1322. FALSE,
  1323. InqComTimeout(),
  1324. INFINITE, // CallTimeout
  1325. NULL // AuthInfo
  1326. );
  1327. if (Status)
  1328. {
  1329. LogError( SU_HANDLE, EV_STATUS, this, 0, Status );
  1330. }
  1331. return Status;
  1332. }
  1333. return RPC_S_OK;
  1334. }
  1335. RPC_STATUS
  1336. DG_BINDING_HANDLE::BindingReset (
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. Reset this binding to a 'zero' value.
  1341. Arguments:
  1342. <none>
  1343. Return Value:
  1344. RPC_S_OK;
  1345. --*/
  1346. {
  1347. LogEvent( SU_HANDLE, EV_PROC, this, 0, 'R' + (('e' + (('s' + ('e' << 8)) << 8)) << 8), TRUE);
  1348. MutexRequest();
  1349. DisassociateFromServer();
  1350. pDceBinding->MakePartiallyBound();
  1351. if (0 != *InquireEpLookupHandle())
  1352. {
  1353. EpFreeLookupHandle(*InquireEpLookupHandle());
  1354. *InquireEpLookupHandle() = 0;
  1355. }
  1356. MutexClear();
  1357. return RPC_S_OK;
  1358. }
  1359. RPC_STATUS
  1360. DG_BINDING_HANDLE::BindingCopy (
  1361. OUT BINDING_HANDLE * __RPC_FAR * DestinationBinding,
  1362. IN unsigned int MaintainContext
  1363. )
  1364. /*++
  1365. Routine Description:
  1366. Creates a copy of this binding handle.
  1367. Arguments:
  1368. DestinationBinding - Where to place a pointer to the new binding.
  1369. Return Value:
  1370. RPC_S_OK
  1371. --*/
  1372. {
  1373. RPC_STATUS Status = RPC_S_OK;
  1374. PDG_BINDING_HANDLE Binding;
  1375. DCE_BINDING * NewDceBinding = 0;
  1376. *DestinationBinding = 0;
  1377. Binding = new DG_BINDING_HANDLE(&Status);
  1378. if ( Binding == 0 || Status != RPC_S_OK)
  1379. {
  1380. return RPC_S_OUT_OF_MEMORY;
  1381. }
  1382. MutexRequest();
  1383. //
  1384. // If the binding refers to a dynamic endpoint or is used for broadcast calls,
  1385. // then the association may have a more up-to-date DCE_BINDING.
  1386. //
  1387. if (Association)
  1388. {
  1389. NewDceBinding = Association->DuplicateDceBinding();
  1390. }
  1391. else
  1392. {
  1393. NewDceBinding = pDceBinding->DuplicateDceBinding();
  1394. }
  1395. if (!NewDceBinding)
  1396. {
  1397. MutexClear();
  1398. delete Binding;
  1399. return RPC_S_OUT_OF_MEMORY;
  1400. }
  1401. //
  1402. // Clone calls MapAuthLevel which depends on these items, so copy them first.
  1403. //
  1404. Binding->TransportObject = TransportObject;
  1405. Binding->TransportInterface = TransportInterface;
  1406. Binding->pDceBinding = NewDceBinding;
  1407. Binding->fDynamicEndpoint = fDynamicEndpoint;
  1408. Binding->fContextHandle = MaintainContext;
  1409. Status = Binding->BINDING_HANDLE::Clone( this );
  1410. if (Status != RPC_S_OK)
  1411. {
  1412. MutexClear();
  1413. delete Binding;
  1414. Binding = 0;
  1415. return Status;
  1416. }
  1417. //
  1418. // If we clone a binding handle with the UNIQUE option set, we want
  1419. // to use a separate association.
  1420. //
  1421. if (Association && !Association->fLoneBindingHandle)
  1422. {
  1423. Binding->Association = Association;
  1424. Binding->Association->IncrementBindingRefCount( MaintainContext );
  1425. }
  1426. else
  1427. {
  1428. Binding->Association = 0;
  1429. }
  1430. MutexClear();
  1431. *DestinationBinding = (BINDING_HANDLE *) Binding;
  1432. if (MaintainContext)
  1433. {
  1434. //
  1435. // We've created a context handle; ensure the keep-alive proc is active.
  1436. //
  1437. DelayedProcedures->Add(ContextHandleTimer, CXT_HANDLE_SWEEP_INTERVAL, FALSE);
  1438. }
  1439. return RPC_S_OK;
  1440. }
  1441. PDG_CCONNECTION
  1442. DG_BINDING_HANDLE::GetReplacementConnection(
  1443. PDG_CCONNECTION OldConnection,
  1444. PRPC_CLIENT_INTERFACE Interface
  1445. )
  1446. {
  1447. BOOL fBroadcast = FALSE;
  1448. CLAIM_MUTEX Lock( BindingMutex );
  1449. if (OldConnection->CurrentCall->IsBroadcast())
  1450. {
  1451. fBroadcast = TRUE;
  1452. }
  1453. if (OldConnection->Association == Association)
  1454. {
  1455. BOOL Dynamic = fDynamicEndpoint;
  1456. Association->SetErrorFlag();
  1457. //
  1458. // If the binding handle has no object ID, releasing the current
  1459. // endpoint would mean all mgmt calls on the new connection would fail.
  1460. //
  1461. if (IsMgmtIfUuid(&Interface->InterfaceId.SyntaxGUID))
  1462. {
  1463. fDynamicEndpoint = FALSE;
  1464. }
  1465. DisassociateFromServer();
  1466. fDynamicEndpoint = (boolean) Dynamic;
  1467. }
  1468. if (!Association && RPC_S_OK != FindOrCreateAssociation(Interface, TRUE, fBroadcast))
  1469. {
  1470. return 0;
  1471. }
  1472. RPC_STATUS Status;
  1473. return Association->AllocateConnection(this,
  1474. OldConnection->InqAuthInfo(),
  1475. OldConnection->ThreadId,
  1476. OldConnection->CurrentCall->pAsync ? TRUE : FALSE,
  1477. &Status
  1478. );
  1479. }
  1480. void
  1481. DG_BINDING_HANDLE::DisassociateFromServer()
  1482. {
  1483. PDG_CASSOCIATION TempAssociation;
  1484. LogEvent(SU_HANDLE, EV_DISASSOC, this, Association, 0, TRUE);
  1485. MutexRequest();
  1486. TempAssociation = Association;
  1487. Association = 0;
  1488. //
  1489. // This frees memory while holding the mutex - not ideal..
  1490. // One could modify DCE_BINDING::MakePartiallyBound to return the old
  1491. // endpoint so we can delete it outside the mutex.
  1492. //
  1493. if (fDynamicEndpoint)
  1494. {
  1495. pDceBinding->MakePartiallyBound();
  1496. }
  1497. MutexClear();
  1498. if (TempAssociation != 0)
  1499. {
  1500. TempAssociation->DecrementBindingRefCount(fContextHandle);
  1501. }
  1502. }
  1503. unsigned long
  1504. DG_BINDING_HANDLE::MapAuthenticationLevel (
  1505. IN unsigned long AuthenticationLevel
  1506. )
  1507. {
  1508. if (AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT ||
  1509. AuthenticationLevel == RPC_C_AUTHN_LEVEL_CALL )
  1510. {
  1511. return(RPC_C_AUTHN_LEVEL_PKT);
  1512. }
  1513. // This is an additional mapping for the reliable DG protocols
  1514. // (i.e. Falcon/RPC). This protocols only use the following
  1515. // three levels: RPC_C_AUTHN_LEVEL_NONE 1
  1516. // RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
  1517. // RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
  1518. if (TransportInterface->IsMessageTransport)
  1519. {
  1520. if (AuthenticationLevel == RPC_C_AUTHN_LEVEL_DEFAULT)
  1521. {
  1522. return RPC_C_AUTHN_LEVEL_NONE;
  1523. }
  1524. if ( (AuthenticationLevel > RPC_C_AUTHN_LEVEL_NONE)
  1525. && (AuthenticationLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY) )
  1526. {
  1527. return RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
  1528. }
  1529. }
  1530. return(AuthenticationLevel);
  1531. }
  1532. BOOL
  1533. DG_BINDING_HANDLE::SetTransportAuthentication(
  1534. IN unsigned long ulAuthenticationLevel,
  1535. IN unsigned long ulAuthenticationService,
  1536. OUT RPC_STATUS *pStatus )
  1537. // Routine Description:
  1538. //
  1539. // Do transport specific security for one of the datagram transports.
  1540. // This is currently only for the Falcon transport.
  1541. //
  1542. // Return Values:
  1543. //
  1544. // TRUE -- Continue with the RPC level authenticaion.
  1545. //
  1546. // FALSE -- This setting is just for the transport, so don't continue
  1547. // setting RPC level authenticaion.
  1548. //
  1549. {
  1550. BOOL fContinue;
  1551. if (RPC_C_AUTHN_NONE == ulAuthenticationService)
  1552. {
  1553. // RPC_C_AUTHN_NONE is a special case that is applied to both RPC and transport
  1554. // authentication.
  1555. *pStatus = SetTransportOption(RPC_C_OPT_MQ_AUTHN_SERVICE,ulAuthenticationService);
  1556. fContinue = TRUE;
  1557. }
  1558. else
  1559. {
  1560. *pStatus = SetTransportOption(RPC_C_OPT_MQ_AUTHN_SERVICE,ulAuthenticationService);
  1561. if (RPC_S_OK == *pStatus)
  1562. {
  1563. *pStatus = SetTransportOption(RPC_C_OPT_MQ_AUTHN_LEVEL,ulAuthenticationLevel);
  1564. fContinue = FALSE;
  1565. }
  1566. else
  1567. {
  1568. *pStatus = RPC_S_CANNOT_SUPPORT;
  1569. fContinue = TRUE;
  1570. }
  1571. }
  1572. return fContinue;
  1573. }
  1574. DG_CASSOCIATION::DG_CASSOCIATION(
  1575. IN RPC_DATAGRAM_TRANSPORT * a_Transport,
  1576. IN LONG a_AssociationFlag,
  1577. IN DCE_BINDING * a_DceBinding,
  1578. IN BOOL a_Unique,
  1579. IN OUT RPC_STATUS * pStatus
  1580. ) :
  1581. Mutex ( pStatus ),
  1582. TransportInterface ( a_Transport ),
  1583. AssociationFlag ( a_AssociationFlag ),
  1584. pDceBinding ( a_DceBinding ),
  1585. CurrentPduSize ( a_Transport->BasePduSize ),
  1586. fLoneBindingHandle ( (boolean) a_Unique ),
  1587. RemoteWindowSize ( 1 ),
  1588. ServerAddress ( 0 ),
  1589. ServerBootTime ( 0 ),
  1590. ReferenceCount ( 0 ),
  1591. BindingHandleReferences( 0 ),
  1592. InternalTableIndex ( -1 ),
  1593. KeepAliveHandle ( 0 ),
  1594. fServerSupportsAsync(FALSE),
  1595. fErrorFlag (FALSE)
  1596. /*++
  1597. Remarks:
  1598. Notice that the object is initialized so that the destructor can be called
  1599. even if the constructor bails out early.
  1600. Arguments:
  1601. pDceBinding - DCE_BINDING that we are associated with
  1602. pStatus - where failure codes go; should be RPC_S_OK on entry
  1603. --*/
  1604. {
  1605. ObjectType = DG_CASSOCIATION_TYPE;
  1606. LogEvent(SU_CASSOC, EV_CREATE, this, 0, *pStatus);
  1607. ResolvedEndpoint = NULL;
  1608. if (*pStatus != RPC_S_OK)
  1609. {
  1610. LogError(SU_CASSOC, EV_CREATE, this, 0, *pStatus);
  1611. return;
  1612. }
  1613. ServerAddress = this + 1;
  1614. ResolvedEndpoint = new RPC_CHAR[1+TransportInterface->EndpointStringSize];
  1615. if (!ResolvedEndpoint)
  1616. {
  1617. *pStatus = RPC_S_OUT_OF_MEMORY;
  1618. return;
  1619. }
  1620. *pStatus = TransportInterface->InitializeAddress(ServerAddress,
  1621. pDceBinding->InqNetworkAddress(),
  1622. pDceBinding->InqEndpoint(),
  1623. TRUE, // use cache
  1624. ( a_AssociationFlag & BROADCAST) ? TRUE : FALSE
  1625. );
  1626. if (*pStatus == RPC_P_FOUND_IN_CACHE)
  1627. {
  1628. *pStatus = RPC_S_OK;
  1629. }
  1630. if (*pStatus)
  1631. {
  1632. return;
  1633. }
  1634. LogEvent(SU_CASSOC, EV_START, this);
  1635. *pStatus = ActiveAssociations->Add( this );
  1636. if (*pStatus)
  1637. {
  1638. LogError(SU_CASSOC, EV_START, this, 0, *pStatus);
  1639. return;
  1640. }
  1641. //
  1642. // If this was created by a UNIQUE binding handle, we want connection keep-alives
  1643. // even though no context handles point to it. This will keep our connection
  1644. // alive on the server.
  1645. //
  1646. IncrementBindingRefCount( fLoneBindingHandle );
  1647. if (fLoneBindingHandle)
  1648. {
  1649. DelayedProcedures->Add(ContextHandleTimer, CXT_HANDLE_SWEEP_INTERVAL, FALSE);
  1650. }
  1651. LastReceiveTime = GetTickCount();
  1652. }
  1653. DG_CASSOCIATION::~DG_CASSOCIATION()
  1654. /*++
  1655. Routine Description:
  1656. Destructor for a DG_CASSOCIATION. This will free up the cached DG_CCALL
  1657. and deregister us from the transport.
  1658. Arguments:
  1659. <none>
  1660. Return Value:
  1661. <none>
  1662. --*/
  1663. {
  1664. LogEvent(SU_CASSOC, EV_DELETE, this);
  1665. ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) );
  1666. PDG_CCONNECTION Connection;
  1667. DictionaryCursor cursor;
  1668. //
  1669. // Delete all calls for this association..
  1670. //
  1671. InactiveConnections.Reset(cursor);
  1672. while ( (Connection = InactiveConnections.Next(cursor)) != 0 )
  1673. {
  1674. InactiveConnections.Delete(Connection->AssociationKey);
  1675. Connection->CancelDelayedAck();
  1676. delete Connection;
  1677. }
  1678. delete pDceBinding;
  1679. delete ResolvedEndpoint;
  1680. delete KeepAliveHandle;
  1681. #if 0
  1682. char * FirstAddress;
  1683. char * SecondAddress;
  1684. FirstAddress = (char *) (this + 1);
  1685. SecondAddress = FirstAddress + TransportInterface->AddressSize;
  1686. ASSERT( ServerAddress == FirstAddress || ServerAddress == SecondAddress );
  1687. TransportInterface->CloseAddress( FirstAddress );
  1688. if (ServerAddress == SecondAddress)
  1689. {
  1690. TransportInterface->CloseAddress( SecondAddress );
  1691. }
  1692. #endif
  1693. }
  1694. RPC_STATUS
  1695. DG_CASSOCIATION::ToStringBinding (
  1696. OUT RPC_CHAR * * StringBinding,
  1697. IN RPC_UUID * ObjectUuid
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. We need to convert the binding handle into a string binding.
  1702. Arguments:
  1703. StringBinding - Returns the string representation of the binding
  1704. handle.
  1705. ObjectUuid - Supplies the object uuid of the binding handle which
  1706. is requesting that we create a string binding.
  1707. Return Value:
  1708. RPC_S_OK
  1709. RPC_S_OUT_OF_MEMORY
  1710. --*/
  1711. {
  1712. CLAIM_MUTEX Lock(Mutex);
  1713. *StringBinding = pDceBinding->StringBindingCompose(ObjectUuid);
  1714. if (*StringBinding == 0)
  1715. {
  1716. return RPC_S_OUT_OF_MEMORY;
  1717. }
  1718. return RPC_S_OK;
  1719. }
  1720. BOOL
  1721. OptionalStringsEqual(
  1722. RPC_CHAR * String1,
  1723. RPC_CHAR * String2
  1724. )
  1725. /*++
  1726. Routine Description:
  1727. Compares two strings, checking for NULL pointers.
  1728. Arguments:
  1729. the strings
  1730. Return Value:
  1731. TRUE if they are equal
  1732. FALSE if they differ
  1733. --*/
  1734. {
  1735. if (String1 == String2)
  1736. {
  1737. return TRUE;
  1738. }
  1739. if (!String1 || !String2)
  1740. {
  1741. return FALSE;
  1742. }
  1743. if (0 == RpcpStringCompare(String1, String2))
  1744. {
  1745. return TRUE;
  1746. }
  1747. return FALSE;
  1748. }
  1749. BOOL
  1750. DG_CASSOCIATION::ComparePartialBinding(
  1751. PDG_BINDING_HANDLE Binding,
  1752. void * InterfaceInformation
  1753. )
  1754. /*++
  1755. Routine Description:
  1756. Checks compatibility between the association and a partially-bound handle.
  1757. Arguments:
  1758. Binding - the binding handle
  1759. InterfaceInformation - a pointer to the RPC_INTERFACE to be used
  1760. Return Value:
  1761. TRUE if the association is compatible
  1762. FALSE if not
  1763. --*/
  1764. {
  1765. RPC_CHAR * String1;
  1766. RPC_CHAR * String2;
  1767. CLAIM_MUTEX lock( Mutex );
  1768. if (FALSE == OptionalStringsEqual(
  1769. pDceBinding->InqRpcProtocolSequence(),
  1770. Binding->pDceBinding->InqRpcProtocolSequence()
  1771. ))
  1772. {
  1773. return FALSE;
  1774. }
  1775. if (FALSE == OptionalStringsEqual(
  1776. pDceBinding->InqNetworkAddress(),
  1777. Binding->pDceBinding->InqNetworkAddress()
  1778. ))
  1779. {
  1780. return FALSE;
  1781. }
  1782. if (FALSE == OptionalStringsEqual(
  1783. pDceBinding->InqNetworkOptions(),
  1784. Binding->pDceBinding->InqNetworkOptions()
  1785. ))
  1786. {
  1787. return FALSE;
  1788. }
  1789. RPC_UUID Object;
  1790. Binding->InquireObjectUuid(&Object);
  1791. return InterfaceAndObjectDict.Find(InterfaceInformation, &Object);
  1792. }
  1793. BOOL
  1794. DG_CASSOCIATION::AddInterface(
  1795. void * InterfaceInformation,
  1796. RPC_UUID * ObjectUuid
  1797. )
  1798. /*++
  1799. Routine Description:
  1800. Declares that this association supports the given <interface, object uuid>
  1801. pair.
  1802. Arguments:
  1803. InterfaceInformation - a pointer to the RPC_INTERFACE
  1804. ObjectUuid - the object UUID
  1805. Return Value:
  1806. TRUE if the pair was added to the dictionary
  1807. FALSE if an error occurred
  1808. --*/
  1809. {
  1810. CLAIM_MUTEX Lock(Mutex);
  1811. return InterfaceAndObjectDict.Insert(InterfaceInformation, ObjectUuid);
  1812. }
  1813. BOOL
  1814. DG_CASSOCIATION::RemoveInterface(
  1815. void * InterfaceInformation,
  1816. RPC_UUID * ObjectUuid
  1817. )
  1818. /*++
  1819. Routine Description:
  1820. Declares that this association no longer supports the given
  1821. <interface, object uuid> pair.
  1822. Arguments:
  1823. InterfaceInformation - a pointer to the RPC_INTERFACE
  1824. ObjectUuid - the object UUID
  1825. Return Value:
  1826. TRUE if the pair was in the dictionary
  1827. FALSE if not
  1828. --*/
  1829. {
  1830. CLAIM_MUTEX Lock(Mutex);
  1831. return InterfaceAndObjectDict.Delete(InterfaceInformation, ObjectUuid);
  1832. }
  1833. DG_CCONNECTION::DG_CCONNECTION(
  1834. IN PDG_CASSOCIATION a_Association,
  1835. IN const CLIENT_AUTH_INFO * a_AuthInfo,
  1836. IN OUT RPC_STATUS * pStatus
  1837. ) :
  1838. DG_COMMON_CONNECTION (a_Association->TransportInterface, pStatus),
  1839. Association (a_Association),
  1840. AuthInfo (a_AuthInfo, pStatus),
  1841. AssociationKey (-1),
  1842. TimeStamp (0),
  1843. SecurityContextId (0),
  1844. BindingHandle (0),
  1845. ThreadId (0),
  1846. CachedCalls (0),
  1847. ActiveCallHead (0),
  1848. ActiveCallTail (0),
  1849. CurrentCall (0),
  1850. AckPending (0),
  1851. AckOrphaned (FALSE),
  1852. SecurityBuffer (0),
  1853. SecurityBufferLength (0),
  1854. ServerResponded (FALSE),
  1855. CallbackCompleted (FALSE),
  1856. fServerSupportsAsync (a_Association->fServerSupportsAsync),
  1857. fSecurePacketReceived (FALSE),
  1858. InConnectionTable (FALSE),
  1859. fBusy (FALSE),
  1860. PossiblyRunDown (FALSE),
  1861. fAutoReconnect (FALSE),
  1862. fError (FALSE),
  1863. DelayedAckTimer (DelayedAckFn, 0)
  1864. {
  1865. ObjectType = DG_CCONNECTION_TYPE;
  1866. LogEvent(SU_CCONN, EV_CREATE, this, a_Association, *pStatus);
  1867. InterlockedIncrement(&ClientConnectionCount);
  1868. if (RPC_S_OK != *pStatus)
  1869. {
  1870. return;
  1871. }
  1872. CurrentPduSize = Association->CurrentPduSize;
  1873. RemoteWindowSize = Association->RemoteWindowSize;
  1874. *pStatus = UuidCreate((UUID *) &ActivityNode.Uuid);
  1875. if (*pStatus == RPC_S_UUID_LOCAL_ONLY)
  1876. {
  1877. *pStatus = RPC_S_OK;
  1878. }
  1879. if (*pStatus)
  1880. {
  1881. return;
  1882. }
  1883. if (AuthInfo.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  1884. {
  1885. *pStatus = InitializeSecurityContext();
  1886. if (*pStatus == RPC_P_CONTINUE_NEEDED ||
  1887. *pStatus == RPC_P_COMPLETE_NEEDED ||
  1888. *pStatus == RPC_P_COMPLETE_AND_CONTINUE)
  1889. {
  1890. *pStatus = RPC_S_OK;
  1891. }
  1892. }
  1893. if (*pStatus)
  1894. {
  1895. LogError(SU_CCONN, EV_SEC_INIT1, this, IntToPtr(*pStatus), I_RpcGetExtendedError());
  1896. return;
  1897. }
  1898. }
  1899. DG_CCONNECTION::~DG_CCONNECTION()
  1900. {
  1901. InterlockedDecrement(&ClientConnectionCount);
  1902. LogEvent(SU_CCONN, EV_DELETE, this, Association);
  1903. #ifdef DEBUGRPC
  1904. BOOL Cancelled = DelayedProcedures->Cancel(&DelayedAckTimer);
  1905. ASSERT( !Cancelled );
  1906. #endif
  1907. while ( AckPending )
  1908. {
  1909. Sleep(10);
  1910. }
  1911. while (CachedCalls)
  1912. {
  1913. DG_CCALL * Call = CachedCalls;
  1914. CachedCalls = CachedCalls->Next;
  1915. delete Call;
  1916. }
  1917. if (SecurityBuffer)
  1918. {
  1919. delete SecurityBuffer;
  1920. }
  1921. }
  1922. long
  1923. DG_CCONNECTION::DecrementRefCountAndKeepMutex()
  1924. {
  1925. Mutex.VerifyOwned();
  1926. long Count = --ReferenceCount;
  1927. LogEvent(SU_CCONN, EV_DEC, this, 0, Count, TRUE);
  1928. // Since this->ThreadId is still nonzero, no other thread will increment
  1929. // the refcount behind our back.
  1930. if (0 == Count)
  1931. {
  1932. TimeStamp = GetTickCount();
  1933. fBusy = TRUE;
  1934. MutexClear();
  1935. fAutoReconnect = FALSE;
  1936. fError = FALSE;
  1937. Association->ReleaseConnection(this);
  1938. // the association may have been deleted
  1939. }
  1940. return Count;
  1941. }
  1942. long
  1943. DG_CCONNECTION::DecrementRefCount()
  1944. {
  1945. long Count = DecrementRefCountAndKeepMutex();
  1946. if (Count > 0)
  1947. {
  1948. MutexClear();
  1949. }
  1950. return Count;
  1951. }
  1952. void
  1953. DG_CCONNECTION::PostDelayedAck(
  1954. )
  1955. {
  1956. Mutex.VerifyOwned();
  1957. LogEvent(SU_CCONN, EV_PROC, this, IntToPtr((AckOrphaned << 16) | AckPending), 0x41736f50);
  1958. if (!AckPending)
  1959. {
  1960. IncrementRefCount();
  1961. ++AckPending;
  1962. DelayedAckTimer.Initialize(DelayedAckFn, this);
  1963. DelayedProcedures->Add(&DelayedAckTimer, TWO_SECS_IN_MSEC, TRUE);
  1964. }
  1965. }
  1966. void
  1967. DelayedAckFn(
  1968. void * parm
  1969. )
  1970. {
  1971. PDG_CCONNECTION(parm)->SendDelayedAck();
  1972. }
  1973. void
  1974. DG_CCONNECTION::SendDelayedAck()
  1975. {
  1976. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_SEND_ACK, 1 ), this );
  1977. MutexRequest();
  1978. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_SEND_ACK, 2 ), this );
  1979. LogEvent(SU_CCONN, EV_PROC, this, IntToPtr((AckOrphaned << 16) | AckPending), 0x41646e53);
  1980. if (AckOrphaned)
  1981. {
  1982. AckOrphaned = FALSE;
  1983. DecrementRefCount();
  1984. return;
  1985. }
  1986. ASSERT( AckPending == 1 );
  1987. //
  1988. // Keep DG_CASSOCIATION::AllocateConnection() from taking the connection
  1989. // once AckPending drops to zero.
  1990. //
  1991. fBusy = TRUE;
  1992. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_SEND_ACK, 3 ), this );
  1993. --AckPending;
  1994. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_SEND_ACK, 4 ), this );
  1995. DecrementRefCountAndKeepMutex();
  1996. CurrentCall->SendAck();
  1997. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_SEND_ACK, 5 ), this );
  1998. CurrentCall->DecrementRefCount();
  1999. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_SEND_ACK, 6 ), this );
  2000. }
  2001. void
  2002. DG_CCONNECTION::CancelDelayedAck(
  2003. BOOL Flush
  2004. )
  2005. {
  2006. boolean Cancelled;
  2007. if (Flush)
  2008. {
  2009. if (!MutexTryRequest())
  2010. {
  2011. return;
  2012. }
  2013. }
  2014. else
  2015. {
  2016. MutexRequest();
  2017. }
  2018. ASSERT( AckPending == 0 || AckPending == 1 );
  2019. Cancelled = (boolean) DelayedProcedures->Cancel(&DelayedAckTimer);
  2020. LogEvent(SU_CCONN, EV_PROC, this, IntToPtr((Cancelled << 16) | AckPending), 0x416e6143);
  2021. CallTestHook( MAKE_TEST_HOOK_ID( TH_DG_SEND_ACK, 7 ), this, (PVOID) Cancelled );
  2022. if (AckPending)
  2023. {
  2024. if (Flush)
  2025. {
  2026. CurrentCall->SendAck();
  2027. }
  2028. if (Cancelled)
  2029. {
  2030. // the proc was queued and had not yet fired
  2031. //
  2032. DecrementRefCountAndKeepMutex();
  2033. }
  2034. else
  2035. {
  2036. // the proc was called but had not yet taken the connection mutex.
  2037. // some callers of this procedure already hold the mutex, so we can't release it
  2038. // and let the othre thread run. So we set this flag to let it know not to send
  2039. // the ack. There is no need to keep a count: there is only one delayed-procedure
  2040. // thread, so only one such proc can be outstanding at a time.
  2041. // This assert doesn't work: if a proc is orphaned, then AckPending is TRUE.
  2042. // Until that thread finishes, every time another thread calls CancelDelayedAck
  2043. // it will come here.
  2044. //
  2045. // ASSERT( AckOrphaned == FALSE );
  2046. AckOrphaned = TRUE;
  2047. }
  2048. --AckPending;
  2049. CurrentCall->DecrementRefCount();
  2050. }
  2051. else
  2052. {
  2053. if (Cancelled)
  2054. {
  2055. ASSERT( 0 && "delayed ack queued but AckPending == 0" );
  2056. }
  2057. else
  2058. {
  2059. // The proc was not queued, or already ran to completion
  2060. //
  2061. }
  2062. MutexClear();
  2063. }
  2064. }
  2065. DG_CCALL::DG_CCALL(
  2066. IN PDG_CCONNECTION a_Connection,
  2067. OUT RPC_STATUS * pStatus
  2068. ) : State (CallInit),
  2069. Connection (a_Connection),
  2070. InterfacePointer (0),
  2071. DelayedSendPending (0),
  2072. CancelPending (FALSE),
  2073. #pragma warning(disable:4355)
  2074. TransmitTimer (DelayedSendProc, this),
  2075. #pragma warning(default:4355)
  2076. DG_PACKET_ENGINE( DG_REQUEST,
  2077. DG_PACKET::AllocatePacket(a_Connection->TransportInterface->ExpectedPduSize),
  2078. pStatus )
  2079. {
  2080. Previous = Next = 0;
  2081. ObjectType = DG_CCALL_TYPE;
  2082. pAsync = 0;
  2083. InterlockedIncrement(&ClientCallCount);
  2084. if (*pStatus != RPC_S_OK)
  2085. {
  2086. return;
  2087. }
  2088. CancelEventId = 1;
  2089. ReadConnectionInfo(a_Connection, 0);
  2090. pSavedPacket->Header.ActivityHint = 0xffff;
  2091. LogEvent(SU_CCALL, EV_CREATE, this, a_Connection);
  2092. }
  2093. DG_CCALL::~DG_CCALL()
  2094. {
  2095. LogEvent(SU_CCALL, EV_DELETE, this, Connection);
  2096. InterlockedDecrement(&ClientCallCount);
  2097. }
  2098. inline RPC_STATUS
  2099. DG_CCALL::GetInitialBuffer(
  2100. IN OUT RPC_MESSAGE * Message,
  2101. IN UUID *MyObjectUuid
  2102. )
  2103. {
  2104. AsyncStatus = RPC_S_ASYNC_CALL_PENDING;
  2105. Message->Handle = (RPC_BINDING_HANDLE) this;
  2106. Next = DG_CCALL_NOT_ACTIVE;
  2107. if (MyObjectUuid)
  2108. {
  2109. UuidSpecified = 1;
  2110. RpcpMemoryCopy(&ObjectUuid, MyObjectUuid, sizeof(UUID));
  2111. }
  2112. else if (Connection->BindingHandle->InqIfNullObjectUuid() == 0)
  2113. {
  2114. UuidSpecified = 1;
  2115. RpcpMemoryCopy(&ObjectUuid,
  2116. Connection->BindingHandle->InqPointerAtObjectUuid(),
  2117. sizeof(UUID));
  2118. }
  2119. else
  2120. {
  2121. UuidSpecified = 0;
  2122. }
  2123. if (GetTickCount() - Connection->TimeStamp > (3 * 60 * 1000))
  2124. {
  2125. Connection->PossiblyRunDown = TRUE;
  2126. }
  2127. RPC_STATUS Status = GetBuffer(Message);
  2128. if (Status)
  2129. {
  2130. Connection->MutexRequest();
  2131. DecrementRefCount();
  2132. }
  2133. return Status;
  2134. }
  2135. long
  2136. DG_CCALL::DecrementRefCount()
  2137. {
  2138. long Count = DecrementRefCountAndKeepMutex();
  2139. if (Count > 0)
  2140. {
  2141. Connection->MutexClear();
  2142. }
  2143. return Count;
  2144. }
  2145. long
  2146. DG_CCALL::DecrementRefCountAndKeepMutex()
  2147. {
  2148. Connection->Mutex.VerifyOwned();
  2149. --ReferenceCount;
  2150. LogEvent(SU_CCALL, EV_DEC, this, 0, ReferenceCount);
  2151. if (ReferenceCount == 0)
  2152. {
  2153. ASSERT( !DelayedSendPending );
  2154. if (SourceEndpoint)
  2155. {
  2156. EndpointManager->ReleaseEndpoint(SourceEndpoint);
  2157. SourceEndpoint = 0;
  2158. }
  2159. TimeStamp = GetTickCount();
  2160. // ASSERT( !LastReceiveBuffer );
  2161. // CheckForLeakedPackets();
  2162. SetState(CallInit);
  2163. Connection->EndCall(this);
  2164. Connection->AddCallToCache(this);
  2165. return Connection->DecrementRefCountAndKeepMutex();
  2166. }
  2167. else
  2168. {
  2169. return 1;
  2170. }
  2171. }
  2172. RPC_STATUS
  2173. DG_CCONNECTION::TransferCallsToNewConnection(
  2174. PDG_CCALL FirstCall,
  2175. PDG_CCONNECTION NewConnection
  2176. )
  2177. {
  2178. PDG_CCALL Call;
  2179. PDG_CCALL NextCall;
  2180. int Count;
  2181. for (Call = FirstCall; Call; Call = NextCall)
  2182. {
  2183. LogError(SU_CCONN, EV_TRANSFER, this, Call);
  2184. NextCall = Call->Next;
  2185. EndCall(Call);
  2186. Count = DecrementRefCountAndKeepMutex();
  2187. NewConnection->BeginCall(Call);
  2188. NewConnection->IncrementRefCount();
  2189. Call->SwitchConnection(NewConnection);
  2190. }
  2191. //
  2192. // AllocateConnection() incremented the refcount so now we have one ref too many.
  2193. //
  2194. NewConnection->DecrementRefCountAndKeepMutex();
  2195. // <this> may have been deleted, I'm not sure.
  2196. if (Count)
  2197. {
  2198. MutexClear();
  2199. }
  2200. NewConnection->fAutoReconnect = TRUE;
  2201. return RPC_S_OK;
  2202. }
  2203. void
  2204. DG_CASSOCIATION::DeleteIdleConnections(
  2205. long CurrentTime
  2206. )
  2207. {
  2208. DictionaryCursor cursor;
  2209. if (CurrentTime - LastScavengeTime < IDLE_CCONNECTION_SWEEP_INTERVAL )
  2210. {
  2211. return;
  2212. }
  2213. if (fLoneBindingHandle)
  2214. {
  2215. //
  2216. // This was created by a binding that wanted exclusive use of the association.
  2217. // The way the cluster guys are using it, retiring connections would only be
  2218. // an intrusion.
  2219. //
  2220. return;
  2221. }
  2222. long ContextHandles = ActiveAssociations->GetContextHandleCount(this);
  2223. MutexRequest();
  2224. if (CurrentTime - LastScavengeTime < IDLE_CCONNECTION_SWEEP_INTERVAL )
  2225. {
  2226. MutexClear();
  2227. return;
  2228. }
  2229. InactiveConnections.Reset(cursor);
  2230. DG_CCONNECTION * Head = 0;
  2231. DG_CCONNECTION * Node = InactiveConnections.Next(cursor);
  2232. //
  2233. // We should never see a context handle on an association with no connections.
  2234. // We preserve one connection on the association so that we can send keep-alives.
  2235. //
  2236. if (ContextHandles > 0 && ActiveConnections.Size() == 0)
  2237. {
  2238. ASSERT( Node );
  2239. Node = InactiveConnections.Next(cursor);
  2240. }
  2241. while (Node)
  2242. {
  2243. if (CurrentTime - Node->TimeStamp > IDLE_CCONNECTION_LIFETIME)
  2244. {
  2245. InactiveConnections.Delete(Node->AssociationKey);
  2246. Node->Next = Head;
  2247. Head = Node;
  2248. }
  2249. Node = InactiveConnections.Next(cursor);
  2250. }
  2251. LastScavengeTime = CurrentTime;
  2252. MutexClear();
  2253. while (Head)
  2254. {
  2255. Node = Head->Next;
  2256. Head->CancelDelayedAck();
  2257. delete Head;
  2258. Head = Node;
  2259. }
  2260. }
  2261. DG_CCALL *
  2262. DG_CCONNECTION::FindIdleCalls(
  2263. long CurrentTime
  2264. )
  2265. {
  2266. Mutex.VerifyOwned();
  2267. if (CurrentTime - LastScavengeTime < IDLE_CCALL_SWEEP_INTERVAL )
  2268. {
  2269. return 0;
  2270. }
  2271. LastScavengeTime = CurrentTime;
  2272. DG_CCALL * Node;
  2273. for (Node = CachedCalls; Node; Node = Node->Next)
  2274. {
  2275. if (CurrentTime - Node->TimeStamp > IDLE_CCALL_LIFETIME )
  2276. {
  2277. break;
  2278. }
  2279. }
  2280. if (Node)
  2281. {
  2282. DG_CCALL * Next = Node->Next;
  2283. Node->Next = 0;
  2284. Node = Next;
  2285. }
  2286. return Node;
  2287. }
  2288. RPC_STATUS
  2289. DG_CCALL::GetBuffer(
  2290. IN OUT PRPC_MESSAGE Message,
  2291. IN UUID *ObjectUuid
  2292. )
  2293. /*++
  2294. Routine Description:
  2295. This method is called to actually allocate memory for an rpc call.
  2296. Arguments:
  2297. Message - The RPC_MESSAGE structure associated with this call.
  2298. ObjectUuid - Ignored
  2299. Return Value:
  2300. RPC_S_OUT_OF_MEMORY
  2301. RPC_S_OK
  2302. --*/
  2303. {
  2304. LogEvent(SU_CCALL, EV_PROC, this, IntToPtr(Message->BufferLength), 'G' + (('B' + (('u' + ('f' << 8)) << 8)) << 8));
  2305. RPC_STATUS Status = CommonGetBuffer(Message);
  2306. LogEvent(SU_CCALL, EV_BUFFER_OUT, this, Message->Buffer, Message->BufferLength);
  2307. if (Status)
  2308. {
  2309. LogError(SU_CCALL, EV_STATUS, this, 0, Status);
  2310. }
  2311. return Status;
  2312. }
  2313. void
  2314. DG_CCALL::FreeBuffer(
  2315. IN OUT PRPC_MESSAGE Message
  2316. )
  2317. /*++
  2318. Routine Description:
  2319. This is called by stubs in order to free a marshalling buffer.
  2320. Arguments:
  2321. Message - The RPC_MESSAGE structure associated with this call.
  2322. Return Value:
  2323. <none>
  2324. --*/
  2325. {
  2326. FreePipeBuffer(Message);
  2327. Connection->MutexRequest();
  2328. DecrementRefCount();
  2329. }
  2330. void
  2331. DG_CCALL::FreePipeBuffer (
  2332. IN OUT PRPC_MESSAGE Message
  2333. )
  2334. /*++
  2335. Routine Description:
  2336. Called by stubs to free a buffer used for marshalling pipe data.
  2337. Arguments:
  2338. Message - description of the buffer
  2339. Return Value:
  2340. z none
  2341. --*/
  2342. {
  2343. LogEvent(SU_CCALL, EV_PROC, this, Message->Buffer, 'F' + (('B' + (('u' + ('f' << 8)) << 8)) << 8));
  2344. CommonFreeBuffer(Message);
  2345. }
  2346. RPC_STATUS
  2347. DG_CCALL::ReallocPipeBuffer (
  2348. IN PRPC_MESSAGE Message,
  2349. IN unsigned int NewSize
  2350. )
  2351. /*++
  2352. Routine Description:
  2353. Called by stubs to change the size of a pipe buffer. If possible, the
  2354. buffer will be reallocated in place; otherwise, we will allocate a new
  2355. buffer and duplicate the existing data.
  2356. Arguments:
  2357. Message - (on entry) describes the existing buffer
  2358. (on exit) describes the new buffer
  2359. NewSize - new requested buffer size
  2360. Return Value:
  2361. mainly RPC_S_OK for success or RPC_S_OUT_OF_MEMORY for failure
  2362. --*/
  2363. {
  2364. LogEvent(SU_CCALL, EV_PROC, this, Message->Buffer, 'R' + (('B' + (('u' + ('f' << 8)) << 8)) << 8));
  2365. RPC_STATUS Status = CommonReallocBuffer(Message, NewSize);
  2366. LogEvent(SU_CCALL, EV_BUFFER_OUT, this, Message->Buffer, Message->BufferLength);
  2367. if (Status)
  2368. {
  2369. LogError(SU_CCALL, EV_STATUS, this, 0, Status);
  2370. }
  2371. return Status;
  2372. }
  2373. void
  2374. DG_CCALL::BuildNcaPacketHeader(
  2375. PNCA_PACKET_HEADER Header,
  2376. PRPC_MESSAGE Message
  2377. )
  2378. /*++
  2379. Routine Description:
  2380. Given an input RPC_MESSAGE, builds a nca packet header.
  2381. Arguments:
  2382. pNcaPacketHeader - Where to build the new packet header.
  2383. Message - The original RPC_MESSAGE.
  2384. Return Value:
  2385. <none>
  2386. --*/
  2387. {
  2388. PRPC_CLIENT_INTERFACE pCli = (PRPC_CLIENT_INTERFACE) (Message->RpcInterfaceInformation);
  2389. RPC_UUID * pUuid = (RPC_UUID *) (&(pCli->InterfaceId.SyntaxGUID));
  2390. Header->InterfaceId = *pUuid;
  2391. if (UuidSpecified)
  2392. {
  2393. RpcpMemoryCopy(&(Header->ObjectId), &ObjectUuid, sizeof(UUID));
  2394. }
  2395. else
  2396. {
  2397. RpcpMemorySet(&Header->ObjectId, 0, sizeof(UUID));
  2398. }
  2399. Header->InterfaceVersion.MajorVersion = pCli->InterfaceId.SyntaxVersion.MajorVersion;
  2400. Header->InterfaceVersion.MinorVersion = pCli->InterfaceId.SyntaxVersion.MinorVersion;
  2401. Header->SequenceNumber = SequenceNumber;
  2402. Header->OperationNumber = (unsigned short) Message->ProcNum;
  2403. Header->ServerBootTime = Connection->Association->ServerBootTime;
  2404. Header->InterfaceHint = 0xffff;
  2405. Header->PacketType = DG_REQUEST;
  2406. Header->PacketFlags = (unsigned char) RpcToPacketFlagsArray[Message->RpcFlags & RPC_NCA_PACKET_FLAGS];
  2407. Header->PacketFlags2 = 0;
  2408. }
  2409. inline RPC_STATUS
  2410. DG_CCONNECTION::UpdateServerAddress(
  2411. IN DG_PACKET * Packet,
  2412. IN DG_TRANSPORT_ADDRESS Address
  2413. )
  2414. {
  2415. ServerResponded = TRUE;
  2416. Association->CurrentPduSize = CurrentPduSize;
  2417. Association->RemoteWindowSize = RemoteWindowSize;
  2418. return Association->UpdateAssociationWithAddress( Packet, Address );
  2419. }
  2420. void
  2421. DG_CCALL::SendAck(
  2422. )
  2423. {
  2424. LogEvent(SU_CCALL, EV_ACK, this);
  2425. pSavedPacket->Header.PacketType = DG_ACK;
  2426. pSavedPacket->SetPacketBodyLen(0);
  2427. pSavedPacket->SetFragmentNumber(ReceiveFragmentBase);
  2428. SetSerialNumber(&pSavedPacket->Header, SendSerialNumber);
  2429. Connection->SealAndSendPacket(SourceEndpoint, 0, &pSavedPacket->Header, 0);
  2430. if (FALSE == SourceEndpoint->Async)
  2431. {
  2432. SourceEndpoint->Flags |= PENALTY_BOX;
  2433. }
  2434. }
  2435. inline RPC_STATUS
  2436. DG_CCALL::SendPing(
  2437. )
  2438. {
  2439. pSavedPacket->Header.PacketType = DG_PING;
  2440. pSavedPacket->Header.PacketFlags &= DG_PF_IDEMPOTENT;
  2441. pSavedPacket->SetPacketBodyLen(0);
  2442. AddSerialNumber(&pSavedPacket->Header);
  2443. unsigned Frag = (pSavedPacket->Header.PacketType << 16) | pSavedPacket->GetFragmentNumber();
  2444. LogEvent(SU_CCALL, EV_PKT_OUT, this, 0, Frag);
  2445. RPC_STATUS Status = Connection->SealAndSendPacket(SourceEndpoint, 0, &pSavedPacket->Header, 0);
  2446. ++SendSerialNumber;
  2447. return Status;
  2448. }
  2449. PDG_CCONNECTION
  2450. MapGenericHandleToConnection(
  2451. handle_t Handle,
  2452. UUID * Uuid
  2453. )
  2454. {
  2455. PDG_CCONNECTION Connection;
  2456. ASSERT( Handle );
  2457. if (PMESSAGE_OBJECT(Handle)->Type(DG_CCONNECTION_TYPE))
  2458. {
  2459. Connection = PDG_CCONNECTION(Handle);
  2460. Connection->MutexRequest();
  2461. }
  2462. else
  2463. {
  2464. ASSERT( PMESSAGE_OBJECT(Handle)->Type(DG_CALLBACK_TYPE) );
  2465. Connection = PDG_CLIENT_CALLBACK(Handle)->Connection;
  2466. if (Connection)
  2467. {
  2468. Connection->MutexRequest();
  2469. }
  2470. else
  2471. {
  2472. Connection = ClientConnections->Lookup( (RPC_UUID *) Uuid );
  2473. PDG_CLIENT_CALLBACK(Handle)->Connection = Connection;
  2474. }
  2475. }
  2476. return Connection;
  2477. }
  2478. #define CCC_SEQUENCE 0x0001
  2479. #define CCC_CAS 0x0002
  2480. #define CCC_AUTH 0x0004
  2481. #define CCC_ASYNC_OK 0x0008
  2482. #define CCC_AUTH_MORE 0x0010
  2483. void
  2484. ConvCore(
  2485. DWORD Bits,
  2486. PRPC_ASYNC_STATE AsyncHandle,
  2487. handle_t Handle,
  2488. UUID * Uuid,
  2489. unsigned long ServerBootTime,
  2490. byte * InData,
  2491. long InLength,
  2492. long OutMaxLength,
  2493. unsigned long * SequenceNumber,
  2494. UUID * pCASUuid,
  2495. byte * OutData,
  2496. long * pOutLength,
  2497. error_status_t *Status
  2498. )
  2499. {
  2500. if (pOutLength)
  2501. {
  2502. *pOutLength = 0;
  2503. }
  2504. PDG_CCONNECTION Connection = MapGenericHandleToConnection(Handle, Uuid);
  2505. LogEvent(SU_CCONN, EV_CALLBACK, Connection, 0, Bits);
  2506. if (!Connection)
  2507. {
  2508. *Status = NCA_STATUS_BAD_ACTID;
  2509. RpcAsyncCompleteCall(AsyncHandle, 0);
  2510. return;
  2511. }
  2512. //
  2513. // See if this activity id has a call in progress.
  2514. //
  2515. if (Connection->ActivityNode.CompareUuid(Uuid) != 0)
  2516. {
  2517. Connection->MutexClear();
  2518. *Status = NCA_STATUS_BAD_ACTID;
  2519. RpcAsyncCompleteCall(AsyncHandle, 0);
  2520. return;
  2521. }
  2522. *Status = RPC_S_OK;
  2523. if (Connection->Association->ServerBootTime == 0)
  2524. {
  2525. //
  2526. // the server is responding to our first call.
  2527. //
  2528. Connection->Association->ServerBootTime = ServerBootTime;
  2529. }
  2530. else if (Connection->Association->ServerBootTime != ServerBootTime)
  2531. {
  2532. //
  2533. // The server crashed.
  2534. //
  2535. Connection->MutexClear();
  2536. *Status = NCA_STATUS_YOU_CRASHED;
  2537. RpcAsyncCompleteCall(AsyncHandle, 0);
  2538. return;
  2539. }
  2540. if (Bits & CCC_ASYNC_OK)
  2541. {
  2542. Connection->EnableOverlappedCalls();
  2543. }
  2544. if (Bits & CCC_SEQUENCE)
  2545. {
  2546. *SequenceNumber = Connection->GetSequenceNumber();
  2547. }
  2548. if (Bits & CCC_CAS)
  2549. {
  2550. ASSERT( ActiveAssociations->fCasUuidReady );
  2551. *pCASUuid = ActiveAssociations->CasUuid;
  2552. }
  2553. if (Bits & CCC_AUTH)
  2554. {
  2555. if (Connection->PossiblyRunDown)
  2556. {
  2557. Connection->PossiblyRunDown = FALSE;
  2558. Connection->fSecurePacketReceived = FALSE;
  2559. }
  2560. *Status = MapToNcaStatusCode(
  2561. Connection->DealWithAuthCallback(
  2562. InData,
  2563. InLength,
  2564. OutData,
  2565. OutMaxLength,
  2566. pOutLength
  2567. )
  2568. );
  2569. }
  2570. if (Bits & CCC_AUTH_MORE)
  2571. {
  2572. *Status = MapToNcaStatusCode(
  2573. Connection->DealWithAuthMore(
  2574. InLength,
  2575. OutData,
  2576. OutMaxLength,
  2577. pOutLength
  2578. )
  2579. );
  2580. }
  2581. if (RPC_S_OK == *Status)
  2582. {
  2583. Connection->CallbackCompleted = TRUE;
  2584. }
  2585. Connection->MutexClear();
  2586. RpcAsyncCompleteCall(AsyncHandle, 0);
  2587. }
  2588. void
  2589. conv_are_you_there(
  2590. PRPC_ASYNC_STATE AsyncHandle,
  2591. handle_t Handle,
  2592. UUID * Uuid,
  2593. unsigned long ServerBootTime,
  2594. error_status_t *Status
  2595. )
  2596. {
  2597. ConvCore(0, // bits
  2598. AsyncHandle,
  2599. Handle,
  2600. Uuid,
  2601. ServerBootTime,
  2602. 0, // in auth data
  2603. 0, // in auth data length
  2604. 0, // out auth data max length
  2605. 0, // sequence number
  2606. 0, // CAS UUID
  2607. 0, // out auth data
  2608. 0, // out auth data length
  2609. Status
  2610. );
  2611. }
  2612. void
  2613. conv_who_are_you(
  2614. PRPC_ASYNC_STATE AsyncHandle,
  2615. IN handle_t Handle,
  2616. IN UUID * Uuid,
  2617. IN unsigned long ServerBootTime,
  2618. OUT unsigned long * SequenceNumber,
  2619. OUT error_status_t * Status
  2620. )
  2621. /*++
  2622. Routine Description:
  2623. This is the conv_who_are_you callback routine that the server will
  2624. call to check if it crashed.
  2625. Arguments:
  2626. pUuid - Activity Uuid.
  2627. ServerBootTime - The server's record of its boot time.
  2628. SequenceNumber - We return our record of our sequence number.
  2629. Status - 0 if we think things are ok, else an NCA error code
  2630. Return Value:
  2631. <none>
  2632. --*/
  2633. {
  2634. ConvCore(CCC_SEQUENCE,
  2635. AsyncHandle,
  2636. Handle,
  2637. Uuid,
  2638. ServerBootTime,
  2639. 0, // in auth data
  2640. 0, // in auth data length
  2641. 0, // out auth data max length
  2642. SequenceNumber,
  2643. 0, // CAS UUID
  2644. 0, // out auth data
  2645. 0, // out auth data length
  2646. Status
  2647. );
  2648. }
  2649. void
  2650. conv_who_are_you2(
  2651. PRPC_ASYNC_STATE AsyncHandle,
  2652. IN handle_t Handle,
  2653. IN UUID * Uuid,
  2654. IN unsigned long ServerBootTime,
  2655. OUT unsigned long * SequenceNumber,
  2656. OUT UUID * pCASUuid,
  2657. OUT error_status_t * Status
  2658. )
  2659. /*++
  2660. Routine Description:
  2661. This is the conv_who_are_you callback routine that the server will
  2662. call to check if it crashed.
  2663. Arguments:
  2664. Return Value:
  2665. <none>
  2666. --*/
  2667. {
  2668. ConvCore(CCC_SEQUENCE | CCC_CAS,
  2669. AsyncHandle,
  2670. Handle,
  2671. Uuid,
  2672. ServerBootTime,
  2673. 0, // in auth data
  2674. 0, // in auth data length
  2675. 0, // out auth data max length
  2676. SequenceNumber,
  2677. pCASUuid,
  2678. 0, // out auth data
  2679. 0, // out auth data length
  2680. Status
  2681. );
  2682. }
  2683. void
  2684. conv_who_are_you_auth(
  2685. PRPC_ASYNC_STATE AsyncHandle,
  2686. handle_t Handle,
  2687. UUID * Uuid,
  2688. unsigned long ServerBootTime,
  2689. byte * InData,
  2690. long InLength,
  2691. long OutMaxLength,
  2692. unsigned long * SequenceNumber,
  2693. UUID * pCASUuid,
  2694. byte * OutData,
  2695. long * pOutLength,
  2696. error_status_t *Status
  2697. )
  2698. {
  2699. ConvCore(CCC_SEQUENCE | CCC_CAS | CCC_AUTH,
  2700. AsyncHandle,
  2701. Handle,
  2702. Uuid,
  2703. ServerBootTime,
  2704. InData,
  2705. InLength,
  2706. OutMaxLength,
  2707. SequenceNumber,
  2708. pCASUuid,
  2709. OutData,
  2710. pOutLength,
  2711. Status
  2712. );
  2713. }
  2714. void
  2715. conv_who_are_you_auth_more(
  2716. PRPC_ASYNC_STATE AsyncHandle,
  2717. handle_t Handle,
  2718. UUID * Uuid,
  2719. unsigned long ServerBootTime,
  2720. long Index,
  2721. long OutMaxLength,
  2722. byte * OutData,
  2723. long * pOutLength,
  2724. error_status_t *Status
  2725. )
  2726. {
  2727. ConvCore(CCC_AUTH_MORE,
  2728. AsyncHandle,
  2729. Handle,
  2730. Uuid,
  2731. ServerBootTime,
  2732. 0,
  2733. Index,
  2734. OutMaxLength,
  2735. 0,
  2736. 0,
  2737. OutData,
  2738. pOutLength,
  2739. Status
  2740. );
  2741. }
  2742. void
  2743. ms_conv_are_you_there(
  2744. PRPC_ASYNC_STATE AsyncHandle,
  2745. handle_t Handle,
  2746. UUID * Uuid,
  2747. unsigned long ServerBootTime,
  2748. error_status_t *Status
  2749. )
  2750. /*++
  2751. Routine Description:
  2752. This is the conv_who_are_you callback routine that the server will
  2753. call to check if it crashed.
  2754. Arguments:
  2755. Return Value:
  2756. <none>
  2757. --*/
  2758. {
  2759. ConvCore(CCC_ASYNC_OK,
  2760. AsyncHandle,
  2761. Handle,
  2762. Uuid,
  2763. ServerBootTime,
  2764. 0, // in auth data
  2765. 0, // in auth data length
  2766. 0, // out auth data max length
  2767. 0, // sequence number
  2768. 0, // CAS UUID
  2769. 0, // out auth data
  2770. 0, // out auth data length
  2771. Status
  2772. );
  2773. }
  2774. void
  2775. ms_conv_who_are_you2(
  2776. PRPC_ASYNC_STATE AsyncHandle,
  2777. IN handle_t Handle,
  2778. IN UUID * Uuid,
  2779. IN unsigned long ServerBootTime,
  2780. OUT unsigned long * SequenceNumber,
  2781. OUT UUID * pCASUuid,
  2782. OUT error_status_t * Status
  2783. )
  2784. /*++
  2785. Routine Description:
  2786. This is the conv_who_are_you callback routine that the server will
  2787. call to check if it crashed.
  2788. Arguments:
  2789. Return Value:
  2790. <none>
  2791. --*/
  2792. {
  2793. ConvCore(CCC_ASYNC_OK | CCC_SEQUENCE | CCC_CAS,
  2794. AsyncHandle,
  2795. Handle,
  2796. Uuid,
  2797. ServerBootTime,
  2798. 0, // in auth data
  2799. 0, // in auth data length
  2800. 0, // out auth data max length
  2801. SequenceNumber,
  2802. pCASUuid,
  2803. 0, // out auth data
  2804. 0, // out auth data length
  2805. Status
  2806. );
  2807. }
  2808. void
  2809. ms_conv_who_are_you_auth(
  2810. PRPC_ASYNC_STATE AsyncHandle,
  2811. handle_t Handle,
  2812. UUID * Uuid,
  2813. unsigned long ServerBootTime,
  2814. byte * InData,
  2815. long InLength,
  2816. long OutMaxLength,
  2817. unsigned long * SequenceNumber,
  2818. UUID * pCASUuid,
  2819. byte * OutData,
  2820. long * pOutLength,
  2821. error_status_t *Status
  2822. )
  2823. {
  2824. ConvCore(CCC_ASYNC_OK | CCC_SEQUENCE | CCC_CAS | CCC_AUTH,
  2825. AsyncHandle,
  2826. Handle,
  2827. Uuid,
  2828. ServerBootTime,
  2829. InData,
  2830. InLength,
  2831. OutMaxLength,
  2832. SequenceNumber,
  2833. pCASUuid,
  2834. OutData,
  2835. pOutLength,
  2836. Status
  2837. );
  2838. }
  2839. void
  2840. DG_CCONNECTION::EnableOverlappedCalls()
  2841. {
  2842. Association->fServerSupportsAsync = TRUE;
  2843. if (FALSE == fServerSupportsAsync)
  2844. {
  2845. fServerSupportsAsync = TRUE;
  2846. MutexRequest();
  2847. MaybeTransmitNextCall();
  2848. MutexClear();
  2849. }
  2850. }
  2851. RPC_STATUS
  2852. DG_CCALL::GetEndpoint(
  2853. DWORD EndpointFlags
  2854. )
  2855. {
  2856. SourceEndpoint = EndpointManager->RequestEndpoint(
  2857. Connection->TransportInterface,
  2858. (pAsync) ? TRUE : FALSE,
  2859. EndpointFlags
  2860. );
  2861. if (!SourceEndpoint)
  2862. {
  2863. return RPC_S_OUT_OF_RESOURCES;
  2864. }
  2865. if (pSavedPacket->MaxDataLength < SourceEndpoint->Stats.PreferredPduSize)
  2866. {
  2867. PDG_PACKET NewPacket = DG_PACKET::AllocatePacket(SourceEndpoint->Stats.PreferredPduSize);
  2868. if (!NewPacket)
  2869. {
  2870. EndpointManager->ReleaseEndpoint(SourceEndpoint);
  2871. SourceEndpoint = 0;
  2872. return RPC_S_OUT_OF_MEMORY;
  2873. }
  2874. NewPacket->Header = pSavedPacket->Header;
  2875. FreePacket(pSavedPacket);
  2876. pSavedPacket = NewPacket;
  2877. }
  2878. //
  2879. // If there is a chance that the endpoint has queued ICMP rejects, drain them.
  2880. //
  2881. if (FALSE == SourceEndpoint->Async &&
  2882. (SourceEndpoint->Flags & PENALTY_BOX))
  2883. {
  2884. RPC_STATUS Status;
  2885. do
  2886. {
  2887. PDG_PACKET Packet = 0;
  2888. DG_TRANSPORT_ADDRESS ReceiveAddress = 0;
  2889. unsigned Length = 0;
  2890. void * Buffer = 0;
  2891. Status = Connection->TransportInterface->SyncReceive(
  2892. &SourceEndpoint->TransportEndpoint,
  2893. &ReceiveAddress,
  2894. &Length,
  2895. &Buffer,
  2896. 0
  2897. );
  2898. LogEvent( SU_CCALL, EV_PKT_IN, Connection, Buffer, Status);
  2899. if (Buffer)
  2900. {
  2901. Packet = DG_PACKET::FromPacketHeader(Buffer);
  2902. Packet->DataLength = Length;
  2903. FreePacket(Packet);
  2904. }
  2905. if (Status == RPC_P_PORT_DOWN)
  2906. {
  2907. Status = 0;
  2908. }
  2909. }
  2910. while ( !Status );
  2911. }
  2912. SourceEndpoint->Flags &= ~(PENALTY_BOX);
  2913. return 0;
  2914. }
  2915. RPC_STATUS
  2916. DG_CCALL::BeforeSendReceive(
  2917. PRPC_MESSAGE Message
  2918. )
  2919. {
  2920. DWORD EndpointFlags;
  2921. RPC_STATUS Status;
  2922. NotificationIssued = -1;
  2923. ASSERT( 0 == (Connection->BindingHandle->EndpointFlags & PORT_FOR_MAYBE_CALLS));
  2924. EndpointFlags = Connection->BindingHandle->EndpointFlags;
  2925. if (Message->RpcFlags & RPC_NCA_FLAGS_MAYBE)
  2926. {
  2927. if (FALSE == Connection->Association->TransportInterface->IsMessageTransport)
  2928. {
  2929. EndpointFlags |= PORT_FOR_MAYBE_CALLS;
  2930. }
  2931. }
  2932. Status = GetEndpoint(EndpointFlags);
  2933. if (Status != RPC_S_OK)
  2934. {
  2935. return Status;
  2936. }
  2937. Status = Connection->BeginCall(this);
  2938. if (Status != RPC_S_OK)
  2939. {
  2940. EndpointManager->ReleaseEndpoint(SourceEndpoint);
  2941. SourceEndpoint = 0;
  2942. return Status;
  2943. }
  2944. InterfacePointer = (PRPC_CLIENT_INTERFACE) Message->RpcInterfaceInformation;
  2945. UnansweredRequestCount = 0;
  2946. NewCall();
  2947. //
  2948. // Set transport specific options for this binding handle (if any).
  2949. // NOTE: These options are from RpcBindingSetOption().
  2950. //
  2951. if ( (Connection->BindingHandle->pvTransportOptions)
  2952. && (Connection->Association->TransportInterface->ImplementOptions) )
  2953. {
  2954. Status = Connection->Association->TransportInterface->ImplementOptions(
  2955. SourceEndpoint->TransportEndpoint,
  2956. Connection->BindingHandle->pvTransportOptions);
  2957. }
  2958. //
  2959. // Fill in common fields of the send packet.
  2960. //
  2961. BuildNcaPacketHeader(&pSavedPacket->Header, Message);
  2962. BasePacketFlags = pSavedPacket->Header.PacketFlags;
  2963. SetState(CallQuiescent);
  2964. ForceAck = FALSE;
  2965. AllArgsSent = FALSE;
  2966. StaticArgsSent = FALSE;
  2967. ASSERT( !DelayedSendPending );
  2968. //#ifdef NTENV
  2969. if (!pAsync)
  2970. {
  2971. Status = RegisterForCancels(this);
  2972. if (Status != RPC_S_OK)
  2973. {
  2974. Connection->EndCall(this);
  2975. EndpointManager->ReleaseEndpoint(SourceEndpoint);
  2976. SourceEndpoint = 0;
  2977. return Status;
  2978. }
  2979. }
  2980. //#endif
  2981. //
  2982. // If this is a call on the "conv" interface, we should set it also.
  2983. //
  2984. PRPC_CLIENT_INTERFACE pCli = (PRPC_CLIENT_INTERFACE) (Message->RpcInterfaceInformation);
  2985. RPC_UUID * pUuid = (RPC_UUID *) (&(pCli->InterfaceId.SyntaxGUID));
  2986. if (0 == pUuid->MatchUuid((RPC_UUID *) &((PRPC_SERVER_INTERFACE) conv_ServerIfHandle)->InterfaceId.SyntaxGUID ))
  2987. {
  2988. BasePacketFlags2 = DG_PF2_UNRELATED;
  2989. if (Previous)
  2990. {
  2991. Previous->ForceAck = TRUE;
  2992. }
  2993. }
  2994. unsigned TimeoutLevel = Connection->BindingHandle->InqComTimeout();
  2995. if (Message->RpcFlags & RPC_NCA_FLAGS_BROADCAST)
  2996. {
  2997. ReceiveTimeout = 3000;
  2998. TimeoutLimit = 1000 * (TimeoutLevel+1)/2;
  2999. }
  3000. else if (TimeoutLevel == RPC_C_BINDING_INFINITE_TIMEOUT)
  3001. {
  3002. ReceiveTimeout = 5000;
  3003. TimeoutLimit = 0x7fffffff;
  3004. }
  3005. else if (Connection->TransportInterface->IsMessageTransport)
  3006. {
  3007. ReceiveTimeout = 5000;
  3008. TimeoutLimit = 300000 + 10000 * ( 1 << TimeoutLevel );
  3009. }
  3010. else
  3011. {
  3012. ReceiveTimeout = 250 + 250 * (TimeoutLevel+1)/2;
  3013. TimeoutLimit = 1000 * ( 1 << TimeoutLevel );
  3014. }
  3015. LastReceiveTime = GetTickCount();
  3016. return Status;
  3017. }
  3018. RPC_STATUS
  3019. DG_CCALL::AfterSendReceive(
  3020. PRPC_MESSAGE Message,
  3021. RPC_STATUS Status
  3022. )
  3023. {
  3024. DG_BINDING_HANDLE * OldBinding = 0;
  3025. Connection->Mutex.VerifyOwned();
  3026. PDG_CASSOCIATION Association = Connection->Association;
  3027. CancelDelayedSend();
  3028. //#ifdef NTENV
  3029. if (!pAsync)
  3030. {
  3031. EVAL_AND_ASSERT(RPC_S_OK == UnregisterForCancels());
  3032. }
  3033. //#endif
  3034. if (RPC_S_OK == Status)
  3035. {
  3036. ASSERT( !Buffer );
  3037. Connection->PossiblyRunDown = FALSE;
  3038. if (0 == (Message->RpcFlags & RPC_NCA_FLAGS_MAYBE))
  3039. {
  3040. Association->ClearErrorFlag();
  3041. }
  3042. // NOTE: No ACK for [message] calls.
  3043. if ( (ForceAck) && !(Message->RpcFlags & RPCFLG_MESSAGE) )
  3044. {
  3045. SendAck();
  3046. }
  3047. else if (Next)
  3048. {
  3049. //
  3050. // Don't ACK because we will transmit the next queued call momentarily.
  3051. //
  3052. }
  3053. else if (0 == (BufferFlags & RPC_NCA_FLAGS_IDEMPOTENT) ||
  3054. Message->BufferLength > MaxFragmentSize)
  3055. {
  3056. //
  3057. // NOTE: We don't need an ACK for [message] calls...
  3058. //
  3059. if ( !(Message->RpcFlags & RPCFLG_MESSAGE) &&
  3060. !(Message->RpcFlags & RPC_NCA_FLAGS_MAYBE) )
  3061. {
  3062. ++ReferenceCount;
  3063. LogEvent(SU_CCALL, EV_INC, this, 0, ReferenceCount);
  3064. Connection->PostDelayedAck();
  3065. }
  3066. }
  3067. }
  3068. else
  3069. {
  3070. if (FALSE == SourceEndpoint->Async)
  3071. {
  3072. SourceEndpoint->Flags |= PENALTY_BOX;
  3073. }
  3074. Status = MapErrorCode(Status);
  3075. CleanupSendWindow();
  3076. CleanupReceiveWindow();
  3077. if (RPC_S_SERVER_UNAVAILABLE == Status ||
  3078. RPC_S_UNKNOWN_IF == Status ||
  3079. RPC_S_CALL_FAILED == Status ||
  3080. RPC_S_CALL_FAILED_DNE == Status ||
  3081. RPC_S_COMM_FAILURE == Status ||
  3082. RPC_S_CALL_CANCELLED == Status ||
  3083. RPC_S_PROTOCOL_ERROR == Status
  3084. )
  3085. {
  3086. Connection->fError = TRUE;
  3087. Association->SetErrorFlag();
  3088. OldBinding = Connection->BindingHandle;
  3089. OldBinding->IncrementRefCount();
  3090. }
  3091. }
  3092. SetState(CallComplete);
  3093. pAsync = 0;
  3094. long CurrentTime = GetTickCount();
  3095. DG_CCALL * IdleCalls = Connection->FindIdleCalls(CurrentTime);
  3096. if (Status == RPC_S_OK)
  3097. {
  3098. Connection->MutexClear();
  3099. //
  3100. // Record that this interface is valid for this association.
  3101. //
  3102. Association->AddInterface(Message->RpcInterfaceInformation, &pSavedPacket->Header.ObjectId);
  3103. }
  3104. else
  3105. {
  3106. RPC_UUID Object;
  3107. Object.CopyUuid(&pSavedPacket->Header.ObjectId);
  3108. Association->IncrementRefCount();
  3109. //
  3110. // If the call is dying, we need to free the current buffer here
  3111. // instead of letting NDR do it on the usual schedule.
  3112. //
  3113. if (0 == DecrementRefCount())
  3114. {
  3115. FreePipeBuffer(Message);
  3116. Message->Handle = 0;
  3117. }
  3118. Association->RemoveInterface(Message->RpcInterfaceInformation, &Object);
  3119. Association->DecrementRefCount();
  3120. }
  3121. if (OldBinding)
  3122. {
  3123. OldBinding->DisassociateFromServer();
  3124. OldBinding->DecrementRefCount();
  3125. }
  3126. while (IdleCalls)
  3127. {
  3128. DG_CCALL * Next = IdleCalls->Next;
  3129. delete IdleCalls;
  3130. IdleCalls = Next;
  3131. }
  3132. return Status;
  3133. }
  3134. RPC_STATUS
  3135. DG_CCALL::MapErrorCode(
  3136. RPC_STATUS Status
  3137. )
  3138. {
  3139. LogError(SU_CCALL, EV_STATUS, this, 0, Status);
  3140. //
  3141. // Map security errors to access-denied.
  3142. //
  3143. if (0x80090000UL == (Status & 0xffff0000UL))
  3144. {
  3145. #ifdef DEBUGRPC
  3146. if (Status != SEC_E_NO_IMPERSONATION &&
  3147. Status != SEC_E_UNSUPPORTED_FUNCTION )
  3148. {
  3149. PrintToDebugger("RPC DG: mapping security error %lx to access-denied\n", Status);
  3150. }
  3151. #endif
  3152. Status = RPC_S_SEC_PKG_ERROR;
  3153. }
  3154. //
  3155. // We have to return CALL_FAILED if all the [in] static parms have
  3156. // been sent, even if they weren't acknowledged.
  3157. //
  3158. if (RPC_P_HOST_DOWN == Status ||
  3159. RPC_P_PORT_DOWN == Status ||
  3160. RPC_P_SEND_FAILED == Status ||
  3161. RPC_P_RECEIVE_FAILED == Status ||
  3162. RPC_P_TIMEOUT == Status )
  3163. {
  3164. if (Connection->CallbackCompleted &&
  3165. !(BufferFlags & RPC_NCA_FLAGS_IDEMPOTENT) &&
  3166. StaticArgsSent)
  3167. {
  3168. Status = RPC_S_CALL_FAILED;
  3169. }
  3170. else if (Connection->ServerResponded)
  3171. {
  3172. Status = RPC_S_CALL_FAILED_DNE;
  3173. }
  3174. else
  3175. {
  3176. Status = RPC_S_SERVER_UNAVAILABLE;
  3177. }
  3178. }
  3179. return Status;
  3180. }
  3181. RPC_STATUS
  3182. DG_CCALL::SendReceive(
  3183. IN OUT PRPC_MESSAGE Message
  3184. )
  3185. {
  3186. LogEvent(SU_CCALL, EV_PROC, this, Message->Buffer, 0x52646e53);
  3187. RPC_STATUS Status;
  3188. ASSERT( !(Message->RpcFlags & RPC_BUFFER_ASYNC) && !pAsync);
  3189. Connection->MutexRequest();
  3190. Status = BeforeSendReceive(Message);
  3191. if (Status)
  3192. {
  3193. FreeBuffer(Message);
  3194. Connection->MutexClear();
  3195. return Status;
  3196. }
  3197. //
  3198. // [maybe], [maybe, broadcast] and [message] calls.
  3199. //
  3200. if ( (Message->RpcFlags & RPC_NCA_FLAGS_MAYBE)
  3201. || (Message->RpcFlags & RPCFLG_MESSAGE) )
  3202. {
  3203. Message->RpcFlags |= RPC_NCA_FLAGS_MAYBE;
  3204. Status = MaybeSendReceive(Message);
  3205. return AfterSendReceive(Message, Status);
  3206. }
  3207. if (Message->RpcFlags & RPC_NCA_FLAGS_BROADCAST)
  3208. {
  3209. if (Message->BufferLength > SourceEndpoint->Stats.PreferredPduSize)
  3210. {
  3211. FreeBuffer(Message);
  3212. Connection->MutexClear();
  3213. return RPC_S_SERVER_UNAVAILABLE;
  3214. }
  3215. }
  3216. //
  3217. // Send a single burst of packets.
  3218. // An asynchronous call will return to the caller; an ordinary call
  3219. // will loop until the call is complete.
  3220. //
  3221. SetFragmentLengths();
  3222. SetState(CallSendReceive);
  3223. Status = PushBuffer(Message);
  3224. if (Status)
  3225. {
  3226. LogEvent(SU_CCALL, EV_BUFFER_OUT, this, Message->Buffer, Message->BufferLength);
  3227. LogError(SU_CCALL, EV_STATUS, this, 0, Status);
  3228. FreePipeBuffer(Message);
  3229. return AfterSendReceive(Message, Status);
  3230. }
  3231. ASSERT( !Message->Buffer );
  3232. ASSERT( !Message->BufferLength );
  3233. while (RPC_S_OK == Status && FALSE == fReceivedAllFragments)
  3234. {
  3235. Status = ReceiveSinglePacket();
  3236. }
  3237. if (Status)
  3238. {
  3239. LogError(SU_CCALL, EV_STATUS, this, 0, Status);
  3240. }
  3241. if (RPC_S_OK == Status)
  3242. {
  3243. Status = AssembleBufferFromPackets(Message, this);
  3244. }
  3245. //
  3246. // Depending upon circumstances, AfterSendReceive() may cause the ccall,
  3247. // the association, and/or the binding handle to be freed.
  3248. //
  3249. SetState(CallQuiescent);
  3250. return AfterSendReceive(Message, Status);
  3251. }
  3252. RPC_STATUS
  3253. DG_CCALL::AttemptAutoReconnect()
  3254. {
  3255. RPC_STATUS Status;
  3256. ASSERT( State == CallSend || State == CallSendReceive ||
  3257. (State == CallReceive && !fRetransmitted && SendWindowBase == 0
  3258. ) );
  3259. /*
  3260. If the call's association has the error flag set, look for a follow-up
  3261. association, otherwise create a follow-up association.
  3262. link the binding handle to the new association, and ask it for a connection
  3263. to be associated with the existing connection's thread ID. Move this call
  3264. and successors to the new connection, send some packets, and return
  3265. to the packet loop.
  3266. */
  3267. PDG_CCONNECTION OldConnection = Connection;
  3268. PDG_CCONNECTION NewConnection;
  3269. //
  3270. // To avoid a deadlock, we must release the connection mutex before
  3271. // taking the binding mutex. The fBusy flag prevents another thread
  3272. // from using it.
  3273. //
  3274. OldConnection->fError = TRUE;
  3275. OldConnection->fBusy = TRUE;
  3276. OldConnection->MutexClear();
  3277. NewConnection = OldConnection->BindingHandle->GetReplacementConnection(OldConnection, InterfacePointer);
  3278. if (!NewConnection)
  3279. {
  3280. OldConnection->MutexRequest();
  3281. return RPC_S_CALL_FAILED_DNE;
  3282. }
  3283. //
  3284. // We now own NewConnection's mutex. Transfer calls to be retried.
  3285. //
  3286. OldConnection->MutexRequest();
  3287. Status = OldConnection->TransferCallsToNewConnection(this, NewConnection);
  3288. ASSERT( !Status );
  3289. if (FALSE == SourceEndpoint->Async)
  3290. {
  3291. //
  3292. // Get a fresh endpoint to avoid a race with any ICMP rejects.
  3293. // If that fails, leave the old endpoint in place and bail out of the call.
  3294. //
  3295. DG_ENDPOINT * OldEndpoint = SourceEndpoint;
  3296. SourceEndpoint = 0;
  3297. Status = GetEndpoint(OldEndpoint->Flags);
  3298. OldEndpoint->Flags |= PENALTY_BOX;
  3299. if (Status)
  3300. {
  3301. SourceEndpoint = OldEndpoint;
  3302. return Status;
  3303. }
  3304. EndpointManager->ReleaseEndpoint(OldEndpoint);
  3305. }
  3306. //
  3307. // Attempt the call again.
  3308. //
  3309. LastReceiveTime = GetTickCount();
  3310. Status = SendSomeFragments();
  3311. return Status;
  3312. }
  3313. RPC_STATUS
  3314. DG_CCALL::ReceiveSinglePacket()
  3315. {
  3316. RPC_STATUS Status;
  3317. PDG_PACKET Packet = 0;
  3318. DG_TRANSPORT_ADDRESS ReceiveAddress = 0;
  3319. Connection->MutexClear();
  3320. unsigned Length = 0;
  3321. void * Buffer = 0;
  3322. Status = Connection->TransportInterface->SyncReceive(
  3323. &SourceEndpoint->TransportEndpoint,
  3324. &ReceiveAddress,
  3325. &Length,
  3326. &Buffer,
  3327. ReceiveTimeout
  3328. );
  3329. if (Buffer)
  3330. {
  3331. Packet = DG_PACKET::FromPacketHeader(Buffer);
  3332. Packet->DataLength = Length;
  3333. }
  3334. Connection->MutexRequest();
  3335. if (Status == RPC_P_HOST_DOWN)
  3336. {
  3337. RpcpErrorAddRecord( EEInfoGCRuntime,
  3338. Status,
  3339. EEInfoDLDG_CCALL__ReceiveSinglePacket10
  3340. );
  3341. return Status;
  3342. }
  3343. //
  3344. // If the transport tells us the server is not present (ICMP reject)
  3345. // then we can try auto-reconnect - as long as there is no possibility
  3346. // that the server crashed while executing our stub.
  3347. //
  3348. if (Status == RPC_P_PORT_DOWN)
  3349. {
  3350. RpcpErrorAddRecord( EEInfoGCRuntime,
  3351. Status,
  3352. EEInfoDLDG_CCALL__ReceiveSinglePacket20,
  3353. (ULONG) Connection->fAutoReconnect,
  3354. (ULONG) BufferFlags
  3355. );
  3356. if (!Connection->fAutoReconnect &&
  3357. (!fRetransmitted || (BufferFlags & RPC_NCA_FLAGS_IDEMPOTENT)))
  3358. {
  3359. Status = AttemptAutoReconnect();
  3360. return Status;
  3361. }
  3362. ASSERT( !Packet && !ReceiveAddress );
  3363. return Status;
  3364. }
  3365. if (Status == RPC_P_OVERSIZE_PACKET)
  3366. {
  3367. #ifdef DEBUGRPC
  3368. PrintToDebugger("RPC DG: packet is too large\n");
  3369. #endif
  3370. Packet->Flags |= DG_PF_PARTIAL;
  3371. Status = RPC_S_OK;
  3372. }
  3373. else
  3374. {
  3375. ASSERT( !Packet || Packet->DataLength <= Packet->MaxDataLength );
  3376. }
  3377. if (Status == RPC_S_OK)
  3378. {
  3379. LogEvent(SU_CCALL, EV_PKT_IN, this, (void *) 0, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  3380. do
  3381. {
  3382. //
  3383. // Request packets are special.
  3384. //
  3385. if (Packet->Header.PacketType == DG_REQUEST)
  3386. {
  3387. Status = StandardPacketChecks(Packet);
  3388. if (Status)
  3389. {
  3390. LogError(SU_CCALL, EV_PKT_IN, this, (void *) 1, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  3391. FreePacket(Packet);
  3392. break;
  3393. }
  3394. if (Packet->Header.AuthProto != 0)
  3395. {
  3396. LogError(SU_CCALL, EV_PKT_IN, this, (void *) 2, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  3397. FreePacket(Packet);
  3398. break;
  3399. }
  3400. if (Packet->Flags & DG_PF_PARTIAL)
  3401. {
  3402. LogError(SU_CCALL, EV_PKT_IN, this, (void *) 3, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  3403. FreePacket(Packet);
  3404. break;
  3405. }
  3406. LogEvent(SU_CCALL, EV_PKT_IN, this, (void *) 4, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  3407. Connection->ServerResponded = TRUE;
  3408. Status = DealWithRequest(Packet, ReceiveAddress);
  3409. if (Status)
  3410. {
  3411. //
  3412. // Make sure that the call times out in a reasonable time period.
  3413. //
  3414. if (long(GetTickCount()) - LastReceiveTime > TimeoutLimit)
  3415. {
  3416. LogError(SU_CCALL, EV_STATUS, this, (void *) 7, RPC_P_TIMEOUT);
  3417. SendQuit();
  3418. return RPC_P_TIMEOUT;
  3419. }
  3420. }
  3421. return RPC_S_OK;
  3422. }
  3423. Status = StandardPacketChecks(Packet);
  3424. if (Status)
  3425. {
  3426. LogError(SU_CCALL, EV_PKT_IN, this, (void *) 5, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  3427. FreePacket(Packet);
  3428. if (Status == NCA_STATUS_VERSION_MISMATCH)
  3429. {
  3430. Status = 0;
  3431. }
  3432. break;
  3433. }
  3434. if (Packet->Header.SequenceNumber != SequenceNumber ||
  3435. Connection->ActivityNode.Uuid.MatchUuid(&Packet->Header.ActivityId))
  3436. {
  3437. LogEvent(SU_CCALL, EV_PKT_IN, this, (void *) 6, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  3438. FreePacket(Packet);
  3439. break;
  3440. }
  3441. Status = Connection->UpdateServerAddress(Packet, ReceiveAddress);
  3442. if (Status)
  3443. {
  3444. break;
  3445. }
  3446. Status = DispatchPacket(Packet);
  3447. }
  3448. while ( 0 );
  3449. }
  3450. else
  3451. {
  3452. ASSERT( !Packet && !ReceiveAddress );
  3453. if (SequenceNumber <= Connection->CurrentSequenceNumber())
  3454. {
  3455. if (!TimeoutCount)
  3456. {
  3457. ReceiveTimeout = 500;
  3458. }
  3459. ++TimeoutCount;
  3460. //
  3461. // Shorten the burst length.
  3462. //
  3463. SendBurstLength = (1+SendBurstLength)/2;
  3464. if (Status == RPC_P_TIMEOUT)
  3465. {
  3466. LogEvent(SU_CCALL, EV_STATUS, this, 0, Status);
  3467. IncreaseReceiveTimeout();
  3468. }
  3469. else
  3470. {
  3471. RpcpErrorAddRecord( EEInfoGCRuntime,
  3472. Status,
  3473. EEInfoDLDG_CCALL__ReceiveSinglePacket30
  3474. );
  3475. LogError(SU_CCALL, EV_STATUS, this, 0, Status);
  3476. //
  3477. // Perhaps it's a transient error. Wait a moment and try again.
  3478. //
  3479. #ifdef DEBUGRPC
  3480. if (Status != RPC_S_OUT_OF_RESOURCES &&
  3481. Status != RPC_S_OUT_OF_MEMORY &&
  3482. Status != RPC_P_RECEIVE_FAILED )
  3483. {
  3484. DbgPrint("RPC: d/g receive status %x\n"
  3485. "Please send the error code to jroberts, and hit 'g'",
  3486. Status
  3487. );
  3488. RpcpBreakPoint();
  3489. }
  3490. #endif
  3491. Sleep(500);
  3492. }
  3493. }
  3494. Status = DealWithTimeout();
  3495. }
  3496. return Status;
  3497. }
  3498. RPC_STATUS
  3499. DG_CCALL::AsyncSend(
  3500. PRPC_MESSAGE Message
  3501. )
  3502. {
  3503. if (AsyncStatus != RPC_S_OK &&
  3504. AsyncStatus != RPC_S_ASYNC_CALL_PENDING )
  3505. {
  3506. Connection->MutexRequest();
  3507. return AfterSendReceive(Message, AsyncStatus);
  3508. }
  3509. return Send(Message);
  3510. }
  3511. RPC_STATUS
  3512. DG_CCALL::Send(
  3513. PRPC_MESSAGE Message
  3514. )
  3515. {
  3516. if (Message->RpcFlags & RPC_BUFFER_ASYNC)
  3517. {
  3518. LogEvent(SU_CCALL, EV_PROC, this, Message->Buffer, 'A' + (('S' + (('n' + ('d' << 8)) << 8)) << 8));
  3519. }
  3520. else
  3521. {
  3522. LogEvent(SU_CCALL, EV_PROC, this, Message->Buffer, 'S' + (('e' + (('n' + ('d' << 8)) << 8)) << 8));
  3523. }
  3524. LogEvent(SU_CCALL, EV_BUFFER_IN, this, Message->Buffer, Message->BufferLength);
  3525. RPC_STATUS Status = RPC_S_OK;
  3526. Connection->MutexRequest();
  3527. //
  3528. // See DG_CCALL::CancelDelayedSend for details.
  3529. //
  3530. while (State == CallCancellingSend)
  3531. {
  3532. Connection->MutexClear();
  3533. Sleep(1);
  3534. Connection->MutexRequest();
  3535. }
  3536. if (State == CallInit)
  3537. {
  3538. Status = BeforeSendReceive(Message);
  3539. if (RPC_S_OK != Status)
  3540. {
  3541. Connection->MutexClear();
  3542. FreeBuffer(Message);
  3543. return Status;
  3544. }
  3545. }
  3546. SetFragmentLengths();
  3547. if ((Message->RpcFlags & RPC_BUFFER_PARTIAL) &&
  3548. Message->BufferLength < (ULONG) MaxFragmentSize * SendWindowSize )
  3549. {
  3550. Status = RPC_S_SEND_INCOMPLETE;
  3551. Connection->IncrementRefCount();
  3552. if (pAsync)
  3553. {
  3554. IssueNotification( RpcSendComplete );
  3555. }
  3556. Connection->DecrementRefCount();
  3557. LogEvent(SU_CCALL, EV_STATUS, this, 0, Status);
  3558. return Status;
  3559. }
  3560. SetState(CallSend);
  3561. Status = PushBuffer(Message);
  3562. if (Status)
  3563. {
  3564. FreePipeBuffer(Message);
  3565. Status = AfterSendReceive(Message, Status);
  3566. LogEvent(SU_CCALL, EV_BUFFER_OUT, this, Message->Buffer, Message->BufferLength);
  3567. LogError(SU_CCALL, EV_STATUS, this, 0, Status);
  3568. return Status;
  3569. }
  3570. if (pAsync)
  3571. {
  3572. Connection->MutexClear();
  3573. }
  3574. else
  3575. {
  3576. while (RPC_S_OK == Status && !IsBufferAcknowledged())
  3577. {
  3578. Status = ReceiveSinglePacket();
  3579. }
  3580. SetState(CallQuiescent);
  3581. if (Status == RPC_S_OK)
  3582. {
  3583. Connection->MutexClear();
  3584. }
  3585. else
  3586. {
  3587. Status = AfterSendReceive(Message, Status);
  3588. }
  3589. }
  3590. if (!Status && Message->BufferLength)
  3591. {
  3592. Status = RPC_S_SEND_INCOMPLETE;
  3593. }
  3594. LogEvent(SU_CCALL, EV_BUFFER_OUT, this, Message->Buffer, Message->BufferLength);
  3595. LogEvent(SU_CCALL, EV_STATUS, this, 0, Status);
  3596. return Status;
  3597. }
  3598. RPC_STATUS
  3599. DG_CCALL::MaybeSendReceive(
  3600. IN OUT PRPC_MESSAGE Message
  3601. )
  3602. /*++
  3603. Routine Description:
  3604. Sends a [maybe], [broadcast, maybe] or [message] call.
  3605. Arguments:
  3606. Message - Message to be sent.
  3607. Return Value:
  3608. RPC_S_OK
  3609. <error from Transport>
  3610. --*/
  3611. {
  3612. RPC_STATUS Status = RPC_S_OK;
  3613. //
  3614. // Make sure this fits into a single packet.
  3615. //
  3616. if ( !(Message->RpcFlags & RPCFLG_MESSAGE)
  3617. && (Message->BufferLength > MaxFragmentSize) )
  3618. {
  3619. FreePipeBuffer(Message);
  3620. return RPC_S_OK;
  3621. }
  3622. //
  3623. // [maybe] calls are implicitly idempotent.
  3624. //
  3625. Message->RpcFlags |= RPC_NCA_FLAGS_IDEMPOTENT;
  3626. //
  3627. // Build the request packet.
  3628. //
  3629. PDG_PACKET Packet = DG_PACKET::FromStubData(Message->Buffer);
  3630. PNCA_PACKET_HEADER Header = &Packet->Header;
  3631. *Header = pSavedPacket->Header;
  3632. BuildNcaPacketHeader(Header, Message);
  3633. Header->SetPacketBodyLen (Message->BufferLength);
  3634. Header->SetFragmentNumber(0);
  3635. Header->AuthProto = 0;
  3636. Header->ServerBootTime = 0;
  3637. AddSerialNumber(Header);
  3638. //
  3639. // Send the packet.
  3640. //
  3641. LogEvent(SU_CCALL, EV_PKT_OUT, this, 0, 0);
  3642. Status = SendSecurePacket(SourceEndpoint,
  3643. Connection->Association->InqServerAddress(),
  3644. Header,
  3645. 0,
  3646. 0
  3647. );
  3648. FreePipeBuffer(Message);
  3649. Message->BufferLength = 0;
  3650. if (Message->RpcFlags & RPCFLG_MESSAGE)
  3651. {
  3652. return Status;
  3653. }
  3654. else
  3655. {
  3656. return RPC_S_OK;
  3657. }
  3658. }
  3659. RPC_STATUS
  3660. DG_CCALL::AsyncReceive(
  3661. PRPC_MESSAGE Message,
  3662. unsigned MinimumSize
  3663. )
  3664. {
  3665. LogEvent(SU_CCALL, EV_PROC, this, IntToPtr(MinimumSize), 0x76635241);
  3666. LogEvent(SU_CCALL, EV_BUFFER_IN, this, Message->Buffer, Message->BufferLength);
  3667. ASSERT( pAsync && (Message->RpcFlags & RPC_BUFFER_ASYNC) );
  3668. Connection->MutexRequest();
  3669. if (State == CallSend)
  3670. {
  3671. Connection->MutexClear();
  3672. return RPC_S_ASYNC_CALL_PENDING;
  3673. }
  3674. //
  3675. // See DG_CCALL::CancelDelayedSend for details.
  3676. //
  3677. while (State == CallCancellingSend)
  3678. {
  3679. Connection->MutexClear();
  3680. Sleep(1);
  3681. Connection->MutexRequest();
  3682. }
  3683. if (AsyncStatus != RPC_S_OK &&
  3684. AsyncStatus != RPC_S_ASYNC_CALL_PENDING )
  3685. {
  3686. return AfterSendReceive(Message, AsyncStatus);
  3687. }
  3688. if (!fReceivedAllFragments &&
  3689. !(ConsecutiveDataBytes >= MinimumSize && (Message->RpcFlags & RPC_BUFFER_PARTIAL)))
  3690. {
  3691. if (Message->RpcFlags & RPC_BUFFER_NONOTIFY)
  3692. {
  3693. // just checking
  3694. }
  3695. else
  3696. {
  3697. SetState(CallReceive);
  3698. PipeReceiveSize = MinimumSize;
  3699. }
  3700. Connection->MutexClear();
  3701. LogEvent(SU_CCALL, EV_STATUS, this, 0, RPC_S_ASYNC_CALL_PENDING);
  3702. return RPC_S_ASYNC_CALL_PENDING;
  3703. }
  3704. RPC_STATUS Status = RPC_S_OK;
  3705. Status = AssembleBufferFromPackets(Message, this);
  3706. LogEvent(SU_CCALL, EV_STATUS, this, 0, Status);
  3707. LogEvent(SU_CCALL, EV_BUFFER_OUT, this, Message->Buffer, Message->BufferLength);
  3708. if (0 == (Message->RpcFlags & RPC_BUFFER_PARTIAL) ||
  3709. (Message->RpcFlags & RPC_BUFFER_COMPLETE) ||
  3710. RPC_S_OK != Status )
  3711. {
  3712. Status = AfterSendReceive(Message, Status);
  3713. }
  3714. else
  3715. {
  3716. Connection->MutexClear();
  3717. }
  3718. return Status;
  3719. }
  3720. RPC_STATUS
  3721. DG_CCALL::Receive(
  3722. PRPC_MESSAGE Message,
  3723. unsigned MinimumSize
  3724. )
  3725. {
  3726. LogEvent(SU_CCALL, EV_PROC, this, IntToPtr(MinimumSize), 0x76636552);
  3727. LogEvent(SU_CCALL, EV_BUFFER_IN, this, Message->Buffer, Message->BufferLength);
  3728. RPC_STATUS Status = RPC_S_OK;
  3729. Connection->MutexRequest();
  3730. SetState(CallReceive);
  3731. while (RPC_S_OK == Status &&
  3732. !fReceivedAllFragments &&
  3733. !(ConsecutiveDataBytes >= MinimumSize && (Message->RpcFlags & RPC_BUFFER_PARTIAL)))
  3734. {
  3735. Status = ReceiveSinglePacket();
  3736. }
  3737. if (RPC_S_OK == Status)
  3738. {
  3739. Status = AssembleBufferFromPackets(Message, this);
  3740. }
  3741. LogEvent(SU_CCALL, EV_STATUS, this, 0, RPC_S_OK);
  3742. LogEvent(SU_CCALL, EV_BUFFER_OUT, this, Message->Buffer, Message->BufferLength);
  3743. if (0 == (Message->RpcFlags & RPC_BUFFER_PARTIAL) ||
  3744. (Message->RpcFlags & RPC_BUFFER_COMPLETE) ||
  3745. RPC_S_OK != Status )
  3746. {
  3747. Status = AfterSendReceive(Message, Status);
  3748. }
  3749. else
  3750. {
  3751. Connection->MutexClear();
  3752. }
  3753. return Status;
  3754. }
  3755. BOOL
  3756. DG_CCALL::IssueNotification (
  3757. IN RPC_ASYNC_EVENT Event
  3758. )
  3759. {
  3760. Connection->Mutex.VerifyOwned();
  3761. LogEvent(SU_CCALL, EV_NOTIFY, this, (void *) Event, AsyncStatus);
  3762. if (State == CallInit ||
  3763. State == CallComplete ||
  3764. State == CallCancellingSend )
  3765. {
  3766. #ifdef DEBUGRPC
  3767. DbgPrint("RPC: redundant notification on ccall %lx\n", this);
  3768. #endif
  3769. return TRUE;
  3770. }
  3771. if (Event == RpcCallComplete)
  3772. {
  3773. SetState(CallComplete);
  3774. }
  3775. else
  3776. {
  3777. SetState(CallQuiescent);
  3778. }
  3779. if (pAsync->NotificationType == RpcNotificationTypeApc)
  3780. {
  3781. IncrementRefCount();
  3782. }
  3783. int i;
  3784. for (i=1; i < 3; ++i)
  3785. {
  3786. if (CALL::IssueNotification(Event))
  3787. {
  3788. return TRUE;
  3789. }
  3790. Sleep(200);
  3791. }
  3792. DecrementRefCountAndKeepMutex();
  3793. return FALSE;
  3794. }
  3795. void
  3796. DG_CCALL::FreeAPCInfo (
  3797. IN RPC_APC_INFO *pAPCInfo
  3798. )
  3799. {
  3800. LogEvent(SU_CCALL, EV_APC, this);
  3801. Connection->MutexRequest();
  3802. CALL::FreeAPCInfo(pAPCInfo);
  3803. DecrementRefCount();
  3804. }
  3805. RPC_STATUS
  3806. DG_CCALL::CancelAsyncCall (
  3807. IN BOOL fAbort
  3808. )
  3809. {
  3810. Connection->MutexRequest();
  3811. if (State == CallInit ||
  3812. State == CallComplete ||
  3813. State == CallCancellingSend )
  3814. {
  3815. Connection->MutexClear();
  3816. return RPC_S_OK;
  3817. }
  3818. RpcpErrorAddRecord( EEInfoGCRuntime,
  3819. RPC_S_CALL_CANCELLED,
  3820. EEInfoDLDG_CCALL__CancelAsyncCall10,
  3821. (ULONG) fAbort
  3822. );
  3823. SendQuit();
  3824. Connection->IncrementRefCount();
  3825. if (fAbort)
  3826. {
  3827. CancelDelayedSend();
  3828. CleanupReceiveWindow();
  3829. AsyncStatus = RPC_S_CALL_CANCELLED;
  3830. IssueNotification( RpcCallComplete );
  3831. }
  3832. else
  3833. {
  3834. CancelPending = TRUE;
  3835. }
  3836. Connection->DecrementRefCount();
  3837. return RPC_S_OK;
  3838. }
  3839. RPC_STATUS
  3840. DG_CCALL::DealWithRequest(
  3841. IN PDG_PACKET Packet,
  3842. IN DG_TRANSPORT_ADDRESS ReceiveAddress
  3843. )
  3844. {
  3845. RPC_STATUS Status = RPC_S_OK;
  3846. RPC_MESSAGE CallbackMessage;
  3847. PNCA_PACKET_HEADER OriginalHeader;
  3848. DG_CLIENT_CALLBACK Callback;
  3849. //
  3850. // Save the server data rep for challenge response processing.
  3851. //
  3852. Connection->Association->ServerDataRep = 0x00ffffff & (*(unsigned long *) (Packet->Header.DataRep));
  3853. Callback.LocalEndpoint = SourceEndpoint;
  3854. Callback.Connection = Connection;
  3855. Callback.RemoteAddress = ReceiveAddress;
  3856. Callback.Request = Packet;
  3857. return DispatchCallbackRequest(&Callback);
  3858. }
  3859. RPC_STATUS
  3860. DG_CCALL::DealWithFack(
  3861. PDG_PACKET pPacket
  3862. )
  3863. {
  3864. BOOL Updated;
  3865. RPC_STATUS Status;
  3866. SendBurstLength += 1;
  3867. Status = UpdateSendWindow(pPacket, &Updated);
  3868. if (Updated)
  3869. {
  3870. Connection->UpdateAssociation();
  3871. }
  3872. FreePacket(pPacket);
  3873. if (Status != RPC_P_PORT_DOWN &&
  3874. Status != RPC_P_HOST_DOWN)
  3875. {
  3876. Status = 0;
  3877. }
  3878. return Status;
  3879. }
  3880. RPC_STATUS
  3881. DG_CCALL::DealWithResponse(
  3882. PDG_PACKET pPacket
  3883. )
  3884. {
  3885. #ifdef DBG
  3886. if (!Connection->TransportInterface->IsMessageTransport)
  3887. {
  3888. ASSERT( !(pPacket->GetPacketBodyLen() % 8) ||
  3889. !(pPacket->Header.PacketFlags & DG_PF_FRAG) ||
  3890. (pPacket->Header.PacketFlags & DG_PF_LAST_FRAG) );
  3891. }
  3892. #endif
  3893. Connection->Association->LastReceiveTime = LastReceiveTime;
  3894. //
  3895. // The first response is implicitly a FACK for the final request packet.
  3896. //
  3897. MarkAllPacketsReceived();
  3898. //
  3899. // Add packet to received list, and send a fack if necessary.
  3900. //
  3901. if (FALSE == UpdateReceiveWindow(pPacket))
  3902. {
  3903. FreePacket(pPacket);
  3904. }
  3905. Connection->MaybeTransmitNextCall();
  3906. return RPC_S_OK;
  3907. }
  3908. RPC_STATUS
  3909. DG_CCALL::DealWithWorking(
  3910. PDG_PACKET pPacket
  3911. )
  3912. {
  3913. Connection->Association->LastReceiveTime = LastReceiveTime;
  3914. //
  3915. // WORKING is implicitly a FACK for the final request packet.
  3916. //
  3917. MarkAllPacketsReceived();
  3918. Connection->MaybeTransmitNextCall();
  3919. //
  3920. // Reduce server load by increasing the timeout during long calls.
  3921. //
  3922. IncreaseReceiveTimeout();
  3923. FreePacket(pPacket);
  3924. return RPC_S_OK;
  3925. }
  3926. void
  3927. DG_CCALL::IncreaseReceiveTimeout()
  3928. {
  3929. if (Connection->TransportInterface->IsMessageTransport)
  3930. {
  3931. return;
  3932. }
  3933. ReceiveTimeout *= 2;
  3934. if (ReceiveTimeout > 16000)
  3935. {
  3936. ReceiveTimeout = 16000;
  3937. }
  3938. if (long(GetTickCount()) - LastReceiveTime + ReceiveTimeout > TimeoutLimit)
  3939. {
  3940. ReceiveTimeout = 1 + TimeoutLimit - (GetTickCount() - LastReceiveTime);
  3941. if (ReceiveTimeout < 0)
  3942. {
  3943. ReceiveTimeout = 0;
  3944. }
  3945. }
  3946. long CancelTimeout = ThreadGetRpcCancelTimeout();
  3947. if (CancelTimeout != RPC_C_CANCEL_INFINITE_TIMEOUT)
  3948. {
  3949. CancelTimeout *= 1000;
  3950. if (CancelTimeout < 2000)
  3951. {
  3952. CancelTimeout = 2000;
  3953. }
  3954. if (ReceiveTimeout > CancelTimeout)
  3955. {
  3956. ReceiveTimeout = CancelTimeout;
  3957. }
  3958. }
  3959. }
  3960. RPC_STATUS
  3961. DG_CCALL::DealWithNocall(
  3962. PDG_PACKET pPacket
  3963. )
  3964. {
  3965. BOOL Used;
  3966. BOOL Updated;
  3967. RPC_STATUS Status;
  3968. if (pPacket->GetPacketBodyLen() == 0)
  3969. {
  3970. //
  3971. // Don't trust the FragmentNumber field.
  3972. //
  3973. pPacket->SetFragmentNumber(0xffff);
  3974. }
  3975. Status = UpdateSendWindow(pPacket, &Updated);
  3976. if (Updated)
  3977. {
  3978. Connection->UpdateAssociation();
  3979. }
  3980. FreePacket(pPacket);
  3981. //
  3982. // Ordinarily a NOCALL means the request wasn't received, and we should
  3983. // fail the call after several in a row. But a NOCALL with window size 0
  3984. // means the request was received and queued, and we want to back off as
  3985. // for a WORKING packet.
  3986. //
  3987. if (SendWindowSize != 0)
  3988. {
  3989. ++UnansweredRequestCount;
  3990. }
  3991. // IncreaseReceiveTimeout();
  3992. if (UnansweredRequestCount > 4)
  3993. {
  3994. SendQuit();
  3995. return RPC_P_PORT_DOWN;
  3996. }
  3997. if (Status != RPC_P_PORT_DOWN &&
  3998. Status != RPC_P_HOST_DOWN)
  3999. {
  4000. Status = 0;
  4001. }
  4002. return Status;
  4003. }
  4004. RPC_STATUS
  4005. DG_CCALL::ProcessFaultOrRejectData(
  4006. PDG_PACKET Packet
  4007. )
  4008. {
  4009. RPC_STATUS Status = RPC_S_CALL_FAILED;
  4010. //
  4011. // Read the standard OSF error code.
  4012. //
  4013. if (Packet->GetPacketBodyLen() >= sizeof(unsigned long))
  4014. {
  4015. unsigned long Error = * (unsigned long *) Packet->Header.Data;
  4016. if (NeedsByteSwap(&Packet->Header))
  4017. {
  4018. Error = RpcpByteSwapLong(Error);
  4019. }
  4020. Status = MapFromNcaStatusCode(Error);
  4021. LogEvent( SU_CCALL, EV_STATUS, this, 0, Error);
  4022. }
  4023. //
  4024. // Read the extended error info, if present.
  4025. //
  4026. if (Packet->GetPacketBodyLen() > sizeof(EXTENDED_FAULT_BODY))
  4027. {
  4028. EXTENDED_FAULT_BODY * body = (EXTENDED_FAULT_BODY *) Packet->Header.Data;
  4029. if (body->Magic == DG_EE_MAGIC_VALUE)
  4030. {
  4031. ExtendedErrorInfo *EEInfo;
  4032. UnpickleEEInfoFromBuffer( body->EeInfo,
  4033. Packet->GetPacketBodyLen() - sizeof(EXTENDED_FAULT_BODY)
  4034. );
  4035. EEInfo = RpcpGetEEInfo();
  4036. if (EEInfo && pAsync)
  4037. {
  4038. ASSERT(this->EEInfo == NULL);
  4039. // move the eeinfo to the call. Even though it is possible
  4040. // that the call will be completed on this thread, it is
  4041. // still ok, as we will move it back during completion
  4042. this->EEInfo = EEInfo;
  4043. RpcpClearEEInfo();
  4044. }
  4045. }
  4046. }
  4047. return Status;
  4048. }
  4049. RPC_STATUS
  4050. DG_CCALL::DealWithFault(
  4051. PDG_PACKET pPacket
  4052. )
  4053. {
  4054. RPC_STATUS Status = ProcessFaultOrRejectData(pPacket);
  4055. FreePacket(pPacket);
  4056. SendAck();
  4057. return Status;
  4058. }
  4059. RPC_STATUS
  4060. DG_CCALL::DealWithReject(
  4061. PDG_PACKET pPacket
  4062. )
  4063. {
  4064. RPC_STATUS Status = ProcessFaultOrRejectData(pPacket);
  4065. FreePacket(pPacket);
  4066. if (!fRetransmitted || (BufferFlags & RPC_NCA_FLAGS_IDEMPOTENT))
  4067. {
  4068. if (Status == NCA_STATUS_WRONG_BOOT_TIME ||
  4069. (!Connection->fAutoReconnect && Status == RPC_S_CALL_FAILED_DNE))
  4070. {
  4071. Status = AttemptAutoReconnect();
  4072. }
  4073. }
  4074. return Status;
  4075. }
  4076. RPC_STATUS
  4077. DG_CCALL::SendQuit(
  4078. )
  4079. {
  4080. QUIT_BODY_0 * pBody = (QUIT_BODY_0 *) pSavedPacket->Header.Data;
  4081. pSavedPacket->Header.PacketType = DG_QUIT;
  4082. pSavedPacket->Header.PacketFlags &= DG_PF_IDEMPOTENT;
  4083. pSavedPacket->SetPacketBodyLen(sizeof(QUIT_BODY_0));
  4084. AddSerialNumber(&pSavedPacket->Header);
  4085. pBody->Version = 0;
  4086. pBody->EventId = CancelEventId;
  4087. unsigned Frag = (pSavedPacket->Header.PacketType << 16) | pSavedPacket->GetFragmentNumber();
  4088. LogEvent(SU_CCALL, EV_PKT_OUT, this, 0, Frag);
  4089. return Connection->SealAndSendPacket(SourceEndpoint, 0, &pSavedPacket->Header, 0);
  4090. }
  4091. RPC_STATUS
  4092. DG_CCALL::DealWithQuack(
  4093. PDG_PACKET pPacket
  4094. )
  4095. {
  4096. if (FALSE == CancelPending)
  4097. {
  4098. FreePacket(pPacket);
  4099. return RPC_S_OK;
  4100. }
  4101. QUACK_BODY_0 * pBody = (QUACK_BODY_0 *) pPacket->Header.Data;
  4102. if (0 == pPacket->GetPacketBodyLen())
  4103. {
  4104. //
  4105. // The server orphaned a call. I hope it is the current one.
  4106. //
  4107. goto ok;
  4108. }
  4109. //
  4110. // The ver 0 quack packet contains two ulongs and a uchar; I'd like to
  4111. // test for sizeof(quack body) but C++ likes to pad structure sizes
  4112. // to 0 mod 4. Hence the explicit test for length < 9.
  4113. //
  4114. if (pPacket->GetPacketBodyLen() < 9 ||
  4115. pBody->Version != 0)
  4116. {
  4117. #ifdef DEBUGRPC
  4118. PrintToDebugger("RPC DG: unknown QUACK format: version 0x%lx, length 0x%hx\n",
  4119. pBody->Version, pPacket->GetPacketBodyLen()
  4120. );
  4121. #endif
  4122. FreePacket(pPacket);
  4123. return RPC_S_OK;
  4124. }
  4125. if (pBody->EventId != CancelEventId)
  4126. {
  4127. #ifdef DEBUGRPC
  4128. PrintToDebugger("RPC DG: ignoring unknown QUACK event id 0x%lx\n",
  4129. pBody->EventId
  4130. );
  4131. #endif
  4132. FreePacket(pPacket);
  4133. return RPC_S_OK;
  4134. }
  4135. ok:
  4136. CancelPending = FALSE;
  4137. FreePacket(pPacket);
  4138. return RPC_S_OK;
  4139. }
  4140. RPC_STATUS
  4141. DG_CCONNECTION::SealAndSendPacket(
  4142. IN DG_ENDPOINT * SourceEndpoint,
  4143. IN DG_TRANSPORT_ADDRESS UnusedRemoteAddress,
  4144. IN UNALIGNED NCA_PACKET_HEADER * Header,
  4145. IN unsigned long DataOffset
  4146. )
  4147. /*
  4148. - NT 3.5 did not support secure datagram RPC.
  4149. - NT 3.51 and NT 4.0 servers will probably fail to decrypt a multifragment
  4150. request if some fragments are encrypted with one context and others use a
  4151. different context, since they decrypt all the packets using the last active
  4152. context instead of looking at each packet's 'ksno' field.
  4153. - NT 3.51 and NT 4.0 servers dispose of stale contexts only when the activity
  4154. is deleted.
  4155. - NT 3.51 and NT 4.0 clients use only one set of security parameters
  4156. (provider, level, principal name) per connection. The only time the ksno
  4157. changes is on NT 4.0 when a Kerberos context expires and must be renewed.
  4158. - NT 3.51 and NT 4.0 clients do not notice if ksno rises above 0xff. If it
  4159. does, the next call will fail because the server sees only the lowest 8 bits
  4160. and mistakenly reuses another context.
  4161. - NT 3.51 clients do not notice whether the thread is impersonating, so they
  4162. can mistakenly reuse a connection if all info except the username is identical.
  4163. - NT 3.51 clients mistakenly send [maybe] calls with an auth trailer, if the
  4164. underlying connection is secure. OSF and NT 4.0 force [maybe] calls insecure.
  4165. */
  4166. {
  4167. ASSERT( 0 == ActivityNode.CompareUuid(&Header->ActivityId) );
  4168. retry_packet:
  4169. RPC_STATUS Status;
  4170. Status = SendSecurePacket(SourceEndpoint,
  4171. Association->InqServerAddress(),
  4172. Header,
  4173. DataOffset,
  4174. ActiveSecurityContext
  4175. );
  4176. if (Status == SEC_E_CONTEXT_EXPIRED)
  4177. {
  4178. Status = InitializeSecurityContext();
  4179. if (RPC_S_OK == Status)
  4180. {
  4181. goto retry_packet;
  4182. }
  4183. }
  4184. return Status;
  4185. }
  4186. RPC_STATUS
  4187. DG_CCONNECTION::InitializeSecurityContext(
  4188. )
  4189. {
  4190. RPC_STATUS RpcStatus = RPC_S_OK;
  4191. delete ActiveSecurityContext;
  4192. if (SecurityContextId > 0xff)
  4193. {
  4194. ActiveSecurityContext = 0;
  4195. return RPC_S_OUT_OF_RESOURCES;
  4196. }
  4197. ActiveSecurityContext = new SECURITY_CONTEXT(&AuthInfo, SecurityContextId, TRUE, &RpcStatus);
  4198. if (0 == ActiveSecurityContext)
  4199. {
  4200. return RPC_S_OUT_OF_MEMORY;
  4201. }
  4202. if (RpcStatus)
  4203. {
  4204. delete ActiveSecurityContext;
  4205. ActiveSecurityContext = 0;
  4206. return RPC_S_OUT_OF_MEMORY;
  4207. }
  4208. ++SecurityContextId;
  4209. SECURITY_BUFFER_DESCRIPTOR BufferDescriptorIn;
  4210. DCE_INIT_SECURITY_INFO InitSecurityInfo;
  4211. SECURITY_BUFFER SecurityBuffersIn[1];
  4212. BufferDescriptorIn.ulVersion = 0;
  4213. BufferDescriptorIn.cBuffers = 1;
  4214. BufferDescriptorIn.pBuffers = SecurityBuffersIn;
  4215. SecurityBuffersIn[0].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
  4216. SecurityBuffersIn[0].pvBuffer = &InitSecurityInfo;
  4217. SecurityBuffersIn[0].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
  4218. InitSecurityInfo.DceSecurityInfo.SendSequenceNumber = 0;
  4219. InitSecurityInfo.DceSecurityInfo.ReceiveSequenceNumber = ActiveSecurityContext->AuthContextId;
  4220. RpcpMemoryCopy(&InitSecurityInfo.DceSecurityInfo.AssociationUuid, &ActivityNode.Uuid, sizeof(UUID));
  4221. InitSecurityInfo.AuthorizationService = AuthInfo.AuthorizationService;
  4222. InitSecurityInfo.PacketType = ~0;
  4223. RpcStatus = ActiveSecurityContext->InitializeFirstTime(
  4224. AuthInfo.Credentials,
  4225. AuthInfo.ServerPrincipalName,
  4226. AuthInfo.AuthenticationLevel,
  4227. &BufferDescriptorIn
  4228. );
  4229. LogEvent(SU_CCONN, EV_SEC_INIT1, this, IntToPtr(RpcStatus), I_RpcGetExtendedError());
  4230. return RpcStatus;
  4231. }
  4232. RPC_STATUS
  4233. DG_CCONNECTION::DealWithAuthCallback(
  4234. IN void * InToken,
  4235. IN long InTokenLength,
  4236. OUT void * OutToken,
  4237. OUT long MaxOutTokenLength,
  4238. OUT long * OutTokenLength
  4239. )
  4240. {
  4241. SECURITY_BUFFER_DESCRIPTOR BufferDescriptorIn;
  4242. SECURITY_BUFFER_DESCRIPTOR BufferDescriptorOut;
  4243. DCE_INIT_SECURITY_INFO InitSecurityInfo;
  4244. SECURITY_BUFFER SecurityBuffersIn [2];
  4245. SECURITY_BUFFER SecurityBuffersOut[2];
  4246. RPC_STATUS Status;
  4247. InitSecurityInfo.DceSecurityInfo.SendSequenceNumber = 0;
  4248. InitSecurityInfo.DceSecurityInfo.ReceiveSequenceNumber = ActiveSecurityContext->AuthContextId;
  4249. ActivityNode.QueryUuid( &InitSecurityInfo.DceSecurityInfo.AssociationUuid );
  4250. InitSecurityInfo.AuthorizationService = AuthInfo.AuthorizationService;
  4251. InitSecurityInfo.PacketType = ~0;
  4252. BufferDescriptorIn.ulVersion = 0;
  4253. BufferDescriptorIn.cBuffers = 2;
  4254. BufferDescriptorIn.pBuffers = SecurityBuffersIn;
  4255. SecurityBuffersIn[0].BufferType = SECBUFFER_TOKEN;
  4256. SecurityBuffersIn[0].pvBuffer = InToken;
  4257. SecurityBuffersIn[0].cbBuffer = InTokenLength;
  4258. SecurityBuffersIn[1].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
  4259. SecurityBuffersIn[1].pvBuffer = &InitSecurityInfo;
  4260. SecurityBuffersIn[1].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
  4261. BufferDescriptorOut.ulVersion = 0;
  4262. BufferDescriptorOut.cBuffers = 1;
  4263. BufferDescriptorOut.pBuffers = SecurityBuffersOut;
  4264. SecurityBuffersOut[0].BufferType = SECBUFFER_TOKEN;
  4265. SecurityBuffersOut[0].pvBuffer = OutToken;
  4266. SecurityBuffersOut[0].cbBuffer = MaxOutTokenLength;
  4267. Status = ActiveSecurityContext->InitializeThirdLeg(
  4268. AuthInfo.Credentials,
  4269. Association->ServerDataRep,
  4270. &BufferDescriptorIn,
  4271. &BufferDescriptorOut
  4272. );
  4273. if (Status != RPC_S_OK)
  4274. {
  4275. LogError(SU_CCONN, EV_SEC_INIT3, this, IntToPtr(Status), I_RpcGetExtendedError());
  4276. *OutTokenLength = 0;
  4277. return (Status);
  4278. }
  4279. else
  4280. {
  4281. LogEvent(SU_CCONN, EV_SEC_INIT3, this, IntToPtr(Status), I_RpcGetExtendedError());
  4282. *OutTokenLength = SecurityBuffersOut[0].cbBuffer;
  4283. }
  4284. //
  4285. // If the result buffer spans multiple packets, return the first and store
  4286. // the complete buffer in the connection for conv_who_are_you_auth_more().
  4287. //
  4288. if (!CurrentCall)
  4289. {
  4290. return 0;
  4291. }
  4292. long MaxData = CurrentCall->SourceEndpoint->Stats.MaxPduSize - sizeof(NCA_PACKET_HEADER) - 0x28;
  4293. if (*OutTokenLength > MaxData)
  4294. {
  4295. if (SecurityBuffer)
  4296. {
  4297. delete SecurityBuffer;
  4298. }
  4299. SecurityBuffer = new unsigned char[ *OutTokenLength ];
  4300. if (!SecurityBuffer)
  4301. {
  4302. *OutTokenLength = 0;
  4303. return NCA_STATUS_REMOTE_OUT_OF_MEMORY;
  4304. }
  4305. memcpy( SecurityBuffer, SecurityBuffersOut[0].pvBuffer, *OutTokenLength );
  4306. SecurityBufferLength = *OutTokenLength;
  4307. *OutTokenLength = MaxData;
  4308. return NCA_STATUS_PARTIAL_CREDENTIALS;
  4309. }
  4310. return (Status);
  4311. }
  4312. RPC_STATUS
  4313. DG_CCONNECTION::DealWithAuthMore(
  4314. IN long Index,
  4315. OUT void * OutToken,
  4316. OUT long MaxOutTokenLength,
  4317. OUT long * OutTokenLength
  4318. )
  4319. {
  4320. if (0 == SecurityBuffer)
  4321. {
  4322. *OutTokenLength = 0;
  4323. return 0;
  4324. }
  4325. if (SecurityBufferLength <= Index)
  4326. {
  4327. *OutTokenLength = 0;
  4328. return 0;
  4329. }
  4330. if (!CurrentCall)
  4331. {
  4332. return 0;
  4333. }
  4334. long MaxData = CurrentCall->SourceEndpoint->Stats.MaxPduSize - sizeof(NCA_PACKET_HEADER) - 0x28;
  4335. *OutTokenLength = SecurityBufferLength - Index;
  4336. if (*OutTokenLength > MaxData)
  4337. {
  4338. *OutTokenLength = MaxData;
  4339. memcpy(OutToken, SecurityBuffer + Index, *OutTokenLength);
  4340. return NCA_STATUS_PARTIAL_CREDENTIALS;
  4341. }
  4342. memcpy(OutToken, SecurityBuffer + Index, *OutTokenLength);
  4343. return 0;
  4344. }
  4345. RPC_STATUS
  4346. DG_CCONNECTION::VerifyPacket(
  4347. DG_PACKET * Packet
  4348. )
  4349. {
  4350. if (AuthInfo.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE ||
  4351. (Packet->Flags & DG_PF_PARTIAL))
  4352. {
  4353. return RPC_S_OK;
  4354. }
  4355. if (!Packet->Header.AuthProto)
  4356. {
  4357. if (!fSecurePacketReceived && Packet->Header.PacketType != DG_RESPONSE)
  4358. {
  4359. return RPC_S_OK;
  4360. }
  4361. if (Packet->Header.PacketType == DG_REJECT ||
  4362. Packet->Header.PacketType == DG_NOCALL)
  4363. {
  4364. return RPC_S_OK;
  4365. }
  4366. return RPC_S_ACCESS_DENIED;
  4367. }
  4368. RPC_STATUS Status;
  4369. PDG_SECURITY_TRAILER Verifier = (PDG_SECURITY_TRAILER) (Packet->Header.Data + Packet->GetPacketBodyLen());
  4370. if (Verifier->key_vers_num == ActiveSecurityContext->AuthContextId)
  4371. {
  4372. Status = VerifySecurePacket(Packet, ActiveSecurityContext);
  4373. }
  4374. // else if (Verifier->key_vers_num == ActiveSecurityContext->AuthContextId - 1)
  4375. // {
  4376. // Status = VerifySecurePacket(Packet, PreviousSecurityContext);
  4377. // }
  4378. else
  4379. {
  4380. Status = RPC_P_CONTEXT_EXPIRED;
  4381. }
  4382. if (RPC_S_OK == Status)
  4383. {
  4384. fSecurePacketReceived = TRUE;
  4385. }
  4386. return Status;
  4387. }
  4388. inline
  4389. int
  4390. DG_CCONNECTION::IsSupportedAuthInfo(
  4391. IN const CLIENT_AUTH_INFO * ClientAuthInfo
  4392. )
  4393. {
  4394. return( AuthInfo.IsSupportedAuthInfo(ClientAuthInfo) );
  4395. }
  4396. int
  4397. DG_CASSOCIATION::CompareWithBinding(
  4398. IN PDG_BINDING_HANDLE Binding
  4399. )
  4400. {
  4401. BOOL Ignored;
  4402. ASSERT( !InvalidHandle(DG_CASSOCIATION_TYPE) );
  4403. CLAIM_MUTEX lock( Mutex );
  4404. if (0 != pDceBinding->Compare(Binding->pDceBinding,
  4405. &Ignored // fOnlyEndpointDifferent
  4406. )
  4407. )
  4408. {
  4409. return 1;
  4410. }
  4411. return 0;
  4412. }
  4413. RPC_STATUS
  4414. DG_CCALL::Cancel(
  4415. void * ThreadHandle
  4416. )
  4417. {
  4418. LogError( SU_CCALL, EV_PROC, this, 0, 'C' + (('a' + (('n' + (' ' << 8) )<< 8) )<< 8));
  4419. InterlockedIncrement(&Cancelled);
  4420. return RPC_S_OK;
  4421. }
  4422. unsigned
  4423. DG_CCALL::TestCancel()
  4424. {
  4425. LogEvent( SU_CCALL, EV_PROC, this, IntToPtr(Cancelled), 'T' + (('s' + (('t' + ('C' << 8)) << 8)) << 8));
  4426. if (!Cancelled)
  4427. {
  4428. return 0;
  4429. }
  4430. return InterlockedExchange(&Cancelled, 0);
  4431. }
  4432. RPC_STATUS
  4433. DG_CCALL::SendSomeFragments(
  4434. )
  4435. {
  4436. RPC_STATUS Status;
  4437. if (0 == FirstUnsentFragment)
  4438. {
  4439. if (SequenceNumber > Connection->CurrentSequenceNumber())
  4440. {
  4441. return RPC_S_OK;
  4442. }
  4443. //
  4444. // If we begin sending this call's request before a previous call
  4445. // is complete, then we should add the DG_PF2_UNRELATED bit to this call.
  4446. //
  4447. if (Connection->Association->fServerSupportsAsync)
  4448. {
  4449. ASSERT( Connection->Association->fServerSupportsAsync );
  4450. PDG_CCALL node = Previous;
  4451. while (node && node->fReceivedAllFragments)
  4452. {
  4453. node = node->Previous;
  4454. }
  4455. if (node)
  4456. {
  4457. BasePacketFlags2 = DG_PF2_UNRELATED;
  4458. Previous->ForceAck = TRUE;
  4459. }
  4460. }
  4461. // Note that Previous may not be the call immediately prior to this one,
  4462. // since the prior call may have completed already and been removed
  4463. // from the list.
  4464. }
  4465. LogEvent(SU_CCALL, EV_PROC, this, (void *) 1, 0x656d6f53);
  4466. Status = DG_PACKET_ENGINE::SendSomeFragments();
  4467. if (IsBufferSent())
  4468. {
  4469. //
  4470. // The first buffer contains all the static args; it's simpler
  4471. // to set the flags multiple times than to set it only for the
  4472. // first buffer.
  4473. //
  4474. StaticArgsSent = TRUE;
  4475. if (0 == (BufferFlags & RPC_BUFFER_PARTIAL))
  4476. {
  4477. AllArgsSent = TRUE;
  4478. }
  4479. }
  4480. if (pAsync && AsyncStatus == RPC_S_ASYNC_CALL_PENDING)
  4481. {
  4482. PostDelayedSend();
  4483. }
  4484. return Status;
  4485. }
  4486. BOOL
  4487. DG_CCALL::CheckForCancelTimeout()
  4488. {
  4489. if (!CancelPending && TestCancel() > 0)
  4490. {
  4491. ++CancelEventId;
  4492. CancelPending = TRUE;
  4493. CancelTime = GetTickCount();
  4494. }
  4495. if (CancelPending)
  4496. {
  4497. SendQuit();
  4498. if ((long(GetTickCount()) - CancelTime) / 1000 > ThreadGetRpcCancelTimeout() )
  4499. {
  4500. CancelPending = FALSE;
  4501. return TRUE;
  4502. }
  4503. }
  4504. return FALSE;
  4505. }
  4506. RPC_STATUS
  4507. DG_CCALL::DealWithTimeout()
  4508. {
  4509. RPC_STATUS Status;
  4510. #ifdef DEBUGRPC
  4511. Status = 0xbaadcccc;
  4512. #endif
  4513. LogEvent(SU_CCALL, EV_PROC, this, 0, 0x656d6f53);
  4514. ASSERT (State != CallComplete);
  4515. if (!CancelPending && TestCancel() > 0)
  4516. {
  4517. ++CancelEventId;
  4518. CancelPending = TRUE;
  4519. CancelTime = GetTickCount();
  4520. }
  4521. if (CancelPending)
  4522. {
  4523. SendQuit();
  4524. if ((long(GetTickCount()) - CancelTime) / 1000 > ThreadGetRpcCancelTimeout() )
  4525. {
  4526. RpcpErrorAddRecord( EEInfoGCRuntime,
  4527. RPC_S_CALL_CANCELLED,
  4528. EEInfoDLDG_CCALL__DealWithTimeout10,
  4529. (ULONG) ThreadGetRpcCancelTimeout(),
  4530. (ULONG) (long(GetTickCount()) - CancelTime)
  4531. );
  4532. CancelPending = FALSE;
  4533. return RPC_S_CALL_CANCELLED;
  4534. }
  4535. return RPC_S_OK;
  4536. }
  4537. if (long(GetTickCount()) - LastReceiveTime > TimeoutLimit)
  4538. {
  4539. LogError(SU_CCALL, EV_PROC, this, (void *) 2, 0x656d6f53);
  4540. RpcpErrorAddRecord( EEInfoGCRuntime,
  4541. RPC_P_TIMEOUT,
  4542. EEInfoDLDG_CCALL__DealWithTimeout20,
  4543. (ULONG) TimeoutLimit,
  4544. (ULONG) (long(GetTickCount()) - LastReceiveTime)
  4545. );
  4546. SendQuit();
  4547. return RPC_P_TIMEOUT;
  4548. }
  4549. LogEvent(SU_CCALL, EV_PROC, this, (void *) 4, 0x656d6f53);
  4550. int ConvComparisonResult = 1;
  4551. //
  4552. // The client for NT 3.5 (build 807) swallows requests for conv_who_are_you2.
  4553. // If the server pings the callback instead of retransmitting the request,
  4554. // the 807 client will give up before we ever try conv_who_are_you. Instead,
  4555. // retransmit the request packet for calls over the conv interface.
  4556. //
  4557. PRPC_SERVER_INTERFACE Conv = (PRPC_SERVER_INTERFACE) conv_ServerIfHandle;
  4558. if (FALSE == AllArgsSent ||
  4559. (BufferFlags & RPC_NCA_FLAGS_BROADCAST) ||
  4560. (0 == (ConvComparisonResult = RpcpMemoryCompare(&pSavedPacket->Header.InterfaceId,
  4561. &Conv->InterfaceId.SyntaxGUID,
  4562. sizeof(UUID)
  4563. ))))
  4564. {
  4565. //
  4566. // Not all request packets have been transferred.
  4567. //
  4568. Status = SendSomeFragments();
  4569. }
  4570. else
  4571. {
  4572. //
  4573. // Send a FACK if we have seen at least one response packet.
  4574. //
  4575. if (pReceivedPackets || ReceiveFragmentBase > 0)
  4576. {
  4577. Status = SendFackOrNocall(pReceivedPackets, DG_FACK);
  4578. }
  4579. else
  4580. {
  4581. Status = SendPing();
  4582. }
  4583. }
  4584. if (pAsync && AsyncStatus == RPC_S_ASYNC_CALL_PENDING)
  4585. {
  4586. PostDelayedSend();
  4587. }
  4588. if (Status != RPC_P_PORT_DOWN &&
  4589. Status != RPC_P_HOST_DOWN)
  4590. {
  4591. Status = 0;
  4592. }
  4593. else
  4594. {
  4595. RpcpErrorAddRecord( EEInfoGCRuntime,
  4596. Status,
  4597. EEInfoDLDG_CCALL__DealWithTimeout30
  4598. );
  4599. }
  4600. return Status;
  4601. }
  4602. BOOL
  4603. INTERFACE_AND_OBJECT_LIST::Insert(
  4604. void __RPC_FAR * Interface,
  4605. RPC_UUID __RPC_FAR * Object
  4606. )
  4607. {
  4608. INTERFACE_AND_OBJECT * Current;
  4609. INTERFACE_AND_OBJECT * Prev;
  4610. unsigned Count;
  4611. for (Count = 0, Prev = 0, Current = Head;
  4612. Count < MAX_ELEMENTS, Current != NULL;
  4613. Count++, Prev = Current, Current = Current->Next)
  4614. {
  4615. if (Interface == Current->Interface &&
  4616. 0 == Current->Object.MatchUuid(Object))
  4617. {
  4618. return TRUE;
  4619. }
  4620. }
  4621. if (Current)
  4622. {
  4623. //
  4624. // We have too many elements in the list. Reuse this one, the oldest.
  4625. //
  4626. if (Current == Head)
  4627. {
  4628. Head = Current->Next;
  4629. }
  4630. else
  4631. {
  4632. Prev->Next = Current->Next;
  4633. }
  4634. }
  4635. else
  4636. {
  4637. if (Cache1Available)
  4638. {
  4639. Cache1Available = FALSE;
  4640. Current = &Cache1;
  4641. }
  4642. else if (Cache2Available)
  4643. {
  4644. Cache2Available = FALSE;
  4645. Current = &Cache2;
  4646. }
  4647. else
  4648. {
  4649. Current = new INTERFACE_AND_OBJECT;
  4650. if (!Current)
  4651. {
  4652. return FALSE;
  4653. }
  4654. }
  4655. }
  4656. Current->Update(Interface, Object);
  4657. Current->Next = Head;
  4658. Head = Current;
  4659. return TRUE;
  4660. }
  4661. BOOL
  4662. INTERFACE_AND_OBJECT_LIST::Find(
  4663. void __RPC_FAR * Interface,
  4664. RPC_UUID __RPC_FAR * Object
  4665. )
  4666. {
  4667. INTERFACE_AND_OBJECT * Current;
  4668. INTERFACE_AND_OBJECT * Prev;
  4669. for (Current = Head; Current; Prev = Current, Current = Current->Next)
  4670. {
  4671. if (Interface == Current->Interface &&
  4672. 0 == Current->Object.MatchUuid(Object))
  4673. {
  4674. break;
  4675. }
  4676. }
  4677. if (!Current)
  4678. {
  4679. return FALSE;
  4680. }
  4681. if (Current != Head)
  4682. {
  4683. Prev->Next = Current->Next;
  4684. Current->Next = Head;
  4685. Head = Current;
  4686. }
  4687. return TRUE;
  4688. }
  4689. BOOL
  4690. INTERFACE_AND_OBJECT_LIST::Delete(
  4691. void __RPC_FAR * Interface,
  4692. RPC_UUID __RPC_FAR * Object
  4693. )
  4694. {
  4695. INTERFACE_AND_OBJECT * Current;
  4696. INTERFACE_AND_OBJECT * Prev;
  4697. for (Current = Head; Current; Prev = Current, Current = Current->Next)
  4698. {
  4699. if (Interface == Current->Interface &&
  4700. 0 == Current->Object.MatchUuid(Object))
  4701. {
  4702. break;
  4703. }
  4704. }
  4705. if (!Current)
  4706. {
  4707. return FALSE;
  4708. }
  4709. if (Current == Head)
  4710. {
  4711. Head = Current->Next;
  4712. }
  4713. else
  4714. {
  4715. Prev->Next = Current->Next;
  4716. }
  4717. if (Current == &Cache1)
  4718. {
  4719. Cache1Available = TRUE;
  4720. }
  4721. else if (Current == &Cache2)
  4722. {
  4723. Cache2Available = TRUE;
  4724. }
  4725. else
  4726. {
  4727. delete Current;
  4728. }
  4729. return TRUE;
  4730. }
  4731. INTERFACE_AND_OBJECT_LIST::~INTERFACE_AND_OBJECT_LIST(
  4732. )
  4733. {
  4734. INTERFACE_AND_OBJECT * Next;
  4735. while (Head)
  4736. {
  4737. Next = Head->Next;
  4738. if (Head != &Cache1 && Head != &Cache2)
  4739. {
  4740. delete Head;
  4741. }
  4742. Head = Next;
  4743. }
  4744. }
  4745. #ifdef DEBUGRPC
  4746. void
  4747. DumpBuffer(
  4748. void FAR * Buffer,
  4749. unsigned Length
  4750. )
  4751. {
  4752. const BYTES_PER_LINE = 16;
  4753. unsigned char FAR *p = (unsigned char FAR *) Buffer;
  4754. //
  4755. // 3 chars per byte for hex display, plus an extra space every 4 bytes,
  4756. // plus a byte for the printable representation, plus the \0.
  4757. //
  4758. char Outbuf[BYTES_PER_LINE*3+BYTES_PER_LINE/4+BYTES_PER_LINE+1];
  4759. Outbuf[0] = 0;
  4760. Outbuf[sizeof(Outbuf)-1] = 0;
  4761. char * HexDigits = "0123456789abcdef";
  4762. unsigned Index;
  4763. for (unsigned Offset=0; Offset < Length; Offset++)
  4764. {
  4765. Index = Offset % BYTES_PER_LINE;
  4766. if (Index == 0)
  4767. {
  4768. DbgPrint(" %s\n", Outbuf);
  4769. memset(Outbuf, ' ', sizeof(Outbuf)-1);
  4770. }
  4771. Outbuf[Index*3+Index/4 ] = HexDigits[p[Offset] / 16];
  4772. Outbuf[Index*3+Index/4+1] = HexDigits[p[Offset] % 16];
  4773. Outbuf[BYTES_PER_LINE*3+BYTES_PER_LINE/4+Index] = iscntrl(p[Offset]) ? '.' : p[Offset];
  4774. }
  4775. DbgPrint(" %s\n", Outbuf);
  4776. }
  4777. #endif
  4778. //------------------------------------------------------------------------
  4779. RPC_STATUS
  4780. DispatchCallbackRequest(
  4781. DG_CLIENT_CALLBACK * CallbackObject
  4782. )
  4783. {
  4784. BOOL fAsyncCapable = FALSE;
  4785. RPC_STATUS Status = RPC_S_OK;
  4786. RPC_MESSAGE CallbackMessage;
  4787. PNCA_PACKET_HEADER pHeader = &CallbackObject->Request->Header;
  4788. CallbackMessage.Buffer = 0;
  4789. if (pHeader->PacketFlags2 & DG_PF2_UNRELATED)
  4790. {
  4791. fAsyncCapable = TRUE;
  4792. }
  4793. //
  4794. // Allow only the internal "conv" interface as a callback.
  4795. //
  4796. if (0 != pHeader->InterfaceId.MatchUuid((RPC_UUID *) &((PRPC_SERVER_INTERFACE) conv_ServerIfHandle)->InterfaceId.SyntaxGUID ))
  4797. {
  4798. Status = RPC_S_UNKNOWN_IF;
  4799. }
  4800. else if (0 != (CallbackObject->Request->Header.PacketFlags & DG_PF_FRAG))
  4801. {
  4802. Status = RPC_S_CALL_FAILED_DNE;
  4803. }
  4804. else
  4805. {
  4806. //
  4807. // Dispatch to the callback stub.
  4808. // The client doesn't support Manager EPVs or nonidempotent callbacks.
  4809. //
  4810. RPC_STATUS ExceptionCode;
  4811. CallbackMessage.Handle = CallbackObject;
  4812. CallbackMessage.DataRepresentation = 0x00ffffff & (*(unsigned long *) &pHeader->DataRep);
  4813. CallbackMessage.Buffer = pHeader->Data;
  4814. CallbackMessage.BufferLength = pHeader->GetPacketBodyLen();
  4815. CallbackMessage.ProcNum = pHeader->OperationNumber;
  4816. CallbackMessage.ManagerEpv = 0;
  4817. CallbackMessage.ImportContext = 0;
  4818. CallbackMessage.TransferSyntax = 0;
  4819. CallbackMessage.RpcFlags = RPC_NCA_FLAGS_IDEMPOTENT;
  4820. CallbackMessage.RpcInterfaceInformation = conv_ServerIfHandle;
  4821. Status = DispatchCallback(((PRPC_SERVER_INTERFACE) CallbackMessage.RpcInterfaceInformation)->DispatchTable,
  4822. &CallbackMessage,
  4823. &ExceptionCode
  4824. );
  4825. if (Status)
  4826. {
  4827. if (Status == RPC_P_EXCEPTION_OCCURED)
  4828. {
  4829. Status = ExceptionCode;
  4830. }
  4831. }
  4832. else if (fAsyncCapable && CallbackObject->Connection)
  4833. {
  4834. CallbackObject->Connection->EnableOverlappedCalls();
  4835. }
  4836. LogEvent(SU_CCONN, EV_STATUS, CallbackObject->Connection, 0, Status);
  4837. }
  4838. if (Status != RPC_S_OK)
  4839. {
  4840. LogError(SU_CCONN, EV_STATUS, CallbackObject->Connection, 0, Status);
  4841. InitErrorPacket(CallbackObject->Request, DG_REJECT, Status);
  4842. CallbackObject->SendPacket( pHeader );
  4843. }
  4844. return Status;
  4845. }
  4846. //------------------------------------------------------------------------
  4847. PDG_CCONNECTION
  4848. CLIENT_ACTIVITY_TABLE::Lookup(
  4849. RPC_UUID * Uuid
  4850. )
  4851. /*++
  4852. Routine Description:
  4853. Arguments:
  4854. Packet
  4855. Return Value:
  4856. --*/
  4857. {
  4858. unsigned Hash = MakeHash(Uuid);
  4859. RequestHashMutex(Hash);
  4860. UUID_HASH_TABLE_NODE * Node = UUID_HASH_TABLE::Lookup(Uuid, Hash);
  4861. PDG_CCONNECTION Connection = 0;
  4862. if (Node)
  4863. {
  4864. Connection = DG_CCONNECTION::FromHashNode(Node);
  4865. Connection->MutexRequest();
  4866. ReleaseHashMutex(Hash);
  4867. }
  4868. else
  4869. {
  4870. ReleaseHashMutex(Hash);
  4871. }
  4872. return Connection;
  4873. }
  4874. RPC_STATUS
  4875. StandardPacketChecks(
  4876. DG_PACKET * pPacket
  4877. )
  4878. {
  4879. if (pPacket->Header.RpcVersion != DG_RPC_PROTOCOL_VERSION)
  4880. {
  4881. return NCA_STATUS_VERSION_MISMATCH;
  4882. }
  4883. ByteSwapPacketHeaderIfNecessary(pPacket);
  4884. if (0 == (pPacket->Flags & DG_PF_PARTIAL))
  4885. {
  4886. //
  4887. // Check for inconsistent packet length fields.
  4888. //
  4889. if (pPacket->DataLength < sizeof(NCA_PACKET_HEADER) ||
  4890. pPacket->DataLength - sizeof(NCA_PACKET_HEADER) < pPacket->GetPacketBodyLen())
  4891. {
  4892. return RPC_S_PROTOCOL_ERROR;
  4893. }
  4894. }
  4895. pPacket->DataLength -= sizeof(NCA_PACKET_HEADER);
  4896. //
  4897. // The X/Open standard does not give these fields a full byte.
  4898. //
  4899. pPacket->Header.RpcVersion &= 0x0F;
  4900. pPacket->Header.PacketType &= 0x1F;
  4901. //
  4902. // Fix up bogus OSF packets.
  4903. //
  4904. DeleteSpuriousAuthProto(pPacket);
  4905. return RPC_S_OK;
  4906. }
  4907. //------------------------------------------------------------------------
  4908. void
  4909. ProcessDgClientPacket(
  4910. IN DWORD Status,
  4911. IN DG_TRANSPORT_ENDPOINT LocalEndpoint,
  4912. IN void * PacketHeader,
  4913. IN unsigned long PacketLength,
  4914. IN DatagramTransportPair *AddressPair
  4915. )
  4916. {
  4917. PDG_PACKET Packet = DG_PACKET::FromPacketHeader(PacketHeader);
  4918. Packet->DataLength = PacketLength;
  4919. #ifdef INTRODUCE_ERRORS
  4920. if (::ClientDropRate)
  4921. {
  4922. if ((GetRandomCounter() % 100) < ::ClientDropRate)
  4923. {
  4924. unsigned Frag = (Packet->Header.PacketType << 16) | Packet->Header.GetFragmentNumber();
  4925. unsigned Uuid = *(unsigned *) &Packet->Header.ActivityId;
  4926. unsigned Type = Packet->Header.PacketType;
  4927. LogError(SU_PACKET, EV_DROP, (void *) Uuid, (void *) Type, Frag);
  4928. Packet->Free();
  4929. return;
  4930. }
  4931. }
  4932. if (::ClientDelayRate)
  4933. {
  4934. if ((GetRandomCounter() % 100) < ::ClientDelayRate)
  4935. {
  4936. unsigned Frag = (Packet->Header.PacketType << 16) | Packet->Header.GetFragmentNumber();
  4937. unsigned Uuid = *(unsigned *) &Packet->Header.ActivityId;
  4938. unsigned Type = Packet->Header.PacketType;
  4939. LogError(SU_PACKET, EV_DELAY, (void *) Uuid, (void *) Type, Frag);
  4940. Sleep(::ClientDelayTime);
  4941. }
  4942. }
  4943. #endif
  4944. if (Status == RPC_P_OVERSIZE_PACKET)
  4945. {
  4946. #ifdef DEBUGRPC
  4947. PrintToDebugger("RPC DG: async packet is too large\n");
  4948. #endif
  4949. Packet->Flags |= DG_PF_PARTIAL;
  4950. Status = RPC_S_OK;
  4951. }
  4952. if (Status != RPC_S_OK)
  4953. {
  4954. #ifdef DEBUGRPC
  4955. PrintToDebugger("RPC DG: async receive completed with status 0x%lx\n", Status);
  4956. RpcpBreakPoint();
  4957. #endif
  4958. Packet->Free(FALSE);
  4959. }
  4960. if (Packet->Header.PacketType == DG_REQUEST)
  4961. {
  4962. DG_CLIENT_CALLBACK CallbackObject;
  4963. CallbackObject.LocalEndpoint = DG_ENDPOINT::FromEndpoint( LocalEndpoint );
  4964. CallbackObject.Connection = 0;
  4965. CallbackObject.Request = Packet;
  4966. CallbackObject.RemoteAddress = AddressPair->RemoteAddress;
  4967. DispatchCallbackRequest(&CallbackObject);
  4968. return;
  4969. }
  4970. RPC_UUID ActivityId = Packet->Header.ActivityId;
  4971. if (NeedsByteSwap(&Packet->Header))
  4972. {
  4973. ByteSwapUuid(&ActivityId);
  4974. }
  4975. PDG_CCONNECTION Connection = ClientConnections->Lookup( &ActivityId );
  4976. if (Connection)
  4977. {
  4978. Connection->DispatchPacket(Packet, AddressPair->RemoteAddress);
  4979. }
  4980. else
  4981. {
  4982. #ifdef DEBUGRPC
  4983. if (Packet->Header.PacketType != DG_QUACK)
  4984. {
  4985. PrintToDebugger("RPC DG: no connection found for async packet of type 0x%hx\n",
  4986. Packet->Header.PacketType);
  4987. }
  4988. #endif
  4989. Packet->Free(FALSE);
  4990. }
  4991. }
  4992. void
  4993. DG_CCONNECTION::DispatchPacket(
  4994. PDG_PACKET Packet,
  4995. DG_TRANSPORT_ADDRESS Address
  4996. )
  4997. {
  4998. Mutex.VerifyOwned();
  4999. PDG_CCALL Call;
  5000. if (RPC_S_OK != StandardPacketChecks(Packet))
  5001. {
  5002. Packet->Free();
  5003. return;
  5004. }
  5005. RPC_STATUS Status = UpdateServerAddress(Packet, Address);
  5006. if (Status)
  5007. {
  5008. MutexClear();
  5009. LogEvent(SU_CCONN, EV_PKT_IN, this, IntToPtr(Packet->Header.SequenceNumber), (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  5010. Packet->Free();
  5011. }
  5012. Call = ActiveCallHead;
  5013. while (Call && Call->GetSequenceNumber() < Packet->Header.SequenceNumber)
  5014. {
  5015. Call = Call->Next;
  5016. }
  5017. if (Call && Call->GetSequenceNumber() == Packet->Header.SequenceNumber)
  5018. {
  5019. Call->IncrementRefCount();
  5020. Call->DispatchPacket(Packet);
  5021. Call->DecrementRefCount();
  5022. }
  5023. else
  5024. {
  5025. MutexClear();
  5026. LogEvent(SU_CCONN, EV_PKT_IN, this, IntToPtr(Packet->Header.SequenceNumber), (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  5027. Packet->Free();
  5028. }
  5029. }
  5030. //------------------------------------------------------------------------
  5031. RPC_STATUS
  5032. DG_CCALL::DispatchPacket(
  5033. IN DG_PACKET * Packet
  5034. )
  5035. {
  5036. BOOL ExtrasReference = FALSE;
  5037. RPC_STATUS Status;
  5038. PNCA_PACKET_HEADER pHeader = &Packet->Header;
  5039. LogEvent(SU_CCALL, EV_PKT_IN, this, (void *) 0, (Packet->Header.PacketType << 16) | Packet->GetFragmentNumber());
  5040. if (State == CallCancellingSend ||
  5041. State == CallComplete )
  5042. {
  5043. FreePacket(Packet);
  5044. return RPC_S_OK;
  5045. }
  5046. CancelDelayedSend();
  5047. if (!CancelPending && TestCancel() > 0)
  5048. {
  5049. ++CancelEventId;
  5050. CancelPending = TRUE;
  5051. CancelTime = GetTickCount();
  5052. }
  5053. if (CancelPending)
  5054. {
  5055. if ((long(GetTickCount()) - CancelTime) / 1000 > ThreadGetRpcCancelTimeout() )
  5056. {
  5057. RpcpErrorAddRecord( EEInfoGCRuntime,
  5058. RPC_S_CALL_CANCELLED,
  5059. EEInfoDLDG_CCALL__DispatchPacket10,
  5060. (ULONG) ThreadGetRpcCancelTimeout(),
  5061. (ULONG) (long(GetTickCount()) - CancelTime)
  5062. );
  5063. SendQuit();
  5064. CancelPending = FALSE;
  5065. FreePacket(Packet);
  5066. return RPC_S_CALL_CANCELLED;
  5067. }
  5068. }
  5069. if (Packet->Flags & DG_PF_PARTIAL)
  5070. {
  5071. SendFackOrNocall(Packet, DG_FACK);
  5072. FreePacket(Packet);
  5073. return RPC_S_OK;
  5074. }
  5075. // If the security context has expired, loop again - we will send
  5076. // a packet using the current security context, and the server
  5077. // will begin using that context to respond.
  5078. //
  5079. Status = Connection->VerifyPacket(Packet);
  5080. if (Status)
  5081. {
  5082. FreePacket(Packet);
  5083. if (Status == ERROR_SHUTDOWN_IN_PROGRESS)
  5084. {
  5085. return ERROR_SHUTDOWN_IN_PROGRESS;
  5086. }
  5087. if (pAsync && AsyncStatus == RPC_S_ASYNC_CALL_PENDING)
  5088. {
  5089. PostDelayedSend();
  5090. }
  5091. return RPC_S_OK;
  5092. }
  5093. if (DG_NOCALL != pHeader->PacketType)
  5094. {
  5095. UnansweredRequestCount = 0;
  5096. TimeoutCount = 0;
  5097. Connection->fAutoReconnect = FALSE;
  5098. }
  5099. LastReceiveTime = GetTickCount();
  5100. //
  5101. // It's not clear when the hint is allowed to change, so let's
  5102. // always save it.
  5103. //
  5104. InterfaceHint = pHeader->InterfaceHint;
  5105. ActivityHint = pHeader->ActivityHint;
  5106. pSavedPacket->Header.InterfaceHint = pHeader->InterfaceHint;
  5107. pSavedPacket->Header.ActivityHint = pHeader->ActivityHint;
  5108. //
  5109. // Handle the packet.
  5110. //
  5111. switch (pHeader->PacketType)
  5112. {
  5113. case DG_RESPONSE: Status = DealWithResponse(Packet); break;
  5114. case DG_FACK: Status = DealWithFack (Packet); break;
  5115. case DG_WORKING: Status = DealWithWorking (Packet); break;
  5116. case DG_NOCALL: Status = DealWithNocall (Packet); break;
  5117. case DG_QUACK: Status = DealWithQuack (Packet); break;
  5118. case DG_FAULT: Status = DealWithFault (Packet); break;
  5119. case DG_REJECT: Status = DealWithReject (Packet); break;
  5120. case DG_PING: FreePacket (Packet); break;
  5121. default: Status = RPC_S_PROTOCOL_ERROR; break;
  5122. }
  5123. if (pAsync)
  5124. {
  5125. if (RPC_S_OK == Status)
  5126. {
  5127. if (State == CallSend )
  5128. {
  5129. if (IsBufferAcknowledged())
  5130. {
  5131. SetState(CallQuiescent);
  5132. if (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE)
  5133. {
  5134. IssueNotification( RpcSendComplete );
  5135. }
  5136. }
  5137. }
  5138. if (fReceivedAllFragments)
  5139. {
  5140. AsyncStatus = RPC_S_OK;
  5141. IssueNotification(RpcCallComplete);
  5142. }
  5143. else
  5144. {
  5145. if (State == CallReceive )
  5146. {
  5147. if (PipeReceiveSize && ConsecutiveDataBytes >= PipeReceiveSize)
  5148. {
  5149. IssueNotification( RpcReceiveComplete );
  5150. }
  5151. }
  5152. PostDelayedSend();
  5153. }
  5154. }
  5155. else
  5156. {
  5157. CancelDelayedSend();
  5158. AsyncStatus = MapErrorCode(Status);
  5159. IssueNotification(RpcCallComplete);
  5160. }
  5161. }
  5162. if (CancelPending)
  5163. {
  5164. SendQuit();
  5165. }
  5166. return Status;
  5167. }
  5168. RPC_STATUS
  5169. DG_CCONNECTION::BeginCall(
  5170. PDG_CCALL Call
  5171. )
  5172. {
  5173. //
  5174. // Add the call to the end of the active call list.
  5175. //
  5176. Call->SetSequenceNumber(LowestUnusedSequence++);
  5177. Call->Next = 0;
  5178. Call->Previous = ActiveCallTail;
  5179. if (ActiveCallHead)
  5180. {
  5181. ASSERT( Call->GetSequenceNumber() > ActiveCallTail->GetSequenceNumber() );
  5182. ActiveCallTail->Next = Call;
  5183. }
  5184. else
  5185. {
  5186. ActiveCallHead = Call;
  5187. }
  5188. ActiveCallTail = Call;
  5189. //
  5190. // Update CurrentCall if appropriate.
  5191. //
  5192. if (WillNextCallBeQueued() == RPC_S_ASYNC_CALL_PENDING)
  5193. {
  5194. LogEvent(SU_CCONN, EV_PUSH, this, Call, (ULONG_PTR) CurrentCall);
  5195. }
  5196. else
  5197. {
  5198. LogEvent(SU_CCONN, EV_PUSH, this, Call, 0);
  5199. if (CurrentCall)
  5200. {
  5201. CancelDelayedAck();
  5202. }
  5203. CurrentCall = Call;
  5204. }
  5205. return RPC_S_OK;
  5206. }
  5207. void
  5208. DG_CCONNECTION::EndCall(
  5209. PDG_CCALL Call
  5210. )
  5211. /*++
  5212. Routine Description:
  5213. This fn removes a call from the active call list.
  5214. If the call posts a delayed ACK, this fn should not be called
  5215. until the delayed procedure runs or is cancelled.
  5216. Arguments:
  5217. Call - the call to remove
  5218. --*/
  5219. {
  5220. if (Call->Next == DG_CCALL_NOT_ACTIVE)
  5221. {
  5222. return;
  5223. }
  5224. if (Call->GetSequenceNumber() == LowestActiveSequence)
  5225. {
  5226. if (Call->Next)
  5227. {
  5228. LowestActiveSequence = Call->Next->GetSequenceNumber();
  5229. }
  5230. else
  5231. {
  5232. LowestActiveSequence = LowestUnusedSequence;
  5233. }
  5234. }
  5235. if (CurrentCall == Call)
  5236. {
  5237. CurrentCall = Call->Next;
  5238. //
  5239. // Queued async calls on a dead connection are cancelled, one at a time.
  5240. // As one is cleaned up, it will cancel the next, by induction.
  5241. //
  5242. if (this->fError)
  5243. {
  5244. if (CurrentCall && CurrentCall->InProgress())
  5245. {
  5246. CurrentCall->CancelAsyncCall( TRUE );
  5247. }
  5248. }
  5249. if (!CurrentCall)
  5250. {
  5251. CurrentCall = Call->Previous;
  5252. }
  5253. }
  5254. //
  5255. // Now remove the call from the active list.
  5256. //
  5257. if (Call->Previous)
  5258. {
  5259. Call->Previous->Next = Call->Next;
  5260. }
  5261. else
  5262. {
  5263. ActiveCallHead = Call->Next;
  5264. }
  5265. if (Call->Next)
  5266. {
  5267. Call->Next->Previous = Call->Previous;
  5268. }
  5269. else
  5270. {
  5271. ActiveCallTail = Call->Previous;
  5272. }
  5273. Call->Next = DG_CCALL_NOT_ACTIVE;
  5274. }
  5275. RPC_STATUS
  5276. DG_CCONNECTION::MaybeTransmitNextCall()
  5277. {
  5278. RPC_STATUS Status = 0;
  5279. Mutex.VerifyOwned();
  5280. if (WillNextCallBeQueued() == RPC_S_ASYNC_CALL_PENDING)
  5281. {
  5282. return RPC_S_OK;
  5283. }
  5284. if (!CurrentCall || !CurrentCall->Next)
  5285. {
  5286. LogEvent(SU_CCONN, EV_POP, this, 0);
  5287. return RPC_S_OK;
  5288. }
  5289. PDG_CCALL Call = CurrentCall->Next;
  5290. LogEvent(SU_CCONN, EV_POP, this, Call);
  5291. ASSERT( Call->GetSequenceNumber() > CurrentCall->GetSequenceNumber() );
  5292. CancelDelayedAck();
  5293. CurrentCall = Call;
  5294. Status = Call->SendSomeFragments();
  5295. if (Status == RPC_P_HOST_DOWN ||
  5296. Status == RPC_P_PORT_DOWN)
  5297. {
  5298. return Status;
  5299. }
  5300. return 0;
  5301. }
  5302. RPC_STATUS
  5303. DG_CCONNECTION::WillNextCallBeQueued()
  5304. {
  5305. if (!CurrentCall)
  5306. {
  5307. return RPC_S_OK;
  5308. }
  5309. if (fServerSupportsAsync)
  5310. {
  5311. if (CurrentCall->AllArgsSent &&
  5312. CurrentCall->IsBufferAcknowledged())
  5313. {
  5314. return RPC_S_OK;
  5315. }
  5316. }
  5317. else
  5318. {
  5319. if (CurrentCall->fReceivedAllFragments)
  5320. {
  5321. return RPC_S_OK;
  5322. }
  5323. }
  5324. return RPC_S_ASYNC_CALL_PENDING;
  5325. }
  5326. RPC_STATUS
  5327. DG_CLIENT_CALLBACK::GetBuffer(
  5328. IN OUT PRPC_MESSAGE Message,
  5329. IN UUID *ObjectUuid
  5330. )
  5331. /*++
  5332. Routine Description:
  5333. This method is called to actually allocate memory for an rpc call.
  5334. Arguments:
  5335. Message - The RPC_MESSAGE structure associated with this call.
  5336. ObjectUuid - Ignored
  5337. Return Value:
  5338. RPC_S_OUT_OF_MEMORY
  5339. RPC_S_OK
  5340. --*/
  5341. {
  5342. PDG_PACKET pPacket;
  5343. //
  5344. // Set up the message structure to point at this DG_CCALL.
  5345. //
  5346. Message->Handle = (RPC_BINDING_HANDLE)this;
  5347. if (Message->BufferLength < LocalEndpoint->Stats.PreferredPduSize)
  5348. {
  5349. Message->BufferLength = LocalEndpoint->Stats.PreferredPduSize;
  5350. }
  5351. pPacket = DG_PACKET::AllocatePacket(Message->BufferLength);
  5352. if (0 == pPacket)
  5353. {
  5354. return RPC_S_OUT_OF_MEMORY;
  5355. }
  5356. //
  5357. // Point the buffer at the appropriate place in the packet.
  5358. //
  5359. Message->Buffer = pPacket->Header.Data;
  5360. return RPC_S_OK;
  5361. }
  5362. void
  5363. DG_CLIENT_CALLBACK::FreeBuffer(
  5364. IN OUT PRPC_MESSAGE Message
  5365. )
  5366. /*++
  5367. Routine Description:
  5368. This is called by stubs in order to free a marshalling buffer.
  5369. Arguments:
  5370. Message - The RPC_MESSAGE structure associated with this call.
  5371. Return Value:
  5372. <none>
  5373. --*/
  5374. {
  5375. if (Message->Buffer)
  5376. {
  5377. PDG_PACKET Packet = DG_PACKET::FromStubData(Message->Buffer);
  5378. Packet->Free(FALSE);
  5379. if (Packet == Request)
  5380. {
  5381. Request = 0;
  5382. }
  5383. Message->Buffer = 0;
  5384. }
  5385. }
  5386. RPC_STATUS
  5387. DG_CLIENT_CALLBACK::SetAsyncHandle (
  5388. IN RPC_ASYNC_STATE * hAsync
  5389. )
  5390. {
  5391. return RPC_S_OK;
  5392. }
  5393. RPC_STATUS
  5394. DG_CLIENT_CALLBACK::AsyncSend(
  5395. IN OUT PRPC_MESSAGE Message
  5396. )
  5397. {
  5398. return Send(Message);
  5399. }
  5400. RPC_STATUS
  5401. DG_CLIENT_CALLBACK::Send(
  5402. IN OUT PRPC_MESSAGE Message
  5403. )
  5404. {
  5405. PNCA_PACKET_HEADER pHeader = CONTAINING_RECORD( Message->Buffer, NCA_PACKET_HEADER, Data );
  5406. DG_PACKET * Packet = CONTAINING_RECORD( Message->Buffer, DG_PACKET, Header.Data );
  5407. //
  5408. // The callback was successful, so the buffer has changed.
  5409. // Create the packet header, send the response, and free the
  5410. // request and response buffers.
  5411. //
  5412. *pHeader = Request->Header;
  5413. SetMyDataRep(pHeader);
  5414. pHeader->PacketType = DG_RESPONSE;
  5415. pHeader->PacketFlags = DG_PF_NO_FACK;
  5416. pHeader->AuthProto = 0;
  5417. pHeader->SetPacketBodyLen (Message->BufferLength);
  5418. pHeader->SetFragmentNumber(0);
  5419. if (Message->BufferLength + sizeof(NCA_PACKET_HEADER) > LocalEndpoint->Stats.MaxPduSize)
  5420. {
  5421. InitErrorPacket( Packet, DG_FAULT, NCA_STATUS_OUT_ARGS_TOO_BIG );
  5422. }
  5423. SendPacket( pHeader );
  5424. FreeBuffer(Message);
  5425. return RPC_S_OK;
  5426. }
  5427. RPC_STATUS
  5428. DG_CLIENT_CALLBACK::SendReceive(
  5429. IN OUT PRPC_MESSAGE Message
  5430. )
  5431. {
  5432. return RPC_S_CANNOT_SUPPORT;
  5433. }
  5434. RPC_STATUS
  5435. DG_CLIENT_CALLBACK::Receive(
  5436. IN OUT PRPC_MESSAGE Message,
  5437. IN unsigned MinimumSize
  5438. )
  5439. {
  5440. return RPC_S_CANNOT_SUPPORT;
  5441. }
  5442. ENDPOINT_MANAGER::ENDPOINT_MANAGER(
  5443. IN OUT RPC_STATUS * pStatus
  5444. ) :
  5445. Mutex(pStatus)
  5446. {
  5447. unsigned u;
  5448. for (u=0; u < DG_TRANSPORT_COUNT; ++u)
  5449. {
  5450. AsyncEndpoints[u] = 0;
  5451. }
  5452. Endpoints = 0;
  5453. LastScavengeTime = GetTickCount();
  5454. }
  5455. DG_ENDPOINT *
  5456. ENDPOINT_MANAGER::RequestEndpoint(
  5457. IN RPC_DATAGRAM_TRANSPORT * TransportInterface,
  5458. IN BOOL Async,
  5459. IN DWORD Flags
  5460. )
  5461. {
  5462. ASSERT(0 == (Flags & PENALTY_BOX) );
  5463. if (Async)
  5464. {
  5465. unsigned u;
  5466. for (u=0; u < DG_TRANSPORT_COUNT && AsyncEndpoints[u]; ++u)
  5467. {
  5468. if (AsyncEndpoints[u]->TransportInterface == TransportInterface &&
  5469. AsyncEndpoints[u]->Flags == Flags)
  5470. {
  5471. LogEvent(SU_CENDPOINT, EV_START, AsyncEndpoints[u], 0, Async);
  5472. InterlockedIncrement(&AsyncEndpoints[u]->NumberOfCalls);
  5473. return AsyncEndpoints[u];
  5474. }
  5475. }
  5476. Mutex.Request();
  5477. for (; u < DG_TRANSPORT_COUNT && AsyncEndpoints[u]; ++u)
  5478. {
  5479. if (AsyncEndpoints[u]->TransportInterface == TransportInterface &&
  5480. AsyncEndpoints[u]->Flags == Flags)
  5481. {
  5482. Mutex.Clear();
  5483. LogEvent(SU_CENDPOINT, EV_START, AsyncEndpoints[u], 0, Async);
  5484. InterlockedIncrement(&AsyncEndpoints[u]->NumberOfCalls);
  5485. return AsyncEndpoints[u];
  5486. }
  5487. }
  5488. DG_ENDPOINT * Node;
  5489. Node = (DG_ENDPOINT *) new char[sizeof(DG_ENDPOINT) + TransportInterface->ClientEndpointSize];
  5490. LogEvent(SU_CENDPOINT, EV_CREATE, Node, TransportInterface, Async);
  5491. if (Node)
  5492. {
  5493. Node->TransportInterface = TransportInterface;
  5494. Node->Async = TRUE;
  5495. Node->Flags = Flags;
  5496. RPC_STATUS Status = TransportInterface->OpenEndpoint(&Node->TransportEndpoint, TRUE, Flags);
  5497. if (Status)
  5498. {
  5499. LogError(SU_CENDPOINT, EV_STATUS, Node, 0, Status);
  5500. Mutex.Clear();
  5501. delete Node;
  5502. return 0;
  5503. }
  5504. Status = TransportInterface->QueryEndpointStats(&Node->TransportEndpoint, &Node->Stats);
  5505. if (Status)
  5506. {
  5507. LogError(SU_CENDPOINT, EV_STATUS, Node, 0, Status);
  5508. Mutex.Clear();
  5509. Node->TransportInterface->Close(Node->TransportEndpoint);
  5510. delete Node;
  5511. return 0;
  5512. }
  5513. Node->NumberOfCalls = 1;
  5514. AsyncEndpoints[u] = Node;
  5515. Mutex.Clear();
  5516. return AsyncEndpoints[u];
  5517. }
  5518. LogEvent(SU_CENDPOINT, EV_STATUS, Node, 0, 0);
  5519. return 0;
  5520. }
  5521. else
  5522. {
  5523. Mutex.Request();
  5524. DG_ENDPOINT * Previous = 0;
  5525. DG_ENDPOINT * Node = Endpoints;
  5526. //
  5527. // Look for a node on the right transport and with the same flags.
  5528. // If the flags match except for the penalty box, use it only if
  5529. // the endpoint has been idle for the right length of time.
  5530. // The caller must drain any buffered packets on a penalty-box endpoint.
  5531. //
  5532. for ( ; Node; Previous=Node, Node=Node->Next )
  5533. {
  5534. if (Node->TransportInterface != TransportInterface)
  5535. {
  5536. continue;
  5537. }
  5538. if (Node->Flags == Flags)
  5539. {
  5540. break;
  5541. }
  5542. if (Node->Flags == (Flags | PENALTY_BOX) &&
  5543. GetTickCount() - Node->TimeStamp >= PENALTY_BOX_DURATION)
  5544. {
  5545. break;
  5546. }
  5547. }
  5548. if (Node)
  5549. {
  5550. if (Previous)
  5551. {
  5552. Previous->Next = Node->Next;
  5553. }
  5554. else
  5555. {
  5556. Endpoints = Node->Next;
  5557. }
  5558. Node->NumberOfCalls = 1;
  5559. Mutex.Clear();
  5560. LogEvent(SU_CENDPOINT, EV_START, Node, 0, Async);
  5561. return Node;
  5562. }
  5563. else
  5564. {
  5565. Mutex.Clear();
  5566. Node = (DG_ENDPOINT *) new char[sizeof(DG_ENDPOINT) + TransportInterface->ClientEndpointSize];
  5567. LogEvent(SU_CENDPOINT, EV_CREATE, Node, TransportInterface, Async);
  5568. if (Node)
  5569. {
  5570. Node->TransportInterface = TransportInterface;
  5571. Node->Async = FALSE;
  5572. Node->Flags = Flags;
  5573. RPC_STATUS Status = TransportInterface->OpenEndpoint(&Node->TransportEndpoint, FALSE, Flags);
  5574. if (Status)
  5575. {
  5576. LogEvent(SU_CENDPOINT, EV_STATUS, Node, 0, Status);
  5577. delete Node;
  5578. return 0;
  5579. }
  5580. Status = TransportInterface->QueryEndpointStats(&Node->TransportEndpoint, &Node->Stats);
  5581. if (Status)
  5582. {
  5583. LogEvent(SU_CENDPOINT, EV_STATUS, Node, 0, Status);
  5584. Mutex.Clear();
  5585. Node->TransportInterface->Close(Node->TransportEndpoint);
  5586. delete Node;
  5587. return 0;
  5588. }
  5589. Node->NumberOfCalls = 1;
  5590. return Node;
  5591. }
  5592. LogEvent(SU_CENDPOINT, EV_STATUS, Node, 0, 0);
  5593. return 0;
  5594. }
  5595. }
  5596. }
  5597. void
  5598. ENDPOINT_MANAGER::ReleaseEndpoint(
  5599. IN DG_ENDPOINT * Node
  5600. )
  5601. {
  5602. LogEvent(SU_CENDPOINT, EV_STOP, Node, 0, Node->Async);
  5603. if (Node->Async)
  5604. {
  5605. InterlockedDecrement(&Node->NumberOfCalls);
  5606. }
  5607. else
  5608. {
  5609. Node->TimeStamp = GetTickCount();
  5610. Mutex.Request();
  5611. Node->Next = Endpoints;
  5612. Endpoints = Node;
  5613. Mutex.Clear();
  5614. EnableGlobalScavenger();
  5615. }
  5616. }
  5617. BOOL
  5618. ENDPOINT_MANAGER::DeleteIdleEndpoints(
  5619. long CurrentTime
  5620. )
  5621. {
  5622. boolean More = FALSE;
  5623. Mutex.Request();
  5624. DG_ENDPOINT * Node;
  5625. DG_ENDPOINT * Prev = 0;
  5626. for (Node = Endpoints; Node; Node = Node->Next)
  5627. {
  5628. ASSERT( Node->Async == FALSE );
  5629. if (CurrentTime - Node->TimeStamp > IDLE_ENDPOINT_LIFETIME )
  5630. {
  5631. break;
  5632. }
  5633. Prev = Node;
  5634. More = TRUE;
  5635. }
  5636. if (Prev)
  5637. {
  5638. Prev->Next = 0;
  5639. }
  5640. else
  5641. {
  5642. Endpoints = 0;
  5643. }
  5644. LastScavengeTime = CurrentTime;
  5645. Mutex.Clear();
  5646. while (Node)
  5647. {
  5648. DG_ENDPOINT * Next = Node->Next;
  5649. LogEvent(SU_CENDPOINT, EV_DELETE, Node, Node->TransportInterface, Node->Async);
  5650. Node->TransportInterface->Close(Node->TransportEndpoint);
  5651. delete Node;
  5652. Node = Next;
  5653. }
  5654. return More;
  5655. }
  5656. void
  5657. DG_CCALL::PostDelayedSend()
  5658. {
  5659. Connection->Mutex.VerifyOwned();
  5660. //
  5661. // Cancel the rpevious send, to make sure the pending-send count is accurate.
  5662. // Then post the new request.
  5663. //
  5664. CancelDelayedSend();
  5665. DelayedSendPending++;
  5666. DelayedProcedures->Add(&TransmitTimer, (GetTickCount() - LastReceiveTime) + ReceiveTimeout, TRUE);
  5667. LogEvent(SU_CCALL, EV_PROC, this, 0, 0x6e534450);
  5668. }
  5669. void
  5670. DG_CCALL::CancelDelayedSend()
  5671. {
  5672. Connection->Mutex.VerifyOwned();
  5673. LogEvent(SU_CCALL, EV_PROC, this, 0, 0x6e534443);
  5674. if (!DelayedSendPending)
  5675. {
  5676. return;
  5677. }
  5678. if (TRUE == DelayedProcedures->Cancel(&TransmitTimer))
  5679. {
  5680. DelayedSendPending--;
  5681. return;
  5682. }
  5683. //
  5684. // We just missed the activation of the delayed procedure.
  5685. // This thread must let go of the mutex in order for ExecuteDelayedSend
  5686. // to continue. It's important that no other thread change the call state
  5687. // during this process, since ExecuteDelayedSend checks for that state.
  5688. //
  5689. DG_CLIENT_STATE OldState = State;
  5690. SetState(CallCancellingSend);
  5691. Connection->MutexClear();
  5692. while (DelayedSendPending)
  5693. {
  5694. Sleep(1);
  5695. }
  5696. Connection->MutexRequest();
  5697. SetState(OldState);
  5698. }
  5699. void
  5700. DG_CCALL::ExecuteDelayedSend()
  5701. {
  5702. LogEvent(SU_CCALL, EV_PROC, this, 0, 0x6e534445);
  5703. Connection->MutexRequest();
  5704. DelayedSendPending--;
  5705. if (DelayedSendPending)
  5706. {
  5707. //
  5708. // Multiple sends are pending. Only one is helpful.
  5709. //
  5710. Connection->MutexClear();
  5711. return;
  5712. }
  5713. if (State == CallCancellingSend)
  5714. {
  5715. Connection->MutexClear();
  5716. return;
  5717. }
  5718. if (!TimeoutCount)
  5719. {
  5720. ReceiveTimeout = 500;
  5721. }
  5722. IncreaseReceiveTimeout();
  5723. RPC_STATUS Status = DealWithTimeout();
  5724. if (Status != RPC_S_OK)
  5725. {
  5726. AsyncStatus = MapErrorCode(Status);
  5727. IssueNotification( RpcCallComplete );
  5728. }
  5729. Connection->MutexClear();
  5730. }
  5731. void
  5732. DelayedSendProc(
  5733. void * parm
  5734. )
  5735. {
  5736. PDG_CCALL(parm)->ExecuteDelayedSend();
  5737. }
  5738. DG_ASSOCIATION_TABLE::DG_ASSOCIATION_TABLE(
  5739. RPC_STATUS * pStatus
  5740. )
  5741. : Mutex( *pStatus )
  5742. {
  5743. Associations = InitialAssociations;
  5744. AssociationsLength = INITIAL_ARRAY_LENGTH;
  5745. long i;
  5746. for (i=0; i < AssociationsLength; ++i)
  5747. {
  5748. Associations[i].fBusy = FALSE;
  5749. Associations[i].Hint = ~0;
  5750. }
  5751. fCasUuidReady = FALSE;
  5752. PreviousFreedCount = MINIMUM_IDLE_ENTRIES;
  5753. }
  5754. RPC_STATUS
  5755. DG_ASSOCIATION_TABLE::Add(
  5756. DG_CASSOCIATION * Association
  5757. )
  5758. /*++
  5759. Routine Description:
  5760. Adds <Association> to the table.
  5761. Return Value:
  5762. zero if success
  5763. a Win32 error if failure
  5764. --*/
  5765. {
  5766. LONG i;
  5767. LONG OldAssociationsLength;
  5768. //
  5769. // Make a hint for the association.
  5770. //
  5771. HINT Hint = MakeHint( Association->pDceBinding );
  5772. //
  5773. // Look for an open space in the current block.
  5774. //
  5775. Mutex.LockExclusive();
  5776. //
  5777. // Make sure this process has a "client address space UUID". The callback
  5778. // for each connection will ask for it.
  5779. // We do this here because we are not supposed to do it in InitializeRpcProtocolDgClient.
  5780. // It would cause a perf hit even in code that uses only LRPCbindings.
  5781. //
  5782. if (!fCasUuidReady)
  5783. {
  5784. RPC_STATUS Status;
  5785. Status = UuidCreate(&CasUuid);
  5786. if (Status == RPC_S_UUID_LOCAL_ONLY)
  5787. {
  5788. Status = 0;
  5789. }
  5790. if (Status)
  5791. {
  5792. Mutex.UnlockExclusive();
  5793. LogEvent( SU_CASSOC, EV_STATUS, 0, 0, Status );
  5794. return Status;
  5795. }
  5796. fCasUuidReady = TRUE;
  5797. }
  5798. for (i = 0; i < AssociationsLength; ++i)
  5799. {
  5800. if (!Associations[i].fBusy)
  5801. {
  5802. break;
  5803. }
  5804. }
  5805. if (i == AssociationsLength)
  5806. {
  5807. //
  5808. // The current block is full; allocate an expanded block.
  5809. //
  5810. LONG NewAssociationsLength = 2*AssociationsLength;
  5811. NODE * NewAssociations = new NODE[ NewAssociationsLength ];
  5812. if (!NewAssociations)
  5813. {
  5814. Mutex.UnlockExclusive();
  5815. LogEvent( SU_CASSOC, EV_STATUS, 0, 0, RPC_S_OUT_OF_MEMORY );
  5816. return RPC_S_OUT_OF_MEMORY;
  5817. }
  5818. //
  5819. // Initialize the used and unused sections of the new block.
  5820. //
  5821. RpcpMemoryCopy( NewAssociations, Associations, sizeof(NODE) * AssociationsLength );
  5822. RpcpMemorySet( &NewAssociations[ AssociationsLength ], 0, sizeof(NODE) * (NewAssociationsLength-AssociationsLength) );
  5823. //
  5824. // Replace the block.
  5825. //
  5826. if (Associations != InitialAssociations)
  5827. {
  5828. delete Associations;
  5829. }
  5830. i = AssociationsLength;
  5831. Associations = NewAssociations;
  5832. AssociationsLength = NewAssociationsLength;
  5833. }
  5834. Associations[i].fBusy = TRUE;
  5835. Associations[i].Hint = Hint;
  5836. Associations[i].Association = Association;
  5837. Associations[i].TimeStamp = GetTickCount();
  5838. Associations[i].ContextHandleCount = 0;
  5839. Association->InternalTableIndex = i;
  5840. Mutex.UnlockExclusive();
  5841. return 0;
  5842. }
  5843. DG_CASSOCIATION *
  5844. DG_ASSOCIATION_TABLE::Find(
  5845. DG_BINDING_HANDLE * Binding,
  5846. RPC_CLIENT_INTERFACE * Interface,
  5847. BOOL fContextHandle,
  5848. BOOL fPartial,
  5849. BOOL fAutoReconnect
  5850. )
  5851. /*++
  5852. Routine Description:
  5853. Locate an association that matches <Binding>'s DCE_BINDING.
  5854. If <fPartial> is true, the endpoint will not be compared, but the
  5855. association must have <Interface> in its list of successful interfaces
  5856. in order to match. <fContextHandle> is true if the binding handle is
  5857. embedded in a context handle.
  5858. Return Value:
  5859. the association, if an matching one was found
  5860. NULL otherwise
  5861. --*/
  5862. {
  5863. //
  5864. // Calculate the hint for a matching association.
  5865. //
  5866. HINT Hint = MakeHint( Binding->pDceBinding );
  5867. //
  5868. // For auto-reconnect, only recently-successful associations qualify.
  5869. // MinimumTime is after the failed call began, at least for most com-timeout
  5870. // settings.
  5871. //
  5872. long MinimumTime = GetTickCount() - (15 * 1000);
  5873. Mutex.LockShared();
  5874. long i;
  5875. for (i = 0; i < AssociationsLength; ++i)
  5876. {
  5877. if (Associations[i].Hint == Hint &&
  5878. Associations[i].fBusy)
  5879. {
  5880. DG_CASSOCIATION * Association = Associations[i].Association;
  5881. if (Association->ErrorFlag())
  5882. {
  5883. continue;
  5884. }
  5885. if (Association->fLoneBindingHandle)
  5886. {
  5887. continue;
  5888. }
  5889. if (fAutoReconnect &&
  5890. MinimumTime - Association->LastReceiveTime > 0)
  5891. {
  5892. continue;
  5893. }
  5894. if (fPartial)
  5895. {
  5896. if (Association->ComparePartialBinding(Binding, Interface) == TRUE)
  5897. {
  5898. Association->IncrementBindingRefCount(fContextHandle);
  5899. Associations[i].TimeStamp = GetTickCount();
  5900. Mutex.UnlockShared();
  5901. return Association;
  5902. }
  5903. }
  5904. else
  5905. {
  5906. if (Association->CompareWithBinding(Binding) == 0)
  5907. {
  5908. Association->IncrementBindingRefCount(fContextHandle);
  5909. Associations[i].TimeStamp = GetTickCount();
  5910. Mutex.UnlockShared();
  5911. return Association;
  5912. }
  5913. }
  5914. }
  5915. }
  5916. Mutex.UnlockShared();
  5917. return 0;
  5918. }
  5919. void
  5920. ContextHandleProc(
  5921. void * arg
  5922. )
  5923. {
  5924. ActiveAssociations->SendContextHandleKeepalives();
  5925. }
  5926. BOOL
  5927. DG_ASSOCIATION_TABLE::SendContextHandleKeepalives()
  5928. {
  5929. BOOL fContextHandles = FALSE;
  5930. long StartTime = GetTickCount();
  5931. Mutex.LockShared();
  5932. long i;
  5933. for (i=0; i < AssociationsLength; ++i)
  5934. {
  5935. if (!Associations[i].fBusy)
  5936. {
  5937. continue;
  5938. }
  5939. if (Associations[i].ContextHandleCount > 0)
  5940. {
  5941. fContextHandles = TRUE;
  5942. if (StartTime - Associations[i].TimeStamp >= CXT_HANDLE_KEEPALIVE_INTERVAL)
  5943. {
  5944. //
  5945. // We have to avoid holding the shared lock when calling a procedure
  5946. // that may take the exclusive lock.
  5947. // DG_CASSOCIATION::DecrementRefCount may delete the association,
  5948. // and that would want the exclusive table lock.
  5949. //
  5950. Associations[i].Association->IncrementRefCount();
  5951. Mutex.UnlockShared();
  5952. if (Associations[i].Association->SendKeepAlive())
  5953. {
  5954. Associations[i].TimeStamp = GetTickCount();
  5955. }
  5956. Associations[i].Association->DecrementRefCount();
  5957. Mutex.LockShared();
  5958. }
  5959. }
  5960. }
  5961. Mutex.UnlockShared();
  5962. if (fContextHandles)
  5963. {
  5964. long FinishTime = GetTickCount();
  5965. if (FinishTime-StartTime >= CXT_HANDLE_SWEEP_INTERVAL)
  5966. {
  5967. //
  5968. // We are behind. Recursion or "goto start" would be cheaper,
  5969. // but would block other delayed procs that are ready to fire.
  5970. //
  5971. DelayedProcedures->Add(ContextHandleTimer, 0, TRUE);
  5972. }
  5973. else
  5974. {
  5975. DelayedProcedures->Add(ContextHandleTimer, CXT_HANDLE_SWEEP_INTERVAL-(FinishTime-StartTime), TRUE);
  5976. }
  5977. }
  5978. return fContextHandles;
  5979. }
  5980. void
  5981. DG_ASSOCIATION_TABLE::Delete(
  5982. DG_CASSOCIATION * Association
  5983. )
  5984. {
  5985. long Index = Association->InternalTableIndex;
  5986. if (Index == -1)
  5987. {
  5988. return;
  5989. }
  5990. ASSERT( Index >= 0 && Index < AssociationsLength );
  5991. ASSERT( Associations[Index].Association == Association );
  5992. Mutex.LockExclusive();
  5993. ASSERT( Associations[Index].fBusy );
  5994. Associations[Index].fBusy = FALSE;
  5995. Associations[Index].Hint = ~0;
  5996. Mutex.UnlockExclusive();
  5997. delete Association;
  5998. }
  5999. BOOL
  6000. DG_ASSOCIATION_TABLE::DeleteIdleEntries(
  6001. long CurrentTime
  6002. )
  6003. /*++
  6004. Routine Description:
  6005. This deletes entries idle more than IDLE_CASSOCIATION_LIFETIME milliseconds.
  6006. The fn takes only the read lock until it finds an entry that needs deletion.
  6007. Then it takes the write lock, and keeps it until the table is scoured.
  6008. Return Value:
  6009. TRUE if items are left in the table at the end
  6010. FALSE if the table is empty at the end
  6011. --*/
  6012. {
  6013. BOOL fExclusive = FALSE;
  6014. BOOL fLeftovers = FALSE;
  6015. long i = 0;
  6016. DG_CASSOCIATION * Association;
  6017. //
  6018. // Initialize an array to hold removed associations.
  6019. //
  6020. long NextFreedEntry = 0;
  6021. long MaximumFreedEntries = PreviousFreedCount;
  6022. DG_CASSOCIATION ** FreedEntries = (DG_CASSOCIATION **) _alloca( sizeof(DG_CASSOCIATION *) * MaximumFreedEntries );
  6023. memset( FreedEntries, 0, sizeof(DG_CASSOCIATION *) * MaximumFreedEntries );
  6024. //
  6025. //
  6026. //
  6027. Mutex.LockShared();
  6028. for (i=0; i < AssociationsLength; ++i)
  6029. {
  6030. if (Associations[i].fBusy)
  6031. {
  6032. if (CurrentTime - Associations[i].TimeStamp > IDLE_CASSOCIATION_LIFETIME)
  6033. {
  6034. //
  6035. // We must claim the exclusive lock now to get an accurate answer.
  6036. //
  6037. if (!fExclusive)
  6038. {
  6039. fExclusive = TRUE;
  6040. Mutex.ConvertToExclusive();
  6041. }
  6042. if (Associations[i].fBusy &&
  6043. CurrentTime - Associations[i].TimeStamp > IDLE_CASSOCIATION_LIFETIME &&
  6044. Associations[i].Association->ReferenceCount.GetInteger() == 0)
  6045. {
  6046. //
  6047. // It's official; the association will be deleted.
  6048. // Add it to the deletion array and release its slot in Associations[]..
  6049. //
  6050. Associations[i].Association->InternalTableIndex = -1;
  6051. FreedEntries[ NextFreedEntry ] = Associations[i].Association;
  6052. Associations[i].fBusy = FALSE;
  6053. Associations[i].Hint = ~0;
  6054. ++NextFreedEntry;
  6055. if (NextFreedEntry == MaximumFreedEntries)
  6056. {
  6057. break;
  6058. }
  6059. }
  6060. else
  6061. {
  6062. fLeftovers = TRUE;
  6063. }
  6064. }
  6065. else
  6066. {
  6067. fLeftovers = TRUE;
  6068. }
  6069. }
  6070. }
  6071. if (fExclusive)
  6072. {
  6073. Mutex.UnlockExclusive();
  6074. }
  6075. else
  6076. {
  6077. Mutex.UnlockShared();
  6078. }
  6079. //
  6080. // Calculate the length of the array for the next pass.
  6081. //
  6082. if (NextFreedEntry == MaximumFreedEntries)
  6083. {
  6084. fLeftovers = TRUE;
  6085. PreviousFreedCount = MaximumFreedEntries * 2;
  6086. }
  6087. else if (NextFreedEntry < MINIMUM_IDLE_ENTRIES)
  6088. {
  6089. PreviousFreedCount = MINIMUM_IDLE_ENTRIES;
  6090. }
  6091. else
  6092. {
  6093. PreviousFreedCount = NextFreedEntry;
  6094. }
  6095. //
  6096. // Delete the removed associations.
  6097. //
  6098. --NextFreedEntry;
  6099. while (NextFreedEntry >= 0)
  6100. {
  6101. delete FreedEntries[ NextFreedEntry ];
  6102. --NextFreedEntry;
  6103. }
  6104. return fLeftovers;
  6105. }
  6106. DG_ASSOCIATION_TABLE::HINT
  6107. DG_ASSOCIATION_TABLE::MakeHint(
  6108. DCE_BINDING * pDceBinding
  6109. )
  6110. /*++
  6111. Routine Description:
  6112. Construct a cheap hint to scan the association table.
  6113. The hint should not depend on the endpoint, since we want
  6114. a partial binding's pDceBinding to match an association
  6115. that has a resolved endpoint.
  6116. Return Value:
  6117. The hint.
  6118. --*/
  6119. {
  6120. HINT Hint = 0;
  6121. RPC_CHAR * String;
  6122. String = pDceBinding->InqNetworkAddress();
  6123. while (*String)
  6124. {
  6125. Hint *= 37;
  6126. Hint += *String;
  6127. ++String;
  6128. }
  6129. return Hint;
  6130. }
  6131. void
  6132. DG_ASSOCIATION_TABLE::IncrementContextHandleCount(
  6133. DG_CASSOCIATION * Association
  6134. )
  6135. /*++
  6136. Routine Description:
  6137. Increment the count of context handles associated with this index.
  6138. This is stired in the table rather than in the association
  6139. so that the count can be accessed even if the association is swapped out.
  6140. --*/
  6141. {
  6142. long Index = Association->InternalTableIndex;
  6143. if (Index == -1)
  6144. {
  6145. return;
  6146. }
  6147. Mutex.LockShared();
  6148. ASSERT( Index >= 0 && Index < AssociationsLength );
  6149. ASSERT( Associations[Index].Association == Association );
  6150. ++Associations[Index].ContextHandleCount;
  6151. Mutex.UnlockShared();
  6152. }
  6153. void
  6154. DG_ASSOCIATION_TABLE::DecrementContextHandleCount(
  6155. DG_CASSOCIATION * Association
  6156. )
  6157. /*++
  6158. Routine Description:
  6159. Decrement the count of context handles associated with this index.
  6160. This is stired in the table rather than in the association
  6161. so that the count can be accessed even if the association is swapped out.
  6162. --*/
  6163. {
  6164. long Index = Association->InternalTableIndex;
  6165. if (Index == -1)
  6166. {
  6167. return;
  6168. }
  6169. Mutex.LockShared();
  6170. ASSERT( Index >= 0 && Index < AssociationsLength );
  6171. ASSERT( Associations[Index].Association == Association );
  6172. --Associations[Index].ContextHandleCount;
  6173. Mutex.UnlockShared();
  6174. }
  6175. long
  6176. DG_ASSOCIATION_TABLE::GetContextHandleCount(
  6177. DG_CASSOCIATION * Association
  6178. )
  6179. /*++
  6180. Routine Description:
  6181. Decrement the count of context handles associated with this index.
  6182. This is stired in the table rather than in the association
  6183. so that the count can be accessed even if the association is swapped out.
  6184. --*/
  6185. {
  6186. long Count;
  6187. long Index = Association->InternalTableIndex;
  6188. if (Index == -1)
  6189. {
  6190. return 0;
  6191. }
  6192. Mutex.LockShared();
  6193. ASSERT( Index >= 0 && Index < AssociationsLength );
  6194. ASSERT( Associations[Index].Association == Association );
  6195. Count = Associations[Index].ContextHandleCount;
  6196. Mutex.UnlockShared();
  6197. return Count;
  6198. }
  6199. void
  6200. DG_ASSOCIATION_TABLE::UpdateTimeStamp(
  6201. DG_CASSOCIATION * Association
  6202. )
  6203. /*++
  6204. Routine Description:
  6205. Decrement the count of context handles associated with this index.
  6206. This is stired in the table rather than in the association
  6207. so that the count can be accessed even if the association is swapped out.
  6208. --*/
  6209. {
  6210. long Index = Association->InternalTableIndex;
  6211. if (Index == -1)
  6212. {
  6213. return;
  6214. }
  6215. ASSERT( Index >= 0 && Index < AssociationsLength );
  6216. ASSERT( Associations[Index].Association == Association );
  6217. Associations[Index].TimeStamp = GetTickCount();
  6218. }
  6219. //
  6220. // test hook data.
  6221. //
  6222. //
  6223. // casting unsigned to/from void * is OK in this case.
  6224. //
  6225. #pragma warning(push)
  6226. #pragma warning(disable:4312)
  6227. NEW_NAMED_SDICT2( TEST_HOOK, RPC_TEST_HOOK_FN_RAW, RPC_TEST_HOOK_ID );
  6228. #pragma warning(pop)
  6229. TEST_HOOK_DICT2 * pTestHookDict;
  6230. RPCRTAPI
  6231. DWORD
  6232. RPC_ENTRY
  6233. I_RpcSetTestHook(
  6234. RPC_TEST_HOOK_ID id,
  6235. RPC_TEST_HOOK_FN fn
  6236. )
  6237. {
  6238. InitializeIfNecessary();
  6239. GlobalMutexRequest();
  6240. if (0 == pTestHookDict)
  6241. {
  6242. pTestHookDict = new TEST_HOOK_DICT2;
  6243. if (!pTestHookDict)
  6244. {
  6245. GlobalMutexClear();
  6246. return ERROR_NOT_ENOUGH_MEMORY;
  6247. }
  6248. }
  6249. pTestHookDict->Delete( id );
  6250. pTestHookDict->Insert( id, fn );
  6251. GlobalMutexClear();
  6252. return 0;
  6253. }
  6254. void
  6255. ForceCallTestHook(
  6256. RPC_TEST_HOOK_ID id,
  6257. PVOID subject,
  6258. PVOID object
  6259. )
  6260. {
  6261. if (pTestHookDict)
  6262. {
  6263. RPC_TEST_HOOK_FN fn = pTestHookDict->Find( id );
  6264. if (fn)
  6265. {
  6266. (*fn)(id, subject, object);
  6267. }
  6268. }
  6269. }
  6270. RPC_TEST_HOOK_FN
  6271. GetTestHook(
  6272. RPC_TEST_HOOK_ID id
  6273. )
  6274. {
  6275. return pTestHookDict->Find( id );
  6276. }