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.

438 lines
10 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. atqxmit.cxx
  5. Abstract:
  6. Contains internal support routines for transmit file
  7. Author:
  8. Johnson Apacible (johnsona) 26-Mar-1996
  9. --*/
  10. #include "isatq.hxx"
  11. //
  12. // Size of buffers for fake xmits
  13. //
  14. DWORD g_cbXmitBufferSize = ATQ_REG_DEF_NONTF_BUFFER_SIZE;
  15. VOID
  16. I_CleanupFakeTransmitFile(
  17. IN PATQ_CONT pContext
  18. )
  19. {
  20. //
  21. // Put the old completion routine back and free allocated buffers
  22. //
  23. pContext->pfnCompletion = pContext->arInfo.uop.opFakeXmit.pfnCompletion;
  24. pContext->ClientContext = pContext->arInfo.uop.opFakeXmit.ClientContext;
  25. if ( pContext->arInfo.uop.opFakeXmit.pBuffer != NULL ) {
  26. LocalFree(pContext->arInfo.uop.opFakeXmit.pBuffer);
  27. pContext->arInfo.uop.opFakeXmit.pBuffer = NULL;
  28. }
  29. //
  30. // Clean up the event
  31. //
  32. if ( pContext->arInfo.uop.opFakeXmit.hOvEvent != NULL ) {
  33. CloseHandle( pContext->arInfo.uop.opFakeXmit.hOvEvent );
  34. pContext->arInfo.uop.opFakeXmit.hOvEvent = NULL;
  35. }
  36. return;
  37. } // I_CleanupFakeTransmitFile
  38. VOID
  39. I_FakeTransmitFileCompletion(
  40. IN PVOID ClientContext,
  41. IN DWORD BytesWritten,
  42. IN DWORD CompletionStatus,
  43. IN OVERLAPPED * lpo
  44. )
  45. {
  46. PATQ_CONT pContext;
  47. DWORD nWrite = 0;
  48. DWORD nRead;
  49. PCHAR buffer;
  50. INT err;
  51. PVOID tail;
  52. OVERLAPPED ov;
  53. OVERLAPPED *pov = &ov;
  54. pContext = (PATQ_CONT)ClientContext;
  55. pContext->arInfo.uop.opFakeXmit.BytesWritten += BytesWritten;
  56. if ( CompletionStatus != NO_ERROR ) {
  57. //
  58. // An error occured, call the completion routine
  59. //
  60. goto call_completion;
  61. }
  62. //
  63. // We already have a buffer of size g_cbXmitBufferSize
  64. //
  65. nRead = pContext->arInfo.uop.opFakeXmit.BytesLeft;
  66. buffer = pContext->arInfo.uop.opFakeXmit.pBuffer;
  67. ATQ_ASSERT(buffer != NULL);
  68. if ( nRead > 0 ) {
  69. //
  70. // Do the read at the specified offset
  71. //
  72. pov->OffsetHigh = 0;
  73. pov->Offset = pContext->arInfo.uop.opFakeXmit.FileOffset;
  74. pov->hEvent = pContext->arInfo.uop.opFakeXmit.hOvEvent;
  75. ATQ_ASSERT(pov->hEvent != NULL);
  76. ResetEvent(pov->hEvent);
  77. if (!ReadFile(
  78. pContext->arInfo.uop.opFakeXmit.hFile,
  79. buffer,
  80. g_cbXmitBufferSize,
  81. &nRead,
  82. pov
  83. ) ) {
  84. err = GetLastError();
  85. if ( (err != ERROR_IO_PENDING) ||
  86. !GetOverlappedResult(
  87. pContext->arInfo.uop.opFakeXmit.hFile,
  88. pov,
  89. &nRead,
  90. TRUE )) {
  91. CompletionStatus = GetLastError();
  92. ATQ_PRINTF(( DBG_CONTEXT,"ReadFile error %d\n",CompletionStatus));
  93. goto call_completion;
  94. }
  95. }
  96. //
  97. // if nRead is zero, we reached the EOF.
  98. //
  99. if ( nRead > 0 ) {
  100. //
  101. // Update for next read
  102. //
  103. pContext->arInfo.uop.opFakeXmit.BytesLeft -= nRead;
  104. pContext->arInfo.uop.opFakeXmit.FileOffset += nRead;
  105. //
  106. // Do the write
  107. //
  108. I_SetNextTimeout(pContext);
  109. pContext->BytesSent = nRead;
  110. //
  111. // Write to the socket
  112. //
  113. if ( !WriteFile(
  114. pContext->hAsyncIO,
  115. buffer,
  116. nRead,
  117. &nWrite,
  118. &pContext->Overlapped
  119. ) &&
  120. (GetLastError() != ERROR_IO_PENDING) ) {
  121. CompletionStatus = GetLastError();
  122. ATQ_PRINTF(( DBG_CONTEXT,
  123. "WriteFile error %d\n",CompletionStatus));
  124. goto call_completion;
  125. }
  126. return;
  127. }
  128. }
  129. //
  130. // Time for the tail. If one exist, send it synchronously and then
  131. // call the completion routine
  132. //
  133. tail = pContext->arInfo.uop.opFakeXmit.Tail;
  134. if ( tail != NULL ) {
  135. DWORD tailLength = pContext->arInfo.uop.opFakeXmit.TailLength;
  136. ATQ_ASSERT(tailLength > 0);
  137. //
  138. // Send it synchronously
  139. //
  140. err = send(
  141. HANDLE_TO_SOCKET(pContext->hAsyncIO),
  142. (PCHAR)tail,
  143. tailLength,
  144. 0
  145. );
  146. if ( err == SOCKET_ERROR ) {
  147. CompletionStatus = GetLastError();
  148. } else {
  149. pContext->arInfo.uop.opFakeXmit.BytesWritten += err;
  150. }
  151. }
  152. call_completion:
  153. //
  154. // cleanup and call real completion routine
  155. //
  156. I_CleanupFakeTransmitFile( pContext );
  157. if ( pContext->pfnCompletion != NULL ) {
  158. pContext->pfnCompletion(
  159. pContext->ClientContext,
  160. pContext->arInfo.uop.opFakeXmit.BytesWritten,
  161. CompletionStatus,
  162. lpo
  163. );
  164. }
  165. return;
  166. } // I_FakeTransmitFileCompletion
  167. BOOL
  168. I_DoFakeTransmitFile(
  169. IN PATQ_CONT pContext,
  170. IN HANDLE hFile,
  171. IN DWORD dwBytesInFile,
  172. IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers
  173. )
  174. /*++
  175. Routine Description:
  176. Posts a completion status on the completion port queue
  177. An IO pending error code is treated as a success error code
  178. Arguments:
  179. patqContext - pointer to ATQ context
  180. hFile - Handle to the file to be read.
  181. dwBytesInFile - Number of bytes to read in the file
  182. lpTransmitBuffers - the transmitfile structure
  183. Return Value:
  184. TRUE if successful, FALSE on error (call GetLastError)
  185. --*/
  186. {
  187. PCHAR buffer = NULL;
  188. DWORD nWrite;
  189. DWORD nRead = 0;
  190. OVERLAPPED ov;
  191. INT err;
  192. DWORD cBuffer = 0;
  193. OVERLAPPED *pov = &ov;
  194. HANDLE hOvEvent = NULL;
  195. INC_ATQ_COUNTER( g_cTotalAllowedRequests);
  196. //
  197. // See if we need to send a header
  198. //
  199. pContext->arInfo.uop.opFakeXmit.BytesWritten = 0;
  200. if ( lpTransmitBuffers != NULL ) {
  201. //
  202. // Store the tail
  203. //
  204. pContext->arInfo.uop.opFakeXmit.Tail = lpTransmitBuffers->Tail;
  205. pContext->arInfo.uop.opFakeXmit.TailLength = lpTransmitBuffers->TailLength;
  206. if (lpTransmitBuffers->HeadLength > 0) {
  207. ATQ_ASSERT(lpTransmitBuffers->Head != NULL);
  208. //
  209. // Send it synchronously
  210. //
  211. err = send(
  212. HANDLE_TO_SOCKET(pContext->hAsyncIO),
  213. (PCHAR)lpTransmitBuffers->Head,
  214. lpTransmitBuffers->HeadLength,
  215. 0
  216. );
  217. if ( err == SOCKET_ERROR ) {
  218. ATQ_PRINTF(( DBG_CONTEXT, "Error %d in send.\n",err));
  219. return(FALSE);
  220. }
  221. pContext->arInfo.uop.opFakeXmit.BytesWritten += err;
  222. }
  223. }
  224. //
  225. // Check the number of bytes to send
  226. //
  227. if ( dwBytesInFile == 0 ) {
  228. //
  229. // Send the whole file.
  230. //
  231. dwBytesInFile = GetFileSize( hFile, NULL );
  232. ATQ_ASSERT(dwBytesInFile >= pContext->Overlapped.Offset);
  233. dwBytesInFile -= pContext->Overlapped.Offset;
  234. }
  235. //
  236. // Allocate the io buffer
  237. //
  238. cBuffer = min( dwBytesInFile, g_cbXmitBufferSize );
  239. if ( cBuffer > 0 ) {
  240. //
  241. // Read the first chunk of the body
  242. //
  243. buffer = (PCHAR)LocalAlloc( 0, cBuffer );
  244. if ( buffer == NULL ) {
  245. ATQ_PRINTF(( DBG_CONTEXT,
  246. "Cannot allocate %d bytes for xmitfile\n",cBuffer));
  247. return(FALSE);
  248. }
  249. //
  250. // Do the read at the specified offset
  251. //
  252. hOvEvent = pov->hEvent = IIS_CREATE_EVENT(
  253. "OVERLAPPED::hEvent",
  254. pov,
  255. TRUE,
  256. FALSE
  257. );
  258. if ( hOvEvent == NULL ) {
  259. ATQ_PRINTF(( DBG_CONTEXT,
  260. "Create event failed with %d\n",GetLastError()));
  261. LocalFree( buffer );
  262. return(FALSE);
  263. }
  264. pov->OffsetHigh = 0;
  265. pov->Offset = pContext->Overlapped.Offset;
  266. if (!ReadFile(
  267. hFile,
  268. buffer,
  269. cBuffer,
  270. &nRead,
  271. pov
  272. ) ) {
  273. err = GetLastError();
  274. if ( (err != ERROR_IO_PENDING) ||
  275. !GetOverlappedResult( hFile, pov, &nRead, TRUE )) {
  276. err = GetLastError();
  277. CloseHandle( hOvEvent );
  278. LocalFree( buffer );
  279. SetLastError(err);
  280. ATQ_PRINTF(( DBG_CONTEXT,
  281. "Error %d in readfile\n",err));
  282. return(FALSE);
  283. }
  284. }
  285. }
  286. //
  287. // are we done reading the body?
  288. //
  289. if ( nRead < g_cbXmitBufferSize ) {
  290. //
  291. // Done.
  292. //
  293. pContext->arInfo.uop.opFakeXmit.BytesLeft = 0;
  294. } else {
  295. pContext->arInfo.uop.opFakeXmit.BytesLeft = dwBytesInFile - nRead;
  296. pContext->arInfo.uop.opFakeXmit.FileOffset =
  297. pContext->Overlapped.Offset + nRead;
  298. }
  299. //
  300. // store data for restarting the operation.
  301. //
  302. pContext->arInfo.uop.opFakeXmit.pBuffer = buffer;
  303. pContext->arInfo.uop.opFakeXmit.hOvEvent = hOvEvent;
  304. pContext->arInfo.uop.opFakeXmit.hFile = hFile;
  305. //
  306. // replace the completion function with our own
  307. //
  308. pContext->arInfo.uop.opFakeXmit.pfnCompletion = pContext->pfnCompletion;
  309. pContext->arInfo.uop.opFakeXmit.ClientContext = pContext->ClientContext;
  310. pContext->pfnCompletion = I_FakeTransmitFileCompletion;
  311. pContext->ClientContext = pContext;
  312. //
  313. // Set the timeout
  314. //
  315. I_SetNextTimeout(pContext);
  316. pContext->BytesSent = nRead;
  317. //
  318. // Write to the socket
  319. //
  320. if ( !WriteFile(
  321. pContext->hAsyncIO,
  322. buffer,
  323. nRead,
  324. &nWrite,
  325. &pContext->Overlapped
  326. ) &&
  327. (GetLastError() != ERROR_IO_PENDING)) {
  328. err = GetLastError();
  329. I_CleanupFakeTransmitFile( pContext );
  330. SetLastError(err);
  331. return(FALSE);
  332. }
  333. SetLastError(NO_ERROR);
  334. return(TRUE);
  335. } // I_DoFakeTransmitFile