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.

782 lines
20 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. CoTrans.cxx
  5. Abstract:
  6. Common connection-oriented helper functions
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 11/11/1996 Async RPC
  11. --*/
  12. #include <precomp.hxx>
  13. #include <trans.hxx>
  14. #include <cotrans.hxx>
  15. RPC_STATUS
  16. RPC_ENTRY
  17. CO_Send(
  18. RPC_TRANSPORT_CONNECTION ThisConnection,
  19. UINT Length,
  20. BUFFER Buffer,
  21. PVOID SendContext
  22. )
  23. /*++
  24. Routine Description:
  25. Submits a send of the buffer on the connection. Will complete with
  26. ConnectionServerSend or ConnectionClientSend event either when
  27. the data has been sent on the network or when the send fails.
  28. Arguments:
  29. ThisConnection - The connection to send the data on.
  30. Length - The length of the data to send.
  31. Buffer - The data to send.
  32. SendContext - A buffer to use as the CO_SEND_CONTEXT for
  33. this operation.
  34. Return Value:
  35. RPC_S_OK
  36. RPC_P_SEND_FAILED - Connection aborted
  37. --*/
  38. {
  39. PCONNECTION pConnection = (PCONNECTION)ThisConnection;
  40. CO_SEND_CONTEXT *pSend = (CO_SEND_CONTEXT *)SendContext;
  41. BOOL b;
  42. DWORD ignored;
  43. RPC_STATUS status;
  44. pConnection->StartingWriteIO();
  45. if (pConnection->fAborted)
  46. {
  47. pConnection->WriteIOFinished();
  48. return(RPC_P_SEND_FAILED);
  49. }
  50. pSend->maxWriteBuffer = Length;
  51. pSend->pWriteBuffer = Buffer;
  52. pSend->Write.pAsyncObject = pConnection;
  53. pSend->Write.ol.hEvent = 0;
  54. pSend->Write.ol.Offset = 0;
  55. pSend->Write.ol.OffsetHigh = 0;
  56. pSend->Write.thread = I_RpcTransProtectThread();
  57. #ifdef _INTERNAL_RPC_BUILD_
  58. if (gpfnFilter)
  59. {
  60. (*gpfnFilter) (Buffer, Length, 0);
  61. }
  62. #endif
  63. status = pConnection->Send(
  64. pConnection->Conn.Handle,
  65. Buffer,
  66. Length,
  67. &ignored,
  68. &pSend->Write.ol
  69. );
  70. pConnection->WriteIOFinished();
  71. if ( (status != RPC_S_OK)
  72. && (status != ERROR_IO_PENDING) )
  73. {
  74. RpcpErrorAddRecord(EEInfoGCIO,
  75. status,
  76. EEInfoDLCOSend10,
  77. (ULONGLONG)pConnection,
  78. (ULONGLONG)Buffer,
  79. Length);
  80. VALIDATE(status)
  81. {
  82. ERROR_NETNAME_DELETED,
  83. ERROR_BROKEN_PIPE,
  84. ERROR_GRACEFUL_DISCONNECT,
  85. ERROR_NO_DATA,
  86. ERROR_NO_SYSTEM_RESOURCES,
  87. ERROR_WORKING_SET_QUOTA,
  88. ERROR_BAD_COMMAND,
  89. ERROR_OPERATION_ABORTED,
  90. ERROR_WORKING_SET_QUOTA,
  91. ERROR_PIPE_NOT_CONNECTED,
  92. WSAECONNABORTED,
  93. WSAECONNRESET
  94. } END_VALIDATE;
  95. I_RpcTransUnprotectThread(pSend->Write.thread);
  96. pConnection->Abort();
  97. return(RPC_P_SEND_FAILED);
  98. }
  99. return(RPC_S_OK);
  100. }
  101. RPC_STATUS
  102. RPC_ENTRY
  103. CO_SubmitRead(
  104. PCONNECTION pConnection
  105. )
  106. /*++
  107. Routine Description:
  108. Generic routine to submit an async read on an existing connection.
  109. Arguments:
  110. pConnection - The connection to submit the read on.
  111. pConnection->pReadBuffer - valid buffer to receive into or null.
  112. pConnection->maxReadBuffer - size of pReadBuffer or null.
  113. pConnection->iLastRead is an offset into pReadBuffer of
  114. data already read.
  115. Return Value:
  116. RPC_S_OK - Read pending
  117. RPC_P_RECEIVE_FAILED - Connection aborted
  118. --*/
  119. {
  120. BOOL b;
  121. DWORD ignored;
  122. RPC_STATUS status;
  123. if (pConnection->pReadBuffer == 0)
  124. {
  125. ASSERT(pConnection->iLastRead == 0);
  126. pConnection->pReadBuffer = TransConnectionAllocatePacket(pConnection,
  127. pConnection->iPostSize);
  128. if (pConnection->pReadBuffer == 0)
  129. {
  130. pConnection->Abort();
  131. return(RPC_P_RECEIVE_FAILED);
  132. }
  133. pConnection->maxReadBuffer = pConnection->iPostSize;
  134. }
  135. else
  136. {
  137. ASSERT(pConnection->iLastRead < pConnection->maxReadBuffer);
  138. }
  139. pConnection->StartingReadIO();
  140. if (pConnection->fAborted)
  141. {
  142. pConnection->ReadIOFinished();
  143. return(RPC_P_RECEIVE_FAILED);
  144. }
  145. pConnection->Read.thread = I_RpcTransProtectThread();
  146. pConnection->Read.ol.hEvent = 0;
  147. ASSERT(pConnection->Read.ol.Internal != STATUS_PENDING);
  148. status = pConnection->Receive(
  149. pConnection->Conn.Handle,
  150. pConnection->pReadBuffer + pConnection->iLastRead,
  151. pConnection->maxReadBuffer - pConnection->iLastRead,
  152. &ignored,
  153. &pConnection->Read.ol
  154. );
  155. pConnection->ReadIOFinished();
  156. if ( (status != RPC_S_OK)
  157. && (status != ERROR_IO_PENDING)
  158. && (status != ERROR_MORE_DATA) )
  159. {
  160. if ( status != ERROR_NETNAME_DELETED
  161. && status != ERROR_BROKEN_PIPE
  162. && status != ERROR_GRACEFUL_DISCONNECT)
  163. {
  164. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  165. DPFLTR_WARNING_LEVEL,
  166. RPCTRANS "UTIL_ReadFile failed %d on %p\n",
  167. status,
  168. pConnection));
  169. }
  170. RpcpErrorAddRecord(EEInfoGCIO,
  171. status,
  172. EEInfoDLCOSubmitRead10);
  173. // the IO system does not necessarily reset the Internal on sync failure.
  174. // Reset it because in HTTP when we encounted a sync failure on RTS receive
  175. // we may submit a second receive after a failed receive and this will
  176. // trigger the ASSERT above
  177. pConnection->Read.ol.Internal = status;
  178. I_RpcTransUnprotectThread(pConnection->Read.thread);
  179. pConnection->Abort();
  180. return(RPC_P_RECEIVE_FAILED);
  181. }
  182. // Even if the read completed here, it will also be posted to the
  183. // completion port. This means we don't need to handle the read here.
  184. return(RPC_S_OK);
  185. }
  186. RPC_STATUS
  187. RPC_ENTRY
  188. CO_Recv(
  189. RPC_TRANSPORT_CONNECTION ThisConnection
  190. )
  191. /*++
  192. Routine Description:
  193. Called be the runtime on a connection without a currently
  194. pending recv.
  195. Arguments:
  196. ThisConnection - A connection without a read pending on it.
  197. Return Value:
  198. RPC_S_OK
  199. RPC_P_RECEIVE_FAILED
  200. --*/
  201. {
  202. PCONNECTION p = (PCONNECTION)ThisConnection;
  203. if ( p->iLastRead
  204. && p->iLastRead == p->maxReadBuffer)
  205. {
  206. ASSERT(p->pReadBuffer);
  207. // This means we received a coalesced read of a complete
  208. // message. (Or that we received a coalesced read < header size)
  209. // We should complete that as it's own IO. This is very
  210. // rare.
  211. TransDbgDetail((DPFLTR_RPCPROXY_ID,
  212. DPFLTR_INFO_LEVEL,
  213. RPCTRANS "Posted coalesced data in %p of %d byte\n",
  214. p,
  215. p->iLastRead));
  216. UINT bytes;
  217. bytes = p->iLastRead;
  218. p->iLastRead = 0;
  219. p->Read.thread = I_RpcTransProtectThread();
  220. // This means we want to process this as a new receive
  221. BOOL b = PostQueuedCompletionStatus(RpcCompletionPort,
  222. bytes,
  223. TRANSPORT_POSTED_KEY,
  224. &p->Read.ol);
  225. ASSERT(b); // See complete.cxx - we can handle it here if needed.
  226. return(RPC_S_OK);
  227. }
  228. ASSERT(p->iLastRead == 0 || (p->iLastRead < p->maxReadBuffer));
  229. return(CO_SubmitRead(p));
  230. }
  231. RPC_STATUS BASE_CONNECTION::ProcessRead(IN DWORD bytes, OUT BUFFER *pBuffer,
  232. OUT PUINT pBufferLength)
  233. /*++
  234. Routine Description:
  235. Receives a message from a message or byte mode protocol.
  236. Arguments:
  237. bytes - The number of read (not including those in iLastRead).
  238. pBuffer - When returning RPC_S_OK will contain the message.
  239. pBufferLength - When return RPC_S_OK will contain the message length.
  240. Return Value:
  241. RPC_S_OK - A complete message has been returned.
  242. RPC_P_RECEIVE_FAILED - something failed.
  243. RPC_P_PARTIAL_RECEIVE - Partial message recv'd, need to submit another recv.
  244. --*/
  245. {
  246. DWORD message_size;
  247. RPC_STATUS status;
  248. bytes += iLastRead;
  249. if (bytes < sizeof(CONN_RPC_HEADER))
  250. {
  251. // Not a whole header, resubmit the read and continue.
  252. iLastRead = bytes;
  253. return(RPC_P_PARTIAL_RECEIVE);
  254. }
  255. message_size = MessageLength((PCONN_RPC_HEADER)pReadBuffer);
  256. if (message_size < sizeof(CONN_RPC_HEADER))
  257. {
  258. ASSERT(message_size >= sizeof(CONN_RPC_HEADER));
  259. Abort();
  260. return(RPC_P_RECEIVE_FAILED);
  261. }
  262. if (bytes == message_size)
  263. {
  264. // All set, have a complete request.
  265. *pBuffer = pReadBuffer;
  266. *pBufferLength = message_size;
  267. iLastRead = 0;
  268. pReadBuffer = 0;
  269. return(RPC_S_OK);
  270. }
  271. else if (message_size > bytes)
  272. {
  273. // Don't have a complete message, realloc if needed and
  274. // resubmit a read for the remaining bytes.
  275. if (maxReadBuffer < message_size)
  276. {
  277. // Buffer too small for the message.
  278. status = TransConnectionReallocPacket(this,
  279. &pReadBuffer,
  280. bytes,
  281. message_size);
  282. if (status != RPC_S_OK)
  283. {
  284. ASSERT(status == RPC_S_OUT_OF_MEMORY);
  285. Abort();
  286. return(RPC_P_RECEIVE_FAILED);
  287. }
  288. // increase the post size, but not if we are in paged
  289. // buffer mode.
  290. if (!fPagedBCacheMode)
  291. iPostSize = message_size;
  292. }
  293. // Setup to receive exactly the remaining bytes of the message.
  294. iLastRead = bytes;
  295. maxReadBuffer = message_size;
  296. return(RPC_P_PARTIAL_RECEIVE);
  297. }
  298. // Coalesced read, save extra data. Very uncommon, impossible for
  299. // message mode protocols.
  300. ASSERT(bytes > message_size);
  301. #ifdef SPX_ON
  302. ASSERT((id == TCP) || (id == SPX) || (id == HTTP) || (id == TCP_IPv6) || (id == HTTPv2));
  303. #else
  304. ASSERT((id == TCP) || (id == HTTP) || (id == TCP_IPv6) || (id == HTTPv2));
  305. #endif
  306. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  307. DPFLTR_WARNING_LEVEL,
  308. RPCTRANS "Coalesced read of %d bytes, connection %p\n",
  309. bytes - message_size,
  310. this));
  311. // The first message and size will be returned
  312. *pBuffer = pReadBuffer;
  313. *pBufferLength = message_size;
  314. UINT extra = bytes - message_size;
  315. UINT alloc_size;
  316. // Try to find a good size of the extra PDU(s)
  317. if (extra < sizeof(CONN_RPC_HEADER))
  318. {
  319. // Not a whole header, we'll assume iPostSize;
  320. alloc_size = iPostSize;
  321. }
  322. else
  323. {
  324. #ifdef _M_IA64
  325. // The first packet may not contain a number of bytes
  326. // that align the second on an 8-byte boundary. Hence, the
  327. // structure may end up unaligned.
  328. alloc_size = MessageLengthUnaligned((PCONN_RPC_HEADER)(pReadBuffer
  329. + message_size));
  330. #else
  331. alloc_size = MessageLength((PCONN_RPC_HEADER)(pReadBuffer
  332. + message_size));
  333. #endif
  334. }
  335. if (alloc_size < extra)
  336. {
  337. // This can happen if there are more than two PDUs coalesced together
  338. // in the buffer. Or if the PDU is invalid. Or if the iPostSize is
  339. // smaller than the next PDU.
  340. alloc_size = extra;
  341. }
  342. // Allocate a new buffer to save the extra data for the next read.
  343. PBYTE pNewBuffer;
  344. pNewBuffer = TransConnectionAllocatePacket(this,
  345. alloc_size);
  346. if (0 == pNewBuffer)
  347. {
  348. // We have a complete request. We could process the request and
  349. // close the connection only after trying to send the reply.
  350. *pBuffer = 0;
  351. *pBufferLength = 0;
  352. Abort();
  353. return(RPC_P_RECEIVE_FAILED);
  354. }
  355. ASSERT(*pBuffer);
  356. // Save away extra data for the next receive
  357. RpcpMemoryCopy(pNewBuffer,
  358. pReadBuffer + *pBufferLength,
  359. extra);
  360. pReadBuffer = pNewBuffer;
  361. iLastRead = extra;
  362. maxReadBuffer = alloc_size;
  363. ASSERT(iLastRead <= maxReadBuffer);
  364. ASSERT(pReadBuffer != *pBuffer);
  365. return(RPC_S_OK);
  366. }
  367. RPC_STATUS
  368. CO_SubmitSyncRead(
  369. IN PCONNECTION pConnection,
  370. OUT BUFFER *pBuffer,
  371. OUT PUINT pMessageLength
  372. )
  373. /*++
  374. Routine Description:
  375. Called in the synchronous receive path when more data is needed
  376. in to complete the message. This function is non-blocking but
  377. it will try to read as much data as it can and may return a
  378. completed PDU.
  379. Arguments:
  380. pConnection - The connection to receive from.
  381. ->pReadBuffer
  382. ->maxReadBuffer
  383. ->iLastRead
  384. Return Value:
  385. RPC_S_OK - Ok and a complete PDU has arrived
  386. RPC_P_IO_PENDING - A receive is now outstanding on the connection.
  387. Wait for it to complete..
  388. RPC_P_RECEIVE_FAILED - Failure
  389. RPC_P_CONNECTION_SHUTDOWN - Failure - graceful close received.
  390. --*/
  391. {
  392. RPC_STATUS status;
  393. ASSERT(pConnection->pReadBuffer);
  394. if (pConnection->maxReadBuffer == pConnection->iLastRead)
  395. {
  396. // Coalesced receive and we've got one (or more) PDUs
  397. status = pConnection->ProcessRead(0, pBuffer, pMessageLength);
  398. ASSERT(status != RPC_P_PARTIAL_RECEIVE);
  399. return(status);
  400. }
  401. DWORD bytes;
  402. DWORD readbytes;
  403. ASSERT_READ_EVENT_IS_THERE(pConnection);
  404. do
  405. {
  406. BOOL b;
  407. readbytes = pConnection->maxReadBuffer - pConnection->iLastRead;
  408. pConnection->StartingReadIO();
  409. if (pConnection->fAborted)
  410. {
  411. pConnection->ReadIOFinished();
  412. return(RPC_P_RECEIVE_FAILED);
  413. }
  414. status = pConnection->Receive(pConnection->Conn.Handle,
  415. pConnection->pReadBuffer + pConnection->iLastRead,
  416. readbytes,
  417. &bytes,
  418. &pConnection->Read.ol);
  419. pConnection->ReadIOFinished();
  420. if ((status == ERROR_IO_PENDING) || (status == ERROR_IO_INCOMPLETE))
  421. {
  422. // The most common path
  423. return(RPC_P_IO_PENDING);
  424. }
  425. if (status != RPC_S_OK)
  426. {
  427. switch (status)
  428. {
  429. case ERROR_MORE_DATA:
  430. // Treat as success
  431. // Note: ReadFile doesn't return the number of bytes read in this
  432. // case even though the data is available...
  433. // It should still be right, but this double checks it.
  434. ASSERT(pConnection->Read.ol.InternalHigh == readbytes);
  435. ASSERT(MessageLength((PCONN_RPC_HEADER)pConnection->pReadBuffer) >
  436. pConnection->maxReadBuffer);
  437. bytes = readbytes;
  438. status = RPC_S_OK;
  439. break;
  440. case ERROR_GRACEFUL_DISCONNECT:
  441. RpcpErrorAddRecord(EEInfoGCIO,
  442. status,
  443. EEInfoDLCOSubmitSyncRead10);
  444. status = RPC_P_CONNECTION_SHUTDOWN;
  445. break;
  446. default:
  447. RpcpErrorAddRecord(EEInfoGCIO,
  448. status,
  449. EEInfoDLCOSubmitSyncRead20);
  450. VALIDATE(status)
  451. {
  452. ERROR_NETNAME_DELETED,
  453. ERROR_BROKEN_PIPE,
  454. ERROR_PIPE_NOT_CONNECTED,
  455. ERROR_NO_SYSTEM_RESOURCES,
  456. ERROR_COMMITMENT_LIMIT,
  457. WSAECONNRESET,
  458. WSAESHUTDOWN,
  459. WSAECONNABORTED,
  460. ERROR_UNEXP_NET_ERR,
  461. ERROR_WORKING_SET_QUOTA
  462. } END_VALIDATE;
  463. status = RPC_P_RECEIVE_FAILED;
  464. break;
  465. }
  466. }
  467. if (bytes == 0)
  468. {
  469. status = RPC_P_CONNECTION_SHUTDOWN;
  470. }
  471. if (status != RPC_S_OK)
  472. {
  473. pConnection->Abort();
  474. return(status);
  475. }
  476. // Read completed, process the data now..
  477. status = pConnection->ProcessRead(bytes, pBuffer, pMessageLength);
  478. }
  479. while (status == RPC_P_PARTIAL_RECEIVE );
  480. return(status);
  481. }
  482. RPC_STATUS
  483. RPC_ENTRY
  484. CO_SyncRecv(
  485. IN RPC_TRANSPORT_CONNECTION ThisConnection,
  486. OUT BUFFER *pBuffer,
  487. OUT PUINT pBufferLength,
  488. IN DWORD dwTimeout
  489. )
  490. /*++
  491. Routine Description:
  492. Receive the next PDU to arrive at the connection.
  493. Arguments:
  494. ThisConnection - The connection to read from.
  495. pBuffer - If successful, points to a buffer containing the next PDU.
  496. pBufferLength - If successful, contains the length of the message.
  497. Return Value:
  498. RPC_S_OK
  499. RPC_P_RECEIVE_FAILED - Connection aborted.
  500. RPC_S_CALL_CANCELLED - Connection aborted.
  501. --*/
  502. {
  503. PCONNECTION p = (PCONNECTION)ThisConnection;
  504. DWORD bytes;
  505. RPC_STATUS status;
  506. HANDLE hEvent;
  507. ASSERT((p->type & TYPE_MASK) == CLIENT);
  508. ASSERT(p->pReadBuffer == 0);
  509. p->pReadBuffer = TransConnectionAllocatePacket(p, p->iPostSize);
  510. hEvent = I_RpcTransGetThreadEvent();
  511. if (p->pReadBuffer == 0)
  512. {
  513. p->Abort();
  514. return(RPC_P_RECEIVE_FAILED);
  515. }
  516. p->maxReadBuffer = p->iPostSize;
  517. p->iLastRead = 0;
  518. p->Read.ol.hEvent = (HANDLE)((ULONG_PTR)hEvent | 0x01);
  519. do
  520. {
  521. status = CO_SubmitSyncRead(p, pBuffer, pBufferLength);
  522. if (status != RPC_P_IO_PENDING)
  523. {
  524. ASSERT(status != RPC_S_CALL_CANCELLED);
  525. break;
  526. }
  527. status = UTIL_GetOverlappedResultEx(ThisConnection,
  528. &p->Read.ol,
  529. &bytes,
  530. TRUE, // Alertable
  531. dwTimeout);
  532. if (status != RPC_S_OK)
  533. {
  534. if (status != ERROR_MORE_DATA)
  535. {
  536. RpcpErrorAddRecord(EEInfoGCIO,
  537. status,
  538. EEInfoDLCOSyncRecv10);
  539. if ((status != RPC_S_CALL_CANCELLED) && (status != RPC_P_TIMEOUT))
  540. {
  541. status = RPC_P_RECEIVE_FAILED;
  542. }
  543. break;
  544. }
  545. // ERROR_MORE_DATA is success
  546. }
  547. status = p->ProcessRead(bytes, pBuffer, pBufferLength);
  548. }
  549. while (status == RPC_P_PARTIAL_RECEIVE);
  550. if (status == RPC_S_OK)
  551. {
  552. ASSERT(p->pReadBuffer == 0);
  553. return(RPC_S_OK);
  554. }
  555. p->Abort();
  556. if ((status == RPC_S_CALL_CANCELLED) || (status == RPC_P_TIMEOUT))
  557. {
  558. // Wait for the read to complete. Since the connection has
  559. // just been closed this won't take very long.
  560. UTIL_WaitForSyncIO(&p->Read.ol,
  561. FALSE,
  562. INFINITE);
  563. }
  564. return(status);
  565. }
  566. void
  567. BASE_CONNECTION::Initialize (
  568. void
  569. )
  570. /*++
  571. Routine Description:
  572. Initializes a base connection. Prior initialization
  573. ensures orderly cleanup.
  574. Arguments:
  575. Return Value:
  576. --*/
  577. {
  578. type = CLIENT | CONNECTION;
  579. pReadBuffer = 0;
  580. Conn.Handle = 0;
  581. fAborted = FALSE;
  582. pReadBuffer = 0;
  583. maxReadBuffer = 0;
  584. iPostSize = gPostSize;
  585. iLastRead = 0;
  586. RpcpMemorySet(&Read.ol, 0, sizeof(Read.ol));
  587. Read.pAsyncObject = this;
  588. Read.thread = 0;
  589. InitIoCounter();
  590. }