diff options
Diffstat (limited to 'netwerk/test/TestNamedPipeService.cpp')
-rw-r--r-- | netwerk/test/TestNamedPipeService.cpp | 334 |
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 |