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.

501 lines
13 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. #include "atqcport.hxx"
  12. //
  13. // local
  14. //
  15. VOID
  16. I_FakeTransmitFileCompletion(
  17. IN PVOID ClientContext,
  18. IN DWORD BytesWritten,
  19. IN DWORD CompletionStatus,
  20. IN OVERLAPPED * lpo
  21. );
  22. VOID
  23. I_CleanupFakeTransmitFile(
  24. IN PATQ_CONT pAtqContext
  25. )
  26. {
  27. //
  28. // Put the old completion routine back and free allocated buffers
  29. //
  30. pAtqContext->arInfo.uop.opFakeXmit.CurrentState = ATQ_XMIT_NONE;
  31. pAtqContext->pfnCompletion = pAtqContext->arInfo.uop.opFakeXmit.pfnCompletion;
  32. pAtqContext->ClientContext = pAtqContext->arInfo.uop.opFakeXmit.ClientContext;
  33. if ( pAtqContext->arInfo.uop.opFakeXmit.pBuffer != NULL ) {
  34. LocalFree(pAtqContext->arInfo.uop.opFakeXmit.pBuffer);
  35. pAtqContext->arInfo.uop.opFakeXmit.pBuffer = NULL;
  36. }
  37. return;
  38. } // I_CleanupFakeTransmitFile
  39. BOOL
  40. SIOTransmitFile(
  41. IN PATQ_CONT pAtqContext,
  42. IN HANDLE hFile,
  43. IN DWORD dwBytesInFile,
  44. IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers
  45. )
  46. /*++
  47. Routine Description:
  48. Posts a completion status on the completion port queue
  49. An IO pending error code is treated as a success error code
  50. Arguments:
  51. patqContext - pointer to ATQ context
  52. hFile - Handle to the file to be read.
  53. dwBytesInFile - Number of bytes to read in the file
  54. lpTransmitBuffers - the transmitfile structure
  55. Return Value:
  56. TRUE if successful, FALSE on error (call GetLastError)
  57. --*/
  58. {
  59. DWORD nRead = 0;
  60. DWORD cBuffer = 0;
  61. ATQ_ASSERT( pAtqContext->m_pBandwidthInfo != NULL );
  62. pAtqContext->m_pBandwidthInfo->IncTotalAllowedRequests();
  63. //
  64. // Store data
  65. //
  66. pAtqContext->pvBuff = NULL;
  67. pAtqContext->arInfo.atqOp = AtqIoXmitFile;
  68. pAtqContext->arInfo.lpOverlapped = &pAtqContext->Overlapped;
  69. pAtqContext->arInfo.uop.opFakeXmit.hFile = hFile;
  70. if( lpTransmitBuffers != NULL ) {
  71. CopyMemory(
  72. &pAtqContext->arInfo.uop.opFakeXmit.TransmitBuffers,
  73. lpTransmitBuffers,
  74. sizeof(TRANSMIT_FILE_BUFFERS)
  75. );
  76. } else {
  77. ZeroMemory(
  78. &pAtqContext->arInfo.uop.opFakeXmit.TransmitBuffers,
  79. sizeof(pAtqContext->arInfo.uop.opFakeXmit.TransmitBuffers)
  80. );
  81. }
  82. pAtqContext->arInfo.uop.opFakeXmit.CurrentState = ATQ_XMIT_START;
  83. //
  84. // Set current file offset to requested
  85. //
  86. pAtqContext->arInfo.uop.opFakeXmit.FileOffset =
  87. pAtqContext->Overlapped.Offset;
  88. pAtqContext->arInfo.dwLastIOError = NOERROR;
  89. pAtqContext->arInfo.uop.opFakeXmit.pBuffer = NULL;
  90. pAtqContext->arInfo.uop.opFakeXmit.hFile = hFile;
  91. pAtqContext->arInfo.uop.opFakeXmit.BytesWritten = 0;
  92. pAtqContext->arInfo.uop.opFakeXmit.pBuffer = NULL;
  93. pAtqContext->arInfo.uop.opFakeXmit.pvLastSent = NULL;
  94. //
  95. // Check the number of bytes from file to send
  96. //
  97. if ( dwBytesInFile == 0 ) {
  98. //
  99. // Send the whole file.
  100. //
  101. dwBytesInFile = GetFileSize( hFile, NULL );
  102. if (dwBytesInFile >= pAtqContext->Overlapped.Offset) {
  103. dwBytesInFile -= pAtqContext->Overlapped.Offset;
  104. } else {
  105. ATQ_ASSERT(NULL);
  106. dwBytesInFile = 0;
  107. }
  108. }
  109. pAtqContext->arInfo.uop.opFakeXmit.BytesLeft = dwBytesInFile;
  110. //
  111. // replace the completion function with our own
  112. //
  113. pAtqContext->arInfo.uop.opFakeXmit.pfnCompletion =
  114. pAtqContext->pfnCompletion;
  115. pAtqContext->arInfo.uop.opFakeXmit.ClientContext =
  116. pAtqContext->ClientContext ;
  117. pAtqContext->ClientContext = pAtqContext;
  118. pAtqContext->pfnCompletion = I_FakeTransmitFileCompletion;
  119. //
  120. // Set the timeout
  121. //
  122. I_SetNextTimeout(pAtqContext);
  123. //
  124. // Kick in transmission loop
  125. //
  126. I_FakeTransmitFileCompletion(pAtqContext,
  127. 0,
  128. NO_ERROR,
  129. &pAtqContext->Overlapped
  130. );
  131. SetLastError(NO_ERROR);
  132. return(TRUE);
  133. } // SIOTransmitFile
  134. VOID
  135. I_FakeTransmitFileCompletion(
  136. IN PVOID ClientContext,
  137. IN DWORD BytesWritten,
  138. IN DWORD CompletionStatus,
  139. IN OVERLAPPED * lpo
  140. )
  141. {
  142. PATQ_CONT pAtqContext = (PATQ_CONT)ClientContext;
  143. DWORD nWrite = 0;
  144. INT err = NOERROR;
  145. OVERLAPPED ov;
  146. OVERLAPPED *pov = &ov;
  147. LPVOID lpBufferSend;
  148. BOOL fRes = FALSE;
  149. //
  150. // We need to use saved context value because of reasons above
  151. //
  152. ATQ_ASSERT(pAtqContext != NULL);
  153. pAtqContext->arInfo.uop.opFakeXmit.BytesWritten += BytesWritten;
  154. if ( CompletionStatus != NO_ERROR ) {
  155. //
  156. // An error occured, call the completion routine
  157. //
  158. pAtqContext->arInfo.dwLastIOError = CompletionStatus;
  159. goto call_completion;
  160. }
  161. //
  162. // Calculate pointer and number of bytes to send , depending on
  163. // the current state of transmission
  164. //
  165. if (pAtqContext->arInfo.uop.opFakeXmit.CurrentState == ATQ_XMIT_START) {
  166. //
  167. // We are just starting transmission, check if there is any
  168. // header part to send
  169. //
  170. nWrite = pAtqContext->arInfo.uop.opFakeXmit.TransmitBuffers.HeadLength;
  171. pAtqContext->arInfo.uop.opFakeXmit.CurrentState = ATQ_XMIT_HEADR_SENT;
  172. lpBufferSend = pAtqContext->arInfo.uop.opFakeXmit.TransmitBuffers.Head;
  173. if ( (nWrite != 0) && (lpBufferSend != NULL) ) {
  174. goto AtqXmitSendData;
  175. }
  176. }
  177. if (pAtqContext->arInfo.uop.opFakeXmit.CurrentState == ATQ_XMIT_HEADR_SENT) {
  178. //
  179. // Clear written bytes counter, as this is very first iteration
  180. //
  181. BytesWritten = 0;
  182. //
  183. // Check if the file was zero lenth ?
  184. // Check if we have temporary transmission buffer
  185. //
  186. if (pAtqContext->arInfo.uop.opFakeXmit.pBuffer == NULL) {
  187. pAtqContext->arInfo.uop.opFakeXmit.pBuffer =
  188. (PCHAR)LocalAlloc(LPTR, g_cbXmitBufferSize);
  189. }
  190. //
  191. // Set starting offset for the opened file
  192. //
  193. SetFilePointer(
  194. pAtqContext->arInfo.uop.opFakeXmit.hFile,
  195. pAtqContext->arInfo.uop.opFakeXmit.FileOffset,
  196. NULL,
  197. FILE_BEGIN
  198. );
  199. pAtqContext->arInfo.uop.opFakeXmit.CurrentState =
  200. ATQ_XMIT_TRANSMITTING_FILE;
  201. }
  202. if (pAtqContext->arInfo.uop.opFakeXmit.CurrentState ==
  203. ATQ_XMIT_TRANSMITTING_FILE) {
  204. //
  205. // We are sending file itself - do we have anything left to do ?
  206. //
  207. if (pAtqContext->arInfo.uop.opFakeXmit.BytesLeft != 0) {
  208. //
  209. // Calculate offset for the next read .
  210. // This would be previous offset plus number of
  211. // bytes written on last operation.
  212. //
  213. pAtqContext->arInfo.uop.opFakeXmit.FileOffset += BytesWritten;
  214. if (pAtqContext->arInfo.uop.opFakeXmit.pBuffer != NULL) {
  215. //
  216. // Read file from current offset
  217. //
  218. DWORD nToRead = g_cbXmitBufferSize;
  219. nToRead = min(
  220. g_cbXmitBufferSize,
  221. pAtqContext->arInfo.uop.opFakeXmit.BytesLeft);
  222. nWrite = 0;
  223. fRes = ReadFile(pAtqContext->arInfo.uop.opFakeXmit.hFile,
  224. pAtqContext->arInfo.uop.opFakeXmit.pBuffer,
  225. nToRead,
  226. &nWrite,
  227. NULL);
  228. if ( !fRes ) {
  229. ATQ_PRINTF((DBG_CONTEXT,
  230. "Error %d in ReadFile\n", GetLastError()));
  231. }
  232. if (pAtqContext->arInfo.uop.opFakeXmit.BytesLeft >= nWrite) {
  233. pAtqContext->arInfo.uop.opFakeXmit.BytesLeft -= nWrite;
  234. } else {
  235. pAtqContext->arInfo.uop.opFakeXmit.BytesLeft = 0;
  236. }
  237. IF_DEBUG(SIO) {
  238. ATQ_PRINTF((DBG_CONTEXT,
  239. "[TransmitFile(%lu)] Got data from file: context=%x Offset=%x nWrite=%x fRes=%d \n",
  240. GetCurrentThreadId(),pAtqContext,
  241. pAtqContext->arInfo.uop.opFakeXmit.FileOffset,
  242. nWrite,fRes));
  243. }
  244. //
  245. // Read succeeded and we got the data - send it to the client
  246. //
  247. if (fRes && (nWrite != 0) ) {
  248. lpBufferSend = pAtqContext->arInfo.uop.opFakeXmit.pBuffer;
  249. goto AtqXmitSendData;
  250. }
  251. //
  252. // If ReadFile failed - get error code and analyze it
  253. //
  254. if (!fRes) {
  255. pAtqContext->arInfo.dwLastIOError = GetLastError();
  256. //
  257. // If we really shipped the whole file and error is EOF - ignore it
  258. //
  259. if ((pAtqContext->arInfo.dwLastIOError == ERROR_HANDLE_EOF) &&
  260. (!pAtqContext->arInfo.uop.opFakeXmit.BytesLeft)) {
  261. pAtqContext->arInfo.dwLastIOError = NO_ERROR;
  262. fRes = TRUE;
  263. }
  264. } else {
  265. //
  266. // If by some reasons we did not send all data planned we need
  267. // to report failure, causing close for socket. Otherwise client will wait
  268. // for the rest of the data and we will wait for client read
  269. // Nb: In some cases Read returns success but does not really get any data
  270. // we will treat this as premature EOF
  271. //
  272. if (pAtqContext->arInfo.uop.opFakeXmit.BytesLeft != 0) {
  273. pAtqContext->arInfo.dwLastIOError = ERROR_HANDLE_EOF;
  274. fRes = FALSE;
  275. }
  276. }
  277. } else {
  278. //
  279. // Buffer was not allocated - fail transmission
  280. //
  281. ATQ_PRINTF((DBG_CONTEXT,"Failed to allocate buffer\n"));
  282. pAtqContext->arInfo.dwLastIOError = ERROR_NOT_ENOUGH_MEMORY;
  283. }
  284. //
  285. // Failed read from file, terminate transmission
  286. //
  287. if (!fRes) {
  288. //
  289. // Abnormal termination of Read - reset the client socket
  290. //
  291. ATQ_PRINTF((DBG_CONTEXT,"Read failed. Shutdown called\n"));
  292. shutdown( HANDLE_TO_SOCKET(pAtqContext->hAsyncIO), 1 );
  293. goto call_completion;
  294. }
  295. }
  296. //
  297. // Free temporary buffer as we no longer need it
  298. //
  299. if (pAtqContext->arInfo.uop.opFakeXmit.pBuffer) {
  300. LocalFree(pAtqContext->arInfo.uop.opFakeXmit.pBuffer);
  301. pAtqContext->arInfo.uop.opFakeXmit.pBuffer = NULL;
  302. }
  303. //
  304. // We are finished with this file
  305. //
  306. pAtqContext->arInfo.uop.opFakeXmit.CurrentState = ATQ_XMIT_FILE_DONE;
  307. }
  308. if (pAtqContext->arInfo.uop.opFakeXmit.CurrentState == ATQ_XMIT_FILE_DONE) {
  309. //
  310. // Check if there is any tail part to send
  311. //
  312. pAtqContext->arInfo.uop.opFakeXmit.CurrentState = ATQ_XMIT_TAIL_SENT;
  313. nWrite = pAtqContext->arInfo.uop.opFakeXmit.TransmitBuffers.TailLength;
  314. lpBufferSend = pAtqContext->arInfo.uop.opFakeXmit.TransmitBuffers.Tail;
  315. }
  316. AtqXmitSendData:
  317. //
  318. // If we have something to send - start i/o operation
  319. //
  320. if ( (nWrite != 0) && (lpBufferSend != NULL) ) {
  321. pAtqContext->arInfo.atqOp = AtqIoXmitFile;
  322. pAtqContext->arInfo.uop.opFakeXmit.pvLastSent = lpBufferSend;
  323. pAtqContext->arInfo.uop.opFakeXmit.cbBuffer = nWrite;
  324. InterlockedIncrement( &pAtqContext->m_nIO);
  325. SIOStartAsyncOperation(g_hCompPort,(PATQ_CONTEXT)pAtqContext);
  326. return ;
  327. }
  328. //
  329. // If it was the last phase of transmission -
  330. // clean up and send successful notification
  331. //
  332. if (pAtqContext->arInfo.uop.opFakeXmit.CurrentState != ATQ_XMIT_TAIL_SENT) {
  333. }
  334. pAtqContext->arInfo.dwLastIOError = NOERROR;
  335. call_completion:
  336. //
  337. // Indicate no transmission in progress
  338. //
  339. pAtqContext->arInfo.uop.opFakeXmit.CurrentState = ATQ_XMIT_NONE;
  340. I_CleanupFakeTransmitFile(pAtqContext);
  341. pAtqContext->arInfo.dwTotalBytesTransferred =
  342. pAtqContext->arInfo.uop.opFakeXmit.BytesWritten;
  343. //
  344. // Clean up SIO state
  345. //
  346. pAtqContext->dwSIOFlags &= ~ATQ_SIO_FLAG_STATE_MASK;
  347. //
  348. // Queue context as completed
  349. //
  350. SIOPostCompletionStatus(g_hCompPort,
  351. pAtqContext->arInfo.uop.opFakeXmit.BytesWritten,
  352. (ULONG_PTR)pAtqContext,
  353. pAtqContext->arInfo.lpOverlapped);
  354. return ;
  355. } // I_FakeTransmitFileCompletion