widl: Print large enum constants in hex.
[wine] / dlls / ntdll / tests / 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 FILE_OVERWRITE */
151     res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 4 /*FILE_OVERWRITE*/,
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 with FILE_OVERWRITE_IF */
158     res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ, 5 /*FILE_OVERWRITE_IF*/,
159                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
160     todo_wine ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
161     if (!res)
162         CloseHandle(handle);
163
164 /* create a pipe with sharing = 0 */
165     res = pNtCreateNamedPipeFile(&handle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &attr, &iosb, 0, 2 /*FILE_CREATE*/,
166                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
167     ok(res == STATUS_INVALID_PARAMETER, "NtCreateNamedPipeFile returned %x\n", res);
168     if (!res)
169         CloseHandle(handle);
170
171 /* create a pipe without r/w access */
172     res = pNtCreateNamedPipeFile(&handle, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
173                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
174     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
175
176     res = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
177     ok(res == STATUS_ACCESS_DENIED, "NtQueryInformationFile returned %x\n", res);
178
179 /* test FILE_CREATE creation disposition */
180     res = pNtCreateNamedPipeFile(&handle2, SYNCHRONIZE, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, 2 /*FILE_CREATE*/,
181                                  0, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout);
182     todo_wine ok(res == STATUS_ACCESS_DENIED, "NtCreateNamedPipeFile returned %x\n", res);
183     if (!res)
184         CloseHandle(handle2);
185
186     CloseHandle(handle);
187 }
188
189 static void test_create(void)
190 {
191     HANDLE hserver;
192     NTSTATUS res;
193     int j, k;
194     FILE_PIPE_LOCAL_INFORMATION info;
195     IO_STATUS_BLOCK iosb;
196
197     static const DWORD access[] = { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE};
198     static const DWORD sharing[] =    { FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE };
199     static const DWORD pipe_config[]= {               1,                0,                                  2 };
200
201     for (j = 0; j < sizeof(sharing) / sizeof(DWORD); j++) {
202         for (k = 0; k < sizeof(access) / sizeof(DWORD); k++) {
203             HANDLE hclient;
204             BOOL should_succeed = TRUE;
205
206             res  = create_pipe(&hserver, sharing[j], FILE_SYNCHRONOUS_IO_NONALERT);
207             if (res) {
208                 ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res, sharing[j]);
209                 continue;
210             }
211
212             res = pNtQueryInformationFile(hserver, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
213             ok(!res, "NtQueryInformationFile for server returned %x, sharing: %x\n", res, sharing[j]);
214             ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
215                info.NamedPipeConfiguration, pipe_config[j]);
216
217             hclient = CreateFileW(testpipe, access[k], 0, 0, OPEN_EXISTING, 0, 0);
218             if (hclient != INVALID_HANDLE_VALUE) {
219                 res = pNtQueryInformationFile(hclient, &iosb, &info, sizeof(info), (FILE_INFORMATION_CLASS)24);
220                 ok(!res, "NtQueryInformationFile for client returned %x, access: %x, sharing: %x\n",
221                    res, access[k], sharing[j]);
222                 ok(info.NamedPipeConfiguration == pipe_config[j], "wrong duplex status for pipe: %d, expected %d\n",
223                    info.NamedPipeConfiguration, pipe_config[j]);
224                 CloseHandle(hclient);
225             }
226
227             if (access[k] & GENERIC_WRITE)
228                 should_succeed &= !!(sharing[j] & FILE_SHARE_WRITE);
229             if (access[k] & GENERIC_READ)
230                 should_succeed &= !!(sharing[j] & FILE_SHARE_READ);
231
232             if (should_succeed)
233                 ok(hclient != INVALID_HANDLE_VALUE, "CreateFile failed for sharing %x, access: %x, GetLastError: %d\n",
234                    sharing[j], access[k], GetLastError());
235             else
236                 ok(hclient == INVALID_HANDLE_VALUE, "CreateFile succeeded for sharing %x, access: %x\n", sharing[j], access[k]);
237
238             CloseHandle(hserver);
239         }
240     }
241 }
242
243 static BOOL ioapc_called;
244 static void CALLBACK ioapc(void *arg, PIO_STATUS_BLOCK io, ULONG reserved)
245 {
246     ioapc_called = TRUE;
247 }
248
249 static NTSTATUS listen_pipe(HANDLE hPipe, HANDLE hEvent, PIO_STATUS_BLOCK iosb, BOOL use_apc)
250 {
251     int dummy;
252
253     ioapc_called = FALSE;
254
255     return pNtFsControlFile(hPipe, hEvent, use_apc ? &ioapc: NULL, use_apc ? &dummy: NULL, iosb, FSCTL_PIPE_LISTEN, 0, 0, 0, 0);
256 }
257
258 static void test_overlapped(void)
259 {
260     IO_STATUS_BLOCK iosb;
261     HANDLE hEvent;
262     HANDLE hPipe;
263     HANDLE hClient;
264     NTSTATUS res;
265
266     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
267     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
268
269     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
270     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
271
272     memset(&iosb, 0x55, sizeof(iosb));
273
274 /* try with event and apc */
275     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
276     ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
277
278     hClient = CreateFileW(testpipe, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
279     ok(hClient != INVALID_HANDLE_VALUE, "can't open pipe, GetLastError: %x\n", GetLastError());
280
281     ok(U(iosb).Status == 0, "Wrong iostatus %x\n", U(iosb).Status);
282     ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
283
284     ok(!ioapc_called, "IOAPC ran too early\n");
285
286     SleepEx(0, TRUE); /* alertable wait state */
287
288     ok(ioapc_called, "IOAPC didn't run\n");
289
290     CloseHandle(hEvent);
291     CloseHandle(hPipe);
292     CloseHandle(hClient);
293 }
294
295 static BOOL userapc_called;
296 static void CALLBACK userapc(ULONG_PTR dwParam)
297 {
298     userapc_called = TRUE;
299 }
300
301 static BOOL open_succeeded;
302 static DWORD WINAPI thread(PVOID main_thread)
303 {
304     HANDLE h;
305
306     Sleep(400);
307
308     if (main_thread) {
309         DWORD ret;
310         userapc_called = FALSE;
311         ret = pQueueUserAPC(&userapc, main_thread, 0);
312         ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
313         CloseHandle(main_thread);
314     }
315
316     Sleep(400);
317
318     h = CreateFileW(testpipe, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
319
320     if (h != INVALID_HANDLE_VALUE) {
321         open_succeeded = TRUE;
322         Sleep(100);
323         CloseHandle(h);
324     } else
325         open_succeeded = FALSE;
326
327     return 0;
328 }
329
330 static void test_alertable(void)
331 {
332     IO_STATUS_BLOCK iosb;
333     HANDLE hEvent;
334     HANDLE hPipe;
335     NTSTATUS res;
336     HANDLE hThread;
337     DWORD ret;
338
339     memset(&iosb, 0x55, sizeof(iosb));
340
341     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
342     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
343
344     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT);
345     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
346
347 /* queue an user apc before calling listen */
348     userapc_called = FALSE;
349     ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
350     ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
351
352     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
353     todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
354
355     todo_wine ok(userapc_called, "user apc didn't run\n");
356     ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
357     todo_wine ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
358     ok(!ioapc_called, "IOAPC ran\n");
359
360 /* queue an user apc from a different thread */
361     hThread = CreateThread(NULL, 0, &thread, pOpenThread(MAXIMUM_ALLOWED, FALSE, GetCurrentThreadId()), 0, 0);
362     ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
363
364     /* wine_todo: the earlier NtFsControlFile call gets cancelled after the pipe gets set into listen state
365                   instead of before, so this NtFsControlFile will fail STATUS_INVALID_HANDLE */
366     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
367     todo_wine ok(res == STATUS_CANCELLED, "NtFsControlFile returned %x\n", res);
368
369     ok(userapc_called, "user apc didn't run\n");
370     todo_wine ok(U(iosb).Status == 0x55555555, "iosb.Status got changed to %x\n", U(iosb).Status);
371     ok(WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_TIMEOUT, "hEvent signaled\n");
372     ok(!ioapc_called, "IOAPC ran\n");
373
374     WaitForSingleObject(hThread, INFINITE);
375
376     SleepEx(0, TRUE); /* get rid of the userapc, if NtFsControlFile failed */
377
378     ok(open_succeeded, "couldn't open client side pipe\n");
379
380     CloseHandle(hThread);
381     DisconnectNamedPipe(hPipe);
382
383 /* finally try without an apc */
384     hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
385     ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
386
387     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
388     todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
389
390     ok(open_succeeded, "couldn't open client side pipe\n");
391     ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
392     todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
393
394     WaitForSingleObject(hThread, INFINITE);
395     CloseHandle(hThread);
396     CloseHandle(hEvent);
397     CloseHandle(hPipe);
398 }
399
400 static void test_nonalertable(void)
401 {
402     IO_STATUS_BLOCK iosb;
403     HANDLE hEvent;
404     HANDLE hPipe;
405     NTSTATUS res;
406     HANDLE hThread;
407     DWORD ret;
408
409     memset(&iosb, 0x55, sizeof(iosb));
410
411     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
412     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
413
414     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
415     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
416
417     hThread = CreateThread(NULL, 0, &thread, 0, 0, 0);
418     ok(hThread != INVALID_HANDLE_VALUE, "can't create thread, GetLastError: %x\n", GetLastError());
419
420     userapc_called = FALSE;
421     ret = pQueueUserAPC(&userapc, GetCurrentThread(), 0);
422     ok(ret, "can't queue user apc, GetLastError: %x\n", GetLastError());
423
424     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
425     todo_wine ok(!res, "NtFsControlFile returned %x\n", res);
426
427     ok(open_succeeded, "couldn't open client side pipe\n");
428     todo_wine ok(!U(iosb).Status, "Wrong iostatus %x\n", U(iosb).Status);
429     todo_wine ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
430
431     ok(!ioapc_called, "IOAPC ran too early\n");
432     ok(!userapc_called, "user apc ran too early\n");
433
434     SleepEx(0, TRUE); /* alertable wait state */
435
436     ok(ioapc_called, "IOAPC didn't run\n");
437     ok(userapc_called, "user apc didn't run\n");
438
439     WaitForSingleObject(hThread, INFINITE);
440     CloseHandle(hThread);
441     CloseHandle(hEvent);
442     CloseHandle(hPipe);
443 }
444
445 static void test_cancelio(void)
446 {
447     IO_STATUS_BLOCK iosb;
448     IO_STATUS_BLOCK cancel_sb;
449     HANDLE hEvent;
450     HANDLE hPipe;
451     NTSTATUS res;
452
453     hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
454     ok(hEvent != INVALID_HANDLE_VALUE, "can't create event, GetLastError: %x\n", GetLastError());
455
456     res = create_pipe(&hPipe, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* OVERLAPPED */);
457     ok(!res, "NtCreateNamedPipeFile returned %x\n", res);
458
459     memset(&iosb, 0x55, sizeof(iosb));
460
461     res = listen_pipe(hPipe, hEvent, &iosb, TRUE);
462     ok(res == STATUS_PENDING, "NtFsControlFile returned %x\n", res);
463
464     res = pNtCancelIoFile(hPipe, &cancel_sb);
465     todo_wine ok(!res, "NtCancelIoFile returned %x\n", res);
466
467     todo_wine {
468         ok(U(iosb).Status == STATUS_CANCELLED, "Wrong iostatus %x\n", U(iosb).Status);
469         ok(WaitForSingleObject(hEvent, 0) == 0, "hEvent not signaled\n");
470     }
471
472     ok(!ioapc_called, "IOAPC ran too early\n");
473
474     SleepEx(0, TRUE); /* alertable wait state */
475
476     ok(ioapc_called, "IOAPC didn't run\n");
477
478     CloseHandle(hEvent);
479     CloseHandle(hPipe);
480 }
481
482 START_TEST(pipe)
483 {
484     if (!init_func_ptrs())
485         return;
486
487     trace("starting invalid create tests\n");
488     test_create_invalid();
489
490     trace("starting create tests\n");
491     test_create();
492
493     trace("starting overlapped tests\n");
494     test_overlapped();
495
496     if (!pOpenThread || !pQueueUserAPC)
497         return;
498
499     trace("starting alertable tests\n");
500     test_alertable();
501
502     trace("starting nonalertable tests\n");
503     test_nonalertable();
504
505     trace("starting cancelio tests\n");
506     test_cancelio();
507 }