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.

2682 lines
82 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. Module Name :
  4. pipe.c
  5. Abstract :
  6. This file contains the idl pipe implementetion code.
  7. Author :
  8. Ryszard K. Kott (ryszardk) Dec 1995
  9. Revision History :
  10. ---------------------------------------------------------------------*/
  11. #define USE_STUBLESS_PROXY
  12. #define CINTERFACE
  13. #include <stdarg.h>
  14. #include "ndrp.h"
  15. #include "ndrole.h"
  16. #include "objidl.h"
  17. #include "rpcproxy.h"
  18. #include "interp.h"
  19. #include "interp2.h"
  20. #include "mulsyntx.h"
  21. #include "pipendr.h"
  22. #include "asyncndr.h"
  23. #if DBG
  24. typedef enum
  25. {
  26. PIPE_LOG_NONE,
  27. PIPE_LOG_CRITICAL,
  28. PIPE_LOG_API,
  29. PIPE_LOG_NOISE
  30. } NDR_PIPE_LOG_LEVEL;
  31. NDR_PIPE_LOG_LEVEL NdrPipeLogLevel = PIPE_LOG_NONE;
  32. #define NDR_PIPE_LOG( level, args ) \
  33. if ( NdrPipeLogLevel > level ) \
  34. { \
  35. DbgPrint( "NdrPipeLog: %d : ", level ); \
  36. DbgPrint args ; \
  37. DbgPrint( "\n" ); \
  38. } \
  39. #else
  40. #define NDR_PIPE_LOG( level, args )
  41. #endif
  42. RPC_STATUS RPC_ENTRY
  43. NdrSend(
  44. NDR_PIPE_DESC * pPipeDesc,
  45. PMIDL_STUB_MESSAGE pStubMsg,
  46. BOOL fPartial )
  47. /*++
  48. Routine Description :
  49. Performs a I_RpcSend in all the context it could be used:
  50. - pipes,
  51. - async, no pipes
  52. Arguments :
  53. pStubMsg - Pointer to stub message structure.
  54. pBufferEnd - taken as StubMsg->Buffer
  55. Return :
  56. The new message buffer pointer returned from the runtime after the
  57. partial Send to the server.
  58. --*/
  59. {
  60. RPC_STATUS Status;
  61. PRPC_MESSAGE pRpcMsg;
  62. pRpcMsg = pStubMsg->RpcMsg;
  63. if ( pRpcMsg->BufferLength <
  64. (uint)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer))
  65. {
  66. NDR_ASSERT( 0, "NdrSend : buffer overflow" );
  67. NdrpRaisePipeException( pPipeDesc, RPC_S_INTERNAL_ERROR );
  68. }
  69. pRpcMsg->BufferLength = (ulong)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer);
  70. pStubMsg->fBufferValid = FALSE;
  71. if ( fPartial )
  72. pRpcMsg->RpcFlags |= RPC_BUFFER_PARTIAL;
  73. else
  74. pRpcMsg->RpcFlags &= ~RPC_BUFFER_PARTIAL;
  75. if ( pStubMsg->pRpcChannelBuffer )
  76. {
  77. ((IRpcChannelBuffer3 *)pStubMsg->pRpcChannelBuffer)->lpVtbl->Send(
  78. (IRpcChannelBuffer3 *)pStubMsg->pRpcChannelBuffer,
  79. (RPCOLEMESSAGE *)pRpcMsg,
  80. (unsigned long*) &Status );
  81. NDR_ASSERT( Status != RPC_S_SEND_INCOMPLETE, "Unexpected channel error" );
  82. }
  83. else
  84. Status = I_RpcSend( pRpcMsg );
  85. if ( ! ( Status == RPC_S_OK ||
  86. (Status == RPC_S_SEND_INCOMPLETE && fPartial) ) )
  87. {
  88. if ( fPartial && ! pStubMsg->IsClient )
  89. {
  90. // The buffer on which it failed has been freed by the runtime.
  91. // The stub has to return to runtime with the original buffer.
  92. // See ResetToDispatchBuffer for more info.
  93. pRpcMsg->Buffer = pPipeDesc->DispatchBuffer;
  94. pStubMsg->BufferStart = pPipeDesc->DispatchBuffer;
  95. pStubMsg->BufferEnd = pPipeDesc->DispatchBuffer +
  96. pPipeDesc->DispatchBufferLength;
  97. }
  98. if ( pStubMsg->pAsyncMsg )
  99. pStubMsg->pAsyncMsg->Flags.RuntimeCleanedUp = 1;
  100. NdrpRaisePipeException( pPipeDesc, Status );
  101. }
  102. pStubMsg->Buffer = (uchar*) pRpcMsg->Buffer;
  103. pStubMsg->fBufferValid = TRUE;
  104. return( Status );
  105. }
  106. void RPC_ENTRY
  107. NdrPartialSend(
  108. NDR_PIPE_DESC * pPipeDesc,
  109. PMIDL_STUB_MESSAGE pStubMsg )
  110. /*++
  111. Routine Description :
  112. Performs a partial I_RpcSend. It's used in the following contexts:
  113. - synchronous pipes
  114. - async pipes
  115. Arguments :
  116. pStubMsg - Pointer to stub message structure.
  117. pBufferEnd - taken as StubMsg->Buffer
  118. Return :
  119. The new message buffer pointer returned from the runtime after the
  120. partial Send to the server.
  121. Note:
  122. The partial I_RpcSend sends out full packets, the data from the last
  123. packet is left over and stays in the same buffer.
  124. That buffer can later be "reallocated" or reallocated for the new size.
  125. This is done in the NdrGetPartialBuffer.
  126. --*/
  127. {
  128. RPC_STATUS Status;
  129. PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg;
  130. // This routine needs to send only multiple of 8s now.
  131. pPipeDesc->LeftoverSize = PtrToUlong(pStubMsg->Buffer) & 0x7;
  132. if ( pPipeDesc->LeftoverSize )
  133. {
  134. pStubMsg->Buffer -= pPipeDesc->LeftoverSize;
  135. RpcpMemoryCopy( pPipeDesc->Leftover,
  136. pStubMsg->Buffer,
  137. pPipeDesc->LeftoverSize );
  138. }
  139. Status = NdrSend( pPipeDesc,
  140. pStubMsg,
  141. TRUE ); // send partial
  142. // Handle unsent buffer case.
  143. if ( Status == RPC_S_SEND_INCOMPLETE )
  144. {
  145. pPipeDesc->LastPartialBuffer = (uchar*) pRpcMsg->Buffer;
  146. pPipeDesc->LastPartialSize = pRpcMsg->BufferLength;
  147. NDR_ASSERT( ((LONG_PTR)pRpcMsg->Buffer & 0x7) == 0,
  148. "unsent buffer should still be a multiple of 8" );
  149. }
  150. else
  151. {
  152. // means no buffer left behind.
  153. pPipeDesc->LastPartialBuffer = NULL;
  154. pPipeDesc->LastPartialSize = 0;
  155. }
  156. // Handle the modulo 8 leftover.
  157. if ( pPipeDesc->LeftoverSize )
  158. {
  159. pPipeDesc->LastPartialBuffer = (uchar*) pRpcMsg->Buffer;
  160. pPipeDesc->LastPartialSize += pPipeDesc->LeftoverSize;
  161. }
  162. }
  163. void RPC_ENTRY
  164. NdrCompleteSend(
  165. NDR_PIPE_DESC * pPipeDesc,
  166. PMIDL_STUB_MESSAGE pStubMsg )
  167. /*++
  168. Routine Description :
  169. Performs a complete send via I_RpcSend.
  170. Arguments :
  171. pStubMsg - Pointer to stub message structure.
  172. pBufferEnd - taken as StubMsg->Buffer
  173. Return :
  174. Note :
  175. I_RpcSend with partial bit zeroed out is a rough equivalant
  176. of RpcSendReceive; this also covers the way the buffer is handled.
  177. The runtime takes care of the sent buffer, returns a buffer with
  178. data that needs to be freed later by the stub.
  179. If the buffer coming back is partial, the partial Receives take
  180. care of it and only the last one needs to be freed w/RpcFreeBuffer.
  181. --*/
  182. {
  183. NdrSend( pPipeDesc,
  184. pStubMsg,
  185. FALSE ); // send not partial
  186. pPipeDesc->LastPartialBuffer = NULL;
  187. pPipeDesc->LastPartialSize = 0;
  188. }
  189. void RPC_ENTRY
  190. NdrReceive(
  191. NDR_PIPE_DESC * pPipeDesc,
  192. PMIDL_STUB_MESSAGE pStubMsg,
  193. unsigned long Size,
  194. BOOL fPartial )
  195. /*++
  196. Routine Description :
  197. Performs a partial I_RpcReceive.
  198. Arguments :
  199. pStubMsg - Pointer to stub message structure.
  200. pBufferEnd - taken as StubMsg->Buffer
  201. Return :
  202. --*/
  203. {
  204. RPC_STATUS Status;
  205. PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg;
  206. unsigned long CurOffset = 0;
  207. pStubMsg->fBufferValid = FALSE;
  208. if ( ! pStubMsg->pRpcChannelBuffer )
  209. {
  210. // Channel sets the flag on the last, complete send
  211. // so we cannot assert for channel for now.
  212. NDR_ASSERT( !(pRpcMsg->RpcFlags & RPC_BUFFER_COMPLETE), "no more buffers" );
  213. }
  214. if ( fPartial )
  215. {
  216. pRpcMsg->RpcFlags |= RPC_BUFFER_PARTIAL;
  217. pRpcMsg->RpcFlags &= ~RPC_BUFFER_EXTRA;
  218. // For partials, the current offset will be zero.
  219. }
  220. else
  221. {
  222. pRpcMsg->RpcFlags &= ~RPC_BUFFER_PARTIAL;
  223. // The extra flag may be set or cleared by the caller.
  224. // On the client
  225. // it should be cleared if there is no out pipes
  226. // it should be set only on the last receive after out pipes
  227. // On the server
  228. // it should be set on the initial receives that get non pipe data
  229. // it should cleared on all the other receives.
  230. // For a complete with extra (i.e. appending new data),
  231. // the current offset needs to be preserved.
  232. // For a complete without extra, the offset is zero
  233. // as the receive follows immediately after a send call.
  234. CurOffset = (ulong)(pStubMsg->Buffer - (uchar*)pRpcMsg->Buffer);
  235. }
  236. if ( pStubMsg->pRpcChannelBuffer )
  237. {
  238. ((IRpcChannelBuffer3 *)pStubMsg->pRpcChannelBuffer)->lpVtbl->Receive(
  239. (IRpcChannelBuffer3 *)pStubMsg->pRpcChannelBuffer,
  240. (RPCOLEMESSAGE *)pRpcMsg,
  241. Size,
  242. (unsigned long *)&Status );
  243. }
  244. else
  245. Status = I_RpcReceive( pRpcMsg, Size );
  246. if ( Status )
  247. {
  248. // Pending is also OK: if so, we should not touch the state,
  249. // just return from the call to the app.
  250. if ( Status != RPC_S_ASYNC_CALL_PENDING )
  251. {
  252. // Real bug happened, the state will be teared down etc.
  253. if ( ! pStubMsg->IsClient )
  254. {
  255. // The buffer on which it failed has been freed by the runtime.
  256. // See ResetToDispatchBuffer for explanations why we do this.
  257. // Also note, on server we never call with async-nonpipe context.
  258. pRpcMsg->Buffer = pPipeDesc->DispatchBuffer;
  259. pStubMsg->BufferStart = pPipeDesc->DispatchBuffer;
  260. pStubMsg->BufferEnd = pPipeDesc->DispatchBuffer +
  261. pPipeDesc->DispatchBufferLength;
  262. }
  263. if ( pStubMsg->pAsyncMsg )
  264. {
  265. // raw rpc: if async, prevent calling abort later.
  266. if ( pStubMsg->pAsyncMsg )
  267. pStubMsg->pAsyncMsg->Flags.RuntimeCleanedUp = 1;
  268. }
  269. }
  270. NdrpRaisePipeException( pPipeDesc, Status);
  271. }
  272. NDR_ASSERT( 0 == pRpcMsg->BufferLength ||
  273. NULL != pRpcMsg->Buffer,
  274. "Rpc runtime returned an invalid buffer." );
  275. if ( fPartial )
  276. {
  277. NDR_ASSERT( pRpcMsg->BufferLength, "a partial buffer can't be empty" );
  278. if ( pRpcMsg->BufferLength == 0)
  279. RpcRaiseException( RPC_X_INVALID_BUFFER );
  280. }
  281. pStubMsg->Buffer = (uchar*) pRpcMsg->Buffer + CurOffset;
  282. pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer;
  283. pStubMsg->BufferEnd = (uchar*)pRpcMsg->Buffer + pRpcMsg->BufferLength;
  284. pStubMsg->fBufferValid = TRUE;
  285. }
  286. void RPC_ENTRY
  287. NdrPartialReceive(
  288. NDR_PIPE_DESC * pPipeDesc,
  289. PMIDL_STUB_MESSAGE pStubMsg,
  290. unsigned long Size )
  291. /*++
  292. Routine Description :
  293. Performs a partial I_RpcReceive.
  294. Arguments :
  295. pStubMsg - Pointer to stub message structure.
  296. pBufferEnd - taken as StubMsg->Buffer
  297. Return :
  298. --*/
  299. {
  300. //
  301. // On the server we need to keep the dispatch buffer as the non-pipe
  302. // arguments may actually reside in the buffer.
  303. // pPipeDesc->DispatchBuffer always points to the original buffer.
  304. //
  305. // Note that the runtime would free any buffer passed in the receive call
  306. // unless the extra flag is set.
  307. // Buffer being zero means a request for a new buffer.
  308. if ( pPipeDesc->Flags.NoMoreBuffersToRead )
  309. NdrpRaisePipeException( pPipeDesc, RPC_X_BAD_STUB_DATA );
  310. if ( ! pStubMsg->IsClient &&
  311. (pPipeDesc->DispatchBuffer == pStubMsg->RpcMsg->Buffer ) )
  312. {
  313. // Setup a request for a new buffer.
  314. pStubMsg->RpcMsg->Buffer = NULL;
  315. }
  316. NdrReceive( pPipeDesc,
  317. pStubMsg,
  318. Size,
  319. TRUE ); // partial
  320. if ( !( pStubMsg->RpcMsg->RpcFlags & RPC_BUFFER_COMPLETE ) &&
  321. ( pStubMsg->RpcMsg->BufferLength & 0x7 ) )
  322. {
  323. NDR_ASSERT( 0, "Partial buffer length not multiple of 8");
  324. NdrpRaisePipeException( pPipeDesc, RPC_S_INTERNAL_ERROR );
  325. }
  326. if ( pStubMsg->RpcMsg->RpcFlags & RPC_BUFFER_COMPLETE )
  327. pPipeDesc->Flags.NoMoreBuffersToRead = 1;
  328. }
  329. unsigned char * RPC_ENTRY
  330. NdrGetPipeBuffer(
  331. PMIDL_STUB_MESSAGE pStubMsg,
  332. unsigned long BufferLength,
  333. RPC_BINDING_HANDLE Handle )
  334. /*++
  335. Routine Description :
  336. This is the first call at the client or server side. Needs to be
  337. different from NdrGetBuffer as later calls to get buffer are different.
  338. - raw: the buffer will be reallocated by means of I_RpcReallocPipeBuffer
  339. --*/
  340. {
  341. unsigned char * pBuffer;
  342. PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg;
  343. pRpcMsg->RpcFlags &= ~RPC_BUFFER_COMPLETE;
  344. pRpcMsg->RpcFlags |= RPC_BUFFER_PARTIAL;
  345. //#if !defined(__RPC_WIN64__)
  346. pRpcMsg->ProcNum |= RPC_FLAGS_VALID_BIT;
  347. //#endif
  348. pBuffer = NdrGetBuffer( pStubMsg, BufferLength, Handle );
  349. return pBuffer;
  350. }
  351. void RPC_ENTRY
  352. NdrGetPartialBuffer(
  353. PMIDL_STUB_MESSAGE pStubMsg )
  354. /*++
  355. Routine Description :
  356. Gets the next buffer for a partial send depending on the pipe state.
  357. Because of the way partial I_RpcSend works, this routine takes care
  358. of the leftover from the last send by means of setting the buffer
  359. pointer to the first free position.
  360. See NdrPartialSend for more comments.
  361. Return :
  362. --*/
  363. {
  364. RPC_STATUS Status = RPC_S_OK;
  365. NDR_PIPE_DESC * pPipeDesc = (NDR_PIPE_DESC *) pStubMsg->pContext->pPipeDesc;
  366. pStubMsg->RpcMsg->RpcFlags &= ~RPC_BUFFER_COMPLETE;
  367. pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_PARTIAL;
  368. Status = I_RpcReallocPipeBuffer( pStubMsg->RpcMsg,
  369. pStubMsg->BufferLength );
  370. if ( Status != RPC_S_OK )
  371. {
  372. // Raw rpc: if async, don't call runtime to abort later.
  373. if ( pStubMsg->pAsyncMsg )
  374. pStubMsg->pAsyncMsg->Flags.RuntimeCleanedUp = 1;
  375. NdrpRaisePipeException( pPipeDesc, Status );
  376. }
  377. ASSERT( pStubMsg->RpcMsg->BufferLength >= pStubMsg->BufferLength );
  378. pStubMsg->Buffer = (uchar*) pStubMsg->RpcMsg->Buffer +
  379. pPipeDesc->LastPartialSize;
  380. if ( pPipeDesc->LeftoverSize )
  381. {
  382. // Because of sizing, LastPartialSize already had LeftoverSize in it.
  383. RpcpMemoryCopy( pStubMsg->Buffer - pPipeDesc->LeftoverSize,
  384. pPipeDesc->Leftover,
  385. pPipeDesc->LeftoverSize );
  386. }
  387. }
  388. void RPC_ENTRY
  389. NdrPipesInitialize(
  390. PMIDL_STUB_MESSAGE pStubMsg,
  391. PNDR_PIPE_HELPER pPipeHelper,
  392. PNDR_ALLOCA_CONTEXT pAllocContext
  393. )
  394. /*+
  395. Initializes all the pipe structures.
  396. Only standard RPC (non-DCOM) pipes are supported now.
  397. +*/
  398. {
  399. NDR_PIPE_STATE * pRuntimeState;
  400. NDR_ASSERT( ! pStubMsg->pRpcChannelBuffer, "DCOM pipes not supported" );
  401. NDR_PIPE_DESC *pPipeDesc = pPipeHelper->GetPipeDesc();
  402. MIDL_memset( pPipeDesc, 0, sizeof(NDR_PIPE_DESC) );
  403. pPipeDesc->pPipeHelper = pPipeHelper;
  404. pPipeDesc->pAllocContext = pAllocContext;
  405. pStubMsg->pContext->pPipeDesc = pPipeDesc;
  406. // See how many pipes we have and what the maximum wire size is.
  407. if ( pPipeHelper->InitParamEnum() )
  408. {
  409. do
  410. {
  411. unsigned short PipeFlags = pPipeHelper->GetParamPipeFlags();
  412. if ( PipeFlags )
  413. {
  414. if ( PipeFlags & NDR_IN_PIPE )
  415. pPipeDesc->InPipes++;
  416. if ( PipeFlags & NDR_OUT_PIPE )
  417. pPipeDesc->OutPipes++;
  418. pPipeDesc->TotalPipes++;
  419. }
  420. }
  421. while ( pPipeHelper->GotoNextParam() );
  422. }
  423. pPipeDesc->pPipeMsg =
  424. (NDR_PIPE_MESSAGE *)NdrpAlloca( pPipeDesc->pAllocContext,
  425. pPipeDesc->TotalPipes * sizeof( NDR_PIPE_MESSAGE ) );
  426. MIDL_memset( pPipeDesc->pPipeMsg,
  427. 0,
  428. pPipeDesc->TotalPipes * sizeof( NDR_PIPE_MESSAGE ));
  429. pPipeDesc->CurrentPipe = -1;
  430. pPipeDesc->PrevPipe = -1;
  431. pPipeDesc->PipeVersion = NDR_PIPE_VERSION;
  432. // Now set the individual pipe messages.
  433. NDR_PIPE_MESSAGE *pLastInPipe = NULL;
  434. NDR_PIPE_MESSAGE *pLastOutPipe = NULL;
  435. int PipeNo = 0;
  436. if ( pPipeHelper->InitParamEnum() )
  437. {
  438. do
  439. {
  440. unsigned short PipeFlags = pPipeHelper->GetParamPipeFlags();
  441. if ( !PipeFlags)
  442. continue;
  443. NDR_PIPE_MESSAGE * pPipe = & pPipeDesc->pPipeMsg[ PipeNo ];
  444. if ( PipeFlags & NDR_IN_PIPE )
  445. pLastInPipe = pPipe;
  446. if ( PipeFlags & NDR_OUT_PIPE )
  447. pLastOutPipe = pPipe;
  448. pPipe->Signature = NDR_PIPE_SIGNATURE;
  449. pPipe->PipeId = (ushort)PipeNo;
  450. pPipe->PipeStatus = NDR_PIPE_NOT_OPENED;
  451. pPipe->PipeFlags = PipeFlags;
  452. pPipe->pTypeFormat = pPipeHelper->GetParamTypeFormat();
  453. pPipe->pStubMsg = pStubMsg;
  454. pPipe->pPipeObject = (GENERIC_PIPE_TYPE *) pPipeHelper->GetParamArgument();
  455. if ( pPipe->PipeFlags & NDR_REF_PIPE )
  456. {
  457. // dereference the argument to get the pipe control block.
  458. if ( ! pStubMsg->IsClient )
  459. {
  460. // For the server, under interpreter, we don't have
  461. // the actual pipe object that is referenced.
  462. // The stack argument should be null.
  463. NDR_ASSERT( ! *(void **)pPipe->pPipeObject,
  464. "null expected for out pipe by ref" );
  465. // The pipe object is not a real parameter in the
  466. // same sense as the other RPC parameters. The user
  467. // can not free the object.
  468. void * temp = NdrpAlloca( pPipeDesc->pAllocContext,
  469. sizeof(GENERIC_PIPE_TYPE ) );
  470. MIDL_memset( temp, 0, sizeof( GENERIC_PIPE_TYPE ) );
  471. *(void **)pPipe->pPipeObject = temp;
  472. pPipe->PipeFlags |= NDR_OUT_ALLOCED;
  473. }
  474. pPipe->pPipeObject = *(GENERIC_PIPE_TYPE **)pPipe->pPipeObject;
  475. }
  476. // For raw async rpc set up the pipe arg on both sides.
  477. // For non-async raw set up the pipe on server only.
  478. if ( pStubMsg->IsClient )
  479. {
  480. if ( pStubMsg->pAsyncMsg )
  481. {
  482. GENERIC_PIPE_TYPE * pPipeType = pPipe->pPipeObject;
  483. pPipeType->pfnPull = NdrAsyncPipePull;
  484. pPipeType->pfnPush = NdrAsyncPipePush;
  485. pPipeType->pfnAlloc= NdrAsyncPipeAlloc;
  486. pPipeType->pState = (char *)pPipe;
  487. }
  488. }
  489. else
  490. {
  491. GENERIC_PIPE_TYPE * pPipeType = pPipe->pPipeObject;
  492. if ( pStubMsg->pAsyncMsg )
  493. {
  494. pPipeType->pfnPull = NdrAsyncPipePull;
  495. pPipeType->pfnPush = NdrAsyncPipePush;
  496. pPipeType->pfnAlloc= NdrAsyncPipeAlloc;
  497. pPipeType->pState = (char *)pPipe;
  498. }
  499. else
  500. {
  501. pPipeType->pfnPull = (NDR_HR_PIPE_PULL_RTN) NdrPipePull;
  502. pPipeType->pfnPush = (NDR_HR_PIPE_PUSH_RTN) NdrPipePush;
  503. pPipeType->pfnAlloc= (NDR_HR_PIPE_ALLOC_RTN)NdrPipeAlloc;
  504. pPipeType->pState = (char *)pPipe;
  505. }
  506. }
  507. PipeNo++;
  508. } while ( pPipeHelper->GotoNextParam() );
  509. }
  510. // Mark the last in and out pipes.
  511. if ( pLastInPipe )
  512. pLastInPipe->PipeFlags |= NDR_LAST_IN_PIPE;
  513. if ( pLastOutPipe )
  514. pLastOutPipe->PipeFlags |= NDR_LAST_OUT_PIPE;
  515. // Set up structures for receiving pipes.
  516. pPipeDesc->DispatchBuffer = (uchar *) pStubMsg->RpcMsg->Buffer;
  517. pPipeDesc->DispatchBufferLength = pStubMsg->RpcMsg->BufferLength;
  518. if ( pPipeDesc->OutPipes && pStubMsg->IsClient ||
  519. pPipeDesc->InPipes && ! pStubMsg->IsClient )
  520. {
  521. pRuntimeState = & pPipeDesc->RuntimeState;
  522. pRuntimeState->CurrentState = START;
  523. pRuntimeState->TotalElemsCount = 0;
  524. pRuntimeState->PartialElem = 0; // temp buf for elem
  525. pRuntimeState->PartialBufferSize = 0; // temp buf for elem
  526. }
  527. if ( ! pStubMsg->IsClient &&
  528. (pStubMsg->RpcMsg->RpcFlags & RPC_BUFFER_COMPLETE ))
  529. pPipeDesc->Flags.NoMoreBuffersToRead = 1;
  530. }
  531. class NDR_PIPE_HELPER32 : public NDR_PIPE_HELPER
  532. {
  533. private:
  534. PMIDL_STUB_MESSAGE pStubMsg;
  535. char *pStackTop;
  536. unsigned long NumberParameters;
  537. PPARAM_DESCRIPTION pFirstParameter;
  538. PPARAM_DESCRIPTION pCurrentParameter;
  539. unsigned long CurrentParamNumber;
  540. NDR_PIPE_DESC PipeDesc;
  541. public:
  542. void *operator new( size_t stAllocateBlock, PNDR_ALLOCA_CONTEXT pAllocContext )
  543. {
  544. return NdrpAlloca( pAllocContext, (UINT)stAllocateBlock );
  545. }
  546. // Do nothing since the memory will be deleted automatically
  547. void operator delete(void *pMemory) {}
  548. NDR_PIPE_HELPER32( PMIDL_STUB_MESSAGE pStubMsg,
  549. PFORMAT_STRING Params,
  550. char * pStackTop,
  551. unsigned long NumberParams )
  552. {
  553. NDR_PIPE_HELPER32::pStubMsg = pStubMsg;
  554. NDR_PIPE_HELPER32::pStackTop = pStackTop;
  555. pFirstParameter = (PPARAM_DESCRIPTION)Params;
  556. NumberParameters = NumberParams;
  557. }
  558. virtual PNDR_PIPE_DESC GetPipeDesc()
  559. {
  560. return &PipeDesc;
  561. }
  562. virtual bool InitParamEnum()
  563. {
  564. pCurrentParameter = pFirstParameter;
  565. CurrentParamNumber = 0;
  566. return NumberParameters > 0;
  567. }
  568. virtual bool GotoNextParam()
  569. {
  570. if ( CurrentParamNumber + 1 >= NumberParameters )
  571. {
  572. return false;
  573. }
  574. CurrentParamNumber++;
  575. pCurrentParameter = pFirstParameter + CurrentParamNumber;
  576. return true;
  577. }
  578. virtual unsigned short GetParamPipeFlags()
  579. {
  580. if ( !pCurrentParameter->ParamAttr.IsPipe )
  581. return 0;
  582. unsigned short Flags = 0;
  583. if ( pCurrentParameter->ParamAttr.IsIn )
  584. Flags |= NDR_IN_PIPE;
  585. if ( pCurrentParameter->ParamAttr.IsOut )
  586. Flags |= NDR_OUT_PIPE;
  587. if ( pCurrentParameter->ParamAttr.IsSimpleRef )
  588. Flags |= NDR_REF_PIPE;
  589. return Flags;
  590. }
  591. virtual PFORMAT_STRING GetParamTypeFormat()
  592. {
  593. return pStubMsg->StubDesc->pFormatTypes +
  594. pCurrentParameter->TypeOffset;
  595. }
  596. virtual char *GetParamArgument()
  597. {
  598. return pStackTop + pCurrentParameter->StackOffset;
  599. }
  600. virtual void InitPipeStateWithType( PNDR_PIPE_MESSAGE pPipeMsg )
  601. {
  602. FC_PIPE_DEF * pPipeFc = (FC_PIPE_DEF *) pPipeMsg->pTypeFormat;
  603. NDR_PIPE_STATE *pState = & PipeDesc.RuntimeState;
  604. pState->LowChunkLimit = 0;
  605. pState->HighChunkLimit = NDR_DEFAULT_PIPE_HIGH_CHUNK_LIMIT;
  606. pState->ElemAlign = pPipeFc->Align;
  607. if ( pPipeFc->BigPipe )
  608. {
  609. pState->ElemMemSize = * (long UNALIGNED *) & pPipeFc->Big.MemSize;
  610. pState->ElemWireSize = * (long UNALIGNED *) & pPipeFc->Big.WireSize;
  611. if ( pPipeFc->HasRange )
  612. {
  613. pState->LowChunkLimit = * (long UNALIGNED *) &pPipeFc->Big.LowChunkLimit;
  614. pState->HighChunkLimit = * (long UNALIGNED *) &pPipeFc->Big.HighChunkLimit;
  615. }
  616. }
  617. else
  618. {
  619. pState->ElemMemSize = pPipeFc->s.MemSize;
  620. pState->ElemWireSize = pPipeFc->s.WireSize;
  621. if ( pPipeFc->HasRange )
  622. {
  623. pState->LowChunkLimit = * (long UNALIGNED *) &pPipeFc->s.LowChunkLimit;
  624. pState->HighChunkLimit = * (long UNALIGNED *) &pPipeFc->s.HighChunkLimit;
  625. }
  626. }
  627. pState->ElemPad = WIRE_PAD( pState->ElemWireSize, pState->ElemAlign );
  628. pState->fBlockCopy = (pState->ElemMemSize ==
  629. pState->ElemWireSize + pState->ElemPad);
  630. }
  631. virtual void MarshallType( PNDR_PIPE_MESSAGE pPipeMsg,
  632. uchar *pMemory,
  633. unsigned long Elements )
  634. {
  635. unsigned long ElemMemSize = PipeDesc.RuntimeState.ElemMemSize;
  636. FC_PIPE_DEF * pPipeFc = (FC_PIPE_DEF *) pPipeMsg->pTypeFormat;
  637. PFORMAT_STRING pElemFormat =
  638. (uchar *) & pPipeFc->TypeOffset + pPipeFc->TypeOffset;
  639. while( Elements-- )
  640. {
  641. (*pfnMarshallRoutines[ROUTINE_INDEX(*pElemFormat)])
  642. ( pPipeMsg->pStubMsg,
  643. pMemory,
  644. pElemFormat);
  645. pMemory += ElemMemSize;
  646. }
  647. }
  648. virtual void UnmarshallType( PNDR_PIPE_MESSAGE pPipeMsg,
  649. uchar *pMemory,
  650. unsigned long Elements )
  651. {
  652. unsigned long ElemMemSize = PipeDesc.RuntimeState.ElemMemSize;
  653. FC_PIPE_DEF * pPipeFc = (FC_PIPE_DEF *) pPipeMsg->pTypeFormat;
  654. PFORMAT_STRING pElemFormat =
  655. (uchar *) & pPipeFc->TypeOffset + pPipeFc->TypeOffset;
  656. while( Elements-- )
  657. {
  658. (*pfnUnmarshallRoutines[ROUTINE_INDEX(*pElemFormat)])
  659. ( pPipeMsg->pStubMsg,
  660. &pMemory,
  661. pElemFormat,
  662. FALSE );
  663. pMemory += ElemMemSize;
  664. }
  665. }
  666. virtual void BufferSizeType( PNDR_PIPE_MESSAGE pPipeMsg,
  667. uchar *pMemory,
  668. unsigned long Elements )
  669. {
  670. unsigned long ElemMemSize = PipeDesc.RuntimeState.ElemMemSize;
  671. FC_PIPE_DEF * pPipeFc = (FC_PIPE_DEF *) pPipeMsg->pTypeFormat;
  672. PFORMAT_STRING pElemFormat =
  673. (uchar *) & pPipeFc->TypeOffset + pPipeFc->TypeOffset;
  674. while( Elements-- )
  675. {
  676. (*pfnSizeRoutines[ROUTINE_INDEX(*pElemFormat)])
  677. ( pPipeMsg->pStubMsg,
  678. pMemory,
  679. pElemFormat);
  680. pMemory += ElemMemSize;
  681. }
  682. }
  683. virtual void ConvertType( PNDR_PIPE_MESSAGE pPipeMsg,
  684. unsigned long Elements )
  685. {
  686. unsigned long ElemMemSize = PipeDesc.RuntimeState.ElemMemSize;
  687. FC_PIPE_DEF * pPipeFc = (FC_PIPE_DEF *) pPipeMsg->pTypeFormat;
  688. PFORMAT_STRING pElemFormat =
  689. (uchar *) & pPipeFc->TypeOffset + pPipeFc->TypeOffset;
  690. PMIDL_STUB_MESSAGE pStubMsg = pPipeMsg->pStubMsg;
  691. if ( pStubMsg->RpcMsg->DataRepresentation
  692. == NDR_LOCAL_DATA_REPRESENTATION )
  693. return;
  694. uchar * BufferSaved = pStubMsg->Buffer;
  695. // We can end up here for any object.
  696. while ( Elements-- )
  697. {
  698. if ( IS_SIMPLE_TYPE( *pElemFormat) )
  699. {
  700. NdrSimpleTypeConvert( pStubMsg, *pElemFormat );
  701. }
  702. else
  703. {
  704. (*pfnConvertRoutines[ ROUTINE_INDEX( *pElemFormat ) ])
  705. ( pStubMsg,
  706. pElemFormat,
  707. FALSE ); // embedded pointers
  708. }
  709. }
  710. pStubMsg->Buffer = BufferSaved;
  711. }
  712. virtual void BufferSizeChunkCounter( PNDR_PIPE_MESSAGE pPipeMsg )
  713. {
  714. PMIDL_STUB_MESSAGE pStubMsg = pPipeMsg->pStubMsg;
  715. LENGTH_ALIGN( pStubMsg->BufferLength, 3 );
  716. pStubMsg->BufferLength += sizeof(ulong);
  717. }
  718. virtual bool UnmarshallChunkCounter( PNDR_PIPE_MESSAGE pPipeMsg,
  719. ulong *pOut )
  720. {
  721. PMIDL_STUB_MESSAGE pStubMsg = pPipeMsg->pStubMsg;
  722. ALIGN( pStubMsg->Buffer, 3);
  723. if ( 0 == REMAINING_BYTES() )
  724. {
  725. return false;
  726. }
  727. // transition: end of src
  728. if (REMAINING_BYTES() < sizeof(DWORD))
  729. {
  730. // with packet sizes being a multiple of 8,
  731. // this cannot happen.
  732. NDR_ASSERT( 0, "Chunk counter split is not possible.");
  733. NdrpRaisePipeException( &PipeDesc, RPC_S_INTERNAL_ERROR );
  734. return false;
  735. }
  736. if ( pStubMsg->RpcMsg->DataRepresentation
  737. != NDR_LOCAL_DATA_REPRESENTATION )
  738. {
  739. uchar * BufferSaved = pStubMsg->Buffer;
  740. NdrSimpleTypeConvert( pStubMsg, FC_LONG );
  741. pStubMsg->Buffer = BufferSaved;
  742. }
  743. ulong Value = *(ulong*)pStubMsg->Buffer;
  744. pStubMsg->Buffer += sizeof(ulong);
  745. CHECK_BOUND( Value, FC_ULONG );
  746. *pOut = Value;
  747. return true;
  748. }
  749. virtual void MarshallChunkCounter( PNDR_PIPE_MESSAGE pPipeMsg,
  750. ulong Counter )
  751. {
  752. PMIDL_STUB_MESSAGE pStubMsg = pPipeMsg->pStubMsg;
  753. CHECK_BOUND( Counter, FC_ULONG );
  754. ALIGN( pStubMsg->Buffer, 3);
  755. *(ulong*)pStubMsg->Buffer = Counter;
  756. pStubMsg->Buffer += sizeof(ulong);
  757. }
  758. virtual void BufferSizeChunkTailCounter( PNDR_PIPE_MESSAGE pPipeMsg ) { pPipeMsg; };
  759. virtual void MarshallChunkTailCounter( PNDR_PIPE_MESSAGE pPipeMsg,
  760. ulong Counter ) { pPipeMsg; Counter; }
  761. virtual bool VerifyChunkTailCounter( PNDR_PIPE_MESSAGE pPipeMsg,
  762. ulong HeaderCounter )
  763. {
  764. pPipeMsg; HeaderCounter;
  765. return true;
  766. }
  767. virtual bool HasChunkTailCounter() { return FALSE; }
  768. };
  769. typedef NDR_PIPE_HELPER *PNDR_PIPE_HELPER;
  770. void
  771. NdrpPipesInitialize32(
  772. PMIDL_STUB_MESSAGE pStubMsg,
  773. PNDR_ALLOCA_CONTEXT pAllocContext,
  774. PFORMAT_STRING Params,
  775. char * pStackTop,
  776. unsigned long NumberParams
  777. )
  778. {
  779. /* C wrapper to initialize the 32 pipe helper and call NdrPipesInitialize*/
  780. NDR_PIPE_HELPER32 *pPipeHelper =
  781. new( pAllocContext ) NDR_PIPE_HELPER32( pStubMsg,
  782. Params,
  783. pStackTop,
  784. NumberParams );
  785. NdrPipesInitialize( pStubMsg,
  786. pPipeHelper,
  787. pAllocContext );
  788. }
  789. void RPC_ENTRY
  790. ResetToDispatchBuffer(
  791. NDR_PIPE_DESC * pPipeDesc,
  792. PMIDL_STUB_MESSAGE pStubMsg
  793. )
  794. /*
  795. This is a server side routine that makes sure that
  796. the original dispatch buffer is restored to the rpc message.
  797. These are the rules:
  798. - the engine can return to the runtime with the original or a new
  799. buffer; if it's a new buffer it has to be valid (not freed yet).
  800. When exception happens, the runtime will be freeing any buffer
  801. that is different from the original buffer.
  802. - when I_RpcReceive or I_RpcSend fail, they free the current
  803. buffer, and so the stub cannot free it. If this is the second
  804. buffer, the original dispatch buffer pointer should be restored
  805. in the rpcmsg.
  806. - the second buffer does not have to be freed in case of a
  807. normal return or an exception clean up in a situation different
  808. from above. The runtime will free it.
  809. Note that we never free the original dispatch buffer.
  810. */
  811. {
  812. PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg;
  813. // If the dispatch buffer was replaced by a partial buffer,
  814. // free the partial buffer and restore the dispatch buffer.
  815. if ( pPipeDesc->DispatchBuffer != pRpcMsg->Buffer )
  816. {
  817. I_RpcFreePipeBuffer( pRpcMsg );
  818. pRpcMsg->Buffer = pPipeDesc->DispatchBuffer;
  819. pStubMsg->BufferStart = pPipeDesc->DispatchBuffer;
  820. pStubMsg->BufferEnd = pStubMsg->BufferStart + pPipeDesc->DispatchBufferLength;
  821. }
  822. }
  823. void RPC_ENTRY
  824. NdrPipeSendReceive(
  825. PMIDL_STUB_MESSAGE pStubMsg,
  826. NDR_PIPE_DESC * pPipeDesc
  827. )
  828. /*+
  829. Complete send-receive routine for client pipes.
  830. It takes over with a buffer filled with non-pipe args,
  831. sends [in] pipes, receives [out] pipes and then receives
  832. the buffer with non-pipe args.
  833. +*/
  834. {
  835. int CurrentPipe;
  836. NDR_PIPE_MESSAGE * pPipeMsg;
  837. RPC_STATUS Status;
  838. // Service the in pipes
  839. if ( pPipeDesc->InPipes )
  840. {
  841. // Once we know we have an [in] pipe, we can send the non-pipe
  842. // arguments via a partial I_RpcSend.
  843. // It is OK to call that with the BufferLength equal zero.
  844. NdrPartialSend( pPipeDesc, pStubMsg );
  845. for ( CurrentPipe = 0; CurrentPipe < pPipeDesc->TotalPipes; CurrentPipe++ )
  846. {
  847. long LastChunkSent;
  848. pPipeMsg = & pPipeDesc->pPipeMsg[ CurrentPipe ];
  849. if ( ! (pPipeMsg->PipeFlags & NDR_IN_PIPE) )
  850. continue;
  851. pPipeDesc->CurrentPipe = (short) CurrentPipe;
  852. pPipeMsg->PipeStatus = (ushort) NDR_PIPE_ACTIVE_IN;
  853. Status = NdrpPushPipeForClient( pStubMsg,
  854. pPipeDesc,
  855. TRUE, // whole pipe
  856. &LastChunkSent );
  857. // The call above would raise an exception for any case other than
  858. // dcom async pipe case. This covers sync usage of this code path.
  859. // So, if we are here, the call succeeded, the status should be ok
  860. // and last chunk zero, as we requested to push the whole pipe.
  861. NDR_ASSERT( Status == RPC_S_OK && LastChunkSent == 0,
  862. "should process all or raise exception" );
  863. pPipeMsg->PipeStatus = NDR_PIPE_DRAINED;
  864. } // for [in] pipes
  865. }
  866. NdrCompleteSend( pPipeDesc, pStubMsg );
  867. // The above call uses I_RpcSend and requires that I_RpcReceive is called
  868. // later. This has to be done regardless whether any data is expected
  869. // in the buffer or not.
  870. // The receive call is complete or partial depending on the context.
  871. if ( pPipeDesc->OutPipes == 0 )
  872. {
  873. // After send we would still have the [in] buffer around so we
  874. // need to clear the extra flag to avoid appending.
  875. pStubMsg->RpcMsg->RpcFlags &= ~RPC_BUFFER_EXTRA;
  876. NdrReceive( pPipeDesc,
  877. pStubMsg,
  878. 0, // size, ignored for complete calls
  879. FALSE ); // complete buffer
  880. return;
  881. }
  882. // Service the out pipes
  883. // Partial calls always clear up the extra flag before calling runtime.
  884. NdrPartialReceive( pPipeDesc,
  885. pStubMsg,
  886. PIPE_PARTIAL_BUFFER_SIZE );
  887. // The buffer has some pipe elemements
  888. pPipeDesc->BufferSave = pStubMsg->Buffer;
  889. pPipeDesc->LengthSave = pStubMsg->RpcMsg->BufferLength;
  890. for ( CurrentPipe = 0; CurrentPipe < pPipeDesc->TotalPipes; CurrentPipe++ )
  891. {
  892. long LastChunk;
  893. BOOL EndOfPipe;
  894. pPipeMsg = & pPipeDesc->pPipeMsg[ CurrentPipe ];
  895. if ( ! (pPipeMsg->PipeFlags & NDR_OUT_PIPE) )
  896. continue;
  897. pPipeDesc->CurrentPipe = (short) CurrentPipe;
  898. pPipeMsg->PipeStatus = NDR_PIPE_ACTIVE_OUT;
  899. Status = NdrpPullPipeForClient( pStubMsg,
  900. pPipeDesc,
  901. TRUE, // whole pipe
  902. & LastChunk,
  903. & EndOfPipe );
  904. NDR_ASSERT( Status == RPC_S_OK && EndOfPipe,
  905. "should process all or raise exception" );
  906. pPipeMsg->PipeStatus = NDR_PIPE_DRAINED;
  907. } // for [out] pipes
  908. // After all the partial receives, have the last one that is complete.
  909. if ( ! (pStubMsg->RpcMsg->RpcFlags & RPC_BUFFER_COMPLETE) )
  910. {
  911. // On the last call at client we need the extra flag as some
  912. // non-pipe data may have already been received.
  913. pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_EXTRA;
  914. NdrReceive( pPipeDesc,
  915. pStubMsg,
  916. 0, // size, ignored for complete calls
  917. FALSE ); // complete buffer
  918. }
  919. }
  920. RPC_STATUS
  921. NdrpPushPipeForClient(
  922. PMIDL_STUB_MESSAGE pStubMsg,
  923. NDR_PIPE_DESC * pPipeDesc,
  924. BOOL fWholePipe,
  925. long * pLastChunkSent )
  926. {
  927. PFORMAT_STRING pElemFormat;
  928. ulong ElemAlign, ElemMemSize, ElemWireSize, ElemPad;
  929. ulong PipeAllocSize, CopySize;
  930. BOOL fBlockCopy;
  931. RPC_STATUS Status = RPC_S_OK;
  932. NDR_PIPE_LOG(PIPE_LOG_NOISE, ("NdrpPushPipeForClient: pStubMsg->Buffer %p", pStubMsg->Buffer) );
  933. RpcTryExcept
  934. {
  935. NDR_PIPE_MESSAGE * pPipeMsg = & pPipeDesc->pPipeMsg[ pPipeDesc->CurrentPipe ];
  936. // Service an in pipe.
  937. GENERIC_PIPE_TYPE * pPipeType = pPipeMsg->pPipeObject;
  938. pPipeDesc->pPipeHelper->InitPipeStateWithType( pPipeMsg );
  939. ElemAlign = pPipeDesc->RuntimeState.ElemAlign;
  940. ElemMemSize = pPipeDesc->RuntimeState.ElemMemSize;
  941. ElemWireSize = pPipeDesc->RuntimeState.ElemWireSize;
  942. ElemPad = pPipeDesc->RuntimeState.ElemPad;
  943. fBlockCopy = pPipeDesc->RuntimeState.fBlockCopy;
  944. if ( PIPE_PARTIAL_BUFFER_SIZE < ElemMemSize )
  945. PipeAllocSize = ElemMemSize;
  946. else
  947. PipeAllocSize = PIPE_PARTIAL_BUFFER_SIZE;
  948. uchar * pMemory;
  949. unsigned long bcChunkSize;
  950. unsigned long ActElems, ReqElems;
  951. NDR_HR_PIPE_PULL_RTN pfnPull = pPipeType->pfnPull;
  952. NDR_HR_PIPE_ALLOC_RTN pfnAlloc = pPipeType->pfnAlloc;
  953. void * pThis = pPipeType->pState;
  954. do
  955. {
  956. HRESULT Hr;
  957. // Get memory for the pipe elements
  958. Hr = (*pfnAlloc)( (char *)pThis,
  959. PipeAllocSize,
  960. (void **) & pMemory,
  961. & bcChunkSize );
  962. if ( pMemory == 0 )
  963. NdrpRaisePipeException( pPipeDesc, RPC_X_PIPE_APP_MEMORY );
  964. // Get the pipe elements to the buffer.
  965. ActElems = bcChunkSize / ElemMemSize;
  966. ReqElems = ActElems;
  967. if ( ActElems == 0 )
  968. NdrpRaisePipeException( pPipeDesc, RPC_X_INVALID_BUFFER );
  969. Hr = (*pfnPull)( (char *)pThis,
  970. pMemory,
  971. ActElems,
  972. & ActElems );
  973. NDR_PIPE_LOG( PIPE_LOG_NOISE, ("NdrpPushPipeForClient: pfnPull returned %d ActElems", ActElems) );
  974. if ( ReqElems < ActElems )
  975. NdrpRaisePipeException( pPipeDesc, RPC_X_INVALID_BUFFER );
  976. //
  977. // Size the chunk and get the marshaling buffer
  978. //
  979. pStubMsg->BufferLength = pPipeDesc->LastPartialSize;
  980. pPipeDesc->pPipeHelper->BufferSizeChunkCounter( pPipeMsg );
  981. CopySize = ( ActElems - 1) * (ElemWireSize + ElemPad)
  982. + ElemWireSize;
  983. if ( ActElems )
  984. {
  985. LENGTH_ALIGN( pStubMsg->BufferLength, ElemAlign );
  986. if ( fBlockCopy )
  987. pStubMsg->BufferLength += CopySize;
  988. else
  989. {
  990. NdrpPipeElementBufferSize( pPipeDesc,
  991. pStubMsg,
  992. pMemory,
  993. ActElems );
  994. }
  995. }
  996. pPipeDesc->pPipeHelper->BufferSizeChunkTailCounter( pPipeMsg );
  997. // Get the new buffer, put the frame leftover in it.
  998. NdrGetPartialBuffer( pStubMsg );
  999. //
  1000. // Marshal the chunk
  1001. //
  1002. pPipeDesc->pPipeHelper->MarshallChunkCounter( pPipeMsg,
  1003. ActElems );
  1004. NDR_PIPE_LOG( PIPE_LOG_NOISE, ( "Writting pipe chunk: %d", ActElems ) );
  1005. if ( ActElems )
  1006. {
  1007. ALIGN( pStubMsg->Buffer, ElemAlign );
  1008. if ( fBlockCopy )
  1009. {
  1010. RpcpMemoryCopy( pStubMsg->Buffer,
  1011. pMemory,
  1012. CopySize );
  1013. pStubMsg->Buffer += CopySize;
  1014. }
  1015. else
  1016. {
  1017. // Again: only complex is possible
  1018. pPipeDesc->pPipeHelper->MarshallType( pPipeMsg,
  1019. pMemory,
  1020. ActElems );
  1021. pMemory += ActElems * ElemMemSize;
  1022. }
  1023. }
  1024. pPipeDesc->pPipeHelper->MarshallChunkTailCounter( pPipeMsg,
  1025. ActElems );
  1026. // Send it if it is not the last partial send.
  1027. if ( !(pPipeMsg->PipeFlags & NDR_LAST_IN_PIPE) ||
  1028. ((pPipeMsg->PipeFlags & NDR_LAST_IN_PIPE) && ActElems)
  1029. )
  1030. NdrPartialSend( pPipeDesc, pStubMsg );
  1031. }
  1032. while( fWholePipe && ActElems > 0 );
  1033. *pLastChunkSent = ActElems;
  1034. NDR_PIPE_LOG( PIPE_LOG_NOISE, ("NdrpPushPipeForClient: exit *pLastChunkSent", *pLastChunkSent ) );
  1035. }
  1036. RpcExcept( ! (RPC_BAD_STUB_DATA_EXCEPTION_FILTER) )
  1037. {
  1038. Status = RpcExceptionCode();
  1039. NdrpRaisePipeException( pPipeDesc, Status );
  1040. }
  1041. RpcEndExcept
  1042. return Status;
  1043. }
  1044. RPC_STATUS
  1045. NdrpPullPipeForClient(
  1046. PMIDL_STUB_MESSAGE pStubMsg,
  1047. NDR_PIPE_DESC * pPipeDesc,
  1048. BOOL fWholePipe,
  1049. long * pActElems,
  1050. BOOL * pEndOfPipe )
  1051. {
  1052. PFORMAT_STRING pElemFormat;
  1053. ulong ElemAlign, ElemMemSize, ElemWireSize, ElemPad;
  1054. BOOL fBlockCopy;
  1055. long ActElems;
  1056. RPC_STATUS Status = RPC_S_OK;
  1057. RpcTryExcept
  1058. {
  1059. NDR_PIPE_MESSAGE * pPipeMsg = & pPipeDesc->pPipeMsg[ pPipeDesc->CurrentPipe ];
  1060. // Service an out pipe
  1061. pPipeDesc->pPipeHelper->InitPipeStateWithType( pPipeMsg );
  1062. pPipeDesc->RuntimeState.EndOfPipe = 0;
  1063. ElemAlign = pPipeDesc->RuntimeState.ElemAlign;
  1064. ElemMemSize = pPipeDesc->RuntimeState.ElemMemSize;
  1065. ElemWireSize = pPipeDesc->RuntimeState.ElemWireSize;
  1066. ElemPad = pPipeDesc->RuntimeState.ElemPad;
  1067. fBlockCopy = pPipeDesc->RuntimeState.fBlockCopy;
  1068. GENERIC_PIPE_TYPE * pPipeType = pPipeMsg->pPipeObject;
  1069. NDR_HR_PIPE_PUSH_RTN pfnPush = pPipeType->pfnPush;
  1070. NDR_HR_PIPE_ALLOC_RTN pfnAlloc = pPipeType->pfnAlloc;
  1071. void * pThis = pPipeType->pState;
  1072. BOOL EndOfPipe;
  1073. // RequestedSize estimates a reasonable size for pfnAlloc call.
  1074. HRESULT Hr;
  1075. ulong RequestedSize;
  1076. uchar * pMemory;
  1077. if (ElemWireSize< PIPE_PARTIAL_BUFFER_SIZE)
  1078. RequestedSize = (PIPE_PARTIAL_BUFFER_SIZE / ElemWireSize)
  1079. * ElemMemSize;
  1080. else
  1081. RequestedSize = 2 * ElemMemSize;
  1082. do
  1083. {
  1084. unsigned long bcChunkSize;
  1085. // Get a chunk of memory for pipe elements to push
  1086. Hr = (*pfnAlloc)( (char *)pThis,
  1087. RequestedSize,
  1088. (void **) & pMemory,
  1089. & bcChunkSize );
  1090. if ( pMemory == 0 )
  1091. NdrpRaisePipeException( pPipeDesc, RPC_X_PIPE_APP_MEMORY );
  1092. ActElems = bcChunkSize / ElemMemSize;
  1093. if ( ActElems == 0 )
  1094. NdrpRaisePipeException( pPipeDesc, RPC_X_INVALID_BUFFER );
  1095. EndOfPipe = NdrReadPipeElements( pPipeDesc,
  1096. pStubMsg,
  1097. pMemory,
  1098. & ActElems );
  1099. Hr = (*pfnPush)( (char *)pThis,
  1100. pMemory,
  1101. ActElems );
  1102. }
  1103. while ( fWholePipe && ActElems && ! EndOfPipe );
  1104. if ( ActElems )
  1105. {
  1106. Hr = (*pfnPush)( (char *)pThis,
  1107. pMemory + ActElems * ElemMemSize,
  1108. 0 );
  1109. }
  1110. *pActElems = ActElems;
  1111. *pEndOfPipe = EndOfPipe;
  1112. }
  1113. RpcExcept( ! (RPC_BAD_STUB_DATA_EXCEPTION_FILTER) )
  1114. {
  1115. Status = RpcExceptionCode();
  1116. NdrpRaisePipeException( pPipeDesc, Status );
  1117. }
  1118. RpcEndExcept
  1119. return Status;
  1120. }
  1121. void
  1122. NdrMarkNextActivePipe(
  1123. NDR_PIPE_DESC * pPipeDesc )
  1124. /*
  1125. Description:
  1126. This routine is used on the server side sync calls, or on both side of async
  1127. calls to manage the proper sequence of pipes to service.
  1128. Note:
  1129. When the last possible pipe is done, this routine restores the
  1130. original dispatch buffer to the rpc message.
  1131. */
  1132. {
  1133. unsigned long Mask;
  1134. int NextPipe = 0;
  1135. int CurrentPipe = pPipeDesc->CurrentPipe;
  1136. if ( CurrentPipe == -1 )
  1137. {
  1138. // This means an initial call at any side.
  1139. // Find the first in pipe, or if none, find first out pipe.
  1140. Mask = pPipeDesc->InPipes ? NDR_IN_PIPE
  1141. : NDR_OUT_PIPE;
  1142. }
  1143. else
  1144. {
  1145. // Switching from one active pipe to another.
  1146. NDR_PIPE_MESSAGE * pPipeMsg;
  1147. unsigned short LastPipeStatus;
  1148. pPipeMsg = & pPipeDesc->pPipeMsg[ pPipeDesc->CurrentPipe ];
  1149. LastPipeStatus = pPipeMsg->PipeStatus;
  1150. pPipeMsg->PipeStatus = NDR_PIPE_DRAINED;
  1151. // Mark no active pipe.
  1152. pPipeDesc->PrevPipe = pPipeDesc->CurrentPipe;
  1153. pPipeDesc->CurrentPipe = -1;
  1154. // See if the drained pipe was the last possible pipe.
  1155. if ( (LastPipeStatus == NDR_PIPE_ACTIVE_OUT) &&
  1156. (pPipeMsg->PipeFlags & NDR_LAST_OUT_PIPE) )
  1157. {
  1158. return;
  1159. }
  1160. // See if the drained pipe was the last in pipe.
  1161. // Set how to look for the next active pipe.
  1162. if ( (LastPipeStatus == NDR_PIPE_ACTIVE_IN) &&
  1163. (pPipeMsg->PipeFlags & NDR_LAST_IN_PIPE) )
  1164. {
  1165. ResetToDispatchBuffer( pPipeDesc, pPipeMsg->pStubMsg );
  1166. if (pPipeDesc->OutPipes == 0)
  1167. return;
  1168. // Change direction after the last in pipe.
  1169. // The search will be from the beginning.
  1170. Mask = NDR_OUT_PIPE;
  1171. }
  1172. else
  1173. {
  1174. // Same direction, start the search with the next pipe.
  1175. NextPipe = CurrentPipe + 1;
  1176. Mask = (LastPipeStatus == NDR_PIPE_ACTIVE_IN) ? NDR_IN_PIPE
  1177. : NDR_OUT_PIPE;
  1178. }
  1179. }
  1180. // First fit. We are here only when there is another pipe to service.
  1181. while( NextPipe < pPipeDesc->TotalPipes )
  1182. {
  1183. if ( pPipeDesc->pPipeMsg[NextPipe].PipeFlags & Mask )
  1184. {
  1185. pPipeDesc->CurrentPipe = (short) NextPipe;
  1186. if ( Mask == NDR_IN_PIPE )
  1187. {
  1188. pPipeDesc->pPipeMsg[NextPipe].PipeStatus = NDR_PIPE_ACTIVE_IN;
  1189. }
  1190. else
  1191. {
  1192. pPipeDesc->pPipeMsg[NextPipe].PipeStatus = NDR_PIPE_ACTIVE_OUT;
  1193. }
  1194. pPipeDesc->pPipeHelper->InitPipeStateWithType( &pPipeDesc->pPipeMsg[NextPipe] );
  1195. pPipeDesc->RuntimeState.EndOfPipe = 0;
  1196. break;
  1197. }
  1198. NextPipe++;
  1199. }
  1200. // If it is the first out pipe on server, get the buffer.
  1201. PMIDL_STUB_MESSAGE pStubMsg = pPipeDesc->pPipeMsg[NextPipe].pStubMsg;
  1202. if ( ! pStubMsg->IsClient &&
  1203. Mask == NDR_OUT_PIPE &&
  1204. ! pPipeDesc->Flags.AuxOutBufferAllocated )
  1205. {
  1206. NdrGetPipeBuffer( pStubMsg,
  1207. PIPE_PARTIAL_BUFFER_SIZE,
  1208. pStubMsg->SavedHandle );
  1209. pPipeDesc->Flags.AuxOutBufferAllocated = 1;
  1210. }
  1211. }
  1212. void
  1213. NdrpVerifyPipe( char * pState )
  1214. /*
  1215. This routine verifies the context for server application calling
  1216. pull or push emtries of the engine.
  1217. */
  1218. {
  1219. NDR_PIPE_MESSAGE * pPipeMsg = (NDR_PIPE_MESSAGE *) pState;
  1220. if ( ! pPipeMsg ||
  1221. ! pPipeMsg->pStubMsg ||
  1222. pPipeMsg->Signature != NDR_PIPE_SIGNATURE )
  1223. RpcRaiseException( RPC_X_INVALID_PIPE_OBJECT );
  1224. NDR_PIPE_DESC * pPipeDesc = (NDR_PIPE_DESC *) pPipeMsg->pStubMsg->pContext->pPipeDesc;
  1225. if ( ! pPipeDesc )
  1226. RpcRaiseException( RPC_X_INVALID_PIPE_OBJECT );
  1227. // An exception occured on the pipe call, but the app
  1228. // for some unknown reason is trying to call Rpc again.
  1229. // Just rethrow the exception that the app received the first time.
  1230. if ( 0 != pPipeDesc->PipeException )
  1231. RpcRaiseException( pPipeDesc->PipeException );
  1232. // See if a different pipe is currently active.
  1233. if ( pPipeDesc->CurrentPipe != -1 &&
  1234. & pPipeDesc->pPipeMsg[ pPipeDesc->CurrentPipe ] != pPipeMsg )
  1235. NdrpRaisePipeException( pPipeDesc, RPC_X_WRONG_PIPE_ORDER );
  1236. }
  1237. void RPC_ENTRY
  1238. NdrIsAppDoneWithPipes(
  1239. NDR_PIPE_DESC * pPipeDesc
  1240. )
  1241. /*
  1242. This routine is called from the engine after the manager code returned
  1243. to the engine to see if all the pipes have been processed.
  1244. It is also called from NdrCompleteAsyncClientCall.
  1245. It is not called from the synchronous client as it is the stub
  1246. that manages the pipe processing for synchronous case.
  1247. */
  1248. {
  1249. // It is possible for the server in sync rpc and both side in async rpc
  1250. // to receive an error, ignore it and continue.
  1251. // To prevent this, rethrow the exception if an exception was hit before.
  1252. if ( pPipeDesc->PipeException )
  1253. RpcRaiseException( pPipeDesc->PipeException );
  1254. if ( pPipeDesc->CurrentPipe != -1 )
  1255. NdrpRaisePipeException( pPipeDesc, RPC_X_PIPE_DISCIPLINE_ERROR );
  1256. for (int i = 0; i < pPipeDesc->TotalPipes; i++ )
  1257. if ( pPipeDesc->pPipeMsg[i].PipeStatus != NDR_PIPE_DRAINED )
  1258. NdrpRaisePipeException( pPipeDesc, RPC_X_PIPE_DISCIPLINE_ERROR );
  1259. }
  1260. void RPC_ENTRY
  1261. NdrPipePull(
  1262. char * pState,
  1263. void * buf,
  1264. unsigned long esize,
  1265. unsigned long * ecount )
  1266. /*+
  1267. Server side [in] pipe arguments.
  1268. -*/
  1269. {
  1270. NDR_PIPE_LOG( PIPE_LOG_API, ( "NdrPipePull: pState %p", pState ) );
  1271. NDR_PIPE_LOG( PIPE_LOG_API, ( " buf %p, esize %u", buf, esize ) );
  1272. NDR_PIPE_LOG( PIPE_LOG_API, ( " ecount %p", ecount ) );
  1273. NdrpVerifyPipe( pState );
  1274. NDR_PIPE_MESSAGE * pPipeMsg = (NDR_PIPE_MESSAGE *) pState;
  1275. PMIDL_STUB_MESSAGE pStubMsg = pPipeMsg->pStubMsg;
  1276. NDR_PIPE_DESC * pPipeDesc = (NDR_PIPE_DESC *) pStubMsg->pContext->pPipeDesc;
  1277. if ( pPipeDesc->CurrentPipe == -1 &&
  1278. & pPipeDesc->pPipeMsg[ pPipeDesc->PrevPipe ] == pPipeMsg )
  1279. {
  1280. // An attempt to read from the pipe that was the last one used.
  1281. NdrpRaisePipeException( pPipeDesc, RPC_X_PIPE_EMPTY );
  1282. }
  1283. // Pulling in pipe on async raw client, out pipe on any server
  1284. if ( pPipeMsg->PipeStatus == NDR_PIPE_ACTIVE_IN && pStubMsg->IsClient ||
  1285. pPipeMsg->PipeStatus == NDR_PIPE_ACTIVE_OUT && !pStubMsg->IsClient )
  1286. NdrpRaisePipeException( pPipeDesc, RPC_X_WRONG_PIPE_ORDER );
  1287. if ( esize == 0 )
  1288. NdrpRaisePipeException( pPipeDesc, RPC_S_INVALID_ARG );
  1289. long ElemCount = (long) esize;
  1290. *ecount = 0;
  1291. if ( pPipeDesc->RuntimeState.EndOfPipe )
  1292. {
  1293. NdrMarkNextActivePipe( pPipeDesc );
  1294. return;
  1295. }
  1296. uchar * pMemory = (uchar*) buf;
  1297. BOOL EndOfPipe;
  1298. EndOfPipe = NdrReadPipeElements( pPipeDesc,
  1299. pStubMsg,
  1300. pMemory,
  1301. & ElemCount );
  1302. NDR_ASSERT( ElemCount <= (long)esize, "read more than asked for" );
  1303. *ecount = ElemCount;
  1304. if ( EndOfPipe && ElemCount == 0 )
  1305. NdrMarkNextActivePipe( pPipeDesc );
  1306. }
  1307. void RPC_ENTRY
  1308. NdrPipePush(
  1309. char * pState,
  1310. void * buf,
  1311. unsigned long ecount )
  1312. /*+
  1313. Server side [out] pipe arguments.
  1314. -*/
  1315. {
  1316. NDR_PIPE_LOG( PIPE_LOG_API, ( "NdrPipePush: pState %p", pState ) );
  1317. NDR_PIPE_LOG( PIPE_LOG_API, ( " Buf %p, ecount %u", buf, ecount ) );
  1318. NdrpVerifyPipe( pState );
  1319. NDR_PIPE_MESSAGE * pPipeMsg = (NDR_PIPE_MESSAGE *) pState;
  1320. PMIDL_STUB_MESSAGE pStubMsg = pPipeMsg->pStubMsg;
  1321. NDR_PIPE_DESC * pPipeDesc = (NDR_PIPE_DESC *) pStubMsg->pContext->pPipeDesc;
  1322. if ( pPipeDesc->CurrentPipe == -1 &&
  1323. & pPipeDesc->pPipeMsg[ pPipeDesc->PrevPipe ] == pPipeMsg )
  1324. {
  1325. // An attempt to write the pipe that was the last one used.
  1326. NdrpRaisePipeException( pPipeDesc, RPC_X_PIPE_CLOSED );
  1327. }
  1328. // Pushing out pipe on async raw client, in pipe on any server
  1329. if ( pPipeMsg->PipeStatus == NDR_PIPE_ACTIVE_OUT && pStubMsg->IsClient ||
  1330. pPipeMsg->PipeStatus == NDR_PIPE_ACTIVE_IN && !pStubMsg->IsClient )
  1331. NdrpRaisePipeException( pPipeDesc, RPC_X_WRONG_PIPE_ORDER );
  1332. ulong ElemAlign = pPipeDesc->RuntimeState.ElemAlign;
  1333. ulong ElemMemSize = pPipeDesc->RuntimeState.ElemMemSize;
  1334. ulong ElemWireSize = pPipeDesc->RuntimeState.ElemWireSize;
  1335. ulong ElemPad = pPipeDesc->RuntimeState.ElemPad;
  1336. BOOL fBlockCopy = pPipeDesc->RuntimeState.fBlockCopy;
  1337. // Size the chunk and get the marshaling buffer
  1338. //
  1339. pStubMsg->BufferLength = pPipeDesc->LastPartialSize;
  1340. pPipeDesc->pPipeHelper->BufferSizeChunkCounter( pPipeMsg );
  1341. ulong CopySize = ( ecount - 1) * (ElemWireSize + ElemPad)
  1342. + ElemWireSize;
  1343. uchar * pMemory = (uchar*) buf;
  1344. if ( ecount )
  1345. {
  1346. LENGTH_ALIGN( pStubMsg->BufferLength, ElemAlign );
  1347. if ( fBlockCopy )
  1348. pStubMsg->BufferLength += CopySize;
  1349. else
  1350. {
  1351. NdrpPipeElementBufferSize( pPipeDesc,
  1352. pStubMsg,
  1353. pMemory,
  1354. ecount );
  1355. }
  1356. }
  1357. pPipeDesc->pPipeHelper->BufferSizeChunkTailCounter( pPipeMsg );
  1358. // Get the new buffer, put the frame leftover in it.
  1359. NdrGetPartialBuffer( pStubMsg );
  1360. // Marshal the chunk
  1361. pPipeDesc->pPipeHelper->MarshallChunkCounter( pPipeMsg, ecount );
  1362. if ( ecount )
  1363. {
  1364. ALIGN( pStubMsg->Buffer, ElemAlign );
  1365. if ( fBlockCopy )
  1366. {
  1367. RpcpMemoryCopy( pStubMsg->Buffer,
  1368. pMemory,
  1369. CopySize );
  1370. pStubMsg->Buffer += CopySize;
  1371. }
  1372. else
  1373. {
  1374. // Again: only complex is possible
  1375. pPipeDesc->pPipeHelper->MarshallType( pPipeMsg,
  1376. pMemory,
  1377. ecount );
  1378. pMemory += ElemMemSize * ecount;
  1379. }
  1380. }
  1381. pPipeDesc->pPipeHelper->MarshallChunkTailCounter( pPipeMsg, ecount );
  1382. // If it is not the last terminator, use a partial send.
  1383. // On client (async only) the last send should be complete,
  1384. // On server (sync or async) the complete send will happen after marshaling
  1385. // non-pipe out data.
  1386. // Channel requires the last call on server.
  1387. if ( pStubMsg->IsClient )
  1388. {
  1389. if ( ecount == 0 && (pPipeMsg->PipeFlags & NDR_LAST_IN_PIPE))
  1390. NdrCompleteSend( pPipeDesc, pStubMsg );
  1391. else
  1392. NdrPartialSend( pPipeDesc, pStubMsg );
  1393. }
  1394. else
  1395. NdrPartialSend( pPipeDesc, pStubMsg );
  1396. if ( ecount == 0 )
  1397. NdrMarkNextActivePipe( pPipeDesc );
  1398. }
  1399. void RPC_ENTRY
  1400. NdrPipeAlloc(
  1401. char * pState,
  1402. unsigned long bsize,
  1403. void **buf,
  1404. unsigned long * bcount )
  1405. /*
  1406. This method has been introduced to support pipe chaining - when
  1407. a server becomes a client and passes a pipe argument along.
  1408. Only one buffer is ever there: next call releases the previous one.
  1409. */
  1410. {
  1411. NDR_PIPE_LOG( PIPE_LOG_API, ( "NdrPipeAlloc: pState %p", pState ) );
  1412. NDR_PIPE_LOG( PIPE_LOG_API, ( " bsize %d, buf %p", bsize, buf ) );
  1413. NDR_PIPE_LOG( PIPE_LOG_API, ( " bcount %p", bcount ) );
  1414. NdrpVerifyPipe( pState );
  1415. NDR_PIPE_MESSAGE * pPipeMsg = (NDR_PIPE_MESSAGE *) pState;
  1416. PMIDL_STUB_MESSAGE pStubMsg = pPipeMsg->pStubMsg;
  1417. NDR_PIPE_DESC * pPipeDesc = (NDR_PIPE_DESC *) pStubMsg->pContext->pPipeDesc;
  1418. if ( pPipeDesc->ChainingBuffer )
  1419. {
  1420. if ( pPipeDesc->ChainingBufferSize >= bsize )
  1421. {
  1422. *bcount = pPipeDesc->ChainingBufferSize;
  1423. *buf = pPipeDesc->ChainingBuffer;
  1424. return;
  1425. }
  1426. else
  1427. {
  1428. NdrpPrivateFree( pPipeDesc->pAllocContext, pPipeDesc->ChainingBuffer );
  1429. pPipeDesc->ChainingBuffer = NULL;
  1430. pPipeDesc->ChainingBufferSize = 0;
  1431. }
  1432. }
  1433. RpcTryExcept
  1434. {
  1435. pPipeDesc->ChainingBuffer = NdrpPrivateAllocate( pPipeDesc->pAllocContext, bsize );
  1436. }
  1437. RpcExcept(1)
  1438. {
  1439. NdrpRaisePipeException( pPipeDesc, RPC_S_OUT_OF_MEMORY );
  1440. }
  1441. RpcEndExcept
  1442. *bcount = bsize;
  1443. *buf = pPipeDesc->ChainingBuffer;
  1444. }
  1445. void
  1446. NdrpAsyncHandlePipeError(
  1447. char * pState,
  1448. RPC_STATUS Status )
  1449. /*++
  1450. Routine Description :
  1451. Forces the connect to close by either freeing the buffer
  1452. or aborting the call on an async pipe error.
  1453. Arguments :
  1454. pState - Supplies the pipe state.
  1455. Statue - Supplies the error code.
  1456. Return :
  1457. None.
  1458. --*/
  1459. {
  1460. NDR_PIPE_MESSAGE *pPipeMsg;
  1461. MIDL_STUB_MESSAGE *pStubMsg;
  1462. PNDR_ASYNC_MESSAGE pAsyncMsg;
  1463. // Pending isn't really an error.
  1464. if ( RPC_S_ASYNC_CALL_PENDING == Status )
  1465. return;
  1466. if ( !pState )
  1467. {
  1468. return;
  1469. }
  1470. pPipeMsg = (NDR_PIPE_MESSAGE *)pState;
  1471. if ( ! pPipeMsg->pStubMsg ||
  1472. pPipeMsg->Signature != NDR_PIPE_SIGNATURE )
  1473. return;
  1474. pStubMsg = pPipeMsg->pStubMsg;
  1475. if ( !pStubMsg->pAsyncMsg )
  1476. {
  1477. return;
  1478. }
  1479. pAsyncMsg = pStubMsg->pAsyncMsg;
  1480. RpcTryExcept
  1481. {
  1482. if ( ! pAsyncMsg->Flags.RuntimeCleanedUp )
  1483. {
  1484. if ( pStubMsg->IsClient )
  1485. {
  1486. NdrFreeBuffer( pStubMsg );
  1487. }
  1488. else
  1489. {
  1490. I_RpcAsyncAbortCall( pAsyncMsg->AsyncHandle, Status);
  1491. }
  1492. }
  1493. }
  1494. RpcExcept(1)
  1495. {
  1496. // Ignore and exceptions that occured
  1497. }
  1498. RpcEndExcept
  1499. pAsyncMsg->Flags.RuntimeCleanedUp = 1;
  1500. }
  1501. RPC_STATUS RPC_ENTRY
  1502. NdrAsyncPipePull(
  1503. char * pState,
  1504. void * buf,
  1505. unsigned long esize,
  1506. unsigned long * ecount )
  1507. {
  1508. RPC_STATUS Status = RPC_S_OK;
  1509. NDR_PIPE_LOG( PIPE_LOG_API, ( "NdrAsyncPipePull: pState %p", pState ) );
  1510. NDR_PIPE_LOG( PIPE_LOG_API, ( " buf %p, esize %u", buf, esize ) );
  1511. NDR_PIPE_LOG( PIPE_LOG_API, ( " ecount %u", ecount ) );
  1512. RpcTryExcept
  1513. {
  1514. NdrPipePull( pState, buf, esize, ecount );
  1515. }
  1516. RpcExcept( ! (RPC_BAD_STUB_DATA_EXCEPTION_FILTER) )
  1517. {
  1518. Status = RpcExceptionCode();
  1519. NdrpAsyncHandlePipeError( pState, Status );
  1520. }
  1521. RpcEndExcept
  1522. return Status;
  1523. }
  1524. RPC_STATUS RPC_ENTRY
  1525. NdrAsyncPipePush(
  1526. char * pState,
  1527. void * buf,
  1528. unsigned long ecount )
  1529. {
  1530. RPC_STATUS Status = RPC_S_OK;
  1531. NDR_PIPE_LOG( PIPE_LOG_API, ( "NdrAsyncPipePush: pState %p", pState ) );
  1532. NDR_PIPE_LOG( PIPE_LOG_API, ( " buf %p, count %u", buf, ecount ) );
  1533. RpcTryExcept
  1534. {
  1535. NdrPipePush( pState, buf, ecount );
  1536. }
  1537. RpcExcept( ! (RPC_BAD_STUB_DATA_EXCEPTION_FILTER) )
  1538. {
  1539. Status = RpcExceptionCode();
  1540. NdrpAsyncHandlePipeError( pState, Status );
  1541. }
  1542. RpcEndExcept
  1543. return Status;
  1544. }
  1545. RPC_STATUS RPC_ENTRY
  1546. NdrAsyncPipeAlloc(
  1547. char * pState,
  1548. unsigned long bsize,
  1549. void **buf,
  1550. unsigned long * bcount )
  1551. /*
  1552. */
  1553. {
  1554. RPC_STATUS Status = RPC_S_OK;
  1555. NDR_PIPE_LOG( PIPE_LOG_API, ( "NdrAsyncPipeAlloc: pState %p", pState ) );
  1556. NDR_PIPE_LOG( PIPE_LOG_API, ( " bsize %u, buf %p", bsize, buf ) );
  1557. NDR_PIPE_LOG( PIPE_LOG_API, ( " bcount %p", bcount ) );
  1558. RpcTryExcept
  1559. {
  1560. NdrPipeAlloc( pState, bsize, buf, bcount );
  1561. }
  1562. RpcExcept( ! (RPC_BAD_STUB_DATA_EXCEPTION_FILTER) )
  1563. {
  1564. Status = RpcExceptionCode();
  1565. NdrpAsyncHandlePipeError( pState, Status );
  1566. }
  1567. RpcEndExcept
  1568. return Status;
  1569. }
  1570. void
  1571. NdrpPipeElementBufferSize(
  1572. NDR_PIPE_DESC * pPipeDesc,
  1573. PMIDL_STUB_MESSAGE pStubMsg,
  1574. uchar * pMemory,
  1575. ulong ElemCount
  1576. )
  1577. /*++
  1578. Routine Description :
  1579. Computes the needed buffer size for the pipe elements.
  1580. Arguments :
  1581. pStubMsg - Pointer to the stub message.
  1582. pMemory - Pointer to the data being sized.
  1583. pFormat - Pointer's format string description.
  1584. Return :
  1585. None.
  1586. --*/
  1587. {
  1588. if ( ElemCount == 0 )
  1589. return;
  1590. // We can end up here only for complex objects.
  1591. // For objects without unions, we may be forced to size because
  1592. // of different packing levels.
  1593. if ( pPipeDesc->RuntimeState.ElemWireSize )
  1594. {
  1595. // There is a fixed WireSize, so use it.
  1596. ulong WireSize = pPipeDesc->RuntimeState.ElemWireSize;
  1597. ulong WireAlign = pPipeDesc->RuntimeState.ElemAlign;
  1598. pStubMsg->BufferLength +=
  1599. (ElemCount -1) * (WireSize + WIRE_PAD( WireSize, WireAlign )) +
  1600. WireSize;
  1601. }
  1602. else
  1603. {
  1604. NDR_PIPE_MESSAGE * pPipeMsg = & pPipeDesc->pPipeMsg[ pPipeDesc->CurrentPipe ];
  1605. pPipeDesc->pPipeHelper->BufferSizeType( pPipeMsg,
  1606. pMemory,
  1607. ElemCount );
  1608. }
  1609. }
  1610. void
  1611. NdrpPipeElementConvertAndUnmarshal(
  1612. NDR_PIPE_DESC * pPipeDesc,
  1613. PMIDL_STUB_MESSAGE pStubMsg,
  1614. uchar * * ppMemory,
  1615. long ActElems,
  1616. long * pActCount
  1617. )
  1618. /*++
  1619. Routine Description :
  1620. Computes the needed buffer size for the pipe elements.
  1621. Arguments :
  1622. pStubMsg - Pointer to the stub message.
  1623. pMemory - Pointer to the data being sized.
  1624. pFormat - Pointer's format string description.
  1625. Return :
  1626. None.
  1627. --*/
  1628. {
  1629. NDR_PIPE_STATE * state = & pPipeDesc->RuntimeState;
  1630. NDR_PIPE_MESSAGE * pPipeMsg = & pPipeDesc->pPipeMsg[ pPipeDesc->CurrentPipe ];
  1631. uchar * pMemory = *ppMemory;
  1632. ulong ElemWireSize = state->ElemWireSize;
  1633. ulong ElemPad = state->ElemPad;
  1634. BOOL fBlockCopy = state->fBlockCopy;
  1635. NDR_PIPE_LOG( PIPE_LOG_NOISE, ( " NdrpPipeElementConvertAndUnmarshal: ActElems %d", ActElems ) );
  1636. NDR_PIPE_LOG( PIPE_LOG_NOISE, (" pStubMsg->Buffer %p, pMemory %p", pStubMsg->Buffer, pMemory ) );
  1637. if ( ActElems )
  1638. {
  1639. pPipeDesc->pPipeHelper->ConvertType( pPipeMsg,
  1640. ActElems );
  1641. // Unmarshal the chunk
  1642. ALIGN( pStubMsg->Buffer, state->ElemAlign );
  1643. if ( fBlockCopy )
  1644. {
  1645. ulong CopySize = ( ActElems - 1) * (ElemWireSize + ElemPad)
  1646. + ElemWireSize;
  1647. RpcpMemoryCopy( pMemory,
  1648. pStubMsg->Buffer,
  1649. CopySize );
  1650. pStubMsg->Buffer += CopySize;
  1651. }
  1652. else
  1653. {
  1654. // Only complex and enum is possible here.
  1655. pPipeDesc->pPipeHelper->UnmarshallType( pPipeMsg,
  1656. pMemory,
  1657. ActElems );
  1658. pMemory += state->ElemMemSize;
  1659. }
  1660. *ppMemory += state->ElemMemSize * ActElems;
  1661. }
  1662. *pActCount += ActElems;
  1663. }
  1664. BOOL
  1665. NdrReadPipeElements(
  1666. NDR_PIPE_DESC * pPipeDesc,
  1667. PMIDL_STUB_MESSAGE pStubMsg,
  1668. unsigned char * pTargetBuffer,
  1669. long * pElementsRead
  1670. )
  1671. /*
  1672. This procedure encapsulates reading pipe elements from the RPC runtime.
  1673. */
  1674. {
  1675. NDR_PIPE_STATE * pRuntimeState = & pPipeDesc->RuntimeState;
  1676. ulong ElemWireSize = pRuntimeState->ElemWireSize;
  1677. // Get the temporary buffers
  1678. if ( ( pRuntimeState->PartialBufferSize / ElemWireSize ) == 0 )
  1679. {
  1680. // buffer too small.
  1681. // We preallocate a buffer that is of an arbitrary big size.
  1682. // If the element is even bigger, we allocate a buffer big
  1683. // enough for one element.
  1684. if ( pRuntimeState->PartialElem )
  1685. NdrpPrivateFree( pPipeDesc->pAllocContext, pRuntimeState->PartialElem );
  1686. if ( PIPE_PARTIAL_BUFFER_SIZE < ElemWireSize )
  1687. pRuntimeState->PartialBufferSize = ElemWireSize;
  1688. else
  1689. pRuntimeState->PartialBufferSize = PIPE_PARTIAL_BUFFER_SIZE;
  1690. // We allocate more for alignment padding.
  1691. RpcTryExcept
  1692. {
  1693. pRuntimeState->PartialElem = (uchar *)
  1694. NdrpPrivateAllocate( pPipeDesc->pAllocContext,
  1695. pRuntimeState->PartialBufferSize + 8);
  1696. }
  1697. RpcExcept(1)
  1698. {
  1699. if ( ! pRuntimeState->PartialElem )
  1700. NdrpRaisePipeException( pPipeDesc, RPC_S_OUT_OF_MEMORY );
  1701. }
  1702. RpcEndExcept
  1703. }
  1704. long ElemsToRead = *pElementsRead;
  1705. long LeftToRead = *pElementsRead;
  1706. long ElemsRead = 0;
  1707. *pElementsRead = 0;
  1708. // New semantics - unmarshal only what we have at hand, don't call
  1709. // for the next buffer unless it would mean giving back 0 elems.
  1710. while ( ( LeftToRead > 0 && ! pPipeDesc->RuntimeState.EndOfPipe ) ||
  1711. pPipeDesc->RuntimeState.EndOfPipePending )
  1712. {
  1713. // See if there is a buffer to process first
  1714. if ( ! pPipeDesc->Flags.NoBufferCallPending )
  1715. {
  1716. // Read elements from the marshaling buffer (the StubMsg->Buffer)
  1717. // to the user's target buffer (converted and unmarshaled).
  1718. // ElemsRead would be cumulative across the calls when looping.
  1719. NdrpReadPipeElementsFromBuffer( pPipeDesc,
  1720. pStubMsg,
  1721. & pTargetBuffer,
  1722. LeftToRead,
  1723. & ElemsRead );
  1724. }
  1725. LeftToRead = ElemsToRead - ElemsRead;
  1726. if ( ( LeftToRead > 0 && ! pPipeDesc->RuntimeState.EndOfPipe ) ||
  1727. pPipeDesc->RuntimeState.EndOfPipePending )
  1728. {
  1729. // We ran out of data in the current buffer.
  1730. // Check if we unmarshaled some elems already - if so, don't read.
  1731. if ( ElemsRead == 0 )
  1732. {
  1733. pPipeDesc->Flags.NoBufferCallPending = 1;
  1734. NdrPartialReceive( pPipeDesc,
  1735. pStubMsg,
  1736. pRuntimeState->PartialBufferSize );
  1737. pPipeDesc->Flags.NoBufferCallPending = 0;
  1738. continue;
  1739. }
  1740. }
  1741. break;
  1742. }
  1743. *pElementsRead = ElemsRead;
  1744. return pPipeDesc->RuntimeState.EndOfPipe;
  1745. }
  1746. void NdrpReadPipeElementsFromBuffer (
  1747. NDR_PIPE_DESC * pPipeDesc,
  1748. PMIDL_STUB_MESSAGE pStubMsg,
  1749. uchar ** pTargetBuffer,
  1750. long ElemsToRead,
  1751. long * NumCopied
  1752. )
  1753. {
  1754. NDR_PIPE_STATE * state = & pPipeDesc->RuntimeState;
  1755. NDR_PIPE_MESSAGE * pPipeMsg = & pPipeDesc->pPipeMsg[ pPipeDesc->CurrentPipe ];
  1756. BOOL fHasChunkTailCounter = pPipeDesc->pPipeHelper->HasChunkTailCounter();
  1757. long len;
  1758. uchar * BufferSave;
  1759. NDR_ASSERT( state->CurrentState == START ||
  1760. state->PartialElemSize < state->ElemWireSize,
  1761. "when starting to read pipe elements" );
  1762. NDR_PIPE_LOG( PIPE_LOG_NOISE, ( "NdrpReadPipeElementsFromBuffer: ElemsToRead %x", ElemsToRead ) );
  1763. NDR_PIPE_LOG( PIPE_LOG_NOISE, ( " pStubMsg->Buffer %p", pStubMsg->Buffer ) );
  1764. if ( ( ElemsToRead == 0 ) &&
  1765. ( !state->EndOfPipePending ) )
  1766. {
  1767. return ;
  1768. }
  1769. while (1)
  1770. {
  1771. switch( state->CurrentState )
  1772. {
  1773. case START:
  1774. NDR_PIPE_LOG( PIPE_LOG_NOISE, ( " START: pStubMgs->Buffer %p", pStubMsg->Buffer ) );
  1775. ASSERT(pStubMsg->Buffer >= pStubMsg->RpcMsg->Buffer);
  1776. ASSERT(pStubMsg->Buffer - pStubMsg->RpcMsg->BufferLength <= pStubMsg->RpcMsg->Buffer);
  1777. // The state to read the chunk counter.
  1778. state->PartialElemSize = 0 ;
  1779. // Read the element count.
  1780. {
  1781. ulong ElemsInChunk;
  1782. if ( !pPipeDesc->pPipeHelper->UnmarshallChunkCounter( pPipeMsg,
  1783. &ElemsInChunk ) )
  1784. return;
  1785. state->ElemsInChunk = state->OrigElemsInChunk = ElemsInChunk;
  1786. }
  1787. NDR_PIPE_LOG( PIPE_LOG_NOISE, ("Read pipe chuck: %d", state->ElemsInChunk ) );
  1788. if (state->ElemsInChunk == 0)
  1789. {
  1790. if ( fHasChunkTailCounter )
  1791. {
  1792. state->EndOfPipePending = 1;
  1793. state->CurrentState = VERIFY_TAIL_CHUNK;
  1794. NDR_PIPE_LOG( PIPE_LOG_NOISE, ("Waiting for duplicate 0...") );
  1795. }
  1796. else
  1797. {
  1798. state->EndOfPipe = 1;
  1799. return;
  1800. }
  1801. }
  1802. else
  1803. {
  1804. if ( state->LowChunkLimit > state->ElemsInChunk ||
  1805. state->HighChunkLimit < state->ElemsInChunk )
  1806. NdrpRaisePipeException( pPipeDesc, RPC_X_INVALID_BOUND );
  1807. state->CurrentState = COPY_PIPE_ELEM;
  1808. }
  1809. break;
  1810. case COPY_PIPE_ELEM:
  1811. NDR_PIPE_LOG( PIPE_LOG_NOISE, (" COPY_PIPE_ELEM: state->ElemsInChunk %d", state->ElemsInChunk ) );
  1812. NDR_PIPE_LOG( PIPE_LOG_NOISE, (" pStubMsg->Buffer %p, ElemsToRead %d", pStubMsg->Buffer, ElemsToRead ) );
  1813. // The state with some elements in the current chunk left.
  1814. // The elements may not be in the current buffer, though.
  1815. NDR_ASSERT( state->ElemsInChunk != 0xbaadf00d, "bogus chunk count" );
  1816. NDR_ASSERT( state->ElemsInChunk, "empty chunk!" );
  1817. ALIGN( pStubMsg->Buffer, state->ElemAlign );
  1818. if ( state->ElemWireSize <= REMAINING_BYTES() )
  1819. {
  1820. // There is enough on wire to unmarshal at least one.
  1821. if ( ElemsToRead )
  1822. {
  1823. long ElemsReady, ActCount, EffectiveSize, WirePad;
  1824. WirePad = WIRE_PAD( state->ElemWireSize, state->ElemAlign );
  1825. EffectiveSize = state->ElemWireSize + WirePad;
  1826. ElemsReady = (REMAINING_BYTES() + WirePad) /
  1827. EffectiveSize;
  1828. if ( ElemsReady > state->ElemsInChunk )
  1829. ElemsReady = state->ElemsInChunk;
  1830. if ( ElemsReady > ElemsToRead )
  1831. ElemsReady = ElemsToRead;
  1832. ActCount = 0;
  1833. NdrpPipeElementConvertAndUnmarshal( pPipeDesc,
  1834. pStubMsg,
  1835. pTargetBuffer,
  1836. ElemsReady,
  1837. & ActCount );
  1838. ElemsToRead -= ActCount;
  1839. state->ElemsInChunk -= ActCount;
  1840. *NumCopied += ActCount;
  1841. if (state->ElemsInChunk == 0)
  1842. {
  1843. state->CurrentState = fHasChunkTailCounter ?
  1844. VERIFY_TAIL_CHUNK :
  1845. START;
  1846. if ( ElemsToRead == 0 )
  1847. return;
  1848. }
  1849. }
  1850. else
  1851. {
  1852. // End of target buffer: return the count.
  1853. // Keep the same state for the next round.
  1854. return;
  1855. }
  1856. }
  1857. else
  1858. {
  1859. // Not enough wire bytes to unmarshal element.
  1860. if ( REMAINING_BYTES() )
  1861. {
  1862. NDR_ASSERT( 0 < REMAINING_BYTES(),
  1863. "buffer pointer not within the buffer" );
  1864. state->CurrentState = RETURN_PARTIAL_ELEM;
  1865. }
  1866. else
  1867. {
  1868. state->PartialElemSize = 0;
  1869. return;
  1870. }
  1871. }
  1872. break;
  1873. case RETURN_PARTIAL_ELEM:
  1874. NDR_PIPE_LOG( PIPE_LOG_NOISE, (" RETURN_PARTIAL_ELEM: state->ElemsInChunk %d", state->ElemsInChunk ) );
  1875. // This happens when there is no whole element left
  1876. // during copying. The chunk has some elements.
  1877. NDR_ASSERT( state->ElemsInChunk, "empty chunk" );
  1878. len = REMAINING_BYTES();
  1879. NDR_ASSERT( 0 < len && len < state->ElemWireSize,
  1880. "element remnant expected" );
  1881. // Save the remnants of the elem in PartialElem;
  1882. // Pay attention to the alignment of the remnant, though.
  1883. state->PartialOffset = 0;
  1884. state->PartialElemSize = 0;
  1885. if ( len )
  1886. {
  1887. // we need to simulate the original alignment by
  1888. // means of an offset in the PartialElem buffer.
  1889. state->PartialOffset = 0x7 & PtrToUlong( pStubMsg->Buffer );
  1890. RpcpMemoryCopy( state->PartialElem + state->PartialOffset,
  1891. pStubMsg->Buffer,
  1892. len );
  1893. pStubMsg->Buffer += len;
  1894. state->PartialElemSize = len;
  1895. }
  1896. state->CurrentState = READ_PARTIAL_ELEM ;
  1897. return;
  1898. case READ_PARTIAL_ELEM: //also a start state
  1899. NDR_PIPE_LOG( PIPE_LOG_NOISE, (" READ_PARTIAL_ELEM: state->ElemsInChunk %d", state->ElemsInChunk ) );
  1900. NDR_ASSERT( state->PartialElemSize > 0 &&
  1901. state->PartialElemSize < state->ElemWireSize,
  1902. "element remnant expected" );
  1903. NDR_ASSERT( ElemsToRead, "no elements to read" );
  1904. len = state->ElemWireSize - state->PartialElemSize;
  1905. if ( len > REMAINING_BYTES() )
  1906. {
  1907. // Add another piece to the partial element,
  1908. // then wait for another round in the same state.
  1909. RpcpMemoryCopy( state->PartialElem + state->PartialOffset
  1910. + state->PartialElemSize,
  1911. pStubMsg->Buffer,
  1912. REMAINING_BYTES() );
  1913. pStubMsg->Buffer += REMAINING_BYTES();
  1914. state->PartialElemSize += REMAINING_BYTES();
  1915. return;
  1916. }
  1917. // Assemble a complete partial element, unmarshal it,
  1918. // then switch to the regular element copying.
  1919. RpcpMemoryCopy( state->PartialElem + state->PartialOffset
  1920. + state->PartialElemSize,
  1921. pStubMsg->Buffer,
  1922. len );
  1923. pStubMsg->Buffer += len;
  1924. state->PartialElemSize += len;
  1925. // Assemble a fake STUB_MESSAGE and RPC_MESSAGE so that
  1926. // the buffer looks likes the a regular RPC buffer.
  1927. {
  1928. // Save modified fields.
  1929. void * RpcBufferSave = pStubMsg->RpcMsg->Buffer;
  1930. unsigned int RpcBufferLength = pStubMsg->RpcMsg->BufferLength;
  1931. unsigned char * BufferSave = pStubMsg->Buffer;
  1932. unsigned char * BufferStartSave = pStubMsg->BufferStart;
  1933. unsigned char * BufferEndSave = pStubMsg->BufferEnd;
  1934. RpcTryFinally
  1935. {
  1936. pStubMsg->RpcMsg->Buffer = state->PartialElem + state->PartialOffset;
  1937. pStubMsg->RpcMsg->BufferLength = state->PartialElemSize;
  1938. pStubMsg->Buffer = (unsigned char *)pStubMsg->RpcMsg->Buffer;
  1939. pStubMsg->BufferStart = pStubMsg->Buffer;
  1940. pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->RpcMsg->BufferLength;
  1941. len = 0;
  1942. NdrpPipeElementConvertAndUnmarshal( pPipeDesc,
  1943. pStubMsg,
  1944. pTargetBuffer,
  1945. 1,
  1946. & len );
  1947. NDR_ASSERT( len == 1, "partial element count" );
  1948. ElemsToRead -= 1;
  1949. state->ElemsInChunk -= 1;
  1950. *NumCopied += 1 ;
  1951. // reset partial element state.
  1952. state->PartialOffset = 0;
  1953. state->PartialElemSize = 0;
  1954. }
  1955. RpcFinally
  1956. {
  1957. // Switch back to regular elem unmarshaling.
  1958. pStubMsg->RpcMsg->Buffer = RpcBufferSave;
  1959. pStubMsg->RpcMsg->BufferLength = RpcBufferLength;
  1960. pStubMsg->Buffer = BufferSave;
  1961. pStubMsg->BufferStart = BufferStartSave;
  1962. pStubMsg->BufferEnd = BufferEndSave;
  1963. }
  1964. RpcEndFinally
  1965. }
  1966. if ( state->ElemsInChunk == 0 )
  1967. {
  1968. state->CurrentState = fHasChunkTailCounter ?
  1969. VERIFY_TAIL_CHUNK :
  1970. START;
  1971. if ( ElemsToRead == 0 )
  1972. return;
  1973. }
  1974. else
  1975. state->CurrentState = COPY_PIPE_ELEM;
  1976. break;
  1977. case VERIFY_TAIL_CHUNK:
  1978. NDR_PIPE_LOG( PIPE_LOG_NOISE, (" VERIFY_TAIL_CHUNK: state->OrigElemsInChunk %d", state->OrigElemsInChunk ) );
  1979. NDR_PIPE_LOG( PIPE_LOG_NOISE, (" pStubMsg->Buffer %p", pStubMsg->Buffer ) );
  1980. ASSERT(pStubMsg->Buffer >= pStubMsg->RpcMsg->Buffer);
  1981. ASSERT(pStubMsg->Buffer - pStubMsg->RpcMsg->BufferLength <= pStubMsg->RpcMsg->Buffer);
  1982. // The state to verify the tail chunk counter.
  1983. state->PartialElemSize = 0 ;
  1984. if (! pPipeDesc->pPipeHelper->VerifyChunkTailCounter( pPipeMsg,
  1985. state->OrigElemsInChunk ) )
  1986. {
  1987. NDR_PIPE_LOG( PIPE_LOG_NOISE, ( "Not enough buffer for tail chunk counter..Leaving state machine."))
  1988. return;
  1989. }
  1990. // Get read for the next chunk.
  1991. state->CurrentState = START;
  1992. if ( state->EndOfPipePending )
  1993. {
  1994. state->EndOfPipePending = 0;
  1995. state->EndOfPipe = 1;
  1996. return;
  1997. }
  1998. break;
  1999. default:
  2000. NDR_ASSERT(0, "unknown state") ;
  2001. break;
  2002. }
  2003. }
  2004. }
  2005. void
  2006. NdrpRaisePipeException(
  2007. NDR_PIPE_DESC * pPipeDesc,
  2008. RPC_STATUS Exception )
  2009. {
  2010. // Remember the first exception that happened,
  2011. // ignore all the subsequent exceptions by reraising the first one.
  2012. if ( Exception != RPC_S_ASYNC_CALL_PENDING && pPipeDesc )
  2013. {
  2014. if ( pPipeDesc->PipeException == 0 )
  2015. pPipeDesc->PipeException = Exception;
  2016. RpcRaiseException( pPipeDesc->PipeException );
  2017. }
  2018. else
  2019. RpcRaiseException( Exception );
  2020. }