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.

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