1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite NPFS Read/Write test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #include "npfs.h"
10 
11 typedef struct _READ_WRITE_TEST_CONTEXT
12 {
13     PCWSTR PipePath;
14     BOOLEAN ServerSynchronous;
15     BOOLEAN ClientSynchronous;
16 } READ_WRITE_TEST_CONTEXT, *PREAD_WRITE_TEST_CONTEXT;
17 
18 #define MAX_INSTANCES   5
19 #define IN_QUOTA        4096
20 #define OUT_QUOTA       4096
21 
22 #define MakeServer(ServerHandle, PipePath, ServerSynchronous)           \
23     NpCreatePipeEx(ServerHandle,                                        \
24                    PipePath,                                            \
25                    BYTE_STREAM,                                         \
26                    QUEUE,                                               \
27                    BYTE_STREAM,                                         \
28                    FILE_SHARE_READ | FILE_SHARE_WRITE,                  \
29                    MAX_INSTANCES,                                       \
30                    IN_QUOTA,                                            \
31                    OUT_QUOTA,                                           \
32                    SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,          \
33                    FILE_OPEN_IF,                                        \
34                    (ServerSynchronous) ? FILE_SYNCHRONOUS_IO_NONALERT   \
35                                        : 0,                             \
36                    &DefaultTimeout)
37 
38 #define CheckServer(ServerHandle, State)                                \
39     NpCheckServerPipe(ServerHandle,                                     \
40                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,          \
41                       MAX_INSTANCES, 1,                                 \
42                       IN_QUOTA, 0,                                      \
43                       OUT_QUOTA, OUT_QUOTA,                             \
44                       State)
45 
46 #define CheckClient(ClientHandle, State)                                \
47     NpCheckClientPipe(ClientHandle,                                     \
48                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,          \
49                       MAX_INSTANCES, 1,                                 \
50                       IN_QUOTA, 0,                                      \
51                       OUT_QUOTA, OUT_QUOTA,                             \
52                       State)
53 
54 #define CheckServerQuota(ServerHandle, InQ, OutQ)                       \
55     NpCheckServerPipe(ServerHandle,                                     \
56                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,          \
57                       MAX_INSTANCES, 1,                                 \
58                       IN_QUOTA, InQ,                                    \
59                       OUT_QUOTA, OUT_QUOTA - (OutQ),                    \
60                       FILE_PIPE_CONNECTED_STATE)
61 
62 #define CheckClientQuota(ClientHandle, InQ, OutQ)                       \
63     NpCheckClientPipe(ClientHandle,                                     \
64                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,          \
65                       MAX_INSTANCES, 1,                                 \
66                       IN_QUOTA, InQ,                                    \
67                       OUT_QUOTA, OUT_QUOTA - (OutQ),                    \
68                       FILE_PIPE_CONNECTED_STATE)
69 
70 #define CheckPipeContext(Context, ExpectedStatus, ExpectedBytes) do             \
71 {                                                                           \
72     ok_bool_true(Okay, "CheckPipeContext");                                     \
73     ok_eq_hex((Context)->ReadWrite.Status, ExpectedStatus);                 \
74     ok_eq_ulongptr((Context)->ReadWrite.BytesTransferred, ExpectedBytes);   \
75 } while (0)
76 
77 static
78 VOID
79 ConnectPipe(
80     IN OUT PTHREAD_CONTEXT Context)
81 {
82     HANDLE ClientHandle;
83 
84     ClientHandle = NULL;
85     Context->Connect.Status = NpOpenPipeEx(&ClientHandle,
86                                            Context->Connect.PipePath,
87                                            SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
88                                            FILE_SHARE_READ | FILE_SHARE_WRITE,
89                                            FILE_OPEN,
90                                            Context->Connect.ClientSynchronous ? FILE_SYNCHRONOUS_IO_NONALERT
91                                                                               : 0);
92     Context->Connect.ClientHandle = ClientHandle;
93 }
94 
95 static
96 VOID
97 ListenPipe(
98     IN OUT PTHREAD_CONTEXT Context)
99 {
100     Context->Listen.Status = NpListenPipe(Context->Listen.ServerHandle);
101 }
102 
103 static
104 VOID
105 ReadPipe(
106     IN OUT PTHREAD_CONTEXT Context)
107 {
108     Context->ReadWrite.Status = NpReadPipe(Context->ReadWrite.PipeHandle,
109                                            Context->ReadWrite.Buffer,
110                                            Context->ReadWrite.BufferSize,
111                                            (PULONG_PTR)&Context->ReadWrite.BytesTransferred);
112 }
113 
114 static
115 VOID
116 WritePipe(
117     IN OUT PTHREAD_CONTEXT Context)
118 {
119     Context->ReadWrite.Status = NpWritePipe(Context->ReadWrite.PipeHandle,
120                                             Context->ReadWrite.Buffer,
121                                             Context->ReadWrite.BufferSize,
122                                             (PULONG_PTR)&Context->ReadWrite.BytesTransferred);
123 }
124 
125 static
126 BOOLEAN
127 CheckConnectPipe(
128     IN PTHREAD_CONTEXT Context,
129     IN PCWSTR PipePath,
130     IN BOOLEAN ClientSynchronous,
131     IN ULONG MilliSeconds)
132 {
133     Context->Work = ConnectPipe;
134     Context->Connect.PipePath = PipePath;
135     Context->Connect.ClientSynchronous = ClientSynchronous;
136     return TriggerWork(Context, MilliSeconds);
137 }
138 
139 static
140 BOOLEAN
141 CheckListenPipe(
142     IN PTHREAD_CONTEXT Context,
143     IN HANDLE ServerHandle,
144     IN ULONG MilliSeconds)
145 {
146     Context->Work = ListenPipe;
147     Context->Listen.ServerHandle = ServerHandle;
148     return TriggerWork(Context, MilliSeconds);
149 }
150 
151 static
152 BOOLEAN
153 CheckReadPipe(
154     IN PTHREAD_CONTEXT Context,
155     IN HANDLE PipeHandle,
156     OUT PVOID Buffer,
157     IN ULONG BufferSize,
158     IN ULONG MilliSeconds)
159 {
160     Context->Work = ReadPipe;
161     Context->ReadWrite.PipeHandle = PipeHandle;
162     Context->ReadWrite.Buffer = Buffer;
163     Context->ReadWrite.BufferSize = BufferSize;
164     return TriggerWork(Context, MilliSeconds);
165 }
166 
167 static
168 BOOLEAN
169 CheckWritePipe(
170     IN PTHREAD_CONTEXT Context,
171     IN HANDLE PipeHandle,
172     IN const VOID *Buffer,
173     IN ULONG BufferSize,
174     IN ULONG MilliSeconds)
175 {
176     Context->Work = WritePipe;
177     Context->ReadWrite.PipeHandle = PipeHandle;
178     Context->ReadWrite.Buffer = (PVOID)Buffer;
179     Context->ReadWrite.BufferSize = BufferSize;
180     return TriggerWork(Context, MilliSeconds);
181 }
182 
183 static KSTART_ROUTINE TestReadWrite;
184 static
185 VOID
186 NTAPI
187 TestReadWrite(
188     IN PVOID Context)
189 {
190     PREAD_WRITE_TEST_CONTEXT TestContext = Context;
191     PCWSTR PipePath = TestContext->PipePath;
192     BOOLEAN ServerSynchronous = TestContext->ServerSynchronous;
193     BOOLEAN ClientSynchronous = TestContext->ClientSynchronous;
194     NTSTATUS Status;
195     HANDLE ServerHandle;
196     LARGE_INTEGER DefaultTimeout;
197     THREAD_CONTEXT ConnectContext;
198     THREAD_CONTEXT ListenContext;
199     THREAD_CONTEXT ClientReadContext;
200     THREAD_CONTEXT ClientWriteContext;
201     THREAD_CONTEXT ServerReadContext;
202     THREAD_CONTEXT ServerWriteContext;
203     BOOLEAN Okay;
204     HANDLE ClientHandle;
205     UCHAR ReadBuffer[128];
206     UCHAR WriteBuffer[128];
207 
208     StartWorkerThread(&ConnectContext);
209     StartWorkerThread(&ListenContext);
210     StartWorkerThread(&ClientReadContext);
211     StartWorkerThread(&ClientWriteContext);
212     StartWorkerThread(&ServerReadContext);
213     StartWorkerThread(&ServerWriteContext);
214 
215     DefaultTimeout.QuadPart = -50 * 1000 * 10;
216 
217     /* Server should start out listening */
218     Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
219     ok_eq_hex(Status, STATUS_SUCCESS);
220     CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
221 
222     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, NULL, 0, 100);
223     ok_bool_true(Okay, "CheckWritePipe returned");
224     ok_eq_ulongptr(ServerWriteContext.ReadWrite.BytesTransferred, 0);
225     ok_eq_hex(ServerWriteContext.ReadWrite.Status, STATUS_PIPE_LISTENING);
226 
227     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, NULL, 0, 100);
228     ok_bool_true(Okay, "CheckReadPipe returned");
229     ok_eq_ulongptr(ServerReadContext.ReadWrite.BytesTransferred, 0);
230     ok_eq_hex(ServerReadContext.ReadWrite.Status, STATUS_PIPE_LISTENING);
231 
232     /* Connect a client */
233     Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
234     ok_bool_true(Okay, "CheckConnectPipe returned");
235     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
236     ClientHandle = ConnectContext.Connect.ClientHandle;
237     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
238     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
239 
240     /** Server to client, write first, 1 byte */
241     WriteBuffer[0] = 'A';
242     ReadBuffer[0] = 'X';
243     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
244     CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
245     CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
246     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
247     CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
248     ok_eq_uint(ReadBuffer[0], 'A');
249     CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
250 
251     /** Server to client, read first, 1 byte */
252     WriteBuffer[0] = 'B';
253     ReadBuffer[0] = 'X';
254     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
255     ok_bool_false(Okay, "CheckReadPipe returned");
256     CheckServerQuota(ServerHandle, 0, 1);
257     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
258     CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
259     Okay = WaitForWork(&ClientReadContext, 100);
260     CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
261     ok_eq_uint(ReadBuffer[0], 'B');
262     CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
263 
264     /** Client to server, write first, 1 byte */
265     WriteBuffer[0] = 'C';
266     ReadBuffer[0] = 'X';
267     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
268     CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
269     CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
270     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
271     CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
272     ok_eq_uint(ReadBuffer[0], 'C');
273     CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
274 
275     /** Client to server, read first, 1 byte */
276     WriteBuffer[0] = 'D';
277     ReadBuffer[0] = 'X';
278     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
279     ok_bool_false(Okay, "CheckReadPipe returned");
280     CheckClientQuota(ClientHandle, 0, 1);
281     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
282     CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
283     Okay = WaitForWork(&ServerReadContext, 100);
284     CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
285     ok_eq_uint(ReadBuffer[0], 'D');
286     CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
287 
288     /** Server to client, write 0 bytes */
289     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, (PVOID)1, 0, 100);
290     CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 0);
291     CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
292 
293     /** Client to Server, write 0 bytes */
294     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, (PVOID)1, 0, 100);
295     CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 0);
296     CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
297 
298     /** Server to client, read 0 bytes blocks, write 0 bytes does not unblock, write 1 byte unblocks */
299     WriteBuffer[0] = 'E';
300     ReadBuffer[0] = 'X';
301     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, (PVOID)1, 0, 100);
302     ok_bool_false(Okay, "CheckReadPipe returned");
303     CheckServerQuota(ServerHandle, 0, 0);
304     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, (PVOID)1, 0, 100);
305     CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 0);
306     Okay = WaitForWork(&ClientReadContext, 100);
307     ok_bool_false(Okay, "WaitForWork returned");
308     CheckServerQuota(ServerHandle, 0, 0);
309     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
310     CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
311     Okay = WaitForWork(&ClientReadContext, 100);
312     CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 0);
313     ok_eq_uint(ReadBuffer[0], 'X');
314     CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
315     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
316     CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
317     ok_eq_uint(ReadBuffer[0], 'E');
318     CheckServerQuota(ServerHandle, 0, 0); CheckClientQuota(ClientHandle, 0, 0);
319 
320     /** Client to server, read 0 bytes blocks, write 0 bytes does not unblock, write 1 byte unblocks */
321     WriteBuffer[0] = 'F';
322     ReadBuffer[0] = 'X';
323     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, (PVOID)1, 0, 100);
324     ok_bool_false(Okay, "CheckReadPipe returned");
325     CheckClientQuota(ClientHandle, 0, 0);
326     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, (PVOID)1, 0, 100);
327     CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 0);
328     Okay = WaitForWork(&ServerReadContext, 100);
329     ok_bool_false(Okay, "WaitForWork returned");
330     CheckClientQuota(ClientHandle, 0, 0);
331     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
332     CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
333     Okay = WaitForWork(&ServerReadContext, 100);
334     CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 0);
335     ok_eq_uint(ReadBuffer[0], 'X');
336     CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
337     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
338     CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
339     ok_eq_uint(ReadBuffer[0], 'F');
340     CheckClientQuota(ClientHandle, 0, 0); CheckServerQuota(ServerHandle, 0, 0);
341 
342     /** Disconnect server with pending read on client */
343     WriteBuffer[0] = 'G';
344     ReadBuffer[0] = 'X';
345     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
346     ok_bool_false(Okay, "CheckReadPipe returned");
347     CheckServerQuota(ServerHandle, 0, 1);
348     Status = NpDisconnectPipe(ServerHandle);
349     ok_eq_hex(Status, STATUS_SUCCESS);
350     Okay = WaitForWork(&ClientReadContext, 100);
351     CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
352     ok_eq_uint(ReadBuffer[0], 'X');
353 
354     /* Read from server when disconnected */
355     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
356     CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
357 
358     /* Write to server when disconnected */
359     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
360     CheckPipeContext(&ServerWriteContext, STATUS_PIPE_DISCONNECTED, 0);
361 
362     /* Read from client when disconnected */
363     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
364     CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
365 
366     /* Write to client when disconnected */
367     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
368     CheckPipeContext(&ClientWriteContext, STATUS_PIPE_DISCONNECTED, 0);
369     Status = ObCloseHandle(ClientHandle, KernelMode);
370     ok_eq_hex(Status, STATUS_SUCCESS);
371 
372     /* Restore the connection */
373     Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
374     ok_bool_false(Okay, "CheckListenPipe returned");
375     Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
376     ok_bool_true(Okay, "CheckConnectPipe returned");
377     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
378     Okay = WaitForWork(&ListenContext, 100);
379     ok_bool_true(Okay, "WaitForWork returned");
380     ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
381     ClientHandle = ConnectContext.Connect.ClientHandle;
382     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
383     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
384 
385     /** Close server with pending read on client */
386     WriteBuffer[0] = 'H';
387     ReadBuffer[0] = 'X';
388     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
389     ok_bool_false(Okay, "CheckReadPipe returned");
390     Status = ObCloseHandle(ServerHandle, KernelMode);
391     ok_eq_hex(Status, STATUS_SUCCESS);
392     Okay = WaitForWork(&ClientReadContext, 100);
393     CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
394     ok_eq_uint(ReadBuffer[0], 'X');
395 
396     /* Read from client when closed */
397     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
398     CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
399 
400     /* Write to client when closed */
401     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
402     CheckPipeContext(&ClientWriteContext, STATUS_PIPE_CLOSING, 0);
403     Status = ObCloseHandle(ClientHandle, KernelMode);
404     ok_eq_hex(Status, STATUS_SUCCESS);
405 
406     /* Restore the connection */
407     Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
408     ok_eq_hex(Status, STATUS_SUCCESS);
409     Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
410     ok_bool_true(Okay, "CheckConnectPipe returned");
411     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
412     ClientHandle = ConnectContext.Connect.ClientHandle;
413     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
414     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
415 
416     /** Close client with pending read on server */
417     WriteBuffer[0] = 'I';
418     ReadBuffer[0] = 'X';
419     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
420     ok_bool_false(Okay, "CheckReadPipe returned");
421     Status = ObCloseHandle(ClientHandle, KernelMode);
422     ok_eq_hex(Status, STATUS_SUCCESS);
423     Okay = WaitForWork(&ServerReadContext, 100);
424     CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
425     ok_eq_uint(ReadBuffer[0], 'X');
426 
427     /* Read from server when closed */
428     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
429     CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
430 
431     /* Write to server when closed */
432     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
433     CheckPipeContext(&ServerWriteContext, STATUS_PIPE_CLOSING, 0);
434     Status = ObCloseHandle(ServerHandle, KernelMode);
435     ok_eq_hex(Status, STATUS_SUCCESS);
436 
437     /* Restore the connection */
438     Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
439     ok_eq_hex(Status, STATUS_SUCCESS);
440     Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
441     ok_bool_true(Okay, "CheckConnectPipe returned");
442     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
443     ClientHandle = ConnectContext.Connect.ClientHandle;
444     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
445     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
446 
447     /** Write to server and disconnect, then read from client */
448     WriteBuffer[0] = 'J';
449     ReadBuffer[0] = 'X';
450     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
451     CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
452     CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
453     Status = NpDisconnectPipe(ServerHandle);
454     ok_eq_hex(Status, STATUS_SUCCESS);
455     NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
456     CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
457     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
458     CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
459     ok_eq_uint(ReadBuffer[0], 'X');
460     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
461     CheckPipeContext(&ClientReadContext, STATUS_PIPE_DISCONNECTED, 0);
462     Status = ObCloseHandle(ClientHandle, KernelMode);
463     ok_eq_hex(Status, STATUS_SUCCESS);
464 
465     /* Restore the connection */
466     Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
467     ok_bool_false(Okay, "CheckListenPipe returned");
468     Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
469     ok_bool_true(Okay, "CheckConnectPipe returned");
470     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
471     Okay = WaitForWork(&ListenContext, 100);
472     ok_bool_true(Okay, "WaitForWork returned");
473     ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
474     ClientHandle = ConnectContext.Connect.ClientHandle;
475     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
476     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
477 
478     /** Write to server and close, then read from client */
479     WriteBuffer[0] = 'K';
480     ReadBuffer[0] = 'X';
481     Okay = CheckWritePipe(&ServerWriteContext, ServerHandle, WriteBuffer, 1, 100);
482     CheckPipeContext(&ServerWriteContext, STATUS_SUCCESS, 1);
483     CheckServerQuota(ServerHandle, 0, 1); CheckClientQuota(ClientHandle, 1, 0);
484     Status = ObCloseHandle(ServerHandle, KernelMode);
485     ok_eq_hex(Status, STATUS_SUCCESS);
486     NpCheckClientPipe(ClientHandle,
487                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
488                       MAX_INSTANCES, 1,
489                       IN_QUOTA, 1,
490                       OUT_QUOTA, OUT_QUOTA,
491                       FILE_PIPE_CLOSING_STATE);
492     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
493     CheckPipeContext(&ClientReadContext, STATUS_SUCCESS, 1);
494     ok_eq_uint(ReadBuffer[0], 'K');
495     Okay = CheckReadPipe(&ClientReadContext, ClientHandle, ReadBuffer, 1, 100);
496     CheckPipeContext(&ClientReadContext, STATUS_PIPE_BROKEN, 0);
497     Status = ObCloseHandle(ClientHandle, KernelMode);
498     ok_eq_hex(Status, STATUS_SUCCESS);
499 
500     /* Restore the connection */
501     Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
502     ok_eq_hex(Status, STATUS_SUCCESS);
503     Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
504     ok_bool_true(Okay, "CheckConnectPipe returned");
505     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
506     ClientHandle = ConnectContext.Connect.ClientHandle;
507     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
508     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
509 
510 
511     /** Write to client and close, then read from server */
512     WriteBuffer[0] = 'L';
513     ReadBuffer[0] = 'X';
514     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
515     CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
516     CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
517     Status = ObCloseHandle(ClientHandle, KernelMode);
518     ok_eq_hex(Status, STATUS_SUCCESS);
519     NpCheckServerPipe(ServerHandle,
520                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
521                       MAX_INSTANCES, 1,
522                       IN_QUOTA, 1,
523                       OUT_QUOTA, OUT_QUOTA,
524                       FILE_PIPE_CLOSING_STATE);
525     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
526     CheckPipeContext(&ServerReadContext, STATUS_SUCCESS, 1);
527     ok_eq_uint(ReadBuffer[0], 'L');
528     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
529     CheckPipeContext(&ServerReadContext, STATUS_PIPE_BROKEN, 0);
530     Status = ObCloseHandle(ServerHandle, KernelMode);
531     ok_eq_hex(Status, STATUS_SUCCESS);
532 
533     /* Restore the connection */
534     Status = MakeServer(&ServerHandle, PipePath, ServerSynchronous);
535     ok_eq_hex(Status, STATUS_SUCCESS);
536     Okay = CheckConnectPipe(&ConnectContext, PipePath, ClientSynchronous, 100);
537     ok_bool_true(Okay, "CheckConnectPipe returned");
538     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
539     ClientHandle = ConnectContext.Connect.ClientHandle;
540     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
541     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
542 
543     /** Write to client and disconnect server, then read from server */
544     WriteBuffer[0] = 'M';
545     ReadBuffer[0] = 'X';
546     Okay = CheckWritePipe(&ClientWriteContext, ClientHandle, WriteBuffer, 1, 100);
547     CheckPipeContext(&ClientWriteContext, STATUS_SUCCESS, 1);
548     CheckClientQuota(ClientHandle, 0, 1); CheckServerQuota(ServerHandle, 1, 0);
549     Status = NpDisconnectPipe(ServerHandle);
550     ok_eq_hex(Status, STATUS_SUCCESS);
551     NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
552     CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
553     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
554     CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
555     ok_eq_uint(ReadBuffer[0], 'X');
556     Okay = CheckReadPipe(&ServerReadContext, ServerHandle, ReadBuffer, 1, 100);
557     CheckPipeContext(&ServerReadContext, STATUS_PIPE_DISCONNECTED, 0);
558     Status = ObCloseHandle(ClientHandle, KernelMode);
559     ok_eq_hex(Status, STATUS_SUCCESS);
560 
561     Status = ObCloseHandle(ServerHandle, KernelMode);
562     ok_eq_hex(Status, STATUS_SUCCESS);
563 
564     FinishWorkerThread(&ServerWriteContext);
565     FinishWorkerThread(&ServerReadContext);
566     FinishWorkerThread(&ClientWriteContext);
567     FinishWorkerThread(&ClientReadContext);
568     FinishWorkerThread(&ListenContext);
569     FinishWorkerThread(&ConnectContext);
570 }
571 
572 START_TEST(NpfsReadWrite)
573 {
574     PKTHREAD Thread;
575     READ_WRITE_TEST_CONTEXT TestContext;
576 
577     TestContext.PipePath = DEVICE_NAMED_PIPE L"\\KmtestNpfsReadWriteTestPipe";
578 
579     TestContext.ServerSynchronous = TRUE;
580     TestContext.ClientSynchronous = TRUE;
581     Thread = KmtStartThread(TestReadWrite, &TestContext);
582     KmtFinishThread(Thread, NULL);
583 
584     TestContext.ServerSynchronous = FALSE;
585     TestContext.ClientSynchronous = TRUE;
586     Thread = KmtStartThread(TestReadWrite, &TestContext);
587     KmtFinishThread(Thread, NULL);
588 
589     TestContext.ServerSynchronous = TRUE;
590     TestContext.ClientSynchronous = FALSE;
591     Thread = KmtStartThread(TestReadWrite, &TestContext);
592     KmtFinishThread(Thread, NULL);
593 
594     TestContext.ServerSynchronous = FALSE;
595     TestContext.ClientSynchronous = FALSE;
596     Thread = KmtStartThread(TestReadWrite, &TestContext);
597     KmtFinishThread(Thread, NULL);
598 }
599