mirror of
https://github.com/reactos/reactos.git
synced 2024-10-31 11:56:26 +00:00
599 lines
26 KiB
C
599 lines
26 KiB
C
|
/*
|
||
|
* 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);
|
||
|
}
|