PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Visual Studio 2008/CppNamedPipeServer/CppNamedPipeServer.cpp

#
C++ | 305 lines | 160 code | 41 blank | 104 comment | 23 complexity | 14a6b72b6b2cfc8178ebba915644648b MD5 | raw file
  1. /****************************** Module Header ******************************\
  2. * Module Name: CppNamedPipeServer.cpp
  3. * Project: CppNamedPipeServer
  4. * Copyright (c) Microsoft Corporation.
  5. *
  6. * Named pipe is a mechanism for one-way or duplex inter-process communication
  7. * between the pipe server and one or more pipe clients in the local machine
  8. * or across the computers in the intranet:
  9. *
  10. * PIPE_ACCESS_INBOUND:
  11. * Client (GENERIC_WRITE) ---> Server (GENERIC_READ)
  12. *
  13. * PIPE_ACCESS_OUTBOUND:
  14. * Client (GENERIC_READ) <--- Server (GENERIC_WRITE)
  15. *
  16. * PIPE_ACCESS_DUPLEX:
  17. * Client (GENERIC_READ or GENERIC_WRITE, or both) <-->
  18. * Server (GENERIC_READ and GENERIC_WRITE)
  19. *
  20. * This code sample demonstrates calling CreateNamedPipe to create a pipe
  21. * named "\\.\pipe\SamplePipe", which supports duplex connections so that both
  22. * client and server can read from and write to the pipe. The security
  23. * attributes of the pipe are customized to allow Authenticated Users read and
  24. * write access to a pipe, and to allow the Administrators group full access
  25. * to the pipe. When the pipe is connected by a client, the server attempts to
  26. * read the client's message from the pipe by calling ReadFile, and write a
  27. * response by calling WriteFile.
  28. *
  29. * This source is subject to the Microsoft Public License.
  30. * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
  31. * All other rights reserved.
  32. *
  33. * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  34. * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
  35. * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  36. \***************************************************************************/
  37. #pragma region Includes
  38. #include <stdio.h>
  39. #include <windows.h>
  40. #include <sddl.h>
  41. #pragma endregion
  42. // The full name of the pipe in the format of \\servername\pipe\pipename.
  43. #define SERVER_NAME L"."
  44. #define PIPE_NAME L"SamplePipe"
  45. #define FULL_PIPE_NAME L"\\\\" SERVER_NAME L"\\pipe\\" PIPE_NAME
  46. #define BUFFER_SIZE 1024
  47. // Response message from client to server. '\0' is appended in the end
  48. // because the client may be a native C++ application that expects NULL
  49. // termiated string.
  50. #define RESPONSE_MESSAGE L"Default response from server"
  51. BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *);
  52. void FreePipeSecurity(PSECURITY_ATTRIBUTES);
  53. int wmain(int argc, wchar_t* argv[])
  54. {
  55. DWORD dwError = ERROR_SUCCESS;
  56. PSECURITY_ATTRIBUTES pSa = NULL;
  57. HANDLE hNamedPipe = INVALID_HANDLE_VALUE;
  58. // Prepare the security attributes (the lpSecurityAttributes parameter in
  59. // CreateNamedPipe) for the pipe. This is optional. If the
  60. // lpSecurityAttributes parameter of CreateNamedPipe is NULL, the named
  61. // pipe gets a default security descriptor and the handle cannot be
  62. // inherited. The ACLs in the default security descriptor of a pipe grant
  63. // full control to the LocalSystem account, (elevated) administrators,
  64. // and the creator owner. They also give only read access to members of
  65. // the Everyone group and the anonymous account. However, if you want to
  66. // customize the security permission of the pipe, (e.g. to allow
  67. // Authenticated Users to read from and write to the pipe), you need to
  68. // create a SECURITY_ATTRIBUTES structure.
  69. if (!CreatePipeSecurity(&pSa))
  70. {
  71. dwError = GetLastError();
  72. wprintf(L"CreatePipeSecurity failed w/err 0x%08lx\n", dwError);
  73. goto Cleanup;
  74. }
  75. // Create the named pipe.
  76. hNamedPipe = CreateNamedPipe(
  77. FULL_PIPE_NAME, // Pipe name.
  78. PIPE_ACCESS_DUPLEX, // The pipe is duplex; both server and
  79. // client processes can read from and
  80. // write to the pipe
  81. PIPE_TYPE_MESSAGE | // Message type pipe
  82. PIPE_READMODE_MESSAGE | // Message-read mode
  83. PIPE_WAIT, // Blocking mode is enabled
  84. PIPE_UNLIMITED_INSTANCES, // Max. instances
  85. BUFFER_SIZE, // Output buffer size in bytes
  86. BUFFER_SIZE, // Input buffer size in bytes
  87. NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval
  88. pSa // Security attributes
  89. );
  90. if (hNamedPipe == INVALID_HANDLE_VALUE)
  91. {
  92. dwError = GetLastError();
  93. wprintf(L"Unable to create named pipe w/err 0x%08lx\n", dwError);
  94. goto Cleanup;
  95. }
  96. wprintf(L"The named pipe (%s) is created.\n", FULL_PIPE_NAME);
  97. // Wait for the client to connect.
  98. wprintf(L"Waiting for the client's connection...\n");
  99. if (!ConnectNamedPipe(hNamedPipe, NULL))
  100. {
  101. if (ERROR_PIPE_CONNECTED != GetLastError())
  102. {
  103. dwError = GetLastError();
  104. wprintf(L"ConnectNamedPipe failed w/err 0x%08lx\n", dwError);
  105. goto Cleanup;
  106. }
  107. }
  108. wprintf(L"Client is connected.\n");
  109. //
  110. // Receive a request from client.
  111. //
  112. BOOL fFinishRead = FALSE;
  113. do
  114. {
  115. wchar_t chRequest[BUFFER_SIZE];
  116. DWORD cbRequest, cbRead;
  117. cbRequest = sizeof(chRequest);
  118. fFinishRead = ReadFile(
  119. hNamedPipe, // Handle of the pipe
  120. chRequest, // Buffer to receive data
  121. cbRequest, // Size of buffer in bytes
  122. &cbRead, // Number of bytes read
  123. NULL // Not overlapped I/O
  124. );
  125. if (!fFinishRead && ERROR_MORE_DATA != GetLastError())
  126. {
  127. dwError = GetLastError();
  128. wprintf(L"ReadFile from pipe failed w/err 0x%08lx\n", dwError);
  129. goto Cleanup;
  130. }
  131. wprintf(L"Receive %ld bytes from client: \"%s\"\n", cbRead, chRequest);
  132. } while (!fFinishRead); // Repeat loop if ERROR_MORE_DATA
  133. //
  134. // Send a response from server to client.
  135. //
  136. wchar_t chResponse[] = RESPONSE_MESSAGE;
  137. DWORD cbResponse, cbWritten;
  138. cbResponse = sizeof(chResponse);
  139. if (!WriteFile(
  140. hNamedPipe, // Handle of the pipe
  141. chResponse, // Buffer to write
  142. cbResponse, // Number of bytes to write
  143. &cbWritten, // Number of bytes written
  144. NULL // Not overlapped I/O
  145. ))
  146. {
  147. dwError = GetLastError();
  148. wprintf(L"WriteFile to pipe failed w/err 0x%08lx\n", dwError);
  149. goto Cleanup;
  150. }
  151. wprintf(L"Send %ld bytes to client: \"%s\"\n", cbWritten, chResponse);
  152. // Flush the pipe to allow the client to read the pipe's contents
  153. // before disconnecting. Then disconnect the client's connection.
  154. FlushFileBuffers(hNamedPipe);
  155. DisconnectNamedPipe(hNamedPipe);
  156. Cleanup:
  157. // Centralized cleanup for all allocated resources.
  158. if (pSa != NULL)
  159. {
  160. FreePipeSecurity(pSa);
  161. pSa = NULL;
  162. }
  163. if (hNamedPipe != INVALID_HANDLE_VALUE)
  164. {
  165. CloseHandle(hNamedPipe);
  166. hNamedPipe = INVALID_HANDLE_VALUE;
  167. }
  168. return dwError;
  169. }
  170. //
  171. // FUNCTION: CreatePipeSecurity(PSECURITY_ATTRIBUTES *)
  172. //
  173. // PURPOSE: The CreatePipeSecurity function creates and initializes a new
  174. // SECURITY_ATTRIBUTES structure to allow Authenticated Users read and
  175. // write access to a pipe, and to allow the Administrators group full
  176. // access to the pipe.
  177. //
  178. // PARAMETERS:
  179. // * ppSa - output a pointer to a SECURITY_ATTRIBUTES structure that allows
  180. // Authenticated Users read and write access to a pipe, and allows the
  181. // Administrators group full access to the pipe. The structure must be
  182. // freed by calling FreePipeSecurity.
  183. //
  184. // RETURN VALUE: Returns TRUE if the function succeeds.
  185. //
  186. // EXAMPLE CALL:
  187. //
  188. // PSECURITY_ATTRIBUTES pSa = NULL;
  189. // if (CreatePipeSecurity(&pSa))
  190. // {
  191. // // Use the security attributes
  192. // // ...
  193. //
  194. // FreePipeSecurity(pSa);
  195. // }
  196. //
  197. BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *ppSa)
  198. {
  199. BOOL fSucceeded = TRUE;
  200. DWORD dwError = ERROR_SUCCESS;
  201. PSECURITY_DESCRIPTOR pSd = NULL;
  202. PSECURITY_ATTRIBUTES pSa = NULL;
  203. // Define the SDDL for the security descriptor.
  204. PCWSTR szSDDL = L"D:" // Discretionary ACL
  205. L"(A;OICI;GRGW;;;AU)" // Allow read/write to authenticated users
  206. L"(A;OICI;GA;;;BA)"; // Allow full control to administrators
  207. if (!ConvertStringSecurityDescriptorToSecurityDescriptor(szSDDL,
  208. SDDL_REVISION_1, &pSd, NULL))
  209. {
  210. fSucceeded = FALSE;
  211. dwError = GetLastError();
  212. goto Cleanup;
  213. }
  214. // Allocate the memory of SECURITY_ATTRIBUTES.
  215. pSa = (PSECURITY_ATTRIBUTES)LocalAlloc(LPTR, sizeof(*pSa));
  216. if (pSa == NULL)
  217. {
  218. fSucceeded = FALSE;
  219. dwError = GetLastError();
  220. goto Cleanup;
  221. }
  222. pSa->nLength = sizeof(*pSa);
  223. pSa->lpSecurityDescriptor = pSd;
  224. pSa->bInheritHandle = FALSE;
  225. *ppSa = pSa;
  226. Cleanup:
  227. // Clean up the allocated resources if something is wrong.
  228. if (!fSucceeded)
  229. {
  230. if (pSd)
  231. {
  232. LocalFree(pSd);
  233. pSd = NULL;
  234. }
  235. if (pSa)
  236. {
  237. LocalFree(pSa);
  238. pSa = NULL;
  239. }
  240. SetLastError(dwError);
  241. }
  242. return fSucceeded;
  243. }
  244. //
  245. // FUNCTION: FreePipeSecurity(PSECURITY_ATTRIBUTES)
  246. //
  247. // PURPOSE: The FreePipeSecurity function frees a SECURITY_ATTRIBUTES
  248. // structure that was created by the CreatePipeSecurity function.
  249. //
  250. // PARAMETERS:
  251. // * pSa - pointer to a SECURITY_ATTRIBUTES structure that was created by
  252. // the CreatePipeSecurity function.
  253. //
  254. void FreePipeSecurity(PSECURITY_ATTRIBUTES pSa)
  255. {
  256. if (pSa)
  257. {
  258. if (pSa->lpSecurityDescriptor)
  259. {
  260. LocalFree(pSa->lpSecurityDescriptor);
  261. }
  262. LocalFree(pSa);
  263. }
  264. }