TestNamedPipeService.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "TestCommon.h"
  6. #include "TestHarness.h"
  7. #include <Windows.h>
  8. #include "mozilla/Atomics.h"
  9. #include "mozilla/Monitor.h"
  10. #include "nsINamedPipeService.h"
  11. #include "nsNetCID.h"
  12. #define PIPE_NAME "\\\\.\\pipe\\TestNPS"
  13. #define TEST_STR "Hello World"
  14. using namespace mozilla;
  15. class nsNamedPipeDataObserver : public nsINamedPipeDataObserver
  16. {
  17. public:
  18. NS_DECL_THREADSAFE_ISUPPORTS
  19. NS_DECL_NSINAMEDPIPEDATAOBSERVER
  20. explicit nsNamedPipeDataObserver(HANDLE aPipe);
  21. int Read(void* aBuffer, uint32_t aSize);
  22. int Write(const void* aBuffer, uint32_t aSize);
  23. uint32_t Transferred() const { return mBytesTransferred; }
  24. private:
  25. ~nsNamedPipeDataObserver() = default;
  26. HANDLE mPipe;
  27. OVERLAPPED mOverlapped;
  28. Atomic<uint32_t> mBytesTransferred;
  29. Monitor mMonitor;
  30. };
  31. NS_IMPL_ISUPPORTS(nsNamedPipeDataObserver, nsINamedPipeDataObserver)
  32. nsNamedPipeDataObserver::nsNamedPipeDataObserver(HANDLE aPipe)
  33. : mPipe(aPipe)
  34. , mOverlapped()
  35. , mBytesTransferred(0)
  36. , mMonitor("named-pipe")
  37. {
  38. mOverlapped.hEvent = CreateEventA(nullptr, TRUE, TRUE, "named-pipe");
  39. }
  40. int
  41. nsNamedPipeDataObserver::Read(void* aBuffer, uint32_t aSize)
  42. {
  43. DWORD bytesRead = 0;
  44. if (!ReadFile(mPipe, aBuffer, aSize, &bytesRead, &mOverlapped)) {
  45. switch(GetLastError()) {
  46. case ERROR_IO_PENDING:
  47. {
  48. MonitorAutoLock lock(mMonitor);
  49. mMonitor.Wait();
  50. }
  51. if (!GetOverlappedResult(mPipe, &mOverlapped, &bytesRead, FALSE)) {
  52. fail("GetOverlappedResult failed");
  53. return -1;
  54. }
  55. if (mBytesTransferred != bytesRead) {
  56. fail("GetOverlappedResult mismatch");
  57. return -1;
  58. }
  59. break;
  60. default:
  61. fail("ReadFile error %d", GetLastError());
  62. return -1;
  63. }
  64. } else {
  65. MonitorAutoLock lock(mMonitor);
  66. mMonitor.Wait();
  67. if (mBytesTransferred != bytesRead) {
  68. fail("GetOverlappedResult mismatch");
  69. return -1;
  70. }
  71. }
  72. mBytesTransferred = 0;
  73. passed("[read] match");
  74. return bytesRead;
  75. }
  76. int
  77. nsNamedPipeDataObserver::Write(const void* aBuffer, uint32_t aSize)
  78. {
  79. DWORD bytesWritten = 0;
  80. if (!WriteFile(mPipe, aBuffer, aSize, &bytesWritten, &mOverlapped)) {
  81. switch(GetLastError()) {
  82. case ERROR_IO_PENDING:
  83. {
  84. MonitorAutoLock lock(mMonitor);
  85. mMonitor.Wait();
  86. }
  87. if (!GetOverlappedResult(mPipe, &mOverlapped, &bytesWritten, FALSE)) {
  88. fail("GetOverlappedResult failed");
  89. return -1;
  90. }
  91. if (mBytesTransferred != bytesWritten) {
  92. fail("GetOverlappedResult mismatch");
  93. return -1;
  94. }
  95. break;
  96. default:
  97. fail("WriteFile error %d", GetLastError());
  98. return -1;
  99. }
  100. } else {
  101. MonitorAutoLock lock(mMonitor);
  102. mMonitor.Wait();
  103. if (mBytesTransferred != bytesWritten) {
  104. fail("GetOverlappedResult mismatch");
  105. return -1;
  106. }
  107. }
  108. mBytesTransferred = 0;
  109. passed("[write] match");
  110. return bytesWritten;
  111. }
  112. NS_IMETHODIMP
  113. nsNamedPipeDataObserver::OnDataAvailable(uint32_t aBytesTransferred,
  114. void *aOverlapped)
  115. {
  116. if (aOverlapped != &mOverlapped) {
  117. fail("invalid overlapped object");
  118. return NS_ERROR_FAILURE;
  119. }
  120. DWORD bytesTransferred = 0;
  121. BOOL ret = GetOverlappedResult(mPipe,
  122. reinterpret_cast<LPOVERLAPPED>(aOverlapped),
  123. &bytesTransferred,
  124. FALSE);
  125. if (!ret) {
  126. fail("GetOverlappedResult failed");
  127. return NS_ERROR_FAILURE;
  128. }
  129. if (bytesTransferred != aBytesTransferred) {
  130. fail("GetOverlappedResult mismatch");
  131. return NS_ERROR_FAILURE;
  132. }
  133. mBytesTransferred += aBytesTransferred;
  134. MonitorAutoLock lock(mMonitor);
  135. mMonitor.Notify();
  136. return NS_OK;
  137. }
  138. NS_IMETHODIMP
  139. nsNamedPipeDataObserver::OnError(uint32_t aError, void *aOverlapped)
  140. {
  141. return NS_ERROR_NOT_IMPLEMENTED;
  142. }
  143. BOOL CreateAndConnectInstance(LPOVERLAPPED aOverlapped, LPHANDLE aPipe);
  144. BOOL ConnectToNewClient(HANDLE aPipe, LPOVERLAPPED aOverlapped);
  145. BOOL CreateAndConnectInstance(LPOVERLAPPED aOverlapped, LPHANDLE aPipe)
  146. {
  147. if (!aPipe) {
  148. fail("Parameter aPipe is NULL\n");
  149. return FALSE;
  150. }
  151. // FIXME: adjust parameters
  152. *aPipe = CreateNamedPipeA(
  153. PIPE_NAME,
  154. PIPE_ACCESS_DUPLEX |
  155. FILE_FLAG_OVERLAPPED,
  156. PIPE_TYPE_MESSAGE |
  157. PIPE_READMODE_MESSAGE |
  158. PIPE_WAIT,
  159. 1,
  160. 65536,
  161. 65536,
  162. 3000,
  163. NULL);
  164. if (*aPipe == INVALID_HANDLE_VALUE) {
  165. fail("CreateNamedPipe failed [%d]\n", GetLastError());
  166. return FALSE;
  167. }
  168. return ConnectToNewClient(*aPipe, aOverlapped);
  169. }
  170. BOOL ConnectToNewClient(HANDLE aPipe, LPOVERLAPPED aOverlapped)
  171. {
  172. if (ConnectNamedPipe(aPipe, aOverlapped)) {
  173. fail("Unexpected, overlapped ConnectNamedPipe() always returns 0.\n");
  174. return FALSE;
  175. }
  176. switch (GetLastError())
  177. {
  178. case ERROR_IO_PENDING:
  179. return TRUE;
  180. case ERROR_PIPE_CONNECTED:
  181. if (SetEvent(aOverlapped->hEvent))
  182. break;
  183. default: // error
  184. fail("ConnectNamedPipe failed [%d]\n", GetLastError());
  185. break;
  186. }
  187. return FALSE;
  188. }
  189. static nsresult
  190. CreateNamedPipe(LPHANDLE aServer, LPHANDLE aClient)
  191. {
  192. OVERLAPPED overlapped;
  193. overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  194. BOOL ret;
  195. ret = CreateAndConnectInstance(&overlapped, aServer);
  196. if (!ret) {
  197. fail("pipe server should be pending");
  198. return NS_ERROR_FAILURE;
  199. }
  200. *aClient = CreateFileA(PIPE_NAME,
  201. GENERIC_READ | GENERIC_WRITE,
  202. FILE_SHARE_READ | FILE_SHARE_WRITE,
  203. nullptr,
  204. OPEN_EXISTING,
  205. FILE_FLAG_OVERLAPPED,
  206. nullptr);
  207. if (*aClient == INVALID_HANDLE_VALUE) {
  208. fail("Unable to create pipe client");
  209. CloseHandle(*aServer);
  210. return NS_ERROR_FAILURE;
  211. }
  212. DWORD pipeMode = PIPE_READMODE_MESSAGE;
  213. if (!SetNamedPipeHandleState(*aClient, &pipeMode, nullptr, nullptr)) {
  214. fail("SetNamedPipeHandleState error (%d)", GetLastError());
  215. CloseHandle(*aServer);
  216. CloseHandle(*aClient);
  217. return NS_ERROR_FAILURE;
  218. }
  219. WaitForSingleObjectEx(overlapped.hEvent, INFINITE, TRUE);
  220. return NS_OK;
  221. }
  222. int
  223. main(int32_t argc, char* argv[])
  224. {
  225. ScopedXPCOM xpcom("NamedPipeService");
  226. if (xpcom.failed()) {
  227. fail("Unable to initalize XPCOM.");
  228. return -1;
  229. }
  230. nsresult rv;
  231. nsCOMPtr<nsINamedPipeService> svc =
  232. do_GetService(NS_NAMEDPIPESERVICE_CONTRACTID, &rv);
  233. if (NS_FAILED(rv)) {
  234. fail("Unable to create named pipe service");
  235. return -1;
  236. }
  237. HANDLE readPipe, writePipe;
  238. if (NS_FAILED(rv = CreateNamedPipe(&readPipe, &writePipe))) {
  239. fail("Unable to create pipes %d", GetLastError());
  240. return -1;
  241. }
  242. RefPtr<nsNamedPipeDataObserver> readObserver =
  243. new nsNamedPipeDataObserver(readPipe);
  244. RefPtr<nsNamedPipeDataObserver> writeObserver =
  245. new nsNamedPipeDataObserver(writePipe);
  246. if (NS_WARN_IF(NS_FAILED(svc->AddDataObserver(readPipe, readObserver)))) {
  247. fail("Unable to add read data observer");
  248. return -1;
  249. }
  250. if (NS_WARN_IF(NS_FAILED(svc->AddDataObserver(writePipe, writeObserver)))) {
  251. fail("Unable to add read data observer");
  252. return -1;
  253. }
  254. if (writeObserver->Write(TEST_STR, sizeof(TEST_STR)) != sizeof(TEST_STR)) {
  255. fail("write error");
  256. return -1;
  257. }
  258. char buffer[sizeof(TEST_STR)];
  259. if (readObserver->Read(buffer, sizeof(buffer)) != sizeof(TEST_STR)) {
  260. fail("read error");
  261. return -1;
  262. }
  263. if (strcmp(buffer, TEST_STR) != 0) {
  264. fail("I/O mismatch");
  265. return -1;
  266. }
  267. if (NS_WARN_IF(NS_FAILED(svc->RemoveDataObserver(readPipe, readObserver)))) {
  268. fail("Unable to remove read data observer");
  269. return -1;
  270. }
  271. if (NS_WARN_IF(NS_FAILED(svc->RemoveDataObserver(writePipe, writeObserver)))) {
  272. fail("Unable to remove read data observer");
  273. return -1;
  274. }
  275. passed("Finish");
  276. return 0;
  277. }