Mypal/netwerk/test/TestNamedPipeService.cpp

334 lines
8.0 KiB
C++

/* -*- 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;
}