8f7bd8fe51f9fbc8a3849714a002c9699642cf7e
[reactos.git] / rostests / winetests / ntdll / pipe.c
1 /* Unit test suite for Ntdll NamedPipe API functions
2 *
3 * Copyright 2011 Bernhard Loos
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "wine/test.h"
31 #include "winternl.h"
32 #include "winioctl.h"
33
34 #ifndef __WINE_WINTERNL_H
35
36 typedef struct {
37 ULONG NamedPipeType;
38 ULONG NamedPipeConfiguration;
39 ULONG MaximumInstances;
40 ULONG CurrentInstances;
41 ULONG InboundQuota;
42 ULONG ReadDataAvailable;
43 ULONG OutboundQuota;
44 ULONG WriteQuotaAvailable;
45 ULONG NamedPipeState;
46 ULONG NamedPipeEnd;
47 } FILE_PIPE_LOCAL_INFORMATION;
48
49 #ifndef FILE_SYNCHRONOUS_IO_ALERT
50 #define FILE_SYNCHRONOUS_IO_ALERT 0x10
51 #endif
52
53 #ifndef FILE_SYNCHRONOUS_IO_NONALERT
54 #define FILE_SYNCHRONOUS_IO_NONALERT 0x20
55 #endif
56
57 #ifndef FSCTL_PIPE_LISTEN
58 #define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
59 #endif
60 #endif
61
62 static NTSTATUS (WINAPI *pNtFsControlFile) (HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, PIO_STATUS_BLOCK io, ULONG code, PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size);
63 static NTSTATUS (WINAPI *pNtCreateNamedPipeFile) (PHANDLE handle, ULONG access,
64 POBJECT_ATTRIBUTES attr, PIO_STATUS_BLOCK iosb,
65 ULONG sharing, ULONG dispo, ULONG options,
66 ULONG pipe_type, ULONG read_mode,
67 ULONG completion_mode, ULONG max_inst,
68 ULONG inbound_quota, ULONG outbound_quota,
69 PLARGE_INTEGER timeout);
70 static NTSTATUS (WINAPI *pNtQueryInformationFile) (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass);
71 static NTSTATUS (WINAPI *pNtCancelIoFile) (HANDLE hFile, PIO_STATUS_BLOCK io_status);
72 static void (WINAPI *pRtlInitUnicodeString) (PUNICODE_STRING target, PCWSTR source);
73
74 static HANDLE (WINAPI *pOpenThread)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
75 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
76
77
78 static BOOL init_func_ptrs(void)
79 {
80 HMODULE module = GetModuleHandle("ntdll.dll");
81
82 #define loadfunc(name) if (!(p##name = (void *)GetProcAddress(module, #name))) { \
83 trace("GetProcAddress(%s) failed\n", #name); \
84 return FALSE; \
85 }
86
87 loadfunc(NtFsControlFile)
88 loadfunc(NtCreateNamedPipeFile)
89 loadfunc(NtQueryInformationFile)
90 loadfunc(NtCancelIoFile)
91 loadfunc(RtlInitUnicodeString)
92
93 /* not fatal */
94 module = GetModuleHandle("kernel32.dll");
95 pOpenThread = (void *)GetProcAddress(module, "OpenThread");
96 pQueueUserAPC = (void *)GetProcAddress(module, "QueueUserAPC");
97 return TRUE;
98 }
99
100 static const WCHAR testpipe[] = { '\\', '\\', '.', '\\', 'p', 'i', 'p', 'e', '\\',
101 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
102 static const WCHAR testpipe_nt[] = { '\\', '?', '?', '\\', 'p', 'i', 'p', 'e', '\\',
103 't', 'e', 's', 't', 'p', 'i', 'p', 'e', 0 };
104
105 static NTSTATUS create_pipe(PHANDLE handle, ULONG sharing, ULONG options)
106 {
107 IO_STATUS_BLOCK iosb;
108 OBJECT_ATTRIBUTES attr;
109 UNICODE_STRING name;
110 LARGE_INTEGER timeout;
111 NTSTATUS res;
112
113 pRtlInitUnicodeString(&name, testpipe_nt);
114
115 attr.Length = sizeof(attr);
116 attr.RootDirectory = 0;
117 attr.ObjectName = &name;
118 attr.Attributes = 0x40; /*case insensitive */
119 attr.SecurityDescriptor = NULL;
120 attr.SecurityQualityOfService = NULL;
121
122 timeout.QuadPart = -100000000000ll;
123
124 res = pNtCreateNamedPipeFile(handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, sharing, 2 /*FILE_CREATE*/,
125 options, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
126 return res;
127 }
128
129 static void test_create_invalid(void)
130 {
131 IO_STATUS_BLOCK iosb;
132 OBJECT_ATTRIBUTES attr;
133 UNICODE_STRING name;
134 LARGE_INTEGER timeout;
135 NTSTATUS res;
136 HANDLE handle, handle2;
137 FILE_PIPE_LOCAL_INFORMATION info;
138
139 pRtlInitUnicodeString(&name, testpipe_nt);
140
141 attr.Length = sizeof(attr);
142 attr.RootDirectory = 0;
143 attr.ObjectName = &name;
144 attr.Attributes = 0x40; /*case insensitive */
145 attr.SecurityDescriptor = NULL;
146 attr.SecurityQualityOfService = NULL;
147
148 timeout.QuadPart = -100000000000ll;
149
150 /* create a pipe with sharing = 0 */
151 res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/,
152 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
153 todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
154 if (!res)
155 CloseHandle(handle);
156
157 /* create a pipe without r/w access */
158 res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
159 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
160 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
161
162 res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
163 todo_wine ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res);
164
165 /* test FILE_CREATE creation disposition */
166 res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
167 0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
168 todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res);
169 if (!res)
170 CloseHandle(handle2);
171
172 CloseHandle(handle);
173 }
174
175 static BOOL ioapc_called;
176 static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
177 {
178 ioapc_called = TRUE;
179 }
180
181 static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
182 {
183 int dummy;
184
185 ioapc_called = FALSE;
186
187 return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
188 }
189
190 static void test_overlapped(void)
191 {
192 IO_STATUS_BLOCK iosb;
193 HANDLE hEvent;
194 HANDLE hPipe;
195 HANDLE hClient;
196 NTSTATUS res;
197
198 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
199 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
200
201 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
202 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
203
204 memset(&iosb, 0x55, sizeof(iosb));
205
206 /* try with event and apc */
207 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
208 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
209
210 hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
211 ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError());
212
213 ok(U(iosb).Status == 0, "Wrong iostatus %x\n", U(iosb).Status);
214 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
215
216 ok(!ioapc_called, "IOAPC ran too early\n");
217
218 SleepEx(0, TRUE); /* alertable wait state */
219
220 ok(ioapc_called, "IOAPC didn't run\n");
221
222 CloseHandle(hEvent);
223 CloseHandle(hPipe);
224 CloseHandle(hClient);
225 }
226
227 static BOOL userapc_called;
228 static void CALLBACK userapc(ULONG_PTR dwParam)
229 {
230 userapc_called = TRUE;
231 }
232
233 static BOOL open_succeeded;
234 static DWORD WINAPI thread(PVOID main_thread)
235 {
236 HANDLE h;
237
238 Sleep(400);
239
240 if (main_thread) {
241 userapc_called = FALSE;
242 ok(pQueueUserAPC(&userapc, main_thread, 0), "can't queue user apc, GetLastError: %x\n", GetLastError());
243 CloseHandle(main_thread);
244 }
245
246 Sleep(400);
247
248 h = CreateFileW(testpipe, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
249
250 if (h != INVALID_HANDLE_VALUE) {
251 open_succeeded = TRUE;
252 Sleep(100);
253 CloseHandle(h);
254 } else
255 open_succeeded = FALSE;
256
257 return 0;
258 }
259
260 static void test_alertable(void)
261 {
262 IO_STATUS_BLOCK iosb;
263 HANDLE hEvent;
264 HANDLE hPipe;
265 NTSTATUS res;
266 HANDLE hThread;
267
268 memset(&iosb, 0x55, sizeof(iosb));
269
270 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
271 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
272
273 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
274 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
275
276 /* queue an user apc before calling listen */
277 userapc_called = FALSE;
278 ok(pQueueUserAPC(&userapc, GetCurrentThread(), 0), "can't queue user apc, GetLastError: %x\n", GetLastError());
279
280 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
281 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
282
283 todo_wine ok(userapc_called, "user apc didn't run\n");
284 ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
285 todo_wine ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
286 ok(!ioapc_called, "IOAPC ran\n");
287
288 /* queue an user apc from a different thread */
289 hThread = CreateThread(NULL, 0, &thread, pOpenThread(MAXIMUM_ALLOWED, FALSE, GetCurrentThreadId()), 0, 0);
290 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
291
292 /* wine_todo: the earlier NtFsControlFile call gets cancelled after the pipe gets set into listen state
293 instead of before, so this NtFsControlFile will fail STATUS_INVALID_HANDLE */
294 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
295 todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
296
297 ok(userapc_called, "user apc didn't run\n");
298 todo_wine ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
299 ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
300 ok(!ioapc_called, "IOAPC ran\n");
301
302 WaitForSingleObject(hThread, INFINITE);
303
304 SleepEx(0, TRUE); /* get rid of the userapc, if NtFsControlFile failed */
305
306 ok(open_succeeded, "couldn't open client side pipe\n");
307
308 CloseHandle(hThread);
309 DisconnectNamedPipe(hPipe);
310
311 /* finally try without an apc */
312 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
313 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
314
315 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
316 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
317
318 ok(open_succeeded, "couldn't open client side pipe\n");
319 ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
320 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
321
322 WaitForSingleObject(hThread, INFINITE);
323 CloseHandle(hThread);
324 CloseHandle(hEvent);
325 CloseHandle(hPipe);
326 }
327
328 static void test_nonalertable(void)
329 {
330 IO_STATUS_BLOCK iosb;
331 HANDLE hEvent;
332 HANDLE hPipe;
333 NTSTATUS res;
334 HANDLE hThread;
335
336 memset(&iosb, 0x55, sizeof(iosb));
337
338 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
339 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
340
341 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
342 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
343
344 hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
345 ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
346
347 userapc_called = FALSE;
348 ok(pQueueUserAPC(&userapc, GetCurrentThread(), 0), "can't queue user apc, GetLastError: %x\n", GetLastError());
349
350 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
351 todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
352
353 ok(open_succeeded, "couldn't open client side pipe\n");
354 todo_wine ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
355 todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
356
357 ok(!ioapc_called, "IOAPC ran too early\n");
358 ok(!userapc_called, "user apc ran too early\n");
359
360 SleepEx(0, TRUE); /* alertable wait state */
361
362 ok(ioapc_called, "IOAPC didn't run\n");
363 ok(userapc_called, "user apc didn't run\n");
364
365 WaitForSingleObject(hThread, INFINITE);
366 CloseHandle(hThread);
367 CloseHandle(hEvent);
368 CloseHandle(hPipe);
369 }
370
371 static void test_cancelio(void)
372 {
373 IO_STATUS_BLOCK iosb;
374 IO_STATUS_BLOCK cancel_sb;
375 HANDLE hEvent;
376 HANDLE hPipe;
377 NTSTATUS res;
378
379 hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
380 ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
381
382 res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
383 ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
384
385 memset(&iosb, 0x55, sizeof(iosb));
386
387 res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
388 ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
389
390 res = pNtCancelIoFile(hPipe, &cancel_sb);
391 todo_wine ok(!res, "NtCancelIoFile returned %x\n", res);
392
393 todo_wine {
394 ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
395 ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
396 }
397
398 ok(!ioapc_called, "IOAPC ran too early\n");
399
400 SleepEx(0, TRUE); /* alertable wait state */
401
402 ok(ioapc_called, "IOAPC didn't run\n");
403
404 CloseHandle(hEvent);
405 CloseHandle(hPipe);
406 }
407
408 START_TEST(pipe)
409 {
410 if (!init_func_ptrs())
411 return;
412
413 trace("starting invalid create tests\n");
414 test_create_invalid();
415
416 trace("starting overlapped tests\n");
417 test_overlapped();
418
419 if (!pOpenThread || !pQueueUserAPC)
420 return;
421
422 trace("starting alertable tests\n");
423 test_alertable();
424
425 trace("starting nonalertable tests\n");
426 test_nonalertable();
427
428 trace("starting cancelio tests\n");
429 test_cancelio();
430 }