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

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