mirror of
https://github.com/reactos/reactos.git
synced 2025-05-19 17:14:32 +00:00
[KMTESTS:NPFS]
- Add some (pretty incomplete) tests for NPFS Create, Connect and Read/Write operations CORE-7451 svn path=/trunk/; revision=62695
This commit is contained in:
parent
9ef6a8868b
commit
08df30bc8b
7 changed files with 1997 additions and 0 deletions
|
@ -28,6 +28,10 @@ list(APPEND KMTEST_DRV_SOURCE
|
|||
|
||||
example/Example.c
|
||||
example/KernelType.c
|
||||
npfs/NpfsConnect.c
|
||||
npfs/NpfsCreate.c
|
||||
npfs/NpfsHelpers.c
|
||||
npfs/NpfsReadWrite.c
|
||||
ntos_ex/ExCallback.c
|
||||
ntos_ex/ExDoubleList.c
|
||||
ntos_ex/ExFastMutex.c
|
||||
|
|
|
@ -38,6 +38,9 @@ KMT_TESTFUNC Test_KeProcessor;
|
|||
KMT_TESTFUNC Test_KeTimer;
|
||||
KMT_TESTFUNC Test_KernelType;
|
||||
KMT_TESTFUNC Test_MmSection;
|
||||
KMT_TESTFUNC Test_NpfsConnect;
|
||||
KMT_TESTFUNC Test_NpfsCreate;
|
||||
KMT_TESTFUNC Test_NpfsReadWrite;
|
||||
KMT_TESTFUNC Test_ObReference;
|
||||
KMT_TESTFUNC Test_ObType;
|
||||
KMT_TESTFUNC Test_ObTypeClean;
|
||||
|
@ -89,6 +92,9 @@ const KMT_TEST TestList[] =
|
|||
{ "KeTimer", Test_KeTimer },
|
||||
{ "-KernelType", Test_KernelType },
|
||||
{ "MmSection", Test_MmSection },
|
||||
{ "NpfsConnect", Test_NpfsConnect },
|
||||
{ "NpfsCreate", Test_NpfsCreate },
|
||||
{ "NpfsReadWrite", Test_NpfsReadWrite },
|
||||
{ "ObReference", Test_ObReference },
|
||||
{ "ObType", Test_ObType },
|
||||
{ "-ObTypeClean", Test_ObTypeClean },
|
||||
|
|
272
rostests/kmtests/npfs/NpfsConnect.c
Normal file
272
rostests/kmtests/npfs/NpfsConnect.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* PROJECT: ReactOS kernel-mode tests
|
||||
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
|
||||
* PURPOSE: Kernel-Mode Test Suite NPFS Connect test
|
||||
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
||||
*/
|
||||
|
||||
#include <kmt_test.h>
|
||||
#include "npfs.h"
|
||||
|
||||
#define MAX_INSTANCES 5
|
||||
#define IN_QUOTA 4096
|
||||
#define OUT_QUOTA 4096
|
||||
|
||||
#define CheckServer(ServerHandle, State) \
|
||||
NpCheckServerPipe(ServerHandle, \
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
|
||||
MAX_INSTANCES, 1, \
|
||||
IN_QUOTA, 0, \
|
||||
OUT_QUOTA, OUT_QUOTA, \
|
||||
State)
|
||||
|
||||
#define CheckClient(ClientHandle, State) \
|
||||
NpCheckClientPipe(ClientHandle, \
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
|
||||
MAX_INSTANCES, 1, \
|
||||
IN_QUOTA, 0, \
|
||||
OUT_QUOTA, OUT_QUOTA, \
|
||||
State)
|
||||
|
||||
static
|
||||
VOID
|
||||
ConnectPipe(
|
||||
IN OUT PTHREAD_CONTEXT Context)
|
||||
{
|
||||
HANDLE ClientHandle;
|
||||
|
||||
ClientHandle = NULL;
|
||||
Context->Connect.Status = NpOpenPipe(&ClientHandle,
|
||||
Context->Connect.PipePath,
|
||||
FILE_PIPE_FULL_DUPLEX);
|
||||
Context->Connect.ClientHandle = ClientHandle;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
ListenPipe(
|
||||
IN OUT PTHREAD_CONTEXT Context)
|
||||
{
|
||||
Context->Listen.Status = NpListenPipe(Context->Listen.ServerHandle);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CheckConnectPipe(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN PCWSTR PipePath,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
Context->Work = ConnectPipe;
|
||||
Context->Connect.PipePath = PipePath;
|
||||
return TriggerWork(Context, MilliSeconds);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CheckListenPipe(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN HANDLE ServerHandle,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
Context->Work = ListenPipe;
|
||||
Context->Listen.ServerHandle = ServerHandle;
|
||||
return TriggerWork(Context, MilliSeconds);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
TestConnect(
|
||||
IN HANDLE ServerHandle,
|
||||
IN PCWSTR PipePath)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
THREAD_CONTEXT ConnectContext;
|
||||
THREAD_CONTEXT ListenContext;
|
||||
BOOLEAN Okay;
|
||||
HANDLE ClientHandle;
|
||||
|
||||
StartWorkerThread(&ConnectContext);
|
||||
StartWorkerThread(&ListenContext);
|
||||
|
||||
/* Server should start out listening */
|
||||
CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
|
||||
|
||||
/* Connect a client */
|
||||
ClientHandle = NULL;
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
if (NT_SUCCESS(ConnectContext.Connect.Status))
|
||||
{
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
}
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/* Connect another client */
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
|
||||
if (NT_SUCCESS(ConnectContext.Connect.Status))
|
||||
ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/* Disconnecting the client should fail */
|
||||
Status = NpDisconnectPipe(ClientHandle);
|
||||
ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION);
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/* Listening on the client should fail */
|
||||
Status = NpListenPipe(ClientHandle);
|
||||
ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION);
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/* Close client */
|
||||
if (ClientHandle)
|
||||
ObCloseHandle(ClientHandle, KernelMode);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
|
||||
|
||||
/* Connecting a client now should fail */
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
|
||||
if (NT_SUCCESS(ConnectContext.Connect.Status))
|
||||
ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
|
||||
|
||||
/* Listening should fail */
|
||||
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
|
||||
ok_bool_true(Okay, "CheckListenPipe returned");
|
||||
if (!skip(Okay, "Listen succeeded unexpectedly\n"))
|
||||
CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
|
||||
|
||||
/* Disconnect server */
|
||||
Status = NpDisconnectPipe(ServerHandle);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
|
||||
|
||||
/* Disconnecting again should fail */
|
||||
Status = NpDisconnectPipe(ServerHandle);
|
||||
ok_eq_hex(Status, STATUS_PIPE_DISCONNECTED);
|
||||
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
|
||||
|
||||
/* Connecting a client now should fail */
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
|
||||
if (NT_SUCCESS(ConnectContext.Connect.Status))
|
||||
ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
|
||||
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
|
||||
|
||||
/**************************************************************************/
|
||||
/* Now listen again */
|
||||
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
|
||||
ok_bool_false(Okay, "CheckListenPipe returned");
|
||||
//blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
|
||||
|
||||
/* Connect client */
|
||||
ClientHandle = NULL;
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
if (NT_SUCCESS(ConnectContext.Connect.Status))
|
||||
{
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
}
|
||||
Okay = WaitForWork(&ListenContext, 100);
|
||||
ok_bool_true(Okay, "WaitForWork returned");
|
||||
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/* Listening again should fail */
|
||||
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
|
||||
ok_bool_true(Okay, "CheckListenPipe returned");
|
||||
ok_eq_hex(ListenContext.Listen.Status, STATUS_PIPE_CONNECTED);
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/* Disconnect server */
|
||||
Status = NpDisconnectPipe(ServerHandle);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
|
||||
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
|
||||
|
||||
/* Close client */
|
||||
if (ClientHandle)
|
||||
ObCloseHandle(ClientHandle, KernelMode);
|
||||
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
|
||||
|
||||
/**************************************************************************/
|
||||
/* Listen once more */
|
||||
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
|
||||
ok_bool_false(Okay, "CheckListenPipe returned");
|
||||
//blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
|
||||
|
||||
/* Connect client */
|
||||
ClientHandle = NULL;
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
if (NT_SUCCESS(ConnectContext.Connect.Status))
|
||||
{
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
}
|
||||
Okay = WaitForWork(&ListenContext, 100);
|
||||
ok_bool_true(Okay, "WaitForWork returned");
|
||||
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/* Close server */
|
||||
Status = ObCloseHandle(ServerHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
CheckClient(ClientHandle, FILE_PIPE_CLOSING_STATE);
|
||||
|
||||
/* Close client */
|
||||
if (ClientHandle)
|
||||
ObCloseHandle(ClientHandle, KernelMode);
|
||||
|
||||
FinishWorkerThread(&ListenContext);
|
||||
FinishWorkerThread(&ConnectContext);
|
||||
}
|
||||
|
||||
static KSTART_ROUTINE RunTest;
|
||||
static
|
||||
VOID
|
||||
NTAPI
|
||||
RunTest(
|
||||
IN PVOID Context)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE ServerHandle;
|
||||
|
||||
UNREFERENCED_PARAMETER(Context);
|
||||
|
||||
ServerHandle = INVALID_HANDLE_VALUE;
|
||||
Status = NpCreatePipe(&ServerHandle,
|
||||
DEVICE_NAMED_PIPE L"\\KmtestNpfsConnectTestPipe",
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MAX_INSTANCES,
|
||||
IN_QUOTA,
|
||||
OUT_QUOTA);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok(ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "ServerHandle = %p\n", ServerHandle);
|
||||
if (!skip(NT_SUCCESS(Status) && ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "No pipe\n"))
|
||||
{
|
||||
CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
|
||||
TestConnect(ServerHandle, DEVICE_NAMED_PIPE L"\\KmtestNpfsConnectTestPipe");
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(NpfsConnect)
|
||||
{
|
||||
PKTHREAD Thread;
|
||||
|
||||
Thread = KmtStartThread(RunTest, NULL);
|
||||
KmtFinishThread(Thread, NULL);
|
||||
}
|
118
rostests/kmtests/npfs/NpfsCreate.c
Normal file
118
rostests/kmtests/npfs/NpfsCreate.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* PROJECT: ReactOS kernel-mode tests
|
||||
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
|
||||
* PURPOSE: Kernel-Mode Test Suite NPFS Create test
|
||||
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
||||
*/
|
||||
|
||||
#include <kmt_test.h>
|
||||
#include "npfs.h"
|
||||
|
||||
static
|
||||
VOID
|
||||
TestCreateNamedPipe(VOID)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE ServerHandle;
|
||||
ULONG MaxInstances;
|
||||
ULONG InQuota, OutQuota;
|
||||
ULONG Quotas[] = { 0, 1, 2, 1024, PAGE_SIZE - 1, PAGE_SIZE, PAGE_SIZE + 1, 2 * PAGE_SIZE, 8 * PAGE_SIZE, 64 * PAGE_SIZE, 64 * PAGE_SIZE + 1, 128 * PAGE_SIZE };
|
||||
ULONG i;
|
||||
LARGE_INTEGER Timeout;
|
||||
|
||||
/* Invalid pipe name */
|
||||
MaxInstances = 1;
|
||||
InQuota = 4096;
|
||||
OutQuota = 4096;
|
||||
ServerHandle = INVALID_HANDLE_VALUE;
|
||||
Status = NpCreatePipe(&ServerHandle,
|
||||
DEVICE_NAMED_PIPE L"",
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MaxInstances,
|
||||
InQuota,
|
||||
OutQuota);
|
||||
ok_eq_hex(Status, STATUS_OBJECT_NAME_INVALID);
|
||||
ok_eq_pointer(ServerHandle, INVALID_HANDLE_VALUE);
|
||||
if (ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE)
|
||||
ObCloseHandle(ServerHandle, KernelMode);
|
||||
|
||||
ServerHandle = INVALID_HANDLE_VALUE;
|
||||
Status = NpCreatePipe(&ServerHandle,
|
||||
DEVICE_NAMED_PIPE L"\\",
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MaxInstances,
|
||||
InQuota,
|
||||
OutQuota);
|
||||
ok_eq_hex(Status, STATUS_OBJECT_NAME_INVALID);
|
||||
ok_eq_pointer(ServerHandle, INVALID_HANDLE_VALUE);
|
||||
if (ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE)
|
||||
ObCloseHandle(ServerHandle, KernelMode);
|
||||
|
||||
ServerHandle = INVALID_HANDLE_VALUE;
|
||||
Status = NpCreatePipe(&ServerHandle,
|
||||
DEVICE_NAMED_PIPE L"\\\\",
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MaxInstances,
|
||||
InQuota,
|
||||
OutQuota);
|
||||
ok_eq_hex(Status, STATUS_OBJECT_NAME_INVALID);
|
||||
ok_eq_pointer(ServerHandle, INVALID_HANDLE_VALUE);
|
||||
if (ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE)
|
||||
ObCloseHandle(ServerHandle, KernelMode);
|
||||
|
||||
/* Test in-quota */
|
||||
MaxInstances = 1;
|
||||
OutQuota = 4096;
|
||||
for (i = 0; i < RTL_NUMBER_OF(Quotas); i++)
|
||||
{
|
||||
InQuota = Quotas[i];
|
||||
ServerHandle = INVALID_HANDLE_VALUE;
|
||||
Status = NpCreatePipe(&ServerHandle,
|
||||
DEVICE_NAMED_PIPE L"\\KmtestNpfsCreateTestPipe",
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MaxInstances,
|
||||
InQuota,
|
||||
OutQuota);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ok(ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "ServerHandle = %p\n", ServerHandle);
|
||||
if (!skip(NT_SUCCESS(Status) && ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "No pipe\n"))
|
||||
{
|
||||
NpCheckServerPipe(ServerHandle,
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MaxInstances, 1,
|
||||
InQuota, 0,
|
||||
OutQuota, OutQuota,
|
||||
FILE_PIPE_LISTENING_STATE);
|
||||
ObCloseHandle(ServerHandle, KernelMode);
|
||||
Timeout.QuadPart = -100 * 1000 * 10;
|
||||
Status = KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
TestCreate(VOID)
|
||||
{
|
||||
}
|
||||
|
||||
static KSTART_ROUTINE RunTest;
|
||||
static
|
||||
VOID
|
||||
NTAPI
|
||||
RunTest(
|
||||
IN PVOID Context)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Context);
|
||||
TestCreateNamedPipe();
|
||||
TestCreate();
|
||||
}
|
||||
|
||||
START_TEST(NpfsCreate)
|
||||
{
|
||||
PKTHREAD Thread;
|
||||
|
||||
Thread = KmtStartThread(RunTest, NULL);
|
||||
KmtFinishThread(Thread, NULL);
|
||||
}
|
774
rostests/kmtests/npfs/NpfsHelpers.c
Normal file
774
rostests/kmtests/npfs/NpfsHelpers.c
Normal file
|
@ -0,0 +1,774 @@
|
|||
/*
|
||||
* PROJECT: ReactOS kernel-mode tests
|
||||
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
|
||||
* PURPOSE: Kernel-Mode Test Suite Helper functions for NPFS tests
|
||||
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
||||
*/
|
||||
|
||||
#include <kmt_test.h>
|
||||
#include "npfs.h"
|
||||
|
||||
NTSTATUS
|
||||
NpCreatePipeEx(
|
||||
OUT PHANDLE ServerHandle,
|
||||
IN PCWSTR PipePath,
|
||||
IN ULONG ReadMode,
|
||||
IN ULONG CompletionMode,
|
||||
IN ULONG NamedPipeType,
|
||||
IN ULONG ShareAccess,
|
||||
IN ULONG MaximumInstances,
|
||||
IN ULONG InboundQuota,
|
||||
IN ULONG OutboundQuota,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN ULONG Disposition,
|
||||
IN ULONG CreateOptions,
|
||||
IN PLARGE_INTEGER DefaultTimeout OPTIONAL)
|
||||
{
|
||||
UNICODE_STRING ObjectName;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
NAMED_PIPE_CREATE_PARAMETERS Params;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
NTSTATUS Status;
|
||||
|
||||
RtlInitUnicodeString(&ObjectName, PipePath);
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&ObjectName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Params.NamedPipeType = NamedPipeType;
|
||||
Params.ReadMode = ReadMode;
|
||||
Params.CompletionMode = CompletionMode;
|
||||
Params.MaximumInstances = MaximumInstances;
|
||||
Params.InboundQuota = InboundQuota;
|
||||
Params.OutboundQuota = OutboundQuota;
|
||||
if (DefaultTimeout)
|
||||
{
|
||||
Params.DefaultTimeout.QuadPart = DefaultTimeout->QuadPart;
|
||||
Params.TimeoutSpecified = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Params.DefaultTimeout.QuadPart = 0;
|
||||
Params.TimeoutSpecified = FALSE;
|
||||
}
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
Status = IoCreateFile(ServerHandle,
|
||||
DesiredAccess,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL, /* AllocationSize */
|
||||
0, /* FileAttributes */
|
||||
ShareAccess,
|
||||
Disposition,
|
||||
CreateOptions,
|
||||
NULL, /* EaBuffer */
|
||||
0, /* EaLength */
|
||||
CreateFileTypeNamedPipe,
|
||||
&Params,
|
||||
0);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, Status);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, FILE_CREATED);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NpCreatePipe(
|
||||
OUT PHANDLE ServerHandle,
|
||||
PCWSTR PipePath,
|
||||
ULONG ReadMode,
|
||||
ULONG CompletionMode,
|
||||
ULONG NamedPipeType,
|
||||
ULONG NamedPipeConfiguration,
|
||||
ULONG MaximumInstances,
|
||||
ULONG InboundQuota,
|
||||
ULONG OutboundQuota)
|
||||
{
|
||||
ULONG ShareAccess;
|
||||
LARGE_INTEGER DefaultTimeout;
|
||||
|
||||
if (NamedPipeConfiguration == FILE_PIPE_INBOUND)
|
||||
ShareAccess = FILE_SHARE_WRITE;
|
||||
else if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND)
|
||||
ShareAccess = FILE_SHARE_READ;
|
||||
else if (NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX)
|
||||
ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
|
||||
DefaultTimeout.QuadPart = -50 * 1000 * 10;
|
||||
|
||||
return NpCreatePipeEx(ServerHandle,
|
||||
PipePath,
|
||||
ReadMode,
|
||||
CompletionMode,
|
||||
NamedPipeType,
|
||||
ShareAccess,
|
||||
MaximumInstances,
|
||||
InboundQuota,
|
||||
OutboundQuota,
|
||||
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_OPEN_IF,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
&DefaultTimeout);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NpOpenPipeEx(
|
||||
OUT PHANDLE ClientHandle,
|
||||
IN PCWSTR PipePath,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN ULONG ShareAccess,
|
||||
IN ULONG Disposition,
|
||||
IN ULONG CreateOptions)
|
||||
{
|
||||
UNICODE_STRING ObjectName;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
RtlInitUnicodeString(&ObjectName, PipePath);
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&ObjectName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
Status = IoCreateFile(ClientHandle,
|
||||
DesiredAccess,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL, /* AllocationSize */
|
||||
0, /* FileAttributes */
|
||||
ShareAccess,
|
||||
Disposition,
|
||||
CreateOptions,
|
||||
NULL, /* EaBuffer */
|
||||
0, /* EaLength */
|
||||
CreateFileTypeNone,
|
||||
NULL,
|
||||
0);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ok(Status != STATUS_PENDING, "IoCreateFile returned pending\n");
|
||||
ok_eq_hex(IoStatusBlock.Status, Status);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, FILE_OPENED);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NpOpenPipe(
|
||||
OUT PHANDLE ClientHandle,
|
||||
IN PCWSTR PipePath,
|
||||
IN ULONG NamedPipeConfiguration)
|
||||
{
|
||||
ULONG ShareAccess;
|
||||
|
||||
if (NamedPipeConfiguration == FILE_PIPE_INBOUND)
|
||||
ShareAccess = FILE_SHARE_WRITE;
|
||||
else if (NamedPipeConfiguration == FILE_PIPE_OUTBOUND)
|
||||
ShareAccess = FILE_SHARE_READ;
|
||||
else if (NamedPipeConfiguration == FILE_PIPE_FULL_DUPLEX)
|
||||
ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
|
||||
return NpOpenPipeEx(ClientHandle,
|
||||
PipePath,
|
||||
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
|
||||
ShareAccess,
|
||||
FILE_OPEN,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NpControlPipe(
|
||||
IN HANDLE ServerHandle,
|
||||
IN ULONG FsControlCode,
|
||||
IN PVOID InputBuffer,
|
||||
IN ULONG InputBufferLength)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
Status = ZwFsControlFile(ServerHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
FsControlCode,
|
||||
InputBuffer,
|
||||
InputBufferLength,
|
||||
NULL,
|
||||
0);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
Status = ZwWaitForSingleObject(ServerHandle,
|
||||
FALSE,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, Status);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NpWaitPipe(
|
||||
IN PCWSTR PipeName,
|
||||
IN PLARGE_INTEGER Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HANDLE RootHandle;
|
||||
UNICODE_STRING RootDirectoryName = RTL_CONSTANT_STRING(DEVICE_NAMED_PIPE);
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
PFILE_PIPE_WAIT_FOR_BUFFER WaitForBuffer;
|
||||
ULONG NameLength;
|
||||
ULONG BufferSize;
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&RootDirectoryName,
|
||||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
Status = IoCreateFile(&RootHandle,
|
||||
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_OPEN,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
NULL,
|
||||
0,
|
||||
CreateFileTypeNone,
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
|
||||
return Status;
|
||||
}
|
||||
ok(Status != STATUS_PENDING, "IoCreateFile returned pending\n");
|
||||
ok_eq_hex(IoStatusBlock.Status, Status);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, FILE_OPENED);
|
||||
|
||||
NameLength = wcslen(PipeName) * sizeof(WCHAR);
|
||||
BufferSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER,
|
||||
Name[NameLength / sizeof(WCHAR)]);
|
||||
WaitForBuffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, 'WPmK');
|
||||
if (WaitForBuffer == NULL)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
if (Timeout)
|
||||
{
|
||||
WaitForBuffer->Timeout.QuadPart = Timeout->QuadPart;
|
||||
WaitForBuffer->TimeoutSpecified = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitForBuffer->Timeout.QuadPart = 0;
|
||||
WaitForBuffer->TimeoutSpecified = FALSE;
|
||||
}
|
||||
WaitForBuffer->NameLength = NameLength;
|
||||
RtlCopyMemory(WaitForBuffer->Name, PipeName, NameLength);
|
||||
Status = NpControlPipe(RootHandle,
|
||||
FSCTL_PIPE_WAIT,
|
||||
WaitForBuffer,
|
||||
BufferSize);
|
||||
ExFreePoolWithTag(WaitForBuffer, 'WPmK');
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NpReadPipe(
|
||||
IN HANDLE PipeHandle,
|
||||
OUT PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PULONG_PTR BytesRead)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
BOOLEAN PendingReturned = FALSE;
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
Status = ZwReadFile(PipeHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
Buffer,
|
||||
BufferSize,
|
||||
NULL,
|
||||
NULL);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
Status = ZwWaitForSingleObject(PipeHandle,
|
||||
FALSE,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Status = IoStatusBlock.Status;
|
||||
PendingReturned = TRUE;
|
||||
}
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, Status);
|
||||
*BytesRead = IoStatusBlock.Information;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PendingReturned)
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, Status);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
|
||||
}
|
||||
*BytesRead = 0;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NpWritePipe(
|
||||
IN HANDLE PipeHandle,
|
||||
IN const VOID *Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PULONG_PTR BytesWritten)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
Status = ZwWriteFile(PipeHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&IoStatusBlock,
|
||||
(PVOID)Buffer,
|
||||
BufferSize,
|
||||
NULL,
|
||||
NULL);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
Status = ZwWaitForSingleObject(PipeHandle,
|
||||
FALSE,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, Status);
|
||||
*BytesWritten = IoStatusBlock.Information;
|
||||
}
|
||||
else
|
||||
{
|
||||
ok_eq_hex(IoStatusBlock.Status, 0x55555555UL);
|
||||
ok_eq_ulongptr(IoStatusBlock.Information, 0x5555555555555555ULL);
|
||||
*BytesWritten = 0;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CheckBuffer(
|
||||
PVOID Buffer,
|
||||
SIZE_T Size,
|
||||
UCHAR Value)
|
||||
{
|
||||
PUCHAR Array = Buffer;
|
||||
SIZE_T i;
|
||||
|
||||
for (i = 0; i < Size; i++)
|
||||
if (Array[i] != Value)
|
||||
{
|
||||
trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define ok_eq_print_(value, expected, spec, FileAndLine) \
|
||||
KmtOk((value) == (expected), FileAndLine, #value " = " spec ", expected " spec "\n", value, expected)
|
||||
#define ok_eq_ulong_(value, expected) ok_eq_print_(value, expected, "%lu", FileAndLine)
|
||||
#define ok_eq_ulonglong_(value, expected) ok_eq_print_(value, expected, "%I64u", FileAndLine)
|
||||
#ifndef _WIN64
|
||||
#define ok_eq_ulongptr_(value, expected) ok_eq_print_(value, (ULONG_PTR)(expected), "%lu", FileAndLine)
|
||||
#elif defined _WIN64
|
||||
#define ok_eq_ulongptr_(value, expected) ok_eq_print_(value, (ULONG_PTR)(expected), "%I64u", FileAndLine)
|
||||
#endif
|
||||
#define ok_eq_hex_(value, expected) ok_eq_print_(value, expected, "0x%08lx", FileAndLine)
|
||||
|
||||
VOID
|
||||
NpCheckServerPipe_(
|
||||
IN HANDLE ServerHandle,
|
||||
/* PipeInformation */
|
||||
IN ULONG ReadMode,
|
||||
IN ULONG CompletionMode,
|
||||
/* PipeLocalInformation */
|
||||
IN ULONG NamedPipeType,
|
||||
IN ULONG NamedPipeConfiguration,
|
||||
IN ULONG MaximumInstances,
|
||||
IN ULONG CurrentInstances,
|
||||
IN ULONG InboundQuota,
|
||||
IN ULONG ReadDataAvailable,
|
||||
IN ULONG OutboundQuota,
|
||||
IN ULONG WriteQuotaAvailable,
|
||||
IN ULONG NamedPipeState,
|
||||
/* PipeRemoteInformation */
|
||||
/* */
|
||||
IN PCSTR FileAndLine)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
FILE_PIPE_INFORMATION PipeInfo;
|
||||
FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
|
||||
FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(ServerHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeInfo,
|
||||
sizeof(PipeInfo),
|
||||
FilePipeInformation);
|
||||
ok_eq_hex_(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
|
||||
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeInfo));
|
||||
ok_eq_ulong_(PipeInfo.ReadMode, ReadMode);
|
||||
ok_eq_ulong_(PipeInfo.CompletionMode, CompletionMode);
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(ServerHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeLocalInfo,
|
||||
sizeof(PipeLocalInfo),
|
||||
FilePipeLocalInformation);
|
||||
ok_eq_hex_(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
|
||||
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeLocalInfo));
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeType, NamedPipeType);
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeConfiguration, NamedPipeConfiguration);
|
||||
ok_eq_ulong_(PipeLocalInfo.MaximumInstances, MaximumInstances);
|
||||
ok_eq_ulong_(PipeLocalInfo.CurrentInstances, CurrentInstances);
|
||||
ok_eq_ulong_(PipeLocalInfo.InboundQuota, InboundQuota);
|
||||
ok_eq_ulong_(PipeLocalInfo.ReadDataAvailable, ReadDataAvailable);
|
||||
ok_eq_ulong_(PipeLocalInfo.OutboundQuota, OutboundQuota);
|
||||
ok_eq_ulong_(PipeLocalInfo.WriteQuotaAvailable, WriteQuotaAvailable);
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeState, NamedPipeState);
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeEnd, (ULONG)FILE_PIPE_SERVER_END);
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(ServerHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeRemoteInfo,
|
||||
sizeof(PipeRemoteInfo),
|
||||
FilePipeInformation);
|
||||
ok_eq_hex_(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
|
||||
ok_eq_ulongptr_(IoStatusBlock.Information, RTL_SIZEOF_THROUGH_FIELD(FILE_PIPE_REMOTE_INFORMATION, CollectDataTime));
|
||||
ok_eq_ulonglong_(PipeRemoteInfo.CollectDataTime.QuadPart, 0ULL);
|
||||
ok_eq_ulong_(PipeRemoteInfo.MaximumCollectionCount, 0x55555555UL);
|
||||
}
|
||||
|
||||
VOID
|
||||
NpCheckClientPipe_(
|
||||
IN HANDLE ClientHandle,
|
||||
/* PipeInformation */
|
||||
IN ULONG ReadMode,
|
||||
IN ULONG CompletionMode,
|
||||
/* PipeLocalInformation */
|
||||
IN ULONG NamedPipeType,
|
||||
IN ULONG NamedPipeConfiguration,
|
||||
IN ULONG MaximumInstances,
|
||||
IN ULONG CurrentInstances,
|
||||
IN ULONG InboundQuota,
|
||||
IN ULONG ReadDataAvailable,
|
||||
IN ULONG OutboundQuota,
|
||||
IN ULONG WriteQuotaAvailable,
|
||||
IN ULONG NamedPipeState,
|
||||
/* PipeRemoteInformation */
|
||||
/* */
|
||||
IN PCSTR FileAndLine)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
FILE_PIPE_INFORMATION PipeInfo;
|
||||
FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
|
||||
FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(ClientHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeInfo,
|
||||
sizeof(PipeInfo),
|
||||
FilePipeInformation);
|
||||
ok_eq_hex_(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
|
||||
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeInfo));
|
||||
ok_eq_ulong_(PipeInfo.ReadMode, ReadMode);
|
||||
ok_eq_ulong_(PipeInfo.CompletionMode, CompletionMode);
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(ClientHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeLocalInfo,
|
||||
sizeof(PipeLocalInfo),
|
||||
FilePipeLocalInformation);
|
||||
ok_eq_hex_(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
|
||||
ok_eq_ulongptr_(IoStatusBlock.Information, sizeof(PipeLocalInfo));
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeType, NamedPipeType);
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeConfiguration, NamedPipeConfiguration);
|
||||
ok_eq_ulong_(PipeLocalInfo.MaximumInstances, MaximumInstances);
|
||||
ok_eq_ulong_(PipeLocalInfo.CurrentInstances, CurrentInstances);
|
||||
ok_eq_ulong_(PipeLocalInfo.InboundQuota, InboundQuota);
|
||||
ok_eq_ulong_(PipeLocalInfo.ReadDataAvailable, ReadDataAvailable);
|
||||
ok_eq_ulong_(PipeLocalInfo.OutboundQuota, OutboundQuota);
|
||||
ok_eq_ulong_(PipeLocalInfo.WriteQuotaAvailable, WriteQuotaAvailable);
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeState, NamedPipeState);
|
||||
ok_eq_ulong_(PipeLocalInfo.NamedPipeEnd, (ULONG)FILE_PIPE_CLIENT_END);
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(ClientHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeRemoteInfo,
|
||||
sizeof(PipeRemoteInfo),
|
||||
FilePipeInformation);
|
||||
ok_eq_hex_(Status, STATUS_SUCCESS);
|
||||
ok_eq_hex_(IoStatusBlock.Status, STATUS_SUCCESS);
|
||||
ok_eq_ulongptr_(IoStatusBlock.Information, RTL_SIZEOF_THROUGH_FIELD(FILE_PIPE_REMOTE_INFORMATION, CollectDataTime));
|
||||
ok_eq_ulonglong_(PipeRemoteInfo.CollectDataTime.QuadPart, 0ULL);
|
||||
ok_eq_ulong_(PipeRemoteInfo.MaximumCollectionCount, 0x55555555UL);
|
||||
}
|
||||
|
||||
VOID
|
||||
NpQueryPipe_(
|
||||
IN HANDLE PipeHandle,
|
||||
IN NTSTATUS ExpectedStatus,
|
||||
IN PCSTR FileAndLine)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
FILE_PIPE_INFORMATION PipeInfo;
|
||||
FILE_PIPE_LOCAL_INFORMATION PipeLocalInfo;
|
||||
FILE_PIPE_REMOTE_INFORMATION PipeRemoteInfo;
|
||||
|
||||
ASSERT(!NT_SUCCESS(ExpectedStatus));
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeInfo, sizeof(PipeInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(PipeHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeInfo,
|
||||
sizeof(PipeInfo),
|
||||
FilePipeInformation);
|
||||
ok_eq_hex_(Status, ExpectedStatus);
|
||||
ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
|
||||
ok_bool_true(CheckBuffer(&PipeInfo, sizeof(PipeInfo), 0x55), "CheckBuffer returned");
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(PipeHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeLocalInfo,
|
||||
sizeof(PipeLocalInfo),
|
||||
FilePipeLocalInformation);
|
||||
ok_eq_hex_(Status, ExpectedStatus);
|
||||
ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
|
||||
ok_bool_true(CheckBuffer(&PipeLocalInfo, sizeof(PipeLocalInfo), 0x55), "CheckBuffer returned");
|
||||
|
||||
RtlFillMemory(&IoStatusBlock, sizeof(IoStatusBlock), 0x55);
|
||||
RtlFillMemory(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55);
|
||||
Status = ZwQueryInformationFile(PipeHandle,
|
||||
&IoStatusBlock,
|
||||
&PipeRemoteInfo,
|
||||
sizeof(PipeRemoteInfo),
|
||||
FilePipeInformation);
|
||||
ok_eq_hex_(Status, ExpectedStatus);
|
||||
ok_bool_true(CheckBuffer(&IoStatusBlock, sizeof(IoStatusBlock), 0x55), "CheckBuffer returned");
|
||||
ok_bool_true(CheckBuffer(&PipeRemoteInfo, sizeof(PipeRemoteInfo), 0x55), "CheckBuffer returned");
|
||||
}
|
||||
|
||||
static KSTART_ROUTINE PipeWorkerThread;
|
||||
static
|
||||
VOID
|
||||
NTAPI
|
||||
PipeWorkerThread(
|
||||
IN PVOID ThreadContext)
|
||||
{
|
||||
PTHREAD_CONTEXT Context = ThreadContext;
|
||||
PVOID WaitEvents[2] = { &Context->ThreadDoneEvent,
|
||||
&Context->StartWorkEvent };
|
||||
NTSTATUS Status;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
Status = KeWaitForMultipleObjects(RTL_NUMBER_OF(WaitEvents),
|
||||
WaitEvents,
|
||||
WaitAny,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL,
|
||||
NULL);
|
||||
if (Status == STATUS_WAIT_0)
|
||||
break;
|
||||
ASSERT(Status == STATUS_WAIT_1);
|
||||
|
||||
Context->Work(Context);
|
||||
|
||||
KeSetEvent(&Context->WorkCompleteEvent, IO_NO_INCREMENT, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
StartWorkerThread(
|
||||
OUT PTHREAD_CONTEXT Context)
|
||||
{
|
||||
KeInitializeEvent(&Context->ThreadDoneEvent, NotificationEvent, FALSE);
|
||||
KeInitializeEvent(&Context->StartWorkEvent, SynchronizationEvent, FALSE);
|
||||
KeInitializeEvent(&Context->WorkCompleteEvent, NotificationEvent, TRUE);
|
||||
|
||||
Context->Thread = KmtStartThread(PipeWorkerThread, Context);
|
||||
}
|
||||
|
||||
VOID
|
||||
FinishWorkerThread(
|
||||
IN PTHREAD_CONTEXT Context)
|
||||
{
|
||||
KmtFinishThread(Context->Thread, &Context->ThreadDoneEvent);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
WaitForWork(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
LARGE_INTEGER Timeout;
|
||||
NTSTATUS Status;
|
||||
|
||||
Timeout.QuadPart = -10 * 1000 * (LONGLONG)MilliSeconds;
|
||||
Status = KeWaitForSingleObject(&Context->WorkCompleteEvent,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
&Timeout);
|
||||
ok(Status == STATUS_SUCCESS || Status == STATUS_TIMEOUT, "Wait status %lx\n", Status);
|
||||
return Status != STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
TriggerWork(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = KeWaitForSingleObject(&Context->WorkCompleteEvent,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
KeResetEvent(&Context->WorkCompleteEvent);
|
||||
KeSetEvent(&Context->StartWorkEvent, IO_NO_INCREMENT, TRUE);
|
||||
return WaitForWork(Context, MilliSeconds);
|
||||
}
|
||||
|
||||
PKTHREAD
|
||||
KmtStartThread(
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext OPTIONAL)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
HANDLE ThreadHandle;
|
||||
PVOID ThreadObject = NULL;
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
NULL,
|
||||
OBJ_KERNEL_HANDLE,
|
||||
NULL,
|
||||
NULL);
|
||||
ThreadHandle = INVALID_HANDLE_VALUE;
|
||||
Status = PsCreateSystemThread(&ThreadHandle,
|
||||
SYNCHRONIZE,
|
||||
&ObjectAttributes,
|
||||
NULL,
|
||||
NULL,
|
||||
StartRoutine,
|
||||
StartContext);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
if (!skip(NT_SUCCESS(Status) && ThreadHandle != NULL && ThreadHandle != INVALID_HANDLE_VALUE, "No thread\n"))
|
||||
{
|
||||
Status = ObReferenceObjectByHandle(ThreadHandle,
|
||||
SYNCHRONIZE,
|
||||
PsThreadType,
|
||||
KernelMode,
|
||||
&ThreadObject,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ObCloseHandle(ThreadHandle, KernelMode);
|
||||
}
|
||||
return ThreadObject;
|
||||
}
|
||||
|
||||
VOID
|
||||
KmtFinishThread(
|
||||
IN PKTHREAD Thread OPTIONAL,
|
||||
IN PKEVENT Event OPTIONAL)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
if (skip(Thread != NULL, "No thread\n"))
|
||||
return;
|
||||
|
||||
if (Event)
|
||||
KeSetEvent(Event, IO_NO_INCREMENT, TRUE);
|
||||
Status = KeWaitForSingleObject(Thread,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
ObDereferenceObject(Thread);
|
||||
}
|
598
rostests/kmtests/npfs/NpfsReadWrite.c
Normal file
598
rostests/kmtests/npfs/NpfsReadWrite.c
Normal file
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* PROJECT: ReactOS kernel-mode tests
|
||||
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
|
||||
* PURPOSE: Kernel-Mode Test Suite NPFS Read/Write test
|
||||
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
||||
*/
|
||||
|
||||
#include <kmt_test.h>
|
||||
#include "npfs.h"
|
||||
|
||||
typedef struct _READ_WRITE_TEST_CONTEXT
|
||||
{
|
||||
PCWSTR PipePath;
|
||||
BOOLEAN ServerSynchronous;
|
||||
BOOLEAN ClientSynchronous;
|
||||
} READ_WRITE_TEST_CONTEXT, *PREAD_WRITE_TEST_CONTEXT;
|
||||
|
||||
#define MAX_INSTANCES 5
|
||||
#define IN_QUOTA 4096
|
||||
#define OUT_QUOTA 4096
|
||||
|
||||
#define MakeServer(ServerHandle, PipePath, ServerSynchronous) \
|
||||
NpCreatePipeEx(ServerHandle, \
|
||||
PipePath, \
|
||||
BYTE_STREAM, \
|
||||
QUEUE, \
|
||||
BYTE_STREAM, \
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, \
|
||||
MAX_INSTANCES, \
|
||||
IN_QUOTA, \
|
||||
OUT_QUOTA, \
|
||||
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE, \
|
||||
FILE_OPEN_IF, \
|
||||
(ServerSynchronous) ? FILE_SYNCHRONOUS_IO_NONALERT \
|
||||
: 0, \
|
||||
&DefaultTimeout)
|
||||
|
||||
#define CheckServer(ServerHandle, State) \
|
||||
NpCheckServerPipe(ServerHandle, \
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
|
||||
MAX_INSTANCES, 1, \
|
||||
IN_QUOTA, 0, \
|
||||
OUT_QUOTA, OUT_QUOTA, \
|
||||
State)
|
||||
|
||||
#define CheckClient(ClientHandle, State) \
|
||||
NpCheckClientPipe(ClientHandle, \
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
|
||||
MAX_INSTANCES, 1, \
|
||||
IN_QUOTA, 0, \
|
||||
OUT_QUOTA, OUT_QUOTA, \
|
||||
State)
|
||||
|
||||
#define CheckServerQuota(ServerHandle, InQ, OutQ) \
|
||||
NpCheckServerPipe(ServerHandle, \
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
|
||||
MAX_INSTANCES, 1, \
|
||||
IN_QUOTA, InQ, \
|
||||
OUT_QUOTA, OUT_QUOTA - (OutQ), \
|
||||
FILE_PIPE_CONNECTED_STATE)
|
||||
|
||||
#define CheckClientQuota(ClientHandle, InQ, OutQ) \
|
||||
NpCheckClientPipe(ClientHandle, \
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX, \
|
||||
MAX_INSTANCES, 1, \
|
||||
IN_QUOTA, InQ, \
|
||||
OUT_QUOTA, OUT_QUOTA - (OutQ), \
|
||||
FILE_PIPE_CONNECTED_STATE)
|
||||
|
||||
#define CheckPipeContext(Context, ExpectedStatus, ExpectedBytes) do \
|
||||
{ \
|
||||
ok_bool_true(Okay, "CheckPipeContext"); \
|
||||
ok_eq_hex((Context)->ReadWrite.Status, ExpectedStatus); \
|
||||
ok_eq_ulongptr((Context)->ReadWrite.BytesTransferred, ExpectedBytes); \
|
||||
} while (0)
|
||||
|
||||
static
|
||||
VOID
|
||||
ConnectPipe(
|
||||
IN OUT PTHREAD_CONTEXT Context)
|
||||
{
|
||||
HANDLE ClientHandle;
|
||||
|
||||
ClientHandle = NULL;
|
||||
Context->Connect.Status = NpOpenPipeEx(&ClientHandle,
|
||||
Context->Connect.PipePath,
|
||||
SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_OPEN,
|
||||
Context->Connect.ClientSynchronous ? FILE_SYNCHRONOUS_IO_NONALERT
|
||||
: 0);
|
||||
Context->Connect.ClientHandle = ClientHandle;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
ListenPipe(
|
||||
IN OUT PTHREAD_CONTEXT Context)
|
||||
{
|
||||
Context->Listen.Status = NpListenPipe(Context->Listen.ServerHandle);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
ReadPipe(
|
||||
IN OUT PTHREAD_CONTEXT Context)
|
||||
{
|
||||
Context->ReadWrite.Status = NpReadPipe(Context->ReadWrite.PipeHandle,
|
||||
Context->ReadWrite.Buffer,
|
||||
Context->ReadWrite.BufferSize,
|
||||
(PULONG_PTR)&Context->ReadWrite.BytesTransferred);
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
WritePipe(
|
||||
IN OUT PTHREAD_CONTEXT Context)
|
||||
{
|
||||
Context->ReadWrite.Status = NpWritePipe(Context->ReadWrite.PipeHandle,
|
||||
Context->ReadWrite.Buffer,
|
||||
Context->ReadWrite.BufferSize,
|
||||
(PULONG_PTR)&Context->ReadWrite.BytesTransferred);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CheckConnectPipe(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN PCWSTR PipePath,
|
||||
IN BOOLEAN ClientSynchronous,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
Context->Work = ConnectPipe;
|
||||
Context->Connect.PipePath = PipePath;
|
||||
Context->Connect.ClientSynchronous = ClientSynchronous;
|
||||
return TriggerWork(Context, MilliSeconds);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CheckListenPipe(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN HANDLE ServerHandle,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
Context->Work = ListenPipe;
|
||||
Context->Listen.ServerHandle = ServerHandle;
|
||||
return TriggerWork(Context, MilliSeconds);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CheckReadPipe(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN HANDLE PipeHandle,
|
||||
OUT PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
Context->Work = ReadPipe;
|
||||
Context->ReadWrite.PipeHandle = PipeHandle;
|
||||
Context->ReadWrite.Buffer = Buffer;
|
||||
Context->ReadWrite.BufferSize = BufferSize;
|
||||
return TriggerWork(Context, MilliSeconds);
|
||||
}
|
||||
|
||||
static
|
||||
BOOLEAN
|
||||
CheckWritePipe(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN HANDLE PipeHandle,
|
||||
IN const VOID *Buffer,
|
||||
IN ULONG BufferSize,
|
||||
IN ULONG MilliSeconds)
|
||||
{
|
||||
Context->Work = WritePipe;
|
||||
Context->ReadWrite.PipeHandle = PipeHandle;
|
||||
Context->ReadWrite.Buffer = (PVOID)Buffer;
|
||||
Context->ReadWrite.BufferSize = BufferSize;
|
||||
return TriggerWork(Context, MilliSeconds);
|
||||
}
|
||||
|
||||
static KSTART_ROUTINE TestReadWrite;
|
||||
static
|
||||
VOID
|
||||
NTAPI
|
||||
TestReadWrite(
|
||||
IN PVOID Context)
|
||||
{
|
||||
PREAD_WRITE_TEST_CONTEXT TestContext = Context;
|
||||
PCWSTR PipePath = TestContext->PipePath;
|
||||
BOOLEAN ServerSynchronous = TestContext->ServerSynchronous;
|
||||
BOOLEAN ClientSynchronous = TestContext->ClientSynchronous;
|
||||
NTSTATUS Status;
|
||||
HANDLE ServerHandle;
|
||||
LARGE_INTEGER DefaultTimeout;
|
||||
THREAD_CONTEXT ConnectContext;
|
||||
THREAD_CONTEXT ListenContext;
|
||||
THREAD_CONTEXT ClientReadContext;
|
||||
THREAD_CONTEXT ClientWriteContext;
|
||||
THREAD_CONTEXT ServerReadContext;
|
||||
THREAD_CONTEXT ServerWriteContext;
|
||||
BOOLEAN Okay;
|
||||
HANDLE ClientHandle;
|
||||
UCHAR ReadBuffer[128];
|
||||
UCHAR WriteBuffer[128];
|
||||
|
||||
StartWorkerThread(&ConnectContext);
|
||||
StartWorkerThread(&ListenContext);
|
||||
StartWorkerThread(&ClientReadContext);
|
||||
StartWorkerThread(&ClientWriteContext);
|
||||
StartWorkerThread(&ServerReadContext);
|
||||
StartWorkerThread(&ServerWriteContext);
|
||||
|
||||
DefaultTimeout.QuadPart = -50 * 1000 * 10;
|
||||
|
||||
/* Server should start out listening */
|
||||
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
|
||||
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, NULL, 0, 100);
|
||||
ok_bool_true(Okay, "CheckWritePipe returned");
|
||||
ok_eq_ulongptr(ServerWriteContext.ReadWrite.BytesTransferred, 0);
|
||||
ok_eq_hex(ServerWriteContext.ReadWrite.Status, STATUS_PIPE_LISTENING);
|
||||
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, NULL, 0, 100);
|
||||
ok_bool_true(Okay, "CheckReadPipe returned");
|
||||
ok_eq_ulongptr(ServerReadContext.ReadWrite.BytesTransferred, 0);
|
||||
ok_eq_hex(ServerReadContext.ReadWrite.Status, STATUS_PIPE_LISTENING);
|
||||
|
||||
/* Connect a client */
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/** Server to client, write first, 1 byte */
|
||||
WriteBuffer[0] = 'A';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
|
||||
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'A');
|
||||
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
|
||||
|
||||
/** Server to client, read first, 1 byte */
|
||||
WriteBuffer[0] = 'B';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
ok_bool_false(Okay, "CheckReadPipe returned");
|
||||
CheckServerQuota(ServerHandle, 0, 1);
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
|
||||
Okay = WaitForWork(&ClientReadContext, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'B');
|
||||
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
|
||||
|
||||
/** Client to server, write first, 1 byte */
|
||||
WriteBuffer[0] = 'C';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
|
||||
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'C');
|
||||
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
|
||||
|
||||
/** Client to server, read first, 1 byte */
|
||||
WriteBuffer[0] = 'D';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
ok_bool_false(Okay, "CheckReadPipe returned");
|
||||
CheckClientQuota(ClientHandle, 0, 1);
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
|
||||
Okay = WaitForWork(&ServerReadContext, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'D');
|
||||
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
|
||||
|
||||
/** Server to client, write 0 bytes */
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, (PVOID)1, 0, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 0);
|
||||
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
|
||||
|
||||
/** Client to Server, write 0 bytes */
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, (PVOID)1, 0, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 0);
|
||||
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
|
||||
|
||||
/** Server to client, read 0 bytes blocks, write 0 bytes does not unblock, write 1 byte unblocks */
|
||||
WriteBuffer[0] = 'E';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, (PVOID)1, 0, 100);
|
||||
ok_bool_false(Okay, "CheckReadPipe returned");
|
||||
CheckServerQuota(ServerHandle, 0, 0);
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, (PVOID)1, 0, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 0);
|
||||
Okay = WaitForWork(&ClientReadContext, 100);
|
||||
ok_bool_false(Okay, "WaitForWork returned");
|
||||
CheckServerQuota(ServerHandle, 0, 0);
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
|
||||
Okay = WaitForWork(&ClientReadContext, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 0);
|
||||
ok_eq_uint(ReadBuffer[0], 'X');
|
||||
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'E');
|
||||
CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
|
||||
|
||||
/** Client to server, read 0 bytes blocks, write 0 bytes does not unblock, write 1 byte unblocks */
|
||||
WriteBuffer[0] = 'F';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, (PVOID)1, 0, 100);
|
||||
ok_bool_false(Okay, "CheckReadPipe returned");
|
||||
CheckClientQuota(ClientHandle, 0, 0);
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, (PVOID)1, 0, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 0);
|
||||
Okay = WaitForWork(&ServerReadContext, 100);
|
||||
ok_bool_false(Okay, "WaitForWork returned");
|
||||
CheckClientQuota(ClientHandle, 0, 0);
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
|
||||
Okay = WaitForWork(&ServerReadContext, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 0);
|
||||
ok_eq_uint(ReadBuffer[0], 'X');
|
||||
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'F');
|
||||
CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
|
||||
|
||||
/** Disconnect server with pending read on client */
|
||||
WriteBuffer[0] = 'G';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
ok_bool_false(Okay, "CheckReadPipe returned");
|
||||
CheckServerQuota(ServerHandle, 0, 1);
|
||||
Status = NpDisconnectPipe(ServerHandle);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Okay = WaitForWork(&ClientReadContext, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
ok_eq_uint(ReadBuffer[0], 'X');
|
||||
|
||||
/* Read from server when disconnected */
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
|
||||
/* Write to server when disconnected */
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
|
||||
/* Read from client when disconnected */
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
|
||||
/* Write to client when disconnected */
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
Status = ObCloseHandle(ClientHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Restore the connection */
|
||||
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
|
||||
ok_bool_false(Okay, "CheckListenPipe returned");
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
Okay = WaitForWork(&ListenContext, 100);
|
||||
ok_bool_true(Okay, "WaitForWork returned");
|
||||
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/** Close server with pending read on client */
|
||||
WriteBuffer[0] = 'H';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
ok_bool_false(Okay, "CheckReadPipe returned");
|
||||
Status = ObCloseHandle(ServerHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Okay = WaitForWork(&ClientReadContext, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
|
||||
ok_eq_uint(ReadBuffer[0], 'X');
|
||||
|
||||
/* Read from client when closed */
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
|
||||
|
||||
/* Write to client when closed */
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_PIPE_CLOSING, 0);
|
||||
Status = ObCloseHandle(ClientHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Restore the connection */
|
||||
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/** Close client with pending read on server */
|
||||
WriteBuffer[0] = 'I';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
ok_bool_false(Okay, "CheckReadPipe returned");
|
||||
Status = ObCloseHandle(ClientHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Okay = WaitForWork(&ServerReadContext, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
|
||||
ok_eq_uint(ReadBuffer[0], 'X');
|
||||
|
||||
/* Read from server when closed */
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
|
||||
|
||||
/* Write to server when closed */
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_PIPE_CLOSING, 0);
|
||||
Status = ObCloseHandle(ServerHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Restore the connection */
|
||||
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/** Write to server and disconnect, then read from client */
|
||||
WriteBuffer[0] = 'J';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
|
||||
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
|
||||
Status = NpDisconnectPipe(ServerHandle);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
|
||||
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
ok_eq_uint(ReadBuffer[0], 'X');
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
Status = ObCloseHandle(ClientHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Restore the connection */
|
||||
Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
|
||||
ok_bool_false(Okay, "CheckListenPipe returned");
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
Okay = WaitForWork(&ListenContext, 100);
|
||||
ok_bool_true(Okay, "WaitForWork returned");
|
||||
ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/** Write to server and close, then read from client */
|
||||
WriteBuffer[0] = 'K';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
|
||||
CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
|
||||
Status = ObCloseHandle(ServerHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
NpCheckClientPipe(ClientHandle,
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MAX_INSTANCES, 1,
|
||||
IN_QUOTA, 1,
|
||||
OUT_QUOTA, OUT_QUOTA,
|
||||
FILE_PIPE_CLOSING_STATE);
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'K');
|
||||
Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
|
||||
Status = ObCloseHandle(ClientHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Restore the connection */
|
||||
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
|
||||
/** Write to client and close, then read from server */
|
||||
WriteBuffer[0] = 'L';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
|
||||
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
|
||||
Status = ObCloseHandle(ClientHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
NpCheckServerPipe(ServerHandle,
|
||||
BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
|
||||
MAX_INSTANCES, 1,
|
||||
IN_QUOTA, 1,
|
||||
OUT_QUOTA, OUT_QUOTA,
|
||||
FILE_PIPE_CLOSING_STATE);
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
|
||||
ok_eq_uint(ReadBuffer[0], 'L');
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
|
||||
Status = ObCloseHandle(ServerHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
/* Restore the connection */
|
||||
Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
|
||||
ok_bool_true(Okay, "CheckConnectPipe returned");
|
||||
ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
|
||||
ClientHandle = ConnectContext.Connect.ClientHandle;
|
||||
CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
|
||||
|
||||
/** Write to client and disconnect server, then read from server */
|
||||
WriteBuffer[0] = 'M';
|
||||
ReadBuffer[0] = 'X';
|
||||
Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
|
||||
CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
|
||||
CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
|
||||
Status = NpDisconnectPipe(ServerHandle);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
|
||||
CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
ok_eq_uint(ReadBuffer[0], 'X');
|
||||
Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
|
||||
CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
|
||||
Status = ObCloseHandle(ClientHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
Status = ObCloseHandle(ServerHandle, KernelMode);
|
||||
ok_eq_hex(Status, STATUS_SUCCESS);
|
||||
|
||||
FinishWorkerThread(&ServerWriteContext);
|
||||
FinishWorkerThread(&ServerReadContext);
|
||||
FinishWorkerThread(&ClientWriteContext);
|
||||
FinishWorkerThread(&ClientReadContext);
|
||||
FinishWorkerThread(&ListenContext);
|
||||
FinishWorkerThread(&ConnectContext);
|
||||
}
|
||||
|
||||
START_TEST(NpfsReadWrite)
|
||||
{
|
||||
PKTHREAD Thread;
|
||||
READ_WRITE_TEST_CONTEXT TestContext;
|
||||
|
||||
TestContext.PipePath = DEVICE_NAMED_PIPE L"\\KmtestNpfsReadWriteTestPipe";
|
||||
|
||||
TestContext.ServerSynchronous = TRUE;
|
||||
TestContext.ClientSynchronous = TRUE;
|
||||
Thread = KmtStartThread(TestReadWrite, &TestContext);
|
||||
KmtFinishThread(Thread, NULL);
|
||||
|
||||
TestContext.ServerSynchronous = FALSE;
|
||||
TestContext.ClientSynchronous = TRUE;
|
||||
Thread = KmtStartThread(TestReadWrite, &TestContext);
|
||||
KmtFinishThread(Thread, NULL);
|
||||
|
||||
TestContext.ServerSynchronous = TRUE;
|
||||
TestContext.ClientSynchronous = FALSE;
|
||||
Thread = KmtStartThread(TestReadWrite, &TestContext);
|
||||
KmtFinishThread(Thread, NULL);
|
||||
|
||||
TestContext.ServerSynchronous = FALSE;
|
||||
TestContext.ClientSynchronous = FALSE;
|
||||
Thread = KmtStartThread(TestReadWrite, &TestContext);
|
||||
KmtFinishThread(Thread, NULL);
|
||||
}
|
225
rostests/kmtests/npfs/npfs.h
Normal file
225
rostests/kmtests/npfs/npfs.h
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* PROJECT: ReactOS kernel-mode tests
|
||||
* LICENSE: LGPLv2+ - See COPYING.LIB in the top level directory
|
||||
* PURPOSE: Kernel-Mode Test Suite NPFS helper declarations
|
||||
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
||||
*/
|
||||
|
||||
#ifndef _KMTEST_NPFS_H_
|
||||
#define _KMTEST_NPFS_H_
|
||||
|
||||
#define DEVICE_NAMED_PIPE L"\\Device\\NamedPipe"
|
||||
|
||||
#define BYTE_STREAM FILE_PIPE_BYTE_STREAM_MODE
|
||||
C_ASSERT(FILE_PIPE_BYTE_STREAM_MODE == FILE_PIPE_BYTE_STREAM_TYPE);
|
||||
#define MESSAGE FILE_PIPE_MESSAGE_MODE
|
||||
C_ASSERT(FILE_PIPE_MESSAGE_MODE == FILE_PIPE_MESSAGE_TYPE);
|
||||
#define QUEUE FILE_PIPE_QUEUE_OPERATION
|
||||
#define COMPLETE FILE_PIPE_COMPLETE_OPERATION
|
||||
#define INBOUND FILE_PIPE_INBOUND
|
||||
#define OUTBOUND FILE_PIPE_OUTBOUND
|
||||
#define DUPLEX FILE_PIPE_FULL_DUPLEX
|
||||
|
||||
NTSTATUS
|
||||
NpCreatePipeEx(
|
||||
OUT PHANDLE ServerHandle,
|
||||
IN PCWSTR PipePath,
|
||||
IN ULONG ReadMode,
|
||||
IN ULONG CompletionMode,
|
||||
IN ULONG NamedPipeType,
|
||||
IN ULONG ShareAccess,
|
||||
IN ULONG MaximumInstances,
|
||||
IN ULONG InboundQuota,
|
||||
IN ULONG OutboundQuota,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN ULONG Disposition,
|
||||
IN ULONG CreateOptions,
|
||||
IN PLARGE_INTEGER DefaultTimeout OPTIONAL);
|
||||
|
||||
NTSTATUS
|
||||
NpCreatePipe(
|
||||
OUT PHANDLE ServerHandle,
|
||||
IN PCWSTR PipePath,
|
||||
IN ULONG ReadMode,
|
||||
IN ULONG CompletionMode,
|
||||
IN ULONG NamedPipeType,
|
||||
IN ULONG NamedPipeConfiguration,
|
||||
IN ULONG MaximumInstances,
|
||||
IN ULONG InboundQuota,
|
||||
IN ULONG OutboundQuota);
|
||||
|
||||
NTSTATUS
|
||||
NpOpenPipeEx(
|
||||
OUT PHANDLE ClientHandle,
|
||||
IN PCWSTR PipePath,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
IN ULONG ShareAccess,
|
||||
IN ULONG Disposition,
|
||||
IN ULONG CreateOptions);
|
||||
|
||||
NTSTATUS
|
||||
NpOpenPipe(
|
||||
OUT PHANDLE ClientHandle,
|
||||
IN PCWSTR PipePath,
|
||||
IN ULONG NamedPipeConfiguration);
|
||||
|
||||
NTSTATUS
|
||||
NpControlPipe(
|
||||
IN HANDLE PipeHandle,
|
||||
IN ULONG FsControlCode,
|
||||
IN PVOID InputBuffer,
|
||||
IN ULONG InputBufferLength);
|
||||
|
||||
#define NpListenPipe(ServerHandle) NpControlPipe(ServerHandle, FSCTL_PIPE_LISTEN, NULL, 0)
|
||||
#define NpDisconnectPipe(ServerHandle) NpControlPipe(ServerHandle, FSCTL_PIPE_DISCONNECT, NULL, 0)
|
||||
|
||||
NTSTATUS
|
||||
NpWaitPipe(
|
||||
IN PCWSTR PipeName,
|
||||
IN PLARGE_INTEGER Timeout);
|
||||
|
||||
NTSTATUS
|
||||
NpReadPipe(
|
||||
IN HANDLE PipeHandle,
|
||||
OUT PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PULONG_PTR BytesRead);
|
||||
|
||||
NTSTATUS
|
||||
NpWritePipe(
|
||||
IN HANDLE PipeHandle,
|
||||
IN const VOID *Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PULONG_PTR BytesWritten);
|
||||
|
||||
#define NpCheckServerPipe(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps) \
|
||||
NpCheckServerPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, __FILE__, __LINE__)
|
||||
|
||||
#define NpCheckServerPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file, line) \
|
||||
NpCheckServerPipe_(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file ":" KMT_STRINGIZE(line))
|
||||
|
||||
VOID
|
||||
NpCheckServerPipe_(
|
||||
IN HANDLE ServerHandle,
|
||||
/* PipeInformation */
|
||||
IN ULONG ReadMode,
|
||||
IN ULONG CompletionMode,
|
||||
/* PipeLocalInformation */
|
||||
IN ULONG NamedPipeType,
|
||||
IN ULONG NamedPipeConfiguration,
|
||||
IN ULONG MaximumInstances,
|
||||
IN ULONG CurrentInstances,
|
||||
IN ULONG InboundQuota,
|
||||
IN ULONG ReadDataAvailable,
|
||||
IN ULONG OutboundQuota,
|
||||
IN ULONG WriteQuotaAvailable,
|
||||
IN ULONG NamedPipeState,
|
||||
/* PipeRemoteInformation */
|
||||
/* */
|
||||
IN PCSTR FileAndLine);
|
||||
|
||||
#define NpCheckClientPipe(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps) \
|
||||
NpCheckClientPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, __FILE__, __LINE__)
|
||||
|
||||
#define NpCheckClientPipe__(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file, line) \
|
||||
NpCheckClientPipe_(h, rm, cm, npt, npc, mi, ci, iq, rsa, oq, wqa, nps, file ":" KMT_STRINGIZE(line))
|
||||
|
||||
VOID
|
||||
NpCheckClientPipe_(
|
||||
IN HANDLE ClientHandle,
|
||||
/* PipeInformation */
|
||||
IN ULONG ReadMode,
|
||||
IN ULONG CompletionMode,
|
||||
/* PipeLocalInformation */
|
||||
IN ULONG NamedPipeType,
|
||||
IN ULONG NamedPipeConfiguration,
|
||||
IN ULONG MaximumInstances,
|
||||
IN ULONG CurrentInstances,
|
||||
IN ULONG InboundQuota,
|
||||
IN ULONG ReadDataAvailable,
|
||||
IN ULONG OutboundQuota,
|
||||
IN ULONG WriteQuotaAvailable,
|
||||
IN ULONG NamedPipeState,
|
||||
/* PipeRemoteInformation */
|
||||
/* */
|
||||
IN PCSTR FileAndLine);
|
||||
|
||||
#define NpQueryPipe(h, es) \
|
||||
NpQueryPipe__(h, es, __FILE__, __LINE__)
|
||||
|
||||
#define NpQueryPipe__(h, es, file, line) \
|
||||
NpQueryPipe_(h, es, file ":" KMT_STRINGIZE(line))
|
||||
|
||||
VOID
|
||||
NpQueryPipe_(
|
||||
IN HANDLE Handle,
|
||||
IN NTSTATUS ExpectedStatus,
|
||||
IN PCSTR FileAndLine);
|
||||
|
||||
|
||||
struct _THREAD_CONTEXT;
|
||||
typedef VOID (WORK_FUNCTION)(IN OUT struct _THREAD_CONTEXT *);
|
||||
typedef WORK_FUNCTION *PWORK_FUNCTION;
|
||||
|
||||
typedef struct _THREAD_CONTEXT
|
||||
{
|
||||
volatile PWORK_FUNCTION Work;
|
||||
volatile union
|
||||
{
|
||||
struct
|
||||
{
|
||||
PCWSTR PipePath;
|
||||
BOOLEAN ClientSynchronous;
|
||||
HANDLE ClientHandle;
|
||||
NTSTATUS Status;
|
||||
} Connect;
|
||||
struct
|
||||
{
|
||||
HANDLE ServerHandle;
|
||||
NTSTATUS Status;
|
||||
} Listen;
|
||||
struct
|
||||
{
|
||||
HANDLE PipeHandle;
|
||||
PVOID Buffer;
|
||||
ULONG BufferSize;
|
||||
ULONG_PTR BytesTransferred;
|
||||
NTSTATUS Status;
|
||||
} ReadWrite;
|
||||
};
|
||||
KEVENT ThreadDoneEvent;
|
||||
KEVENT StartWorkEvent;
|
||||
KEVENT WorkCompleteEvent;
|
||||
PKTHREAD Thread;
|
||||
} THREAD_CONTEXT, *PTHREAD_CONTEXT;
|
||||
|
||||
VOID
|
||||
StartWorkerThread(
|
||||
OUT PTHREAD_CONTEXT Context);
|
||||
|
||||
VOID
|
||||
FinishWorkerThread(
|
||||
IN PTHREAD_CONTEXT Context);
|
||||
|
||||
BOOLEAN
|
||||
WaitForWork(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN ULONG MilliSeconds);
|
||||
|
||||
BOOLEAN
|
||||
TriggerWork(
|
||||
IN PTHREAD_CONTEXT Context,
|
||||
IN ULONG MilliSeconds);
|
||||
|
||||
|
||||
PKTHREAD
|
||||
KmtStartThread(
|
||||
IN PKSTART_ROUTINE StartRoutine,
|
||||
IN PVOID StartContext OPTIONAL);
|
||||
|
||||
VOID
|
||||
KmtFinishThread(
|
||||
IN PKTHREAD Thread OPTIONAL,
|
||||
IN PKEVENT Event OPTIONAL);
|
||||
|
||||
#endif /* !defined _KMTEST_NPFS_H_ */
|
Loading…
Reference in a new issue