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

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