Leaked source code of windows server 2003
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.

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