Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11975 lines
327 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. osfclnt.cxx
  5. Abstract:
  6. This file contains the client side implementation of the OSF connection
  7. oriented RPC protocol engine.
  8. Author:
  9. Michael Montague (mikemon) 17-Jul-1990
  10. Revision History:
  11. Mazhar Mohammed (mazharm) 11-08-1996 - Major re-haul to support async:
  12. - Added support for Async RPC, Pipes
  13. - Changed it to operate as a state machine
  14. - Changed class structure
  15. - Got rid of the TRANS classes.
  16. Kamen Moutafov (kamenm) Jan-2000 Support for multiple transfer syntaxes
  17. Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
  18. Kamen Moutafov (KamenM) Mar-2000 Support for extended error info
  19. --*/
  20. #include <precomp.hxx>
  21. #include <osfpcket.hxx>
  22. #include <bitset.hxx>
  23. #include <queue.hxx>
  24. #include <ProtBind.hxx>
  25. #include <osfclnt.hxx>
  26. #include <rpccfg.h>
  27. #include <epmap.h>
  28. #include <twrtypes.h>
  29. #include <hndlsvr.hxx>
  30. #include <schnlsp.h>
  31. #include <charconv.hxx>
  32. //
  33. // Maximum retries in light of getting a shutdown
  34. // or closed in doing a bind or shutdown
  35. //
  36. #define MAX_RETRIES 3
  37. // #define RPC_IDLE_CLEANUP_AUDIT
  38. NEW_SDICT(OSF_CASSOCIATION);
  39. MUTEX *AssocDictMutex = NULL;
  40. OSF_CASSOCIATION_DICT * AssociationDict;
  41. long OsfLingeredAssociations = 0;
  42. const long MaxOsfLingeredAssociations = 8;
  43. ULONG OsfDestroyedAssociations = 0;
  44. const ULONG NumberOfOsfDestroyedAssociationsToSample = 128;
  45. // in 100 nano-second intervals, this constant is 2 seconds
  46. const DWORD DestroyedOsfAssociationBatchThreshold = 1000 * 10 * 1000 * 2;
  47. ULARGE_INTEGER OsfLastDestroyedAssociationsBatchTimestamp;
  48. OSF_BINDING_HANDLE::OSF_BINDING_HANDLE (
  49. IN OUT RPC_STATUS * Status
  50. ) : BINDING_HANDLE(Status)
  51. {
  52. ALLOCATE_THIS(OSF_BINDING_HANDLE);
  53. ObjectType = OSF_BINDING_HANDLE_TYPE;
  54. Association = 0;
  55. ReferenceCount = 1;
  56. DceBinding = 0;
  57. TransInfo = 0;
  58. TransAuthInitialized = 0;
  59. pToken = 0;
  60. }
  61. OSF_BINDING_HANDLE::~OSF_BINDING_HANDLE (
  62. )
  63. {
  64. OSF_RECURSIVE_ENTRY *RecursiveEntry;
  65. DictionaryCursor cursor;
  66. if (Association != 0)
  67. {
  68. Unbind();
  69. }
  70. else
  71. {
  72. delete DceBinding;
  73. }
  74. RecursiveCalls.Reset(cursor);
  75. while ((RecursiveEntry = RecursiveCalls.Next(cursor)))
  76. {
  77. delete RecursiveEntry->CCall;
  78. }
  79. }
  80. RPC_STATUS
  81. OSF_BINDING_HANDLE::AcquireCredentialsForTransport(
  82. )
  83. /*++
  84. Function Name:AcquireCredentialsForTransport
  85. Parameters:
  86. Description:
  87. Returns:
  88. --*/
  89. {
  90. BOOL Result, fTokenFound;
  91. unsigned long Size;
  92. RPC_STATUS Status;
  93. HANDLE ImpersonationToken = 0;
  94. TOKEN_STATISTICS TokenStatisticsInformation;
  95. //
  96. // This function is called only when RPC security is not being used
  97. //
  98. ASSERT(fNamedPipe == 1);
  99. ASSERT(ClientAuthInfo.AuthenticationService == RPC_C_AUTHN_NONE);
  100. ASSERT(Association);
  101. if (OpenThreadToken (GetCurrentThread(),
  102. TOKEN_IMPERSONATE | TOKEN_QUERY,
  103. TRUE,
  104. &ImpersonationToken) == FALSE)
  105. {
  106. ClientAuthInfo.DefaultLogonId = TRUE;
  107. pToken = NULL;
  108. if (GetLastError() != ERROR_NO_TOKEN)
  109. {
  110. return RPC_S_ACCESS_DENIED;
  111. }
  112. return RPC_S_OK;
  113. }
  114. Result = GetTokenInformation(
  115. ImpersonationToken,
  116. TokenStatistics,
  117. &TokenStatisticsInformation,
  118. sizeof(TOKEN_STATISTICS),
  119. &Size
  120. );
  121. if (Result != TRUE)
  122. {
  123. ClientAuthInfo.DefaultLogonId = TRUE;
  124. CloseHandle(ImpersonationToken);
  125. return RPC_S_ACCESS_DENIED;
  126. }
  127. ClientAuthInfo.DefaultLogonId = FALSE;
  128. Status = Association->FindOrCreateToken(
  129. ImpersonationToken,
  130. &TokenStatisticsInformation.AuthenticationId,
  131. &pToken,
  132. &fTokenFound);
  133. if (Status != RPC_S_OK)
  134. {
  135. //
  136. // If there is a failure, the callee will free the token
  137. //
  138. return Status;
  139. }
  140. if (fTokenFound)
  141. {
  142. CloseHandle(ImpersonationToken);
  143. }
  144. ASSERT(pToken);
  145. FastCopyLUIDAligned(&ClientAuthInfo.ModifiedId, &pToken->ModifiedId);
  146. return RPC_S_OK;
  147. }
  148. BOOL
  149. ReplaceToken(
  150. HANDLE NewToken
  151. )
  152. /*++
  153. Function Name:ReplaceToken
  154. Parameters:
  155. Description:
  156. Returns:
  157. --*/
  158. {
  159. NTSTATUS NtStatus;
  160. HANDLE hTokenToReplace = NewToken;
  161. //
  162. // This thread should either have a null token or
  163. // the token we captured in Initialize. It cannot have
  164. // any other token.
  165. //
  166. NtStatus = NtSetInformationThread(NtCurrentThread(),
  167. ThreadImpersonationToken,
  168. &hTokenToReplace,
  169. sizeof(HANDLE));
  170. if (!NT_SUCCESS(NtStatus))
  171. {
  172. return FALSE;
  173. }
  174. return TRUE;
  175. }
  176. BOOL
  177. OSF_BINDING_HANDLE::SwapToken (
  178. HANDLE *OldToken
  179. )
  180. /*++
  181. Function Name:SwapToken
  182. Parameters:
  183. Description:
  184. Returns:
  185. --*/
  186. {
  187. HANDLE ImpersonationToken = 0;
  188. HANDLE NewToken ;
  189. *OldToken = 0;
  190. if (!(ClientAuthInfo.AuthenticationService == RPC_C_AUTHN_NONE && fNamedPipe))
  191. {
  192. return FALSE;
  193. }
  194. if (pToken == 0)
  195. {
  196. NewToken = 0;
  197. }
  198. else
  199. {
  200. NewToken = pToken->hToken;
  201. }
  202. ImpersonationToken = 0;
  203. if (OpenThreadToken (GetCurrentThread(),
  204. TOKEN_IMPERSONATE | TOKEN_QUERY,
  205. TRUE,
  206. &ImpersonationToken) == FALSE)
  207. {
  208. ImpersonationToken = 0;
  209. }
  210. if (ReplaceToken(NewToken) == FALSE)
  211. {
  212. if (ImpersonationToken)
  213. {
  214. CloseHandle(ImpersonationToken);
  215. }
  216. return FALSE;
  217. }
  218. *OldToken = ImpersonationToken;
  219. return TRUE;
  220. }
  221. RPC_STATUS
  222. OSF_BINDING_HANDLE::NegotiateTransferSyntax (
  223. IN OUT PRPC_MESSAGE Message
  224. )
  225. /*++
  226. Function Name:NegotiateTransferSyntax
  227. Parameters:
  228. Description:
  229. Negotiate a transfer syntax, if necessary. A bind/alter context may be done
  230. in the process.
  231. Returns:
  232. Status of the operation
  233. --*/
  234. {
  235. OSF_CCALL *CCall;
  236. RPC_STATUS Status;
  237. unsigned int NotChangedRetry = 0;
  238. unsigned int Retry;
  239. RPC_CLIENT_INTERFACE *ClientInterface;
  240. BOOL fResult;
  241. BOOL fRetry;
  242. AssocDictMutex->VerifyNotOwned();
  243. for (;;)
  244. {
  245. Retry = 0;
  246. for (;;)
  247. {
  248. //
  249. // Allocate a call object.
  250. //
  251. Status = AllocateCCall(&CCall, Message, &fRetry);
  252. Message->Handle = (RPC_BINDING_HANDLE) CCall;
  253. if (Status == RPC_S_OK)
  254. {
  255. // by now the Binding in the CCall should have
  256. // been fixed or in the async case, NDR20 should have been
  257. // used
  258. ClientInterface = (RPC_CLIENT_INTERFACE *)Message->RpcInterfaceInformation;
  259. if (DoesInterfaceSupportMultipleTransferSyntaxes(ClientInterface))
  260. Message->TransferSyntax = CCall->GetSelectedBinding()->GetTransferSyntaxId();
  261. return Status;
  262. }
  263. if ((Status != RPC_P_CONNECTION_SHUTDOWN)
  264. && (Status != RPC_P_CONNECTION_CLOSED)
  265. && (fRetry == FALSE))
  266. {
  267. break;
  268. }
  269. if (this->Association != 0)
  270. {
  271. Association->ShutdownRequested(Status, NULL);
  272. }
  273. Retry++;
  274. if (Retry == MAX_RETRIES)
  275. break;
  276. }
  277. if (Status == EPT_S_NOT_REGISTERED)
  278. {
  279. BindingMutex.Request();
  280. if (DceBinding == NULL)
  281. {
  282. // in a scenario where multiple threads make an RPC
  283. // call on the same binding handle, it is possible that
  284. // even though this thread failed with EPT_S_NOT_REGISTERED
  285. // another thread succeeded and transferred the ownership of
  286. // the DceBinding to the association. In such case we're
  287. // already bound to an association, and all we need is to
  288. // loop around and try the call again
  289. BindingMutex.Clear();
  290. continue;
  291. }
  292. // we ran out of endpoints - drop the endpoint set for the next
  293. // iteration
  294. fResult = DceBinding->MaybeMakePartiallyBound(
  295. (PRPC_CLIENT_INTERFACE)Message->RpcInterfaceInformation,
  296. InqPointerAtObjectUuid());
  297. if (fResult)
  298. {
  299. if ( *InquireEpLookupHandle() != 0 )
  300. {
  301. EpFreeLookupHandle(*InquireEpLookupHandle());
  302. *InquireEpLookupHandle() = 0;
  303. }
  304. }
  305. BindingMutex.Clear();
  306. break;
  307. }
  308. if (Status != RPC_S_SERVER_UNAVAILABLE)
  309. {
  310. break;
  311. }
  312. // if this is either a static endpoint, or an endpoint resolved through
  313. // the interface information, there is no need to iterate
  314. if (!fDynamicEndpoint
  315. ||
  316. ((RPC_CLIENT_INTERFACE *)Message->RpcInterfaceInformation)->RpcProtseqEndpointCount)
  317. {
  318. break;
  319. }
  320. //
  321. // If we reach here, it means that we are iterating through the list
  322. // of endpoints obtained from the endpoint mapper.
  323. //
  324. BindingMutex.Request();
  325. if (ReferenceCount == 1
  326. && Association != 0)
  327. {
  328. // there is an association (which means the server's endpoint
  329. // mapper was contacted), and the refcount is 1 (we're the
  330. // only user). We know this is a dynamic endpoint. We have
  331. // the following cases to take care of:
  332. // - the list of endpoints is exhausted. If this is the case,
  333. // we wouldn't have gotten here, as we will get
  334. // EPT_S_NOT_REGISTERED from AllocateCCall and we would
  335. // have bailed out earlier on the first iteration. Since
  336. // the code above would have dropped the endpoints list for
  337. // the next iteration, we will be fine
  338. // - we're iterating over the list of endpoints in the same
  339. // call. In this case, we will be getting server unavailable
  340. // from each endpoint for which the server is not there,
  341. // and we will move on to the next endpoint, until we exhaust
  342. // them and get EPT_S_NOT_REGISTERED
  343. DceBinding = Association->DuplicateDceBinding();
  344. Unbind();
  345. if (DceBinding == NULL)
  346. {
  347. BindingMutex.Clear();
  348. return RPC_S_OUT_OF_MEMORY;
  349. }
  350. RpcpErrorAddRecord(EEInfoGCRuntime,
  351. Status,
  352. EEInfoDLOSF_BINDING_HANDLE__NegotiateTransferSyntax10,
  353. DceBinding->InqEndpoint()
  354. );
  355. // whack the endpoint and move on to the next (if any)
  356. fResult = DceBinding->MaybeMakePartiallyBound(
  357. (PRPC_CLIENT_INTERFACE)Message->RpcInterfaceInformation,
  358. InqPointerAtObjectUuid());
  359. if (fResult == FALSE)
  360. {
  361. NotChangedRetry += 1;
  362. RpcpPurgeEEInfo();
  363. }
  364. else
  365. {
  366. // we don't purge here because we want next iterations
  367. // to add to the record
  368. NotChangedRetry = 0;
  369. }
  370. }
  371. else
  372. {
  373. // either there is more then one reference to the binding handle,
  374. // or the endpoint mapper could not be contacted (i.e. no
  375. // association)
  376. NotChangedRetry += 1;
  377. RpcpPurgeEEInfo();
  378. }
  379. BindingMutex.Clear();
  380. if (NotChangedRetry > 4)
  381. {
  382. return(RPC_S_SERVER_UNAVAILABLE);
  383. }
  384. }
  385. ASSERT(Status != RPC_S_OK);
  386. if (Status == RPC_P_CONNECTION_CLOSED
  387. || Status == RPC_P_CONNECTION_SHUTDOWN)
  388. {
  389. return(RPC_S_CALL_FAILED_DNE);
  390. }
  391. return(Status);
  392. }
  393. RPC_STATUS
  394. OSF_BINDING_HANDLE::GetBuffer (
  395. IN PRPC_MESSAGE Message,
  396. IN UUID *ObjectUuid
  397. )
  398. /*++
  399. Function Name:GetBuffer
  400. Parameters:
  401. Description:
  402. Ask the call object for a buffer
  403. Returns:
  404. --*/
  405. {
  406. ASSERT(!"We should never be here - the binding handle cannot allocate a buffer");
  407. return RPC_S_INTERNAL_ERROR;
  408. }
  409. RPC_STATUS
  410. OSF_BINDING_HANDLE::AllocateCCall (
  411. OUT OSF_CCALL * *CCall,
  412. IN PRPC_MESSAGE Message,
  413. OUT BOOL *Retry
  414. )
  415. /*++
  416. Function Name:AllocateCCall
  417. Parameters:
  418. CCall - Returns the allocated Call object
  419. Message - The RPC_MESSAGE for this call.
  420. Retry - if set on output, the caller should retry the allocation.
  421. Description:
  422. Finds an existing association or creates a new one. Asks the association
  423. to allocate the call object for us.
  424. Returns:
  425. RPC_S_OK or an error code.
  426. --*/
  427. {
  428. OSF_RECURSIVE_ENTRY *RecursiveEntry;
  429. CLIENT_AUTH_INFO * AuthInfo;
  430. RPC_STATUS Status;
  431. BOOL fDynamic = FALSE;
  432. CLIENT_AUTH_INFO AuthInfo2;
  433. DictionaryCursor cursor;
  434. BOOL fBindingHandleReferenceRemoved;
  435. ULONG_PTR CallTimeout;
  436. *Retry = FALSE;
  437. BindingMutex.Request();
  438. //
  439. // First we need to check if there is already a recursive Call
  440. // for this thread and interface. To make the common case quicker,
  441. // we will check to see if there are any Calls in the dictionary
  442. // first. ** We will find a recursive call only in the case of callbacks **
  443. //
  444. if ( RecursiveCalls.Size() != 0 )
  445. {
  446. RecursiveCalls.Reset(cursor);
  447. while ( (RecursiveEntry = RecursiveCalls.Next(cursor)) != 0 )
  448. {
  449. *CCall = RecursiveEntry->IsThisMyRecursiveCall(
  450. GetThreadIdentifier(),
  451. (RPC_CLIENT_INTERFACE *)
  452. Message->RpcInterfaceInformation);
  453. if ( *CCall != 0 )
  454. {
  455. BindingMutex.Clear();
  456. if ((*CCall)->CurrentState == Aborted)
  457. {
  458. return (*CCall)->AsyncStatus;
  459. }
  460. //
  461. // This reference will be removed when the send
  462. // for this call is complete
  463. //
  464. (*CCall)->CurrentState = SendingFirstBuffer;
  465. return(RPC_S_OK);
  466. }
  467. }
  468. }
  469. if (Association == 0)
  470. {
  471. // if we don't have an object UUID, and we have a dynamic endpoint,
  472. // attempt quick resolution
  473. if (InqIfNullObjectUuid() && DceBinding->IsNullEndpoint())
  474. {
  475. Association = FindOrCreateAssociation(
  476. DceBinding,
  477. TransInfo,
  478. (RPC_CLIENT_INTERFACE *)Message->RpcInterfaceInformation
  479. );
  480. AssocDictMutex->VerifyNotOwned();
  481. // do nothing in both cases. In failure case, we will do full
  482. // resolution. In success case, ownership of the dce binding
  483. // has passed to the association, and we don't need to copy
  484. // the resolved endpoint back
  485. }
  486. // if we are still NULL, attempt full resolution
  487. if (Association == NULL)
  488. {
  489. Status = OSF_BINDING_HANDLE::InqTransportOption(
  490. RPC_C_OPT_CALL_TIMEOUT,
  491. &CallTimeout);
  492. // this function cannot fail unless it is given invalid
  493. // parameters
  494. ASSERT(Status == RPC_S_OK);
  495. Status = DceBinding->ResolveEndpointIfNecessary(
  496. (RPC_CLIENT_INTERFACE *)
  497. Message->RpcInterfaceInformation,
  498. InqPointerAtObjectUuid(),
  499. InquireEpLookupHandle(),
  500. FALSE,
  501. InqComTimeout(),
  502. (ULONG)CallTimeout,
  503. &ClientAuthInfo
  504. );
  505. if ( Status != RPC_S_OK )
  506. {
  507. BindingMutex.Clear();
  508. return(Status);
  509. }
  510. Association = FindOrCreateAssociation(
  511. DceBinding,
  512. TransInfo,
  513. NULL
  514. );
  515. AssocDictMutex->VerifyNotOwned();
  516. if (Association == 0)
  517. {
  518. BindingMutex.Clear();
  519. return RPC_S_OUT_OF_MEMORY;
  520. }
  521. }
  522. //
  523. // Ownership of the DCE binding passes to the association. We are
  524. // going to set the field to zero so that no one screws with them.
  525. //
  526. DceBinding = 0;
  527. if (ClientAuthInfo.AuthenticationService == RPC_C_AUTHN_NONE && fNamedPipe)
  528. {
  529. if (TransAuthInitialized == 0)
  530. {
  531. Status = AcquireCredentialsForTransport();
  532. if (Status != RPC_S_OK)
  533. {
  534. BindingMutex.Clear();
  535. return Status;
  536. }
  537. TransAuthInitialized = 1;
  538. }
  539. }
  540. }
  541. else
  542. {
  543. if (Association->IsValid() == 0)
  544. {
  545. if (ReferenceCount == 1)
  546. {
  547. DceBinding = Association->DuplicateDceBinding();
  548. if (DceBinding == 0)
  549. {
  550. Status = RPC_S_OUT_OF_MEMORY;
  551. }
  552. else
  553. {
  554. Status = Association->AssociationShutdownError;
  555. Unbind();
  556. *Retry = TRUE;
  557. }
  558. }
  559. else
  560. {
  561. Status = Association->AssociationShutdownError;
  562. }
  563. BindingMutex.Clear();
  564. return Status;
  565. }
  566. }
  567. //
  568. // We will assume that we are successfully able to allocate a Call,
  569. // so we bump the reference count now.
  570. //
  571. ReferenceCount++;
  572. AuthInfo = InquireAuthInformation();
  573. //
  574. // If this is a secure BH and it requires DYNAMIC TRACKING, check if
  575. // LogonID has changed. If it has changed, get new Credential Handle
  576. //
  577. if ((AuthInfo != 0)
  578. && (AuthInfo->AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  579. && (AuthInfo->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC))
  580. {
  581. Status = ReAcquireCredentialsIfNecessary();
  582. if (Status != RPC_S_OK)
  583. {
  584. ReferenceCount -=1;
  585. BindingMutex.Clear();
  586. return (Status);
  587. }
  588. fDynamic = TRUE;
  589. AuthInfo = AuthInfo->ShallowCopyTo(&AuthInfo2);
  590. AuthInfo->ReferenceCredentials();
  591. }
  592. BindingMutex.Clear();
  593. Status = Association->AllocateCCall(
  594. this,
  595. Message,
  596. AuthInfo,
  597. CCall,
  598. &fBindingHandleReferenceRemoved);
  599. if (fDynamic)
  600. AuthInfo->PrepareForDestructionAfterShallowCopy();
  601. if ( Status == RPC_S_OK )
  602. {
  603. if ((*CCall)->CurrentState != SendingFirstBuffer
  604. && (*CCall)->Connection->fExclusive)
  605. {
  606. OSF_CCALL_STATE myState = (*CCall)->CurrentState;
  607. Status = (*CCall)->BindToServer(
  608. FALSE // sync bind
  609. );
  610. if (Status != RPC_S_OK)
  611. {
  612. //
  613. // Call has not yet started, ok to directly
  614. // free the call.
  615. //
  616. if (myState == NeedOpenAndBind)
  617. {
  618. (*CCall)->FreeCCall(RPC_S_CALL_FAILED_DNE);
  619. }
  620. else
  621. {
  622. (*CCall)->FreeCCall(Status);
  623. }
  624. }
  625. }
  626. }
  627. else
  628. {
  629. if (fBindingHandleReferenceRemoved == 0)
  630. {
  631. BindingMutex.Request();
  632. ReferenceCount -= 1;
  633. ASSERT( ReferenceCount != 0 );
  634. BindingMutex.Clear();
  635. }
  636. }
  637. return Status;
  638. }
  639. RPC_STATUS
  640. OSF_BINDING_HANDLE::BindingCopy (
  641. OUT BINDING_HANDLE * * DestinationBinding,
  642. IN UINT MaintainContext
  643. )
  644. /*++
  645. Routine Description:
  646. We need to copy this binding handle. This is relatively easy to
  647. do: we just need to point the copied binding handle to the same
  648. association as this binding handle. We also need to tell the
  649. association about the new binding handle.
  650. Arguments:
  651. DestinationBinding - Returns a copy of this binding handle.
  652. MaintainContext - Supplies a flag that indicates whether or not context
  653. is being maintained over this binding handle. A non-zero value
  654. indicates that context is being maintained.
  655. Return Value:
  656. RPC_S_OUT_OF_MEMORY - This indicates that there is not enough memory
  657. to allocate a new binding handle.
  658. RPC_S_OK - We successfully copied this binding handle.
  659. --*/
  660. {
  661. RPC_STATUS Status = RPC_S_OK;
  662. OSF_BINDING_HANDLE * Binding;
  663. RPC_UUID Uuid;
  664. CLIENT_AUTH_INFO * AuthInfo;
  665. Binding = new OSF_BINDING_HANDLE(&Status);
  666. if ( Status != RPC_S_OK )
  667. {
  668. delete Binding;
  669. Binding = 0;
  670. }
  671. if ( Binding == 0 )
  672. {
  673. *DestinationBinding = 0;
  674. return(RPC_S_OUT_OF_MEMORY);
  675. }
  676. BindingMutex.Request();
  677. Status = Binding->BINDING_HANDLE::Clone( this );
  678. if (Status != RPC_S_OK)
  679. {
  680. delete Binding;
  681. Binding = 0;
  682. *DestinationBinding = 0;
  683. BindingMutex.Clear();
  684. return Status;
  685. }
  686. Binding->ClientAuthInfo.DefaultLogonId = ClientAuthInfo.DefaultLogonId;
  687. Binding->fNamedPipe = fNamedPipe;
  688. Binding->fDynamicEndpoint = fDynamicEndpoint;
  689. if (pToken)
  690. {
  691. ASSERT(Association);
  692. ASSERT(fNamedPipe);
  693. Association->ReferenceToken(pToken);
  694. Binding->pToken = pToken;
  695. FastCopyLUIDAligned(&(Binding->ClientAuthInfo.ModifiedId),
  696. &(pToken->ModifiedId));
  697. }
  698. Binding->Association = Association;
  699. if ( DceBinding != 0 )
  700. {
  701. ASSERT( MaintainContext == 0 );
  702. Binding->DceBinding = DceBinding->DuplicateDceBinding();
  703. }
  704. else
  705. {
  706. Binding->DceBinding = 0;
  707. }
  708. Binding->TransInfo = TransInfo;
  709. if ( Association != 0 )
  710. {
  711. Association->IncrementCount();
  712. if ( MaintainContext != 0 )
  713. {
  714. Association->MaintainingContext();
  715. }
  716. }
  717. BindingMutex.Clear();
  718. *DestinationBinding = (BINDING_HANDLE *) Binding;
  719. return(RPC_S_OK);
  720. }
  721. RPC_STATUS
  722. OSF_BINDING_HANDLE::BindingFree (
  723. )
  724. /*++
  725. Routine Description:
  726. This method gets called when the application calls RpcBindingFree.
  727. All we have got to do is to decrement the reference count, and if
  728. it has reached zero, delete the binding handle.
  729. Return Value:
  730. RPC_S_OK - This operation always succeeds.
  731. --*/
  732. {
  733. BindingMutex.Request();
  734. ReferenceCount -= 1;
  735. if ( ReferenceCount == 0 )
  736. {
  737. BindingMutex.Clear();
  738. delete this;
  739. }
  740. else
  741. {
  742. BindingMutex.Clear();
  743. }
  744. return(RPC_S_OK);
  745. }
  746. RPC_STATUS
  747. OSF_BINDING_HANDLE::PrepareBindingHandle (
  748. IN TRANS_INFO * TransInfo,
  749. IN DCE_BINDING * DceBinding
  750. )
  751. /*++
  752. Routine Description:
  753. This method will be called just before a new binding handle is returned
  754. to the user. We just stash the transport interface and binding
  755. information so we can use it later when the first remote procedure
  756. call is made. At that time, we will actually bind to the interface.
  757. Arguments:
  758. TransportInterface - Supplies a pointer to a data structure describing
  759. a loadable transport.
  760. DceBinding - Supplies the binding information for this binding handle.
  761. --*/
  762. {
  763. this->TransInfo = (TRANS_INFO *) TransInfo;
  764. this->DceBinding = DceBinding;
  765. fDynamicEndpoint = DceBinding->IsNullEndpoint();
  766. // we count it as named pipes only in the remote case
  767. fNamedPipe = DceBinding->IsNamedPipeTransport() && DceBinding->InqNetworkAddress();
  768. Association = 0;
  769. return RPC_S_OK;
  770. }
  771. RPC_STATUS
  772. OSF_BINDING_HANDLE::ToStringBinding (
  773. OUT RPC_CHAR * * StringBinding
  774. )
  775. /*++
  776. Routine Description:
  777. We need to convert the binding handle into a string binding. If the
  778. binding handle has not yet been used to make a remote procedure
  779. call, then we can just use the information in the binding handle to
  780. create the string binding. Otherwise, we need to ask the association
  781. to do it for us.
  782. Arguments:
  783. StringBinding - Returns the string representation of the binding
  784. handle.
  785. Return Value:
  786. RPC_S_OK - The operation completed successfully.
  787. RPC_S_OUT_OF_MEMORY - We do not have enough memory available to
  788. allocate space for the string binding.
  789. --*/
  790. {
  791. if ( Association == 0 )
  792. {
  793. *StringBinding = DceBinding->StringBindingCompose(
  794. InqPointerAtObjectUuid());
  795. if (*StringBinding == 0)
  796. return(RPC_S_OUT_OF_MEMORY);
  797. return(RPC_S_OK);
  798. }
  799. return(Association->ToStringBinding(StringBinding,
  800. InqPointerAtObjectUuid()));
  801. }
  802. RPC_STATUS
  803. OSF_BINDING_HANDLE::BindingReset (
  804. )
  805. /*++
  806. Routine Description:
  807. This routine will set the endpoint of this binding handle to zero,
  808. if possible. The binding handle will become partially bound as a
  809. result. If a remote procedure call has been made on this binding
  810. handle, it will fail as well.
  811. Return Value:
  812. RPC_S_OK - The binding handle has successfully been made partially
  813. bound.
  814. RPC_S_WRONG_KIND_OF_BINDING - The binding handle currently has remote
  815. procedure calls active.
  816. --*/
  817. {
  818. BindingMutex.Request();
  819. if ( Association != 0 )
  820. {
  821. if ( ReferenceCount != 1 )
  822. {
  823. BindingMutex.Clear();
  824. return(RPC_S_WRONG_KIND_OF_BINDING);
  825. }
  826. DceBinding = Association->DuplicateDceBinding();
  827. if (DceBinding == NULL)
  828. {
  829. BindingMutex.Clear();
  830. return RPC_S_OUT_OF_MEMORY;
  831. }
  832. Unbind();
  833. }
  834. DceBinding->MakePartiallyBound();
  835. fDynamicEndpoint = TRUE;
  836. if ( *InquireEpLookupHandle() != 0 )
  837. {
  838. EpFreeLookupHandle(*InquireEpLookupHandle());
  839. *InquireEpLookupHandle() = 0;
  840. }
  841. BindingMutex.Clear();
  842. return(RPC_S_OK);
  843. }
  844. ULONG
  845. OSF_BINDING_HANDLE::MapAuthenticationLevel (
  846. IN ULONG AuthenticationLevel
  847. )
  848. /*++
  849. Routine Description:
  850. The connection oriented protocol module supports all authentication
  851. levels except for RPC_C_AUTHN_LEVEL_CALL. We just need to map it
  852. to RPC_C_AUTHN_LEVEL_PKT.
  853. --*/
  854. {
  855. UNUSED(this);
  856. if ( AuthenticationLevel == RPC_C_AUTHN_LEVEL_CALL )
  857. {
  858. return(RPC_C_AUTHN_LEVEL_PKT);
  859. }
  860. return(AuthenticationLevel);
  861. }
  862. RPC_STATUS
  863. OSF_BINDING_HANDLE::ResolveBinding (
  864. IN PRPC_CLIENT_INTERFACE RpcClientInterface
  865. )
  866. /*++
  867. Routine Description:
  868. We need to try and resolve the endpoint for this binding handle
  869. if necessary (the binding handle is partially-bound). We check
  870. to see if an association has been obtained for this binding
  871. handle; if so, we need to do nothing since the binding handle is
  872. fully-bound, otherwise, we try and resolve an endpoint for it.
  873. Arguments:
  874. RpcClientInterface - Supplies interface information to be used
  875. in resolving the endpoint.
  876. Return Value:
  877. RPC_S_OK - The binding handle is now fully-bound.
  878. RPC_S_NO_ENDPOINT_FOUND - We were unable to resolve the endpoint
  879. for this particular combination of binding handle (network address)
  880. and interface.
  881. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to resolve
  882. the endpoint.
  883. --*/
  884. {
  885. RPC_STATUS Status;
  886. BindingMutex.Request();
  887. if ( Association == 0 )
  888. {
  889. Status = DceBinding->ResolveEndpointIfNecessary(
  890. RpcClientInterface,
  891. InqPointerAtObjectUuid(),
  892. InquireEpLookupHandle(),
  893. FALSE,
  894. InqComTimeout(),
  895. INFINITE, // CallTimeout
  896. &ClientAuthInfo
  897. );
  898. }
  899. else
  900. {
  901. Status = RPC_S_OK;
  902. }
  903. BindingMutex.Clear();
  904. return(Status);
  905. }
  906. RPC_STATUS
  907. OSF_BINDING_HANDLE::AddRecursiveEntry (
  908. IN OSF_CCALL * CCall,
  909. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  910. )
  911. /*++
  912. Routine Description:
  913. When a callback occurs, we need to add an entry for the thread and
  914. interface being using for the callback to the binding handle. This
  915. is so that we can later turn original calls into callbacks if they
  916. are from the same thread (as the original call) and to the same
  917. interface (as the original call).
  918. Arguments:
  919. CCall - Supplies the Call on which the original call was
  920. sent.
  921. RpcInterfaceInformation - Supplies the interface used by the original
  922. call.
  923. Return Value:
  924. RPC_S_OK - An recursive entry has been added to the binding handle for
  925. the supplied Call and interface.
  926. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to perform the
  927. operation.
  928. --*/
  929. {
  930. OSF_RECURSIVE_ENTRY * RecursiveEntry;
  931. BindingMutex.Request();
  932. RecursiveEntry = new OSF_RECURSIVE_ENTRY(GetThreadIdentifier(),
  933. RpcInterfaceInformation, CCall);
  934. if ( RecursiveEntry == 0 )
  935. {
  936. BindingMutex.Clear();
  937. return(RPC_S_OUT_OF_MEMORY);
  938. }
  939. CCall->RecursiveCallsKey = RecursiveCalls.Insert(
  940. RecursiveEntry);
  941. if ( CCall->RecursiveCallsKey == -1 )
  942. {
  943. BindingMutex.Clear();
  944. delete RecursiveEntry;
  945. return(RPC_S_OUT_OF_MEMORY);
  946. }
  947. ReferenceCount += 1;
  948. BindingMutex.Clear();
  949. return(RPC_S_OK);
  950. }
  951. void
  952. OSF_BINDING_HANDLE::RemoveRecursiveCall (
  953. IN OSF_CCALL * CCall
  954. )
  955. /*++
  956. Routine Description:
  957. The specified Call is removed from the dictionary of active
  958. Calls for this binding handle.
  959. Arguments:
  960. CCall - Supplies the Call to be removed from the
  961. dictionary of active Calls.
  962. --*/
  963. {
  964. OSF_RECURSIVE_ENTRY * RecursiveEntry;
  965. BindingMutex.Request();
  966. RecursiveEntry = RecursiveCalls.Delete(CCall->RecursiveCallsKey);
  967. if ( RecursiveEntry != 0 )
  968. {
  969. delete RecursiveEntry;
  970. }
  971. CCall->RecursiveCallsKey = -1;
  972. ReferenceCount -= 1;
  973. BindingMutex.Clear();
  974. }
  975. OSF_CASSOCIATION *
  976. OSF_BINDING_HANDLE::FindOrCreateAssociation (
  977. IN DCE_BINDING * DceBinding,
  978. IN TRANS_INFO *TransInfo,
  979. IN RPC_CLIENT_INTERFACE *InterfaceInfo
  980. )
  981. /*++
  982. Function Name:FindOrCreateAssociation
  983. Parameters:
  984. DceBinding - Supplies binding information; ownership of this object
  985. passes to this routine.
  986. TransportInterface - Supplies a pointer to the data structure which
  987. describes a loadable transport.
  988. InterfaceInfo - Supplied the interface information for this call. Used
  989. to make quick resolution on new binding handles if existing bindings
  990. for this interface exist. If supplied, it takes precedence over
  991. endpoint matching for selecting an association, and no new association
  992. will be created - only existing ones will be found!
  993. Description:
  994. This routine finds an existing association supporting the requested
  995. DCE binding, or create a new association which supports the
  996. requested DCE binding. Ownership of the passed DceBinding pass
  997. to this routine.
  998. Returns:
  999. An association which supports the requested binding will be returned;
  1000. Otherwise, zero will be returned, indicating insufficient memory.
  1001. --*/
  1002. {
  1003. OSF_CASSOCIATION * CAssociation;
  1004. RPC_STATUS Status = RPC_S_OK;
  1005. DictionaryCursor cursor;
  1006. ULONG_PTR fUnique;
  1007. BOOL fOnlyEndpointDifferent;
  1008. int Result;
  1009. Status = OSF_BINDING_HANDLE::InqTransportOption(RPC_C_OPT_UNIQUE_BINDING, &fUnique);
  1010. ASSERT(Status == RPC_S_OK);
  1011. //
  1012. // We start be looking in the dictionary of existing associations
  1013. // to see if there is one supporting the binding information specified.
  1014. //
  1015. AssocDictMutex->Request();
  1016. if (fUnique == 0)
  1017. {
  1018. AssociationDict->Reset(cursor);
  1019. while ( (CAssociation = AssociationDict->Next(cursor)) != 0 )
  1020. {
  1021. if (CAssociation->IsValid())
  1022. {
  1023. Result = CAssociation->CompareWithDceBinding(DceBinding,
  1024. &fOnlyEndpointDifferent);
  1025. // if the DceBindings are the same, or they differ only
  1026. // by the endpoint, and it is a NULL endpoint, and there
  1027. // is InterfaceInfo specified, and this association
  1028. // supports at least one binding for this interface,
  1029. // choose the association
  1030. if (!Result
  1031. ||
  1032. (
  1033. fOnlyEndpointDifferent
  1034. && DceBinding->IsNullEndpoint()
  1035. && InterfaceInfo
  1036. && CAssociation->DoesBindingForInterfaceExist(InterfaceInfo)
  1037. )
  1038. )
  1039. {
  1040. if (CAssociation->Linger.fAssociationLingered == TRUE)
  1041. {
  1042. #if defined (RPC_GC_AUDIT)
  1043. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) OSF lingering association resurrected %X %S %S %S\n",
  1044. GetCurrentProcessId(), GetCurrentProcessId(), CAssociation,
  1045. CAssociation->DceBinding->InqRpcProtocolSequence(),
  1046. CAssociation->DceBinding->InqNetworkAddress(),
  1047. CAssociation->DceBinding->InqEndpoint());
  1048. #endif
  1049. OsfLingeredAssociations --;
  1050. ASSERT(OsfLingeredAssociations >= 0);
  1051. CAssociation->Linger.fAssociationLingered = FALSE;
  1052. }
  1053. CAssociation->IncrementCount();
  1054. AssocDictMutex->Clear();
  1055. delete DceBinding;
  1056. return(CAssociation);
  1057. }
  1058. }
  1059. }
  1060. }
  1061. // if asked to do short endpoint resolution, don't create new association
  1062. if (InterfaceInfo)
  1063. {
  1064. AssocDictMutex->Clear();
  1065. return NULL;
  1066. }
  1067. #if defined (RPC_GC_AUDIT)
  1068. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) Creating association to: %S, %S, %S\n",
  1069. GetCurrentProcessId(), GetCurrentProcessId(), DceBinding->InqRpcProtocolSequence(),
  1070. DceBinding->InqNetworkAddress(), DceBinding->InqEndpoint());
  1071. #endif
  1072. RPC_CONNECTION_TRANSPORT *ClientInfo =
  1073. (RPC_CONNECTION_TRANSPORT *) TransInfo->InqTransInfo();
  1074. CAssociation = new (ClientInfo->ResolverHintSize)
  1075. OSF_CASSOCIATION(DceBinding,
  1076. TransInfo,
  1077. &Status);
  1078. if ( (Status != RPC_S_OK) && (CAssociation != NULL) )
  1079. {
  1080. CAssociation->DceBinding = 0;
  1081. delete CAssociation;
  1082. CAssociation = 0;
  1083. }
  1084. if (CAssociation != 0)
  1085. {
  1086. CAssociation->Key = AssociationDict->Insert(CAssociation);
  1087. if (CAssociation->Key == -1)
  1088. {
  1089. CAssociation->DceBinding = 0;
  1090. delete CAssociation;
  1091. CAssociation = 0;
  1092. }
  1093. }
  1094. AssocDictMutex->Clear();
  1095. return(CAssociation);
  1096. }
  1097. RPC_STATUS
  1098. OSF_BINDING_HANDLE::SetTransportOption( IN unsigned long option,
  1099. IN ULONG_PTR optionValue )
  1100. {
  1101. if (option == RPC_C_OPT_DONT_LINGER)
  1102. {
  1103. if (Association == NULL)
  1104. return RPC_S_WRONG_KIND_OF_BINDING;
  1105. if (Association->GetDontLingerState())
  1106. return RPC_S_WRONG_KIND_OF_BINDING;
  1107. Association->SetDontLingerState((BOOL)optionValue);
  1108. return RPC_S_OK;
  1109. }
  1110. else
  1111. {
  1112. return BINDING_HANDLE::SetTransportOption(option, optionValue);
  1113. }
  1114. }
  1115. RPC_STATUS
  1116. OSF_BINDING_HANDLE::InqTransportOption( IN unsigned long option,
  1117. OUT ULONG_PTR * pOptionValue )
  1118. {
  1119. if (option == RPC_C_OPT_DONT_LINGER)
  1120. {
  1121. if (Association == NULL)
  1122. return RPC_S_WRONG_KIND_OF_BINDING;
  1123. *pOptionValue = Association->GetDontLingerState();
  1124. return RPC_S_OK;
  1125. }
  1126. else
  1127. {
  1128. return BINDING_HANDLE::InqTransportOption(option, pOptionValue);
  1129. }
  1130. }
  1131. #pragma optimize ("t", on)
  1132. OSF_CCONNECTION *
  1133. OSF_CASSOCIATION::LookForExistingConnection(
  1134. IN OSF_BINDING_HANDLE *BindingHandle,
  1135. IN BOOL fExclusive,
  1136. IN CLIENT_AUTH_INFO *ClientAuthInfo,
  1137. IN int *PresentationContexts,
  1138. IN int NumberOfPresentationContexts,
  1139. OUT int *PresentationContextSupported,
  1140. OUT OSF_CCALL_STATE *InitialCallState,
  1141. IN BOOL fUseSeparateConnection
  1142. )
  1143. /*++
  1144. Function Name:LookForExistingConnection
  1145. Parameters:
  1146. BindingHandle - the binding handle through which the call is made
  1147. fExclusive - non-zero if we are looking for an exclusive connection
  1148. zero otherwise
  1149. ClientAuthInfo - a connection must support this specified auth info
  1150. PresentationContexts - array of presentation contexts, any of which
  1151. is acceptable to our callers
  1152. NumberOfPresentationContexts - the size of the PresentationContexts
  1153. array
  1154. PreferredPresentationContext - the preferred presentation context for
  1155. this connection. -1 if no preferences. Note that this is taken
  1156. from a previous binding to the server - this is not the client
  1157. preference.
  1158. PresentationContextSupported - the presentation context that the
  1159. chosen connection supports. This is useful only if multiple
  1160. presentation contexts were given. Also, if the connection
  1161. supports multiple pcontexts and multiple pcontexts were given
  1162. this would be any of the pcontexts. This is an index into the
  1163. NumberOfPresentationContexts array. If the connection supports
  1164. none of the suggested presentation contexts, this is set to -1.
  1165. In this case, alter context is required
  1166. InitialCallState - the initial state that the call should have is
  1167. returned in this parameter
  1168. fUseSeparateconnection - if non-zero, a separate connection is requested
  1169. Description:
  1170. Returns:
  1171. --*/
  1172. {
  1173. OSF_CCONNECTION *CConnection, *FirstMatch = 0;
  1174. DictionaryCursor cursor;
  1175. RPC_STATUS Status;
  1176. ASSERT(ClientAuthInfo);
  1177. AssociationMutex.VerifyOwned();
  1178. *PresentationContextSupported = -1;
  1179. ActiveConnections.Reset(cursor);
  1180. if (fExclusive || fUseSeparateConnection)
  1181. {
  1182. INT cConnectionFree, cConnectionBusy;
  1183. if (fExclusive)
  1184. {
  1185. cConnectionFree = SYNC_CONN_FREE;
  1186. cConnectionBusy = SYNC_CONN_BUSY;
  1187. }
  1188. else
  1189. {
  1190. cConnectionFree = ASYNC_CONN_FREE;
  1191. cConnectionBusy = ASYNC_CONN_BUSY;
  1192. }
  1193. while ((CConnection = ActiveConnections.Next(cursor)) != 0)
  1194. {
  1195. if (cConnectionFree == (INT) CConnection->ThreadId
  1196. && CConnection->SupportedAuthInfo(ClientAuthInfo,
  1197. BindingHandle->fNamedPipe) != 0)
  1198. {
  1199. if (CConnection->SupportedPContext(PresentationContexts,
  1200. NumberOfPresentationContexts, PresentationContextSupported) !=0)
  1201. {
  1202. CConnection->ThreadId = cConnectionBusy;
  1203. *InitialCallState = SendingFirstBuffer;
  1204. break;
  1205. }
  1206. else
  1207. {
  1208. //
  1209. // We found a connection that will require an alt-context
  1210. // before we can use it.
  1211. //
  1212. FirstMatch = CConnection;
  1213. } // if-else
  1214. } // if
  1215. } // while
  1216. if (0 == CConnection && FirstMatch)
  1217. {
  1218. CConnection = FirstMatch ;
  1219. CConnection->ThreadId = cConnectionBusy;
  1220. *InitialCallState = NeedAlterContext;
  1221. }
  1222. }
  1223. else
  1224. {
  1225. DWORD ThreadId = GetCurrentThreadId();
  1226. while ((CConnection = ActiveConnections.Next(cursor)) != 0)
  1227. {
  1228. if (CConnection->SupportedAuthInfo(ClientAuthInfo,
  1229. BindingHandle->fNamedPipe) != 0)
  1230. {
  1231. if (CConnection->SupportedPContext(PresentationContexts,
  1232. NumberOfPresentationContexts, PresentationContextSupported) !=0)
  1233. {
  1234. if (ThreadId == CConnection->ThreadId)
  1235. {
  1236. //
  1237. // We found a connection where everything matches,
  1238. // including the thread id. Go ahead and use it.
  1239. //
  1240. *InitialCallState = SendingFirstBuffer;
  1241. break;
  1242. }
  1243. }
  1244. else
  1245. {
  1246. if (ThreadId == CConnection->ThreadId)
  1247. {
  1248. //
  1249. // We found a connection where the thread id matches, but
  1250. // it will need an alt-context, before it can be used. Mark it as
  1251. // our first choice.
  1252. //
  1253. FirstMatch = CConnection;
  1254. }
  1255. } // if-else
  1256. } // if
  1257. } // while
  1258. if (0 == CConnection && FirstMatch)
  1259. {
  1260. //
  1261. // Matching thread-id, but will need an alt-context, before
  1262. // it can be used. The alt-context will be sent when the call
  1263. // actually gets scheduled.
  1264. //
  1265. CConnection = FirstMatch;
  1266. *InitialCallState = NeedAlterContext;
  1267. }
  1268. } // if-else
  1269. if (CConnection)
  1270. {
  1271. if (fExclusive)
  1272. {
  1273. CConnection->fExclusive = 1;
  1274. }
  1275. else
  1276. {
  1277. CConnection->fExclusive = 0;
  1278. }
  1279. // CCONN++
  1280. CConnection->AddReference();
  1281. // mark this connection as just retrieved from the cache
  1282. // see the comments to the FreshFromCache flag
  1283. CConnection->SetFreshFromCacheFlag();
  1284. }
  1285. return CConnection;
  1286. }
  1287. #pragma optimize("", on)
  1288. /*
  1289. Mechanism: Multiple transfer syntax negotiation
  1290. Purpose: Negotiate a transfer syntax supported by both the client and
  1291. the server and optimal for the server (if there is a choice). It should
  1292. allow for fail-over of the server to a downlevel node in the case
  1293. of mixed clusters, but it is allowed to fail the first one or more calls
  1294. after the failover while it adjusts (this restricted implementation was
  1295. approved by MarioGo on RPC team meeting on Apr 10th, 2000).
  1296. Implementation: Here's the matrix for the scenarios. The only current
  1297. difference b/n sync and async is the initial conn establishment. The
  1298. matrix describes only the case where we support both (the others are
  1299. trivial)
  1300. Sync Calls:
  1301. Conn Av. Preference Action
  1302. ------------- ------------ -------------
  1303. No conn. Doesn't matter Offer both. Don't fix choice for call
  1304. Conn NDR20 Not set Alter context to both. This cannot
  1305. fail with invalid xfer syntax.
  1306. Conn NDR20 NDR20 Use the conn.
  1307. Conn NDR20 NDR64 The connection is stale. Use the
  1308. connection anyway. We know it will
  1309. blow and we'll open a new one.
  1310. Conn NDR64 Not set Alter context to both. This cannot
  1311. fail with invalid xfer syntax.
  1312. Conn NDR64 NDR20 The connection is stale. Use the
  1313. connection anyway. We know it will
  1314. blow and we'll open a new one.
  1315. Conn NDR64 NDR64 Use the conn
  1316. Conn both Any Use preference.
  1317. Non-sync Calls:
  1318. Conn Av. Preference Action
  1319. ------------- ------------ -------------
  1320. No conn. Not set Offer both. If NDR64 is negotiated,
  1321. negotiate once more (alter context)
  1322. for NDR20, so that we can send the first
  1323. call, which was marshalled NDR20.
  1324. Conn NDR20 Not set Alter context to both. Choose NDR20.
  1325. Conn NDR20 NDR20 Use the conn.
  1326. Conn NDR20 NDR64 The connection is stale. Use the
  1327. connection anyway. We know it will
  1328. blow and we'll open a new one.
  1329. Conn NDR64 Not set Alter context to both. Choose NDR20.
  1330. If NDR64 is chosen, alter context
  1331. to NDR20. If NDR20 is chosen, use it.
  1332. Conn NDR64 NDR20 The connection is stale. Use the
  1333. connection anyway. We know it will
  1334. blow and we'll open a new one.
  1335. Conn NDR64 NDR64 Use the conn
  1336. Conn both All Use preference.
  1337. */
  1338. const int AUTO_ENABLE_IDLE_CLEANUP = 70;
  1339. RPC_STATUS
  1340. OSF_CASSOCIATION::AllocateCCall (
  1341. IN OSF_BINDING_HANDLE *BindingHandle,
  1342. IN PRPC_MESSAGE Message,
  1343. IN CLIENT_AUTH_INFO * ClientAuthInfo,
  1344. OUT OSF_CCALL ** pCCall,
  1345. OUT BOOL *fBindingHandleReferenceRemoved
  1346. )
  1347. /*++
  1348. Function Name:AllocateCCall
  1349. Parameters:
  1350. CCall - Returns the allocated call.
  1351. ClientAuthInfo - Supplies the authentication and authorization
  1352. information required for the connection.
  1353. Description:
  1354. In this method, we allocate a connection supporting the requested
  1355. interface information. This means that first we need to find the
  1356. presentation context corresponding to the requested interface
  1357. interface. Then we search for an existing connection supporting
  1358. the presentation context, and then we try and create a new
  1359. connection. We then ask the Connection object to create a Call
  1360. for us.
  1361. Returns:
  1362. RPC_S_OK - The operation completed successfully.
  1363. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to create
  1364. objects necessary to allocate a connection.
  1365. --*/
  1366. {
  1367. ULONG CallIdToUse;
  1368. RPC_STATUS Status;
  1369. OSF_BINDING *BindingsForThisInterface[MaximumNumberOfTransferSyntaxes];
  1370. int NumberOfBindingsAvailable;
  1371. int NumberOfBindingsToUse;
  1372. int PresentationContextsAvailable[MaximumNumberOfTransferSyntaxes];
  1373. int *PresentationContextsToUse;
  1374. int PresentationContextSupported;
  1375. int NDR20PresentationContext;
  1376. int i;
  1377. OSF_CCALL_STATE InitialCallState;
  1378. OSF_CCONNECTION *CConnection = 0;
  1379. BOOL fExclusive = !NONSYNC(Message);
  1380. ULONG_PTR fUseSeparateConnection = PARTIAL(Message);
  1381. RPC_CLIENT_INTERFACE *RpcInterfaceInformation =
  1382. (RPC_CLIENT_INTERFACE *) Message->RpcInterfaceInformation;
  1383. OSF_BINDING *BindingsList;
  1384. OSF_BINDING *BindingToUse;
  1385. RPC_DISPATCH_TABLE *DispatchTableToUse;
  1386. *fBindingHandleReferenceRemoved = FALSE;
  1387. //
  1388. // To begin with, we need to obtain the presentation context
  1389. // corresponding to the specified interface information.
  1390. //
  1391. Status = AssociationMutex.RequestSafe();
  1392. if (Status)
  1393. return Status;
  1394. Status = FindOrCreateOsfBinding(RpcInterfaceInformation, Message, &NumberOfBindingsAvailable,
  1395. BindingsForThisInterface);
  1396. if ( Status != RPC_S_OK )
  1397. {
  1398. AssociationMutex.Clear();
  1399. return(Status);
  1400. }
  1401. CallIdToUse = CallIdCounter++;
  1402. if (fExclusive == 0 && fUseSeparateConnection == 0)
  1403. {
  1404. Status = BindingHandle->InqTransportOption(
  1405. RPC_C_OPT_BINDING_NONCAUSAL,
  1406. &fUseSeparateConnection);
  1407. ASSERT(Status == RPC_S_OK);
  1408. }
  1409. //
  1410. // Ok, now we search for an available connection supporting the
  1411. // requested presentation context.
  1412. //
  1413. // construct the array of presentation contexts any of which will
  1414. // do the job
  1415. #ifdef DEBUGRPC
  1416. BindingsList = 0;
  1417. NDR20PresentationContext = -1;
  1418. #endif
  1419. NumberOfBindingsToUse = NumberOfBindingsAvailable;
  1420. PresentationContextsToUse = PresentationContextsAvailable;
  1421. for (i = 0; i < NumberOfBindingsAvailable; i ++)
  1422. {
  1423. PresentationContextsAvailable[i] = BindingsForThisInterface[i]->GetPresentationContext();
  1424. if (BindingsForThisInterface[i]->IsTransferSyntaxListStart())
  1425. {
  1426. // make sure only one binding is the list start
  1427. ASSERT(BindingsList == 0);
  1428. BindingsList = BindingsForThisInterface[i];
  1429. }
  1430. if (BindingsForThisInterface[i]->IsTransferSyntaxServerPreferred())
  1431. {
  1432. // one of the transfer syntaxes is marked as preferred -
  1433. // try to use it.
  1434. // Note that this doesn't break the mixed cluster scenario,
  1435. // because when binding on new connection, we always offer both, regardless of
  1436. // preferences. We hit this path only when we choose from
  1437. // existing. If we moved the association to a different node
  1438. // of the cluster, all the old connections will be blown
  1439. // away, and it doesn't matter what presentation context we
  1440. // choose for them. A successful bind to the new node will
  1441. // reset the preferences, so we're fine
  1442. NumberOfBindingsToUse = 1;
  1443. PresentationContextsToUse = &PresentationContextsAvailable[i];
  1444. }
  1445. if (IsNonsyncMessage(Message))
  1446. {
  1447. // the call is non sync and there may be no preference. For non sync,
  1448. // we start with NDR20, because the client may be downlevel. When
  1449. // the first bind completes, it will set the preference
  1450. if (BindingsForThisInterface[i]->CompareWithTransferSyntax(NDR20TransferSyntax) == 0)
  1451. {
  1452. NDR20PresentationContext = i;
  1453. }
  1454. }
  1455. }
  1456. // at least one binding must be the start of the list
  1457. ASSERT(BindingsList != 0);
  1458. CConnection = LookForExistingConnection (
  1459. BindingHandle,
  1460. fExclusive,
  1461. ClientAuthInfo,
  1462. PresentationContextsToUse,
  1463. NumberOfBindingsToUse,
  1464. &PresentationContextSupported,
  1465. &InitialCallState,
  1466. BOOL(fUseSeparateConnection)) ;
  1467. AssociationMutex.Clear();
  1468. if (CConnection == 0)
  1469. {
  1470. //
  1471. // Allocate a new connection
  1472. //
  1473. RPC_CONNECTION_TRANSPORT *ClientInfo
  1474. = (RPC_CONNECTION_TRANSPORT *) TransInfo->InqTransInfo();
  1475. Status = RPC_S_OK;
  1476. CConnection = new(ClientInfo->ClientConnectionSize
  1477. + ClientInfo->SendContextSize
  1478. + sizeof(PVOID))
  1479. OSF_CCONNECTION(
  1480. this,
  1481. ClientInfo,
  1482. BindingHandle->InqComTimeout(),
  1483. ClientAuthInfo,
  1484. fExclusive,
  1485. BOOL(fUseSeparateConnection),
  1486. &Status);
  1487. if (CConnection == 0)
  1488. {
  1489. Status = RPC_S_OUT_OF_MEMORY;
  1490. }
  1491. if (Status != RPC_S_OK)
  1492. {
  1493. delete CConnection;
  1494. return Status;
  1495. }
  1496. Status = AssociationMutex.RequestSafe();
  1497. if (Status)
  1498. {
  1499. delete CConnection;
  1500. return Status;
  1501. }
  1502. if (!fExclusive)
  1503. {
  1504. Status = TransInfo->StartServerIfNecessary();
  1505. if (Status != RPC_S_OK)
  1506. {
  1507. AssociationMutex.Clear();
  1508. delete CConnection;
  1509. return Status;
  1510. }
  1511. }
  1512. CConnection->ConnectionKey = ActiveConnections.Insert(CConnection);
  1513. if (CConnection->ConnectionKey == -1)
  1514. {
  1515. AssociationMutex.Clear();
  1516. delete CConnection;
  1517. return RPC_S_OUT_OF_MEMORY;
  1518. }
  1519. if (IsValid() == FALSE)
  1520. {
  1521. ActiveConnections.Delete(CConnection->ConnectionKey);
  1522. CConnection->ConnectionKey = -1;
  1523. AssociationMutex.Clear();
  1524. delete CConnection;
  1525. return AssociationShutdownError;
  1526. }
  1527. if (ActiveConnections.Size() > AUTO_ENABLE_IDLE_CLEANUP)
  1528. {
  1529. // EnableIdleConnectionCleanup doesn't fail
  1530. (void) EnableIdleConnectionCleanup();
  1531. }
  1532. InitialCallState = NeedOpenAndBind;
  1533. //
  1534. // Since this is the first call on the connection
  1535. // we might as well use the cached CCall
  1536. // we are deliberately not taking the connection mutex
  1537. // The cached call is already marked as not available in
  1538. // the constructor of the connection
  1539. //
  1540. *pCCall = CConnection->CachedCCall;
  1541. if (fEnableIdleConnectionCleanup && (fIdleConnectionCleanupNeeded == FALSE))
  1542. {
  1543. fIdleConnectionCleanupNeeded = TRUE;
  1544. //
  1545. // Finally, we need to notify the protocol independent layer that
  1546. // the code to delete idle connections should be executed periodically.
  1547. // We divide by two to reduce the amount of extra time an idle
  1548. // connection lives beyond the minimum.
  1549. //
  1550. GarbageCollectionNeeded(FALSE, CLIENT_DISCONNECT_TIME1 / 2);
  1551. }
  1552. AssociationMutex.Clear();
  1553. if (NumberOfBindingsAvailable == 1)
  1554. {
  1555. // we support only one binding - just use it
  1556. BindingToUse = BindingsForThisInterface[0];
  1557. DispatchTableToUse = BindingToUse->GetDispatchTable();
  1558. BindingsList = 0;
  1559. }
  1560. else if (IsNonsyncMessage(Message))
  1561. {
  1562. // if there is still more than one available binding left
  1563. // and the call is non-sync (this can happen while the server
  1564. // preferences are not yet recorded), artifically limit the connection
  1565. // lookup to NDR20 to avoid downward level server compatibility problems
  1566. ASSERT (NDR20PresentationContext != -1);
  1567. // we may overwrite the choices made up when we iterated over the
  1568. // available bindings. That's ok - we always want to advertise both
  1569. // for new connections
  1570. NumberOfBindingsToUse = 1;
  1571. PresentationContextsToUse = &PresentationContextsAvailable[NDR20PresentationContext];
  1572. i = (int)(PresentationContextsToUse - PresentationContextsAvailable);
  1573. BindingToUse = BindingsForThisInterface[i];
  1574. DispatchTableToUse = BindingToUse->GetDispatchTable();
  1575. }
  1576. else
  1577. {
  1578. // even if server preference is set, we should still suggest both
  1579. // to support the mixed cluster scenario
  1580. BindingToUse = 0;
  1581. DispatchTableToUse = 0;
  1582. }
  1583. Status = (*pCCall)->ActivateCall(
  1584. BindingHandle,
  1585. BindingToUse,
  1586. BindingsList,
  1587. CallIdToUse,
  1588. InitialCallState,
  1589. DispatchTableToUse,
  1590. CConnection);
  1591. if (Status != RPC_S_OK)
  1592. {
  1593. ConnectionAborted(CConnection);
  1594. delete CConnection;
  1595. return Status ;
  1596. }
  1597. if (!fExclusive)
  1598. {
  1599. BindingHandle->OSF_BINDING_HANDLE::AddReference();
  1600. // add one more reference to the connection in case the sync
  1601. // path fails with out of memory and starts cleaning up
  1602. // This extra reference will make sure that the connection
  1603. // and cached call do not go away underneath the async path
  1604. CConnection->OSF_CCONNECTION::AddReference();
  1605. (*pCCall)->OSF_CCALL::AddReference();
  1606. Status = CConnection->TransPostEvent(*pCCall);
  1607. if (Status != RPC_S_OK)
  1608. {
  1609. BindingHandle->OSF_BINDING_HANDLE::BindingFree();
  1610. ConnectionAborted(CConnection);
  1611. (*pCCall)->OSF_CCALL::RemoveReference();
  1612. delete CConnection;
  1613. return Status;
  1614. }
  1615. }
  1616. }
  1617. else
  1618. {
  1619. // there is a connection found. If the connection supports both
  1620. // transfer syntaxes, then a server preferred syntax must have
  1621. // been established. If there is no server preferred syntax,
  1622. // the chosen connection supports at most one syntax currently
  1623. // If there is only one binding to use (either because we support
  1624. // only one, or because there is server preference set), we use it
  1625. // if the connection supports it. Otherwise, we need to alter
  1626. // context the connection.
  1627. // If there are more bindings, this means there are no server
  1628. // preferences, and it gets more complicated. First, we need to
  1629. // alter context both to find out the server preference. The server
  1630. // may choose the same syntax that we already support, or it may
  1631. // choose a different syntax. In the async case, we choose whatever
  1632. // is currently supported, but we try to alter context both to give
  1633. // the server a chance to indicate its preferences.
  1634. if (NumberOfBindingsToUse == 1)
  1635. {
  1636. // only one binding. Do we support it?
  1637. if (PresentationContextSupported >= 0) // faster version of != -1
  1638. {
  1639. // yes - easy choice. Just use it.
  1640. // calculate the offset of the chosen presentation context in the original
  1641. // presentation contexts array (PresentationContextsAvailable).
  1642. i = (int)((PresentationContextsToUse - PresentationContextsAvailable) + PresentationContextSupported);
  1643. }
  1644. else
  1645. {
  1646. // if we are here, the connection does not support the transfer
  1647. // syntax we need. We have only one that we support, so we
  1648. // stick with it and fail the call if we cannot
  1649. // negotiate to it (just a shortcut version of the first case).
  1650. // Note that the LookForExistingConnection has set the state of
  1651. // the call to NeedAlterContext if this is the case, so the
  1652. // bind function will do the right thing - we don't need to worry
  1653. // about it.
  1654. i = (int)(PresentationContextsToUse - PresentationContextsAvailable);
  1655. }
  1656. // this is the same offset as the offset in the BindingsForThisInterface array, since the
  1657. // two arrays are parallel
  1658. BindingToUse = BindingsForThisInterface[i];
  1659. DispatchTableToUse = BindingToUse->GetDispatchTable();
  1660. BindingsList = 0;
  1661. }
  1662. else
  1663. {
  1664. // here NumberOfBindingsToUse is more than one. This means we support
  1665. // more than one xfer syntax, and the server preferences are not
  1666. // set.
  1667. InitialCallState = NeedAlterContext;
  1668. // We offered both. At least one must be supported - otherwise
  1669. // the connection should have been gone.
  1670. if (PresentationContextSupported >= 0)
  1671. {
  1672. // this should never happen yet. It can only happen
  1673. // in the multiple client stubs with differen xfer syntax
  1674. // support scenario, but we don't support it yet.
  1675. ASSERT(0);
  1676. if (IsNonsyncMessage(Message))
  1677. {
  1678. i = (int)((PresentationContextsToUse - PresentationContextsAvailable) + PresentationContextSupported);
  1679. BindingToUse = BindingsForThisInterface[i];
  1680. DispatchTableToUse = BindingToUse->GetDispatchTable();
  1681. // Don't whack out the list - this allows the client to offer both
  1682. // BindingsList = 0;
  1683. }
  1684. else
  1685. {
  1686. BindingToUse = 0;
  1687. DispatchTableToUse = 0;
  1688. }
  1689. }
  1690. else
  1691. {
  1692. if (IsNonsyncMessage(Message))
  1693. {
  1694. // if there is still more than one available binding left
  1695. // and the call is non-sync (this can happen while the server
  1696. // preferences are not yet recorded), artifically limit the connection
  1697. // lookup to NDR20 to avoid downward level server compatibility problems
  1698. ASSERT (NDR20PresentationContext != -1);
  1699. // we may overwrite the choices made up when we iterated over the
  1700. // available bindings. That's ok - we always want to advertise both
  1701. // in this case
  1702. NumberOfBindingsToUse = 1;
  1703. PresentationContextsToUse = &PresentationContextsAvailable[NDR20PresentationContext];
  1704. i = (int)(PresentationContextsToUse - PresentationContextsAvailable);
  1705. BindingToUse = BindingsForThisInterface[i];
  1706. DispatchTableToUse = BindingToUse->GetDispatchTable();
  1707. // Don't whack out the list - this allows the client to offer both
  1708. // BindingsList = 0;
  1709. }
  1710. else
  1711. {
  1712. // even if server preference is set, we should still suggest both
  1713. // to support the mixed cluster scenario
  1714. BindingToUse = 0;
  1715. DispatchTableToUse = 0;
  1716. }
  1717. }
  1718. }
  1719. //
  1720. // This is not the first call on the connection. We will ask it to allocate
  1721. // a call for us
  1722. //
  1723. Status = CConnection->AllocateCCall(pCCall);
  1724. if (Status == RPC_S_OK)
  1725. {
  1726. Status = (*pCCall)->ActivateCall(
  1727. BindingHandle,
  1728. BindingToUse,
  1729. BindingsList,
  1730. CallIdToUse,
  1731. InitialCallState,
  1732. DispatchTableToUse,
  1733. CConnection);
  1734. if (Status != RPC_S_OK)
  1735. {
  1736. //
  1737. // Call has not yet started, ok to directly
  1738. // free the call.
  1739. //
  1740. (*pCCall)->FreeCCall(RPC_S_CALL_FAILED_DNE);
  1741. *fBindingHandleReferenceRemoved = TRUE;
  1742. return Status;
  1743. }
  1744. Status = (*pCCall)->ReserveSpaceForSecurityIfNecessary();
  1745. if (Status != RPC_S_OK)
  1746. {
  1747. //
  1748. // Call has not yet started, ok to directly
  1749. // free the call.
  1750. //
  1751. (*pCCall)->FreeCCall(RPC_S_CALL_FAILED_DNE);
  1752. *fBindingHandleReferenceRemoved = TRUE;
  1753. return Status;
  1754. }
  1755. }
  1756. }
  1757. return Status;
  1758. }
  1759. BOOL
  1760. OSF_CASSOCIATION::ConnectionAborted (
  1761. IN OSF_CCONNECTION *Connection
  1762. )
  1763. /*++
  1764. Function Name:ConnectionAborted
  1765. Parameters:
  1766. Description:
  1767. Returns:
  1768. --*/
  1769. {
  1770. BOOL fDontKill = FALSE;
  1771. AssociationMutex.Request();
  1772. if (Connection->ConnectionKey != -1)
  1773. {
  1774. LogEvent(SU_CCONN, EV_STOP, Connection, this, Connection->ConnectionKey, 1, 0);
  1775. ActiveConnections.Delete(Connection->ConnectionKey);
  1776. Connection->ConnectionKey = -1;
  1777. }
  1778. if (Connection->fConnectionAborted == 0)
  1779. {
  1780. NotifyConnectionClosed();
  1781. Connection->fConnectionAborted = 1;
  1782. }
  1783. else
  1784. {
  1785. fDontKill = TRUE;
  1786. }
  1787. AssociationMutex.Clear();
  1788. return fDontKill;
  1789. }
  1790. RPC_STATUS
  1791. OSF_CASSOCIATION::FindOrCreateToken (
  1792. IN HANDLE hToken,
  1793. IN LUID *pModifiedId,
  1794. OUT RPC_TOKEN **ppToken,
  1795. OUT BOOL *pfTokenFound
  1796. )
  1797. /*++
  1798. Function Name:FindOrCreateToken
  1799. Parameters:
  1800. Description:
  1801. Returns:
  1802. --*/
  1803. {
  1804. DictionaryCursor cursor;
  1805. RPC_TOKEN *Token;
  1806. RPC_STATUS Status;
  1807. Status = AssociationMutex.RequestSafe();
  1808. if (Status)
  1809. return Status;
  1810. TokenDict.Reset(cursor);
  1811. while ((Token = TokenDict.Next(cursor)) != 0)
  1812. {
  1813. if (FastCompareLUIDAligned(&Token->ModifiedId, pModifiedId))
  1814. {
  1815. *pfTokenFound = TRUE;
  1816. Token->RefCount++; // Token++;
  1817. LogEvent(SU_REFOBJ, EV_INC, Token, 0, Token->RefCount, 1, 1);
  1818. *ppToken = Token;
  1819. Status = RPC_S_OK;
  1820. goto Cleanup;
  1821. }
  1822. }
  1823. *pfTokenFound = FALSE;
  1824. *ppToken = new RPC_TOKEN(hToken, pModifiedId); // constructor cannot fail
  1825. if (*ppToken == 0)
  1826. {
  1827. CloseHandle(hToken);
  1828. Status = RPC_S_OUT_OF_MEMORY;
  1829. goto Cleanup;
  1830. }
  1831. if (((*ppToken)->Key = TokenDict.Insert(*ppToken)) == -1)
  1832. {
  1833. Status = RPC_S_OUT_OF_MEMORY;
  1834. delete *ppToken;
  1835. goto Cleanup;
  1836. }
  1837. Status = RPC_S_OK;
  1838. Cleanup:
  1839. AssociationMutex.Clear();
  1840. return Status;
  1841. }
  1842. void
  1843. OSF_CASSOCIATION::ReferenceToken(
  1844. IN RPC_TOKEN *pToken
  1845. )
  1846. /*++
  1847. Function Name:ReferenceToken
  1848. Parameters:
  1849. Description:
  1850. Returns:
  1851. --*/
  1852. {
  1853. AssociationMutex.Request();
  1854. ASSERT(pToken->RefCount);
  1855. pToken->RefCount++; // Token++
  1856. LogEvent(SU_REFOBJ, EV_INC, pToken, 0, pToken->RefCount, 1, 1);
  1857. AssociationMutex.Clear();
  1858. }
  1859. void
  1860. OSF_CASSOCIATION::DereferenceToken(
  1861. IN RPC_TOKEN *pToken
  1862. )
  1863. /*++
  1864. Function Name:DereferenceToken
  1865. Parameters:
  1866. Description:
  1867. Returns:
  1868. --*/
  1869. {
  1870. AssociationMutex.Request();
  1871. LogEvent(SU_REFOBJ, EV_DEC, pToken, 0, pToken->RefCount, 1, 1);
  1872. pToken->RefCount--; // Token--
  1873. if (pToken->RefCount == 0)
  1874. {
  1875. TokenDict.Delete(pToken->Key);
  1876. CleanupConnectionList(pToken);
  1877. delete pToken;
  1878. }
  1879. AssociationMutex.Clear();
  1880. }
  1881. void
  1882. OSF_CASSOCIATION::CleanupConnectionList(
  1883. IN RPC_TOKEN *pToken
  1884. )
  1885. /*++
  1886. Function Name:CleanupConnectionList
  1887. Parameters:
  1888. Description:
  1889. Returns:
  1890. --*/
  1891. {
  1892. DictionaryCursor cursor;
  1893. OSF_CCONNECTION *CConnection;
  1894. AssociationMutex.VerifyOwned();
  1895. if ( MaintainContext != 0 && ActiveConnections.Size() <= 1) return;
  1896. ActiveConnections.Reset(cursor);
  1897. while ( (CConnection = ActiveConnections.Next(cursor)) != 0 )
  1898. {
  1899. if (CConnection->ThreadId == SYNC_CONN_FREE
  1900. || CConnection->ThreadId == ASYNC_CONN_FREE)
  1901. {
  1902. if (CConnection->MatchModifiedId(&(pToken->ModifiedId)) == TRUE)
  1903. {
  1904. CConnection->AddReference(); //CCONN++
  1905. ConnectionAborted(CConnection);
  1906. CConnection->DeleteConnection();
  1907. //
  1908. // I don't if the add/remove reference is really needed
  1909. // I am only doing it to preserve existing semantics
  1910. //
  1911. CConnection->RemoveReference(); // CCONN--
  1912. }
  1913. }
  1914. }
  1915. }
  1916. void
  1917. ConstructPContextList (
  1918. OUT p_cont_list_t *pCon, // Place the list here.
  1919. IN OSF_BINDING *AvailableBindings,
  1920. IN int NumberOfBindings
  1921. )
  1922. /*++
  1923. Function Name:ConstructPContextList
  1924. Parameters:
  1925. Description:
  1926. Construct the presentation context list in the
  1927. rpc_bind packet (and implicitly rpc_alter_context)
  1928. packet.
  1929. Returns:
  1930. --*/
  1931. {
  1932. int i;
  1933. OSF_BINDING *CurrentBinding;
  1934. pCon->n_context_elem = (unsigned char)NumberOfBindings;
  1935. pCon->reserved = 0;
  1936. pCon->reserved2 = 0;
  1937. CurrentBinding = AvailableBindings;
  1938. for (i = 0; i < NumberOfBindings; i ++, CurrentBinding = CurrentBinding->GetNextBinding())
  1939. {
  1940. pCon->p_cont_elem[i].p_cont_id = CurrentBinding->GetOnTheWirePresentationContext();
  1941. pCon->p_cont_elem[i].n_transfer_syn = (unsigned char) 1;
  1942. pCon->p_cont_elem[i].reserved = 0;
  1943. RpcpMemoryCopy(&pCon->p_cont_elem[i].abstract_syntax,
  1944. CurrentBinding->GetInterfaceId(),
  1945. sizeof(RPC_SYNTAX_IDENTIFIER));
  1946. RpcpMemoryCopy(pCon->p_cont_elem[i].transfer_syntaxes,
  1947. CurrentBinding->GetTransferSyntaxId(),
  1948. sizeof(RPC_SYNTAX_IDENTIFIER));
  1949. }
  1950. }
  1951. OSF_CCONNECTION::OSF_CCONNECTION (
  1952. IN OSF_CASSOCIATION *MyAssociation,
  1953. IN RPC_CONNECTION_TRANSPORT * RpcClientInfo,
  1954. IN UINT Timeout,
  1955. IN CLIENT_AUTH_INFO * ClientAuthInfo,
  1956. IN BOOL fExclusive,
  1957. IN BOOL fSeparateConnection,
  1958. OUT RPC_STATUS * pStatus
  1959. ) : ConnMutex(pStatus),
  1960. ClientSecurityContext(ClientAuthInfo, 0, FALSE, pStatus)
  1961. /*++
  1962. Function Name:OSF_CCONNECTION
  1963. Parameters:
  1964. Description:
  1965. Constructor for the connection object
  1966. Returns:
  1967. --*/
  1968. {
  1969. LogEvent(SU_CCONN, EV_CREATE, this);
  1970. Association = MyAssociation;
  1971. // CASSOC++
  1972. Association->AddReference();
  1973. ObjectType = OSF_CCONNECTION_TYPE;
  1974. ClientInfo = RpcClientInfo;
  1975. State = ConnUninitialized;
  1976. ComTimeout = Timeout ;
  1977. u.ConnSendContext = (char *) TransConnection()
  1978. + ClientInfo->ClientConnectionSize
  1979. + sizeof(PVOID);
  1980. *((PVOID *) ((char *) u.ConnSendContext - sizeof(PVOID))) = (PVOID) this;
  1981. MaxFrag = 512;
  1982. ConnectionKey = -1;
  1983. AdditionalLegNeeded = 0;
  1984. LastTimeUsed = 0;
  1985. SavedHeader = 0;
  1986. SavedHeaderSize = 0;
  1987. MaxSavedHeaderSize = 0;
  1988. BufferToFree = 0;
  1989. fIdle = 0;
  1990. this->fExclusive = fExclusive;
  1991. this->fSeparateConnection = fSeparateConnection;
  1992. InitializeWireAuthId(ClientAuthInfo);
  1993. if (fExclusive)
  1994. {
  1995. AdditionalSpaceForSecurity = 0;
  1996. ThreadId = SYNC_CONN_BUSY;
  1997. }
  1998. else
  1999. {
  2000. //
  2001. // If it turns out that needed size is actually bigger
  2002. // we will really the buffers
  2003. //
  2004. AdditionalSpaceForSecurity = 0x140;
  2005. if (fSeparateConnection)
  2006. {
  2007. ThreadId = ASYNC_CONN_BUSY;
  2008. }
  2009. else
  2010. {
  2011. ThreadId = GetCurrentThreadId();
  2012. }
  2013. }
  2014. fConnectionAborted = 1;
  2015. //
  2016. // We need two references on the connection. One for itself, and
  2017. // one for the cached ccall, which is implicitly getting allocated.
  2018. //
  2019. SetReferenceCount(2);
  2020. DceSecurityInfo.SendSequenceNumber = 0;
  2021. DceSecurityInfo.ReceiveSequenceNumber = 0;
  2022. *pStatus = TransInitialize(
  2023. Association->DceBinding->InqNetworkAddress(),
  2024. Association->DceBinding->InqNetworkOptions());
  2025. if (*pStatus == RPC_S_OK)
  2026. {
  2027. CachedCCall = new (ClientInfo->SendContextSize+sizeof(PVOID))
  2028. OSF_CCALL(pStatus);
  2029. if (CachedCCall == 0)
  2030. {
  2031. *pStatus = RPC_S_OUT_OF_MEMORY;
  2032. }
  2033. }
  2034. else
  2035. {
  2036. CachedCCall = NULL;
  2037. }
  2038. CachedCCallAvailable = 0;
  2039. CurrentCall = CachedCCall;
  2040. ConnectionReady = 0;
  2041. }
  2042. OSF_CCONNECTION::~OSF_CCONNECTION (
  2043. )
  2044. {
  2045. LogEvent(SU_CCONN, EV_DELETE, this);
  2046. RPC_STATUS Status;
  2047. if (CachedCCall)
  2048. {
  2049. delete CachedCCall;
  2050. }
  2051. TransInitComplete();
  2052. TransClose();
  2053. Association->ConnectionAborted(this);
  2054. if (SavedHeader != 0)
  2055. {
  2056. ASSERT(SavedHeaderSize != 0);
  2057. RpcpFarFree(SavedHeader);
  2058. }
  2059. // CASSOC--
  2060. Association->RemoveReference();
  2061. }
  2062. RPC_STATUS
  2063. OSF_CCONNECTION::ValidateHeader(
  2064. rpcconn_common * Buffer,
  2065. unsigned long BufferLength
  2066. )
  2067. {
  2068. if (ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  2069. {
  2070. unsigned CopyLength;
  2071. if (Buffer->PTYPE == rpc_bind_ack ||
  2072. Buffer->PTYPE == rpc_alter_context_resp)
  2073. {
  2074. CopyLength = BufferLength;
  2075. }
  2076. else
  2077. {
  2078. CopyLength = sizeof(rpcconn_response);
  2079. }
  2080. if (MaxSavedHeaderSize < CopyLength)
  2081. {
  2082. if (SavedHeader != 0)
  2083. {
  2084. ASSERT(MaxSavedHeaderSize != 0);
  2085. RpcpFarFree(SavedHeader);
  2086. }
  2087. SavedHeader = RpcpFarAllocate(CopyLength);
  2088. if (SavedHeader == 0)
  2089. {
  2090. MaxSavedHeaderSize = 0;
  2091. return(RPC_S_OUT_OF_MEMORY);
  2092. }
  2093. MaxSavedHeaderSize = CopyLength;
  2094. RpcpMemoryCopy(SavedHeader, Buffer, CopyLength);
  2095. }
  2096. else
  2097. {
  2098. RpcpMemoryCopy(SavedHeader, Buffer, CopyLength);
  2099. }
  2100. SavedHeaderSize = CopyLength;
  2101. }
  2102. RPC_STATUS Status = ValidatePacket(Buffer, BufferLength);
  2103. if ( Status != RPC_S_OK )
  2104. {
  2105. ASSERT( Status == RPC_S_PROTOCOL_ERROR );
  2106. return Status;
  2107. }
  2108. return RPC_S_OK;
  2109. }
  2110. RPC_STATUS
  2111. OSF_CCONNECTION::TransReceive (
  2112. OUT PVOID * Buffer,
  2113. OUT UINT * BufferLength,
  2114. IN ULONG Timeout
  2115. )
  2116. /*++
  2117. Routine Description:
  2118. Arguments:
  2119. Buffer - Returns a packet received from the transport.
  2120. BufferLength - Returns the length of the buffer.
  2121. Return Value:
  2122. RPC_S_OK - We successfully received a packet from the server.
  2123. RPC_S_* - an error has occurred. See the validate clause at the
  2124. end
  2125. --*/
  2126. {
  2127. RPC_STATUS Status;
  2128. if ( State != ConnOpen )
  2129. {
  2130. return(RPC_P_CONNECTION_CLOSED);
  2131. }
  2132. ASSERT(CurrentCall);
  2133. Status = ClientInfo->SyncRecv(
  2134. TransConnection(),
  2135. (BUFFER *) Buffer,
  2136. BufferLength,
  2137. INFINITE);
  2138. if ( (Status == RPC_P_RECEIVE_FAILED)
  2139. || (Status == RPC_P_CONNECTION_SHUTDOWN)
  2140. || (Status == RPC_P_TIMEOUT))
  2141. {
  2142. State = ConnAborted;
  2143. }
  2144. VALIDATE(Status)
  2145. {
  2146. RPC_S_OK,
  2147. RPC_S_OUT_OF_MEMORY,
  2148. RPC_S_OUT_OF_RESOURCES,
  2149. RPC_S_CALL_CANCELLED,
  2150. RPC_P_RECEIVE_ALERTED,
  2151. RPC_P_TIMEOUT,
  2152. RPC_P_RECEIVE_FAILED,
  2153. RPC_P_CONNECTION_SHUTDOWN
  2154. } END_VALIDATE;
  2155. return(Status);
  2156. }
  2157. RPC_STATUS
  2158. OSF_CCONNECTION::TransOpen (
  2159. IN OSF_BINDING_HANDLE *BindingHandle,
  2160. IN RPC_CHAR *RpcProtocolSequence,
  2161. IN RPC_CHAR *NetworkAddress,
  2162. IN RPC_CHAR *Endpoint,
  2163. IN RPC_CHAR *NetworkOptions,
  2164. IN void *ResolverHint,
  2165. IN BOOL fHintInitialized,
  2166. IN ULONG CallTimeout
  2167. )
  2168. /*++
  2169. Function Name:TransOpen
  2170. Parameters:
  2171. CallTimeout - call timeout in milliseconds
  2172. Description:
  2173. Returns:
  2174. --*/
  2175. {
  2176. RPC_STATUS Status ;
  2177. BOOL fTokenSwapped ;
  2178. HANDLE OldToken = 0;
  2179. CLIENT_AUTH_INFO *ClientAuthInfo;
  2180. fTokenSwapped = BindingHandle->SwapToken(&OldToken);
  2181. ClientAuthInfo = BindingHandle->InquireAuthInformation();
  2182. Status = ClientInfo->Open(TransConnection(),
  2183. RpcProtocolSequence,
  2184. NetworkAddress,
  2185. Endpoint,
  2186. NetworkOptions,
  2187. ComTimeout,
  2188. 0,
  2189. 0,
  2190. ResolverHint,
  2191. fHintInitialized,
  2192. CallTimeout,
  2193. ClientAuthInfo->AdditionalTransportCredentialsType,
  2194. ClientAuthInfo->AdditionalCredentials
  2195. );
  2196. if (fTokenSwapped)
  2197. {
  2198. ReplaceToken(OldToken);
  2199. if (OldToken)
  2200. {
  2201. CloseHandle(OldToken);
  2202. }
  2203. }
  2204. //
  2205. // If an error occurs in opening the connection, we go ahead and
  2206. // delete the memory for the connection, and return zero (setting
  2207. // this to zero does that).
  2208. //
  2209. VALIDATE (Status)
  2210. {
  2211. RPC_S_OK,
  2212. RPC_S_PROTSEQ_NOT_SUPPORTED,
  2213. RPC_S_SERVER_UNAVAILABLE,
  2214. RPC_S_OUT_OF_MEMORY,
  2215. RPC_S_OUT_OF_RESOURCES,
  2216. RPC_S_SERVER_TOO_BUSY,
  2217. RPC_S_INVALID_NETWORK_OPTIONS,
  2218. RPC_S_INVALID_ENDPOINT_FORMAT,
  2219. RPC_S_INVALID_NET_ADDR,
  2220. RPC_S_ACCESS_DENIED,
  2221. RPC_S_INTERNAL_ERROR,
  2222. RPC_S_SERVER_OUT_OF_MEMORY,
  2223. RPC_S_CALL_CANCELLED
  2224. } END_VALIDATE;
  2225. if ( Status == RPC_S_OK )
  2226. {
  2227. State = ConnOpen;
  2228. }
  2229. return Status ;
  2230. }
  2231. void
  2232. OSF_CCONNECTION::TransClose (
  2233. )
  2234. {
  2235. RPC_STATUS Status;
  2236. if (State != ConnUninitialized)
  2237. {
  2238. __try
  2239. {
  2240. Status = ClientInfo->Close(TransConnection(), 0);
  2241. ASSERT( Status == RPC_S_OK );
  2242. }
  2243. __except( EXCEPTION_EXECUTE_HANDLER )
  2244. {
  2245. #if DBG
  2246. PrintToDebugger("RPC: exception in Close\n") ;
  2247. #endif
  2248. Status = RPC_S_OUT_OF_MEMORY ;
  2249. }
  2250. State = ConnUninitialized;
  2251. }
  2252. }
  2253. RPC_STATUS
  2254. OSF_CCONNECTION::TransAsyncSend (
  2255. IN void * Buffer,
  2256. IN UINT BufferLength,
  2257. IN void *SendContext
  2258. )
  2259. /*++
  2260. Function Name:TransAsyncSend
  2261. Parameters:
  2262. Description:
  2263. Returns:
  2264. --*/
  2265. {
  2266. RPC_STATUS Status;
  2267. {
  2268. rpcconn_common * pkt = (rpcconn_common *) Buffer;
  2269. LogEvent(SU_CCONN, EV_PKT_OUT, this, pkt, (pkt->PTYPE << 16) | pkt->frag_length);
  2270. }
  2271. //
  2272. // When this function is called, there is should be not outstanding send
  2273. //
  2274. if ( State != ConnOpen )
  2275. {
  2276. return(RPC_P_CONNECTION_CLOSED);
  2277. }
  2278. DceSecurityInfo.SendSequenceNumber += 1;
  2279. Status = ClientInfo->Send(TransConnection(),
  2280. BufferLength,
  2281. (BUFFER) Buffer,
  2282. SendContext);
  2283. if ( Status != RPC_S_OK )
  2284. {
  2285. State = ConnAborted;
  2286. }
  2287. VALIDATE(Status)
  2288. {
  2289. RPC_S_OK,
  2290. RPC_S_OUT_OF_MEMORY,
  2291. RPC_S_OUT_OF_RESOURCES,
  2292. RPC_P_SEND_FAILED
  2293. } END_VALIDATE;
  2294. return(Status);
  2295. }
  2296. RPC_STATUS
  2297. OSF_CCONNECTION::TransAsyncReceive (
  2298. )
  2299. /*++
  2300. Function Name:TransAsyncReceive
  2301. Parameters:
  2302. Description:
  2303. Returns:
  2304. --*/
  2305. {
  2306. RPC_STATUS Status;
  2307. if (State != ConnOpen || fConnectionAborted)
  2308. {
  2309. return(RPC_P_CONNECTION_CLOSED);
  2310. }
  2311. //
  2312. // If the call to Recv succeeds, this reference is removed
  2313. // in ProcessIOEvents after the call to ProcessReceiveComplete
  2314. //
  2315. // CCONN++
  2316. AddReference();
  2317. Status = ClientInfo->Recv(TransConnection());
  2318. if ((Status == RPC_P_RECEIVE_FAILED)
  2319. || (Status == RPC_P_CONNECTION_SHUTDOWN)
  2320. || (Status == RPC_P_TIMEOUT))
  2321. {
  2322. State = ConnAborted;
  2323. }
  2324. VALIDATE(Status)
  2325. {
  2326. RPC_S_OK,
  2327. RPC_S_OUT_OF_MEMORY,
  2328. RPC_S_OUT_OF_RESOURCES,
  2329. RPC_P_RECEIVE_ALERTED,
  2330. RPC_P_RECEIVE_FAILED,
  2331. RPC_P_CONNECTION_SHUTDOWN
  2332. } END_VALIDATE;
  2333. if (Status != RPC_S_OK)
  2334. {
  2335. ConnectionAborted(Status);
  2336. // CCONN--
  2337. RemoveReference();
  2338. }
  2339. return(Status);
  2340. }
  2341. void
  2342. OsfBindToServer(
  2343. PVOID Context
  2344. )
  2345. {
  2346. ((OSF_CCALL *) Context)->BindToServer(
  2347. TRUE // this is an async bind - slightly different
  2348. // refcounting is used
  2349. );
  2350. }
  2351. RPC_STATUS
  2352. OSF_CCONNECTION::TransPostEvent (
  2353. IN PVOID Context
  2354. )
  2355. /*++
  2356. Function Name:TransPostEvent
  2357. Parameters:
  2358. Description:
  2359. Returns:
  2360. --*/
  2361. {
  2362. LogEvent(SU_CCONN, EV_NOTIFY, this, Context, 0, 1);
  2363. return ClientInfo->PostEvent( CO_EVENT_BIND_TO_SERVER, Context) ;
  2364. }
  2365. RPC_STATUS
  2366. OSF_CCONNECTION::TransSend (
  2367. IN void * Buffer,
  2368. IN UINT BufferLength,
  2369. IN BOOL fDisableShutdownCheck,
  2370. IN BOOL fDisableCancelCheck,
  2371. IN ULONG Timeout
  2372. )
  2373. /*++
  2374. Routine Description:
  2375. Arguments:
  2376. Buffer - Supplies a packet to be sent to the server.
  2377. BufferLength - Supplies the length of the buffer in bytes.
  2378. Return Value:
  2379. RPC_S_OK - The packet was successfully sent to the server.
  2380. RPC_S_* - an error occurred - see the validate clause at the
  2381. end
  2382. --*/
  2383. {
  2384. RPC_STATUS Status;
  2385. {
  2386. rpcconn_common * pkt = (rpcconn_common *) Buffer;
  2387. LogEvent(SU_CCONN, EV_PKT_OUT, this, 0, (pkt->PTYPE << 16) | pkt->frag_length);
  2388. }
  2389. if ( State != ConnOpen )
  2390. {
  2391. return(RPC_P_CONNECTION_CLOSED);
  2392. }
  2393. if (fDisableCancelCheck == 0
  2394. && CurrentCall->fCallCancelled)
  2395. {
  2396. return(RPC_S_CALL_CANCELLED);
  2397. }
  2398. DceSecurityInfo.SendSequenceNumber += 1;
  2399. Status = ClientInfo->SyncSend(TransConnection(),
  2400. BufferLength,
  2401. (BUFFER) Buffer,
  2402. fDisableShutdownCheck,
  2403. fDisableCancelCheck,
  2404. INFINITE); // Timeout
  2405. if ( Status == RPC_P_SEND_FAILED )
  2406. {
  2407. State = ConnAborted;
  2408. }
  2409. VALIDATE(Status)
  2410. {
  2411. RPC_S_OK,
  2412. RPC_S_OUT_OF_MEMORY,
  2413. RPC_S_OUT_OF_RESOURCES,
  2414. RPC_P_SEND_FAILED,
  2415. RPC_S_CALL_CANCELLED,
  2416. RPC_P_RECEIVE_COMPLETE,
  2417. RPC_P_TIMEOUT
  2418. } END_VALIDATE;
  2419. return(Status);
  2420. }
  2421. void
  2422. OSF_CCONNECTION::TransAbortConnection (
  2423. )
  2424. {
  2425. ClientInfo->Abort(TransConnection());
  2426. }
  2427. RPC_STATUS
  2428. OSF_CCONNECTION::TransSendReceive (
  2429. IN void * SendBuffer,
  2430. IN UINT SendBufferLength,
  2431. OUT void * * ReceiveBuffer,
  2432. OUT UINT * ReceiveBufferLength,
  2433. IN ULONG Timeout
  2434. )
  2435. /*++
  2436. Routine Description:
  2437. Arguments:
  2438. SendBuffer - Supplies a packet to be sent to the server.
  2439. SendBufferLength - Supplies the length of the send buffer in bytes.
  2440. ReceiveBuffer - Returns a packet received from the transport.
  2441. ReceiveBufferLength - Returns the length of the receive buffer in bytes.
  2442. dwTimeout - the timeout to wait for the receive. -1 if infinite.
  2443. Return Value:
  2444. RPC_S_OK - The packet was successfully sent to the server, and we
  2445. successfully received one from the server.
  2446. RPC_S_* - an error occurred - see the validate clause at the end
  2447. --*/
  2448. {
  2449. RPC_STATUS Status;
  2450. {
  2451. rpcconn_common * pkt = (rpcconn_common *) SendBuffer;
  2452. if (pkt->PTYPE != rpc_request)
  2453. {
  2454. LogEvent(SU_CCONN, EV_PKT_OUT, this, ULongToPtr(pkt->call_id), (pkt->PTYPE << 16) | pkt->frag_length);
  2455. }
  2456. else
  2457. {
  2458. LogEvent(SU_CCONN, EV_PKT_OUT, this, ULongToPtr(pkt->call_id),
  2459. (((rpcconn_request *)pkt)->opnum << 24) | (pkt->PTYPE << 16) | pkt->frag_length);
  2460. }
  2461. }
  2462. if ( State != ConnOpen )
  2463. {
  2464. return(RPC_P_CONNECTION_CLOSED);
  2465. }
  2466. if (CurrentCall->fCallCancelled)
  2467. {
  2468. return(RPC_S_CALL_CANCELLED);
  2469. }
  2470. DceSecurityInfo.SendSequenceNumber += 1;
  2471. if ( ClientInfo->SyncSendRecv != 0
  2472. && (CurrentCall->CancelState != CANCEL_NOTINFINITE)
  2473. && (Timeout == INFINITE))
  2474. {
  2475. Status = ClientInfo->SyncSendRecv(TransConnection(),
  2476. SendBufferLength,
  2477. (BUFFER) SendBuffer,
  2478. ReceiveBufferLength,
  2479. (BUFFER *) ReceiveBuffer);
  2480. if (!Status)
  2481. {
  2482. rpcconn_common * pkt = (rpcconn_common *) *ReceiveBuffer;
  2483. LogEvent(SU_CCONN, EV_PKT_IN, this, 0, (pkt->PTYPE << 16) | pkt->frag_length);
  2484. }
  2485. }
  2486. else
  2487. {
  2488. Status = ClientInfo->SyncSend (TransConnection(),
  2489. SendBufferLength,
  2490. (BUFFER) SendBuffer,
  2491. FALSE,
  2492. FALSE,
  2493. Timeout); // Timeout
  2494. if ( Status == RPC_S_OK
  2495. || Status == RPC_P_RECEIVE_COMPLETE )
  2496. {
  2497. Status = ClientInfo->SyncRecv(TransConnection(),
  2498. (BUFFER *) ReceiveBuffer,
  2499. ReceiveBufferLength,
  2500. Timeout);
  2501. if (!Status)
  2502. {
  2503. rpcconn_common * pkt = (rpcconn_common *) *ReceiveBuffer;
  2504. LogEvent(SU_CCONN, EV_PKT_IN, this, 0, (pkt->PTYPE << 16) | pkt->frag_length);
  2505. }
  2506. }
  2507. }
  2508. if ((Status == RPC_P_SEND_FAILED)
  2509. || (Status == RPC_P_RECEIVE_FAILED)
  2510. || (Status == RPC_P_CONNECTION_SHUTDOWN)
  2511. || (Status == RPC_P_TIMEOUT))
  2512. {
  2513. State = ConnAborted;
  2514. }
  2515. VALIDATE(Status)
  2516. {
  2517. RPC_S_OK,
  2518. RPC_S_OUT_OF_MEMORY,
  2519. RPC_S_OUT_OF_RESOURCES,
  2520. RPC_P_RECEIVE_FAILED,
  2521. RPC_S_CALL_CANCELLED,
  2522. RPC_P_SEND_FAILED,
  2523. RPC_P_CONNECTION_SHUTDOWN,
  2524. RPC_P_TIMEOUT
  2525. } END_VALIDATE;
  2526. return(Status);
  2527. }
  2528. UINT
  2529. OSF_CCONNECTION::TransMaximumSend (
  2530. )
  2531. /*++
  2532. Return Value:
  2533. The maximum packet size which can be sent on this transport is returned.
  2534. --*/
  2535. {
  2536. return(ClientInfo->MaximumFragmentSize);
  2537. }
  2538. void
  2539. OSF_CCONNECTION::ConnectionAborted (
  2540. IN RPC_STATUS Status,
  2541. IN BOOL fShutdownAssoc
  2542. )
  2543. /*++
  2544. Function Name:AbortConnection
  2545. Parameters:
  2546. Description:
  2547. Returns:
  2548. --*/
  2549. {
  2550. OSF_CCALL *CCall;
  2551. unsigned int Size;
  2552. DictionaryCursor cursor;
  2553. BOOL fFreeLastBuffer;
  2554. // the failing of the call may take a reference from underneath us
  2555. // bump up the reference count while we have a reference on the
  2556. // object. We'll remove it by the end of the function
  2557. // CCONN++
  2558. ASSERT(fExclusive == 0);
  2559. AddReference();
  2560. // make sure the connection gets removed from the dictionary
  2561. Association->ConnectionAborted(this);
  2562. if (fShutdownAssoc)
  2563. {
  2564. Association->ShutdownRequested(Status, NULL);
  2565. }
  2566. ConnMutex.Request();
  2567. ActiveCalls.Reset(cursor);
  2568. while (CCall = ActiveCalls.Next(cursor))
  2569. {
  2570. if (CCall->CALL::GetCallStatus() == RPC_S_CALL_CANCELLED)
  2571. {
  2572. CCall->CallFailed(RPC_S_CALL_CANCELLED);
  2573. }
  2574. else
  2575. {
  2576. fFreeLastBuffer = FALSE;
  2577. if (CCall->fLastSendComplete)
  2578. {
  2579. if (CurrentCall != CCall)
  2580. {
  2581. if ((CCall->CurrentState == NeedOpenAndBind)
  2582. ||
  2583. (CCall->CurrentState == NeedAlterContext))
  2584. {
  2585. fFreeLastBuffer = TRUE;
  2586. }
  2587. }
  2588. else if ((CCall->CurrentState == NeedOpenAndBind)
  2589. ||
  2590. (CCall->CurrentState == NeedAlterContext)
  2591. ||
  2592. (CCall->CurrentState == WaitingForAlterContext)
  2593. ||
  2594. (CCall->CurrentState == SendingFirstBuffer)
  2595. )
  2596. {
  2597. fFreeLastBuffer = TRUE;
  2598. }
  2599. }
  2600. if (fFreeLastBuffer)
  2601. {
  2602. TransFreeBuffer(CCall->ActualBuffer(CCall->LastBuffer));
  2603. CCall->LastBuffer = NULL;
  2604. }
  2605. CCall->CallFailed(Status);
  2606. }
  2607. }
  2608. //
  2609. // Remove the send references on all the calls currently in the queue
  2610. //
  2611. while (CCall = (OSF_CCALL *) CallQueue.TakeOffQueue(&Size))
  2612. {
  2613. //
  2614. // Remove the send reference, CCALL--
  2615. //
  2616. CCall->RemoveReference();
  2617. }
  2618. ConnMutex.Clear();
  2619. //
  2620. // Make sure we remove this connection from the dictionary
  2621. // before deleting it. We don't want another thread to pick it up
  2622. //
  2623. TransAbortConnection();
  2624. Delete();
  2625. //
  2626. // This routine will always be called with a reference held
  2627. //
  2628. ASSERT(RefCount.GetInteger());
  2629. State = ConnAborted;
  2630. // CCONN--
  2631. RemoveReference();
  2632. }
  2633. void
  2634. OSF_CCONNECTION::AdvanceToNextCall(
  2635. )
  2636. /*++
  2637. Function Name:AdvanceToNextCall
  2638. Parameters:
  2639. Description:
  2640. Returns:
  2641. --*/
  2642. {
  2643. UINT Size;
  2644. RPC_STATUS Status;
  2645. ConnMutex.Request();
  2646. CurrentCall = (OSF_CCALL *) CallQueue.TakeOffQueue(&Size);
  2647. if (CurrentCall == 0)
  2648. {
  2649. MakeConnectionIdle();
  2650. ConnMutex.Clear();
  2651. }
  2652. else
  2653. {
  2654. ConnMutex.Clear();
  2655. Status = CurrentCall->SendData(0);
  2656. if (Status != RPC_S_OK)
  2657. {
  2658. ConnectionAborted(Status);
  2659. //
  2660. // The connection cannot die.
  2661. //
  2662. //
  2663. // Remove the send reference for this call. CCALL--
  2664. //
  2665. CurrentCall->RemoveReference();
  2666. }
  2667. }
  2668. }
  2669. inline RPC_STATUS
  2670. OSF_CCONNECTION::TransGetBuffer (
  2671. OUT void * * Buffer,
  2672. IN UINT BufferLength
  2673. )
  2674. /*++
  2675. Routine Description:
  2676. We need a buffer to receive data into or to put data into to be sent.
  2677. This should be really simple, but we need to make sure that buffer we
  2678. return is aligned on an 8 byte boundary. The stubs make this requirement.
  2679. Arguments:
  2680. Buffer - Returns a pointer to the buffer.
  2681. BufferLength - Supplies the required length of the buffer in bytes.
  2682. Return Value:
  2683. RPC_S_OK - We successfully allocated a buffer of at least the required
  2684. size.
  2685. RPC_S_OUT_OF_MEMORY - There is insufficient memory available to allocate
  2686. the required buffer.
  2687. --*/
  2688. {
  2689. int * Memory;
  2690. //
  2691. // Our memory allocator returns memory which is aligned by at least
  2692. // 8, so we dont need to worry about aligning it.
  2693. //
  2694. Memory = (int *) CoAllocateBuffer(BufferLength);
  2695. if ( Memory == 0 )
  2696. {
  2697. return RPC_S_OUT_OF_MEMORY;
  2698. }
  2699. ASSERT(IsBufferAligned(Memory));
  2700. *Buffer = Memory;
  2701. ASSERT(PadPtr8(*Buffer) == 0);
  2702. return(RPC_S_OK);
  2703. }
  2704. inline void
  2705. OSF_CCONNECTION::TransFreeBuffer (
  2706. IN void * Buffer
  2707. )
  2708. /*++
  2709. Routine Description:
  2710. We need to free a buffer which was allocated via TransGetBuffer. The
  2711. only tricky part is remembering to remove the padding before actually
  2712. freeing the memory.
  2713. --*/
  2714. {
  2715. CoFreeBuffer(Buffer);
  2716. }
  2717. RPC_STATUS
  2718. OSF_CCONNECTION::TransReallocBuffer (
  2719. IN OUT void * * Buffer,
  2720. IN UINT OldSize,
  2721. IN UINT NewSize
  2722. )
  2723. /*++
  2724. Function Name:TransReallocBuffer
  2725. Parameters:
  2726. Description:
  2727. Reallocates a give buffer to the new size.
  2728. Returns:
  2729. RPC_S_OK: the buffer is successfully reallocated
  2730. RPC_S_OUT_OF_MEMORY: the realloc failed, the old buffer
  2731. is still valid.
  2732. --*/
  2733. {
  2734. BUFFER NewBuffer;
  2735. RPC_STATUS Status;
  2736. Status = TransGetBuffer(
  2737. (PVOID *) &NewBuffer,
  2738. NewSize);
  2739. if (Status != RPC_S_OK)
  2740. {
  2741. return RPC_S_OUT_OF_MEMORY;
  2742. }
  2743. if (OldSize)
  2744. {
  2745. RpcpMemoryCopy(NewBuffer, *Buffer, OldSize);
  2746. TransFreeBuffer(*Buffer);
  2747. }
  2748. *Buffer = NewBuffer;
  2749. return RPC_S_OK;
  2750. }
  2751. inline RPC_STATUS
  2752. OSF_CCONNECTION::AllocateCCall (
  2753. OUT OSF_CCALL **CCall
  2754. )
  2755. /*++
  2756. Function Name:AllocateCCall
  2757. Parameters:
  2758. Description:
  2759. Returns:
  2760. --*/
  2761. {
  2762. RPC_STATUS Status;
  2763. if (fExclusive)
  2764. {
  2765. ASSERT(CachedCCallAvailable == 1);
  2766. CachedCCallAvailable = 0;
  2767. *CCall = CachedCCall;
  2768. }
  2769. else
  2770. {
  2771. if (InterlockedCompareExchange( (PLONG)&CachedCCallAvailable, 0, 1))
  2772. {
  2773. *CCall = CachedCCall;
  2774. }
  2775. else
  2776. {
  2777. Status = RPC_S_OK;
  2778. *CCall = new (ClientInfo->SendContextSize+sizeof(PVOID))
  2779. OSF_CCALL(&Status);
  2780. if (*CCall == 0)
  2781. {
  2782. Status = RPC_S_OUT_OF_MEMORY;
  2783. }
  2784. if (Status != RPC_S_OK)
  2785. {
  2786. delete *CCall;
  2787. return Status;
  2788. }
  2789. }
  2790. }
  2791. LogEvent(SU_CCALL, EV_START, *CCall);
  2792. return RPC_S_OK;
  2793. }
  2794. RPC_STATUS
  2795. OSF_CCONNECTION::AddCall (
  2796. IN OSF_CCALL *CCall
  2797. )
  2798. /*++
  2799. Function Name:AddCall
  2800. Parameters:
  2801. Description:
  2802. Returns:
  2803. --*/
  2804. {
  2805. RPC_STATUS Status;
  2806. //
  2807. // Think of a better way of doing this. This condition is true the first
  2808. // time a connection is created, and when we are talking to legacy
  2809. // servers over non-exclusive connections
  2810. //
  2811. if (CurrentCall == CCall)
  2812. {
  2813. return RPC_S_OK;
  2814. }
  2815. ConnMutex.Request();
  2816. if (CurrentCall == 0)
  2817. {
  2818. CurrentCall = CCall;
  2819. }
  2820. else
  2821. {
  2822. if ((State == ConnAborted)
  2823. || ((Association->IsAssociationReset())
  2824. &&
  2825. (State != ConnUninitialized)
  2826. )
  2827. )
  2828. {
  2829. ConnMutex.Clear();
  2830. return RPC_S_CALL_FAILED;
  2831. }
  2832. Status = CallQueue.PutOnQueue(CCall, 0);
  2833. if (Status != 0)
  2834. {
  2835. ConnMutex.Clear();
  2836. return RPC_S_OUT_OF_MEMORY;
  2837. }
  2838. }
  2839. ConnMutex.Clear();
  2840. return RPC_S_OK;
  2841. }
  2842. void
  2843. OSF_CCONNECTION::FreeCCall (
  2844. IN OSF_CCALL *CCall,
  2845. IN RPC_STATUS Status,
  2846. IN ULONG ComTimeout
  2847. )
  2848. /*++
  2849. Function Name:FreeCCall
  2850. Parameters:
  2851. CCall - the call that is being freed
  2852. Status - the status with which the call completed
  2853. ComTimeout - the communication timeout for this call
  2854. Description:
  2855. Free the call, remove reference on the connection. If the free
  2856. is abortive, we need to cleanup the connection and inform the
  2857. association about it.
  2858. Returns:
  2859. --*/
  2860. {
  2861. LogEvent(SU_CCALL, EV_STOP, CCall);
  2862. ConnMutex.Request();
  2863. if (CCall->EEInfo)
  2864. {
  2865. FreeEEInfoChain(CCall->EEInfo);
  2866. CCall->EEInfo = NULL;
  2867. }
  2868. if (fExclusive == 0)
  2869. {
  2870. ActiveCalls.Delete(IntToPtr(CCall->CallId));
  2871. }
  2872. if (CCall == CachedCCall)
  2873. {
  2874. CachedCCallAvailable = 1;
  2875. }
  2876. else
  2877. {
  2878. delete CCall;
  2879. }
  2880. switch (Status)
  2881. {
  2882. case RPC_S_OUT_OF_MEMORY:
  2883. case RPC_S_ACCESS_DENIED:
  2884. case RPC_S_PROTOCOL_ERROR:
  2885. case RPC_S_CALL_FAILED:
  2886. case RPC_S_CALL_FAILED_DNE:
  2887. case RPC_S_CALL_CANCELLED:
  2888. case RPC_S_SEC_PKG_ERROR:
  2889. case RPC_S_INVALID_ARG:
  2890. case RPC_S_SERVER_UNAVAILABLE:
  2891. case RPC_P_CONNECTION_SHUTDOWN:
  2892. case RPC_P_CONNECTION_CLOSED:
  2893. //
  2894. // Need to release the connection mutex, so we won't deadlock
  2895. //
  2896. ConnMutex.Clear();
  2897. Association->ConnectionAborted(this);
  2898. ConnMutex.Request();
  2899. if (fExclusive)
  2900. {
  2901. Delete();
  2902. }
  2903. else
  2904. {
  2905. TransAbortConnection();
  2906. }
  2907. break;
  2908. default:
  2909. // RPC_S_UNKNOWN_IF & others
  2910. // Put error codes here only if you are absolutely
  2911. // sure you can recover. If in doubt, put them
  2912. // above
  2913. if (ThreadId == SYNC_CONN_BUSY)
  2914. {
  2915. ThreadId = SYNC_CONN_FREE;
  2916. }
  2917. else if (ThreadId == ASYNC_CONN_BUSY)
  2918. {
  2919. ThreadId = ASYNC_CONN_FREE;
  2920. ASSERT(fExclusive == FALSE);
  2921. if (ComTimeout != RPC_C_BINDING_INFINITE_TIMEOUT)
  2922. {
  2923. TurnOnOffKeepAlives (FALSE, 0);
  2924. }
  2925. }
  2926. SetLastTimeUsedToNow();
  2927. break;
  2928. }
  2929. ConnMutex.Clear();
  2930. //
  2931. // Remove the reference held by the call, CCONN--
  2932. //
  2933. RemoveReference();
  2934. }
  2935. void
  2936. OSF_CCONNECTION::ProcessSendComplete (
  2937. IN RPC_STATUS EventStatus,
  2938. IN BUFFER Buffer
  2939. )
  2940. /*++
  2941. Function Name:ProcessSendComplete
  2942. Parameters:
  2943. Description:
  2944. Returns:
  2945. --*/
  2946. {
  2947. rpcconn_common *Packet = (rpcconn_common *) Buffer;
  2948. OSF_CCALL *OldCall = CurrentCall;
  2949. switch (Packet->PTYPE)
  2950. {
  2951. case rpc_request:
  2952. case rpc_response:
  2953. TransFreeBuffer(BufferToFree);
  2954. if (EventStatus == RPC_S_OK)
  2955. {
  2956. if (Association->fMultiplex == mpx_yes)
  2957. {
  2958. //
  2959. // We are have no more data to send on this
  2960. // call. Remove ourselves from the call queue
  2961. //
  2962. AdvanceToNextCall();
  2963. }
  2964. else
  2965. {
  2966. if (OldCall->fOkToAdvanceCall())
  2967. {
  2968. AdvanceToNextCall();
  2969. }
  2970. }
  2971. //
  2972. // Remove the send reference on the call, CCALL--
  2973. //
  2974. OldCall->RemoveReference();
  2975. return;
  2976. }
  2977. break;
  2978. default:
  2979. ASSERT(ConnectionReady == 0);
  2980. TransFreeBuffer(Buffer);
  2981. ConnectionReady = 1;
  2982. break;
  2983. }
  2984. if (EventStatus != RPC_S_OK)
  2985. {
  2986. VALIDATE(EventStatus)
  2987. {
  2988. RPC_P_SEND_FAILED,
  2989. RPC_P_CONNECTION_CLOSED,
  2990. RPC_P_CONNECTION_SHUTDOWN
  2991. } END_VALIDATE;
  2992. ConnectionAborted(RPC_S_CALL_FAILED_DNE);
  2993. if (OldCall)
  2994. {
  2995. //
  2996. // The current I/O failed.
  2997. // Remove the send reference on the call, CCALL--
  2998. //
  2999. OldCall->RemoveReference();
  3000. }
  3001. }
  3002. }
  3003. void
  3004. OSF_CCONNECTION::ProcessReceiveComplete (
  3005. IN RPC_STATUS EventStatus,
  3006. IN BUFFER Buffer,
  3007. IN UINT BufferLength
  3008. )
  3009. /*++
  3010. Function Name:ProcessReceiveComplete
  3011. Parameters:
  3012. Description:
  3013. Returns:
  3014. --*/
  3015. {
  3016. RPC_STATUS Status;
  3017. OSF_CCALL *CCall;
  3018. BOOL fSubmitReceive;
  3019. if (EventStatus)
  3020. {
  3021. LogEvent(SU_CCONN, EV_PKT_IN, this, LongToPtr(EventStatus));
  3022. }
  3023. else
  3024. {
  3025. rpcconn_common * pkt = (rpcconn_common *) Buffer;
  3026. LogEvent(SU_CCONN, EV_PKT_IN, this, 0, (pkt->PTYPE << 16) | pkt->frag_length);
  3027. }
  3028. if (EventStatus != RPC_S_OK)
  3029. {
  3030. VALIDATE(EventStatus)
  3031. {
  3032. RPC_P_CONNECTION_CLOSED,
  3033. RPC_P_RECEIVE_FAILED,
  3034. RPC_P_CONNECTION_SHUTDOWN
  3035. } END_VALIDATE;
  3036. ASSERT(Buffer == 0);
  3037. ConnectionAborted(RPC_S_CALL_FAILED);
  3038. return;
  3039. }
  3040. ASSERT(Buffer);
  3041. unsigned long CallId = ((rpcconn_common *) Buffer)->call_id;
  3042. if (DataConvertEndian(((rpcconn_common *) Buffer)->drep) != 0)
  3043. {
  3044. CallId = RpcpByteSwapLong(CallId);
  3045. }
  3046. ConnMutex.Request();
  3047. CCall = ActiveCalls.Find(IntToPtr(CallId));
  3048. if (CCall)
  3049. {
  3050. if (CCall->CurrentState == Aborted)
  3051. {
  3052. ConnMutex.Clear();
  3053. TransAbortConnection();
  3054. return;
  3055. }
  3056. // CCALL++
  3057. CCall->AddReference();
  3058. ConnMutex.Clear();
  3059. //
  3060. // We try to create a thread. If it doesn't work,
  3061. // well too bad !, we'll go ahead and process this
  3062. // PDU any way
  3063. //
  3064. Status = Association->TransInfo->CreateThread();
  3065. VALIDATE(Status)
  3066. {
  3067. RPC_S_OK,
  3068. RPC_S_OUT_OF_MEMORY,
  3069. RPC_S_OUT_OF_THREADS
  3070. } END_VALIDATE;
  3071. //
  3072. // if fSubmitReceive is 1, we need to post a receive,
  3073. // otherwise, the receive will be posted by someone else
  3074. //
  3075. fSubmitReceive = CCall->ProcessReceivedPDU(
  3076. (rpcconn_common *) Buffer,
  3077. BufferLength);
  3078. ConnMutex.Request();
  3079. CCall->RemoveReference(); // CCALL--
  3080. ConnMutex.Clear();
  3081. }
  3082. else
  3083. {
  3084. ConnMutex.Clear();
  3085. fSubmitReceive = 0;
  3086. TransAbortConnection();
  3087. }
  3088. if (fSubmitReceive)
  3089. {
  3090. //
  3091. // TransAsyncReceive will retry several times
  3092. // before giving up
  3093. //
  3094. TransAsyncReceive ();
  3095. }
  3096. }
  3097. RPC_STATUS
  3098. OSF_CCONNECTION::OpenConnectionAndBind (
  3099. IN OSF_BINDING_HANDLE *BindingHandle,
  3100. IN ULONG Timeout,
  3101. IN BOOL fAlwaysNegotiateNDR20,
  3102. OUT FAILURE_COUNT_STATE *fFailureCountExceeded OPTIONAL
  3103. )
  3104. /*++
  3105. Function Name: OpenConnectionAndBind
  3106. Parameters:
  3107. BindingHandle - the binding handle on which we are doing the call
  3108. Timeout - the timeout for the bind (if any)
  3109. fAlwaysNegotiateNDR20 - TRUE if NDR20 should always be negotiated.
  3110. If the server chooses NDR64, we will explicitly alter-context
  3111. to NDR20 if this flag is set.
  3112. fFailureCountExceeded - if supplied, must be FailureCountUnknown. If
  3113. supplied, and we got bind failure with reason not specified, and
  3114. we haven't exceeded the failure count, this function will keep
  3115. retrying. If supplied, and we received bind failure with reason
  3116. not specified and the failure count is exceeded, it will be set
  3117. to FailureCountExceeded.
  3118. Description:
  3119. Returns:
  3120. --*/
  3121. {
  3122. RPC_STATUS Status;
  3123. BOOL fMutexHeld;
  3124. ULONG MyAssocGroupId;
  3125. MPX_TYPES myfMpx = Association->fMultiplex;
  3126. ULONG MyfInitialized;
  3127. void *MyHint = NULL;
  3128. OSF_BINDING *BindingNegotiated;
  3129. OSF_BINDING *IgnoredBinding;
  3130. BOOL fPossibleAssociationReset;
  3131. if (ARGUMENT_PRESENT(fFailureCountExceeded))
  3132. {
  3133. ASSERT(*fFailureCountExceeded == FailureCountUnknown);
  3134. }
  3135. if (!fExclusive)
  3136. {
  3137. //
  3138. // First thing we do is kick off a thread to go and listen
  3139. // this stuff is going to take very long
  3140. //
  3141. Status = Association->TransInfo->CreateThread();
  3142. if (Status != RPC_S_OK)
  3143. {
  3144. //
  3145. // Can't do anything right now, lets just go back and listen
  3146. //
  3147. return Status;
  3148. }
  3149. }
  3150. while (1)
  3151. {
  3152. if (Association->IsResolverHintSynchronizationNeeded())
  3153. {
  3154. Association->AssociationMutex.Request();
  3155. fMutexHeld = TRUE;
  3156. }
  3157. else
  3158. fMutexHeld = FALSE;
  3159. MyfInitialized = Association->AssocGroupId;
  3160. if (MyfInitialized == 0)
  3161. {
  3162. // make sure the hint is allocated only once on the stack
  3163. // otherwise, some of the retry paths will loop through here
  3164. // and may contribute to a stack overflow
  3165. if (MyHint == NULL)
  3166. {
  3167. MyHint = alloca(ClientInfo->ResolverHintSize);
  3168. ASSERT((ClientInfo->ResolverHintSize == 0) || MyHint);
  3169. }
  3170. }
  3171. else
  3172. {
  3173. MyHint = Association->InqResolverHint();
  3174. }
  3175. while (TRUE)
  3176. {
  3177. RpcpPurgeEEInfo();
  3178. Status = TransOpen (
  3179. BindingHandle,
  3180. Association->DceBinding->InqRpcProtocolSequence(),
  3181. Association->DceBinding->InqNetworkAddress(),
  3182. Association->DceBinding->InqEndpoint(),
  3183. Association->DceBinding->InqNetworkOptions(),
  3184. MyHint,
  3185. MyfInitialized,
  3186. Timeout);
  3187. if (Status != RPC_S_OK)
  3188. {
  3189. if (ComTimeout == RPC_C_BINDING_INFINITE_TIMEOUT
  3190. && (Status == RPC_S_SERVER_UNAVAILABLE
  3191. || Status == RPC_S_SERVER_TOO_BUSY))
  3192. {
  3193. continue;
  3194. }
  3195. if (fMutexHeld)
  3196. {
  3197. Association->AssociationMutex.Clear();
  3198. fMutexHeld = FALSE;
  3199. }
  3200. if (Status == RPC_S_SERVER_UNAVAILABLE)
  3201. {
  3202. Association->ShutdownRequested(Status, NULL);
  3203. }
  3204. return Status;
  3205. }
  3206. if (fMutexHeld == FALSE)
  3207. {
  3208. Association->AssociationMutex.Request();
  3209. fMutexHeld = TRUE;
  3210. }
  3211. MyAssocGroupId = Association->AssocGroupId;
  3212. if (MyAssocGroupId != 0)
  3213. {
  3214. if (MyfInitialized == 0 && ClientInfo->ResolverHintSize)
  3215. {
  3216. //
  3217. // We lost the race, we need to check if the address
  3218. // we picked up is the same as the one the winner picked up
  3219. // if it is not, we need to loop back
  3220. //
  3221. if (Association->CompareResolverHint(MyHint))
  3222. {
  3223. if (Association->IsResolverHintSynchronizationNeeded() == FALSE)
  3224. {
  3225. // if the resolver does not require synchronization, loop
  3226. // around without the mutex
  3227. Association->AssociationMutex.Clear();
  3228. fMutexHeld = FALSE;
  3229. }
  3230. if (MyHint != Association->InqResolverHint())
  3231. Association->FreeResolverHint(MyHint);
  3232. MyfInitialized = 1;
  3233. MyHint = Association->InqResolverHint();
  3234. TransClose();
  3235. continue;
  3236. }
  3237. }
  3238. Association->AssociationMutex.Clear();
  3239. fMutexHeld = FALSE;
  3240. if (MyHint != Association->InqResolverHint())
  3241. Association->FreeResolverHint(MyHint);
  3242. }
  3243. else
  3244. {
  3245. //
  3246. // We won the race, we need to store the resolved address in
  3247. // the association
  3248. //
  3249. if (ClientInfo->ResolverHintSize)
  3250. {
  3251. Association->SetResolverHint(MyHint);
  3252. Association->ResolverHintInitialized = TRUE;
  3253. }
  3254. }
  3255. break;
  3256. } // while (1)
  3257. TransInitComplete();
  3258. //
  3259. // Send a bind packet and wait for response
  3260. //
  3261. Status = ActuallyDoBinding (
  3262. CurrentCall,
  3263. MyAssocGroupId,
  3264. TRUE, // fNewConnection
  3265. Timeout,
  3266. &BindingNegotiated,
  3267. &fPossibleAssociationReset,
  3268. fFailureCountExceeded);
  3269. if (Status != RPC_S_OK)
  3270. {
  3271. if (fMutexHeld)
  3272. {
  3273. Association->AssociationMutex.Clear();
  3274. fMutexHeld = FALSE;
  3275. }
  3276. LogEvent(SU_CCONN, EV_STATE, ULongToPtr(MyAssocGroupId), ULongToPtr(Association->AssocGroupId), Status, 1, 0);
  3277. if ((Status == RPC_P_CONNECTION_SHUTDOWN)
  3278. &&
  3279. (
  3280. fPossibleAssociationReset
  3281. ||
  3282. (
  3283. ARGUMENT_PRESENT(fFailureCountExceeded)
  3284. &&
  3285. (*fFailureCountExceeded == FailureCountNotExceeded)
  3286. )
  3287. )
  3288. &&
  3289. (Association->IsValid())
  3290. )
  3291. {
  3292. //
  3293. // Either:
  3294. // 1. We have hit a race condition where the
  3295. // AssocGroupId is renegotiated because the
  3296. // close for the last connection came ahead
  3297. // of the bind for the next connection. In this
  3298. // case server returns BindNak with
  3299. // reason_not_specified, which gets translated
  3300. // to RPC_P_CONNECTION_SHUTDOWN. Retry again.
  3301. // or
  3302. // 2. We got bind_nak with reason not specified
  3303. // and the failure count was not exceeded
  3304. //
  3305. TransClose();
  3306. ASSERT(fMutexHeld == FALSE);
  3307. Association->AssociationMutex.Request();
  3308. if (fConnectionAborted == 0)
  3309. {
  3310. ASSERT(Association);
  3311. Association->NotifyConnectionClosed();
  3312. fConnectionAborted = 1;
  3313. }
  3314. if (fPossibleAssociationReset)
  3315. Association->FailureCount = 0;
  3316. InitializeWireAuthId(&ClientSecurityContext);
  3317. if (ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  3318. {
  3319. // DeleteSecurityContext checks and deletes
  3320. // the security context only if necessary
  3321. ClientSecurityContext.DeleteSecurityContext();
  3322. }
  3323. Association->AssociationMutex.Clear();
  3324. if (ARGUMENT_PRESENT(fFailureCountExceeded))
  3325. {
  3326. *fFailureCountExceeded = FailureCountUnknown;
  3327. }
  3328. continue;
  3329. }
  3330. if (fExclusive == 0
  3331. && Status == RPC_S_PROTOCOL_ERROR
  3332. && myfMpx == mpx_unknown)
  3333. {
  3334. Association->fMultiplex = mpx_no;
  3335. //Association->MinorVersion = 0;
  3336. //
  3337. // The server seems to be a legacy server,
  3338. // close the connection and start over,
  3339. // this time, don't set the PFC_CONC_MPX bit
  3340. //
  3341. TransClose();
  3342. ASSERT(fMutexHeld == FALSE);
  3343. Association->AssociationMutex.Request();
  3344. if (fConnectionAborted == 0)
  3345. {
  3346. ASSERT(Association);
  3347. Association->NotifyConnectionClosed();
  3348. fConnectionAborted = 1;
  3349. }
  3350. InitializeWireAuthId(&ClientSecurityContext);
  3351. if (ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  3352. {
  3353. // DeleteSecurityContext checks and deletes
  3354. // the security context only if necessary
  3355. ClientSecurityContext.DeleteSecurityContext();
  3356. }
  3357. Association->AssociationMutex.Clear();
  3358. continue;
  3359. }
  3360. return Status;
  3361. }
  3362. break;
  3363. }
  3364. // if we negotiated NDR64, but we were asked to negotiate NDR20,
  3365. // alter context to get the right context for this call
  3366. if (fAlwaysNegotiateNDR20
  3367. && (BindingNegotiated->CompareWithTransferSyntax(NDR64TransferSyntax) == 0))
  3368. {
  3369. // limit the choice to NDR20 only
  3370. // We do this by whacking the list of available bindings. Since the chosen binding
  3371. // is NDR20, this will force the bind to negotiate NDR20. We also change the state
  3372. // to WaitingForAlterContext
  3373. ASSERT(CurrentCall->Bindings.SelectedBinding->CompareWithTransferSyntax(NDR20TransferSyntax) == 0);
  3374. CurrentCall->Bindings.AvailableBindingsList = NULL;
  3375. CurrentCall->CurrentState = NeedAlterContext;
  3376. Status = ActuallyDoBinding (
  3377. CurrentCall,
  3378. MyAssocGroupId,
  3379. FALSE, // fNewConnection
  3380. Timeout,
  3381. &IgnoredBinding,
  3382. &fPossibleAssociationReset, // never actually used here
  3383. NULL // fFailureCountExceeded
  3384. );
  3385. if (Status)
  3386. {
  3387. if (fMutexHeld)
  3388. {
  3389. Association->AssociationMutex.Clear();
  3390. }
  3391. return Status;
  3392. }
  3393. }
  3394. if (fMutexHeld)
  3395. {
  3396. Association->AssociationMutex.Clear();
  3397. }
  3398. ASSERT((CurrentCall->CurrentState == NeedOpenAndBind)
  3399. || (CurrentCall->CurrentState == NeedAlterContext)
  3400. || (CurrentCall->CurrentState == Aborted));
  3401. if ((CurrentCall == NULL) || (CurrentCall->CurrentState == Aborted))
  3402. {
  3403. TransAbortConnection();
  3404. if ((CurrentCall != NULL) && (CurrentCall->GetCallStatus() == RPC_S_CALL_CANCELLED))
  3405. {
  3406. return RPC_S_CALL_CANCELLED;
  3407. }
  3408. else
  3409. {
  3410. return RPC_S_CALL_FAILED_DNE;
  3411. }
  3412. }
  3413. CurrentCall->CurrentState = SendingFirstBuffer;
  3414. if (!fExclusive)
  3415. {
  3416. Status = TransAsyncReceive();
  3417. if (Status != RPC_S_OK)
  3418. {
  3419. return Status;
  3420. }
  3421. CurrentCall->CallMutex.Request();
  3422. if (CurrentCall->CurrentBuffer == 0)
  3423. {
  3424. MakeConnectionIdle();
  3425. CurrentCall->CallMutex.Clear();
  3426. }
  3427. else
  3428. {
  3429. ASSERT(IsIdle() == 0);
  3430. CurrentCall->CallMutex.Clear();
  3431. Status = CurrentCall->SendNextFragment();
  3432. }
  3433. }
  3434. return Status ;
  3435. }
  3436. RPC_STATUS
  3437. OSF_CCONNECTION::ActuallyDoBinding (
  3438. IN OSF_CCALL *CCall,
  3439. IN ULONG MyAssocGroupId,
  3440. IN BOOL fNewConnection,
  3441. IN ULONG Timeout,
  3442. OUT OSF_BINDING **BindingNegotiated,
  3443. OUT BOOL *fPossibleAssociationReset,
  3444. OUT FAILURE_COUNT_STATE *fFailureCountExceeded
  3445. )
  3446. /*++
  3447. Function Name:ActuallyDoBinding
  3448. Parameters:
  3449. fFailureCountExceeded - if supplied, must be FailureCountUnknown. If
  3450. we got bind failure with reason not specified, and we haven't
  3451. exceeded the failure count, it will be set to
  3452. FailureCountNotExceeded. If we received bind failure with reason
  3453. not specified and the failure count is exceeded, it will be set
  3454. to FailureCountExceeded.
  3455. Description:
  3456. Returns:
  3457. --*/
  3458. {
  3459. RPC_STATUS Status;
  3460. rpcconn_common * Buffer = 0;
  3461. UINT BufferLength = 0;
  3462. OSF_BINDING *Binding;
  3463. if (ARGUMENT_PRESENT(fFailureCountExceeded))
  3464. {
  3465. ASSERT(*fFailureCountExceeded == FailureCountUnknown);
  3466. }
  3467. *fPossibleAssociationReset = FALSE;
  3468. if ( fNewConnection != 0)
  3469. {
  3470. ASSERT(fConnectionAborted == 1);
  3471. Association->AssociationMutex.Request();
  3472. if ((MyAssocGroupId != 0) && (Association->AssocGroupId != MyAssocGroupId))
  3473. {
  3474. // if we are already reset, then the server connection may
  3475. // be killed also. Just back out and retry
  3476. LogEvent(SU_CASSOC, EV_STATE, (PVOID)55, (PVOID)55, 66, 1, 0);
  3477. *fPossibleAssociationReset = TRUE;
  3478. Association->FailureCount = 0;
  3479. Association->AssociationMutex.Clear();
  3480. return (RPC_P_CONNECTION_SHUTDOWN);
  3481. }
  3482. Association->NotifyConnectionBindInProgress();
  3483. Association->AssociationMutex.Clear();
  3484. }
  3485. Status = SendBindPacket( TRUE,
  3486. CCall,
  3487. MyAssocGroupId,
  3488. (fNewConnection ? rpc_bind : rpc_alter_context),
  3489. Timeout,
  3490. FALSE, // synchronous
  3491. &Buffer,
  3492. &BufferLength,
  3493. 0, // no input buffer
  3494. 0 // no input buffer
  3495. );
  3496. //
  3497. // Now mark this connection as a part of the pool
  3498. //
  3499. if ( fNewConnection != 0)
  3500. {
  3501. Association->AssociationMutex.Request();
  3502. if (Association->fPossibleServerReset)
  3503. {
  3504. LogEvent(SU_CASSOC, EV_STATE, (PVOID)77, (PVOID)77, 88, 1, 0);
  3505. *fPossibleAssociationReset = TRUE;
  3506. }
  3507. //
  3508. // Did we get aborted while we were trying to bind ?
  3509. //
  3510. if (ConnectionKey == -1)
  3511. {
  3512. Association->NotifyConnectionBindCompleted();
  3513. TransAbortConnection();
  3514. if (Status == RPC_S_OK)
  3515. {
  3516. TransFreeBuffer(Buffer);
  3517. }
  3518. Status = RPC_P_CONNECTION_SHUTDOWN;
  3519. }
  3520. else
  3521. {
  3522. if ((Status != RPC_S_OK) || ( Buffer->PTYPE != rpc_bind_nak ))
  3523. {
  3524. Association->NotifyConnectionOpen();
  3525. fConnectionAborted = 0;
  3526. }
  3527. Association->NotifyConnectionBindCompleted();
  3528. }
  3529. Association->AssociationMutex.Clear();
  3530. }
  3531. if ( Status != RPC_S_OK )
  3532. {
  3533. VALIDATE(Status)
  3534. {
  3535. RPC_S_OUT_OF_MEMORY,
  3536. RPC_S_OUT_OF_RESOURCES,
  3537. RPC_P_CONNECTION_SHUTDOWN,
  3538. RPC_P_CONNECTION_CLOSED,
  3539. RPC_S_UUID_NO_ADDRESS,
  3540. RPC_S_ACCESS_DENIED,
  3541. RPC_S_SEC_PKG_ERROR,
  3542. RPC_S_CALL_CANCELLED,
  3543. RPC_P_TIMEOUT,
  3544. ERROR_SHUTDOWN_IN_PROGRESS
  3545. } END_VALIDATE;
  3546. //
  3547. // We'll let the call decide whether to nuke the connection
  3548. //
  3549. return(Status);
  3550. }
  3551. // We loop around ignoring shutdown packets until we get a response.
  3552. for (;;)
  3553. {
  3554. if ( Buffer->PTYPE == rpc_shutdown )
  3555. {
  3556. Association->ShutdownRequested(RPC_S_CALL_FAILED_DNE, NULL);
  3557. TransFreeBuffer(Buffer);
  3558. Status = TransReceive((void **) &Buffer,
  3559. &BufferLength,
  3560. Timeout);
  3561. if ( Status != RPC_S_OK )
  3562. {
  3563. VALIDATE(Status)
  3564. {
  3565. RPC_S_OUT_OF_MEMORY,
  3566. RPC_S_OUT_OF_RESOURCES,
  3567. RPC_P_RECEIVE_FAILED,
  3568. RPC_P_CONNECTION_CLOSED,
  3569. RPC_S_CALL_CANCELLED,
  3570. RPC_P_TIMEOUT
  3571. } END_VALIDATE;
  3572. if ( Status == RPC_P_RECEIVE_FAILED )
  3573. {
  3574. return RPC_P_CONNECTION_CLOSED;
  3575. }
  3576. return Status;
  3577. }
  3578. // If there is security, we need to save the packet header;
  3579. // byte-swapping the header will mess up decryption.
  3580. Status = ValidateHeader(Buffer, BufferLength);
  3581. if ( Status != RPC_S_OK )
  3582. {
  3583. TransFreeBuffer(Buffer);
  3584. return Status;
  3585. }
  3586. continue;
  3587. }
  3588. else if ( fNewConnection )
  3589. {
  3590. // Since this is a new connection, the packet we receive
  3591. // must be either a bind_ack or a bind_nak; anything else
  3592. // is an error.
  3593. if (Buffer->PTYPE == rpc_bind_ack || Buffer->PTYPE == rpc_bind_nak)
  3594. {
  3595. break;
  3596. }
  3597. else
  3598. {
  3599. TransFreeBuffer(Buffer);
  3600. return RPC_S_PROTOCOL_ERROR;
  3601. }
  3602. }
  3603. else
  3604. {
  3605. // This is a preexisting connection.
  3606. // We allow only an alter_context_response.
  3607. if ( Buffer->PTYPE == rpc_alter_context_resp )
  3608. {
  3609. break;
  3610. }
  3611. else
  3612. {
  3613. TransFreeBuffer(Buffer);
  3614. return RPC_S_PROTOCOL_ERROR;
  3615. }
  3616. }
  3617. }
  3618. ULONG NewGroupId;
  3619. //
  3620. // We subtract from BufferLength the length of the authentication
  3621. // information; that way ProcessBindAckOrNak can check the length
  3622. // correctly, whether or not there is security information.
  3623. //
  3624. if (MyAssocGroupId == 0)
  3625. {
  3626. Association->AssociationMutex.VerifyOwned();
  3627. Status = Association->ProcessBindAckOrNak(
  3628. Buffer,
  3629. BufferLength - Buffer->auth_length,
  3630. this,
  3631. CCall,
  3632. &NewGroupId,
  3633. BindingNegotiated,
  3634. fFailureCountExceeded);
  3635. }
  3636. else
  3637. {
  3638. Status = Association->AssociationMutex.RequestSafe();
  3639. if (Status == RPC_S_OK)
  3640. {
  3641. Status = Association->ProcessBindAckOrNak(
  3642. Buffer,
  3643. BufferLength - Buffer->auth_length,
  3644. this,
  3645. CCall,
  3646. &NewGroupId,
  3647. BindingNegotiated,
  3648. fFailureCountExceeded);
  3649. Association->AssociationMutex.Clear();
  3650. }
  3651. }
  3652. LogEvent(SU_CCONN, EV_STATE, ULongToPtr(MyAssocGroupId), ULongToPtr(Association->AssocGroupId), Status, 1, 0);
  3653. if (fExclusive == 0
  3654. && Association->fMultiplex == mpx_unknown)
  3655. {
  3656. if (((rpcconn_common *) Buffer)->pfc_flags & PFC_CONC_MPX)
  3657. {
  3658. Association->fMultiplex = mpx_yes;
  3659. }
  3660. else
  3661. {
  3662. Association->fMultiplex = mpx_no;
  3663. }
  3664. }
  3665. if ( Status == RPC_S_OK )
  3666. {
  3667. Status = FinishSecurityContextSetup(
  3668. CCall,
  3669. MyAssocGroupId,
  3670. &Buffer,
  3671. &BufferLength,
  3672. Timeout
  3673. );
  3674. }
  3675. else
  3676. {
  3677. TransFreeBuffer(Buffer);
  3678. }
  3679. if ( Status == RPC_S_OK )
  3680. {
  3681. Binding = CCall->GetSelectedBinding();
  3682. if (MyAssocGroupId == 0)
  3683. {
  3684. Association->AssociationMutex.VerifyOwned();
  3685. if (AddPContext(Binding->GetPresentationContext()) != 0)
  3686. {
  3687. Status = RPC_S_OUT_OF_RESOURCES;
  3688. }
  3689. else
  3690. {
  3691. //
  3692. // Once we reach here, we know that the binding has been accepted,
  3693. // so we can go ahead and set the association group id.
  3694. // warning: as soon as the AssocGroupId is set, threads
  3695. // will start sending the bind without acquiring the mutex
  3696. //
  3697. LogEvent(SU_CASSOC, EV_NOTIFY, Association, this, NewGroupId, 1, 0);
  3698. Association->AssocGroupId = NewGroupId;
  3699. }
  3700. }
  3701. else
  3702. {
  3703. Status = Association->AssociationMutex.RequestSafe();
  3704. if (Status == RPC_S_OK)
  3705. {
  3706. if (AddPContext(Binding->GetPresentationContext()) != 0)
  3707. {
  3708. Status = RPC_S_OUT_OF_RESOURCES;
  3709. }
  3710. Association->AssociationMutex.Clear();
  3711. }
  3712. }
  3713. if (fNewConnection)
  3714. {
  3715. Status = CCall->ReserveSpaceForSecurityIfNecessary();
  3716. }
  3717. }
  3718. else
  3719. {
  3720. if (fNewConnection != 0)
  3721. {
  3722. //
  3723. // If Status == DNE, it means that we probably got a B-NAK
  3724. // [Also note this is a new connection]
  3725. // If we were using security, [Auth Level != NONE]
  3726. // delete this connection, and return RPC_P_CONNECTION_SHUTDOWN
  3727. // which will cause BH->GetBuffer code to retry 2 more times
  3728. //
  3729. if (Status == RPC_S_CALL_FAILED_DNE)
  3730. {
  3731. //
  3732. // Retry failures over non-authenticated
  3733. // binds also.. the ones we retry over are bind naks with
  3734. // unspecifed reason .. one day we can get OSF to send
  3735. // bind_nk with reason assoc_group_shutdown..
  3736. // && (CConnection->AuthInfo.AuthenticationLevel
  3737. // != RPC_C_AUTHN_LEVEL_NONE))
  3738. //
  3739. Status = RPC_P_CONNECTION_SHUTDOWN;
  3740. }
  3741. }
  3742. }
  3743. return(Status);
  3744. }
  3745. RPC_STATUS
  3746. OSF_CCONNECTION::FinishSecurityContextSetup (
  3747. IN OSF_CCALL *Call,
  3748. IN unsigned long AssocGroup,
  3749. IN OUT rpcconn_common * * Buffer,
  3750. IN OUT unsigned int * BufferLength,
  3751. IN ULONG Timeout
  3752. )
  3753. {
  3754. RPC_STATUS Status = RPC_S_OK;
  3755. if (ClientSecurityContext.AuthenticationService == RPC_C_AUTHN_NONE
  3756. || ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
  3757. {
  3758. TransFreeBuffer(*Buffer);
  3759. return RPC_S_OK;
  3760. }
  3761. if ( !ClientSecurityContext.FullyConstructed() )
  3762. {
  3763. //
  3764. // Some packages need more than one round trip; we keep sending secure
  3765. // alter-context packets until the security context is fully set up.
  3766. //
  3767. do
  3768. {
  3769. rpcconn_common * InputBuffer = *Buffer;
  3770. *Buffer = 0;
  3771. Status = SendBindPacket(
  3772. FALSE,
  3773. Call,
  3774. AssocGroup,
  3775. rpc_alter_context,
  3776. Timeout,
  3777. FALSE, // synchronous
  3778. Buffer,
  3779. BufferLength,
  3780. InputBuffer,
  3781. *BufferLength
  3782. );
  3783. TransFreeBuffer(InputBuffer);
  3784. }
  3785. while (Status == RPC_S_OK && !ClientSecurityContext.FullyConstructed() );
  3786. if (Status == RPC_S_OK && *Buffer)
  3787. {
  3788. TransFreeBuffer(*Buffer);
  3789. }
  3790. }
  3791. else
  3792. {
  3793. TransFreeBuffer(*Buffer);
  3794. }
  3795. if (RPC_S_OK == Status)
  3796. {
  3797. // We need to figure out how much space to reserve for security
  3798. // information at the end of request and response packets.
  3799. // In addition to saving space for the signature or header,
  3800. // we need space to pad the packet to a multiple of the maximum
  3801. // security block size as well as for the security trailer.
  3802. switch ( ClientSecurityContext.AuthenticationLevel )
  3803. {
  3804. case RPC_C_AUTHN_LEVEL_CONNECT:
  3805. case RPC_C_AUTHN_LEVEL_PKT:
  3806. case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
  3807. AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
  3808. ClientSecurityContext.MaximumSignatureLength()
  3809. + sizeof(sec_trailer);
  3810. break;
  3811. case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
  3812. AdditionalSpaceForSecurity = MAXIMUM_SECURITY_BLOCK_SIZE +
  3813. ClientSecurityContext.MaximumHeaderLength()
  3814. + sizeof(sec_trailer);
  3815. break;
  3816. default:
  3817. ASSERT(!"Unknown Security Level\n");
  3818. }
  3819. }
  3820. return Status;
  3821. }
  3822. RPC_STATUS
  3823. OSF_CCONNECTION::DealWithAlterContextResp (
  3824. IN OSF_CCALL *CCall,
  3825. IN rpcconn_common *Packet,
  3826. IN int PacketLength,
  3827. IN OUT BOOL *AlterContextToNDR20IfNDR64Negotiated
  3828. )
  3829. /*++
  3830. Function Name:DealWithAlterContextResp
  3831. Parameters:
  3832. Description:
  3833. Returns:
  3834. --*/
  3835. {
  3836. RPC_STATUS Status;
  3837. ULONG NewGroupId;
  3838. BOOL fContextAddingFailed;
  3839. OSF_BINDING *Binding;
  3840. OSF_BINDING *NegotiatedBinding;
  3841. Status = Association->AssociationMutex.RequestSafe();
  3842. if (Status)
  3843. return Status;
  3844. Status = Association->ProcessBindAckOrNak(
  3845. Packet,
  3846. PacketLength - Packet->auth_length,
  3847. this,
  3848. CCall,
  3849. &NewGroupId,
  3850. &NegotiatedBinding,
  3851. NULL // fFailureCountExceeded
  3852. );
  3853. if ( Status != RPC_S_OK )
  3854. {
  3855. Association->AssociationMutex.Clear();
  3856. }
  3857. else
  3858. {
  3859. // the binding must have been fixed on the call by now
  3860. Binding = CCall->GetSelectedBinding();
  3861. ASSERT(Binding);
  3862. fContextAddingFailed = AddPContext(Binding->GetPresentationContext());
  3863. Association->AssociationMutex.Clear();
  3864. if (fContextAddingFailed)
  3865. return RPC_S_OUT_OF_MEMORY;
  3866. if (*AlterContextToNDR20IfNDR64Negotiated)
  3867. {
  3868. if (NegotiatedBinding->CompareWithTransferSyntax(NDR64TransferSyntax) == 0)
  3869. {
  3870. ConnectionReady = 0;
  3871. CCall->SendAlterContextPDU();
  3872. }
  3873. else
  3874. {
  3875. *AlterContextToNDR20IfNDR64Negotiated = FALSE;
  3876. }
  3877. }
  3878. }
  3879. return Status;
  3880. }
  3881. RPC_STATUS
  3882. OSF_CCONNECTION::SendBindPacket (
  3883. IN BOOL fInitialPass,
  3884. IN OSF_CCALL *Call,
  3885. IN ULONG AssocGroup,
  3886. IN unsigned char PacketType,
  3887. IN ULONG Timeout,
  3888. IN BOOL fAsync,
  3889. OUT rpcconn_common * * Buffer,
  3890. OUT UINT * BufferLength,
  3891. IN rpcconn_common * InputPacket,
  3892. IN unsigned int InputPacketLength
  3893. )
  3894. /*++
  3895. Routine Description:
  3896. This routine is used to send a bind or alter context packet. It
  3897. will allocate a buffer, fill in the packet, and then send it and
  3898. receive a reply. The reply buffer is just returned to the caller.
  3899. Arguments:
  3900. fInitialPass - true if this is the first bind packet sent for this
  3901. connection
  3902. Call - the call whose binding information we need to use in order
  3903. to bind.
  3904. AssocGroup - Supplies the association group id for the association
  3905. group of which this connection is a new member.
  3906. PacketType - Supplies the packet type which must be one of rpc_bind
  3907. or rpc_alter_context.
  3908. fAsync - the binding is async
  3909. Buffer - Returns the reply buffer.
  3910. BufferLength - Returns the length of the reply buffer.
  3911. InputPacket - the packet received from a peer, if this is not
  3912. the first leg of a security negotiation
  3913. InputPacketLength - the length of the input packet
  3914. Return Value:
  3915. RPC_S_OK - The operation completed successfully.
  3916. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
  3917. the operation.
  3918. RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to
  3919. complete the operation.
  3920. RPC_S_ACCESS_DENIED - The security package won't allow this.
  3921. RPC_P_CONNECTION_CLOSED - The connection has been closed and the
  3922. receive operation failed. The send operation may or may not
  3923. have succeeded.
  3924. --*/
  3925. {
  3926. rpcconn_bind * BindPacket = 0;
  3927. UINT BindPacketLength, AuthPadLength, SecurityTokenLength;
  3928. RPC_STATUS Status;
  3929. sec_trailer * SecurityTrailer;
  3930. SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
  3931. SECURITY_BUFFER SecurityBuffers[4];
  3932. DCE_INIT_SECURITY_INFO InitSecurityInfo;
  3933. UINT CompleteNeeded = 0;
  3934. OSF_CCALL *CallToBindFor = Call;
  3935. OSF_BINDING *BindingsAvailable;
  3936. OSF_BINDING *CurrentBinding;
  3937. BOOL fMultipleBindingsAvailable;
  3938. int AvailableBindingsCount;
  3939. ASSERT(CallToBindFor != 0);
  3940. BindingsAvailable = CallToBindFor->GetListOfAvaialbleBindings(&fMultipleBindingsAvailable);
  3941. if (fMultipleBindingsAvailable)
  3942. {
  3943. AvailableBindingsCount = 0;
  3944. CurrentBinding = BindingsAvailable;
  3945. do
  3946. {
  3947. AvailableBindingsCount ++;
  3948. CurrentBinding = CurrentBinding->GetNextBinding();
  3949. }
  3950. while (CurrentBinding != 0);
  3951. }
  3952. else
  3953. {
  3954. AvailableBindingsCount = 1;
  3955. }
  3956. BindPacketLength = sizeof(rpcconn_bind) + sizeof(p_cont_list_t) +
  3957. (AvailableBindingsCount - 1) * sizeof(p_cont_elem_t);
  3958. //
  3959. // If we need to send authentication information in the packet, we
  3960. // need to save space for it. This method prepares and sends both
  3961. // rpc_bind and rpc_alter_context packets; we will only send
  3962. // authentication information in rpc_bind packets. This is due to
  3963. // a design decision that each connection supports only a single
  3964. // security context, which is determined when the connection is
  3965. // created.
  3966. //
  3967. if (ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE
  3968. && !ClientSecurityContext.FullyConstructed())
  3969. {
  3970. VALIDATE(ClientSecurityContext.AuthenticationLevel)
  3971. {
  3972. RPC_C_AUTHN_LEVEL_CONNECT,
  3973. RPC_C_AUTHN_LEVEL_PKT,
  3974. RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
  3975. RPC_C_AUTHN_LEVEL_PKT_PRIVACY
  3976. } END_VALIDATE;
  3977. if (fInitialPass)
  3978. {
  3979. Status = UuidCreateSequential(&(DceSecurityInfo.AssociationUuid));
  3980. if ((Status != RPC_S_OK )
  3981. && (Status != RPC_S_UUID_LOCAL_ONLY))
  3982. {
  3983. return(Status);
  3984. }
  3985. }
  3986. //
  3987. // We align the packet length to a four byte boundary, and then
  3988. // save space for the token and the sec_trailer. We also need
  3989. // to save the length of the token because we will need it later
  3990. // if we do third leg authentication.
  3991. //
  3992. AuthPadLength = Pad4(BindPacketLength);
  3993. BindPacketLength += AuthPadLength;
  3994. TokenLength = ClientSecurityContext.Credentials->MaximumTokenLength();
  3995. BindPacketLength += TokenLength + sizeof(sec_trailer);
  3996. }
  3997. Status = TransGetBuffer((void * *) &BindPacket,
  3998. BindPacketLength);
  3999. if ( Status != RPC_S_OK )
  4000. {
  4001. ASSERT( Status == RPC_S_OUT_OF_MEMORY );
  4002. TransFreeBuffer(BindPacket);
  4003. return(RPC_S_OUT_OF_MEMORY);
  4004. }
  4005. ConstructPacket((rpcconn_common *) BindPacket, PacketType, BindPacketLength);
  4006. //
  4007. // A three-leg protocol will be sending an RPC_AUTH_3 instead of a BIND or ALTER_CONTEXT.
  4008. // DCE Kerberos is the only package that uses the read-only output buffers.
  4009. //
  4010. BindPacket->max_xmit_frag
  4011. = BindPacket->max_recv_frag
  4012. = (unsigned short) TransMaximumSend();
  4013. BindPacket->assoc_group_id = AssocGroup;
  4014. BindPacket->common.call_id = CallToBindFor->CallId;
  4015. BindPacket->common.pfc_flags =
  4016. PFC_FIRST_FRAG | PFC_LAST_FRAG;
  4017. if (fSeparateConnection == 0
  4018. && fExclusive == 0
  4019. && Association->fMultiplex != mpx_no)
  4020. {
  4021. //
  4022. // We don't want to set PFC_CONC_MPX for all the requests
  4023. // because the legacy NT server will send a protocol error fault
  4024. // and nuke the connection
  4025. //
  4026. BindPacket->common.pfc_flags |= PFC_CONC_MPX;
  4027. }
  4028. ConstructPContextList((p_cont_list_t *) (BindPacket + 1),
  4029. BindingsAvailable,
  4030. AvailableBindingsCount);
  4031. //
  4032. // If this connection is using security, we need to stick the
  4033. // authentication information into the packet.
  4034. //
  4035. if ( ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE
  4036. && !ClientSecurityContext.FullyConstructed() )
  4037. {
  4038. InitSecurityInfo.DceSecurityInfo = DceSecurityInfo;
  4039. InitSecurityInfo.AuthorizationService = ClientSecurityContext.AuthorizationService;
  4040. InitSecurityInfo.PacketType = PacketType;
  4041. BufferDescriptor.ulVersion = 0;
  4042. BufferDescriptor.cBuffers = 4;
  4043. BufferDescriptor.pBuffers = SecurityBuffers;
  4044. SecurityBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
  4045. SecurityBuffers[3].pvBuffer = &InitSecurityInfo;
  4046. SecurityBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
  4047. if (fInitialPass)
  4048. {
  4049. AdditionalLegNeeded = 0;
  4050. SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4051. SecurityBuffers[0].pvBuffer = BindPacket;
  4052. SecurityBuffers[0].cbBuffer = sizeof(rpcconn_bind);
  4053. SecurityBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4054. SecurityBuffers[1].pvBuffer = ((unsigned char *) BindPacket)
  4055. + sizeof(rpcconn_bind);
  4056. SecurityBuffers[1].cbBuffer = BindPacketLength
  4057. - sizeof(rpcconn_bind)
  4058. - ClientSecurityContext.Credentials->MaximumTokenLength();
  4059. SecurityBuffers[2].BufferType = SECBUFFER_TOKEN;
  4060. SecurityBuffers[2].pvBuffer = ((unsigned char *) BindPacket)
  4061. + BindPacketLength
  4062. - ClientSecurityContext.Credentials->MaximumTokenLength();
  4063. SecurityBuffers[2].cbBuffer = ClientSecurityContext.Credentials->MaximumTokenLength();
  4064. Status = ClientSecurityContext.InitializeFirstTime(
  4065. ClientSecurityContext.Credentials,
  4066. ClientSecurityContext.ServerPrincipalName,
  4067. ClientSecurityContext.AuthenticationLevel,
  4068. &BufferDescriptor,
  4069. &WireAuthId);
  4070. LogEvent(SU_CCONN, EV_SEC_INIT1, this, LongToPtr(Status), SecurityBuffers[2].cbBuffer);
  4071. }
  4072. else
  4073. {
  4074. if (ClientSecurityContext.Legs == ThreeLegs)
  4075. {
  4076. BindPacket->common.PTYPE = rpc_auth_3;
  4077. SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4078. SecurityBuffers[0].pvBuffer = BindPacket;
  4079. SecurityBuffers[0].cbBuffer = sizeof(rpcconn_auth3);
  4080. SecurityBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4081. SecurityBuffers[1].pvBuffer = ((unsigned char *) BindPacket)
  4082. + sizeof(rpcconn_auth3);
  4083. SecurityBuffers[1].cbBuffer = sizeof(sec_trailer);
  4084. SecurityBuffers[2].BufferType = SECBUFFER_TOKEN;
  4085. SecurityBuffers[2].pvBuffer = ((unsigned char *) BindPacket)
  4086. + sizeof(rpcconn_auth3)
  4087. + sizeof(sec_trailer);
  4088. SecurityBuffers[2].cbBuffer = TokenLength;
  4089. //
  4090. // These structures are already 4-aligned, so no padding is needed.
  4091. //
  4092. BindPacketLength = sizeof(rpcconn_auth3) + sizeof(sec_trailer) + TokenLength;
  4093. }
  4094. else
  4095. {
  4096. SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4097. SecurityBuffers[0].pvBuffer = BindPacket;
  4098. SecurityBuffers[0].cbBuffer = sizeof(rpcconn_bind);
  4099. SecurityBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4100. SecurityBuffers[1].pvBuffer = ((unsigned char *) BindPacket)
  4101. + sizeof(rpcconn_bind);
  4102. SecurityBuffers[1].cbBuffer = BindPacketLength
  4103. - sizeof(rpcconn_bind)
  4104. - TokenLength;
  4105. SecurityBuffers[2].BufferType = SECBUFFER_TOKEN;
  4106. SecurityBuffers[2].pvBuffer = ((unsigned char *) BindPacket)
  4107. + BindPacketLength
  4108. - TokenLength;
  4109. SecurityBuffers[2].cbBuffer = TokenLength;
  4110. }
  4111. //
  4112. // a third leg auth may not be needed with some packages
  4113. // on an alter context [where only pcon is changed as opposed
  4114. // to an alternative client principal]
  4115. //
  4116. AdditionalLegNeeded = 0;
  4117. if (InputPacket)
  4118. {
  4119. SECURITY_BUFFER_DESCRIPTOR InputBufferDescriptor;
  4120. SECURITY_BUFFER InputBuffers[4];
  4121. DCE_INIT_SECURITY_INFO InputSecurityInfo;
  4122. InputSecurityInfo.DceSecurityInfo = DceSecurityInfo;
  4123. InputSecurityInfo.AuthorizationService = ClientSecurityContext.AuthorizationService;
  4124. InputSecurityInfo.PacketType = InputPacket->PTYPE;
  4125. InputBufferDescriptor.ulVersion = 0;
  4126. InputBufferDescriptor.cBuffers = 4;
  4127. InputBufferDescriptor.pBuffers = InputBuffers;
  4128. ASSERT((SavedHeader != 0) && (SavedHeaderSize != 0));
  4129. InputBuffers[0].cbBuffer = sizeof(rpcconn_bind_ack) - sizeof(unsigned short);
  4130. InputBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4131. InputBuffers[0].pvBuffer = SavedHeader;
  4132. InputBuffers[1].cbBuffer = InputPacketLength
  4133. - (sizeof(rpcconn_bind_ack) - sizeof(unsigned short))
  4134. - InputPacket->auth_length;
  4135. InputBuffers[1].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4136. InputBuffers[1].pvBuffer = ((unsigned char *) SavedHeader)
  4137. + sizeof(rpcconn_bind_ack) - sizeof(unsigned short);
  4138. InputBuffers[2].cbBuffer = InputPacket->auth_length;
  4139. InputBuffers[2].BufferType = SECBUFFER_TOKEN;
  4140. InputBuffers[2].pvBuffer = ((unsigned char *) InputPacket) + InputPacketLength - InputPacket->auth_length;
  4141. InputBuffers[3].cbBuffer = sizeof(DCE_INIT_SECURITY_INFO);
  4142. InputBuffers[3].BufferType = SECBUFFER_PKG_PARAMS | SECBUFFER_READONLY;
  4143. InputBuffers[3].pvBuffer = &InputSecurityInfo;
  4144. Status = ClientSecurityContext.InitializeThirdLeg(
  4145. ClientSecurityContext.Credentials,
  4146. *((unsigned long *) &(BindPacket->common.drep[0])),
  4147. &InputBufferDescriptor,
  4148. &BufferDescriptor
  4149. );
  4150. }
  4151. else
  4152. {
  4153. Status = ClientSecurityContext.InitializeThirdLeg(
  4154. ClientSecurityContext.Credentials,
  4155. *((unsigned long *) &(BindPacket->common.drep[0])),
  4156. 0,
  4157. &BufferDescriptor
  4158. );
  4159. }
  4160. LogEvent(SU_CCONN, EV_SEC_INIT3, this, LongToPtr(Status), SecurityBuffers[2].cbBuffer);
  4161. }
  4162. //
  4163. // The security package has encrypted or signed the data.
  4164. //
  4165. if ( Status == RPC_P_CONTINUE_NEEDED )
  4166. {
  4167. //
  4168. // Remember the fact that the security package requested that
  4169. // it be called again. This will be important later: see
  4170. // OSF_CASSOCIATION::ActuallyDoBinding.
  4171. //
  4172. AdditionalLegNeeded = 1;
  4173. }
  4174. else if ( Status == RPC_P_COMPLETE_NEEDED )
  4175. {
  4176. CompleteNeeded = 1;
  4177. }
  4178. else if ( Status == RPC_P_COMPLETE_AND_CONTINUE )
  4179. {
  4180. AdditionalLegNeeded = 1;
  4181. CompleteNeeded = 1;
  4182. }
  4183. else if ( Status != RPC_S_OK )
  4184. {
  4185. VALIDATE(Status)
  4186. {
  4187. RPC_S_OUT_OF_MEMORY,
  4188. RPC_S_ACCESS_DENIED,
  4189. RPC_S_SEC_PKG_ERROR,
  4190. RPC_S_UNKNOWN_AUTHN_SERVICE,
  4191. RPC_S_INVALID_ARG,
  4192. ERROR_SHUTDOWN_IN_PROGRESS
  4193. } END_VALIDATE;
  4194. TransFreeBuffer(BindPacket);
  4195. return(Status);
  4196. }
  4197. //
  4198. // The Snego package can behave either as a 3- or 4-leg protocol depending
  4199. // upon the server. It knows which way to go after the first call to
  4200. // InitializeSecurityContext().
  4201. //
  4202. if (fInitialPass && AdditionalLegNeeded)
  4203. {
  4204. ClientSecurityContext.Legs = GetPackageLegCount( WireAuthId );
  4205. if (ClientSecurityContext.Legs == LegsUnknown)
  4206. {
  4207. TransFreeBuffer(BindPacket);
  4208. return RPC_S_OUT_OF_MEMORY;
  4209. }
  4210. }
  4211. //
  4212. // In NT 4.0 and before, the length was considered a read-only field.
  4213. //
  4214. SecurityTokenLength = (UINT) SecurityBuffers[2].cbBuffer;
  4215. if (!AdditionalLegNeeded &&
  4216. 0 == SecurityTokenLength)
  4217. {
  4218. //
  4219. // No more packets to send.
  4220. //
  4221. TransFreeBuffer(BindPacket);
  4222. return RPC_S_OK;
  4223. }
  4224. //
  4225. // We need to fill in the fields of the security trailer.
  4226. //
  4227. SecurityTrailer = (sec_trailer *)
  4228. (((unsigned char *) BindPacket)
  4229. + BindPacketLength
  4230. - ClientSecurityContext.Credentials->MaximumTokenLength()
  4231. - sizeof(sec_trailer));
  4232. SecurityTrailer->auth_type = WireAuthId;
  4233. SecurityTrailer->auth_level = (unsigned char) ClientSecurityContext.AuthenticationLevel;
  4234. SecurityTrailer->auth_pad_length = (unsigned char) AuthPadLength;
  4235. SecurityTrailer->auth_reserved = 0;
  4236. SecurityTrailer->auth_context_id = PtrToUlong(this);
  4237. //
  4238. // Ok, finally, we need to adjust the length of the packet,
  4239. // and set the length of the authentication information.
  4240. //
  4241. BindPacket->common.auth_length = (unsigned short) SecurityTokenLength;
  4242. BindPacketLength = BindPacketLength
  4243. - ClientSecurityContext.Credentials->MaximumTokenLength()
  4244. + SecurityTokenLength;
  4245. BindPacket->common.frag_length = (unsigned short) BindPacketLength;
  4246. if ( CompleteNeeded != 0 )
  4247. {
  4248. Status = ClientSecurityContext.CompleteSecurityToken(
  4249. &BufferDescriptor);
  4250. if (Status != 0)
  4251. {
  4252. TransFreeBuffer(BindPacket);
  4253. return(Status);
  4254. }
  4255. }
  4256. }
  4257. if (fAsync)
  4258. {
  4259. Status = TransAsyncSend(BindPacket,
  4260. BindPacketLength,
  4261. u.ConnSendContext);
  4262. }
  4263. else if (BindPacket->common.PTYPE == rpc_auth_3)
  4264. {
  4265. Status = TransSend(BindPacket,
  4266. BindPacketLength,
  4267. TRUE, // fDisableShutdownCheck
  4268. FALSE, // fDisableCancelCheck
  4269. Timeout
  4270. );
  4271. //
  4272. // Null out the reply buffer, because there is none !
  4273. //
  4274. *Buffer = NULL;
  4275. }
  4276. else
  4277. {
  4278. Status = TransSendReceive(BindPacket,
  4279. BindPacketLength,
  4280. (void * *) Buffer,
  4281. BufferLength,
  4282. Timeout);
  4283. }
  4284. if ( Status != RPC_S_OK )
  4285. {
  4286. VALIDATE(Status)
  4287. {
  4288. RPC_S_OUT_OF_MEMORY,
  4289. RPC_S_ACCESS_DENIED,
  4290. RPC_S_OUT_OF_RESOURCES,
  4291. RPC_P_CONNECTION_CLOSED,
  4292. RPC_P_RECEIVE_FAILED,
  4293. RPC_P_SEND_FAILED,
  4294. RPC_P_CONNECTION_SHUTDOWN,
  4295. RPC_S_CALL_CANCELLED,
  4296. RPC_P_TIMEOUT
  4297. } END_VALIDATE;
  4298. TransFreeBuffer(BindPacket);
  4299. if ((Status == RPC_P_RECEIVE_FAILED)
  4300. || (Status == RPC_P_SEND_FAILED))
  4301. {
  4302. return(RPC_P_CONNECTION_CLOSED);
  4303. }
  4304. return(Status);
  4305. }
  4306. else
  4307. {
  4308. ClearFreshFromCacheFlag();
  4309. if (fAsync == 0)
  4310. {
  4311. switch (BindPacket->common.PTYPE)
  4312. {
  4313. case rpc_auth_3:
  4314. // don't have a new packet
  4315. break;
  4316. case rpc_fault:
  4317. Status = ValidatePacket(*Buffer, *BufferLength);
  4318. if (Status == RPC_S_OK)
  4319. {
  4320. Status = ((rpcconn_fault *) *Buffer)->status;
  4321. }
  4322. break;
  4323. default:
  4324. Status = ValidateHeader(*Buffer, *BufferLength);
  4325. }
  4326. TransFreeBuffer(BindPacket);
  4327. }
  4328. }
  4329. return Status;
  4330. }
  4331. void
  4332. OSF_CCONNECTION::SetMaxFrag (
  4333. IN unsigned short max_xmit_frag,
  4334. IN unsigned short max_recv_frag
  4335. )
  4336. {
  4337. UNUSED(max_recv_frag);
  4338. unsigned TranMax = TransMaximumSend();
  4339. MaxFrag = max_xmit_frag;
  4340. if (MaxFrag > TranMax || MaxFrag == 0)
  4341. {
  4342. MaxFrag = (unsigned short) TranMax;
  4343. }
  4344. #ifndef WIN
  4345. ASSERT( MaxFrag >= MUST_RECV_FRAG_SIZE );
  4346. #endif // WIN
  4347. }
  4348. RPC_STATUS
  4349. OSF_CCONNECTION::SendFragment(
  4350. IN rpcconn_common *pFragment,
  4351. IN OSF_CCALL *CCall,
  4352. IN UINT LastFragmentFlag,
  4353. IN UINT HeaderSize,
  4354. IN UINT MaxSecuritySize,
  4355. IN UINT DataLength,
  4356. IN UINT MaxFragmentLength,
  4357. IN unsigned char *ReservedForSecurity,
  4358. IN BOOL fAsync,
  4359. IN void *SendContext,
  4360. IN ULONG Timeout,
  4361. OUT void **ReceiveBuffer,
  4362. OUT UINT *ReceiveBufferLength
  4363. )
  4364. /*++
  4365. Routine Description:
  4366. Sends on fragment
  4367. --*/
  4368. {
  4369. sec_trailer * SecurityTrailer;
  4370. UINT SecurityLength;
  4371. UINT AuthPadLength;
  4372. SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
  4373. SECURITY_BUFFER SecurityBuffers[5];
  4374. DCE_MSG_SECURITY_INFO MsgSecurityInfo;
  4375. RPC_STATUS Status;
  4376. if (ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE
  4377. || (ClientSecurityContext.AuthenticationLevel == RPC_C_AUTHN_LEVEL_CONNECT
  4378. && MaxSecuritySize == 0))
  4379. {
  4380. SecurityLength = 0;
  4381. if (LastFragmentFlag != 0)
  4382. {
  4383. pFragment->pfc_flags |= PFC_LAST_FRAG;
  4384. }
  4385. }
  4386. else
  4387. {
  4388. VALIDATE(ClientSecurityContext.AuthenticationLevel)
  4389. {
  4390. RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
  4391. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  4392. RPC_C_AUTHN_LEVEL_PKT,
  4393. RPC_C_AUTHN_LEVEL_CONNECT
  4394. } END_VALIDATE;
  4395. if ( LastFragmentFlag == 0 )
  4396. {
  4397. SecurityTrailer = (sec_trailer *)
  4398. (((unsigned char *) pFragment)
  4399. + MaxFragmentLength - MaxSecuritySize);
  4400. //
  4401. // It is not the last fragment, so we need to save away the
  4402. // part of the buffer which could get overwritten with
  4403. // authentication information. We can not use memcpy,
  4404. // because the source and destination regions may overlap.
  4405. //
  4406. RpcpMemoryMove(ReservedForSecurity,
  4407. SecurityTrailer,
  4408. MaxSecuritySize);
  4409. AuthPadLength = 0;
  4410. }
  4411. else
  4412. {
  4413. ASSERT( MAXIMUM_SECURITY_BLOCK_SIZE == 16 );
  4414. AuthPadLength = Pad16(HeaderSize+DataLength+sizeof(sec_trailer));
  4415. DataLength += AuthPadLength;
  4416. ASSERT( ((HeaderSize+DataLength+sizeof(sec_trailer))
  4417. % MAXIMUM_SECURITY_BLOCK_SIZE) == 0 );
  4418. SecurityTrailer = (sec_trailer *)
  4419. (((unsigned char *) pFragment)
  4420. + DataLength + HeaderSize);
  4421. pFragment->pfc_flags |= PFC_LAST_FRAG;
  4422. }
  4423. SecurityTrailer->auth_type = (unsigned char) WireAuthId;
  4424. SecurityTrailer->auth_level = (unsigned char) ClientSecurityContext.AuthenticationLevel;
  4425. SecurityTrailer->auth_pad_length = (unsigned char) AuthPadLength;
  4426. SecurityTrailer->auth_reserved = 0;
  4427. SecurityTrailer->auth_context_id = PtrToUlong(this);
  4428. BufferDescriptor.ulVersion = 0;
  4429. BufferDescriptor.cBuffers = 5;
  4430. BufferDescriptor.pBuffers = SecurityBuffers;
  4431. SecurityBuffers[0].cbBuffer = HeaderSize;
  4432. SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4433. SecurityBuffers[0].pvBuffer = ((unsigned char *) pFragment);
  4434. SecurityBuffers[1].cbBuffer = (LastFragmentFlag != 0 ?
  4435. (DataLength)
  4436. : (MaxFragmentLength - HeaderSize - MaxSecuritySize)
  4437. );
  4438. SecurityBuffers[1].BufferType = SECBUFFER_DATA;
  4439. SecurityBuffers[1].pvBuffer = ((unsigned char *) pFragment)
  4440. + HeaderSize;
  4441. SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  4442. SecurityBuffers[2].cbBuffer = sizeof(sec_trailer);
  4443. SecurityBuffers[2].pvBuffer = SecurityTrailer;
  4444. SecurityBuffers[3].cbBuffer = MaxSecuritySize - sizeof(sec_trailer);
  4445. SecurityBuffers[3].BufferType = SECBUFFER_TOKEN;
  4446. SecurityBuffers[3].pvBuffer = SecurityTrailer + 1;
  4447. SecurityBuffers[4].cbBuffer = sizeof(DCE_MSG_SECURITY_INFO);
  4448. SecurityBuffers[4].BufferType = (SECBUFFER_PKG_PARAMS
  4449. | SECBUFFER_READONLY);
  4450. SecurityBuffers[4].pvBuffer = &MsgSecurityInfo;
  4451. MsgSecurityInfo.SendSequenceNumber =
  4452. DceSecurityInfo.SendSequenceNumber;
  4453. MsgSecurityInfo.ReceiveSequenceNumber =
  4454. InquireReceiveSequenceNumber();
  4455. MsgSecurityInfo.PacketType = pFragment->PTYPE;
  4456. //
  4457. // DCE computes check sums for Header also
  4458. // Make sure Header remains intact
  4459. // Infact may need to extend security interface if
  4460. // some packages return dynamic size seals/signatures
  4461. //
  4462. pFragment->auth_length = SecurityLength = (unsigned short)
  4463. SecurityBuffers[3].cbBuffer;
  4464. SecurityLength += sizeof(sec_trailer);
  4465. if ( LastFragmentFlag != 0)
  4466. {
  4467. pFragment->pfc_flags |= PFC_LAST_FRAG;
  4468. pFragment->frag_length = HeaderSize + DataLength
  4469. + SecurityLength;
  4470. }
  4471. else
  4472. {
  4473. pFragment->frag_length += SecurityLength - MaxSecuritySize;
  4474. }
  4475. Status = ClientSecurityContext.SignOrSeal(
  4476. MsgSecurityInfo.SendSequenceNumber,
  4477. ClientSecurityContext.AuthenticationLevel
  4478. != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  4479. &BufferDescriptor);
  4480. //
  4481. // The fragment may have been checksumed. Do not touch the fragment
  4482. // after this (including the header), if you do it will cause a checksum error
  4483. //
  4484. ASSERT(SecurityBuffers[3].cbBuffer <= pFragment->auth_length);
  4485. if (Status != RPC_S_OK)
  4486. {
  4487. if ( LastFragmentFlag == 0 )
  4488. {
  4489. RpcpMemoryCopy(SecurityTrailer,
  4490. ReservedForSecurity,
  4491. MaxSecuritySize);
  4492. }
  4493. if (Status == ERROR_SHUTDOWN_IN_PROGRESS)
  4494. {
  4495. return Status;
  4496. }
  4497. if ((Status == SEC_E_CONTEXT_EXPIRED)
  4498. || (Status == SEC_E_QOP_NOT_SUPPORTED))
  4499. {
  4500. return (RPC_S_SEC_PKG_ERROR);
  4501. }
  4502. return (RPC_S_ACCESS_DENIED);
  4503. }
  4504. }
  4505. if (LastFragmentFlag != 0)
  4506. {
  4507. ASSERT(!RpcpCheckHeap());
  4508. if (fAsync)
  4509. {
  4510. Status = TransAsyncSend(pFragment,
  4511. pFragment->frag_length,
  4512. SendContext);
  4513. }
  4514. else
  4515. {
  4516. if (ReceiveBuffer)
  4517. {
  4518. Status = TransSendReceive(pFragment,
  4519. pFragment->frag_length,
  4520. ReceiveBuffer,
  4521. ReceiveBufferLength,
  4522. Timeout);
  4523. }
  4524. else
  4525. {
  4526. Status = TransSend(pFragment,
  4527. pFragment->frag_length,
  4528. FALSE, // fDisableShutdownCheck
  4529. FALSE, // fDisableCancelCheck
  4530. Timeout);
  4531. }
  4532. }
  4533. if (Status != RPC_S_OK)
  4534. {
  4535. if ((Status == RPC_P_CONNECTION_CLOSED)
  4536. || (Status == RPC_P_SEND_FAILED))
  4537. {
  4538. return(RPC_S_CALL_FAILED_DNE);
  4539. }
  4540. if (Status == RPC_P_RECEIVE_FAILED)
  4541. {
  4542. return(RPC_S_CALL_FAILED);
  4543. }
  4544. if (Status == RPC_P_TIMEOUT)
  4545. {
  4546. RpcpErrorAddRecord(EEInfoGCRuntime,
  4547. RPC_S_CALL_CANCELLED,
  4548. EEInfoDLOSF_CCONNECTION__SendFragment10,
  4549. (ULONG)Status,
  4550. (ULONG)Timeout);
  4551. return(RPC_S_CALL_CANCELLED);
  4552. }
  4553. VALIDATE(Status)
  4554. {
  4555. RPC_S_OUT_OF_MEMORY,
  4556. RPC_S_OUT_OF_RESOURCES,
  4557. RPC_P_CONNECTION_SHUTDOWN,
  4558. RPC_S_CALL_CANCELLED
  4559. } END_VALIDATE;
  4560. return(Status);
  4561. }
  4562. ClearFreshFromCacheFlag();
  4563. return(RPC_S_OK);
  4564. }
  4565. if (fAsync)
  4566. {
  4567. Status = TransAsyncSend(pFragment,
  4568. pFragment->frag_length,
  4569. CCall->CallSendContext);
  4570. }
  4571. else
  4572. {
  4573. Status = TransSend(pFragment,
  4574. pFragment->frag_length,
  4575. FALSE, // fDisableShutdownCheck
  4576. FALSE, // fDisableCancelCheck
  4577. Timeout);
  4578. //
  4579. // We need to restore the part of the buffer which we overwrote
  4580. // with authentication information.
  4581. //
  4582. if ((ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  4583. && (ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_CONNECT
  4584. || (MaxSecuritySize != 0)))
  4585. {
  4586. //
  4587. // if MaxSecuritySize == 0, there will be no copying,
  4588. // so its OK to not check for it.
  4589. //
  4590. VALIDATE(ClientSecurityContext.AuthenticationLevel)
  4591. {
  4592. RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
  4593. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  4594. RPC_C_AUTHN_LEVEL_PKT,
  4595. RPC_C_AUTHN_LEVEL_CONNECT
  4596. } END_VALIDATE;
  4597. RpcpMemoryCopy(SecurityTrailer, ReservedForSecurity,
  4598. MaxSecuritySize);
  4599. }
  4600. if (ReceiveBuffer
  4601. && Status == RPC_P_RECEIVE_COMPLETE)
  4602. {
  4603. // we're going to do a receive - whack any eeinfo
  4604. // on the thread that the WS_CheckForShutdowns has
  4605. // added
  4606. RpcpPurgeEEInfo();
  4607. Status = TransReceive(ReceiveBuffer,
  4608. ReceiveBufferLength,
  4609. Timeout);
  4610. }
  4611. }
  4612. if ( Status != RPC_S_OK )
  4613. {
  4614. if ((Status == RPC_P_CONNECTION_CLOSED)
  4615. || (Status == RPC_P_SEND_FAILED))
  4616. {
  4617. return(RPC_S_CALL_FAILED_DNE);
  4618. }
  4619. if (Status == RPC_P_TIMEOUT)
  4620. {
  4621. RpcpErrorAddRecord(EEInfoGCRuntime,
  4622. RPC_S_CALL_CANCELLED,
  4623. EEInfoDLOSF_CCONNECTION__SendFragment20,
  4624. (ULONG)Status,
  4625. (ULONG)Timeout);
  4626. return RPC_S_CALL_CANCELLED;
  4627. }
  4628. VALIDATE(Status)
  4629. {
  4630. RPC_S_OUT_OF_MEMORY,
  4631. RPC_S_OUT_OF_RESOURCES,
  4632. RPC_P_CONNECTION_SHUTDOWN,
  4633. RPC_S_CALL_CANCELLED,
  4634. RPC_P_RECEIVE_FAILED
  4635. } END_VALIDATE;
  4636. return(Status);
  4637. }
  4638. ClearFreshFromCacheFlag();
  4639. return Status;
  4640. }
  4641. inline int
  4642. OSF_CCONNECTION::SupportedAuthInfo (
  4643. IN CLIENT_AUTH_INFO * ClientAuthInfo,
  4644. IN BOOL fNamedPipe
  4645. )
  4646. /*++
  4647. Arguments:
  4648. ClientAuthInfo - Supplies the authentication and authorization information
  4649. required of this connection. A value of zero (the pointer is
  4650. zero) indicates that we want an unauthenticated connection.
  4651. Return Value:
  4652. Non-zero indicates that the connection has the requested authentication
  4653. and authorization information; otherwise, zero will be returned.
  4654. --*/
  4655. {
  4656. return (ClientSecurityContext.IsSupportedAuthInfo(ClientAuthInfo, fNamedPipe));
  4657. }
  4658. RPC_STATUS
  4659. OSF_CCONNECTION::AddActiveCall (
  4660. IN ULONG CallId,
  4661. IN OSF_CCALL *CCall
  4662. )
  4663. /*++
  4664. Function Name:AddActiveCall
  4665. Parameters:
  4666. Description:
  4667. Returns:
  4668. --*/
  4669. {
  4670. int retval;
  4671. ConnMutex.Request();
  4672. if (State == ConnAborted)
  4673. {
  4674. ConnMutex.Clear();
  4675. return RPC_S_CALL_FAILED;
  4676. }
  4677. retval = ActiveCalls.Insert(IntToPtr(CallId), CCall);
  4678. ConnMutex.Clear();
  4679. if (retval == -1)
  4680. {
  4681. return RPC_S_OUT_OF_MEMORY;
  4682. }
  4683. return RPC_S_OK;
  4684. }
  4685. RPC_STATUS
  4686. OSF_CCONNECTION::CallCancelled (
  4687. OUT PDWORD Timeout
  4688. )
  4689. /*++
  4690. Function Name:CallCancelled
  4691. Parameters:
  4692. Description:
  4693. This function is called by the transport interface when it notices that it has
  4694. received an altert. This routine is called via I_RpcIOAlerted
  4695. Returns:
  4696. --*/
  4697. {
  4698. if (fExclusive == 0 || CurrentCall == 0)
  4699. {
  4700. return RPC_S_NO_CALL_ACTIVE;
  4701. }
  4702. ASSERT(fExclusive && CurrentCall);
  4703. //
  4704. // Even if we get alerted in the bind path, we already have a call object.
  4705. // That makes it easy for us to track cancels
  4706. //
  4707. return CurrentCall->CallCancelled(Timeout);
  4708. }
  4709. MTSyntaxBinding *CreateOsfBinding(
  4710. IN RPC_SYNTAX_IDENTIFIER *InterfaceId,
  4711. IN TRANSFER_SYNTAX_STUB_INFO *TransferSyntaxInfo,
  4712. IN int CapabilitiesBitmap
  4713. )
  4714. {
  4715. return new OSF_BINDING(InterfaceId,
  4716. TransferSyntaxInfo,
  4717. CapabilitiesBitmap);
  4718. }
  4719. extern "C" RPC_IF_HANDLE _mgmt_ClientIfHandle;
  4720. OSF_CCALL::OSF_CCALL (
  4721. RPC_STATUS __RPC_FAR * pStatus
  4722. ) : CallMutex(pStatus),
  4723. SyncEvent(pStatus, 0),
  4724. fAdvanceCallCount(0)
  4725. {
  4726. LogEvent(SU_CCALL, EV_CREATE, this);
  4727. ObjectType = OSF_CCALL_TYPE;
  4728. ReservedForSecurity = 0;
  4729. SecBufferLength = 0;
  4730. SavedHeaderSize = 0;
  4731. SavedHeader = 0;
  4732. InReply = 0;
  4733. EEInfo = NULL;
  4734. CachedAPCInfoAvailable = 1;
  4735. #ifdef DEBUGRPC
  4736. CallbackLevel = 0;
  4737. #endif
  4738. CallSendContext = (char *) this+sizeof(OSF_CCALL)+sizeof(PVOID);
  4739. *((PVOID *) ((char *) CallSendContext - sizeof(PVOID))) = (PVOID) this;
  4740. }
  4741. OSF_CCALL::~OSF_CCALL (
  4742. )
  4743. {
  4744. LogEvent(SU_CCALL, EV_DELETE, this);
  4745. if (CachedAPCInfoAvailable == 0)
  4746. {
  4747. ASSERT(!"Can't destroy call with queued APCs on it");
  4748. }
  4749. if (ReservedForSecurity)
  4750. {
  4751. RpcpFarFree(ReservedForSecurity);
  4752. }
  4753. if (SavedHeader)
  4754. {
  4755. RpcpFarFree(SavedHeader);
  4756. }
  4757. Connection->NotifyCallDeleted();
  4758. }
  4759. RPC_STATUS OSF_CCALL::ReserveSpaceForSecurityIfNecessary (void)
  4760. {
  4761. SECURITY_CONTEXT *ClientSecurityContext ;
  4762. ClientSecurityContext = &(Connection->ClientSecurityContext);
  4763. //
  4764. // We need to figure out about security: do we need to put authentication
  4765. // information into each packet, and if so, how much space should we
  4766. // reserve. So that we have space to save the contents of the buffer
  4767. // which will be overwritten with authentication information (for all but
  4768. // the last fragment).
  4769. //
  4770. if (ClientSecurityContext->AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  4771. {
  4772. VALIDATE(ClientSecurityContext->AuthenticationLevel)
  4773. {
  4774. RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
  4775. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  4776. RPC_C_AUTHN_LEVEL_CONNECT,
  4777. RPC_C_AUTHN_LEVEL_PKT
  4778. } END_VALIDATE;
  4779. MaxSecuritySize = Connection->AdditionalSpaceForSecurity
  4780. - MAXIMUM_SECURITY_BLOCK_SIZE;
  4781. if (MaxSecuritySize < sizeof(sec_trailer))
  4782. {
  4783. ASSERT(MaxSecuritySize >= sizeof(sec_trailer));
  4784. return(RPC_S_INTERNAL_ERROR);
  4785. }
  4786. if (MaxSecuritySize == sizeof(sec_trailer))
  4787. {
  4788. if (ClientSecurityContext->AuthenticationLevel
  4789. != RPC_C_AUTHN_LEVEL_CONNECT)
  4790. {
  4791. ASSERT(0);
  4792. return(RPC_S_INTERNAL_ERROR);
  4793. }
  4794. MaxSecuritySize = 0;
  4795. }
  4796. else
  4797. {
  4798. if (SecBufferLength < Connection->AdditionalSpaceForSecurity)
  4799. {
  4800. if (ReservedForSecurity)
  4801. {
  4802. RpcpFarFree(ReservedForSecurity);
  4803. }
  4804. ReservedForSecurity = (unsigned char *)
  4805. RpcpFarAllocate(Connection->AdditionalSpaceForSecurity);
  4806. if (ReservedForSecurity == 0)
  4807. {
  4808. SecBufferLength = 0;
  4809. return RPC_S_OUT_OF_MEMORY;
  4810. }
  4811. SecBufferLength = Connection->AdditionalSpaceForSecurity;
  4812. }
  4813. }
  4814. }
  4815. // if the header size has already been determined, update the frag length
  4816. // if not, we'll let the GetBuffer thread do it. Also, there is a small
  4817. // race condition where we may update it twice, but since this is perf
  4818. // only, we don't care - in the common case the gains are huge when we
  4819. // don't have to update
  4820. if (HeaderSize != 0)
  4821. UpdateMaxFragLength(ClientSecurityContext->AuthenticationLevel);
  4822. fDataLengthNegotiated = TRUE;
  4823. return RPC_S_OK;
  4824. }
  4825. void OSF_CCALL::UpdateObjectUUIDInfo (IN UUID *ObjectUuid)
  4826. {
  4827. UUID *ObjectUuidToUse;
  4828. ULONG AuthnLevel;
  4829. //
  4830. // Do the initial setup
  4831. //
  4832. if (ObjectUuid)
  4833. {
  4834. ObjectUuidToUse = ObjectUuid;
  4835. }
  4836. else if (BindingHandle->InqIfNullObjectUuid() == 0)
  4837. {
  4838. ObjectUuidToUse = BindingHandle->InqPointerAtObjectUuid();
  4839. }
  4840. else
  4841. {
  4842. ObjectUuidToUse = 0;
  4843. UuidSpecified = 0;
  4844. HeaderSize = sizeof(rpcconn_request);
  4845. }
  4846. if (ObjectUuidToUse)
  4847. {
  4848. UuidSpecified = 1;
  4849. HeaderSize = sizeof(rpcconn_request) + sizeof(UUID);
  4850. RpcpMemoryCopy(&this->ObjectUuid, ObjectUuidToUse, sizeof(UUID));
  4851. }
  4852. AuthnLevel = Connection->ClientSecurityContext.AuthenticationLevel;
  4853. // recalc if either there is no security size or if it is ready
  4854. if ((MaxSecuritySize != 0) || (AuthnLevel == RPC_C_AUTHN_LEVEL_NONE))
  4855. {
  4856. UpdateMaxFragLength(AuthnLevel);
  4857. }
  4858. }
  4859. void OSF_CCALL::UpdateMaxFragLength (ULONG AuthnLevel)
  4860. {
  4861. BOOL fExclusive = Connection->fExclusive;
  4862. // if the connection is exclusive, this all happens on the same thread -
  4863. // no need for a mutex
  4864. if (!fExclusive)
  4865. CallMutex.Request();
  4866. MaximumFragmentLength = Connection->MaxFrag;
  4867. if (AuthnLevel != RPC_C_AUTHN_LEVEL_NONE)
  4868. {
  4869. MaximumFragmentLength -= ((MaximumFragmentLength
  4870. - HeaderSize - MaxSecuritySize)
  4871. % MAXIMUM_SECURITY_BLOCK_SIZE);
  4872. }
  4873. MaxDataLength = MaximumFragmentLength
  4874. - HeaderSize - MaxSecuritySize;
  4875. if (!fExclusive)
  4876. CallMutex.Clear();
  4877. }
  4878. BOOL
  4879. OSF_CCALL::IssueNotification (
  4880. IN RPC_ASYNC_EVENT Event
  4881. )
  4882. {
  4883. BOOL fRes;
  4884. RPC_STATUS Status;
  4885. if (pAsync == 0)
  4886. {
  4887. if (Connection->fExclusive == 0)
  4888. {
  4889. SyncEvent.Raise();
  4890. }
  4891. return 0;
  4892. }
  4893. // we must have bailed out by now if this is sync
  4894. ASSERT (pAsync);
  4895. fRes = CCALL::IssueNotificationEntry(Event);
  4896. if (!fRes)
  4897. return 0;
  4898. if (AsyncStatus == RPC_S_OK)
  4899. {
  4900. RPC_SECURITY_CALLBACK_FN *SecurityCallback = NULL;
  4901. Status = BindingHandle->InqTransportOption(
  4902. RPC_C_OPT_SECURITY_CALLBACK,
  4903. (ULONG_PTR *) &SecurityCallback);
  4904. ASSERT(Status == RPC_S_OK);
  4905. if (SecurityCallback)
  4906. {
  4907. (*SecurityCallback) (this);
  4908. }
  4909. }
  4910. return CCALL::IssueNotificationMain(Event);
  4911. }
  4912. const int MAX_ASYNC_RETRIES = 3;
  4913. RPC_STATUS
  4914. OSF_CCALL::BindToServer (
  4915. BOOL fAsyncBind
  4916. )
  4917. /*++
  4918. Function Name:BindToServer
  4919. Parameters:
  4920. Description:
  4921. Returns:
  4922. --*/
  4923. {
  4924. RPC_STATUS Status;
  4925. OSF_BINDING_HANDLE *pLocalBindingHandle = BindingHandle;
  4926. OSF_CCONNECTION *pLocalConnection;
  4927. ULONG Timeout;
  4928. BOOL fBindingHandleTimeoutUsed = TRUE;
  4929. BOOL fAlwaysNegotiateNDR20 = FALSE;
  4930. OSF_BINDING *IgnoredBinding;
  4931. ULONG LocalAssociationGroupId;
  4932. BOOL Ignored;
  4933. FAILURE_COUNT_STATE fFailureCountExceeded = FailureCountUnknown;
  4934. int AsyncRetries = 0;
  4935. if (EEInfo)
  4936. {
  4937. FreeEEInfoChain(EEInfo);
  4938. EEInfo = NULL;
  4939. }
  4940. if (fAsyncBind == FALSE)
  4941. {
  4942. //
  4943. // We party on the call even after the connection is aborted.
  4944. // We need to keep a reference on the call
  4945. // CCALL++
  4946. // We do this only in the sync case, as in the async,
  4947. // the reference has already been added for us by the caller
  4948. //
  4949. AddReference();
  4950. }
  4951. else
  4952. {
  4953. ASSERT(Connection->fExclusive == FALSE);
  4954. // if this is a new, non-exclusive conn
  4955. if (pLocalBindingHandle && (CurrentState == NeedOpenAndBind))
  4956. {
  4957. // if we have had no preferences at the time of
  4958. // establishment (which is signified by the fact that both
  4959. // SelectedBinding and AvalableBindingsList is set)
  4960. if (Bindings.SelectedBinding && Bindings.AvailableBindingsList)
  4961. {
  4962. fAlwaysNegotiateNDR20 = TRUE;
  4963. }
  4964. }
  4965. }
  4966. Connection->CurrentCall = this;
  4967. if (pLocalBindingHandle)
  4968. {
  4969. Timeout = GetEffectiveTimeoutForBind(pLocalBindingHandle, &fBindingHandleTimeoutUsed);
  4970. do
  4971. {
  4972. switch (CurrentState)
  4973. {
  4974. case NeedOpenAndBind:
  4975. Status = Connection->OpenConnectionAndBind(
  4976. pLocalBindingHandle,
  4977. Timeout,
  4978. fAlwaysNegotiateNDR20,
  4979. &fFailureCountExceeded);
  4980. break;
  4981. case NeedAlterContext:
  4982. if (Connection->fExclusive)
  4983. {
  4984. LocalAssociationGroupId = Connection->Association->AssocGroupId;
  4985. if (LocalAssociationGroupId)
  4986. {
  4987. Status = Connection->ActuallyDoBinding(
  4988. this,
  4989. Connection->Association->AssocGroupId,
  4990. 0,
  4991. Timeout,
  4992. &IgnoredBinding,
  4993. &Ignored, // fPossibleAssociationReset
  4994. NULL // fFailureCountExceeded
  4995. );
  4996. if (Status == RPC_S_OK)
  4997. {
  4998. CurrentState = SendingFirstBuffer;
  4999. }
  5000. }
  5001. else
  5002. Status = RPC_S_CALL_FAILED_DNE;
  5003. }
  5004. else
  5005. {
  5006. Status = SendAlterContextPDU();
  5007. }
  5008. break;
  5009. default:
  5010. #if DBG
  5011. PrintToDebugger("RPC: BindToServer was a nop, CurrentState: %d\n",
  5012. CurrentState);
  5013. #endif
  5014. Status = RPC_S_OK;
  5015. break;
  5016. }
  5017. if (fAsyncBind)
  5018. {
  5019. ASSERT(fFailureCountExceeded != FailureCountNotExceeded);
  5020. // if this is a bind_nak with reason not specified, and retry
  5021. // attempts exhausted, shutdown the association, but without this
  5022. // connection, and then retry the OpenConnectionAndBind
  5023. if (
  5024. (fFailureCountExceeded == FailureCountExceeded)
  5025. &&
  5026. (CurrentState == NeedOpenAndBind)
  5027. )
  5028. {
  5029. Connection->Association->ShutdownRequested(RPC_S_OK, Connection);
  5030. // do some cleanup work on the current connection to avoid
  5031. // leaks.
  5032. Connection->TransClose();
  5033. Connection->InitializeWireAuthId(&Connection->ClientSecurityContext);
  5034. if (Connection->ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE)
  5035. {
  5036. // DeleteSecurityContext checks and deletes
  5037. // the security context only if necessary
  5038. Connection->ClientSecurityContext.DeleteSecurityContext();
  5039. }
  5040. fFailureCountExceeded = FailureCountUnknown;
  5041. AsyncRetries ++;
  5042. // retry the bind
  5043. continue;
  5044. }
  5045. pLocalBindingHandle->BindingFree();
  5046. }
  5047. // all paths except those with explicit continue exit the loop
  5048. break;
  5049. }
  5050. while (AsyncRetries <= MAX_ASYNC_RETRIES);
  5051. }
  5052. else
  5053. Status = RPC_S_CALL_FAILED_DNE;
  5054. // save the data member in a local variable
  5055. pLocalConnection = Connection;
  5056. if (Status != RPC_S_OK)
  5057. {
  5058. if (pLocalBindingHandle)
  5059. {
  5060. Status = GetStatusForTimeout(
  5061. pLocalBindingHandle,
  5062. Status,
  5063. fBindingHandleTimeoutUsed);
  5064. }
  5065. if (Connection->fExclusive == 0)
  5066. {
  5067. if (Status == RPC_P_CONNECTION_CLOSED
  5068. || Status == RPC_P_CONNECTION_SHUTDOWN
  5069. || Status == RPC_P_SEND_FAILED)
  5070. {
  5071. Status = RPC_S_CALL_FAILED_DNE;
  5072. }
  5073. Connection->ConnectionAborted(Status, 0);
  5074. //
  5075. // Remove the send reference for this call, CCALL--
  5076. //
  5077. RemoveReference();
  5078. }
  5079. }
  5080. //
  5081. // Remove the reference we added above
  5082. // CCALL--
  5083. //
  5084. RemoveReference();
  5085. if (fAsyncBind)
  5086. pLocalConnection->RemoveReference();
  5087. return Status;
  5088. }
  5089. RPC_STATUS
  5090. OSF_CCALL::ActuallyAllocateBuffer (
  5091. OUT void * * Buffer,
  5092. IN UINT BufferLength
  5093. )
  5094. /*++
  5095. Routine Description:
  5096. We need a buffer to receive data into or to put data into to be sent.
  5097. This should be really simple, but we need to make sure that buffer we
  5098. return is aligned on an 8 byte boundary. The stubs make this requirement.
  5099. Arguments:
  5100. Buffer - Returns a pointer to the buffer.
  5101. BufferLength - Supplies the required length of the buffer in bytes.
  5102. Return Value:
  5103. RPC_S_OK - We successfully allocated a buffer of at least the required
  5104. size.
  5105. RPC_S_OUT_OF_MEMORY - There is insufficient memory available to allocate
  5106. the required buffer.
  5107. --*/
  5108. {
  5109. return Connection->TransGetBuffer(Buffer, BufferLength);
  5110. }
  5111. void
  5112. OSF_CCALL::ActuallyFreeBuffer (
  5113. IN void * Buffer
  5114. )
  5115. /*++
  5116. Routine Description:
  5117. We need to free a buffer which was allocated via TransGetBuffer. The
  5118. only tricky part is remembering to remove the padding before actually
  5119. freeing the memory.
  5120. --*/
  5121. {
  5122. Connection->TransFreeBuffer(Buffer);
  5123. }
  5124. RPC_STATUS
  5125. OSF_CCALL::ActivateCall (
  5126. IN OSF_BINDING_HANDLE *BindingHandle,
  5127. IN OSF_BINDING *Binding,
  5128. IN OSF_BINDING *AvailableBindingsList,
  5129. IN ULONG CallIdToUse,
  5130. IN OSF_CCALL_STATE InitialCallState,
  5131. IN PRPC_DISPATCH_TABLE DispatchTable,
  5132. IN OSF_CCONNECTION *CConnection
  5133. )
  5134. /*++
  5135. Function Name:ActivateCall
  5136. Parameters:
  5137. Description:
  5138. Only Binding or AvailableBindingsList can be used, but not both
  5139. Returns:
  5140. --*/
  5141. {
  5142. RPC_STATUS Status = RPC_S_OK;
  5143. ASSERT(BufferQueue.IsQueueEmpty());
  5144. MaxSecuritySize = 0;
  5145. MaxDataLength = 0;
  5146. Connection = CConnection;
  5147. this->BindingHandle = BindingHandle;
  5148. CurrentBuffer = 0;
  5149. CurrentOffset = 0;
  5150. CurrentState = InitialCallState;
  5151. CallStack = 0;
  5152. RcvBufferLength = 0;
  5153. pAsync = 0;
  5154. NeededLength = 0;
  5155. MaximumFragmentLength = 0;
  5156. LastBuffer = NULL;
  5157. RecursiveCallsKey = -1;
  5158. fDataLengthNegotiated = FALSE;
  5159. if (Binding)
  5160. {
  5161. // we can have both binding and binding list only for non-sync
  5162. // calls
  5163. ASSERT((AvailableBindingsList == NULL) || (Connection->fExclusive == FALSE));
  5164. }
  5165. else
  5166. {
  5167. // if we don't have a binding, this must be a sync call.
  5168. // Async calls must have their bindings fixed by now
  5169. ASSERT(Connection->fExclusive);
  5170. }
  5171. Bindings.SelectedBinding = Binding;
  5172. Bindings.AvailableBindingsList = AvailableBindingsList;
  5173. this->DispatchTableCallback = DispatchTable;
  5174. CallId = CallIdToUse;
  5175. fCallCancelled = FALSE;
  5176. CancelState = CANCEL_NOTREGISTERED;
  5177. AdditionalSpaceForSecurity = Connection->AdditionalSpaceForSecurity;
  5178. fPeerChoked = 0;
  5179. fDoFlowControl = 0;
  5180. HeaderSize = 0;
  5181. if (Connection->fExclusive == 0)
  5182. {
  5183. //
  5184. // 1. The first reference is removed when
  5185. // all the sends are complete. This is called the send reference
  5186. // CCALL++
  5187. // 2. The second one is removed when the client is done with the call,
  5188. // ie: when freebuffer is called or when an operation fails. This is called
  5189. // the call reference. CCALL++
  5190. //
  5191. SetReferenceCount(2);
  5192. fAdvanceCallCount.SetInteger(0);
  5193. AsyncStatus = RPC_S_ASYNC_CALL_PENDING ;
  5194. FirstSend = 1;
  5195. NotificationIssued = -1;
  5196. fChoked = 0;
  5197. fLastSendComplete = 0;
  5198. CallingThread = ThreadSelf();
  5199. if (CallingThread == 0)
  5200. {
  5201. //
  5202. // If the thread pointer should have been initialized in
  5203. // GetBuffer.
  5204. return RPC_S_INTERNAL_ERROR;
  5205. }
  5206. Status = Connection->AddActiveCall(
  5207. CallIdToUse,
  5208. this);
  5209. }
  5210. else
  5211. {
  5212. CallingThread = 0;
  5213. }
  5214. return Status;
  5215. }
  5216. RPC_STATUS
  5217. OSF_CCALL::SendHelper (
  5218. IN PRPC_MESSAGE Message,
  5219. OUT BOOL *fFirstSend
  5220. )
  5221. /*++
  5222. Function Name:Send
  5223. Parameters:
  5224. Message - Contains information about the request
  5225. Description:
  5226. Returns:
  5227. --*/
  5228. {
  5229. void *NewBuffer;
  5230. int RemainingLength = 0;
  5231. RPC_STATUS Status = RPC_S_OK;
  5232. BOOL fRegisterFailed = 0;
  5233. ASSERT(HeaderSize != 0);
  5234. *fFirstSend = 0;
  5235. if (PARTIAL(Message))
  5236. {
  5237. if (fDataLengthNegotiated == 0
  5238. || Message->BufferLength < MaxDataLength)
  5239. {
  5240. if (pAsync && (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
  5241. {
  5242. if (!IssueNotification(RpcSendComplete))
  5243. {
  5244. CallFailed(Status);
  5245. // this is async only. We don't need to unregister for cancels
  5246. return Status;
  5247. }
  5248. }
  5249. return (RPC_S_SEND_INCOMPLETE);
  5250. }
  5251. ASSERT(MaxDataLength);
  5252. RemainingLength = Message->BufferLength % MaxDataLength;
  5253. if (RemainingLength)
  5254. {
  5255. Status = GetBufferDo(RemainingLength, &NewBuffer);
  5256. if (Status != RPC_S_OK)
  5257. {
  5258. CallFailed(Status);
  5259. UnregisterCallForCancels();
  5260. return Status;
  5261. }
  5262. Message->BufferLength -= RemainingLength;
  5263. RpcpMemoryCopy(NewBuffer,
  5264. (char *) Message->Buffer + Message->BufferLength,
  5265. RemainingLength);
  5266. }
  5267. }
  5268. else
  5269. {
  5270. ASSERT(LastBuffer == NULL);
  5271. LastBuffer = Message->Buffer;
  5272. }
  5273. //
  5274. // Add a reference for this send, CCALL++
  5275. //
  5276. AddReference();
  5277. //
  5278. // You get to actually send only if you are the CurrentCall
  5279. // and the connection is idle.
  5280. //
  5281. Retry:
  5282. if (AsyncStatus != RPC_S_ASYNC_CALL_PENDING)
  5283. {
  5284. Status = AsyncStatus;
  5285. ASSERT(Status != RPC_S_OK);
  5286. if (Status == RPC_S_CALL_FAILED_DNE)
  5287. {
  5288. Status = RPC_S_CALL_FAILED;
  5289. }
  5290. // N.B. The connection that does the bind will have
  5291. // its send reference removed in case of failure, and
  5292. // will be the current call. Therefore, we remove
  5293. // the reference only if we aren't the current call
  5294. if (Connection->CurrentCall != this)
  5295. {
  5296. //
  5297. // We didn't get a chance to submit a new send
  5298. // Remove the send reference CCALL--
  5299. //
  5300. OSF_CCALL::RemoveReference();
  5301. }
  5302. goto Cleanup;
  5303. }
  5304. CallMutex.Request();
  5305. if (CurrentBuffer)
  5306. {
  5307. //
  5308. // If the call had failed, we will find out after the we return
  5309. // from this routine
  5310. //
  5311. if (pAsync == 0 && BufferQueue.Size() >= 4)
  5312. {
  5313. fChoked = 1;
  5314. CallMutex.Clear();
  5315. SyncEvent.Wait();
  5316. goto Retry;
  5317. }
  5318. //
  5319. // Since CurrentBuffer != 0, the connection could not have been
  5320. // in a quiscent state. Therefore, we don't need to tickle it. This
  5321. // also means that the call is currently in the call queue of the connection.
  5322. // So, we don't need to add ourselves to the call queue.
  5323. //
  5324. if (BufferQueue.PutOnQueue(Message->Buffer, Message->BufferLength))
  5325. {
  5326. Status = RPC_S_OUT_OF_MEMORY;
  5327. if (Connection->CurrentCall != this)
  5328. {
  5329. //
  5330. // We didn't get a chance to submit a new send
  5331. // Remove the send reference CCALL--
  5332. //
  5333. OSF_CCALL::RemoveReference();
  5334. }
  5335. }
  5336. CallMutex.Clear();
  5337. }
  5338. else
  5339. {
  5340. CurrentOffset = 0;
  5341. CurrentBuffer = Message->Buffer;
  5342. CurrentBufferLength = Message->BufferLength;
  5343. if (FirstSend)
  5344. {
  5345. FirstSend = 0;
  5346. CallStack++;
  5347. CallMutex.Clear();
  5348. Status = RegisterCallForCancels();
  5349. if (Status != RPC_S_OK)
  5350. {
  5351. fRegisterFailed = 1;
  5352. if (Connection->CurrentCall != this)
  5353. {
  5354. //
  5355. // We didn't get a chance to submit a new send
  5356. // Remove the send reference CCALL--
  5357. //
  5358. OSF_CCALL::RemoveReference();
  5359. }
  5360. goto Cleanup;
  5361. }
  5362. Status = Connection->AddCall(this);
  5363. *fFirstSend = 1;
  5364. if (Status != RPC_S_OK)
  5365. {
  5366. if (Connection->CurrentCall != this)
  5367. {
  5368. //
  5369. // We didn't get a chance to submit a new send
  5370. // Remove the send reference CCALL--
  5371. //
  5372. OSF_CCALL::RemoveReference();
  5373. }
  5374. goto Cleanup;
  5375. }
  5376. }
  5377. else
  5378. {
  5379. CallMutex.Clear();
  5380. }
  5381. //
  5382. // The connection could be in a quiescent state
  5383. // we need to tickle it
  5384. //
  5385. Connection->ConnMutex.Request();
  5386. if (CurrentState == Complete)
  5387. {
  5388. Connection->ConnMutex.Clear();
  5389. // Status should already be RPC_S_OK
  5390. ASSERT(Status == RPC_S_OK);
  5391. goto Cleanup;
  5392. }
  5393. if (Connection->CurrentCall == this
  5394. && Connection->IsIdle())
  5395. {
  5396. Connection->MakeConnectionActive();
  5397. if ((Connection->fExclusive == FALSE)
  5398. && (BindingHandle->InqComTimeout() != RPC_C_BINDING_INFINITE_TIMEOUT))
  5399. {
  5400. // this is a best effort - ignore failure
  5401. (void)Connection->TurnOnOffKeepAlives(TRUE, // turn on
  5402. BindingHandle->InqComTimeout()
  5403. );
  5404. }
  5405. Connection->ConnMutex.Clear();
  5406. Status = SendData(0);
  5407. if (Status != RPC_S_OK)
  5408. {
  5409. //
  5410. // We didn't get a chance to submit a new send
  5411. // Remove the send reference CCALL--
  5412. //
  5413. OSF_CCALL::RemoveReference();
  5414. }
  5415. }
  5416. else
  5417. {
  5418. Connection->ConnMutex.Clear();
  5419. }
  5420. }
  5421. Cleanup:
  5422. if (Status)
  5423. {
  5424. ASSERT(Status != RPC_S_SEND_INCOMPLETE);
  5425. if (RemainingLength)
  5426. {
  5427. //
  5428. // NewBuffer should be initialized
  5429. //
  5430. FreeBufferDo(NewBuffer);
  5431. }
  5432. AsyncStatus = Status;
  5433. if (!fRegisterFailed)
  5434. {
  5435. UnregisterCallForCancels();
  5436. }
  5437. }
  5438. else
  5439. {
  5440. if (RemainingLength)
  5441. {
  5442. Message->Buffer = NewBuffer;
  5443. Message->BufferLength = RemainingLength;
  5444. ActualBufferLength = RemainingLength;
  5445. Status = RPC_S_SEND_INCOMPLETE;
  5446. }
  5447. else
  5448. {
  5449. ActualBufferLength = 0;
  5450. Message->Buffer = 0;
  5451. Message->BufferLength = 0;
  5452. }
  5453. //
  5454. // Call reference is removed in FreeBuffer
  5455. //
  5456. }
  5457. //
  5458. // Remove the reference for this send we added above, CCALL--
  5459. //
  5460. OSF_CCALL::RemoveReference();
  5461. return Status;
  5462. }
  5463. RPC_STATUS
  5464. OSF_CCALL::Send (
  5465. IN PRPC_MESSAGE Message
  5466. )
  5467. {
  5468. int i;
  5469. BOOL fFirstSend;
  5470. void *TempBuffer;
  5471. RPC_STATUS Status;
  5472. PRPC_ASYNC_STATE MypAsync = this->pAsync;
  5473. OSF_BINDING_HANDLE *MyBindingHandle = this->BindingHandle;
  5474. //
  5475. // WARNING: Do not use any members of OSF_CCALL beyond this point.
  5476. // the object could have been deleted.
  5477. //
  5478. for (i = 0;;i++)
  5479. {
  5480. Status = ((OSF_CCALL *) Message->Handle)->SendHelper(Message, &fFirstSend);
  5481. if (Status == RPC_S_OK)
  5482. {
  5483. if (!PARTIAL(Message) && MypAsync)
  5484. {
  5485. //
  5486. // Last send
  5487. //
  5488. ((OSF_CCALL *) Message->Handle)->CallMutex.Request();
  5489. ASSERT(((OSF_CCALL *) Message->Handle)->fLastSendComplete == 0);
  5490. if (((OSF_CCALL *) Message->Handle)->CurrentState == Aborted)
  5491. {
  5492. Status = ((OSF_CCALL *) Message->Handle)->GetCallStatus();
  5493. ((OSF_CCALL *) Message->Handle)->CallMutex.Clear();
  5494. //
  5495. // Remove the call reference, CCALL--
  5496. //
  5497. ((OSF_CCALL *) Message->Handle)->RemoveReference();
  5498. //
  5499. // No need to free the send buffer, it will be freed when the
  5500. // send is complete
  5501. //
  5502. }
  5503. else
  5504. {
  5505. //
  5506. // For any future failures, a notification is issued
  5507. //
  5508. ((OSF_CCALL *) Message->Handle)->fLastSendComplete = 1;
  5509. ((OSF_CCALL *) Message->Handle)->CallMutex.Clear();
  5510. }
  5511. }
  5512. return Status;
  5513. }
  5514. if (Status != RPC_S_CALL_FAILED_DNE || i > 0 || fFirstSend == 0)
  5515. {
  5516. if (Status != RPC_S_SEND_INCOMPLETE)
  5517. {
  5518. ((OSF_CCALL *) Message->Handle)->FreeBufferDo(Message->Buffer);
  5519. //
  5520. // Remove the call reference, CCALL--
  5521. //
  5522. ((OSF_CCALL *) Message->Handle)->RemoveReference();
  5523. }
  5524. return Status;
  5525. }
  5526. Status = AutoRetryCall(Message,
  5527. FALSE, // not in SendReceive path
  5528. MyBindingHandle,
  5529. Status,
  5530. MypAsync);
  5531. if (Status != RPC_S_OK)
  5532. break;
  5533. }
  5534. return Status;
  5535. }
  5536. RPC_STATUS
  5537. OSF_CCALL::AutoRetryCall (
  5538. IN OUT RPC_MESSAGE *Message,
  5539. IN BOOL fSendReceivePath,
  5540. IN OSF_BINDING_HANDLE *LocalBindingHandle,
  5541. IN RPC_STATUS CurrentStatus,
  5542. IN RPC_ASYNC_STATE *AsyncState OPTIONAL
  5543. )
  5544. /*++
  5545. Function Name:AutoRetryCall
  5546. Parameters:
  5547. Message - Contains information about the request
  5548. fSendReceivePath - TRUE if this is the send receive path, FALSE if it is the
  5549. Send path. We need to differentiate, because we do the cleanup of the old
  5550. call in slightly different ways
  5551. LocalBindingHandle - a local copy of the binding handle that was used to
  5552. make the original call
  5553. AsyncState - a pointer to the async state of the original call (if any)
  5554. Description:
  5555. Retries the current call. If the buffer is large, we allocate the new
  5556. call first, and copy the contents of the buffers directly. Otherwise,
  5557. we allocate the new call first, and then we copy directly from the old
  5558. call buffer to the new call buffer. This saves on double copying in the
  5559. large buffer case.
  5560. Returns:
  5561. --*/
  5562. {
  5563. void *TempBuffer;
  5564. RPC_STATUS Status;
  5565. UUID MyUuid;
  5566. UUID *UuidToUse;
  5567. BOOL fUuidSpecified;
  5568. OSF_CCALL *OldCall;
  5569. BOOL fLargeBuffer;
  5570. // any failure after this is unrelated
  5571. RpcpPurgeEEInfo();
  5572. OldCall = (OSF_CCALL *) Message->Handle;
  5573. // if the buffer is larger than 128K (absolutely arbitrary value),
  5574. // we'd rather open a new connection, than copy the buffer twice
  5575. fLargeBuffer = Message->BufferLength > (1 << 17);
  5576. ASSERT(OldCall->HeaderSize != 0);
  5577. fUuidSpecified = OldCall->UuidSpecified;
  5578. if (fUuidSpecified)
  5579. {
  5580. RpcpMemoryCopy(&MyUuid,
  5581. &(OldCall->ObjectUuid), sizeof(UUID));
  5582. }
  5583. if (fLargeBuffer)
  5584. {
  5585. TempBuffer = Message->Buffer;
  5586. }
  5587. else
  5588. {
  5589. TempBuffer = RpcpFarAllocate(Message->BufferLength);
  5590. if (TempBuffer != 0)
  5591. RpcpMemoryCopy(TempBuffer, Message->Buffer, Message->BufferLength);
  5592. OldCall->CleanupOldCallOnAutoRetry(Message->Buffer, fSendReceivePath, CurrentStatus);
  5593. if (TempBuffer == 0)
  5594. {
  5595. return RPC_S_OUT_OF_MEMORY;
  5596. }
  5597. }
  5598. Message->Handle = LocalBindingHandle;
  5599. UuidToUse = fUuidSpecified ? &MyUuid : 0;
  5600. Status = NegotiateTransferSyntaxAndGetBuffer(Message, UuidToUse);
  5601. if (Status != RPC_S_OK)
  5602. {
  5603. // the transfer syntax should not change in the async path for now - this
  5604. // indicates application error, and it's better to ASSERT here in checked
  5605. // builds, than leave the app writer bewildered on what has gone wrong if
  5606. // we just spew the error code back
  5607. if (!fSendReceivePath)
  5608. {
  5609. ASSERT(Status != RPC_P_TRANSFER_SYNTAX_CHANGED);
  5610. }
  5611. if (fLargeBuffer)
  5612. OldCall->CleanupOldCallOnAutoRetry(TempBuffer, fSendReceivePath, CurrentStatus);
  5613. else
  5614. RpcpFarFree(TempBuffer);
  5615. return Status;
  5616. }
  5617. if (AsyncState)
  5618. {
  5619. Status = I_RpcAsyncSetHandle(Message, AsyncState);
  5620. if (Status != RPC_S_OK)
  5621. {
  5622. if (fLargeBuffer)
  5623. OldCall->CleanupOldCallOnAutoRetry(TempBuffer, fSendReceivePath, CurrentStatus);
  5624. else
  5625. RpcpFarFree(TempBuffer);
  5626. return Status;
  5627. }
  5628. }
  5629. RpcpMemoryCopy(Message->Buffer, TempBuffer, Message->BufferLength);
  5630. if (fLargeBuffer)
  5631. OldCall->CleanupOldCallOnAutoRetry(TempBuffer, fSendReceivePath, CurrentStatus);
  5632. else
  5633. RpcpFarFree(TempBuffer);
  5634. return RPC_S_OK;
  5635. }
  5636. RPC_STATUS
  5637. OSF_CCALL::AsyncSend (
  5638. IN PRPC_MESSAGE Message
  5639. )
  5640. /*++
  5641. Function Name:AsyncSend
  5642. Parameters:
  5643. Message - Contains information about the request.
  5644. Description:
  5645. This function is used in conjunction with Async RPC. This function may
  5646. be used to send regular requests as well as pipe requests.
  5647. Returns:
  5648. --*/
  5649. {
  5650. return Send(Message);
  5651. }
  5652. RPC_STATUS
  5653. OSF_CCALL::Receive (
  5654. IN OUT PRPC_MESSAGE Message,
  5655. IN UINT Size
  5656. )
  5657. /*++
  5658. Function Name:Receive
  5659. Parameters:
  5660. Description:
  5661. This function is used in conjunction with synchronous pipes. It is used to receive
  5662. partial pipe data. If the RPC_BUFFER_EXTRA flag is set, the pipe data is
  5663. appended to the end of the current buffer. If it is not set, the pipe data is copied
  5664. from starting from the beginning of the buffer.
  5665. Returns:
  5666. --*/
  5667. {
  5668. RPC_STATUS Status = RPC_S_OK;
  5669. unsigned long OldFlags = IsExtraMessage(Message);
  5670. ASSERT(pAsync == 0);
  5671. if (!EXTRA(Message) && Message->Buffer)
  5672. {
  5673. ActuallyFreeBuffer((char *)Message->Buffer-sizeof(rpcconn_request));
  5674. Message->Buffer = 0;
  5675. }
  5676. while (TRUE)
  5677. {
  5678. switch (CurrentState)
  5679. {
  5680. case Complete:
  5681. Status = GetCoalescedBuffer(Message);
  5682. break;
  5683. case Aborted:
  5684. ASSERT(AsyncStatus != RPC_S_OK);
  5685. Status = AsyncStatus;
  5686. break;
  5687. default:
  5688. if (RcvBufferLength >= Connection->MaxFrag)
  5689. {
  5690. Status = GetCoalescedBuffer(Message);
  5691. if (Status != RPC_S_OK)
  5692. {
  5693. break;
  5694. }
  5695. if (PARTIAL(Message) && Message->BufferLength >= Size)
  5696. {
  5697. break;
  5698. }
  5699. Message->RpcFlags |= RPC_BUFFER_EXTRA;
  5700. }
  5701. else
  5702. {
  5703. //
  5704. // the call is not yet complete, wait for it.
  5705. //
  5706. SyncEvent.Wait();
  5707. }
  5708. continue;
  5709. }
  5710. break;
  5711. }
  5712. Message->DataRepresentation = Connection->Association->SavedDrep;
  5713. Message->RpcFlags &= ~(RPC_BUFFER_EXTRA);
  5714. Message->RpcFlags |= OldFlags;
  5715. if (Status != RPC_S_OK)
  5716. {
  5717. UnregisterCallForCancels();
  5718. AsyncStatus = Status;
  5719. // Remove the call reference, CCALL--
  5720. OSF_CCALL::RemoveReference();
  5721. }
  5722. return Status;
  5723. }
  5724. RPC_STATUS
  5725. OSF_CCALL::GetCoalescedBuffer (
  5726. IN PRPC_MESSAGE Message
  5727. )
  5728. /*++
  5729. Function Name:GetCoalescedBuffer
  5730. Parameters:
  5731. Message - the message structure that will receive the params
  5732. Description:
  5733. This routine will coalesce the buffers in the buffer queue into a single
  5734. buffer and return it in the Message structure. If the RPC_BUFFER_EXTRA
  5735. flag is set, the data is appended to the existing buffer in Message->Buffer.
  5736. Returns:
  5737. RPC_S_OK - the function was successful in doing its job
  5738. RPC_S_OUT_OF_MEMORY - ran out of memory.
  5739. --*/
  5740. {
  5741. char *Current;
  5742. PVOID NewBuffer, Buffer;
  5743. UINT bufferlength;
  5744. UINT TotalLength;
  5745. int Extra = IsExtraMessage(Message);
  5746. RPC_STATUS Status;
  5747. BOOL fSubmitReceive = 0;
  5748. CallMutex.Request();
  5749. if (RcvBufferLength == 0)
  5750. {
  5751. CallMutex.Clear();
  5752. if (!Extra)
  5753. {
  5754. ASSERT(CurrentState == Complete);
  5755. Message->Buffer = BufferQueue.TakeOffQueue(&bufferlength);
  5756. ASSERT(Message->Buffer);
  5757. ASSERT(bufferlength == 0);
  5758. Message->BufferLength = 0;
  5759. Message->RpcFlags |= RPC_BUFFER_COMPLETE;
  5760. CallStack--;
  5761. }
  5762. return RPC_S_OK;
  5763. }
  5764. if (Extra)
  5765. {
  5766. TotalLength = RcvBufferLength + Message->BufferLength;
  5767. }
  5768. else
  5769. {
  5770. TotalLength = RcvBufferLength;
  5771. }
  5772. Status = Connection->TransGetBuffer (
  5773. &NewBuffer,
  5774. TotalLength+sizeof(rpcconn_request));
  5775. if (Status != RPC_S_OK)
  5776. {
  5777. CallMutex.Clear();
  5778. return RPC_S_OUT_OF_MEMORY;
  5779. }
  5780. NewBuffer = (char *) NewBuffer+sizeof(rpcconn_request);
  5781. if (Extra && Message->Buffer)
  5782. {
  5783. RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength);
  5784. Current = (char *) NewBuffer + Message->BufferLength;
  5785. Connection->TransFreeBuffer(
  5786. (char *) Message->Buffer
  5787. -sizeof(rpcconn_request));
  5788. }
  5789. else
  5790. {
  5791. Current = (char *) NewBuffer;
  5792. }
  5793. while ((Buffer = BufferQueue.TakeOffQueue(&bufferlength)) != 0)
  5794. {
  5795. RpcpMemoryCopy(Current, Buffer, bufferlength);
  5796. Current += bufferlength;
  5797. Connection->TransFreeBuffer(
  5798. (char *) Buffer
  5799. -sizeof(rpcconn_request));
  5800. }
  5801. if (fPeerChoked)
  5802. {
  5803. fSubmitReceive = 1;
  5804. fPeerChoked = 0;
  5805. }
  5806. Message->Buffer = NewBuffer;
  5807. Message->BufferLength = TotalLength;
  5808. if (CurrentState == Complete)
  5809. {
  5810. Message->RpcFlags |= RPC_BUFFER_COMPLETE;
  5811. CallStack--;
  5812. }
  5813. RcvBufferLength = 0;
  5814. CallMutex.Clear();
  5815. if (fSubmitReceive)
  5816. {
  5817. Connection->TransAsyncReceive();
  5818. }
  5819. return RPC_S_OK;
  5820. }
  5821. RPC_STATUS
  5822. OSF_CCALL::AsyncReceive (
  5823. IN OUT PRPC_MESSAGE Message,
  5824. IN UINT Size
  5825. )
  5826. /*++
  5827. Function Name:AsyncReceive
  5828. Parameters:
  5829. Message - Contains information about the call
  5830. Size - This field is ignored on the client.
  5831. Description:
  5832. This is API is used to receive the non-pipe data in an async call. It this
  5833. function is called before the call is actually complete, an
  5834. RPC_S_ASYNC_CALL_PENDING is returned.
  5835. Returns:
  5836. --*/
  5837. {
  5838. RPC_STATUS Status;
  5839. if (!EXTRA(Message) && Message->Buffer)
  5840. {
  5841. ActuallyFreeBuffer((char *)Message->Buffer-sizeof(rpcconn_request));
  5842. Message->Buffer = 0;
  5843. Message->BufferLength = 0;
  5844. }
  5845. while (TRUE)
  5846. {
  5847. switch (CurrentState)
  5848. {
  5849. case Complete:
  5850. Status = GetCoalescedBuffer(Message);
  5851. break;
  5852. case Aborted:
  5853. Status = AsyncStatus;
  5854. break;
  5855. default:
  5856. if (PARTIAL(Message))
  5857. {
  5858. fDoFlowControl = 1;
  5859. CallMutex.Request();
  5860. if (RcvBufferLength < Size)
  5861. {
  5862. if (NOTIFY(Message))
  5863. {
  5864. NeededLength = Size;
  5865. }
  5866. CallMutex.Clear();
  5867. return RPC_S_ASYNC_CALL_PENDING;
  5868. }
  5869. else
  5870. {
  5871. Status = GetCoalescedBuffer(Message);
  5872. }
  5873. CallMutex.Clear();
  5874. }
  5875. else
  5876. {
  5877. return RPC_S_ASYNC_CALL_PENDING;
  5878. }
  5879. break;
  5880. }
  5881. break;
  5882. }
  5883. Message->DataRepresentation = Connection->Association->SavedDrep;
  5884. if (Status != RPC_S_OK)
  5885. {
  5886. //
  5887. // FreeBuffer is not going to be called. Cleanup now..
  5888. //
  5889. AsyncStatus = Status;
  5890. // remove the call reference, CCALL--
  5891. OSF_CCALL::RemoveReference();
  5892. }
  5893. return Status;
  5894. }
  5895. RPC_STATUS
  5896. OSF_CCALL::ReceiveReply (
  5897. IN rpcconn_request *Request,
  5898. IN PRPC_MESSAGE Message
  5899. )
  5900. /*++
  5901. Function Name:ReceiveReply
  5902. Parameters:
  5903. Description:
  5904. Helper function to receive the complete reply. The reply may either be a
  5905. callback, or a response.
  5906. Returns:
  5907. --*/
  5908. {
  5909. int BytesRead;
  5910. PVOID NewBuffer;
  5911. RPC_STATUS Status;
  5912. UINT BytesRemaining;
  5913. RPC_MESSAGE NewMessage;
  5914. UINT NewBufferLength;
  5915. int AllocHint = Request->alloc_hint;
  5916. ULONG Timeout;
  5917. //
  5918. // Allocate a buffer, big enough to hold the non pipe data.
  5919. // All the non pipe data will go into the first buffer, all other fragments
  5920. // will go as separate buffers in the received buffer queue
  5921. //
  5922. if (AllocHint)
  5923. {
  5924. Status = Connection->TransGetBuffer(
  5925. &NewBuffer,
  5926. AllocHint+sizeof(rpcconn_request));
  5927. if (Status != RPC_S_OK)
  5928. {
  5929. Connection->TransFreeBuffer(Request);
  5930. return Status;
  5931. }
  5932. NewBuffer = (char *) NewBuffer+sizeof(rpcconn_request);
  5933. RpcpMemoryCopy(NewBuffer, Message->Buffer, Message->BufferLength);
  5934. Connection->TransFreeBuffer(Request);
  5935. Message->Buffer = NewBuffer;
  5936. BytesRemaining = AllocHint - Message->BufferLength;
  5937. }
  5938. else
  5939. {
  5940. BytesRemaining = 0;
  5941. }
  5942. BytesRead = Message->BufferLength;
  5943. NewMessage.RpcFlags = Message->RpcFlags;
  5944. Timeout = GetBindingHandleTimeout(BindingHandle);
  5945. //
  5946. // Receive the complete data
  5947. //
  5948. while (!COMPLETE(&NewMessage))
  5949. {
  5950. Status = Connection->TransReceive(
  5951. &NewBuffer,
  5952. &NewBufferLength,
  5953. Timeout);
  5954. if (Status != RPC_S_OK)
  5955. {
  5956. Connection->TransFreeBuffer((char *) Message->Buffer-sizeof(rpcconn_request));
  5957. if ((Status == RPC_P_RECEIVE_FAILED)
  5958. || (Status == RPC_P_CONNECTION_CLOSED)
  5959. || (Status == RPC_P_CONNECTION_SHUTDOWN))
  5960. {
  5961. RpcpErrorAddRecord(EEInfoGCRuntime,
  5962. RPC_S_CALL_FAILED,
  5963. EEInfoDLOSF_CCALL__ReceiveReply10,
  5964. Status);
  5965. return(RPC_S_CALL_FAILED);
  5966. }
  5967. if (Status == RPC_P_TIMEOUT)
  5968. {
  5969. RpcpErrorAddRecord(EEInfoGCRuntime,
  5970. RPC_S_CALL_CANCELLED,
  5971. EEInfoDLOSF_CCALL__ReceiveReply20,
  5972. (ULONG)Status,
  5973. (ULONG)Timeout);
  5974. return RPC_S_CALL_CANCELLED;
  5975. }
  5976. return Status;
  5977. }
  5978. Status = ActuallyProcessPDU(
  5979. (rpcconn_common *) NewBuffer,
  5980. NewBufferLength,
  5981. &NewMessage);
  5982. if (Status != RPC_S_OK)
  5983. {
  5984. Connection->TransFreeBuffer((char *) Message->Buffer-sizeof(rpcconn_request));
  5985. return Status;
  5986. }
  5987. if (BytesRemaining < NewMessage.BufferLength)
  5988. {
  5989. //
  5990. // This code path is taken only in the OSF interop case
  5991. //
  5992. Message->Buffer = (char *) Message->Buffer - sizeof(rpcconn_request);
  5993. Status = Connection->TransReallocBuffer(
  5994. &Message->Buffer,
  5995. BytesRead+sizeof(rpcconn_request),
  5996. BytesRead
  5997. +NewMessage.BufferLength
  5998. +sizeof(rpcconn_request));
  5999. if (Status != RPC_S_OK)
  6000. {
  6001. Connection->TransFreeBuffer((char *) Message->Buffer-sizeof(rpcconn_request));
  6002. return Status;
  6003. }
  6004. Message->Buffer = (char *) Message->Buffer + sizeof(rpcconn_request);
  6005. BytesRemaining = NewMessage.BufferLength;
  6006. }
  6007. RpcpMemoryCopy((char *) Message->Buffer+BytesRead,
  6008. NewMessage.Buffer,
  6009. NewMessage.BufferLength);
  6010. Connection->TransFreeBuffer(NewBuffer);
  6011. BytesRead += NewMessage.BufferLength;
  6012. BytesRemaining -= NewMessage.BufferLength;
  6013. }
  6014. ASSERT(BytesRemaining == 0);
  6015. Message->BufferLength = BytesRead;
  6016. Message->RpcFlags = RPC_BUFFER_COMPLETE;
  6017. return RPC_S_OK;
  6018. }
  6019. RPC_STATUS
  6020. OSF_CCALL::DealWithCallback (
  6021. IN rpcconn_request *Request,
  6022. IN PRPC_MESSAGE Message
  6023. )
  6024. /*++
  6025. Function Name:DealWithCallback
  6026. Parameters:
  6027. Description:
  6028. Returns:
  6029. --*/
  6030. {
  6031. RPC_STATUS Status, ExceptionCode;
  6032. void *OriginalBuffer ;
  6033. ASSERT(CurrentState == InCallbackRequest);
  6034. if (CallStack == 1)
  6035. {
  6036. BindingHandle->AddRecursiveEntry(this,
  6037. (RPC_CLIENT_INTERFACE *)
  6038. Message->RpcInterfaceInformation);
  6039. }
  6040. #ifdef DEBUGRPC
  6041. EnterCallback();
  6042. #endif
  6043. if (!COMPLETE(Message))
  6044. {
  6045. ASSERT(Request);
  6046. ASSERT(Request->common.PTYPE == rpc_request);
  6047. //
  6048. // Receive the complete reply
  6049. //
  6050. Status = ReceiveReply(Request, Message);
  6051. if (Status != RPC_S_OK)
  6052. {
  6053. return Status;
  6054. }
  6055. }
  6056. ASSERT(COMPLETE(Message));
  6057. CurrentState = SendingFirstBuffer;
  6058. OriginalBuffer = Message->Buffer;
  6059. //
  6060. // Dispatch the callback
  6061. //
  6062. Status = DispatchCallback(
  6063. DispatchTableCallback,
  6064. Message,
  6065. &ExceptionCode);
  6066. #ifdef DEBUGRPC
  6067. ExitCallback();
  6068. #endif
  6069. ActuallyFreeBuffer((char *) OriginalBuffer-sizeof(rpcconn_request));
  6070. if ( Status != RPC_S_OK )
  6071. {
  6072. VALIDATE(Status)
  6073. {
  6074. RPC_P_EXCEPTION_OCCURED,
  6075. RPC_S_PROCNUM_OUT_OF_RANGE
  6076. } END_VALIDATE;
  6077. if (Status == RPC_S_PROCNUM_OUT_OF_RANGE)
  6078. {
  6079. SendFault(RPC_S_PROCNUM_OUT_OF_RANGE, 0);
  6080. }
  6081. else
  6082. {
  6083. SendFault(ExceptionCode, 0);
  6084. Status = ExceptionCode;
  6085. }
  6086. RpcpPurgeEEInfo();
  6087. return Status;
  6088. }
  6089. CurrentState = InCallbackReply;
  6090. CurrentOffset = 0;
  6091. CurrentBuffer = Message->Buffer;
  6092. CurrentBufferLength = Message->BufferLength;
  6093. LastBuffer = Message->Buffer;
  6094. Status = SendNextFragment(rpc_response);
  6095. ASSERT(Connection->fExclusive);
  6096. if (Connection->fExclusive)
  6097. {
  6098. if (Status != RPC_S_OK || (CurrentBufferLength == 0))
  6099. {
  6100. goto Cleanup;
  6101. }
  6102. while (CurrentBufferLength)
  6103. {
  6104. Status = SendNextFragment(rpc_response, FALSE);
  6105. if (Status != RPC_S_OK)
  6106. {
  6107. break;
  6108. }
  6109. }
  6110. Cleanup:
  6111. if (CallStack == 1)
  6112. {
  6113. BindingHandle->RemoveRecursiveCall(this);
  6114. }
  6115. FreeBufferDo(Message->Buffer);
  6116. }
  6117. else
  6118. {
  6119. //
  6120. // Callbacks not allowed in the async or in pipes
  6121. //
  6122. Status = RPC_S_CALL_FAILED;
  6123. }
  6124. return Status;
  6125. }
  6126. RPC_STATUS
  6127. OSF_CCALL::FastSendReceive (
  6128. IN OUT PRPC_MESSAGE Message,
  6129. OUT BOOL *fRetry
  6130. )
  6131. /*++
  6132. Function Name:FastSendReceive
  6133. Parameters:
  6134. Description:
  6135. Returns:
  6136. --*/
  6137. {
  6138. RPC_STATUS Status;
  6139. UINT BufferLength;
  6140. rpcconn_common *Request;
  6141. DebugClientCallInfo *ClientCallInfo;
  6142. DebugCallTargetInfo *CallTargetInfo;
  6143. CellTag ClientCallInfoCellTag;
  6144. CellTag CallTargetInfoCellTag;
  6145. THREAD *ThisThread = RpcpGetThreadPointer();
  6146. BOOL fDebugInfoSet = FALSE;
  6147. ULONG Timeout;
  6148. CurrentOffset = 0;
  6149. CurrentBuffer = Message->Buffer;
  6150. CurrentBufferLength = Message->BufferLength;
  6151. Message->RpcFlags = 0;
  6152. ASSERT(ThisThread);
  6153. // if either client side debugging is enabled or we are
  6154. // calling on a thread that has a scall dispatched
  6155. if (IsClientSideDebugInfoEnabled() || ((ThisThread->Context) && IsServerSideDebugInfoEnabled()))
  6156. {
  6157. CStackAnsi AnsiString;
  6158. RPC_CHAR *Endpoint;
  6159. RPC_CHAR *NetworkAddress;
  6160. int EndpointLength;
  6161. int NetworkAddressLength;
  6162. if (!IsClientSideDebugInfoEnabled())
  6163. {
  6164. Status = SetDebugClientCallInformation(&ClientCallInfo, &ClientCallInfoCellTag,
  6165. &CallTargetInfo, &CallTargetInfoCellTag, Message, ThisThread->DebugCell,
  6166. ThisThread->DebugCellTag);
  6167. }
  6168. else
  6169. {
  6170. Status = SetDebugClientCallInformation(&ClientCallInfo, &ClientCallInfoCellTag,
  6171. &CallTargetInfo, &CallTargetInfoCellTag, Message, NULL, NULL);
  6172. }
  6173. if (Status != RPC_S_OK)
  6174. return Status;
  6175. ClientCallInfo->CallID = CallId;
  6176. Endpoint = Connection->InqEndpoint();
  6177. NetworkAddress = Connection->InqNetworkAddress();
  6178. EndpointLength = RpcpStringLength(Endpoint) + 1;
  6179. NetworkAddressLength = RpcpStringLength(NetworkAddress) + 1;
  6180. *(AnsiString.GetPAnsiString()) = (char *)_alloca(max(EndpointLength, NetworkAddressLength));
  6181. Status = AnsiString.Attach(Endpoint, EndpointLength, EndpointLength * 2);
  6182. // effectively ignore failure in the conversion
  6183. if (Status == RPC_S_OK)
  6184. {
  6185. strncpy(ClientCallInfo->Endpoint, AnsiString, sizeof(ClientCallInfo->Endpoint));
  6186. }
  6187. CallTargetInfo->ProtocolSequence = Connection->ClientInfo->TransId;
  6188. Status = AnsiString.Attach(NetworkAddress, NetworkAddressLength, NetworkAddressLength * 2);
  6189. if (Status == RPC_S_OK)
  6190. {
  6191. strncpy(CallTargetInfo->TargetServer, AnsiString, sizeof(CallTargetInfo->TargetServer));
  6192. }
  6193. fDebugInfoSet = TRUE;
  6194. }
  6195. Status = SendNextFragment(rpc_request, TRUE, (void **) &Request, &BufferLength) ;
  6196. if (Status != RPC_S_OK)
  6197. {
  6198. goto Cleanup;
  6199. }
  6200. *fRetry = FALSE;
  6201. while (CurrentBufferLength)
  6202. {
  6203. Status = SendNextFragment(rpc_request, FALSE, (void **) &Request, &BufferLength);
  6204. if (Status != RPC_S_OK)
  6205. {
  6206. goto Cleanup;
  6207. }
  6208. }
  6209. //
  6210. // We have sent the complete request. It is time to start
  6211. // receiving the reply. The reply could either be a response
  6212. // or a callback
  6213. //
  6214. CurrentState = WaitingForReply;
  6215. while (1)
  6216. {
  6217. //
  6218. // This is the only place where we can receive a callback PDU
  6219. //
  6220. Status = ActuallyProcessPDU(
  6221. Request,
  6222. BufferLength,
  6223. Message);
  6224. if (Status != RPC_S_OK)
  6225. {
  6226. goto Cleanup;
  6227. }
  6228. VALIDATE(Request->PTYPE)
  6229. {
  6230. rpc_request,
  6231. rpc_response,
  6232. rpc_shutdown
  6233. } END_VALIDATE;
  6234. switch (Request->PTYPE)
  6235. {
  6236. case rpc_request:
  6237. Status = DealWithCallback(
  6238. (rpcconn_request *) Request,
  6239. Message);
  6240. Message->RpcFlags = 0;
  6241. break;
  6242. case rpc_response:
  6243. if (!COMPLETE(Message))
  6244. {
  6245. Status = ReceiveReply(
  6246. (rpcconn_request *) Request,
  6247. Message);
  6248. }
  6249. goto Cleanup;
  6250. default:
  6251. // ignore the pdu
  6252. break;
  6253. }
  6254. Timeout = GetBindingHandleTimeout(BindingHandle);
  6255. Status = Connection->TransReceive(
  6256. (PVOID *) &Request,
  6257. &BufferLength,
  6258. Timeout);
  6259. if (Status != RPC_S_OK)
  6260. {
  6261. if ((Status == RPC_P_RECEIVE_FAILED )
  6262. || ( Status == RPC_P_CONNECTION_CLOSED ) )
  6263. {
  6264. RpcpErrorAddRecord(EEInfoGCRuntime,
  6265. RPC_S_CALL_FAILED_DNE,
  6266. EEInfoDLOSF_CCALL__FastSendReceive10,
  6267. Status);
  6268. Status = RPC_S_CALL_FAILED;
  6269. }
  6270. else if (Status == RPC_P_CONNECTION_SHUTDOWN)
  6271. {
  6272. RpcpErrorAddRecord(EEInfoGCRuntime,
  6273. RPC_S_CALL_FAILED_DNE,
  6274. EEInfoDLOSF_CCALL__FastSendReceive20,
  6275. Status);
  6276. Status = RPC_S_CALL_FAILED_DNE;
  6277. }
  6278. else if (Status == RPC_P_TIMEOUT)
  6279. {
  6280. Status = RPC_S_CALL_CANCELLED;
  6281. RpcpErrorAddRecord(EEInfoGCRuntime,
  6282. Status,
  6283. EEInfoDLOSF_CCALL__FastSendReceive30,
  6284. RPC_P_TIMEOUT,
  6285. Timeout);
  6286. }
  6287. goto Cleanup;
  6288. }
  6289. }
  6290. Cleanup:
  6291. if (fDebugInfoSet)
  6292. {
  6293. FreeCell(CallTargetInfo, &CallTargetInfoCellTag);
  6294. FreeCell(ClientCallInfo, &ClientCallInfoCellTag);
  6295. }
  6296. return Status;
  6297. }
  6298. void
  6299. OSF_CCALL::CallFailed (
  6300. IN RPC_STATUS Status
  6301. )
  6302. /*++
  6303. Function Name:
  6304. Parameters:
  6305. Description:
  6306. Returns:
  6307. --*/
  6308. {
  6309. ExtendedErrorInfo * pThreadEEInfo;
  6310. CallMutex.Request();
  6311. //
  6312. // Should not transition from Complete -> Aborted
  6313. //
  6314. if (CurrentState != Complete
  6315. && CurrentState != Aborted)
  6316. {
  6317. //
  6318. // Notify the client that the call is complete. When the stub calls
  6319. // I_RpcReceive, we can cleanup the call and return a failure
  6320. // status.
  6321. //
  6322. AsyncStatus = Status;
  6323. CurrentState = Aborted;
  6324. //
  6325. // If the last send is complete, then we need to issue the notification so
  6326. // that I_RpcReceive is called. If the last send is not complete, we don't need
  6327. // to issue the notification because
  6328. if (pAsync)
  6329. {
  6330. if (EEInfo)
  6331. {
  6332. FreeEEInfoChain(EEInfo);
  6333. EEInfo = NULL;
  6334. }
  6335. pThreadEEInfo = RpcpGetEEInfo();
  6336. if (pThreadEEInfo)
  6337. {
  6338. EEInfo = pThreadEEInfo;
  6339. RpcpClearEEInfo();
  6340. }
  6341. if (fLastSendComplete)
  6342. {
  6343. IssueNotification();
  6344. }
  6345. }
  6346. else
  6347. {
  6348. SyncEvent.Raise();
  6349. }
  6350. }
  6351. CallMutex.Clear();
  6352. }
  6353. RPC_STATUS
  6354. OSF_CCALL::CallCancelled (
  6355. OUT PDWORD Timeout
  6356. )
  6357. /*++
  6358. Function Name:CallCancelled
  6359. Parameters:
  6360. Description:
  6361. This function is called via the connection whenever the transport interface
  6362. notices that it has received an alert. This function should only be used in conjuction
  6363. with sync non pipe calls.
  6364. Returns:
  6365. RPC_S_OK: The call was cancelled
  6366. others - if a failure occured.
  6367. --*/
  6368. {
  6369. RPC_STATUS Status;
  6370. if (CurrentState == NeedOpenAndBind)
  6371. {
  6372. *Timeout = 0;
  6373. return RPC_S_OK;
  6374. }
  6375. if (fCallCancelled == 0)
  6376. {
  6377. return RPC_S_NO_CALL_ACTIVE;
  6378. }
  6379. Status = SendCancelPDU();
  6380. //
  6381. // Ignore the return status
  6382. //
  6383. *Timeout = (DWORD) ThreadGetRpcCancelTimeout();
  6384. return Status;
  6385. }
  6386. inline RPC_STATUS
  6387. OSF_CCALL::SendReceiveHelper (
  6388. IN OUT PRPC_MESSAGE Message,
  6389. OUT BOOL *fRetry
  6390. )
  6391. /*++
  6392. Function Name:SendReceive
  6393. Parameters:
  6394. Description:
  6395. Returns:
  6396. --*/
  6397. {
  6398. RPC_STATUS Status;
  6399. THREAD *ThreadInfo;
  6400. CallStack++;
  6401. ASSERT(!PARTIAL(Message) && !ASYNC(Message));
  6402. ThreadInfo = RpcpGetThreadPointer();
  6403. ASSERT(ThreadInfo);
  6404. if (CallStack == 1)
  6405. {
  6406. Status = ThreadInfo->RegisterForCancels(this);
  6407. if (Status != RPC_S_OK)
  6408. {
  6409. return Status;
  6410. }
  6411. }
  6412. if (ThreadInfo->CancelTimeout == RPC_C_CANCEL_INFINITE_TIMEOUT)
  6413. {
  6414. CancelState = CANCEL_INFINITE;
  6415. }
  6416. else
  6417. {
  6418. CancelState = CANCEL_NOTINFINITE;
  6419. }
  6420. LastBuffer = Message->Buffer;
  6421. ASSERT (Connection->fExclusive);
  6422. ASSERT(CurrentState == SendingFirstBuffer);
  6423. Status = FastSendReceive(Message, fRetry);
  6424. if (CallStack == 1)
  6425. {
  6426. ThreadInfo->UnregisterForCancels();
  6427. }
  6428. CallStack--;
  6429. if (Status == RPC_S_OK
  6430. && CallStack == 0)
  6431. {
  6432. RPC_SECURITY_CALLBACK_FN *SecurityCallback = NULL;
  6433. CurrentState = Complete;
  6434. Status = BindingHandle->InqTransportOption(
  6435. RPC_C_OPT_SECURITY_CALLBACK,
  6436. (ULONG_PTR *) &SecurityCallback);
  6437. ASSERT(Status == RPC_S_OK);
  6438. if (SecurityCallback)
  6439. {
  6440. (*SecurityCallback) (this);
  6441. }
  6442. }
  6443. return Status;
  6444. }
  6445. RPC_STATUS
  6446. OSF_CCALL::SendReceive (
  6447. IN OUT PRPC_MESSAGE Message
  6448. )
  6449. /*++
  6450. Function Name:SendReceive
  6451. Parameters:
  6452. Description:
  6453. Returns:
  6454. --*/
  6455. {
  6456. RPC_STATUS Status;
  6457. void *TempBuffer ;
  6458. OSF_BINDING_HANDLE *MyBindingHandle;
  6459. void *OriginalBuffer;
  6460. BOOL fRetry = TRUE;
  6461. int RetryAttempts = 0;
  6462. OSF_CCONNECTION *LocalConnection;
  6463. AssocDictMutex->VerifyNotOwned();
  6464. MyBindingHandle = BindingHandle;
  6465. //
  6466. // WARNING: Do not use any members of OSF_CCALL beyond this point.
  6467. // the object could have been deleted.
  6468. //
  6469. while (RetryAttempts <= 5)
  6470. {
  6471. OriginalBuffer = Message->Buffer;
  6472. Status = ((OSF_CCALL *) Message->Handle)->SendReceiveHelper(Message, &fRetry);
  6473. if (Status == RPC_S_OK || ((OSF_CCALL *) Message->Handle)->CallStack > 0)
  6474. {
  6475. ((OSF_CCALL *) Message->Handle)->FreeBufferDo(OriginalBuffer);
  6476. break;
  6477. }
  6478. else
  6479. {
  6480. ASSERT(Status != RPC_S_SEND_INCOMPLETE);
  6481. ASSERT(((OSF_CCALL *) Message->Handle)->CallStack == 0);
  6482. if (Status == RPC_P_CONNECTION_SHUTDOWN)
  6483. {
  6484. Status = RPC_S_CALL_FAILED_DNE;
  6485. }
  6486. LocalConnection = ((OSF_CCALL *) Message->Handle)->Connection;
  6487. if (fRetry == FALSE
  6488. || (Status != RPC_S_CALL_FAILED_DNE)
  6489. || (LocalConnection->ClientSecurityContext.AuthenticationLevel
  6490. == RPC_C_AUTHN_LEVEL_PKT_PRIVACY))
  6491. {
  6492. ((OSF_CCALL *) Message->Handle)->FreeBufferDo(OriginalBuffer);
  6493. ((OSF_CCALL *) Message->Handle)->FreeCCall(Status);
  6494. LogEvent(SU_CCALL, EV_DELETE, Message->Handle, 0, Status, 1, 1);
  6495. break;
  6496. }
  6497. }
  6498. if (!LocalConnection->GetFreshFromCacheFlag())
  6499. {
  6500. // count this as a retry attempt only if the
  6501. // connection was not from the cache
  6502. RetryAttempts ++;
  6503. }
  6504. Status = AutoRetryCall(Message,
  6505. TRUE, // this is the SendReceive path
  6506. MyBindingHandle,
  6507. Status,
  6508. 0);
  6509. if (Status != RPC_S_OK)
  6510. break;
  6511. if (RetryAttempts > 5)
  6512. Status = RPC_S_CALL_FAILED_DNE;
  6513. }
  6514. return Status;
  6515. }
  6516. RPC_STATUS
  6517. OSF_CCALL::ProcessRequestOrResponse (
  6518. IN rpcconn_request *Request,
  6519. IN UINT PacketLength,
  6520. IN BOOL fRequest,
  6521. IN OUT PRPC_MESSAGE Message
  6522. )
  6523. /*++
  6524. Function Name:ProcessRequestOrResponse
  6525. Parameters:
  6526. fRequest - If true, this is a request. Otherwise, it is a response
  6527. Description:
  6528. This function is called by ActuallyProcessPDU
  6529. Returns:
  6530. --*/
  6531. {
  6532. RPC_STATUS Status;
  6533. if ((Request->common.pfc_flags & PFC_OBJECT_UUID) != 0)
  6534. {
  6535. ASSERT(0);
  6536. return RPC_S_PROTOCOL_ERROR;
  6537. }
  6538. if ((Request->common.pfc_flags & PFC_FIRST_FRAG))
  6539. {
  6540. InReply = 1;
  6541. ASSERT(BufferQueue.IsQueueEmpty());
  6542. Message->DataRepresentation = Connection->Association->SavedDrep;
  6543. //
  6544. // Transition to the next state
  6545. //
  6546. if (fRequest)
  6547. {
  6548. CurrentState = InCallbackRequest;
  6549. }
  6550. else
  6551. {
  6552. CurrentState = Receiving;
  6553. }
  6554. }
  6555. else
  6556. {
  6557. if (CurrentState == WaitingForReply)
  6558. {
  6559. ASSERT(0);
  6560. return RPC_S_PROTOCOL_ERROR;
  6561. }
  6562. }
  6563. if ((Request->common.pfc_flags & PFC_LAST_FRAG) != 0)
  6564. {
  6565. Message->RpcFlags |= RPC_BUFFER_COMPLETE;
  6566. }
  6567. Status = EatAuthInfoFromPacket(
  6568. Request,
  6569. &PacketLength);
  6570. if (Status != RPC_S_OK)
  6571. {
  6572. return Status;
  6573. }
  6574. Message->BufferLength = PacketLength - sizeof(rpcconn_request);
  6575. Message->Buffer = (void *) (Request + 1);
  6576. return RPC_S_OK;
  6577. }
  6578. RPC_STATUS
  6579. OSF_CCALL::ActuallyProcessPDU (
  6580. IN rpcconn_common *Packet,
  6581. IN UINT PacketLength,
  6582. IN OUT PRPC_MESSAGE Message,
  6583. IN BOOL fAsync,
  6584. OUT BOOL *pfSubmitReceive
  6585. )
  6586. /*++
  6587. Function Name:ActuallyProcessPDU
  6588. Parameters:
  6589. Description:
  6590. Returns:
  6591. --*/
  6592. {
  6593. RPC_STATUS Status = RPC_S_OK;
  6594. ULONG FaultStatus;
  6595. BOOL AlterContextToNDR20IfNDR64Negotiated;
  6596. //
  6597. // If there is security save the rpc header
  6598. //
  6599. if (Connection->ClientSecurityContext.AuthenticationLevel != RPC_C_AUTHN_LEVEL_NONE )
  6600. {
  6601. CallMutex.Request();
  6602. if (SavedHeader == 0)
  6603. {
  6604. SavedHeader = RpcpFarAllocate(sizeof(rpcconn_response));
  6605. if (SavedHeader == 0)
  6606. {
  6607. CallMutex.Clear();
  6608. Status = RPC_S_OUT_OF_MEMORY;
  6609. goto Cleanup;
  6610. }
  6611. SavedHeaderSize = sizeof(rpcconn_response);
  6612. }
  6613. CallMutex.Clear();
  6614. RpcpMemoryCopy(
  6615. SavedHeader,
  6616. Packet,
  6617. sizeof(rpcconn_response));
  6618. }
  6619. Status = ValidatePacket(Packet, PacketLength);
  6620. if (Status != RPC_S_OK)
  6621. {
  6622. goto Cleanup;
  6623. }
  6624. switch (Packet->PTYPE)
  6625. {
  6626. case rpc_response:
  6627. Status = ProcessRequestOrResponse(
  6628. (rpcconn_request *) Packet,
  6629. PacketLength,
  6630. 0,
  6631. Message);
  6632. if (Status != RPC_S_OK)
  6633. {
  6634. goto Cleanup;
  6635. }
  6636. if (fAsync)
  6637. {
  6638. Status = ProcessResponse((rpcconn_response *) Packet,
  6639. Message, pfSubmitReceive);
  6640. }
  6641. break;
  6642. case rpc_alter_context_resp:
  6643. if (CurrentState != WaitingForAlterContext)
  6644. {
  6645. ASSERT(0);
  6646. Status = RPC_S_PROTOCOL_ERROR;
  6647. goto Cleanup;
  6648. }
  6649. // if we have chosen NDR20 in the call, we must warn the DealWithAlterContextResp
  6650. // to alter context once more to NDR20 if NDR64 was chosen by the server
  6651. if (Bindings.AvailableBindingsList
  6652. && Bindings.SelectedBinding
  6653. && (Bindings.SelectedBinding->CompareWithTransferSyntax(NDR20TransferSyntax) == 0))
  6654. {
  6655. AlterContextToNDR20IfNDR64Negotiated = TRUE;
  6656. }
  6657. else
  6658. {
  6659. AlterContextToNDR20IfNDR64Negotiated = FALSE;
  6660. }
  6661. Status = Connection->DealWithAlterContextResp(
  6662. this,
  6663. Packet,
  6664. PacketLength,
  6665. &AlterContextToNDR20IfNDR64Negotiated);
  6666. ActuallyFreeBuffer(Packet);
  6667. if (Status != RPC_S_OK)
  6668. {
  6669. return Status;
  6670. }
  6671. // if we sent another alter context, return and wait for the response
  6672. if (AlterContextToNDR20IfNDR64Negotiated)
  6673. return RPC_S_OK;
  6674. //
  6675. // Wait for the send to complete
  6676. //
  6677. Connection->WaitForSend();
  6678. //
  6679. // We sent the alter-context PDU when it was our turn,
  6680. // now that we have received a response, we need to get
  6681. // the ball rolling.
  6682. //
  6683. CurrentState = SendingFirstBuffer;
  6684. ASSERT(Connection->IsIdle() == 0);
  6685. CallMutex.Request();
  6686. if (CurrentBuffer)
  6687. {
  6688. CallMutex.Clear();
  6689. Status = SendNextFragment();
  6690. }
  6691. else
  6692. {
  6693. //
  6694. // We don't have a buffer to send from this call, we will force
  6695. // the connection to idle and wait for the this call to give us
  6696. // its buffer. The send function will notice that the connection is
  6697. // idle, and send its first data buffer.
  6698. //
  6699. Connection->MakeConnectionIdle();
  6700. CallMutex.Clear();
  6701. ASSERT(Status == RPC_S_OK);
  6702. }
  6703. return Status;
  6704. case rpc_request:
  6705. //
  6706. // if we are going to reuse this function to handle
  6707. // sync SendReceive, we need to keep track of this
  6708. // and puke on the other cases (ie: when using Async
  6709. // and when using pipes).
  6710. //
  6711. if (fAsync)
  6712. {
  6713. SendFault(RPC_S_CALL_FAILED, 0);
  6714. Status = RPC_S_CALL_FAILED;
  6715. goto Cleanup;
  6716. }
  6717. if ( Packet->call_id != CallId )
  6718. {
  6719. ASSERT(0);
  6720. Status = RPC_S_PROTOCOL_ERROR;
  6721. goto Cleanup;
  6722. }
  6723. if (((rpcconn_request *) Packet)->p_cont_id
  6724. != GetSelectedBinding()->GetOnTheWirePresentationContext() )
  6725. {
  6726. SendFault(RPC_S_UNKNOWN_IF, 0);
  6727. Status = RPC_S_UNKNOWN_IF;
  6728. goto Cleanup;
  6729. }
  6730. Status = ProcessRequestOrResponse(
  6731. (rpcconn_request *) Packet,
  6732. PacketLength,
  6733. 1,
  6734. Message);
  6735. if (Status != RPC_S_OK)
  6736. {
  6737. goto Cleanup;
  6738. }
  6739. Message->ProcNum = ((rpcconn_request *) Packet)->opnum;
  6740. break;
  6741. case rpc_fault:
  6742. FaultStatus = ((rpcconn_fault *) Packet)->status;
  6743. if ((FaultStatus == 0)
  6744. && (Packet->frag_length >= FaultSizeWithoutEEInfo + 4))
  6745. {
  6746. //
  6747. // DCE 1.0.x style fault status:
  6748. // Zero status and stub data contains the fault.
  6749. //
  6750. FaultStatus = *(ULONG *) ((unsigned char *)Packet + FaultSizeWithoutEEInfo);
  6751. }
  6752. if (DataConvertEndian(Packet->drep) != 0)
  6753. {
  6754. FaultStatus = RpcpByteSwapLong(FaultStatus);
  6755. }
  6756. ASSERT(FaultStatus != 0);
  6757. Status = MapFromNcaStatusCode(FaultStatus);
  6758. ASSERT(Status != RPC_S_OK);
  6759. if (((rpcconn_fault *) Packet)->reserved & FaultEEInfoPresent)
  6760. {
  6761. ExtendedErrorInfo *EEInfo;
  6762. UnpickleEEInfoFromBuffer(((rpcconn_fault *) Packet)->buffer,
  6763. GetEEInfoSizeFromFaultPacket((rpcconn_fault *) Packet));
  6764. EEInfo = RpcpGetEEInfo();
  6765. if (EEInfo && pAsync)
  6766. {
  6767. ASSERT(this->EEInfo == NULL);
  6768. // move the eeinfo to the call. Even though it is possible
  6769. // that the call will be completed on this thread, it is
  6770. // still ok, as we will move it back during completion
  6771. this->EEInfo = EEInfo;
  6772. RpcpClearEEInfo();
  6773. }
  6774. }
  6775. //
  6776. // In 3.5 we didnt Sign/Seal Faults. So .. Unsign/UnSeal doesnt
  6777. // get called and hence Client side and Server side Seq# are
  6778. // out of Sync.. So cheat ..
  6779. //
  6780. Connection->IncReceiveSequenceNumber();
  6781. if (fAsync)
  6782. {
  6783. if (Connection->Association->fMultiplex == mpx_no
  6784. && fOkToAdvanceCall())
  6785. {
  6786. //
  6787. // In the multiplexed case, the call is advanced
  6788. // when the send completes
  6789. //
  6790. Connection->AdvanceToNextCall();
  6791. }
  6792. }
  6793. break;
  6794. case rpc_orphaned :
  6795. case rpc_cancel :
  6796. case rpc_shutdown :
  6797. //
  6798. // For the first release, we will just ignore these messages.
  6799. //
  6800. ASSERT(Status == RPC_S_OK);
  6801. ActuallyFreeBuffer(Packet);
  6802. break;
  6803. }
  6804. Cleanup:
  6805. if (Status != RPC_S_OK)
  6806. {
  6807. ActuallyFreeBuffer(Packet);
  6808. }
  6809. return Status;
  6810. }
  6811. BOOL
  6812. OSF_CCALL::ProcessReceivedPDU (
  6813. IN void *Buffer,
  6814. IN int BufferLength
  6815. )
  6816. /*++
  6817. Function Name:ProcessReceivedPDU
  6818. Parameters:
  6819. Description:
  6820. Returns:
  6821. --*/
  6822. {
  6823. RPC_STATUS Status;
  6824. RPC_MESSAGE Message;
  6825. rpcconn_common * Packet = (rpcconn_common *) Buffer;
  6826. BOOL fSubmitReceive = 1;
  6827. Message.RpcFlags = 0;
  6828. Status = ActuallyProcessPDU(
  6829. Packet,
  6830. BufferLength,
  6831. &Message,
  6832. 1,
  6833. &fSubmitReceive);
  6834. if (Status != RPC_S_OK)
  6835. {
  6836. CallFailed(Status);
  6837. }
  6838. return fSubmitReceive;
  6839. }
  6840. RPC_STATUS
  6841. OSF_CCALL::UpdateBufferSize (
  6842. IN OUT void **Buffer,
  6843. IN int CurrentBufferLength
  6844. )
  6845. {
  6846. RPC_MESSAGE Message;
  6847. RPC_STATUS Status;
  6848. Message.RpcFlags = 0;
  6849. Message.Handle = this;
  6850. Message.ProcNum = ProcNum;
  6851. Message.BufferLength = CurrentBufferLength;
  6852. Status = GetBufferWithoutCleanup(&Message, 0);
  6853. if (Status != RPC_S_OK)
  6854. {
  6855. CallFailed(Status);
  6856. return Status;
  6857. }
  6858. RpcpMemoryCopy(Message.Buffer, *Buffer, CurrentBufferLength);
  6859. ActuallyFreeBuffer((char *) (*Buffer) - sizeof(rpcconn_request));
  6860. return RPC_S_OK;
  6861. }
  6862. RPC_STATUS
  6863. OSF_CCALL::NegotiateTransferSyntaxAndGetBuffer (
  6864. IN OUT PRPC_MESSAGE Message,
  6865. IN UUID *ObjectUuid
  6866. )
  6867. {
  6868. OSF_BINDING_HANDLE *BindingHandle;
  6869. OSF_CCALL *CCall;
  6870. RPC_STATUS Status;
  6871. RPC_SYNTAX_IDENTIFIER TransferSyntax;
  6872. BOOL fInterfaceSupportsMultipleTransferSyntaxes;
  6873. BindingHandle = (OSF_BINDING_HANDLE *)Message->Handle;
  6874. ASSERT(BindingHandle->Type(OSF_BINDING_HANDLE_TYPE));
  6875. fInterfaceSupportsMultipleTransferSyntaxes =
  6876. DoesInterfaceSupportMultipleTransferSyntaxes(Message->RpcInterfaceInformation);
  6877. if (fInterfaceSupportsMultipleTransferSyntaxes)
  6878. RpcpMemoryCopy(&TransferSyntax, Message->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER));
  6879. Status = BindingHandle->OSF_BINDING_HANDLE::NegotiateTransferSyntax(Message);
  6880. if (Status != RPC_S_OK)
  6881. return Status;
  6882. CCall = (OSF_CCALL *)Message->Handle;
  6883. if (fInterfaceSupportsMultipleTransferSyntaxes)
  6884. {
  6885. if (RpcpMemoryCompare(&TransferSyntax, Message->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)) != 0)
  6886. {
  6887. // the transfer syntax has changed - possible during auto-reconnect, especially in a
  6888. // mixed cluster environment
  6889. //
  6890. // We cannot free the call, because an async bind may be
  6891. // in progress. All we should do is remove our ref counts
  6892. // The async bind path holds its own ref count, so
  6893. // we don't need to worry about it
  6894. //
  6895. CCall->AsyncStatus = RPC_S_CALL_FAILED_DNE;
  6896. // we need to remove only one reference - the second reference
  6897. // is removed during a successful bind, and another reference
  6898. // will be added when a successful send is made - we're not
  6899. // there yet, so we have only one reference.
  6900. CCall->OSF_CCALL::RemoveReference();
  6901. // When NDR starts supporting remarshalling, we should
  6902. // return RPC_P_TRANSFER_SYNTAX_CHANGED
  6903. return RPC_S_CALL_FAILED_DNE;
  6904. }
  6905. }
  6906. Status = CCall->GetBuffer(Message, ObjectUuid);
  6907. return Status;
  6908. }
  6909. RPC_STATUS
  6910. OSF_CCALL::SendMoreData (
  6911. IN BUFFER Buffer
  6912. )
  6913. /*++
  6914. Function Name:SendMoreData
  6915. Parameters:
  6916. Description:
  6917. This function can only be called on a send completion
  6918. Returns:
  6919. --*/
  6920. {
  6921. RPC_STATUS Status;
  6922. void * SecurityTrailer;
  6923. CallMutex.Request();
  6924. if (Buffer)
  6925. {
  6926. //
  6927. // If we reach here, it means that this routine was called
  6928. // as a result of a send complete
  6929. //
  6930. ASSERT(HeaderSize != 0);
  6931. ASSERT(CurrentBuffer);
  6932. ASSERT(CurrentBuffer != LastBuffer
  6933. || CurrentBufferLength > MaxDataLength);
  6934. CurrentOffset += MaxDataLength;
  6935. CurrentBufferLength -= MaxDataLength;
  6936. if (CurrentBufferLength == 0)
  6937. {
  6938. FreeBufferDo(CurrentBuffer);
  6939. if (pAsync && (pAsync->Flags & RPC_C_NOTIFY_ON_SEND_COMPLETE))
  6940. {
  6941. if (!IssueNotification(RpcSendComplete))
  6942. {
  6943. CallMutex.Clear();
  6944. #if DBG
  6945. PrintToDebugger("RPC: SendMoreData failed: %d\n", AsyncStatus);
  6946. #endif
  6947. return RPC_S_OUT_OF_MEMORY;
  6948. }
  6949. }
  6950. //
  6951. // We can be in SendingFirstBuffer, if the we had a very small pipe
  6952. //
  6953. VALIDATE(CurrentState)
  6954. {
  6955. SendingMoreData,
  6956. SendingFirstBuffer
  6957. } END_VALIDATE;
  6958. CurrentOffset = 0;
  6959. CurrentBuffer = BufferQueue.TakeOffQueue(
  6960. (unsigned int *) &CurrentBufferLength);
  6961. if (fChoked == 1 && pAsync == 0 && BufferQueue.Size() <=1)
  6962. {
  6963. fChoked = 0;
  6964. SyncEvent.Raise();
  6965. }
  6966. if (CurrentBuffer)
  6967. {
  6968. if ((AdditionalSpaceForSecurity < Connection->AdditionalSpaceForSecurity)
  6969. && UpdateBufferSize(&CurrentBuffer, CurrentBufferLength) != RPC_S_OK)
  6970. {
  6971. CallMutex.Clear();
  6972. return RPC_S_OUT_OF_MEMORY;
  6973. }
  6974. }
  6975. else
  6976. {
  6977. Connection->MakeConnectionIdle();
  6978. ASSERT(CurrentBufferLength == 0);
  6979. CallMutex.Clear();
  6980. return RPC_S_OK;
  6981. }
  6982. }
  6983. else
  6984. {
  6985. //
  6986. // We need to restore the part of the buffer which we overwrote
  6987. // with authentication information.
  6988. //
  6989. if (Connection->ClientSecurityContext.AuthenticationLevel
  6990. != RPC_C_AUTHN_LEVEL_NONE)
  6991. {
  6992. VALIDATE(Connection->ClientSecurityContext.AuthenticationLevel)
  6993. {
  6994. RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
  6995. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  6996. RPC_C_AUTHN_LEVEL_PKT,
  6997. RPC_C_AUTHN_LEVEL_CONNECT
  6998. } END_VALIDATE;
  6999. ASSERT(HeaderSize != 0);
  7000. SecurityTrailer = (char *) Buffer
  7001. + MaximumFragmentLength - MaxSecuritySize;
  7002. RpcpMemoryCopy(SecurityTrailer, ReservedForSecurity,
  7003. MaxSecuritySize);
  7004. }
  7005. }
  7006. }
  7007. else
  7008. {
  7009. if (AdditionalSpaceForSecurity <
  7010. Connection->AdditionalSpaceForSecurity)
  7011. {
  7012. if (UpdateBufferSize(&CurrentBuffer, CurrentBufferLength) != RPC_S_OK)
  7013. {
  7014. CallMutex.Clear();
  7015. return RPC_S_OUT_OF_MEMORY;
  7016. }
  7017. }
  7018. }
  7019. CallMutex.Clear();
  7020. BOOL fFirstSend = (CurrentState == SendingFirstBuffer)
  7021. && (CurrentOffset == 0);
  7022. //
  7023. // When the last fragment is sent
  7024. // the state changes to WaitingForReply
  7025. //
  7026. Status = SendNextFragment(rpc_request, fFirstSend);
  7027. if (Status != RPC_S_OK)
  7028. {
  7029. VALIDATE(CurrentState)
  7030. {
  7031. InCallbackReply,
  7032. SendingMoreData,
  7033. SendingFirstBuffer,
  7034. WaitingForReply,
  7035. Aborted
  7036. } END_VALIDATE;
  7037. if (CurrentState == InCallbackReply)
  7038. {
  7039. AsyncStatus = Status;
  7040. SendFault(Status, 0);
  7041. Status = RPC_S_OK;
  7042. }
  7043. }
  7044. return Status;
  7045. }
  7046. RPC_STATUS
  7047. OSF_CCALL::SendData (
  7048. IN BUFFER Buffer
  7049. )
  7050. {
  7051. RPC_STATUS Status = RPC_S_OK;
  7052. switch (CurrentState)
  7053. {
  7054. case NeedAlterContext:
  7055. //
  7056. // need to send an alter context on the call
  7057. //
  7058. Status = SendAlterContextPDU();
  7059. break;
  7060. case WaitingForAlterContext:
  7061. //
  7062. // We are still waiting for alter-context to complete,
  7063. // we don't have anything to do at this very point.
  7064. // We will start sending data once we receive the
  7065. // response to the alter-context.
  7066. //
  7067. break;
  7068. case SendingMoreData:
  7069. case InCallbackReply:
  7070. case SendingFirstBuffer:
  7071. //
  7072. // the call is still sending the non pipe data
  7073. // we need to finish sending this before
  7074. // we can move on the the next call.
  7075. //
  7076. Status = SendMoreData(Buffer);
  7077. break;
  7078. case Aborted:
  7079. //
  7080. // some failure occured. the call is now in an
  7081. // aborted state
  7082. //
  7083. Status = AsyncStatus;
  7084. #if DBG
  7085. PrintToDebugger("RPC: Call in aborted state\n");
  7086. #endif
  7087. ASSERT(Status != RPC_S_OK);
  7088. break;
  7089. case Complete:
  7090. //
  7091. // the call is complete, the receive complete before the send could
  7092. // complete, but we should have advanced to the next call when
  7093. // sending the last fragment. We should never get into this state,
  7094. // unless we are talking to a legacy server
  7095. //
  7096. ASSERT(Status == RPC_S_OK);
  7097. ASSERT(Connection->Association->fMultiplex == mpx_no);
  7098. break;
  7099. case Receiving:
  7100. //
  7101. // We should never be in this state unless we are talking to a legacy
  7102. // server
  7103. //
  7104. ASSERT(Connection->Association->fMultiplex == mpx_no);
  7105. // intentional fall through
  7106. case WaitingForReply:
  7107. ASSERT(Status == RPC_S_OK);
  7108. break;
  7109. case InCallbackRequest:
  7110. default:
  7111. //
  7112. // we should never be in these states.
  7113. #if DBG
  7114. PrintToDebugger("RPC: Bad call state: %d\n", CurrentState);
  7115. #endif
  7116. ASSERT(0);
  7117. Status = RPC_S_INTERNAL_ERROR;
  7118. break;
  7119. }
  7120. return Status;
  7121. }
  7122. void
  7123. OSF_CCALL::ProcessSendComplete (
  7124. IN RPC_STATUS EventStatus,
  7125. IN BUFFER Buffer
  7126. )
  7127. /*++
  7128. Function Name:ProcessSendComplete
  7129. Parameters:
  7130. Description:
  7131. Returns:
  7132. --*/
  7133. {
  7134. if (EventStatus == RPC_S_OK)
  7135. {
  7136. EventStatus = SendData(Buffer);
  7137. }
  7138. if (EventStatus != RPC_S_OK)
  7139. {
  7140. Connection->ConnectionAborted(EventStatus);
  7141. //
  7142. // Remove the send reference on the call, CCALL--
  7143. //
  7144. RemoveReference();
  7145. }
  7146. }
  7147. RPC_STATUS
  7148. OSF_CCALL::SendNextFragment (
  7149. IN unsigned char PacketType,
  7150. IN BOOL fFirstSend,
  7151. OUT void **ReceiveBuffer,
  7152. OUT UINT *ReceivedLength
  7153. )
  7154. /*++
  7155. Function Name:SendNextFragment
  7156. Parameters:
  7157. Description:
  7158. Returns:
  7159. --*/
  7160. {
  7161. int PacketLength;
  7162. RPC_STATUS Status;
  7163. BOOL LastFragmentFlag;
  7164. rpcconn_common *pFragment;
  7165. void *SendContext = CallSendContext;
  7166. int MyBufferLength;
  7167. int MyHeaderSize = HeaderSize;
  7168. ULONG Timeout;
  7169. ASSERT(HeaderSize != 0);
  7170. ASSERT(MaxDataLength);
  7171. ASSERT(CurrentBuffer);
  7172. if (UuidSpecified && (CallStack > 1 || PacketType != rpc_request))
  7173. {
  7174. MyHeaderSize -= sizeof(UUID);
  7175. }
  7176. //
  7177. // Prepare the fragment
  7178. //
  7179. if (CurrentBuffer == LastBuffer
  7180. && CurrentBufferLength <= MaxDataLength)
  7181. {
  7182. PacketLength = CurrentBufferLength + MyHeaderSize + MaxSecuritySize;
  7183. LastFragmentFlag = 1;
  7184. if (CurrentState != InCallbackReply)
  7185. {
  7186. ASSERT((CurrentState == SendingFirstBuffer)
  7187. || (CurrentState == SendingMoreData)
  7188. || (CurrentState == Aborted));
  7189. CurrentState = WaitingForReply;
  7190. if (Connection->fExclusive == 0)
  7191. {
  7192. //
  7193. // This async send will complete on the connection
  7194. // and the connection will free the buffer
  7195. //
  7196. SendContext = Connection->u.ConnSendContext;
  7197. Connection->BufferToFree = ActualBuffer(CurrentBuffer);
  7198. }
  7199. }
  7200. }
  7201. else
  7202. {
  7203. PacketLength = MaximumFragmentLength;
  7204. LastFragmentFlag = 0;
  7205. if (CurrentBufferLength == MaxDataLength
  7206. && CurrentState == SendingFirstBuffer)
  7207. {
  7208. CurrentState = SendingMoreData;
  7209. }
  7210. }
  7211. pFragment = (rpcconn_common *)
  7212. ((char *) CurrentBuffer + CurrentOffset - MyHeaderSize);
  7213. ConstructPacket(pFragment,
  7214. PacketType,
  7215. PacketLength);
  7216. if (fFirstSend)
  7217. {
  7218. pFragment->pfc_flags |= PFC_FIRST_FRAG;
  7219. }
  7220. if ( PacketType == rpc_request )
  7221. {
  7222. if (UuidSpecified && (pAsync || CallStack == 1))
  7223. {
  7224. pFragment->pfc_flags |= PFC_OBJECT_UUID;
  7225. RpcpMemoryCopy(((unsigned char *) pFragment)
  7226. + sizeof(rpcconn_request),
  7227. &ObjectUuid,
  7228. sizeof(UUID));
  7229. }
  7230. ((rpcconn_request *) pFragment)->alloc_hint = CurrentBufferLength;
  7231. ((rpcconn_request *) pFragment)->p_cont_id
  7232. = GetSelectedBinding()->GetOnTheWirePresentationContext();
  7233. ((rpcconn_request *) pFragment)->opnum = (unsigned short) ProcNum;
  7234. }
  7235. else
  7236. {
  7237. ((rpcconn_response *) pFragment)->alloc_hint = CurrentBufferLength;
  7238. ((rpcconn_response *) pFragment)->p_cont_id
  7239. = GetSelectedBinding()->GetOnTheWirePresentationContext();
  7240. ((rpcconn_response *) pFragment)->alert_count = 0;
  7241. ((rpcconn_response *) pFragment)->reserved = 0;
  7242. }
  7243. pFragment->call_id = CallId;
  7244. MyBufferLength = CurrentBufferLength;
  7245. if (Connection->fExclusive)
  7246. {
  7247. Timeout = GetBindingHandleTimeout(BindingHandle);
  7248. if (LastFragmentFlag == 0)
  7249. {
  7250. CurrentOffset += MaxDataLength;
  7251. CurrentBufferLength -= MaxDataLength;
  7252. if (UuidSpecified && (CallStack > 1 || PacketType != rpc_request))
  7253. {
  7254. CurrentOffset += sizeof(UUID);
  7255. CurrentBufferLength -= sizeof(UUID);
  7256. }
  7257. ASSERT(((long)CurrentBufferLength) >= 0);
  7258. }
  7259. else
  7260. {
  7261. CurrentBufferLength = 0;
  7262. }
  7263. }
  7264. else
  7265. Timeout = INFINITE;
  7266. if (ReceiveBuffer)
  7267. {
  7268. *ReceiveBuffer = NULL;
  7269. }
  7270. Status = Connection->SendFragment (
  7271. pFragment,
  7272. this,
  7273. LastFragmentFlag,
  7274. MyHeaderSize,
  7275. MaxSecuritySize,
  7276. MyBufferLength,
  7277. MaximumFragmentLength,
  7278. ReservedForSecurity,
  7279. !(Connection->fExclusive),
  7280. SendContext,
  7281. Timeout,
  7282. ReceiveBuffer,
  7283. ReceivedLength);
  7284. if (ReceiveBuffer && *ReceiveBuffer)
  7285. {
  7286. CurrentBufferLength = 0;
  7287. }
  7288. return Status;
  7289. }
  7290. RPC_STATUS
  7291. OSF_CCALL::ProcessResponse (
  7292. IN rpcconn_response *Packet,
  7293. IN PRPC_MESSAGE Message,
  7294. OUT BOOL *pfSubmitReceive
  7295. )
  7296. /*++
  7297. Function Name:ProcessResponse
  7298. Parameters:
  7299. Description:
  7300. Process the response data. The first buffer is placed on the buffer queue
  7301. only after alloc_hint bytes have been received.
  7302. Returns:
  7303. --*/
  7304. {
  7305. RPC_STATUS Status;
  7306. //
  7307. // We don't need to look at alloc_hint for the response PDUs
  7308. // we can simply queue up the buffers. When we get the last one,
  7309. // we'll coalesce them for for the non pipe case. For the pipe case,
  7310. // we will progressively give the buffers to the stub.
  7311. //
  7312. CallMutex.Request();
  7313. if (QueueBuffer(Message->Buffer,
  7314. Message->BufferLength))
  7315. {
  7316. CallFailed(RPC_S_OUT_OF_MEMORY);
  7317. CallMutex.Clear();
  7318. return RPC_S_OUT_OF_MEMORY;
  7319. }
  7320. if (COMPLETE(Message))
  7321. {
  7322. AsyncStatus = RPC_S_OK;
  7323. CurrentState = Complete;
  7324. CallMutex.Clear();
  7325. if (Connection->Association->fMultiplex == mpx_no
  7326. && fOkToAdvanceCall())
  7327. {
  7328. //
  7329. // In the multiplexed case, the call is advanced
  7330. // when the send completes
  7331. //
  7332. Connection->AdvanceToNextCall();
  7333. }
  7334. IssueNotification();
  7335. }
  7336. else
  7337. {
  7338. if (pAsync == 0)
  7339. {
  7340. if (BufferQueue.Size() >= 4
  7341. && pfSubmitReceive)
  7342. {
  7343. fPeerChoked = 1;
  7344. *pfSubmitReceive = 0;
  7345. }
  7346. CallMutex.Clear();
  7347. SyncEvent.Raise();
  7348. }
  7349. else
  7350. {
  7351. if (NeededLength > 0
  7352. && RcvBufferLength > NeededLength)
  7353. {
  7354. IssueNotification(RpcReceiveComplete);
  7355. }
  7356. else
  7357. {
  7358. if (fDoFlowControl
  7359. && BufferQueue.Size() >= 4
  7360. && pfSubmitReceive)
  7361. {
  7362. fPeerChoked = 1;
  7363. *pfSubmitReceive = 0;
  7364. }
  7365. }
  7366. CallMutex.Clear();
  7367. }
  7368. }
  7369. return RPC_S_OK;
  7370. }
  7371. RPC_STATUS
  7372. OSF_CCALL::SendAlterContextPDU (
  7373. )
  7374. /*++
  7375. Function Name:SendAlterContextPDU
  7376. Parameters:
  7377. Description:
  7378. Returns:
  7379. --*/
  7380. {
  7381. RPC_STATUS Status;
  7382. ULONG Timeout;
  7383. BOOL fBindingHandleTimeoutUsed;
  7384. //
  7385. // We try to create a thread to go down and listen
  7386. //
  7387. Status = BindingHandle->TransInfo->CreateThread();
  7388. VALIDATE(Status)
  7389. {
  7390. RPC_S_OK,
  7391. RPC_S_OUT_OF_MEMORY,
  7392. RPC_S_OUT_OF_THREADS
  7393. } END_VALIDATE;
  7394. CurrentState = WaitingForAlterContext;
  7395. ASSERT(Connection->Association->AssocGroupId);
  7396. Timeout = GetEffectiveTimeoutForBind(
  7397. BindingHandle,
  7398. &fBindingHandleTimeoutUsed);
  7399. //
  7400. // Send the alter-context PDU
  7401. //
  7402. Status = Connection->SendBindPacket(
  7403. FALSE,
  7404. this,
  7405. Connection->Association->AssocGroupId,
  7406. rpc_alter_context,
  7407. Timeout
  7408. );
  7409. if (Status != RPC_S_OK)
  7410. {
  7411. Status = GetStatusForTimeout(BindingHandle, Status, fBindingHandleTimeoutUsed);
  7412. CallFailed(Status);
  7413. #if DBG
  7414. PrintToDebugger("RPC: SendAlterContextPDU failed: %d\n", Status);
  7415. #endif
  7416. }
  7417. return Status;
  7418. }
  7419. RPC_STATUS
  7420. OSF_CCALL::EatAuthInfoFromPacket (
  7421. IN rpcconn_request * Request,
  7422. IN OUT UINT * RequestLength
  7423. )
  7424. /*++
  7425. Routine Description:
  7426. If there is authentication information in the packet, this routine
  7427. will check it, and perform security as necessary. This may include
  7428. calls to the security support package.
  7429. Arguments:
  7430. Request - Supplies the packet which may contain authentication
  7431. information.
  7432. RequestLength - Supplies the length of the packet in bytes, and
  7433. returns the length of the packet without authentication
  7434. information.
  7435. Return Value:
  7436. RPC_S_OK - Everything went just fine.
  7437. RPC_S_ACCESS_DENIED - A security failure of some sort occured.
  7438. RPC_S_PROTOCOL_ERROR - This will occur if no authentication information
  7439. is in the packet, and some was expected, or visa versa.
  7440. --*/
  7441. {
  7442. RPC_STATUS Status;
  7443. sec_trailer * SecurityTrailer;
  7444. SECURITY_BUFFER SecurityBuffers[5];
  7445. DCE_MSG_SECURITY_INFO MsgSecurityInfo;
  7446. SECURITY_BUFFER_DESCRIPTOR BufferDescriptor;
  7447. if ( Request->common.auth_length != 0 )
  7448. {
  7449. SecurityTrailer = (sec_trailer *)
  7450. (((unsigned char *) Request)
  7451. + Request->common.frag_length
  7452. - Request->common.auth_length
  7453. - sizeof(sec_trailer));
  7454. ASSERT(SecurityTrailer->auth_context_id == PtrToUlong(Connection));
  7455. if ((Connection->ClientSecurityContext.AuthenticationLevel
  7456. == RPC_C_AUTHN_LEVEL_NONE))
  7457. {
  7458. return(RPC_S_PROTOCOL_ERROR);
  7459. }
  7460. *RequestLength -= Request->common.auth_length;
  7461. MsgSecurityInfo.SendSequenceNumber =
  7462. Connection->InquireSendSequenceNumber();
  7463. MsgSecurityInfo.ReceiveSequenceNumber =
  7464. Connection->InquireReceiveSequenceNumber();
  7465. MsgSecurityInfo.PacketType = Request->common.PTYPE;
  7466. BufferDescriptor.ulVersion = 0;
  7467. BufferDescriptor.cBuffers = 5;
  7468. BufferDescriptor.pBuffers = SecurityBuffers;
  7469. SecurityBuffers[0].cbBuffer = sizeof(rpcconn_request);
  7470. SecurityBuffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  7471. SecurityBuffers[0].pvBuffer = ((unsigned char *) SavedHeader);
  7472. SecurityBuffers[1].cbBuffer = *RequestLength
  7473. - sizeof(rpcconn_request)
  7474. - sizeof (sec_trailer);
  7475. SecurityBuffers[1].BufferType = SECBUFFER_DATA;
  7476. SecurityBuffers[1].pvBuffer = ((unsigned char *) Request)
  7477. + sizeof(rpcconn_request);
  7478. SecurityBuffers[2].cbBuffer = sizeof(sec_trailer);
  7479. SecurityBuffers[2].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
  7480. SecurityBuffers[2].pvBuffer = SecurityTrailer;
  7481. SecurityBuffers[3].cbBuffer = Request->common.auth_length;
  7482. SecurityBuffers[3].BufferType = SECBUFFER_TOKEN;
  7483. SecurityBuffers[3].pvBuffer = SecurityTrailer + 1;
  7484. SecurityBuffers[4].cbBuffer = sizeof(DCE_MSG_SECURITY_INFO);
  7485. SecurityBuffers[4].BufferType = (SECBUFFER_PKG_PARAMS
  7486. | SECBUFFER_READONLY);
  7487. SecurityBuffers[4].pvBuffer = &MsgSecurityInfo;
  7488. Status = Connection->ClientSecurityContext.VerifyOrUnseal(
  7489. MsgSecurityInfo.ReceiveSequenceNumber,
  7490. Connection->ClientSecurityContext.AuthenticationLevel
  7491. != RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  7492. &BufferDescriptor);
  7493. if ( Status != RPC_S_OK )
  7494. {
  7495. ASSERT( (Status == RPC_S_ACCESS_DENIED) ||
  7496. (Status == ERROR_SHUTDOWN_IN_PROGRESS) ||
  7497. (Status == ERROR_PASSWORD_MUST_CHANGE) ||
  7498. (Status == ERROR_PASSWORD_EXPIRED) ||
  7499. (Status == ERROR_ACCOUNT_DISABLED) ||
  7500. (Status == ERROR_INVALID_LOGON_HOURS));
  7501. return(Status);
  7502. }
  7503. *RequestLength -= (sizeof(sec_trailer)
  7504. + SecurityTrailer->auth_pad_length);
  7505. }
  7506. else
  7507. {
  7508. if ((Connection->ClientSecurityContext.AuthenticationLevel
  7509. == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
  7510. || (Connection->ClientSecurityContext.AuthenticationLevel
  7511. == RPC_C_AUTHN_LEVEL_PKT_PRIVACY))
  7512. {
  7513. return(RPC_S_PROTOCOL_ERROR);
  7514. }
  7515. }
  7516. Connection->IncReceiveSequenceNumber();
  7517. return(RPC_S_OK);
  7518. }
  7519. void
  7520. OSF_CCALL::SendFault (
  7521. IN RPC_STATUS Status,
  7522. IN int DidNotExecute
  7523. )
  7524. {
  7525. rpcconn_fault Fault;
  7526. memset(&Fault, 0, sizeof(Fault));
  7527. ConstructPacket((rpcconn_common *) &Fault,rpc_fault,
  7528. sizeof(rpcconn_fault));
  7529. if (DidNotExecute)
  7530. Fault.common.pfc_flags |= PFC_DID_NOT_EXECUTE;
  7531. Fault.common.pfc_flags |= PFC_FIRST_FRAG | PFC_LAST_FRAG;
  7532. Fault.p_cont_id = GetSelectedBinding()->GetOnTheWirePresentationContext();
  7533. Fault.status = MapToNcaStatusCode(Status);
  7534. Fault.common.call_id = CallId;
  7535. Connection->TransSend(&Fault,
  7536. sizeof(rpcconn_fault),
  7537. TRUE, // fDisableShutdownCheck
  7538. TRUE, // fDisableCancelCheck
  7539. INFINITE
  7540. );
  7541. }
  7542. RPC_STATUS
  7543. OSF_CCALL::SendCancelPDU(
  7544. )
  7545. {
  7546. rpcconn_common CancelPDU;
  7547. RPC_STATUS Status;
  7548. ULONG Timeout;
  7549. ConstructPacket(
  7550. (rpcconn_common *) &CancelPDU,
  7551. rpc_cancel,
  7552. sizeof(rpcconn_common));
  7553. CancelPDU.call_id = CallId;
  7554. CancelPDU.pfc_flags = PFC_LAST_FRAG | PFC_PENDING_CANCEL;
  7555. Timeout = GetBindingHandleTimeout(BindingHandle);
  7556. Status = Connection->TransSend(&CancelPDU,
  7557. sizeof(rpcconn_common),
  7558. TRUE, // fDisableShutdownCheck
  7559. TRUE, // fDisableCancelCheck
  7560. Timeout
  7561. );
  7562. if (Status == RPC_P_TIMEOUT)
  7563. {
  7564. Status = RPC_S_CALL_CANCELLED;
  7565. }
  7566. else
  7567. {
  7568. ASSERT(Status != RPC_S_CALL_CANCELLED);
  7569. }
  7570. return Status;
  7571. }
  7572. RPC_STATUS
  7573. OSF_CCALL::SendOrphanPDU (
  7574. )
  7575. {
  7576. rpcconn_common Orphan;
  7577. RPC_STATUS Status;
  7578. ULONG Timeout;
  7579. ConstructPacket(
  7580. (rpcconn_common *) &Orphan,
  7581. rpc_orphaned,
  7582. sizeof(rpcconn_common));
  7583. Orphan.call_id = CallId;
  7584. Orphan.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
  7585. Timeout = GetBindingHandleTimeout(BindingHandle);
  7586. Status = Connection->TransSend(&Orphan,
  7587. sizeof(rpcconn_common),
  7588. TRUE, // fDisableShutdownCheck
  7589. TRUE, // fDisableCancelCheck
  7590. Timeout
  7591. );
  7592. return Status;
  7593. }
  7594. RPC_STATUS
  7595. OSF_CCALL::NegotiateTransferSyntax (
  7596. IN OUT PRPC_MESSAGE Message
  7597. )
  7598. {
  7599. // this can only happen for callbacks
  7600. ASSERT(IsCallInCallback());
  7601. // just return the transfer syntax already negotiated in the binding
  7602. Message->TransferSyntax = GetSelectedBinding()->GetTransferSyntaxId();
  7603. return RPC_S_OK;
  7604. }
  7605. RPC_STATUS
  7606. OSF_CCALL::GetBuffer (
  7607. IN OUT PRPC_MESSAGE Message,
  7608. IN UUID *ObjectUuid
  7609. )
  7610. /*++
  7611. Routine Description:
  7612. Arguments:
  7613. Message - Supplies a description containing the length of buffer to be
  7614. allocated, and returns the allocated buffer.
  7615. ObjectUuid - this parameter is ignored
  7616. Return Value:
  7617. RPC_S_OK - A buffer of the requested size has successfully been allocated.
  7618. RPC_S_OUT_OF_MEMORY - Insufficient memory is available.
  7619. --*/
  7620. {
  7621. RPC_STATUS Status;
  7622. AssocDictMutex->VerifyNotOwned();
  7623. UpdateObjectUUIDInfo(ObjectUuid);
  7624. Status = GetBufferWithoutCleanup(Message, ObjectUuid);
  7625. // do the cleanup to get regular GetBuffer semantics
  7626. if (Status != RPC_S_OK)
  7627. {
  7628. //
  7629. // We cannot free the call, because an async bind may be
  7630. // in progress. All we should do is remove our ref counts
  7631. // The async bind path holds its own ref count, so
  7632. // we don't need to worry about it
  7633. //
  7634. AsyncStatus = RPC_S_CALL_FAILED_DNE;
  7635. if (Connection->fExclusive == 0)
  7636. {
  7637. // async calls have one more reference
  7638. OSF_CCALL::RemoveReference();
  7639. }
  7640. OSF_CCALL::RemoveReference();
  7641. }
  7642. return(Status);
  7643. }
  7644. RPC_STATUS
  7645. OSF_CCALL::GetBufferWithoutCleanup (
  7646. IN OUT PRPC_MESSAGE Message,
  7647. IN UUID *ObjectUuid
  7648. )
  7649. {
  7650. RPC_STATUS Status;
  7651. ULONG MaxFrag;
  7652. ULONG NewLength;
  7653. MaxFrag = Connection->MaxFrag;
  7654. ProcNum = Message->ProcNum;
  7655. //
  7656. // In addition to saving space for the request (or response) header
  7657. // and an object UUID, we want to save space for security information
  7658. // if necessary.
  7659. //
  7660. if ((Message->RpcFlags & RPC_BUFFER_PARTIAL)
  7661. && (Message->BufferLength < MaxFrag))
  7662. {
  7663. ActualBufferLength = MaxFrag;
  7664. }
  7665. else
  7666. {
  7667. ActualBufferLength = Message->BufferLength;
  7668. }
  7669. NewLength = ActualBufferLength
  7670. + sizeof(rpcconn_request)
  7671. + sizeof(UUID)
  7672. + (2 * Connection->AdditionalSpaceForSecurity);
  7673. Status = ActuallyAllocateBuffer(&Message->Buffer,
  7674. NewLength);
  7675. if ( Status != RPC_S_OK )
  7676. {
  7677. ASSERT( Status == RPC_S_OUT_OF_MEMORY );
  7678. return Status;
  7679. }
  7680. ASSERT(HeaderSize != 0);
  7681. if (UuidSpecified)
  7682. {
  7683. Message->Buffer = (char *) Message->Buffer
  7684. + sizeof(rpcconn_request)
  7685. + sizeof(UUID);
  7686. }
  7687. else
  7688. {
  7689. Message->Buffer = (char *) Message->Buffer
  7690. + sizeof(rpcconn_request);
  7691. }
  7692. return RPC_S_OK;
  7693. }
  7694. RPC_STATUS
  7695. OSF_CCALL::GetBufferDo (
  7696. IN UINT culRequiredLength,
  7697. OUT void * * ppBuffer,
  7698. IN int fDataValid,
  7699. IN int DataLength
  7700. )
  7701. /*++
  7702. Function Name:GetBufferDo
  7703. Parameters:
  7704. Description:
  7705. Returns:
  7706. --*/
  7707. {
  7708. RPC_STATUS Status;
  7709. void *NewBuffer;
  7710. Status = ActuallyAllocateBuffer(&NewBuffer,
  7711. culRequiredLength
  7712. + sizeof(rpcconn_request)
  7713. + sizeof(UUID));
  7714. if (Status)
  7715. return(RPC_S_OUT_OF_MEMORY);
  7716. ASSERT(HeaderSize != 0);
  7717. if (UuidSpecified)
  7718. {
  7719. NewBuffer = (((unsigned char *) NewBuffer)
  7720. + sizeof(rpcconn_request))
  7721. + sizeof(UUID);
  7722. }
  7723. else
  7724. {
  7725. NewBuffer = (((unsigned char *) NewBuffer)
  7726. + sizeof(rpcconn_request));
  7727. }
  7728. if (fDataValid)
  7729. {
  7730. RpcpMemoryCopy(NewBuffer, *ppBuffer, DataLength);
  7731. ActuallyFreeBuffer(*ppBuffer);
  7732. }
  7733. *ppBuffer = NewBuffer;
  7734. return(RPC_S_OK);
  7735. }
  7736. void
  7737. OSF_CCALL::FreeBufferDo (
  7738. IN void *Buffer
  7739. )
  7740. /*++
  7741. Function Name:FreeBufferDo
  7742. Parameters:
  7743. Description:
  7744. Returns:
  7745. --*/
  7746. {
  7747. ASSERT(HeaderSize != 0);
  7748. if (UuidSpecified)
  7749. {
  7750. Buffer = (char *) Buffer - sizeof(rpcconn_request) - sizeof(UUID);
  7751. }
  7752. else
  7753. {
  7754. Buffer = (char *) Buffer - sizeof(rpcconn_request);
  7755. }
  7756. ActuallyFreeBuffer((char *)Buffer);
  7757. }
  7758. void
  7759. OSF_CCALL::FreeBuffer (
  7760. IN PRPC_MESSAGE Message
  7761. )
  7762. /*++
  7763. Function Name:FreeBuffer
  7764. Parameters:
  7765. Description:
  7766. Returns:
  7767. --*/
  7768. {
  7769. if (CallStack == 0)
  7770. {
  7771. if (Message->Buffer != NULL)
  7772. {
  7773. if (CurrentState == Complete)
  7774. {
  7775. ActuallyFreeBuffer((char *)Message->Buffer-sizeof(rpcconn_response));
  7776. }
  7777. else
  7778. {
  7779. FreeBufferDo(Message->Buffer);
  7780. }
  7781. }
  7782. if (Connection->fExclusive)
  7783. {
  7784. FreeCCall(RPC_S_OK);
  7785. }
  7786. else
  7787. {
  7788. UnregisterCallForCancels();
  7789. // Remove the call reference CCALL--
  7790. RemoveReference();
  7791. }
  7792. }
  7793. else
  7794. {
  7795. if (Message->Buffer != NULL)
  7796. {
  7797. ActuallyFreeBuffer((char *)Message->Buffer-sizeof(rpcconn_response));
  7798. CurrentBufferLength = 0;
  7799. }
  7800. else
  7801. {
  7802. FreeCCall(RPC_S_OK);
  7803. }
  7804. }
  7805. }
  7806. void
  7807. OSF_CCALL::FreePipeBuffer (
  7808. IN PRPC_MESSAGE Message
  7809. )
  7810. /*++
  7811. Function Name:FreePipeBuffer
  7812. Parameters:
  7813. Description:
  7814. Returns:
  7815. --*/
  7816. {
  7817. ASSERT(HeaderSize != 0);
  7818. if (UuidSpecified)
  7819. {
  7820. Message->Buffer = (char *) Message->Buffer
  7821. - sizeof(rpcconn_request) - sizeof(UUID);
  7822. }
  7823. else
  7824. {
  7825. Message->Buffer = (char *) Message->Buffer
  7826. - sizeof(rpcconn_request);
  7827. }
  7828. ActuallyFreeBuffer((char *)Message->Buffer);
  7829. }
  7830. RPC_STATUS
  7831. OSF_CCALL::ReallocPipeBuffer (
  7832. IN PRPC_MESSAGE Message,
  7833. IN UINT NewSize
  7834. )
  7835. /*++
  7836. Function Name:ReallocPipeBuffer
  7837. Parameters:
  7838. Description:
  7839. Returns:
  7840. --*/
  7841. {
  7842. void *TempBuffer;
  7843. RPC_STATUS Status;
  7844. ULONG SizeToAlloc;
  7845. ULONG MaxFrag = Connection->MaxFrag;
  7846. if (NewSize > ActualBufferLength)
  7847. {
  7848. SizeToAlloc = (NewSize > MaxFrag) ? NewSize:MaxFrag;
  7849. Status = ActuallyAllocateBuffer(&TempBuffer,
  7850. SizeToAlloc
  7851. + sizeof(rpcconn_request) + sizeof(UUID)
  7852. + (2 * Connection->AdditionalSpaceForSecurity));
  7853. if ( Status != RPC_S_OK )
  7854. {
  7855. ASSERT( Status == RPC_S_OUT_OF_MEMORY );
  7856. return(RPC_S_OUT_OF_MEMORY);
  7857. }
  7858. ASSERT(HeaderSize != 0);
  7859. //
  7860. // N.B. Potentially, if we could return ActualBufferLength
  7861. // in NewSize, the stubs can take advantage of that and gain
  7862. // perf.
  7863. //
  7864. if (UuidSpecified)
  7865. {
  7866. TempBuffer = (char *) TempBuffer
  7867. + sizeof(rpcconn_request)
  7868. + sizeof(UUID);
  7869. }
  7870. else
  7871. {
  7872. TempBuffer = (char *) TempBuffer
  7873. + sizeof(rpcconn_request);
  7874. }
  7875. if (Message->BufferLength > 0)
  7876. {
  7877. RpcpMemoryCopy(TempBuffer, Message->Buffer,
  7878. Message->BufferLength);
  7879. FreePipeBuffer(Message);
  7880. }
  7881. Message->Buffer = TempBuffer;
  7882. ActualBufferLength = SizeToAlloc;
  7883. }
  7884. Message->BufferLength = NewSize;
  7885. return (RPC_S_OK);
  7886. }
  7887. void
  7888. OSF_CCALL::FreeCCall (
  7889. IN RPC_STATUS Status
  7890. )
  7891. /*++
  7892. Routine Description:
  7893. This routine is used to free a connection when the original remote
  7894. procedure call using it completes.
  7895. --*/
  7896. {
  7897. void *Buffer;
  7898. UINT BufferLength;
  7899. OSF_BINDING_HANDLE *MyBindingHandle;
  7900. ULONG Timeout;
  7901. ASSERT(BindingHandle != 0);
  7902. LogEvent(SU_CCALL, EV_DELETE, this, NULL, Status, 1, 1);
  7903. if (EEInfo)
  7904. {
  7905. ASSERT(pAsync);
  7906. ASSERT(RpcpGetEEInfo() == NULL);
  7907. // move the eeinfo to the thread
  7908. RpcpSetEEInfo(EEInfo);
  7909. EEInfo = NULL;
  7910. }
  7911. //
  7912. // Empty the buffer queue and nuke the buffers
  7913. //
  7914. while (Buffer = BufferQueue.TakeOffQueue(&BufferLength))
  7915. {
  7916. if (InReply)
  7917. {
  7918. ActuallyFreeBuffer((char *) Buffer-sizeof(rpcconn_request));
  7919. }
  7920. else
  7921. {
  7922. FreeBufferDo(Buffer);
  7923. }
  7924. }
  7925. if (RecursiveCallsKey != -1)
  7926. {
  7927. BindingHandle->RemoveRecursiveCall(this);
  7928. }
  7929. //
  7930. // We will not send an Orphan PDU if the call was cancelled
  7931. // This is because, we are going to close the connection anyway
  7932. // When a connection close is received while a call is in progress,
  7933. // it is treated as an orphan
  7934. //
  7935. MyBindingHandle = BindingHandle;
  7936. BindingHandle = 0;
  7937. //
  7938. // N.B. If this call failed with a fatal error, we will nuke the connection
  7939. // and all calls after it.
  7940. //
  7941. //
  7942. // If its been this long and we are still the current call,
  7943. // we need to advance the call
  7944. //
  7945. Connection->MaybeAdvanceToNextCall(this);
  7946. //
  7947. // release this CCall to the connection
  7948. //
  7949. if (MyBindingHandle)
  7950. Timeout = MyBindingHandle->InqComTimeout();
  7951. else
  7952. Timeout = 0;
  7953. Connection->FreeCCall(this,
  7954. Status,
  7955. Timeout) ;
  7956. //
  7957. // The ref count on the binding handle
  7958. // needs to be decremented if the binding handle is still there
  7959. //
  7960. if (MyBindingHandle)
  7961. MyBindingHandle->BindingFree();
  7962. }
  7963. #if 1
  7964. RPC_STATUS
  7965. OSF_CCALL::Cancel(
  7966. void * ThreadHandle
  7967. )
  7968. {
  7969. fCallCancelled = TRUE;
  7970. return RPC_S_OK;
  7971. }
  7972. #else
  7973. RPC_STATUS
  7974. OSF_CCALL::Cancel(
  7975. void * Tid
  7976. )
  7977. {
  7978. RPC_STATUS Status;
  7979. Cancelled = TRUE;
  7980. Status = I_RpcIOAlerted((OSF_CCONNECTION *)this,(DWORD)Tid);
  7981. return RPC_S_OK;
  7982. }
  7983. #endif
  7984. RPC_STATUS
  7985. OSF_CCALL::CancelAsyncCall (
  7986. IN BOOL fAbort
  7987. )
  7988. /*++
  7989. Function Name:CancelAsyncCall
  7990. Parameters:
  7991. fAbort - TRUE: the cancel is abortive, ie, the call completes immediately
  7992. FALSE: a cancel PDU is sent to the server, the call doesn't complete
  7993. until the server returns
  7994. Description:
  7995. Returns:
  7996. RPC_S_OK: The call was successfully cancelled
  7997. others - an error occured during the cancellation process
  7998. --*/
  7999. {
  8000. RPC_STATUS Status;
  8001. // The EEInfo that may be sitting on this thread could have
  8002. // nothing to do with the the async call that we are about to cancel.
  8003. RpcpPurgeEEInfo();
  8004. switch (CurrentState)
  8005. {
  8006. case NeedOpenAndBind:
  8007. case NeedAlterContext:
  8008. case WaitingForAlterContext:
  8009. //
  8010. // The call has not yet started
  8011. // fail the call right now
  8012. //
  8013. CallFailed(RPC_S_CALL_CANCELLED);
  8014. break;
  8015. case Aborted:
  8016. case Complete:
  8017. //
  8018. // The call has either failed or has completed
  8019. // we don't need to do anything
  8020. //
  8021. break;
  8022. default:
  8023. //
  8024. // The call is in progress, we need to cancel it.
  8025. //
  8026. if (fAbort)
  8027. {
  8028. SendOrphanPDU();
  8029. CallFailed(RPC_S_CALL_CANCELLED);
  8030. }
  8031. else
  8032. {
  8033. return SendCancelPDU();
  8034. }
  8035. }
  8036. return RPC_S_OK;
  8037. }
  8038. RPC_STATUS
  8039. OSF_CCALL::BindCompleteNotify (
  8040. IN p_result_t *OsfResult,
  8041. IN int IndexOfPresentationContextAccepted,
  8042. OUT OSF_BINDING **BindingNegotiated
  8043. )
  8044. /*++
  8045. Function Name:BindCompleteNotify
  8046. Parameters:
  8047. OsfResult - The one and only result element that contained acceptance
  8048. IndexOfPresentationContextAccepted - the index of the accepted
  8049. presentation context. Recall that the server indicates acceptance
  8050. by position.
  8051. BindingNegotiated - on success for multiple bindings proposed, the
  8052. pointer to the OSF binding that the server chose. On failure, or if
  8053. only one binding is proposed, it is undefined.
  8054. Description:
  8055. Examines the accepted context, does a bunch of validity checks, and
  8056. if necessary, fixes the binding which the call will use. If the binding
  8057. is already fixed, it won't touch it.
  8058. Returns:
  8059. RPC_S_OK: The acceptance is valid, and the call binding was fixed
  8060. others: error code
  8061. --*/
  8062. {
  8063. int CurrentBindingIndex;
  8064. if (Bindings.AvailableBindingsList == FALSE)
  8065. {
  8066. // only one binding was proposed - it better be accepted
  8067. if (GetSelectedBinding()->CompareWithTransferSyntax(&OsfResult->transfer_syntax) != 0)
  8068. {
  8069. return RPC_S_PROTOCOL_ERROR;
  8070. }
  8071. if (IndexOfPresentationContextAccepted > 0)
  8072. return RPC_S_PROTOCOL_ERROR;
  8073. }
  8074. else
  8075. {
  8076. OSF_BINDING *CurrentBinding = GetBindingList();
  8077. OSF_BINDING *BindingToUse;
  8078. // multiple bindings were proposed - lookup the binding that
  8079. // the server chose, fix our binding and record the server
  8080. // preferences
  8081. BindingToUse = 0;
  8082. CurrentBindingIndex = 0;
  8083. do
  8084. {
  8085. if (CurrentBinding->CompareWithTransferSyntax(&OsfResult->transfer_syntax) == 0)
  8086. {
  8087. BindingToUse = CurrentBinding;
  8088. break;
  8089. }
  8090. CurrentBinding = CurrentBinding->GetNextBinding();
  8091. CurrentBindingIndex ++;
  8092. }
  8093. while (CurrentBinding != 0);
  8094. if (BindingToUse == 0)
  8095. {
  8096. ASSERT(0);
  8097. // if the transfer syntax approved is none of the transfer syntaxes we suggested
  8098. // this is a protocol error
  8099. return RPC_S_PROTOCOL_ERROR;
  8100. }
  8101. if (CurrentBindingIndex != IndexOfPresentationContextAccepted)
  8102. {
  8103. ASSERT(0);
  8104. // if server did choose a transfer syntax from a different p_cont_elem_t,
  8105. // this is a protocol error
  8106. return RPC_S_PROTOCOL_ERROR;
  8107. }
  8108. // we have suggested multiple syntaxes, and the server picked one of them - record
  8109. // the server preferences. Instead of just setting the preference on the binding
  8110. // the server chose, we need to walk the list, and reset the preferences on the
  8111. // other bindings, to handle mixed cluster scenario case, where the server
  8112. // preferences actually change
  8113. BindingToUse->TransferSyntaxIsServerPreferred();
  8114. CurrentBinding = GetBindingList();
  8115. do
  8116. {
  8117. if (CurrentBinding != BindingToUse)
  8118. CurrentBinding->TransferSyntaxIsNotServerPreferred();
  8119. CurrentBinding = CurrentBinding->GetNextBinding();
  8120. }
  8121. while (CurrentBinding != 0);
  8122. Bindings.AvailableBindingsList = 0;
  8123. if (Bindings.SelectedBinding == NULL)
  8124. {
  8125. Bindings.SelectedBinding = BindingToUse;
  8126. }
  8127. *BindingNegotiated = BindingToUse;
  8128. DispatchTableCallback = BindingToUse->GetDispatchTable();
  8129. }
  8130. return RPC_S_OK;
  8131. }
  8132. OSF_CASSOCIATION::OSF_CASSOCIATION (
  8133. IN DCE_BINDING * DceBinding,
  8134. IN TRANS_INFO *TransInfo,
  8135. IN OUT RPC_STATUS * Status
  8136. ) : AssociationMutex(Status),
  8137. CallIdCounter(1),
  8138. BindHandleCount(1)
  8139. /*++
  8140. Routine Description:
  8141. We construct a OSF_CASSOCIATION object in this routine. This consists
  8142. of initializing some instance variables, and saving the parameters
  8143. away.
  8144. Arguments:
  8145. DceBinding - Supplies the binding information for this association.
  8146. Ownership of this data passes to this object.
  8147. RpcClientInfo - Supplies the information necessary to use the loadable
  8148. transport corresponding to the network interface type used by
  8149. this association.
  8150. --*/
  8151. {
  8152. ALLOCATE_THIS(OSF_CASSOCIATION);
  8153. LogEvent(SU_CASSOC, EV_START, this, 0, 0, 1, 0);
  8154. ObjectType = OSF_CASSOCIATION_TYPE;
  8155. AssocGroupId = 0;
  8156. this->DceBinding = DceBinding;
  8157. this->TransInfo = TransInfo;
  8158. SecondaryEndpoint = 0;
  8159. OpenConnectionCount = 0;
  8160. ConnectionsDoingBindCount = 0;
  8161. fPossibleServerReset = 0;
  8162. ResolverHintInitialized = FALSE;
  8163. DontLinger = FALSE;
  8164. MaintainContext = 0;
  8165. AssociationValid = TRUE;
  8166. FailureCount = 0;
  8167. fMultiplex = mpx_unknown;
  8168. SetReferenceCount(1);
  8169. SavedDrep = 0;
  8170. fIdleConnectionCleanupNeeded = FALSE;
  8171. Linger.fAssociationLingered = FALSE;
  8172. }
  8173. OSF_CASSOCIATION::~OSF_CASSOCIATION (
  8174. )
  8175. {
  8176. OSF_BINDING * Binding;
  8177. DictionaryCursor cursor;
  8178. if (ResolverHintInitialized)
  8179. {
  8180. FreeResolverHint(InqResolverHint());
  8181. }
  8182. if (DceBinding != 0)
  8183. {
  8184. delete DceBinding;
  8185. }
  8186. Bindings.Reset(cursor);
  8187. while ((Binding = Bindings.Next(cursor)))
  8188. delete Binding;
  8189. if ( SecondaryEndpoint != 0 )
  8190. {
  8191. delete SecondaryEndpoint;
  8192. }
  8193. if (fIdleConnectionCleanupNeeded)
  8194. {
  8195. if (InterlockedDecrement(&PeriodicGarbageCollectItems) == 0)
  8196. {
  8197. #if defined (RPC_GC_AUDIT)
  8198. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) PeriodicGarbageCollectItems dropped to 0\n",
  8199. GetCurrentProcessId(), GetCurrentProcessId());
  8200. #endif
  8201. }
  8202. }
  8203. }
  8204. void
  8205. OSF_CASSOCIATION::NotifyConnectionOpen (
  8206. )
  8207. /*++
  8208. Function Name:NotifyConnectionOpen
  8209. Parameters:
  8210. Description:
  8211. Returns:
  8212. --*/
  8213. {
  8214. AssociationMutex.VerifyOwned();
  8215. OpenConnectionCount++;
  8216. LogEvent(SU_CASSOC, EV_INC, this, 0, OpenConnectionCount, 1, 1);
  8217. }
  8218. void
  8219. OSF_CASSOCIATION::NotifyConnectionClosed (
  8220. )
  8221. /*++
  8222. Routine Description:
  8223. This routine is necessary so that we can know when to set the association
  8224. group id back to zero. We do this when no more connections owned by
  8225. this association can possibly be connected with the server.
  8226. --*/
  8227. {
  8228. AssociationMutex.Request();
  8229. ASSERT( OpenConnectionCount > 0 );
  8230. OpenConnectionCount -= 1;
  8231. LogEvent(SU_CASSOC, EV_DEC, this, 0, OpenConnectionCount, 1, 1);
  8232. if ( OpenConnectionCount == 0 )
  8233. {
  8234. if (ConnectionsDoingBindCount == 0)
  8235. {
  8236. LogEvent(SU_CASSOC, EV_NOTIFY, this, ULongToPtr(OpenConnectionCount), 0, 1, 0);
  8237. if (IsValid())
  8238. {
  8239. // don't reset invalid associations
  8240. ResetAssociation();
  8241. }
  8242. }
  8243. else
  8244. {
  8245. if (IsValid())
  8246. {
  8247. // don't signal possible reset on invalid associations - this will
  8248. // cause more retries
  8249. fPossibleServerReset = TRUE;
  8250. }
  8251. }
  8252. }
  8253. AssociationMutex.Clear();
  8254. }
  8255. void
  8256. OSF_CASSOCIATION::NotifyConnectionBindInProgress (
  8257. void
  8258. )
  8259. {
  8260. AssociationMutex.VerifyOwned();
  8261. ConnectionsDoingBindCount ++;
  8262. LogEvent(SU_CASSOC, EV_INC, this, (PVOID)1, ConnectionsDoingBindCount, 1, 1);
  8263. }
  8264. void
  8265. OSF_CASSOCIATION::NotifyConnectionBindCompleted (
  8266. void
  8267. )
  8268. {
  8269. AssociationMutex.VerifyOwned();
  8270. ConnectionsDoingBindCount --;
  8271. LogEvent(SU_CASSOC, EV_DEC, this, (PVOID)1, ConnectionsDoingBindCount, 1, 1);
  8272. if (ConnectionsDoingBindCount == 0)
  8273. {
  8274. if (OpenConnectionCount == 0)
  8275. {
  8276. LogEvent(SU_CASSOC, EV_NOTIFY, this, ULongToPtr(OpenConnectionCount), ConnectionsDoingBindCount, 1, 0);
  8277. if (IsValid())
  8278. {
  8279. // don't reset invalid associations
  8280. ResetAssociation();
  8281. }
  8282. }
  8283. else
  8284. {
  8285. if (IsValid())
  8286. {
  8287. // don't signal possible reset on invalid associations - this will
  8288. // cause more retries
  8289. fPossibleServerReset = FALSE;
  8290. }
  8291. }
  8292. }
  8293. }
  8294. RPC_STATUS
  8295. OSF_CASSOCIATION::ProcessBindAckOrNak (
  8296. IN rpcconn_common * Buffer,
  8297. IN UINT BufferLength,
  8298. IN OSF_CCONNECTION * CConnection,
  8299. IN OSF_CCALL *CCall,
  8300. OUT ULONG *NewGroupId,
  8301. OUT OSF_BINDING **BindingNegotiated,
  8302. OUT FAILURE_COUNT_STATE *fFailureCountExceeded
  8303. )
  8304. /*++
  8305. Routine Description:
  8306. Arguments:
  8307. Buffer - Supplies the buffer containing either the bind_ack, bind_nak,
  8308. or alter_context_resp packet.
  8309. BufferLength - Supplies the length of the buffer, less the length of
  8310. the authorization information.
  8311. CConnection - Supplies the connection from which we received the packet.
  8312. CCall - the call for which the bind is done.
  8313. NewGroupId - if the bind was successful the new association group id
  8314. will be returned.
  8315. BindingNegotiated - The binding that was negotiated in the case of
  8316. success and multiple proposed bindings. Undefined if there is
  8317. failure, or if only one binding was proposed.
  8318. fFailureCountExceeded - if supplied, must be FailureCountUnknown. If
  8319. we got bind failure with reason not specified, and we haven't
  8320. exceeded the failure count, it will be set to
  8321. FailureCountNotExceeded. If we received bind failure with reason
  8322. not specified and the failure count is exceeded, it will be set
  8323. to FailureCountExceeded.
  8324. Return Value:
  8325. RPC_S_OK - The client has successfully bound with the server.
  8326. RPC_S_PROTOCOL_ERROR - The packet received from the server does not
  8327. follow the protocol.
  8328. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to make a
  8329. copy of the secondary endpoint.
  8330. RPC_S_UNSUPPORTED_TRANS_SYN - The transfer syntax supplied by the client
  8331. is not supported by the server.
  8332. RPC_S_UNKNOWN_IF - The interface to which the client wished to bind is not
  8333. supported by the server.
  8334. RPC_S_SERVER_TOO_BUSY - The server is too busy to accept the clients
  8335. bind request.
  8336. RPC_S_UNKNOWN_AUTHN_TYPE - The server does not support the authentication
  8337. type specified by the client.
  8338. --*/
  8339. {
  8340. rpcconn_bind_ack *pBindAck;
  8341. rpcconn_bind_nak *pBindNak;
  8342. p_result_list_t *pResults;
  8343. int port_spec_plus_pad;
  8344. UINT SecondaryEndpointLength;
  8345. unsigned char * Pointer;
  8346. RPC_STATUS Status;
  8347. int NumberOfResultElements;
  8348. int i;
  8349. BOOL fConvertEndian;
  8350. int PresentationContextAccepted;
  8351. if (ARGUMENT_PRESENT(fFailureCountExceeded))
  8352. {
  8353. ASSERT(*fFailureCountExceeded == FailureCountUnknown);
  8354. }
  8355. AssociationMutex.VerifyOwned();
  8356. SavedDrep = (Buffer->drep[0]| (Buffer->drep[1] << 8));
  8357. //
  8358. // The common header of the packet has already been validated and data
  8359. // converted, if necessary, by whoever called this method.
  8360. //
  8361. if ( (Buffer->PTYPE == rpc_bind_ack)
  8362. || (Buffer->PTYPE == rpc_alter_context_resp))
  8363. {
  8364. FailureCount = 0;
  8365. //
  8366. // The bind_ack and alter_context_resp packets are the same.
  8367. //
  8368. pBindAck = (rpcconn_bind_ack *) Buffer;
  8369. //
  8370. // We need to convert the max_xmit_frag, max_recv_frag, and
  8371. // assoc_group_id fields of the packet.
  8372. //
  8373. if ( DataConvertEndian(Buffer->drep) != 0 )
  8374. {
  8375. pBindAck->max_xmit_frag = RpcpByteSwapShort(pBindAck->max_xmit_frag);
  8376. pBindAck->max_recv_frag = RpcpByteSwapShort(pBindAck->max_recv_frag);
  8377. pBindAck->assoc_group_id = RpcpByteSwapLong(pBindAck->assoc_group_id);
  8378. pBindAck->sec_addr_length = RpcpByteSwapShort(pBindAck->sec_addr_length);
  8379. }
  8380. if ( Buffer->PTYPE == rpc_bind_ack )
  8381. {
  8382. if (Buffer->pfc_flags & PFC_CONC_MPX)
  8383. {
  8384. fMultiplex = mpx_yes;
  8385. }
  8386. CConnection->SetMaxFrag(pBindAck->max_xmit_frag,
  8387. pBindAck->max_recv_frag);
  8388. }
  8389. BufferLength -= sizeof(rpcconn_bind_ack);
  8390. Pointer = (unsigned char *) (pBindAck + 1);
  8391. if ( pBindAck->sec_addr_length )
  8392. {
  8393. SecondaryEndpointLength = pBindAck->sec_addr_length;
  8394. //
  8395. // The secondary address length is two bytes long. We want
  8396. // to align the total of the secondary address length itself,
  8397. // the the secondary address. Hence, the length of the secondary
  8398. // address and the necessary pad is calculated below. Think
  8399. // very carefully before changing this piece of code.
  8400. //
  8401. port_spec_plus_pad = SecondaryEndpointLength +
  8402. Pad4(SecondaryEndpointLength + 2);
  8403. if ( BufferLength < (UINT) port_spec_plus_pad )
  8404. {
  8405. return(RPC_S_PROTOCOL_ERROR);
  8406. }
  8407. #if 0
  8408. if ( SecondaryEndpoint != 0 )
  8409. {
  8410. delete SecondaryEndpoint;
  8411. }
  8412. SecondaryEndpoint = new unsigned char[SecondaryEndpointLength];
  8413. if ( SecondaryEndpoint == 0 )
  8414. return(RPC_S_OUT_OF_MEMORY);
  8415. RpcpMemoryCopy(SecondaryEndpoint, Pointer, SecondaryEndpointLength);
  8416. if ( DataConvertCharacter(Buffer->drep) != 0 )
  8417. {
  8418. ConvertStringEbcdicToAscii(SecondaryEndpoint);
  8419. }
  8420. #endif
  8421. BufferLength -= port_spec_plus_pad;
  8422. Pointer = Pointer + port_spec_plus_pad;
  8423. }
  8424. else
  8425. {
  8426. Pointer = Pointer + 2;
  8427. BufferLength -= 2;
  8428. }
  8429. pResults = (p_result_list_t *) Pointer;
  8430. // the buffer must have at least as much results as it claims to have
  8431. NumberOfResultElements = pResults->n_results;
  8432. if (BufferLength < sizeof(p_result_list_t) + sizeof(p_result_t) * (NumberOfResultElements - 1))
  8433. {
  8434. return(RPC_S_PROTOCOL_ERROR);
  8435. }
  8436. PresentationContextAccepted = -1;
  8437. fConvertEndian = DataConvertEndian(Buffer->drep);
  8438. // we walk through the list of elements, and see which ones are accepted, and which
  8439. // ones are rejected. If we have at least one accepted, the bind succeeds. If all are
  8440. // rejected, we arbitrarily pick the first error code and declare it the cause of
  8441. // the failure. Note that according to DCE spec, it is not a protocol error to
  8442. // have a bind ack and no presentation contexts accepted
  8443. for (i = 0; i < NumberOfResultElements; i ++)
  8444. {
  8445. if (fConvertEndian)
  8446. {
  8447. pResults->p_results[i].result = RpcpByteSwapShort(pResults->p_results[i].result);
  8448. pResults->p_results[i].reason = RpcpByteSwapShort(pResults->p_results[i].reason);
  8449. ByteSwapSyntaxId(&(pResults->p_results[i].transfer_syntax));
  8450. }
  8451. if ( pResults->p_results[i].result == acceptance )
  8452. {
  8453. // currently we can handle at most one acceptance. Everything else
  8454. // is a protocol error. This is fine since we know only we will
  8455. // propose NDR64, and any third party should accept at most NDR20
  8456. // Our servers will always choose exactly one
  8457. if (PresentationContextAccepted >= 0)
  8458. return RPC_S_PROTOCOL_ERROR;
  8459. PresentationContextAccepted = i;
  8460. }
  8461. }
  8462. if (PresentationContextAccepted < 0) // faster version of == -1
  8463. {
  8464. if ( pResults->p_results[0].result != provider_rejection )
  8465. {
  8466. return(RPC_S_CALL_FAILED_DNE);
  8467. }
  8468. switch (pResults->p_results[0].reason)
  8469. {
  8470. case abstract_syntax_not_supported:
  8471. return(RPC_S_UNKNOWN_IF);
  8472. case proposed_transfer_syntaxes_not_supported:
  8473. return(RPC_S_UNSUPPORTED_TRANS_SYN);
  8474. case local_limit_exceeded:
  8475. return(RPC_S_SERVER_TOO_BUSY);
  8476. default:
  8477. return(RPC_S_CALL_FAILED_DNE);
  8478. }
  8479. }
  8480. // we have bound successfully. Notify the call so that
  8481. // it can fix what binding it will use
  8482. Status = CCall->BindCompleteNotify(
  8483. &pResults->p_results[PresentationContextAccepted],
  8484. PresentationContextAccepted,
  8485. BindingNegotiated);
  8486. if (Status != RPC_S_OK)
  8487. return Status;
  8488. *NewGroupId = pBindAck->assoc_group_id;
  8489. return RPC_S_OK;
  8490. }
  8491. if (Buffer->PTYPE == rpc_bind_nak)
  8492. {
  8493. if (BufferLength < MinimumBindNakLength)
  8494. {
  8495. RpcpErrorAddRecord (EEInfoGCRuntime,
  8496. RPC_S_PROTOCOL_ERROR,
  8497. EEInfoDLOSF_CASSOCIATION__ProcessBindAckOrNak10,
  8498. (ULONG)BufferLength,
  8499. (ULONG)MinimumBindNakLength);
  8500. return(RPC_S_PROTOCOL_ERROR);
  8501. }
  8502. pBindNak = (rpcconn_bind_nak *) Buffer;
  8503. if ( DataConvertEndian(Buffer->drep) != 0 )
  8504. {
  8505. pBindNak->provider_reject_reason = RpcpByteSwapShort(pBindNak->provider_reject_reason);
  8506. }
  8507. if (pBindNak->common.frag_length > BindNakSizeWithoutEEInfo)
  8508. {
  8509. if (RpcpMemoryCompare(&pBindNak->Signature, BindNakEEInfoSignature, sizeof(UUID)) == 0)
  8510. {
  8511. UnpickleEEInfoFromBuffer(pBindNak->buffer,
  8512. GetEEInfoSizeFromBindNakPacket(pBindNak));
  8513. }
  8514. }
  8515. if ( (pBindNak->provider_reject_reason == temporary_congestion)
  8516. || (pBindNak->provider_reject_reason
  8517. == local_limit_exceeded_reject))
  8518. {
  8519. Status = RPC_S_SERVER_TOO_BUSY;
  8520. }
  8521. else if ( pBindNak->provider_reject_reason
  8522. == protocol_version_not_supported )
  8523. {
  8524. Status = RPC_S_PROTOCOL_ERROR;
  8525. }
  8526. else if ( pBindNak->provider_reject_reason
  8527. == authentication_type_not_recognized )
  8528. {
  8529. Status = RPC_S_UNKNOWN_AUTHN_SERVICE;
  8530. }
  8531. else if ( pBindNak->provider_reject_reason
  8532. == invalid_checksum )
  8533. {
  8534. Status = RPC_S_ACCESS_DENIED;
  8535. }
  8536. else
  8537. {
  8538. FailureCount++;
  8539. if (FailureCount >= 40)
  8540. {
  8541. LogEvent(SU_CASSOC, EV_ABORT, this, 0, FailureCount, 1, 0);
  8542. AssociationValid = FALSE;
  8543. AssociationShutdownError = RPC_S_CALL_FAILED_DNE;
  8544. if (ARGUMENT_PRESENT(fFailureCountExceeded))
  8545. *fFailureCountExceeded = FailureCountExceeded;
  8546. }
  8547. else if (ARGUMENT_PRESENT(fFailureCountExceeded))
  8548. {
  8549. *fFailureCountExceeded = FailureCountNotExceeded;
  8550. }
  8551. Status = RPC_S_CALL_FAILED_DNE;
  8552. }
  8553. RpcpErrorAddRecord(EEInfoGCRuntime,
  8554. Status,
  8555. EEInfoDLOSF_CASSOCIATION__ProcessBindAckOrNak20,
  8556. (ULONG)pBindNak->provider_reject_reason,
  8557. (ULONG)FailureCount);
  8558. return (Status);
  8559. }
  8560. return(RPC_S_PROTOCOL_ERROR);
  8561. }
  8562. void
  8563. OSF_CASSOCIATION::UnBind (
  8564. )
  8565. {
  8566. OSF_CCONNECTION * CConnection;
  8567. BOOL fWillLinger = FALSE;
  8568. DWORD OldestAssociationTimestamp;
  8569. OSF_CASSOCIATION *CurrentAssociation;
  8570. OSF_CASSOCIATION *OldestAssociation = NULL;
  8571. BOOL fEnableGarbageCollection = FALSE;
  8572. DictionaryCursor cursor;
  8573. RPC_CHAR *NetworkAddress;
  8574. long LocalBindHandleCount;
  8575. LogEvent(SU_CASSOC, EV_DEC, this, (PVOID)2, BindHandleCount.GetInteger(), 1, 0);
  8576. LocalBindHandleCount = BindHandleCount.Decrement();
  8577. if (LocalBindHandleCount == 0)
  8578. {
  8579. // we don't linger remote named pipes, as sometimes this results in
  8580. // credentials conflict
  8581. NetworkAddress = DceBinding->InqNetworkAddress();
  8582. if ((OpenConnectionCount > 0)
  8583. &&
  8584. AssocGroupId
  8585. &&
  8586. AssociationValid
  8587. &&
  8588. (!DontLinger)
  8589. &&
  8590. (
  8591. (NetworkAddress == NULL)
  8592. ||
  8593. (NetworkAddress[0] == 0)
  8594. ||
  8595. (!DceBinding->IsNamedPipeTransport())
  8596. )
  8597. )
  8598. {
  8599. if (IsGarbageCollectionAvailable())
  8600. {
  8601. if (OsfLingeredAssociations >= MaxOsfLingeredAssociations)
  8602. {
  8603. OldestAssociationTimestamp = ~(DWORD)0;
  8604. // need to walk the dictionary and clean up the oldest item
  8605. AssociationDict->Reset(cursor);
  8606. while ((CurrentAssociation = AssociationDict->Next(cursor)) != 0)
  8607. {
  8608. if (CurrentAssociation->Linger.fAssociationLingered)
  8609. {
  8610. // yes, if the tick count wraps around, we may make a
  8611. // suboptimal decision and destroy a newer lingering
  8612. // association. That's ok - it will be a slight perf hit once
  8613. // every ~47 days - it won't be a bug
  8614. if (OldestAssociationTimestamp > CurrentAssociation->Linger.Timestamp)
  8615. {
  8616. OldestAssociation = CurrentAssociation;
  8617. }
  8618. }
  8619. }
  8620. // there must be an oldest association here
  8621. ASSERT(OldestAssociation);
  8622. AssociationDict->Delete(OldestAssociation->Key);
  8623. OldestAssociation->Key = -1;
  8624. // no need to update OsfLingeredAssociations - we removed one,
  8625. // but we add one, so the balance is the same
  8626. }
  8627. else
  8628. {
  8629. OsfLingeredAssociations ++;
  8630. ASSERT(OsfLingeredAssociations <= MaxOsfLingeredAssociations);
  8631. }
  8632. Linger.Timestamp = GetTickCount() + gThreadTimeout;
  8633. Linger.fAssociationLingered = TRUE;
  8634. fWillLinger = TRUE;
  8635. // Add one artifical reference. Once we release the AssocDictMutex,
  8636. // a gc thread can come in and nuke the association, and if we
  8637. // decide that we cannot do garbage collecting below and decide
  8638. // to shutdown the association we may land on a freed object
  8639. // CASSOC++
  8640. OSF_CASSOCIATION::AddReference();
  8641. }
  8642. else
  8643. {
  8644. // good association, but can't linger it, because gc is not available
  8645. // let's see if we can turn it on
  8646. OsfDestroyedAssociations ++;
  8647. fEnableGarbageCollection = CheckIfGCShouldBeTurnedOn(
  8648. OsfDestroyedAssociations,
  8649. NumberOfOsfDestroyedAssociationsToSample,
  8650. DestroyedOsfAssociationBatchThreshold,
  8651. &OsfLastDestroyedAssociationsBatchTimestamp
  8652. );
  8653. }
  8654. }
  8655. if (!fWillLinger)
  8656. {
  8657. AssociationDict->Delete(Key);
  8658. }
  8659. AssocDictMutex->Clear();
  8660. if (!fWillLinger)
  8661. {
  8662. AssociationValid = FALSE;
  8663. LogEvent(SU_CASSOC, EV_STOP, this, 0, 0, 1, 0);
  8664. ShutdownRequested(RPC_S_CALL_FAILED_DNE, NULL);
  8665. }
  8666. AssociationMutex.Clear();
  8667. if (OldestAssociation)
  8668. {
  8669. #if defined (RPC_GC_AUDIT)
  8670. int Diff;
  8671. Diff = (int)(GetTickCount() - OldestAssociation->Linger.Timestamp);
  8672. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) OSF association sync gc'ed %d ms after expire\n",
  8673. GetCurrentProcessId(), GetCurrentProcessId(), Diff);
  8674. #endif
  8675. OldestAssociation->AssociationMutex.Request();
  8676. OldestAssociation->AssociationValid = FALSE;
  8677. OldestAssociation->ShutdownRequested(RPC_S_CALL_FAILED_DNE, NULL);
  8678. OldestAssociation->AssociationMutex.Clear();
  8679. OldestAssociation->OSF_CASSOCIATION::RemoveReference();
  8680. }
  8681. if (!fWillLinger)
  8682. {
  8683. // CASSOC--
  8684. OSF_CASSOCIATION::RemoveReference();
  8685. // N.B. If fWillLinger is FALSE, don't touch the this pointer
  8686. // after here
  8687. }
  8688. if (fEnableGarbageCollection)
  8689. {
  8690. // ignore the return value - we'll make a best effort to
  8691. // create the thread, but if there's no memory, that's
  8692. // still ok as the garbage collection thread only
  8693. // provides better perf in this case
  8694. (void) CreateGarbageCollectionThread();
  8695. }
  8696. if (fWillLinger)
  8697. {
  8698. fWillLinger = GarbageCollectionNeeded(TRUE, gThreadTimeout);
  8699. if (fWillLinger == FALSE)
  8700. {
  8701. // uh-oh - we couldn't register for garbage collection - probably
  8702. // extremely low on memory. If nobody has picked us up in the meantime,
  8703. // delete this association. Otherwise, let it go - somebody is using
  8704. // it and we don't need to worry about gc'ing it. We also need to guard
  8705. // against the gc thread trying to do Delete on this also. If it does
  8706. // so, it will set the Key to -1 before it releases
  8707. // the mutex - therefore we can check for this. A gc thread cannot
  8708. // completely kill the object as we will hold one reference on it
  8709. AssocDictMutex->Request();
  8710. if ((Linger.fAssociationLingered) && (Key != -1))
  8711. {
  8712. OsfLingeredAssociations --;
  8713. ASSERT(OsfLingeredAssociations >= 0);
  8714. AssociationDict->Delete(Key);
  8715. Key = -1;
  8716. AssociationShutdownError = RPC_S_CALL_FAILED_DNE;
  8717. AssociationValid = FALSE;
  8718. AssocDictMutex->Clear();
  8719. LogEvent(SU_CASSOC, EV_STOP, this, 0, 0, 1, 0);
  8720. ShutdownRequested(RPC_S_CALL_FAILED_DNE, NULL);
  8721. // CASSOC--
  8722. OSF_CASSOCIATION::RemoveReference();
  8723. }
  8724. else
  8725. {
  8726. AssocDictMutex->Clear();
  8727. }
  8728. }
  8729. #if defined (RPC_GC_AUDIT)
  8730. else
  8731. {
  8732. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) OSF association lingered %X\n",
  8733. GetCurrentProcessId(), GetCurrentProcessId(), this);
  8734. }
  8735. #endif
  8736. // Remove the artifical reference we added above
  8737. // CASSOC--
  8738. OSF_CASSOCIATION::RemoveReference();
  8739. // N.B. don't touch the this pointer after here
  8740. }
  8741. }
  8742. else
  8743. {
  8744. AssocDictMutex->Clear();
  8745. AssociationMutex.Clear();
  8746. }
  8747. }
  8748. RPC_STATUS
  8749. OSF_CASSOCIATION::FindOrCreateOsfBinding (
  8750. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
  8751. IN RPC_MESSAGE *Message,
  8752. OUT int *NumberOfBindings,
  8753. IN OUT OSF_BINDING *BindingsForThisInterface[]
  8754. )
  8755. /*++
  8756. Routine Description:
  8757. This method gets called to find the osf bindings (a dictionary
  8758. entry) corresponding to the specified rpc interface information.
  8759. The caller of this routine must be holding (ie. requested) the
  8760. association mutex.
  8761. Arguments:
  8762. RpcInterfaceInformation - Supplies the interface information for
  8763. which we are looking for an osf binding object.
  8764. Message - supplies the RPC_MESSAGE for this call
  8765. NumberOfBindings - an out parameter that will return the number
  8766. of retrieved bindings
  8767. BindingsForThisInterface - a caller supplied array where the
  8768. found bindings will be placed.
  8769. Return Value:
  8770. RPC_S_OK for success, other for failure
  8771. --*/
  8772. {
  8773. BOOL Ignored[MaximumNumberOfTransferSyntaxes];
  8774. AssociationMutex.VerifyOwned();
  8775. return MTSyntaxBinding::FindOrCreateBinding(RpcInterfaceInformation,
  8776. Message, &Bindings, CreateOsfBinding, NumberOfBindings,
  8777. (MTSyntaxBinding **)BindingsForThisInterface, Ignored);
  8778. }
  8779. BOOL
  8780. OSF_CASSOCIATION::DoesBindingForInterfaceExist (
  8781. IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation
  8782. )
  8783. /*++
  8784. Routine Description:
  8785. Checks if an association supports a binding for this interface.
  8786. Arguments:
  8787. RpcInterfaceInformation - Supplies the interface information for
  8788. which we are looking for an osf binding object.
  8789. Return Value:
  8790. FALSE if it doesn't. Non-zero if it does.
  8791. --*/
  8792. {
  8793. OSF_BINDING *Binding;
  8794. DictionaryCursor cursor;
  8795. BOOL fRetVal = FALSE;
  8796. BOOL Result;
  8797. // if we are not in lsa, just ask for the mutex. If we are (or may be)
  8798. // we have some more work to do. We can't directly ask for the mutex
  8799. // since we may deadlock. In lsa the security providers can make RPC
  8800. // calls from within the security context establishment routine. If
  8801. // they do, they will hold an association mutex, and ask for the
  8802. // association dict mutex within the inner RPC call. This thread
  8803. // already holds the assoc dict mutex and will ask for the assoc
  8804. // mutex (reverse order) causing a deadlock. Since this routine
  8805. // is used only to shortcut remote endpoint resolution, and as
  8806. // optimization, in lsa, if we can't get the mutex, we forego the
  8807. // optimization and return not found. This will cause caller to
  8808. // do remote endpoint resolution
  8809. if (!fMaybeLsa)
  8810. {
  8811. AssociationMutex.Request();
  8812. }
  8813. else
  8814. {
  8815. Result = AssociationMutex.TryRequest();
  8816. if (!Result)
  8817. return FALSE;
  8818. }
  8819. Bindings.Reset(cursor);
  8820. while ((Binding = Bindings.Next(cursor)) != 0)
  8821. {
  8822. // if we have a binding on the same interface,
  8823. // return TRUE
  8824. if (RpcpMemoryCompare(Binding->GetInterfaceId(),
  8825. &RpcInterfaceInformation->InterfaceId,
  8826. sizeof(RPC_SYNTAX_IDENTIFIER)) == 0)
  8827. {
  8828. fRetVal = TRUE;
  8829. break;
  8830. }
  8831. }
  8832. AssociationMutex.Clear();
  8833. return fRetVal;
  8834. }
  8835. void
  8836. OSF_CASSOCIATION::ShutdownRequested (
  8837. IN RPC_STATUS AssociationShutdownError OPTIONAL,
  8838. IN OSF_CCONNECTION *ExemptConnection OPTIONAL
  8839. )
  8840. /*++
  8841. Routine Description:
  8842. Aborts all connections in the association, except the Exempt
  8843. connection, and marks the association as invalid.
  8844. Arguments:
  8845. AssociationShutdownError - the error with which the association
  8846. is to be shutdown
  8847. ExemptConnection - an optional pointer to a connection which
  8848. is not to be aborted.
  8849. --*/
  8850. {
  8851. OSF_CCONNECTION * CConnection;
  8852. DictionaryCursor cursor;
  8853. BOOL fDontKill;
  8854. BOOL fExemptConnectionSkipped = FALSE;
  8855. AssociationMutex.Request();
  8856. if (!ExemptConnection)
  8857. {
  8858. ASSERT(AssociationShutdownError != RPC_S_OK);
  8859. LogEvent(SU_CASSOC, EV_STOP, this, 0, 0, 1, 0);
  8860. // we will abort all connections - the association is invalid
  8861. // mark it as such
  8862. AssociationValid = FALSE;
  8863. this->AssociationShutdownError = AssociationShutdownError;
  8864. }
  8865. ActiveConnections.Reset(cursor);
  8866. while ((CConnection = ActiveConnections.Next(cursor)) != NULL)
  8867. {
  8868. if (CConnection == ExemptConnection)
  8869. {
  8870. fExemptConnectionSkipped = TRUE;
  8871. continue;
  8872. }
  8873. fDontKill = ConnectionAborted(CConnection);
  8874. if (fDontKill == FALSE)
  8875. {
  8876. // CCONN++
  8877. CConnection->AddReference();
  8878. CConnection->DeleteConnection();
  8879. // CCONN--
  8880. CConnection->RemoveReference();
  8881. }
  8882. }
  8883. if (ExemptConnection)
  8884. {
  8885. ASSERT(fExemptConnectionSkipped);
  8886. }
  8887. // if at least one connection wasn't aborted, the association
  8888. // is still valid - it just needs resetting
  8889. if (ExemptConnection)
  8890. ResetAssociation();
  8891. AssociationMutex.Clear();
  8892. }
  8893. RPC_STATUS
  8894. OSF_CASSOCIATION::ToStringBinding (
  8895. OUT RPC_CHAR * * StringBinding,
  8896. IN RPC_UUID * ObjectUuid
  8897. )
  8898. /*++
  8899. Routine Description:
  8900. We need to convert the binding handle into a string binding. If the
  8901. binding handle has not yet been used to make a remote procedure
  8902. call, then we can just use the information in the binding handle to
  8903. create the string binding. Otherwise, we need to ask the association
  8904. to do it for us.
  8905. Arguments:
  8906. StringBinding - Returns the string representation of the binding
  8907. handle.
  8908. ObjectUuid - Supplies the object uuid of the binding handle which
  8909. is requesting that we create a string binding.
  8910. Return Value:
  8911. RPC_S_OK - The operation completed successfully.
  8912. RPC_S_OUT_OF_MEMORY - We do not have enough memory available to
  8913. allocate space for the string binding.
  8914. --*/
  8915. {
  8916. *StringBinding = DceBinding->StringBindingCompose(ObjectUuid);
  8917. if (*StringBinding == 0)
  8918. return(RPC_S_OUT_OF_MEMORY);
  8919. return(RPC_S_OK);
  8920. }
  8921. int
  8922. OSF_CASSOCIATION::CompareWithDceBinding (
  8923. IN DCE_BINDING * DceBinding,
  8924. OUT BOOL *fOnlyEndpointDifferent
  8925. )
  8926. /*++
  8927. Routine Description:
  8928. This routine compares the specified binding information with the
  8929. binding information in the object, this.
  8930. Arguments:
  8931. DceBinding - Supplies the binding information to compare against
  8932. the binding information in this.
  8933. fOnlyEndpointDiffers - this output variable will be set to TRUE
  8934. if the result is non-zero and only the endpoint is different.
  8935. It will be set to FALSE if the result is non-zero, and there
  8936. is more than the endpoint different. If this function returns
  8937. 0, the fOnlyEndpointDiffers argument is undefined.
  8938. Return Value:
  8939. Zero will be returned if the specified binding information,
  8940. DceBinding, is the same as in this. Otherwise, non-zero will be
  8941. returned.
  8942. --*/
  8943. {
  8944. int Result;
  8945. if ((Result = this->DceBinding->Compare(DceBinding, fOnlyEndpointDifferent)) != 0)
  8946. return(Result);
  8947. return(0);
  8948. }
  8949. OSF_CCONNECTION *
  8950. OSF_CASSOCIATION::FindIdleConnection (
  8951. void
  8952. )
  8953. /*++
  8954. Routine Description:
  8955. This routine is used to find a connection which has been idle more
  8956. than the minimum number of seconds specified. If one is found, it
  8957. is removed from the set of free connections and returned. The
  8958. association dict mutex will be held when this routine is called.
  8959. Arguments:
  8960. Return Value:
  8961. If one or more idle connections are found, the first will be returned. Next
  8962. connections can be retrieved by following the u.NextConnection link until
  8963. NULL is reached; if no connections are idle, NULL will be returned.
  8964. --*/
  8965. {
  8966. OSF_CCONNECTION *CConnection;
  8967. OSF_CCONNECTION *FirstConnection;
  8968. BOOL fMutexTaken;
  8969. BOOL fThreadCreated = 0;
  8970. DictionaryCursor cursor;
  8971. ULONG TickCount;
  8972. ULONG ClientDisconnectTime;
  8973. #if defined (RPC_IDLE_CLEANUP_AUDIT)
  8974. ULONG ConnectionsPickedForCleanup = 0;
  8975. #endif
  8976. //
  8977. // If we need to maintain context with server, we do not want to close
  8978. // the last open connection. To be on the safe side, we will make
  8979. // sure that there is at least one free connection.
  8980. //
  8981. fMutexTaken = AssociationMutex.TryRequest();
  8982. if (!fMutexTaken)
  8983. {
  8984. #if defined (RPC_IDLE_CLEANUP_AUDIT)
  8985. DbgPrintEx(77, DPFLTR_ERROR_LEVEL, "%d (0x%X) Association mutex busy - aborting\n",
  8986. GetCurrentProcessId(), GetCurrentProcessId());
  8987. #endif
  8988. return NULL;
  8989. }
  8990. if ( ActiveConnections.Size() <= 1 )
  8991. {
  8992. if ( (MaintainContext != 0) || (ActiveConnections.Size() == 0))
  8993. {
  8994. ClearIdleConnectionCleanupFlag();
  8995. AssociationMutex.Clear();
  8996. return(0);
  8997. }
  8998. }
  8999. FirstConnection = NULL;
  9000. if (ActiveConnections.Size() > AGGRESSIVE_TIMEOUT_THRESHOLD)
  9001. {
  9002. ClientDisconnectTime = CLIENT_DISCONNECT_TIME2;
  9003. }
  9004. else
  9005. {
  9006. ClientDisconnectTime = CLIENT_DISCONNECT_TIME1;
  9007. }
  9008. #if defined (RPC_IDLE_CLEANUP_AUDIT)
  9009. DbgPrintEx(77, DPFLTR_ERROR_LEVEL, "%d (0x%X) Dictionary size for assoc %p is %d. Using timeout %d\n",
  9010. GetCurrentProcessId(), GetCurrentProcessId(), this, ActiveConnections.Size(), ClientDisconnectTime);
  9011. #endif
  9012. ActiveConnections.Reset(cursor);
  9013. while ( (CConnection = ActiveConnections.Next(cursor)) != 0 )
  9014. {
  9015. if (CConnection->ThreadId == SYNC_CONN_FREE
  9016. || CConnection->ThreadId == ASYNC_CONN_FREE)
  9017. {
  9018. TickCount = NtGetTickCount();
  9019. if ( CConnection->InquireLastTimeUsed() == 0 )
  9020. {
  9021. CConnection->SetLastTimeUsedToNow();
  9022. }
  9023. // TickCount is ULONG and InquireLastTimeUsed is ULONG
  9024. // If the tick count has wrapped, the result will still
  9025. // be valid. Note that even though it is not technically
  9026. // impossible that the cleanup is not called for ~47
  9027. // days, and the next time we're called the connection
  9028. // looks like just used, a call after that will still
  9029. // timeout and destroy the connection. If the caller has
  9030. // waited for 47 days, it will wait for 30 more seconds.
  9031. else if ( TickCount - CConnection->InquireLastTimeUsed()
  9032. > ClientDisconnectTime )
  9033. {
  9034. if (!fThreadCreated)
  9035. {
  9036. RPC_STATUS Status;
  9037. Status = TransInfo->CreateThread();
  9038. if (Status != RPC_S_OK)
  9039. {
  9040. AssociationMutex.Clear();
  9041. return (0);
  9042. }
  9043. fThreadCreated = 1;
  9044. }
  9045. // link all obtained connections on a list
  9046. CConnection->u.NextConnection = FirstConnection;
  9047. FirstConnection = CConnection;
  9048. //
  9049. // This reference will be removed by OsfDeleteIdleConnections, CCONN++
  9050. //
  9051. CConnection->AddReference();
  9052. // remove the connection from the association dictionary so that nobody
  9053. // picks it up
  9054. ConnectionAborted(CConnection);
  9055. #if defined (RPC_IDLE_CLEANUP_AUDIT)
  9056. ConnectionsPickedForCleanup ++;
  9057. #endif
  9058. // are we up to the last connection?
  9059. if ((ActiveConnections.Size() <= 1) && (MaintainContext != 0))
  9060. break;
  9061. }
  9062. }
  9063. }
  9064. AssociationMutex.Clear();
  9065. #if defined (RPC_IDLE_CLEANUP_AUDIT)
  9066. DbgPrintEx(77, DPFLTR_ERROR_LEVEL, "%d (0x%X) Assoc %p - %d connections picked for cleanup\n",
  9067. GetCurrentProcessId(), GetCurrentProcessId(), this, ConnectionsPickedForCleanup);
  9068. #endif
  9069. return(FirstConnection);
  9070. }
  9071. void
  9072. OSF_CCONNECTION::OsfDeleteIdleConnections (
  9073. void
  9074. )
  9075. /*++
  9076. Routine Description:
  9077. This routine will be called to delete connections which have been
  9078. idle for a certain amount of time. We need to be careful of a couple
  9079. of things in writing this routine:
  9080. (1) We dont want to grab the global mutex for too long, because this
  9081. will prevent threads which are trying to do real work from doing
  9082. it.
  9083. (2) We dont want to be holding the global mutex when we delete the
  9084. connection.
  9085. --*/
  9086. {
  9087. OSF_CASSOCIATION *Association;
  9088. OSF_CCONNECTION *FirstConnection;
  9089. OSF_CCONNECTION *CurrentConnection;
  9090. OSF_CCONNECTION *NextConnection;
  9091. BOOL fMutexTaken;
  9092. DictionaryCursor cursor;
  9093. ULONG ClientDisconnectTime;
  9094. #if defined (RPC_IDLE_CLEANUP_AUDIT)
  9095. DbgPrintEx(77, DPFLTR_ERROR_LEVEL, "%d (0x%X) Attempting OSF garbage collection\n",
  9096. GetCurrentProcessId(), GetCurrentProcessId());
  9097. #endif
  9098. fMutexTaken = AssocDictMutex->TryRequest();
  9099. if (!fMutexTaken)
  9100. {
  9101. #if defined (RPC_IDLE_CLEANUP_AUDIT)
  9102. DbgPrintEx(77, DPFLTR_ERROR_LEVEL, "%d (0x%X) Association dict mutex busy - aborting\n",
  9103. GetCurrentProcessId(), GetCurrentProcessId());
  9104. #endif
  9105. return;
  9106. }
  9107. AssociationDict->Reset(cursor);
  9108. while ( (Association = AssociationDict->Next(cursor)) != 0 )
  9109. {
  9110. //
  9111. // The architecture says that the client should disconnect
  9112. // connections which have been idle too long.
  9113. //
  9114. FirstConnection = Association->FindIdleConnection();
  9115. if (FirstConnection != 0)
  9116. {
  9117. AssocDictMutex->Clear();
  9118. CurrentConnection = FirstConnection;
  9119. while (CurrentConnection != NULL)
  9120. {
  9121. NextConnection = CurrentConnection->u.NextConnection;
  9122. Association->ConnectionAborted(CurrentConnection);
  9123. CurrentConnection->DeleteConnection();
  9124. // CCONN--
  9125. CurrentConnection->RemoveReference();
  9126. CurrentConnection = NextConnection;
  9127. }
  9128. fMutexTaken = AssocDictMutex->TryRequest();
  9129. if (!fMutexTaken)
  9130. return;
  9131. }
  9132. }
  9133. AssocDictMutex->Clear();
  9134. }
  9135. RPC_STATUS
  9136. OSF_CCONNECTION::TurnOnOffKeepAlives (
  9137. IN BOOL TurnOn,
  9138. IN ULONG Time
  9139. )
  9140. /*++
  9141. Routine Description:
  9142. Turns on or off keepalives for the given connection
  9143. Arguments:
  9144. TurnOn - if non-zero, keep alives will be turned on with
  9145. a value appropriate for this transport. If zero, keep
  9146. alives will be turned off
  9147. Timeout - if TurnOn is not zero, the time scale after which
  9148. to turn on keep alives. If TurnOn is zero this parameter
  9149. is ignored. The time scale is in runtime unitsd -
  9150. RPC_C_BINDING_MIN_TIMEOUT to RPC_C_BINDING_MAX_TIMEOUT
  9151. Return Value:
  9152. RPC_S_OK if the transport supports keep alives
  9153. RPC_S_CANNOT_SUPPORT otherwise
  9154. --*/
  9155. {
  9156. KEEPALIVE_TIMEOUT uTime;
  9157. uTime.RuntimeUnits = Time;
  9158. if (ClientInfo->TurnOnOffKeepAlives)
  9159. {
  9160. // While turning on the keepalive we need to protect the IO
  9161. // against connection closure.
  9162. return ClientInfo->TurnOnOffKeepAlives(TransConnection(),
  9163. TurnOn,
  9164. TRUE,
  9165. tuRuntime,
  9166. uTime);
  9167. }
  9168. else
  9169. {
  9170. return RPC_S_CANNOT_SUPPORT;
  9171. }
  9172. }
  9173. void
  9174. OSF_CASSOCIATION::OsfDeleteLingeringAssociations (
  9175. void
  9176. )
  9177. /*++
  9178. Routine Description:
  9179. Will attempt to clean up lingering conn associations.
  9180. Return Value:
  9181. --*/
  9182. {
  9183. BOOL fMutexTaken;
  9184. OSF_CASSOCIATION *CurrentAssociation;
  9185. OSF_CASSOCIATION *NextAssociation;
  9186. OSF_CASSOCIATION *FirstAssociation;
  9187. DictionaryCursor cursor;
  9188. DWORD CurrentTickCount;
  9189. int Diff;
  9190. // if there are no osf associations, return
  9191. if (!AssociationDict)
  9192. return;
  9193. fMutexTaken = AssocDictMutex->TryRequest();
  9194. if (!fMutexTaken)
  9195. {
  9196. // we couldn't cleanup anything - restore the flag
  9197. if (!GarbageCollectionRequested)
  9198. GarbageCollectionRequested = TRUE;
  9199. return;
  9200. }
  9201. FirstAssociation = NULL;
  9202. CurrentTickCount = GetTickCount();
  9203. // need to walk the dictionary and clean up all associations with
  9204. // expired timeouts
  9205. AssociationDict->Reset(cursor);
  9206. while ((CurrentAssociation = AssociationDict->Next(cursor)) != 0)
  9207. {
  9208. if (CurrentAssociation->Linger.fAssociationLingered)
  9209. {
  9210. // this will work even for wrapped tick count
  9211. Diff = (int)(CurrentTickCount - CurrentAssociation->Linger.Timestamp);
  9212. if (Diff > 0)
  9213. {
  9214. #if defined (RPC_GC_AUDIT)
  9215. DbgPrintEx(77, DPFLTR_WARNING_LEVEL, "%d (0x%X) OSF association gc'ed %d ms after expire\n",
  9216. GetCurrentProcessId(), GetCurrentProcessId(), Diff);
  9217. #endif
  9218. // enlink the expired associations to a list - we'll clean it up
  9219. // later
  9220. CurrentAssociation->NextAssociation = FirstAssociation;
  9221. FirstAssociation = CurrentAssociation;
  9222. AssociationDict->Delete(CurrentAssociation->Key);
  9223. // indicate to the other threads (needed once we release the mutex)
  9224. // that this association is being cleaned up and they cannot clean it up
  9225. CurrentAssociation->Key = -1;
  9226. OsfLingeredAssociations --;
  9227. // Add one artificial reference to the association. This will
  9228. // prevent a thread that is doing unbind and lingered the
  9229. // association, but later found out it couldn't destroy it
  9230. // (see OSF_CASSOCIATION::UnBind) from deleteing the object
  9231. // from underneath us
  9232. // CASSOC++
  9233. CurrentAssociation->OSF_CASSOCIATION::AddReference();
  9234. }
  9235. else
  9236. {
  9237. // this item hasn't expired yet - update the first gc time, and
  9238. // raise the GarbageCollectionRequested flag if necessary
  9239. if ((int)(CurrentAssociation->Linger.Timestamp - NextOneTimeCleanup) < 0)
  9240. {
  9241. // there is a race between this thread and threads calling
  9242. // GarbageCollectionNeeded. Those threads may overwrite the
  9243. // value we're about to write, which can result in delayed
  9244. // garbage collection for this value - that's ok.
  9245. NextOneTimeCleanup = CurrentAssociation->Linger.Timestamp;
  9246. }
  9247. if (!GarbageCollectionRequested)
  9248. GarbageCollectionRequested = TRUE;
  9249. }
  9250. }
  9251. }
  9252. AssocDictMutex->Clear();
  9253. // destroy the associations at our leasure
  9254. CurrentAssociation = FirstAssociation;
  9255. while (CurrentAssociation != NULL)
  9256. {
  9257. CurrentAssociation->AssociationMutex.Request();
  9258. NextAssociation = CurrentAssociation->NextAssociation;
  9259. CurrentAssociation->AssociationValid = FALSE;
  9260. CurrentAssociation->ShutdownRequested(RPC_S_CALL_FAILED_DNE, NULL);
  9261. CurrentAssociation->AssociationMutex.Clear();
  9262. // Remove the artificial reference we added above
  9263. // CASSOC--
  9264. CurrentAssociation->OSF_CASSOCIATION::RemoveReference();
  9265. CurrentAssociation->OSF_CASSOCIATION::RemoveReference();
  9266. CurrentAssociation = NextAssociation;
  9267. }
  9268. }
  9269. int
  9270. InitializeRpcProtocolOfsClient (
  9271. )
  9272. /*++
  9273. Routine Description:
  9274. We perform loadtime initialization necessary for the code in this
  9275. file. In particular, it means we allocate the association dictionary
  9276. and the association dictionary mutex.
  9277. Return Value:
  9278. Zero will be returned if initialization completes successfully;
  9279. otherwise, non-zero will be returned.
  9280. --*/
  9281. {
  9282. RPC_STATUS Status = RPC_S_OK;
  9283. AssocDictMutex = new MUTEX(&Status,
  9284. TRUE // pre-allocate semaphore
  9285. );
  9286. if (AssocDictMutex == 0
  9287. || Status != RPC_S_OK)
  9288. {
  9289. delete AssocDictMutex;
  9290. return 1;
  9291. }
  9292. AssociationDict = new OSF_CASSOCIATION_DICT;
  9293. if (AssociationDict == 0)
  9294. {
  9295. delete AssocDictMutex;
  9296. return(1);
  9297. }
  9298. return(0);
  9299. }
  9300. RPC_STATUS
  9301. OsfMapRpcProtocolSequence (
  9302. IN BOOL ServerSideFlag,
  9303. IN RPC_CHAR * RpcProtocolSequence,
  9304. OUT TRANS_INFO * *ClientTransInfo
  9305. )
  9306. /*++
  9307. Routine Description:
  9308. This routine is used to determine whether a given rpc protocol sequence
  9309. is supported, and to get a pointer to the transport interface, so we
  9310. do not have to keep looking it up.
  9311. Arguments:
  9312. RpcProtocolSequence - Supplies the rpc protocol sequence.
  9313. A pointer to the transport interface is returned. This pointer
  9314. must not be dereferenced by the caller.
  9315. Return Value:
  9316. RPC_S_OK - The rpc protocol sequence is supported.
  9317. RPC_S_PROTSEQ_NOT_SUPPORTED - The rpc protocol sequence is
  9318. not supported.
  9319. RPC_S_OUT_OF_MEMORY - There is insufficient memory to perform
  9320. the operation.
  9321. --*/
  9322. {
  9323. RPC_CHAR * DllName;
  9324. RPC_STATUS Status;
  9325. Status= RpcConfigMapRpcProtocolSequence(ServerSideFlag,
  9326. RpcProtocolSequence,
  9327. &DllName);
  9328. if (Status != RPC_S_OK)
  9329. {
  9330. return Status;
  9331. }
  9332. Status = LoadableTransportInfo(DllName,
  9333. RpcProtocolSequence,
  9334. ClientTransInfo);
  9335. delete DllName;
  9336. return(Status);
  9337. }
  9338. BINDING_HANDLE *
  9339. OsfCreateBindingHandle (
  9340. )
  9341. /*++
  9342. Routine Description:
  9343. This routine does exactly one thing: it creates a binding handle of
  9344. the appropriate type for the osf connection protocol module.
  9345. Return Value:
  9346. A new binding handle will be returned. Zero will be returned if
  9347. insufficient memory is available to create the binding handle.
  9348. --*/
  9349. {
  9350. BINDING_HANDLE * BindingHandle;
  9351. RPC_STATUS Status = RPC_S_OK;
  9352. BindingHandle = new OSF_BINDING_HANDLE(&Status);
  9353. if ( Status != RPC_S_OK )
  9354. {
  9355. delete BindingHandle;
  9356. return(0);
  9357. }
  9358. return(BindingHandle);
  9359. }
  9360. extern "C" {
  9361. RPC_STATUS RPC_ENTRY
  9362. OsfTowerConstruct(
  9363. IN char * ProtocolSeq,
  9364. IN char * Endpoint,
  9365. IN char * NetworkAddress,
  9366. OUT unsigned short * Floors,
  9367. OUT ULONG * ByteCount,
  9368. OUT unsigned char * * Tower
  9369. )
  9370. /*++
  9371. Routine Description:
  9372. This routine constructs and returns the upper floors of a tower.
  9373. It invokes the appropriate loadable transport and has them construct
  9374. it.
  9375. Return Value:
  9376. --*/
  9377. {
  9378. TRANS_INFO *ClientTransInfo;
  9379. RPC_STATUS Status = RPC_S_OK;
  9380. #ifdef UNICODE
  9381. CStackUnicode Pseq;
  9382. USES_CONVERSION;
  9383. #else
  9384. RPC_CHAR * Pseq;
  9385. #endif
  9386. #ifdef UNICODE
  9387. ATTEMPT_STACK_A2W(Pseq, ProtocolSeq);
  9388. #else
  9389. Pseq = (RPC_CHAR * )ProtocolSeq;
  9390. #endif
  9391. if (Status == RPC_S_OK)
  9392. {
  9393. Status = OsfMapRpcProtocolSequence( 0,
  9394. Pseq,
  9395. &ClientTransInfo);
  9396. }
  9397. if (Status == RPC_S_OK)
  9398. {
  9399. Status = ClientTransInfo->InqTransInfo()->TowerConstruct( ProtocolSeq,
  9400. NetworkAddress,
  9401. Endpoint,
  9402. Floors,
  9403. ByteCount,
  9404. Tower);
  9405. }
  9406. return(Status);
  9407. }
  9408. RPC_STATUS RPC_ENTRY
  9409. OsfTowerExplode(
  9410. IN unsigned char * Tower,
  9411. OUT char * * Protseq,
  9412. OUT char * * Endpoint,
  9413. OUT char * * NWAddress
  9414. )
  9415. /*++
  9416. Routine Description:
  9417. This routine accepts upper floors of a tower [Floor 3 onwards]
  9418. It invokes the appropriate loadable transport based on the opcode
  9419. it finds in level 3 to return protocol sequence, endpoint and nwaddress.
  9420. Return Value:
  9421. --*/
  9422. {
  9423. RPC_STATUS Status;
  9424. unsigned short TransportId;
  9425. unsigned char * Id;
  9426. unsigned char * ProtocolSequence;
  9427. TRANS_INFO *ClientTransInfo;
  9428. #ifdef UNICODE
  9429. CStackUnicode Pseq;
  9430. USES_CONVERSION;
  9431. #else
  9432. RPC_CHAR * Pseq;
  9433. #endif
  9434. Id = (Tower + sizeof(unsigned short));
  9435. TransportId = (0x00FF & *Id);
  9436. ClientTransInfo = GetLoadedClientTransportInfoFromId(TransportId);
  9437. if (ClientTransInfo != 0)
  9438. {
  9439. Status = ClientTransInfo->InqTransInfo()->TowerExplode(
  9440. Tower,
  9441. Protseq,
  9442. NWAddress,
  9443. Endpoint);
  9444. return(Status);
  9445. }
  9446. #ifndef UNICODE
  9447. Status = RpcGetWellKnownTransportInfo(TransportId, &Pseq);
  9448. #else
  9449. Status = RpcGetWellKnownTransportInfo(TransportId, Pseq.GetPUnicodeString());
  9450. #endif
  9451. if (Status != RPC_S_OK)
  9452. {
  9453. Status = RpcGetAdditionalTransportInfo(TransportId, &ProtocolSequence);
  9454. if (Status == RPC_S_OK)
  9455. {
  9456. #ifdef UNICODE
  9457. ATTEMPT_STACK_A2W(Pseq, ProtocolSequence);
  9458. #else
  9459. Pseq = (RPC_CHAR *) ProtocolSequence;
  9460. #endif
  9461. }
  9462. else
  9463. {
  9464. return (Status);
  9465. }
  9466. }
  9467. Status = OsfMapRpcProtocolSequence(0,
  9468. Pseq,
  9469. &ClientTransInfo);
  9470. if (Status == RPC_S_OK)
  9471. {
  9472. ASSERT(ClientTransInfo != 0);
  9473. Status = ClientTransInfo->InqTransInfo()->TowerExplode(
  9474. Tower,
  9475. Protseq,
  9476. NWAddress,
  9477. Endpoint);
  9478. }
  9479. return(Status);
  9480. }
  9481. } // extern "C"
  9482. RPC_STATUS SetAuthInformation (
  9483. IN RPC_BINDING_HANDLE BindingHandle,
  9484. IN CLIENT_AUTH_INFO *AuthInfo
  9485. )
  9486. /*++
  9487. Routine Description:
  9488. Sets the auth info for a binding handle. Caller must take
  9489. care to pass only OSF binding handles. Transport credentials
  9490. are set, but normal are not (on purpose).
  9491. Arguments:
  9492. BindingHandle - the binding handle on which to set auth info.
  9493. AuthInfo - the auth info to set.
  9494. Return Value:
  9495. RPC_S_OK or RPC_S_* for error
  9496. --*/
  9497. {
  9498. OSF_BINDING_HANDLE *OsfBindingHandle;
  9499. SEC_WINNT_AUTH_IDENTITY_W *NewAuthIdentity;
  9500. RPC_HTTP_TRANSPORT_CREDENTIALS_W *HttpCredentials;
  9501. RPC_STATUS Status;
  9502. OsfBindingHandle = (OSF_BINDING_HANDLE *)BindingHandle;
  9503. // the only non-trivial piece to copy is the transport credentials
  9504. // since they are encrypted in memory
  9505. if (AuthInfo->AdditionalTransportCredentialsType == RPC_C_AUTHN_INFO_TYPE_HTTP)
  9506. {
  9507. ASSERT(AuthInfo->AdditionalCredentials);
  9508. HttpCredentials = (RPC_HTTP_TRANSPORT_CREDENTIALS_W *)AuthInfo->AdditionalCredentials;
  9509. HttpCredentials = DuplicateHttpTransportCredentials(HttpCredentials);
  9510. if (HttpCredentials == NULL)
  9511. return RPC_S_OUT_OF_MEMORY;
  9512. if (HttpCredentials->TransportCredentials)
  9513. {
  9514. Status = DecryptAuthIdentity(HttpCredentials->TransportCredentials);
  9515. if (Status != RPC_S_OK)
  9516. {
  9517. // on failure the credentials will be wiped out already by
  9518. // DecryptAuthIdentity. Just free the credentials
  9519. FreeHttpTransportCredentials (HttpCredentials);
  9520. return Status;
  9521. }
  9522. }
  9523. }
  9524. else
  9525. {
  9526. HttpCredentials = NULL;
  9527. }
  9528. Status = OsfBindingHandle->SetAuthInformation(
  9529. NULL,
  9530. AuthInfo->AuthenticationLevel,
  9531. RPC_C_AUTHN_NONE,
  9532. AuthInfo->AuthIdentity,
  9533. AuthInfo->AuthorizationService,
  9534. NULL, // SecurityCredentials
  9535. AuthInfo->ImpersonationType,
  9536. AuthInfo->IdentityTracking,
  9537. AuthInfo->Capabilities,
  9538. TRUE, // Acquire new credentials
  9539. AuthInfo->AdditionalTransportCredentialsType,
  9540. HttpCredentials
  9541. );
  9542. // success or not, we need to wipe out and free the transport credentials (if any)
  9543. if (HttpCredentials)
  9544. {
  9545. WipeOutAuthIdentity (HttpCredentials->TransportCredentials);
  9546. FreeHttpTransportCredentials (HttpCredentials);
  9547. }
  9548. return Status;
  9549. }
  9550. RPC_STATUS RPC_ENTRY
  9551. I_RpcTransIoCancelled (
  9552. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  9553. OUT PDWORD Timeout
  9554. )
  9555. /*++
  9556. Function Name:I_RpcTransIOCancelled
  9557. Parameters:
  9558. TransConnection: The connection on which the thread was partying on, when the
  9559. alert was received.
  9560. Timeout - If the call was cancelled, on return, this param will contain
  9561. the cancel timeout.
  9562. Description:
  9563. This function is called by the transport interface, when it notices that an alert has
  9564. been received. This function should only be called when the transport is dealing with
  9565. a sync call.
  9566. Returns:
  9567. RPC_S_OK: The call was cancelled
  9568. RPC_S_NO_CALL_ACTIVE: no call was cancelled
  9569. others - If a failure occured.
  9570. --*/
  9571. {
  9572. THREAD *ThreadInfo = RpcpGetThreadPointer();
  9573. ASSERT(ThreadInfo != 0);
  9574. if (ThreadInfo->GetCallCancelledFlag() == 0)
  9575. {
  9576. return RPC_S_NO_CALL_ACTIVE;
  9577. }
  9578. return InqTransCConnection(ThisConnection)->CallCancelled(Timeout);
  9579. }
  9580. unsigned short RPC_ENTRY
  9581. I_RpcTransClientMaxFrag (
  9582. IN RPC_TRANSPORT_CONNECTION ThisConnection
  9583. )
  9584. /*++
  9585. Routine Description:
  9586. The client side transport interface modules will use this routine to
  9587. determine the negotiated maximum fragment size.
  9588. Arguments:
  9589. ThisConnection - Supplies the connection for which we are returning
  9590. the maximum fragment size.
  9591. --*/
  9592. {
  9593. return (unsigned short) InqTransCConnection(ThisConnection)->InqMaximumFragmentLength();
  9594. }
  9595. BUFFER RPC_ENTRY
  9596. I_RpcTransConnectionAllocatePacket(
  9597. RPC_TRANSPORT_CONNECTION ThisConnection,
  9598. UINT Size
  9599. )
  9600. /*++
  9601. Function Name:I_RpcTransConnectionAllocatePacket
  9602. Parameters:
  9603. Description:
  9604. Returns:
  9605. --*/
  9606. {
  9607. return(RpcAllocateBuffer(Size));
  9608. }
  9609. void RPC_ENTRY
  9610. I_RpcTransConnectionFreePacket(
  9611. RPC_TRANSPORT_CONNECTION ThisConnection,
  9612. BUFFER Ptr
  9613. )
  9614. /*++
  9615. Function Name:I_RpcTransConnectionFreePacket
  9616. Parameters:
  9617. Description:
  9618. Returns:
  9619. --*/
  9620. {
  9621. RpcFreeBuffer(Ptr);
  9622. }
  9623. RPC_STATUS RPC_ENTRY
  9624. I_RpcTransConnectionReallocPacket(
  9625. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  9626. IN BUFFER *ppBuffer,
  9627. IN UINT OldSize,
  9628. IN UINT NewSize
  9629. )
  9630. /*++
  9631. Function Name:I_RpcTransConnectionReallocPacket
  9632. Parameters:
  9633. Description:
  9634. Returns:
  9635. --*/
  9636. {
  9637. ASSERT(NewSize > OldSize);
  9638. PVOID Buffer = RpcAllocateBuffer(NewSize);
  9639. if (Buffer)
  9640. {
  9641. if (OldSize)
  9642. {
  9643. RpcpMemoryCopy(Buffer, *ppBuffer, OldSize);
  9644. RpcFreeBuffer(*ppBuffer);
  9645. }
  9646. *ppBuffer = Buffer;
  9647. return(RPC_S_OK);
  9648. }
  9649. return(RPC_S_OUT_OF_MEMORY);
  9650. }
  9651. BOOL RPC_ENTRY
  9652. I_RpcTransPingServer (
  9653. IN RPC_TRANSPORT_CONNECTION ThisConnection
  9654. )
  9655. {
  9656. #if 0
  9657. RPC_STATUS Status = RPC_S_OK;
  9658. THREAD *ThisThread = ThreadSelf();
  9659. BOOL fRetVal;
  9660. if (ThisThread->fPinging)
  9661. {
  9662. //
  9663. // We are already pinging, it is best to give up
  9664. // on the server
  9665. //
  9666. return FALSE;
  9667. }
  9668. ThisThread->fPinging = 1;
  9669. EVENT ThreadEvent(&Status);
  9670. EVENT WriteEvent(&Status);
  9671. HANDLE hOldThreadEvent, hOldWriteEvent;
  9672. ASSERT(ThisThread);
  9673. if (Status != RPC_S_OK)
  9674. {
  9675. return TRUE;
  9676. }
  9677. hOldWriteEvent = ThisThread->hWriteEvent;
  9678. hOldThreadEvent = ThisThread->hThreadEvent;
  9679. ThisThread->hWriteEvent = WriteEvent.EventHandle;
  9680. ThisThread->hThreadEvent = ThreadEvent.EventHandle;
  9681. fRetVal = InqTransCConnection(ThisConnection)->PingServer();
  9682. ThisThread->hWriteEvent = hOldWriteEvent;
  9683. ThisThread->hThreadEvent = hOldThreadEvent;
  9684. ThisThread->fPinging = 0;
  9685. return fRetVal;
  9686. #else
  9687. return(FALSE);
  9688. #endif
  9689. }
  9690. void
  9691. I_RpcTransVerifyClientRuntimeCallFromContext(
  9692. void *SendContext
  9693. )
  9694. /*++
  9695. Routine Description:
  9696. Verifies that the supplied context follows a valid
  9697. runtime client call object.
  9698. Arguments:
  9699. SendContext - the context as seen by the transport
  9700. Return Value:
  9701. --*/
  9702. {
  9703. REFERENCED_OBJECT *pObj;
  9704. pObj = (REFERENCED_OBJECT *) *((PVOID *)
  9705. ((char *) SendContext - sizeof(void *)));
  9706. ASSERT(pObj->InvalidHandle(OSF_CCALL_TYPE | OSF_CCONNECTION_TYPE) == 0);
  9707. }
  9708. BOOL
  9709. I_RpcTransIsClientConnectionExclusive(
  9710. void *RuntimeConnection
  9711. )
  9712. /*++
  9713. Routine Description:
  9714. Checks whether the supplied runtime connection
  9715. is exclusive.
  9716. Arguments:
  9717. RuntimeConnection - the connection to check.
  9718. Return Value:
  9719. non-zero if the connection is exclusive. 0 otherwise.
  9720. --*/
  9721. {
  9722. OSF_CCONNECTION *Connection = (OSF_CCONNECTION *)RuntimeConnection;
  9723. ASSERT(Connection->InvalidHandle(OSF_CCONNECTION_TYPE) == 0);
  9724. return Connection->IsExclusive();
  9725. }
  9726. RPC_STATUS RPC_ENTRY
  9727. I_RpcBindingInqWireIdForSnego (
  9728. IN RPC_BINDING_HANDLE Binding,
  9729. OUT unsigned char *WireId
  9730. )
  9731. /*++
  9732. Routine Description:
  9733. Arguments:
  9734. Return Value:
  9735. The status for the operation is returned.
  9736. --*/
  9737. {
  9738. OSF_CCALL * Call;
  9739. InitializeIfNecessary();
  9740. Call = (OSF_CCALL *) Binding;
  9741. if (Call->InvalidHandle(OSF_CCALL_TYPE))
  9742. return(RPC_S_INVALID_BINDING);
  9743. return(Call->InqWireIdForSnego(WireId));
  9744. }
  9745. RPCRTAPI
  9746. RPC_STATUS
  9747. RPC_ENTRY
  9748. I_RpcBindingHandleToAsyncHandle (
  9749. IN RPC_BINDING_HANDLE Binding,
  9750. OUT void **AsyncHandle
  9751. )
  9752. {
  9753. OSF_CCALL * Call;
  9754. InitializeIfNecessary();
  9755. Call = (OSF_CCALL *) Binding;
  9756. if (Call->InvalidHandle(OSF_CCALL_TYPE))
  9757. return(RPC_S_INVALID_BINDING);
  9758. return Call->BindingHandleToAsyncHandle(AsyncHandle);
  9759. }
  9760. extern "C"
  9761. {
  9762. void
  9763. I_Trace (
  9764. int IgnoreFirst,
  9765. const char * IgnoreSecond,
  9766. ...
  9767. )
  9768. /*++
  9769. Routine Description:
  9770. This is an old routine which is no longer used. Because it is exported
  9771. by the dll, we need to leave an entry point.
  9772. --*/
  9773. {
  9774. UNUSED(IgnoreFirst);
  9775. UNUSED(IgnoreSecond);
  9776. }
  9777. }; // extern "C"