summaryrefslogtreecommitdiffstats
path: root/netwerk/test/TestNamedPipeService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/TestNamedPipeService.cpp')
-rw-r--r--netwerk/test/TestNamedPipeService.cpp334
1 files changed, 334 insertions, 0 deletions
diff --git a/netwerk/test/TestNamedPipeService.cpp b/netwerk/test/TestNamedPipeService.cpp
new file mode 100644
index 000000000..7d3f2b58c
--- /dev/null
+++ b/netwerk/test/TestNamedPipeService.cpp
@@ -0,0 +1,334 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TestCommon.h"
+#include "TestHarness.h"
+
+#include <Windows.h>
+
+#include "mozilla/Atomics.h"
+#include "mozilla/Monitor.h"
+#include "nsINamedPipeService.h"
+#include "nsNetCID.h"
+
+#define PIPE_NAME "\\\\.\\pipe\\TestNPS"
+#define TEST_STR "Hello World"
+
+using namespace mozilla;
+
+class nsNamedPipeDataObserver : public nsINamedPipeDataObserver
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSINAMEDPIPEDATAOBSERVER
+
+ explicit nsNamedPipeDataObserver(HANDLE aPipe);
+
+ int Read(void* aBuffer, uint32_t aSize);
+ int Write(const void* aBuffer, uint32_t aSize);
+
+ uint32_t Transferred() const { return mBytesTransferred; }
+
+private:
+ ~nsNamedPipeDataObserver() = default;
+
+ HANDLE mPipe;
+ OVERLAPPED mOverlapped;
+ Atomic<uint32_t> mBytesTransferred;
+ Monitor mMonitor;
+};
+
+NS_IMPL_ISUPPORTS(nsNamedPipeDataObserver, nsINamedPipeDataObserver)
+
+nsNamedPipeDataObserver::nsNamedPipeDataObserver(HANDLE aPipe)
+ : mPipe(aPipe)
+ , mOverlapped()
+ , mBytesTransferred(0)
+ , mMonitor("named-pipe")
+{
+ mOverlapped.hEvent = CreateEventA(nullptr, TRUE, TRUE, "named-pipe");
+}
+
+int
+nsNamedPipeDataObserver::Read(void* aBuffer, uint32_t aSize)
+{
+ DWORD bytesRead = 0;
+ if (!ReadFile(mPipe, aBuffer, aSize, &bytesRead, &mOverlapped)) {
+ switch(GetLastError()) {
+ case ERROR_IO_PENDING:
+ {
+ MonitorAutoLock lock(mMonitor);
+ mMonitor.Wait();
+ }
+ if (!GetOverlappedResult(mPipe, &mOverlapped, &bytesRead, FALSE)) {
+ fail("GetOverlappedResult failed");
+ return -1;
+ }
+ if (mBytesTransferred != bytesRead) {
+ fail("GetOverlappedResult mismatch");
+ return -1;
+ }
+
+ break;
+ default:
+ fail("ReadFile error %d", GetLastError());
+ return -1;
+ }
+ } else {
+ MonitorAutoLock lock(mMonitor);
+ mMonitor.Wait();
+
+ if (mBytesTransferred != bytesRead) {
+ fail("GetOverlappedResult mismatch");
+ return -1;
+ }
+ }
+
+ mBytesTransferred = 0;
+ passed("[read] match");
+ return bytesRead;
+}
+
+int
+nsNamedPipeDataObserver::Write(const void* aBuffer, uint32_t aSize)
+{
+ DWORD bytesWritten = 0;
+ if (!WriteFile(mPipe, aBuffer, aSize, &bytesWritten, &mOverlapped)) {
+ switch(GetLastError()) {
+ case ERROR_IO_PENDING:
+ {
+ MonitorAutoLock lock(mMonitor);
+ mMonitor.Wait();
+ }
+ if (!GetOverlappedResult(mPipe, &mOverlapped, &bytesWritten, FALSE)) {
+ fail("GetOverlappedResult failed");
+ return -1;
+ }
+ if (mBytesTransferred != bytesWritten) {
+ fail("GetOverlappedResult mismatch");
+ return -1;
+ }
+
+ break;
+ default:
+ fail("WriteFile error %d", GetLastError());
+ return -1;
+ }
+ } else {
+ MonitorAutoLock lock(mMonitor);
+ mMonitor.Wait();
+
+ if (mBytesTransferred != bytesWritten) {
+ fail("GetOverlappedResult mismatch");
+ return -1;
+ }
+ }
+
+ mBytesTransferred = 0;
+ passed("[write] match");
+ return bytesWritten;
+}
+
+NS_IMETHODIMP
+nsNamedPipeDataObserver::OnDataAvailable(uint32_t aBytesTransferred,
+ void *aOverlapped)
+{
+ if (aOverlapped != &mOverlapped) {
+ fail("invalid overlapped object");
+ return NS_ERROR_FAILURE;
+ }
+
+ DWORD bytesTransferred = 0;
+ BOOL ret = GetOverlappedResult(mPipe,
+ reinterpret_cast<LPOVERLAPPED>(aOverlapped),
+ &bytesTransferred,
+ FALSE);
+
+ if (!ret) {
+ fail("GetOverlappedResult failed");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (bytesTransferred != aBytesTransferred) {
+ fail("GetOverlappedResult mismatch");
+ return NS_ERROR_FAILURE;
+ }
+
+ mBytesTransferred += aBytesTransferred;
+ MonitorAutoLock lock(mMonitor);
+ mMonitor.Notify();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNamedPipeDataObserver::OnError(uint32_t aError, void *aOverlapped)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+BOOL CreateAndConnectInstance(LPOVERLAPPED aOverlapped, LPHANDLE aPipe);
+BOOL ConnectToNewClient(HANDLE aPipe, LPOVERLAPPED aOverlapped);
+
+BOOL CreateAndConnectInstance(LPOVERLAPPED aOverlapped, LPHANDLE aPipe)
+{
+ if (!aPipe) {
+ fail("Parameter aPipe is NULL\n");
+ return FALSE;
+ }
+
+ // FIXME: adjust parameters
+ *aPipe = CreateNamedPipeA(
+ PIPE_NAME,
+ PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE |
+ PIPE_WAIT,
+ 1,
+ 65536,
+ 65536,
+ 3000,
+ NULL);
+
+ if (*aPipe == INVALID_HANDLE_VALUE) {
+ fail("CreateNamedPipe failed [%d]\n", GetLastError());
+ return FALSE;
+ }
+
+ return ConnectToNewClient(*aPipe, aOverlapped);
+}
+
+BOOL ConnectToNewClient(HANDLE aPipe, LPOVERLAPPED aOverlapped)
+{
+ if (ConnectNamedPipe(aPipe, aOverlapped)) {
+ fail("Unexpected, overlapped ConnectNamedPipe() always returns 0.\n");
+ return FALSE;
+ }
+
+ switch (GetLastError())
+ {
+ case ERROR_IO_PENDING:
+ return TRUE;
+
+ case ERROR_PIPE_CONNECTED:
+ if (SetEvent(aOverlapped->hEvent))
+ break;
+
+ default: // error
+ fail("ConnectNamedPipe failed [%d]\n", GetLastError());
+ break;
+ }
+
+ return FALSE;
+}
+
+static nsresult
+CreateNamedPipe(LPHANDLE aServer, LPHANDLE aClient)
+{
+ OVERLAPPED overlapped;
+ overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ BOOL ret;
+
+ ret = CreateAndConnectInstance(&overlapped, aServer);
+ if (!ret) {
+ fail("pipe server should be pending");
+ return NS_ERROR_FAILURE;
+ }
+
+ *aClient = CreateFileA(PIPE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ nullptr);
+
+ if (*aClient == INVALID_HANDLE_VALUE) {
+ fail("Unable to create pipe client");
+ CloseHandle(*aServer);
+ return NS_ERROR_FAILURE;
+ }
+
+ DWORD pipeMode = PIPE_READMODE_MESSAGE;
+ if (!SetNamedPipeHandleState(*aClient, &pipeMode, nullptr, nullptr)) {
+ fail("SetNamedPipeHandleState error (%d)", GetLastError());
+ CloseHandle(*aServer);
+ CloseHandle(*aClient);
+ return NS_ERROR_FAILURE;
+ }
+
+ WaitForSingleObjectEx(overlapped.hEvent, INFINITE, TRUE);
+
+ return NS_OK;
+}
+
+int
+main(int32_t argc, char* argv[])
+{
+ ScopedXPCOM xpcom("NamedPipeService");
+ if (xpcom.failed()) {
+ fail("Unable to initalize XPCOM.");
+ return -1;
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsINamedPipeService> svc =
+ do_GetService(NS_NAMEDPIPESERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ fail("Unable to create named pipe service");
+ return -1;
+ }
+
+ HANDLE readPipe, writePipe;
+ if (NS_FAILED(rv = CreateNamedPipe(&readPipe, &writePipe))) {
+ fail("Unable to create pipes %d", GetLastError());
+ return -1;
+ }
+
+ RefPtr<nsNamedPipeDataObserver> readObserver =
+ new nsNamedPipeDataObserver(readPipe);
+ RefPtr<nsNamedPipeDataObserver> writeObserver =
+ new nsNamedPipeDataObserver(writePipe);
+
+ if (NS_WARN_IF(NS_FAILED(svc->AddDataObserver(readPipe, readObserver)))) {
+ fail("Unable to add read data observer");
+ return -1;
+ }
+
+ if (NS_WARN_IF(NS_FAILED(svc->AddDataObserver(writePipe, writeObserver)))) {
+ fail("Unable to add read data observer");
+ return -1;
+ }
+
+ if (writeObserver->Write(TEST_STR, sizeof(TEST_STR)) != sizeof(TEST_STR)) {
+ fail("write error");
+ return -1;
+ }
+
+ char buffer[sizeof(TEST_STR)];
+ if (readObserver->Read(buffer, sizeof(buffer)) != sizeof(TEST_STR)) {
+ fail("read error");
+ return -1;
+ }
+
+ if (strcmp(buffer, TEST_STR) != 0) {
+ fail("I/O mismatch");
+ return -1;
+ }
+
+ if (NS_WARN_IF(NS_FAILED(svc->RemoveDataObserver(readPipe, readObserver)))) {
+ fail("Unable to remove read data observer");
+ return -1;
+ }
+
+ if (NS_WARN_IF(NS_FAILED(svc->RemoveDataObserver(writePipe, writeObserver)))) {
+ fail("Unable to remove read data observer");
+ return -1;
+ }
+
+ passed("Finish");
+ return 0;
+} \ No newline at end of file