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