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.

1015 lines
33 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name :
  4. async.c
  5. Abstract :
  6. This file contains the ndr async implementation.
  7. Author :
  8. Ryszard K. Kott (ryszardk) Nov 1996
  9. Revision History :
  10. ---------------------------------------------------------------------*/
  11. #include "precomp.hxx"
  12. #define USE_STUBLESS_PROXY
  13. #define CINTERFACE
  14. #include "ndrole.h"
  15. #include "rpcproxy.h"
  16. #include "interp2.h"
  17. #include "asyndr64.h"
  18. #include <stdarg.h>
  19. #pragma code_seg(".ndr64")
  20. #ifdef _PPC_
  21. #error PPC code has been removed
  22. #endif
  23. void RPC_ENTRY
  24. Ndr64AsyncServerWorker(
  25. PRPC_MESSAGE pRpcMsg,
  26. ulong Index );
  27. CLIENT_CALL_RETURN RPC_VAR_ENTRY
  28. Ndr64AsyncClientCall(
  29. MIDL_STUBLESS_PROXY_INFO *pProxyInfo,
  30. ulong nProcNum,
  31. void *pReturnValue,
  32. ...
  33. )
  34. /*
  35. This entry is used for raw rpc only.
  36. No support for OLE [async] attribute anymore.
  37. */
  38. {
  39. va_list ArgList;
  40. unsigned char * StartofStack;
  41. CLIENT_CALL_RETURN Ret;
  42. //
  43. // Get address of argument to this function following pFormat. This
  44. // is the address of the address of the first argument of the function
  45. // calling this function.
  46. // Then get the address of the stack where the parameters are.
  47. //
  48. RPC_ASYNC_HANDLE AsyncHandle;
  49. PNDR_ASYNC_MESSAGE pAsyncMsg;
  50. RPC_MESSAGE * pRpcMsg;
  51. MIDL_STUB_MESSAGE * pStubMsg;
  52. ulong ProcNum;
  53. uchar * pArg;
  54. ushort StackSize;
  55. PPARAM_DESCRIPTION Params;
  56. long n;
  57. RPC_STATUS Status;
  58. NDR_PROC_CONTEXT * pContext;
  59. PMIDL_STUB_DESC pStubDesc;
  60. Ret.Simple = NULL;
  61. if ( NULL == pReturnValue )
  62. pReturnValue = &Ret;
  63. INIT_ARG( ArgList, pReturnValue );
  64. GET_FIRST_IN_ARG(ArgList);
  65. StartofStack = (uchar *) GET_STACK_START(ArgList);
  66. RPC_ASYNC_HANDLE * pHandleArg;
  67. // async message needs to be allocated on heap to be passed between calls.
  68. pAsyncMsg = (NDR_ASYNC_MESSAGE*) I_RpcBCacheAllocate( sizeof( NDR_ASYNC_MESSAGE) );
  69. if ( ! pAsyncMsg )
  70. Status = RPC_S_OUT_OF_MEMORY;
  71. else
  72. {
  73. memset( pAsyncMsg, 0, sizeof( NDR_ASYNC_MESSAGE ) );
  74. Ndr64ClientInitializeContext( NdrpGetSyntaxType( pProxyInfo->pTransferSyntax),
  75. pProxyInfo,
  76. nProcNum,
  77. &pAsyncMsg->ProcContext,
  78. StartofStack );
  79. Status = NdrpInitializeAsyncMsg( StartofStack,
  80. pAsyncMsg );
  81. }
  82. // We need to cleanup and return if something wrong in the async message
  83. if ( Status )
  84. {
  85. MIDL_STUB_MESSAGE StubMsgTemp;
  86. NDR_PROC_CONTEXT ProcContext;
  87. Ndr64ClientInitializeContext( NdrpGetSyntaxType( pProxyInfo->pTransferSyntax),
  88. pProxyInfo,
  89. nProcNum,
  90. &ProcContext,
  91. StartofStack );
  92. StubMsgTemp.StubDesc = pProxyInfo->pStubDesc;
  93. StubMsgTemp.StackTop = StartofStack;
  94. StubMsgTemp.pContext = &ProcContext;
  95. (ProcContext.pfnExceptionHandling)(&StubMsgTemp,
  96. nProcNum,
  97. ( RPC_STATUS )Ret.Simple,
  98. &Ret );
  99. return Ret;
  100. }
  101. pContext = & pAsyncMsg->ProcContext;
  102. // proc context
  103. // We need to switch to our copy of the stack everywhere, including pStubMsg.
  104. StartofStack = pAsyncMsg->ProcContext.StartofStack;
  105. // We abstract the level of indirection here.
  106. AsyncHandle = pAsyncMsg->AsyncHandle;
  107. pRpcMsg = & pAsyncMsg->RpcMsg;
  108. pStubMsg = & pAsyncMsg->StubMsg;
  109. // Wrap everything in a try-finally pair. The finally clause does the
  110. // required freeing of resources (RpcBuffer and Full ptr package).
  111. //
  112. RpcTryFinally
  113. {
  114. // Use a nested try-except pair to support [comm_status][fault_status].
  115. //
  116. RpcTryExcept
  117. {
  118. BOOL fRaiseExcFlag;
  119. pContext->RpcFlags |= RPC_BUFFER_ASYNC;
  120. Ndr64pClientSetupTransferSyntax( NULL, // pThis
  121. pRpcMsg,
  122. pStubMsg,
  123. pProxyInfo,
  124. pContext,
  125. nProcNum );
  126. pStubMsg->pAsyncMsg = pAsyncMsg;
  127. pStubMsg->pContext = pContext;
  128. (* pAsyncMsg->ProcContext.pfnInit) ( pStubMsg,
  129. pReturnValue );
  130. ( * pAsyncMsg->ProcContext.pfnSizing) ( pStubMsg,
  131. TRUE ); // isclient
  132. //
  133. // Do the GetBuffer.
  134. //
  135. pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
  136. Ndr64GetBuffer( pStubMsg,
  137. pStubMsg->BufferLength );
  138. NDR_ASSERT( pStubMsg->fBufferValid, "Invalid buffer" );
  139. // Let runtime associate async handle with the call.
  140. NdrpRegisterAsyncHandle( pStubMsg, AsyncHandle );
  141. pAsyncMsg->StubPhase = NDR_ASYNC_SET_PHASE;
  142. //
  143. // ----------------------------------------------------------
  144. // Marshall Pass.
  145. // ----------------------------------------------------------
  146. //
  147. (* pAsyncMsg->ProcContext.pfnMarshal) (pStubMsg,
  148. FALSE );
  149. //
  150. // Make the RPC call.
  151. //
  152. pAsyncMsg->StubPhase = NDR_ASYNC_CALL_PHASE;
  153. NdrAsyncSend( pStubMsg,
  154. pContext->HasPipe && pContext->pPipeDesc->InPipes );
  155. pAsyncMsg->Flags.ValidCallPending = 1;
  156. }
  157. RpcExcept( pAsyncMsg->ProcContext.ExceptionFlag )
  158. {
  159. RPC_STATUS ExceptionCode = RpcExceptionCode();
  160. // Actually dismantle the call.
  161. // This is a request call and there is nothing left at the runtime.
  162. pAsyncMsg->StubPhase = NDR_ASYNC_ERROR_PHASE;
  163. (* pAsyncMsg->ProcContext.pfnExceptionHandling) ( pStubMsg,
  164. nProcNum,
  165. ExceptionCode,
  166. &Ret );
  167. }
  168. RpcEndExcept
  169. }
  170. RpcFinally
  171. {
  172. if ( pAsyncMsg->Flags.ValidCallPending )
  173. {
  174. if ( pContext->HasPipe )
  175. {
  176. NdrMarkNextActivePipe( pContext->pPipeDesc );
  177. pContext->pPipeDesc->Flags.NoBufferCallPending = 1;
  178. }
  179. }
  180. else
  181. {
  182. // Cleanup everything but the user's handle.
  183. NdrpFreeAsyncMsg( pAsyncMsg );
  184. AsyncHandle->StubInfo = 0;
  185. }
  186. InterlockedDecrement( & AsyncHandle->Lock );
  187. }
  188. RpcEndFinally
  189. return Ret;
  190. }
  191. RPC_STATUS
  192. Ndr64pCompleteAsyncClientCall(
  193. RPC_ASYNC_HANDLE AsyncHandle,
  194. PNDR_ASYNC_MESSAGE pAsyncMsg,
  195. void * pReturnValue
  196. )
  197. {
  198. RPC_MESSAGE * pRpcMsg = & pAsyncMsg->RpcMsg;
  199. MIDL_STUB_MESSAGE * pStubMsg = & pAsyncMsg->StubMsg;
  200. NDR_PROC_CONTEXT * pContext = & pAsyncMsg->ProcContext;
  201. PMIDL_STUB_DESC pStubDescriptor = pStubMsg->StubDesc;
  202. CLIENT_CALL_RETURN RetVal ;
  203. uchar * pArg;
  204. long n;
  205. NDR_ASYNC_CALL_FLAGS CallFlags = pAsyncMsg->Flags;
  206. RetVal.Simple = 0;
  207. RpcTryFinally
  208. {
  209. // Use a nested try-except pair to support [comm_status][fault_status].
  210. //
  211. RpcTryExcept
  212. {
  213. if ( ! CallFlags.ValidCallPending )
  214. RpcRaiseException( RPC_S_INVALID_ASYNC_HANDLE );
  215. CallFlags.ValidCallPending = 0;
  216. // Non-pipe case or after pipe args case.
  217. if ( pContext->HasPipe )
  218. {
  219. RPC_STATUS rc = RpcAsyncGetCallStatus( AsyncHandle );
  220. if ( rc == RPC_S_OK || rc == RPC_S_ASYNC_CALL_PENDING )
  221. NdrIsAppDoneWithPipes( pContext->pPipeDesc );
  222. else
  223. RpcRaiseException( rc );
  224. }
  225. NdrLastAsyncReceive( pStubMsg );
  226. //
  227. // ----------------------------------------------------------
  228. // Unmarshall Pass.
  229. // ----------------------------------------------------------
  230. //
  231. (*pAsyncMsg->ProcContext.pfnUnMarshal)( pStubMsg,
  232. (CLIENT_CALL_RETURN *) pReturnValue );
  233. }
  234. RpcExcept( pAsyncMsg->ProcContext.ExceptionFlag )
  235. {
  236. RPC_STATUS ExceptionCode = RpcExceptionCode();
  237. CallFlags.ValidCallPending = ExceptionCode == RPC_S_ASYNC_CALL_PENDING;
  238. (* pAsyncMsg->ProcContext.pfnExceptionHandling) ( pStubMsg,
  239. pRpcMsg->ProcNum,
  240. ExceptionCode,
  241. &RetVal );
  242. }
  243. RpcEndExcept
  244. }
  245. RpcFinally
  246. {
  247. // There is only one way a valid call may be pending at this stage:
  248. // that is the receive call returned with RPC_S_CALL_PENDING.
  249. if ( ! CallFlags.ValidCallPending )
  250. {
  251. // Cleanup everything. However, don't free user's handle.
  252. NdrpFreeAsyncMsg( pAsyncMsg );
  253. AsyncHandle->StubInfo = 0;
  254. }
  255. InterlockedDecrement( & AsyncHandle->Lock );
  256. }
  257. RpcEndFinally
  258. return (RPC_STATUS)RetVal.Simple;
  259. }
  260. RPCRTAPI
  261. void
  262. RPC_ENTRY
  263. Ndr64AsyncServerCall64(
  264. PRPC_MESSAGE pRpcMsg )
  265. {
  266. // When compiled with -protocol ndr64,
  267. // NDR64 is the 1st (and only one) in MIDL_SYNTAX_INFO array.
  268. Ndr64AsyncServerWorker(
  269. pRpcMsg,
  270. 0 ); // Index 0
  271. }
  272. RPCRTAPI
  273. void
  274. RPC_ENTRY
  275. Ndr64AsyncServerCallAll(
  276. PRPC_MESSAGE pRpcMsg )
  277. {
  278. // When compiles with -protocol all,
  279. // NDR64 is the 2nd in MIDL_SYNTAX_INFO array
  280. Ndr64AsyncServerWorker(
  281. pRpcMsg,
  282. 1 ); // Index 1
  283. }
  284. void RPC_ENTRY
  285. Ndr64AsyncServerWorker(
  286. PRPC_MESSAGE pRpcMsg,
  287. ulong SyntaxIndex )
  288. /*++
  289. Routine Description :
  290. The server side entry point for regular asynchronous RPC procs.
  291. Arguments :
  292. pRpcMsg - The RPC message.
  293. Return :
  294. None.
  295. --*/
  296. {
  297. ulong dwStubPhase = STUB_UNMARSHAL;
  298. PRPC_SERVER_INTERFACE pServerIfInfo;
  299. PMIDL_SERVER_INFO pServerInfo;
  300. const SERVER_ROUTINE * DispatchTable;
  301. MIDL_SYNTAX_INFO * pSyntaxInfo;
  302. RPC_ASYNC_HANDLE AsyncHandle = 0;
  303. PNDR_ASYNC_MESSAGE pAsyncMsg;
  304. ushort ProcNum;
  305. PMIDL_STUB_MESSAGE pStubMsg;
  306. uchar * pArgBuffer;
  307. uchar * pArg;
  308. uchar ** ppArg;
  309. NDR64_PROC_FORMAT * pHeader;
  310. NDR64_PARAM_FORMAT * Params;
  311. long NumberParams;
  312. NDR64_PROC_FLAGS * pNdr64Flags;
  313. ushort ClientBufferSize;
  314. BOOL HasExplicitHandle;
  315. long n;
  316. // This context is just for setting up the call. embedded one in asyncmsg is the
  317. // one to be used during the life of this async call.
  318. NDR_PROC_CONTEXT *pContext;
  319. RPC_STATUS Status = RPC_S_OK;
  320. NDR64_PARAM_FLAGS * pParamFlags;
  321. NDR64_BIND_AND_NOTIFY_EXTENSION * pHeaderExts = NULL;
  322. pServerIfInfo = (PRPC_SERVER_INTERFACE)pRpcMsg->RpcInterfaceInformation;
  323. pServerInfo = (PMIDL_SERVER_INFO)pServerIfInfo->InterpreterInfo;
  324. DispatchTable = pServerInfo->DispatchTable;
  325. pSyntaxInfo = &pServerInfo->pSyntaxInfo[SyntaxIndex];
  326. NDR_ASSERT( XFER_SYNTAX_NDR64 == NdrpGetSyntaxType(&pSyntaxInfo->TransferSyntax),
  327. " invalid transfer syntax" );
  328. //
  329. // In the case of a context handle, the server side manager function has
  330. // to be called with NDRSContextValue(ctxthandle). But then we may need to
  331. // marshall the handle, so NDRSContextValue(ctxthandle) is put in the
  332. // argument buffer and the handle itself is stored in the following array.
  333. // When marshalling a context handle, we marshall from this array.
  334. //
  335. // The handle table is part of the async handle.
  336. ProcNum = (ushort) pRpcMsg->ProcNum;
  337. NDR_ASSERT( ! ((ULONG_PTR)pRpcMsg->Buffer & 0x7),
  338. "marshaling buffer misaligned at server" );
  339. AsyncHandle = 0;
  340. pAsyncMsg = (NDR_ASYNC_MESSAGE*) I_RpcBCacheAllocate( sizeof( NDR_ASYNC_MESSAGE) );
  341. if ( ! pAsyncMsg )
  342. Status = RPC_S_OUT_OF_MEMORY;
  343. else
  344. {
  345. memset( pAsyncMsg, 0, sizeof( NDR_ASYNC_MESSAGE ) );
  346. NdrServerSetupNDR64TransferSyntax(
  347. ProcNum,
  348. pSyntaxInfo,
  349. &pAsyncMsg->ProcContext );
  350. Status = NdrpInitializeAsyncMsg( 0, // StartofStack, server
  351. pAsyncMsg
  352. );
  353. }
  354. if ( Status )
  355. RpcRaiseException( Status );
  356. pContext = &pAsyncMsg->ProcContext;
  357. PFORMAT_STRING pFormat = pContext->pProcFormat;
  358. pAsyncMsg->StubPhase = STUB_UNMARSHAL;
  359. pStubMsg = & pAsyncMsg->StubMsg;
  360. // same in ndr20
  361. pStubMsg->RpcMsg = pRpcMsg;
  362. // The arg buffer is zeroed out already.
  363. pArgBuffer = pContext->StartofStack;
  364. pHeader = (NDR64_PROC_FORMAT *) pFormat;
  365. pNdr64Flags = (NDR64_PROC_FLAGS *) &pHeader->Flags;
  366. HasExplicitHandle = !NDR64MAPHANDLETYPE( NDR64GETHANDLETYPE ( pNdr64Flags ) );
  367. if ( pNdr64Flags->HasOtherExtensions )
  368. pHeaderExts = (NDR64_BIND_AND_NOTIFY_EXTENSION *) (pFormat + sizeof( NDR64_PROC_FORMAT ) );
  369. if ( HasExplicitHandle )
  370. {
  371. NDR_ASSERT( pHeaderExts, "NULL extension header" );
  372. //
  373. // For a handle_t parameter we must pass the handle field of
  374. // the RPC message to the server manager.
  375. //
  376. if ( pHeaderExts->Binding.HandleType == FC64_BIND_PRIMITIVE )
  377. {
  378. pArg = pArgBuffer + pHeaderExts->Binding.StackOffset;
  379. if ( NDR64_IS_HANDLE_PTR( pHeaderExts->Binding.Flags ) )
  380. pArg = *((uchar **)pArg);
  381. *((handle_t *)pArg) = pRpcMsg->Handle;
  382. }
  383. }
  384. //
  385. // Get new interpreter info.
  386. //
  387. NumberParams = pHeader->NumberOfParams;
  388. Params = (NDR64_PARAM_FORMAT *)( (uchar *) pFormat + sizeof( NDR64_PROC_FORMAT ) + pHeader->ExtensionSize );
  389. //
  390. // Wrap the unmarshalling and the invoke call in the try block of
  391. // a try-finally. Put the free phase in the associated finally block.
  392. //
  393. BOOL fManagerCodeInvoked = FALSE;
  394. BOOL fErrorInInvoke = FALSE;
  395. RPC_STATUS ExceptionCode = 0;
  396. // We abstract the level of indirection here.
  397. AsyncHandle = pAsyncMsg->AsyncHandle;
  398. RpcTryFinally
  399. {
  400. RpcTryExcept
  401. {
  402. // Put the async handle on stack.
  403. ((void **)pArgBuffer)[0] = AsyncHandle;
  404. //
  405. // Initialize the Stub message.
  406. // Note that for pipes we read non-pipe data synchronously,
  407. // and so the init routine doesn't need to know about async.
  408. //
  409. if ( ! pNdr64Flags->UsesPipes )
  410. {
  411. Ndr64ServerInitialize( pRpcMsg,
  412. pStubMsg,
  413. pServerInfo->pStubDesc );
  414. }
  415. else
  416. Ndr64ServerInitializePartial( pRpcMsg,
  417. pStubMsg,
  418. pServerInfo->pStubDesc,
  419. pHeader->ConstantClientBufferSize );
  420. // We need to set up this flag because the runtime does not know whether
  421. // it dispatched a sync or async call to us. same as ndr20
  422. pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
  423. pStubMsg->pAsyncMsg = pAsyncMsg;
  424. pStubMsg->RpcMsg = pRpcMsg;
  425. pStubMsg->pContext = &pAsyncMsg->ProcContext;
  426. //
  427. // Set up for context handle management.
  428. //
  429. pStubMsg->SavedContextHandles = & pAsyncMsg->CtxtHndl[0];
  430. // Raise exceptions after initializing the stub.
  431. if ( pNdr64Flags->UsesFullPtrPackage )
  432. pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit( 0, XLAT_SERVER );
  433. //
  434. // Set StackTop AFTER the initialize call, since it zeros the field
  435. // out.
  436. //
  437. pStubMsg->pCorrMemory = pStubMsg->StackTop;
  438. if ( pNdr64Flags->UsesPipes )
  439. NdrpPipesInitialize64( pStubMsg,
  440. &pContext->AllocateContext,
  441. (PFORMAT_STRING) Params,
  442. (char*)pArgBuffer,
  443. NumberParams );
  444. //
  445. // We must make this check AFTER the call to ServerInitialize,
  446. // since that routine puts the stub descriptor alloc/dealloc routines
  447. // into the stub message.
  448. //
  449. if ( pNdr64Flags->UsesRpcSmPackage )
  450. NdrRpcSsEnableAllocate( pStubMsg );
  451. // Let runtime associate async handle with the call.
  452. NdrpRegisterAsyncHandle( pStubMsg, AsyncHandle );
  453. pAsyncMsg->StubPhase = NDR_ASYNC_SET_PHASE;
  454. // --------------------------------
  455. // Unmarshall all of our parameters.
  456. // --------------------------------
  457. NDR_ASSERT( pContext->StartofStack == pArgBuffer, "startofstack is not set" );
  458. Ndr64pServerUnMarshal( pStubMsg );
  459. if ( pRpcMsg->BufferLength <
  460. (uint)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer) )
  461. {
  462. RpcRaiseException( RPC_X_BAD_STUB_DATA );
  463. }
  464. }
  465. RpcExcept( NdrServerUnmarshallExceptionFlag(GetExceptionInformation()) )
  466. {
  467. ExceptionCode = RpcExceptionCode();
  468. if( RPC_BAD_STUB_DATA_EXCEPTION_FILTER )
  469. {
  470. ExceptionCode = RPC_X_BAD_STUB_DATA;
  471. }
  472. pAsyncMsg->Flags.BadStubData = 1;
  473. pAsyncMsg->ErrorCode = ExceptionCode;
  474. NdrpFreeMemoryList( pStubMsg );
  475. RpcRaiseException( ExceptionCode );
  476. }
  477. RpcEndExcept
  478. // Two separate blocks because the filters are different.
  479. // We need to catch exception in the manager code separately
  480. // as the model implies that there will be no other call from
  481. // the server app to clean up.
  482. RpcTryExcept
  483. {
  484. //
  485. // Do [out] initialization before the invoke.
  486. //
  487. Ndr64pServerOutInit( pStubMsg );
  488. //
  489. // Unblock the first pipe; this needs to be after unmarshalling
  490. // because the buffer may need to be changed to the secondary one.
  491. // In the out only pipes case this happens immediately.
  492. //
  493. if ( pNdr64Flags->UsesPipes )
  494. NdrMarkNextActivePipe( pContext->pPipeDesc );
  495. pAsyncMsg->StubPhase = STUB_CALL_SERVER;
  496. //
  497. // Check for a thunk. Compiler does all the setup for us.
  498. //
  499. if ( pServerInfo->ThunkTable && pServerInfo->ThunkTable[ProcNum] )
  500. {
  501. pAsyncMsg->Flags.ValidCallPending = 1;
  502. InterlockedDecrement( & AsyncHandle->Lock );
  503. fManagerCodeInvoked = TRUE;
  504. fErrorInInvoke = TRUE;
  505. pServerInfo->ThunkTable[ProcNum]( pStubMsg );
  506. }
  507. else
  508. {
  509. //
  510. // Note that this ArgNum is not the number of arguments declared
  511. // in the function we called, but really the number of
  512. // REGISTER_TYPEs occupied by the arguments to a function.
  513. //
  514. long ArgNum;
  515. MANAGER_FUNCTION pFunc;
  516. REGISTER_TYPE returnValue;
  517. if ( pRpcMsg->ManagerEpv )
  518. pFunc = ((MANAGER_FUNCTION *)pRpcMsg->ManagerEpv)[ProcNum];
  519. else
  520. pFunc = (MANAGER_FUNCTION) DispatchTable[ProcNum];
  521. ArgNum = (long) pContext->StackSize / sizeof(REGISTER_TYPE);
  522. //
  523. // The StackSize includes the size of the return. If we want
  524. // just the number of REGISTER_TYPES, then ArgNum must be reduced
  525. // by 1 when there is a return value AND the current ArgNum count
  526. // is greater than 0.
  527. //
  528. if ( ArgNum && pNdr64Flags->HasReturn )
  529. ArgNum--;
  530. // Being here means that we can expect results. Note that the user
  531. // can call RpcCompleteCall from inside of the manager code.
  532. pAsyncMsg->Flags.ValidCallPending = 1;
  533. // Unlock the handle - the app is allowed to call RpCAsyncComplete
  534. // or RpcAsyncAbort from the manager code.
  535. InterlockedDecrement( & AsyncHandle->Lock );
  536. fManagerCodeInvoked = TRUE;
  537. fErrorInInvoke = TRUE;
  538. returnValue = Invoke( pFunc,
  539. (REGISTER_TYPE *)pArgBuffer,
  540. #if defined(_WIN64)
  541. pHeader->FloatDoubleMask,
  542. #endif
  543. ArgNum);
  544. // We are discarding the return value as it is not the real one.
  545. // The real return value is passed in the complete call.
  546. }
  547. fErrorInInvoke = FALSE;
  548. }
  549. RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) )
  550. {
  551. ExceptionCode = RpcExceptionCode();
  552. if ( ExceptionCode == 0 )
  553. ExceptionCode = ERROR_INVALID_PARAMETER;
  554. // We may not have the async message around anymore.
  555. RpcRaiseException( ExceptionCode );
  556. }
  557. RpcEndExcept
  558. }
  559. RpcFinally
  560. {
  561. if ( fManagerCodeInvoked && !fErrorInInvoke )
  562. {
  563. // Success. Just skip everything if the manager code was invoked
  564. // and returned successfully.
  565. // Note that manager code could have called Complete or Abort by now
  566. // and so the async handle may not be valid anymore.
  567. }
  568. else
  569. {
  570. // See if we can clean up;
  571. Status = RPC_S_OK;
  572. if ( fErrorInInvoke )
  573. {
  574. // After an exception in invoking, let's see if we can get a hold
  575. // of the handle. If so, we will be able to clean up.
  576. // If not, there may be a leak there that we can do nothing about.
  577. // The rule is: after an exception the app cannot call Abort or
  578. // Complete. So, we need to force complete if we can.
  579. Status = NdrValidateBothAndLockAsyncHandle( AsyncHandle );
  580. }
  581. if ( Status == RPC_S_OK )
  582. {
  583. // Something went wrong but we are able to do the cleanup.
  584. // Cleanup parameters and async message/handle.
  585. // propagate the exception.
  586. Ndr64pCleanupServerContextHandles( pStubMsg,
  587. NumberParams,
  588. Params,
  589. pArgBuffer,
  590. TRUE ); // fail before/during manager routine
  591. if (!pAsyncMsg->Flags.BadStubData)
  592. {
  593. Ndr64pFreeParams( pStubMsg,
  594. NumberParams,
  595. Params,
  596. pArgBuffer );
  597. }
  598. NdrpFreeAsyncHandleAndMessage( AsyncHandle );
  599. }
  600. // else manager code invoked and we could not recover.
  601. // Exception will be raised by the EndFinally below.
  602. }
  603. }
  604. RpcEndFinally
  605. }
  606. RPC_STATUS
  607. Ndr64pCompleteAsyncServerCall(
  608. RPC_ASYNC_HANDLE AsyncHandle,
  609. PNDR_ASYNC_MESSAGE pAsyncMsg,
  610. void * pReturnValue
  611. )
  612. /*++
  613. Routine Description :
  614. Complete an async call on the server side. If an exception occurs, the
  615. asynchronous rpc call is aborted with the exception code and the server side
  616. caller is returned S_OK.
  617. Arguments :
  618. AsyncHandle - validated asynchronous handle,
  619. pAsyncMsg - pointer to async msg structure,
  620. pReturnValue - pointer to the return value to be passed to the client.
  621. Return :
  622. Status of S_OK.
  623. --*/
  624. {
  625. MIDL_STUB_MESSAGE * pStubMsg = & pAsyncMsg->StubMsg;
  626. RPC_MESSAGE * pRpcMsg = pStubMsg->RpcMsg;
  627. NDR64_PARAM_FORMAT * Params ;
  628. uchar * pArgBuffer = pAsyncMsg->ProcContext.StartofStack;
  629. ushort StackSize = (ushort)pAsyncMsg->ProcContext.StackSize;
  630. uchar * pArg;
  631. long NumberParams ;
  632. long n;
  633. boolean fParamsFreed = FALSE;
  634. NDR64_PROC_FORMAT * pHeader = pAsyncMsg->ProcContext.Ndr64Header;
  635. NDR64_PROC_FLAGS * pNdr64Flags = ( NDR64_PROC_FLAGS * )&pHeader->Flags;
  636. NumberParams = pAsyncMsg->ProcContext.NumberParams;
  637. Params = ( NDR64_PARAM_FORMAT * ) pAsyncMsg->ProcContext.Params;
  638. //
  639. // Wrap the unmarshalling, mgr call and marshalling in the try block of
  640. // a try-except. Put the call to abort in the except clause.
  641. //
  642. RpcTryExcept
  643. {
  644. // At this point, this is a valid RPC call since the asynchronous handle
  645. // is owned by NDR on the server side and NDR passes the handle
  646. // to the server during the invoke call. During invoke
  647. // the parameters have already been unmarshalled.
  648. pAsyncMsg->StubPhase = STUB_MARSHAL;
  649. if( pNdr64Flags->HasReturn )
  650. {
  651. // Put user's return value on the stack as usual.
  652. // See the invoke for comments on folding return into the arg satck.
  653. long ArgNum = (long) StackSize / sizeof(REGISTER_TYPE);
  654. if ( ArgNum )
  655. ArgNum--;
  656. if ( ! pReturnValue )
  657. RpcRaiseException( RPC_S_INVALID_ARG );
  658. if ( Params[NumberParams-1].Attributes.IsBasetype )
  659. memcpy( &((REGISTER_TYPE *)pArgBuffer)[ArgNum],
  660. pReturnValue,
  661. (size_t)NDR64_SIMPLE_TYPE_MEMSIZE( *(PFORMAT_STRING) Params[NumberParams-1].Type ) );
  662. else
  663. ((REGISTER_TYPE *)pArgBuffer)[ArgNum] = *(REGISTER_TYPE*)pReturnValue;
  664. }
  665. //
  666. // Buffer size pass.
  667. //
  668. ushort ConstantBufferSize = (ushort)pHeader->ConstantServerBufferSize;
  669. if ( pNdr64Flags->UsesPipes )
  670. {
  671. NdrIsAppDoneWithPipes( pStubMsg->pContext->pPipeDesc );
  672. pStubMsg->BufferLength += ConstantBufferSize;
  673. }
  674. else
  675. pStubMsg->BufferLength = ConstantBufferSize;
  676. if ( pNdr64Flags->ServerMustSize )
  677. {
  678. NDR_ASSERT( pAsyncMsg->ProcContext.StartofStack == pArgBuffer,
  679. "startofstack is not set" );
  680. Ndr64pSizing( pStubMsg,
  681. FALSE );
  682. }
  683. // Get buffer.
  684. if ( pNdr64Flags->UsesPipes && pStubMsg->pContext->pPipeDesc->OutPipes )
  685. {
  686. NdrGetPartialBuffer( pStubMsg );
  687. pStubMsg->RpcMsg->RpcFlags &= ~RPC_BUFFER_PARTIAL;
  688. }
  689. else
  690. {
  691. Ndr64GetBuffer( pStubMsg,
  692. pStubMsg->BufferLength );
  693. }
  694. //
  695. // Marshall pass.
  696. //
  697. Ndr64pServerMarshal( pStubMsg );
  698. pRpcMsg->BufferLength = (ulong)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer);
  699. // We don't drop to the runtime like for synchronous calls,
  700. // we send the last buffer explicitly.
  701. // set the freed flag.
  702. fParamsFreed = TRUE;
  703. /*
  704. we have to do release twice here:
  705. After the last piece of data is sent via NdrAsyncSend, dispatch buffer
  706. will be freed by runtime. We'll have problem calling ndr free routines to
  707. free unique pointers (where both pointer and pointee are in the buffer). So
  708. we call ndr free routines BEFORE the send, because it won't free anything
  709. inside dispatch buffer, and runtime send only cares about dispatch buffer.
  710. We still have to call ndr free routines in RpcFinally for exception cleanup. we
  711. check the flag to avoid calling free twice.
  712. */
  713. Ndr64pFreeParams( pStubMsg,
  714. NumberParams,
  715. Params,
  716. pArgBuffer );
  717. NdrAsyncSend( pStubMsg,
  718. FALSE ); // the last call is always non-partial
  719. }
  720. RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) )
  721. {
  722. // If we died during the marshaling phase, see if context handles are fine.
  723. // Abort the call which will result in the exception being propagated to
  724. // the client.
  725. Ndr64pAsyncAbortCall( AsyncHandle,
  726. pAsyncMsg,
  727. RpcExceptionCode(),
  728. !fParamsFreed ); // Do not free if second attempt.
  729. return S_OK;
  730. }
  731. RpcEndExcept
  732. NdrpFreeAsyncHandleAndMessage( AsyncHandle );
  733. return S_OK;
  734. }
  735. RPC_STATUS
  736. Ndr64pAsyncAbortCall (
  737. PRPC_ASYNC_STATE AsyncHandle,
  738. PNDR_ASYNC_MESSAGE pAsyncMsg,
  739. unsigned long ExceptionCode,
  740. BOOL bFreeParams
  741. )
  742. /*++
  743. Routine Description:
  744. Aborts the asynchronous RPC call indicated by AsyncHandle on the server and
  745. frees memory allocated for the parameters, message, and handle.
  746. Arguments:
  747. AsyncHandle - supplies the async handle for the call
  748. AsyncMessage - supplies the async message for the call
  749. ExceptionCode - supplies the exception code to send to the client.
  750. bFreeParams - TRUE if the parameters should be freed.
  751. Return Value:
  752. NONE.
  753. --*/
  754. {
  755. RPC_STATUS Status = RPC_S_OK;
  756. // If the async call is aborted, see if context handles are fine.
  757. // We are dying after manager routine is called
  758. Ndr64pCleanupServerContextHandles( &pAsyncMsg->StubMsg,
  759. pAsyncMsg->ProcContext.NumberParams,
  760. (NDR64_PARAM_FORMAT *) pAsyncMsg->ProcContext.Params,
  761. pAsyncMsg->ProcContext.StartofStack,
  762. FALSE ); // no exception in manager routine
  763. if (bFreeParams)
  764. {
  765. Ndr64pFreeParams( & pAsyncMsg->StubMsg,
  766. pAsyncMsg->ProcContext.NumberParams, //Number of parameters
  767. (NDR64_PARAM_FORMAT *) pAsyncMsg->ProcContext.Params,
  768. pAsyncMsg->ProcContext.StartofStack );
  769. }
  770. if ( ! pAsyncMsg->Flags.RuntimeCleanedUp )
  771. Status = I_RpcAsyncAbortCall( AsyncHandle, ExceptionCode);
  772. NdrpFreeAsyncHandleAndMessage( AsyncHandle );
  773. return Status;
  774. }
  775. #pragma code_seg()