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.

473 lines
12 KiB

  1. /******************************************************************************\
  2. * This is a part of the Microsoft Source Code Samples.
  3. * Copyright 1995 - 1997 Microsoft Corporation.
  4. * All rights reserved.
  5. * This source code is only intended as a supplement to
  6. * Microsoft Development Tools and/or WinHelp documentation.
  7. * See these sources for detailed information regarding the
  8. * Microsoft samples programs.
  9. \******************************************************************************/
  10. /*++
  11. Copyright (c) 1997 Microsoft Corporation
  12. Module Name:
  13. SrvStoC.c
  14. Abstract:
  15. This file implements the server-to-client flow
  16. of data for remote server. The data is the output
  17. of the child program intermingled with client input.
  18. Author:
  19. Dave Hart 30 May 1997
  20. Environment:
  21. Console App. User mode.
  22. Revision History:
  23. --*/
  24. #include <windows.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <io.h>
  28. #include <string.h>
  29. #include "Remote.h"
  30. #include "Server.h"
  31. VOID
  32. FASTCALL
  33. StartServerToClientFlow(
  34. VOID
  35. )
  36. {
  37. PREMOTE_CLIENT pClient;
  38. //
  39. // Start read operations against the temp file for
  40. // all active clients that aren't currently doing
  41. // read temp/write client operations and that are
  42. // fully connected.
  43. //
  44. for (pClient = (PREMOTE_CLIENT) ClientListHead.Flink;
  45. pClient != (PREMOTE_CLIENT) &ClientListHead;
  46. pClient = (PREMOTE_CLIENT) pClient->Links.Flink ) {
  47. if (! pClient->cbWrite) {
  48. StartReadTempFile( pClient );
  49. }
  50. }
  51. }
  52. VOID
  53. FASTCALL
  54. StartReadTempFile(
  55. PREMOTE_CLIENT pClient
  56. )
  57. {
  58. //
  59. // pClient->cbWrite is used dually. WriteSessionOutputCompleted
  60. // uses it when 0 bytes are written to know how much to ask
  61. // to write when it resubmits the request. We use it to
  62. // indicate whether a read temp/write session chain of I/Os
  63. // is currently active for this client.
  64. //
  65. if (pClient->cbWrite) {
  66. ErrorExit("StartReadTempFile entered with nonzero cbWrite.");
  67. }
  68. if (dwWriteFilePointer > pClient->dwFilePos) {
  69. pClient->cbWrite = min(BUFFSIZE,
  70. dwWriteFilePointer - pClient->dwFilePos);
  71. pClient->WriteOverlapped.OffsetHigh = 0;
  72. pClient->WriteOverlapped.Offset = pClient->dwFilePos;
  73. if ( ! ReadFileEx(
  74. pClient->rSaveFile,
  75. pClient->ReadTempBuffer,
  76. pClient->cbWrite,
  77. &pClient->WriteOverlapped,
  78. ReadTempFileCompleted
  79. )) {
  80. if (ERROR_HANDLE_EOF == GetLastError()) {
  81. pClient->cbWrite = 0;
  82. } else {
  83. TRACE(SESSION, ("ReadFileEx for temp file failed error %d, closing client.\n", GetLastError()));
  84. CloseClient(pClient);
  85. }
  86. }
  87. }
  88. }
  89. VOID
  90. WINAPI
  91. ReadTempFileCompleted(
  92. DWORD dwError,
  93. DWORD cbRead,
  94. LPOVERLAPPED lpO
  95. )
  96. {
  97. PREMOTE_CLIENT pClient;
  98. pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
  99. if (HandleSessionError(pClient, dwError)) {
  100. return;
  101. }
  102. if (cbRead != pClient->cbWrite) {
  103. TRACE(SESSION, ("Read %d from temp file asked for %d\n", cbRead, pClient->cbWrite));
  104. }
  105. if (cbRead) {
  106. pClient->cbReadTempBuffer = cbRead;
  107. pClient->dwFilePos += cbRead;
  108. StartWriteSessionOutput(pClient);
  109. } else {
  110. //
  111. // Note that the server to client flow is halting for now
  112. // for this client.
  113. //
  114. pClient->cbWrite = 0;
  115. }
  116. }
  117. VOID
  118. FASTCALL
  119. StartWriteSessionOutput(
  120. PREMOTE_CLIENT pClient
  121. )
  122. {
  123. DWORD cbRead;
  124. char *pch;
  125. cbRead = pClient->cbReadTempBuffer;
  126. //
  127. // We need to split commands from other text read
  128. // from the temp file and hold off on writing them
  129. // to the client until we make sure we're not the
  130. // client that submitted it. This isn't perfect
  131. // since we match on client name which can be
  132. // duplicated but it solves the problem of
  133. // duplicated input most of the time.
  134. //
  135. for (pch = pClient->ReadTempBuffer;
  136. pch < pClient->ReadTempBuffer + cbRead;
  137. pch++) {
  138. if ( ! (pClient->ServerFlags & SFLG_READINGCOMMAND) ) {
  139. if (BEGINMARK == *pch) {
  140. pClient->ServerFlags |= SFLG_READINGCOMMAND;
  141. if (pch != pClient->ReadTempBuffer &&
  142. pClient->cbWriteBuffer) {
  143. //
  144. // Start a write of everything we've come across
  145. // before the start of this command, with
  146. // WriteSessionOutputCompletedWriteNext specified
  147. // so we can continue processing the remainder
  148. // of pReadTempBuffer.
  149. //
  150. pClient->cbReadTempBuffer -= (DWORD)( pch - pClient->ReadTempBuffer) + 1;
  151. cbRead = pClient->cbReadTempBuffer;
  152. #if DBG
  153. if (pClient->cbReadTempBuffer == (DWORD)-1) {
  154. ErrorExit("cbReadTempBuffer underflow.");
  155. }
  156. #endif
  157. MoveMemory(pClient->ReadTempBuffer, pch + 1, cbRead);
  158. pClient->cbWrite = pClient->cbWriteBuffer;
  159. pClient->WriteOverlapped.OffsetHigh = 0;
  160. pClient->WriteOverlapped.Offset = 0;
  161. if ( ! WriteFileEx(
  162. pClient->PipeWriteH,
  163. pClient->WriteBuffer,
  164. pClient->cbWrite,
  165. &pClient->WriteOverlapped,
  166. WriteSessionOutputCompletedWriteNext
  167. )) {
  168. CloseClient(pClient);
  169. }
  170. TRACE(SESSION, ("%p Wrote %d bytes pre-command output\n", pClient, pClient->cbWrite));
  171. pClient->cbWriteBuffer = 0;
  172. return;
  173. }
  174. } else {
  175. if (pClient->cbWriteBuffer == BUFFSIZE) {
  176. ErrorExit("cbWriteBuffer overflow");
  177. }
  178. pClient->WriteBuffer[ pClient->cbWriteBuffer++ ] = *pch;
  179. }
  180. } else {
  181. if (ENDMARK == *pch ||
  182. pClient->cbCommandBuffer == BUFFSIZE) {
  183. pClient->ServerFlags &= ~SFLG_READINGCOMMAND;
  184. //
  185. // Preceding ENDMARK is the pClient in hex ascii of the
  186. // client that generated the command, not null terminated.
  187. //
  188. if (ENDMARK == *pch) {
  189. pClient->cbCommandBuffer -=
  190. min(pClient->cbCommandBuffer, sizeof(pClient->HexAsciiId));
  191. }
  192. //
  193. // We hide each client's input from their output pipe
  194. // because their local remote.exe has already displayed it.
  195. //
  196. if ( pClient->cbCommandBuffer &&
  197. ! (ENDMARK == *pch &&
  198. ! memcmp(
  199. pch - sizeof(pClient->HexAsciiId),
  200. pClient->HexAsciiId,
  201. sizeof(pClient->HexAsciiId)))) {
  202. //
  203. // Start a write of the accumulated command with
  204. // WriteSessionOutputCompletedWriteNext specified
  205. // so we can continue processing the remainder
  206. // of pReadTempBuffer.
  207. //
  208. pClient->cbReadTempBuffer -= (DWORD)(pch - pClient->ReadTempBuffer) + 1;
  209. MoveMemory(pClient->ReadTempBuffer, pch + 1, pClient->cbReadTempBuffer);
  210. pClient->cbWrite = pClient->cbCommandBuffer;
  211. pClient->cbCommandBuffer = 0;
  212. pClient->WriteOverlapped.OffsetHigh = 0;
  213. pClient->WriteOverlapped.Offset = 0;
  214. if ( ! WriteFileEx(
  215. pClient->PipeWriteH,
  216. pClient->CommandBuffer,
  217. pClient->cbWrite,
  218. &pClient->WriteOverlapped,
  219. WriteSessionOutputCompletedWriteNext
  220. )) {
  221. CloseClient(pClient);
  222. return;
  223. } else {
  224. TRACE(SESSION, ("%p Wrote %d bytes command\n", pClient, pClient->cbWrite));
  225. return;
  226. }
  227. } else {
  228. //
  229. // We're eating this command for this session.
  230. //
  231. pClient->cbCommandBuffer = 0;
  232. }
  233. } else {
  234. pClient->CommandBuffer[ pClient->cbCommandBuffer++ ] = *pch;
  235. }
  236. }
  237. }
  238. //
  239. // We're done with the ReadTempBuffer.
  240. //
  241. pClient->cbReadTempBuffer = 0;
  242. if (pClient->cbWriteBuffer) {
  243. pClient->cbWrite = pClient->cbWriteBuffer;
  244. pClient->WriteOverlapped.OffsetHigh = 0;
  245. pClient->WriteOverlapped.Offset = 0;
  246. if ( ! WriteFileEx(
  247. pClient->PipeWriteH,
  248. pClient->WriteBuffer,
  249. pClient->cbWrite,
  250. &pClient->WriteOverlapped,
  251. WriteSessionOutputCompletedReadNext
  252. )) {
  253. CloseClient(pClient);
  254. return;
  255. } else {
  256. TRACE(SESSION, ("%p Wrote %d bytes normal\n", pClient, pClient->cbWrite));
  257. pClient->cbWriteBuffer = 0;
  258. }
  259. } else {
  260. //
  261. // Write buffer is empty.
  262. //
  263. pClient->cbWrite = 0;
  264. StartReadTempFile(pClient);
  265. }
  266. }
  267. BOOL
  268. FASTCALL
  269. WriteSessionOutputCompletedCommon(
  270. PREMOTE_CLIENT pClient,
  271. DWORD dwError,
  272. DWORD cbWritten,
  273. LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
  274. )
  275. {
  276. if (HandleSessionError(pClient, dwError)) {
  277. return TRUE;
  278. }
  279. if (!pClient->cbWrite) {
  280. ErrorExit("Zero cbWrite in WriteSessionOutputCompletedCommon");
  281. }
  282. if (!cbWritten && pClient->cbWrite) {
  283. printf("WriteSessionOutput zero bytes written of %d.\n", pClient->cbWrite);
  284. ErrorExit("WriteSessionOutputCompletedCommon failure");
  285. return TRUE;
  286. }
  287. #if DBG
  288. if (cbWritten != pClient->cbWrite) {
  289. printf("%p cbWritten %d cbWrite %d\n", pClient, cbWritten, pClient->cbWrite);
  290. }
  291. #endif
  292. return FALSE;
  293. }
  294. VOID
  295. WINAPI
  296. WriteSessionOutputCompletedWriteNext(
  297. DWORD dwError,
  298. DWORD cbWritten,
  299. LPOVERLAPPED lpO
  300. )
  301. {
  302. PREMOTE_CLIENT pClient;
  303. pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
  304. if (WriteSessionOutputCompletedCommon(
  305. pClient,
  306. dwError,
  307. cbWritten,
  308. WriteSessionOutputCompletedWriteNext
  309. )) {
  310. return;
  311. }
  312. StartWriteSessionOutput(pClient);
  313. }
  314. VOID
  315. WINAPI
  316. WriteSessionOutputCompletedReadNext(
  317. DWORD dwError,
  318. DWORD cbWritten,
  319. LPOVERLAPPED lpO
  320. )
  321. {
  322. PREMOTE_CLIENT pClient;
  323. pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
  324. if (WriteSessionOutputCompletedCommon(
  325. pClient,
  326. dwError,
  327. cbWritten,
  328. WriteSessionOutputCompletedReadNext
  329. )) {
  330. return;
  331. }
  332. //
  333. // Start another temp file read.
  334. //
  335. pClient->cbWrite = 0;
  336. StartReadTempFile(pClient);
  337. }