зеркало из https://github.com/mozilla/gecko-dev.git
334 строки
8.0 KiB
C++
334 строки
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;
|
|
} |