dinput: Fix printing NULL strings.
[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 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 }