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 Connect test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #include "npfs.h"
10 
11 #define MAX_INSTANCES   5
12 #define IN_QUOTA        4096
13 #define OUT_QUOTA       4096
14 
15 #define CheckServer(ServerHandle, State)                        \
16     NpCheckServerPipe(ServerHandle,                             \
17                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,  \
18                       MAX_INSTANCES, 1,                         \
19                       IN_QUOTA, 0,                              \
20                       OUT_QUOTA, OUT_QUOTA,                     \
21                       State)
22 
23 #define CheckClient(ClientHandle, State)                        \
24     NpCheckClientPipe(ClientHandle,                             \
25                       BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,  \
26                       MAX_INSTANCES, 1,                         \
27                       IN_QUOTA, 0,                              \
28                       OUT_QUOTA, OUT_QUOTA,                     \
29                       State)
30 
31 static
32 VOID
ConnectPipe(IN OUT PTHREAD_CONTEXT Context)33 ConnectPipe(
34     IN OUT PTHREAD_CONTEXT Context)
35 {
36     HANDLE ClientHandle;
37 
38     ClientHandle = NULL;
39     Context->Connect.Status = NpOpenPipe(&ClientHandle,
40                                          Context->Connect.PipePath,
41                                          FILE_PIPE_FULL_DUPLEX);
42     Context->Connect.ClientHandle = ClientHandle;
43 }
44 
45 static
46 VOID
ListenPipe(IN OUT PTHREAD_CONTEXT Context)47 ListenPipe(
48     IN OUT PTHREAD_CONTEXT Context)
49 {
50     Context->Listen.Status = NpListenPipe(Context->Listen.ServerHandle);
51 }
52 
53 static
54 BOOLEAN
CheckConnectPipe(IN PTHREAD_CONTEXT Context,IN PCWSTR PipePath,IN ULONG MilliSeconds)55 CheckConnectPipe(
56     IN PTHREAD_CONTEXT Context,
57     IN PCWSTR PipePath,
58     IN ULONG MilliSeconds)
59 {
60     Context->Work = ConnectPipe;
61     Context->Connect.PipePath = PipePath;
62     return TriggerWork(Context, MilliSeconds);
63 }
64 
65 static
66 BOOLEAN
CheckListenPipe(IN PTHREAD_CONTEXT Context,IN HANDLE ServerHandle,IN ULONG MilliSeconds)67 CheckListenPipe(
68     IN PTHREAD_CONTEXT Context,
69     IN HANDLE ServerHandle,
70     IN ULONG MilliSeconds)
71 {
72     Context->Work = ListenPipe;
73     Context->Listen.ServerHandle = ServerHandle;
74     return TriggerWork(Context, MilliSeconds);
75 }
76 
77 static
78 VOID
TestConnect(IN HANDLE ServerHandle,IN PCWSTR PipePath)79 TestConnect(
80     IN HANDLE ServerHandle,
81     IN PCWSTR PipePath)
82 {
83     NTSTATUS Status;
84     THREAD_CONTEXT ConnectContext;
85     THREAD_CONTEXT ListenContext;
86     BOOLEAN Okay;
87     HANDLE ClientHandle;
88 
89     StartWorkerThread(&ConnectContext);
90     StartWorkerThread(&ListenContext);
91 
92     /* Server should start out listening */
93     CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
94 
95     /* Connect a client */
96     ClientHandle = NULL;
97     Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
98     ok_bool_true(Okay, "CheckConnectPipe returned");
99     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
100     if (NT_SUCCESS(ConnectContext.Connect.Status))
101     {
102         ClientHandle = ConnectContext.Connect.ClientHandle;
103         CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
104     }
105     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
106 
107     /* Connect another client */
108     Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
109     ok_bool_true(Okay, "CheckConnectPipe returned");
110     ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
111     if (NT_SUCCESS(ConnectContext.Connect.Status))
112         ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
113     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
114     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
115 
116     /* Disconnecting the client should fail */
117     Status = NpDisconnectPipe(ClientHandle);
118     ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION);
119     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
120     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
121 
122     /* Listening on the client should fail */
123     Status = NpListenPipe(ClientHandle);
124     ok_eq_hex(Status, STATUS_ILLEGAL_FUNCTION);
125     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
126     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
127 
128     /* Close client */
129     if (ClientHandle)
130         ObCloseHandle(ClientHandle, KernelMode);
131     CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
132 
133     /* Connecting a client now should fail */
134     Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
135     ok_bool_true(Okay, "CheckConnectPipe returned");
136     ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
137     if (NT_SUCCESS(ConnectContext.Connect.Status))
138         ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
139     CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
140 
141     /* Listening should fail */
142     Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
143     ok_bool_true(Okay, "CheckListenPipe returned");
144     if (!skip(Okay, "Listen succeeded unexpectedly\n"))
145         CheckServer(ServerHandle, FILE_PIPE_CLOSING_STATE);
146 
147     /* Disconnect server */
148     Status = NpDisconnectPipe(ServerHandle);
149     ok_eq_hex(Status, STATUS_SUCCESS);
150     CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
151 
152     /* Disconnecting again should fail */
153     Status = NpDisconnectPipe(ServerHandle);
154     ok_eq_hex(Status, STATUS_PIPE_DISCONNECTED);
155     CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
156 
157     /* Connecting a client now should fail */
158     Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
159     ok_bool_true(Okay, "CheckConnectPipe returned");
160     ok_eq_hex(ConnectContext.Connect.Status, STATUS_PIPE_NOT_AVAILABLE);
161     if (NT_SUCCESS(ConnectContext.Connect.Status))
162         ObCloseHandle(ConnectContext.Connect.ClientHandle, KernelMode);
163     CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
164 
165     /**************************************************************************/
166     /* Now listen again */
167     Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
168     ok_bool_false(Okay, "CheckListenPipe returned");
169     //blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
170 
171     /* Connect client */
172     ClientHandle = NULL;
173     Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
174     ok_bool_true(Okay, "CheckConnectPipe returned");
175     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
176     if (NT_SUCCESS(ConnectContext.Connect.Status))
177     {
178         ClientHandle = ConnectContext.Connect.ClientHandle;
179         CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
180     }
181     Okay = WaitForWork(&ListenContext, 100);
182     ok_bool_true(Okay, "WaitForWork returned");
183     ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
184     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
185 
186     /* Listening again should fail */
187     Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
188     ok_bool_true(Okay, "CheckListenPipe returned");
189     ok_eq_hex(ListenContext.Listen.Status, STATUS_PIPE_CONNECTED);
190     CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
191     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
192 
193     /* Disconnect server */
194     Status = NpDisconnectPipe(ServerHandle);
195     ok_eq_hex(Status, STATUS_SUCCESS);
196     NpQueryPipe(ClientHandle, STATUS_PIPE_DISCONNECTED);
197     CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
198 
199     /* Close client */
200     if (ClientHandle)
201         ObCloseHandle(ClientHandle, KernelMode);
202     CheckServer(ServerHandle, FILE_PIPE_DISCONNECTED_STATE);
203 
204     /**************************************************************************/
205     /* Listen once more */
206     Okay = CheckListenPipe(&ListenContext, ServerHandle, 100);
207     ok_bool_false(Okay, "CheckListenPipe returned");
208     //blocks: CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
209 
210     /* Connect client */
211     ClientHandle = NULL;
212     Okay = CheckConnectPipe(&ConnectContext, PipePath, 100);
213     ok_bool_true(Okay, "CheckConnectPipe returned");
214     ok_eq_hex(ConnectContext.Connect.Status, STATUS_SUCCESS);
215     if (NT_SUCCESS(ConnectContext.Connect.Status))
216     {
217         ClientHandle = ConnectContext.Connect.ClientHandle;
218         CheckClient(ClientHandle, FILE_PIPE_CONNECTED_STATE);
219     }
220     Okay = WaitForWork(&ListenContext, 100);
221     ok_bool_true(Okay, "WaitForWork returned");
222     ok_eq_hex(ListenContext.Listen.Status, STATUS_SUCCESS);
223     CheckServer(ServerHandle, FILE_PIPE_CONNECTED_STATE);
224 
225     /* Close server */
226     Status = ObCloseHandle(ServerHandle, KernelMode);
227     ok_eq_hex(Status, STATUS_SUCCESS);
228     CheckClient(ClientHandle, FILE_PIPE_CLOSING_STATE);
229 
230     /* Close client */
231     if (ClientHandle)
232         ObCloseHandle(ClientHandle, KernelMode);
233 
234     FinishWorkerThread(&ListenContext);
235     FinishWorkerThread(&ConnectContext);
236 }
237 
238 static KSTART_ROUTINE RunTest;
239 static
240 VOID
241 NTAPI
RunTest(IN PVOID Context)242 RunTest(
243     IN PVOID Context)
244 {
245     NTSTATUS Status;
246     HANDLE ServerHandle;
247 
248     UNREFERENCED_PARAMETER(Context);
249 
250     ServerHandle = INVALID_HANDLE_VALUE;
251     Status = NpCreatePipe(&ServerHandle,
252                           DEVICE_NAMED_PIPE L"\\KmtestNpfsConnectTestPipe",
253                           BYTE_STREAM, QUEUE, BYTE_STREAM, DUPLEX,
254                           MAX_INSTANCES,
255                           IN_QUOTA,
256                           OUT_QUOTA);
257     ok_eq_hex(Status, STATUS_SUCCESS);
258     ok(ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "ServerHandle = %p\n", ServerHandle);
259     if (!skip(NT_SUCCESS(Status) && ServerHandle != NULL && ServerHandle != INVALID_HANDLE_VALUE, "No pipe\n"))
260     {
261         CheckServer(ServerHandle, FILE_PIPE_LISTENING_STATE);
262         TestConnect(ServerHandle, DEVICE_NAMED_PIPE L"\\KmtestNpfsConnectTestPipe");
263     }
264 }
265 
START_TEST(NpfsConnect)266 START_TEST(NpfsConnect)
267 {
268     PKTHREAD Thread;
269 
270     Thread = KmtStartThread(RunTest, NULL);
271     KmtFinishThread(Thread, NULL);
272 }
273