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.

415 lines
9.5 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. SrvHShak.c
  14. Abstract:
  15. The server component of Remote. Handshake with
  16. client at start of session.
  17. Author:
  18. Dave Hart 30 May 1997
  19. Environment:
  20. Console App. User mode.
  21. Revision History:
  22. --*/
  23. #include <windows.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <io.h>
  27. #include <string.h>
  28. #include "Remote.h"
  29. #include "Server.h"
  30. VOID
  31. FASTCALL
  32. HandshakeWithRemoteClient(
  33. PREMOTE_CLIENT pClient
  34. )
  35. {
  36. pClient->ServerFlags |= SFLG_HANDSHAKING;
  37. AddClientToHandshakingList(pClient);
  38. //
  39. // Read hostname from client
  40. //
  41. ZeroMemory(
  42. &pClient->ReadOverlapped,
  43. sizeof(pClient->ReadOverlapped)
  44. );
  45. if ( ! ReadFileEx(
  46. pClient->PipeReadH,
  47. pClient->Name,
  48. HOSTNAMELEN - 1,
  49. &pClient->ReadOverlapped,
  50. ReadClientNameCompleted
  51. )) {
  52. CloseClient(pClient);
  53. }
  54. }
  55. VOID
  56. WINAPI
  57. ReadClientNameCompleted(
  58. DWORD dwError,
  59. DWORD cbRead,
  60. LPOVERLAPPED lpO
  61. )
  62. {
  63. PREMOTE_CLIENT pClient;
  64. SESSION_STARTREPLY ssr;
  65. pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, ReadOverlapped);
  66. if (pClient->ServerFlags & SFLG_CLOSING) {
  67. return;
  68. }
  69. if (dwError) {
  70. CloseClient(pClient);
  71. return;
  72. }
  73. if ((HOSTNAMELEN - 1) != cbRead) {
  74. printf("ReadClientNameCompleted read %d s/b %d.\n", cbRead, (HOSTNAMELEN - 1));
  75. CloseClient(pClient);
  76. return;
  77. }
  78. //
  79. // The client name read is 15 bytes always. The last four
  80. // should match MAGICNUMBER, which conveniently has the
  81. // low byte zeroed to terminate the client name after 11
  82. // characters.
  83. //
  84. if (MAGICNUMBER != *(DWORD UNALIGNED *)&pClient->Name[11]) {
  85. pClient->Name[11] = 0;
  86. CloseClient(pClient);
  87. return;
  88. }
  89. //
  90. // Now we can tell if this is a single-pipe or two-pipe
  91. // client, because single-pipe clients replace the
  92. // first byte of the computername with the illegal
  93. // character '?'.
  94. //
  95. if ('?' == pClient->Name[0]) {
  96. pClient->PipeWriteH = pClient->PipeReadH;
  97. TRACE(CONNECT, ("Client %d pipe %p is single-pipe.\n", pClient->dwID, pClient->PipeWriteH));
  98. //
  99. // In order for things to work reliably for 2-pipe clients
  100. // when there are multiple remote servers on the same pipename,
  101. // we need to tear down the listening OUT pipe and recreate it so
  102. // that the oldest listening IN pipe will be from the same process
  103. // as the oldest listening OUT pipe.
  104. //
  105. if (1 == cConnectIns) {
  106. TRACE(CONNECT, ("Recycling OUT pipe %p as well for round-robin behavior.\n",
  107. hPipeOut));
  108. CANCELIO(hPipeOut);
  109. DisconnectNamedPipe(hPipeOut);
  110. CloseHandle(hPipeOut);
  111. hPipeOut = INVALID_HANDLE_VALUE;
  112. bOutPipeConnected = FALSE;
  113. CreatePipeAndIssueConnect(OUT_PIPE);
  114. }
  115. } else {
  116. if ( ! bOutPipeConnected ) {
  117. printf("Remote: %p two-pipe client connected to IN pipe but not OUT?\n", pClient);
  118. CloseClient(pClient);
  119. return;
  120. }
  121. bOutPipeConnected = FALSE;
  122. if (INVALID_HANDLE_VALUE != hConnectOutTimer) {
  123. pfnCancelWaitableTimer(hConnectOutTimer);
  124. }
  125. pClient->PipeWriteH = hPipeOut;
  126. hPipeOut = INVALID_HANDLE_VALUE;
  127. TRACE(CONNECT, ("Client %d is dual-pipe IN %p OUT %p.\n", pClient->dwID, pClient->PipeReadH, pClient->PipeWriteH));
  128. CreatePipeAndIssueConnect(OUT_PIPE);
  129. }
  130. TRACE(SHAKE, ("Read client name %s\n", pClient->Name));
  131. //
  132. // Send our little pile of goodies to the client
  133. //
  134. ssr.MagicNumber = MAGICNUMBER;
  135. ssr.Size = sizeof(ssr);
  136. ssr.FileSize = dwWriteFilePointer;
  137. //
  138. // Copy ssr structure to a buffer that will be around
  139. // for the entire I/O.
  140. //
  141. CopyMemory(pClient->WriteBuffer, &ssr, sizeof(ssr));
  142. if ( ! WriteFileEx(
  143. pClient->PipeWriteH,
  144. pClient->WriteBuffer,
  145. sizeof(ssr),
  146. &pClient->WriteOverlapped,
  147. WriteServerReplyCompleted
  148. )) {
  149. CloseClient(pClient);
  150. }
  151. }
  152. VOID
  153. WINAPI
  154. WriteServerReplyCompleted(
  155. DWORD dwError,
  156. DWORD cbWritten,
  157. LPOVERLAPPED lpO
  158. )
  159. {
  160. PREMOTE_CLIENT pClient;
  161. pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, WriteOverlapped);
  162. if (pClient->ServerFlags & SFLG_CLOSING) {
  163. return;
  164. }
  165. if (HandleSessionError(pClient, dwError)) {
  166. return;
  167. }
  168. TRACE(SHAKE, ("Wrote server reply\n"));
  169. //
  170. // Read the size of the SESSION_STARTUPINFO the client is
  171. // sending us, to deal gracefully with different versions
  172. // on client and server.
  173. //
  174. if ( ! ReadFileEx(
  175. pClient->PipeReadH,
  176. pClient->ReadBuffer,
  177. sizeof(DWORD),
  178. &pClient->ReadOverlapped,
  179. ReadClientStartupInfoSizeCompleted
  180. )) {
  181. CloseClient(pClient);
  182. }
  183. }
  184. VOID
  185. WINAPI
  186. ReadClientStartupInfoSizeCompleted(
  187. DWORD dwError,
  188. DWORD cbRead,
  189. LPOVERLAPPED lpO
  190. )
  191. {
  192. PREMOTE_CLIENT pClient;
  193. DWORD dwSize;
  194. pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, ReadOverlapped);
  195. if (HandleSessionError(pClient, dwError)) {
  196. return;
  197. }
  198. if (cbRead != sizeof(DWORD)) {
  199. CloseClient(pClient);
  200. return;
  201. }
  202. //
  203. // Sanity check the size
  204. //
  205. dwSize = *(DWORD *)pClient->ReadBuffer;
  206. if (dwSize > 1024) {
  207. CloseClient(pClient);
  208. return;
  209. }
  210. //
  211. // Squirrel away the size in the write buffer,
  212. // since during handshaking we never have both a
  213. // read and write pending this is OK.
  214. //
  215. *(DWORD *)pClient->WriteBuffer = dwSize;
  216. TRACE(SHAKE, ("Read client reply size %d\n", dwSize));
  217. //
  218. // Read the rest of the SESSION_STARTUPINFO into the read buffer
  219. // after the size.
  220. //
  221. RtlZeroMemory(
  222. &pClient->ReadOverlapped,
  223. sizeof(pClient->ReadOverlapped)
  224. );
  225. if ( ! ReadFileEx(
  226. pClient->PipeReadH,
  227. pClient->ReadBuffer + sizeof(DWORD),
  228. dwSize - sizeof(DWORD),
  229. &pClient->ReadOverlapped,
  230. ReadClientStartupInfoCompleted
  231. )) {
  232. CloseClient(pClient);
  233. }
  234. }
  235. VOID
  236. WINAPI
  237. ReadClientStartupInfoCompleted(
  238. DWORD dwError,
  239. DWORD cbRead,
  240. LPOVERLAPPED lpO
  241. )
  242. {
  243. PREMOTE_CLIENT pClient;
  244. DWORD dwSize;
  245. SESSION_STARTUPINFO ssi;
  246. char Buf[256];
  247. pClient = CONTAINING_RECORD(lpO, REMOTE_CLIENT, ReadOverlapped);
  248. if (HandleSessionError(pClient, dwError)) {
  249. return;
  250. }
  251. dwSize = *(DWORD *)pClient->WriteBuffer;
  252. if (cbRead != (dwSize - sizeof(ssi.Size))) {
  253. CloseClient(pClient);
  254. return;
  255. }
  256. CopyMemory(&ssi, pClient->ReadBuffer, min(dwSize, sizeof(ssi)));
  257. CopyMemory(pClient->Name, ssi.ClientName, sizeof(pClient->Name));
  258. pClient->Flag = ssi.Flag;
  259. if (ssi.Version != VERSION) {
  260. printf("Remote Warning: Server Version=%d Client Version=%d for %s\n", VERSION, ssi.Version, pClient->Name);
  261. }
  262. TRACE(SHAKE, ("Read client info, new name %s, %d lines\n", pClient->Name, ssi.LinesToSend));
  263. //
  264. // Set temp file position according to the client's
  265. // requested lines to send. The heuristic of 45 chars
  266. // per average line is used by the client. However since old clients
  267. // hardcode this knowledge and sit and spin trying to read that many
  268. // bytes before completing initialization, and because we might not send
  269. // that many due to stripping BEGINMARK and ENDMARK characters, we
  270. // use 50 chars per line to calculate the temp file position in hopes
  271. // the extra bytes will overcome the missing MARK characters.
  272. //
  273. pClient->dwFilePos = dwWriteFilePointer > (ssi.LinesToSend * 50)
  274. ? dwWriteFilePointer - (ssi.LinesToSend * 50)
  275. : 0;
  276. //
  277. // This client's ready to roll.
  278. //
  279. pClient->ServerFlags &= ~SFLG_HANDSHAKING;
  280. MoveClientToNormalList(pClient);
  281. //
  282. // Start read operation against this client's input.
  283. //
  284. StartReadClientInput(pClient);
  285. //
  286. // Announce the connection.
  287. //
  288. sprintf(Buf,
  289. "\n**Remote: Connected to %s %s%s [%s]\n",
  290. pClient->Name,
  291. pClient->UserName,
  292. (pClient->PipeReadH != pClient->PipeWriteH)
  293. ? " (two pipes)"
  294. : "",
  295. GetFormattedTime(TRUE));
  296. if (WriteFileSynch(hWriteTempFile,Buf,strlen(Buf),&dwSize,dwWriteFilePointer,&olMainThread)) {
  297. dwWriteFilePointer += dwSize;
  298. StartServerToClientFlow();
  299. }
  300. //
  301. // Start write cycle for client output from the temp
  302. // file.
  303. // not needed because of StartServerToClientFlow() just above
  304. // StartReadTempFile(pClient);
  305. }