Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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