1 /* Unit test suite for Ntdll NamedPipe API functions
3 * Copyright 2011 Bernhard Loos
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.
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.
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
24 #define WIN32_NO_STATUS
30 #include "wine/test.h"
34 #ifndef __WINE_WINTERNL_H
38 ULONG NamedPipeConfiguration
;
39 ULONG MaximumInstances
;
40 ULONG CurrentInstances
;
42 ULONG ReadDataAvailable
;
44 ULONG WriteQuotaAvailable
;
47 } FILE_PIPE_LOCAL_INFORMATION
;
49 #ifndef FILE_SYNCHRONOUS_IO_ALERT
50 #define FILE_SYNCHRONOUS_IO_ALERT 0x10
53 #ifndef FILE_SYNCHRONOUS_IO_NONALERT
54 #define FILE_SYNCHRONOUS_IO_NONALERT 0x20
57 #ifndef FSCTL_PIPE_LISTEN
58 #define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
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
);
74 static HANDLE (WINAPI
*pOpenThread
)(DWORD dwDesiredAccess
, BOOL bInheritHandle
, DWORD dwThreadId
);
75 static DWORD (WINAPI
*pQueueUserAPC
)(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
);
78 static BOOL
init_func_ptrs(void)
80 HMODULE module
= GetModuleHandle("ntdll.dll");
82 #define loadfunc(name) if (!(p##name = (void *)GetProcAddress(module, #name))) { \
83 trace("GetProcAddress(%s) failed\n", #name); \
87 loadfunc(NtFsControlFile
)
88 loadfunc(NtCreateNamedPipeFile
)
89 loadfunc(NtQueryInformationFile
)
90 loadfunc(NtCancelIoFile
)
91 loadfunc(RtlInitUnicodeString
)
94 module
= GetModuleHandle("kernel32.dll");
95 pOpenThread
= (void *)GetProcAddress(module
, "OpenThread");
96 pQueueUserAPC
= (void *)GetProcAddress(module
, "QueueUserAPC");
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 };
105 static NTSTATUS
create_pipe(PHANDLE handle
, ULONG sharing
, ULONG options
)
107 IO_STATUS_BLOCK iosb
;
108 OBJECT_ATTRIBUTES attr
;
110 LARGE_INTEGER timeout
;
113 pRtlInitUnicodeString(&name
, testpipe_nt
);
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
;
122 timeout
.QuadPart
= -100000000000ll;
124 res
= pNtCreateNamedPipeFile(handle
, FILE_READ_ATTRIBUTES
| SYNCHRONIZE
, &attr
, &iosb
, sharing
, 2 /*FILE_CREATE*/,
125 options
, 1, 0, 0, 0xFFFFFFFF, 500, 500, &timeout
);
129 static void test_create_invalid(void)
131 IO_STATUS_BLOCK iosb
;
132 OBJECT_ATTRIBUTES attr
;
134 LARGE_INTEGER timeout
;
136 HANDLE handle
, handle2
;
137 FILE_PIPE_LOCAL_INFORMATION info
;
139 pRtlInitUnicodeString(&name
, testpipe_nt
);
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
;
148 timeout
.QuadPart
= -100000000000ll;
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
);
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
);
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
);
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
);
176 res
= pNtQueryInformationFile(handle
, &iosb
, &info
, sizeof(info
), (FILE_INFORMATION_CLASS
)24);
177 ok(res
== STATUS_ACCESS_DENIED
, "NtQueryInformationFile returned %x\n", res
);
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
);
184 CloseHandle(handle2
);
189 static void test_create(void)
194 FILE_PIPE_LOCAL_INFORMATION info
;
195 IO_STATUS_BLOCK iosb
;
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 };
201 for (j
= 0; j
< sizeof(sharing
) / sizeof(DWORD
); j
++) {
202 for (k
= 0; k
< sizeof(access
) / sizeof(DWORD
); k
++) {
204 BOOL should_succeed
= TRUE
;
206 res
= create_pipe(&hserver
, sharing
[j
], FILE_SYNCHRONOUS_IO_NONALERT
);
208 ok(0, "NtCreateNamedPipeFile returned %x, sharing: %x\n", res
, sharing
[j
]);
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
]);
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
);
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
);
233 ok(hclient
!= INVALID_HANDLE_VALUE
, "CreateFile failed for sharing %x, access: %x, GetLastError: %d\n",
234 sharing
[j
], access
[k
], GetLastError());
236 ok(hclient
== INVALID_HANDLE_VALUE
, "CreateFile succeeded for sharing %x, access: %x\n", sharing
[j
], access
[k
]);
238 CloseHandle(hserver
);
243 static BOOL ioapc_called
;
244 static void CALLBACK
ioapc(void *arg
, PIO_STATUS_BLOCK io
, ULONG reserved
)
249 static NTSTATUS
listen_pipe(HANDLE hPipe
, HANDLE hEvent
, PIO_STATUS_BLOCK iosb
, BOOL use_apc
)
253 ioapc_called
= FALSE
;
255 return pNtFsControlFile(hPipe
, hEvent
, use_apc
? &ioapc
: NULL
, use_apc
? &dummy
: NULL
, iosb
, FSCTL_PIPE_LISTEN
, 0, 0, 0, 0);
258 static void test_overlapped(void)
260 IO_STATUS_BLOCK iosb
;
266 hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
267 ok(hEvent
!= INVALID_HANDLE_VALUE
, "can't create event, GetLastError: %x\n", GetLastError());
269 res
= create_pipe(&hPipe
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, 0 /* OVERLAPPED */);
270 ok(!res
, "NtCreateNamedPipeFile returned %x\n", res
);
272 memset(&iosb
, 0x55, sizeof(iosb
));
274 /* try with event and apc */
275 res
= listen_pipe(hPipe
, hEvent
, &iosb
, TRUE
);
276 ok(res
== STATUS_PENDING
, "NtFsControlFile returned %x\n", res
);
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());
281 ok(U(iosb
).Status
== 0, "Wrong iostatus %x\n", U(iosb
).Status
);
282 ok(WaitForSingleObject(hEvent
, 0) == 0, "hEvent not signaled\n");
284 ok(!ioapc_called
, "IOAPC ran too early\n");
286 SleepEx(0, TRUE
); /* alertable wait state */
288 ok(ioapc_called
, "IOAPC didn't run\n");
292 CloseHandle(hClient
);
295 static BOOL userapc_called
;
296 static void CALLBACK
userapc(ULONG_PTR dwParam
)
298 userapc_called
= TRUE
;
301 static BOOL open_succeeded
;
302 static DWORD WINAPI
thread(PVOID main_thread
)
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
);
318 h
= CreateFileW(testpipe
, GENERIC_WRITE
| GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0);
320 if (h
!= INVALID_HANDLE_VALUE
) {
321 open_succeeded
= TRUE
;
325 open_succeeded
= FALSE
;
330 static void test_alertable(void)
332 IO_STATUS_BLOCK iosb
;
339 memset(&iosb
, 0x55, sizeof(iosb
));
341 hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
342 ok(hEvent
!= INVALID_HANDLE_VALUE
, "can't create event, GetLastError: %x\n", GetLastError());
344 res
= create_pipe(&hPipe
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, FILE_SYNCHRONOUS_IO_ALERT
);
345 ok(!res
, "NtCreateNamedPipeFile returned %x\n", res
);
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());
352 res
= listen_pipe(hPipe
, hEvent
, &iosb
, TRUE
);
353 todo_wine
ok(res
== STATUS_CANCELLED
, "NtFsControlFile returned %x\n", res
);
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");
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());
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
);
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");
374 WaitForSingleObject(hThread
, INFINITE
);
376 SleepEx(0, TRUE
); /* get rid of the userapc, if NtFsControlFile failed */
378 ok(open_succeeded
, "couldn't open client side pipe\n");
380 CloseHandle(hThread
);
381 DisconnectNamedPipe(hPipe
);
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());
387 res
= listen_pipe(hPipe
, hEvent
, &iosb
, TRUE
);
388 todo_wine
ok(!res
, "NtFsControlFile returned %x\n", res
);
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");
394 WaitForSingleObject(hThread
, INFINITE
);
395 CloseHandle(hThread
);
400 static void test_nonalertable(void)
402 IO_STATUS_BLOCK iosb
;
409 memset(&iosb
, 0x55, sizeof(iosb
));
411 hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
412 ok(hEvent
!= INVALID_HANDLE_VALUE
, "can't create event, GetLastError: %x\n", GetLastError());
414 res
= create_pipe(&hPipe
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, FILE_SYNCHRONOUS_IO_NONALERT
);
415 ok(!res
, "NtCreateNamedPipeFile returned %x\n", res
);
417 hThread
= CreateThread(NULL
, 0, &thread
, 0, 0, 0);
418 ok(hThread
!= INVALID_HANDLE_VALUE
, "can't create thread, GetLastError: %x\n", GetLastError());
420 userapc_called
= FALSE
;
421 ret
= pQueueUserAPC(&userapc
, GetCurrentThread(), 0);
422 ok(ret
, "can't queue user apc, GetLastError: %x\n", GetLastError());
424 res
= listen_pipe(hPipe
, hEvent
, &iosb
, TRUE
);
425 todo_wine
ok(!res
, "NtFsControlFile returned %x\n", res
);
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");
431 ok(!ioapc_called
, "IOAPC ran too early\n");
432 ok(!userapc_called
, "user apc ran too early\n");
434 SleepEx(0, TRUE
); /* alertable wait state */
436 ok(ioapc_called
, "IOAPC didn't run\n");
437 ok(userapc_called
, "user apc didn't run\n");
439 WaitForSingleObject(hThread
, INFINITE
);
440 CloseHandle(hThread
);
445 static void test_cancelio(void)
447 IO_STATUS_BLOCK iosb
;
448 IO_STATUS_BLOCK cancel_sb
;
453 hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
454 ok(hEvent
!= INVALID_HANDLE_VALUE
, "can't create event, GetLastError: %x\n", GetLastError());
456 res
= create_pipe(&hPipe
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, 0 /* OVERLAPPED */);
457 ok(!res
, "NtCreateNamedPipeFile returned %x\n", res
);
459 memset(&iosb
, 0x55, sizeof(iosb
));
461 res
= listen_pipe(hPipe
, hEvent
, &iosb
, TRUE
);
462 ok(res
== STATUS_PENDING
, "NtFsControlFile returned %x\n", res
);
464 res
= pNtCancelIoFile(hPipe
, &cancel_sb
);
465 todo_wine
ok(!res
, "NtCancelIoFile returned %x\n", res
);
468 ok(U(iosb
).Status
== STATUS_CANCELLED
, "Wrong iostatus %x\n", U(iosb
).Status
);
469 ok(WaitForSingleObject(hEvent
, 0) == 0, "hEvent not signaled\n");
472 ok(!ioapc_called
, "IOAPC ran too early\n");
474 SleepEx(0, TRUE
); /* alertable wait state */
476 ok(ioapc_called
, "IOAPC didn't run\n");
484 if (!init_func_ptrs())
487 trace("starting invalid create tests\n");
488 test_create_invalid();
490 trace("starting create tests\n");
493 trace("starting overlapped tests\n");
496 if (!pOpenThread
|| !pQueueUserAPC
)
499 trace("starting alertable tests\n");
502 trace("starting nonalertable tests\n");
505 trace("starting cancelio tests\n");