[GDI32_WINETEST][KERNEL32_WINETEST]
[reactos.git] / rostests / winetests / kernel32 / pipe.c
1 /*
2 * Unit tests for named pipe functions in Wine
3 *
4 * Copyright (c) 2002 Dan Kegel
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24
25 #include <windef.h>
26 #include <winbase.h>
27 #include <winsock.h>
28 #include <wtypes.h>
29 #include <winerror.h>
30
31 #include "wine/test.h"
32
33 #define PIPENAME "\\\\.\\PiPe\\tests_pipe.c"
34
35 #define NB_SERVER_LOOPS 8
36
37 static HANDLE alarm_event;
38 static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
39 SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
40 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
41
42 static BOOL user_apc_ran;
43 static void CALLBACK user_apc(ULONG_PTR param)
44 {
45 user_apc_ran = TRUE;
46 }
47
48 static void test_CreateNamedPipe(int pipemode)
49 {
50 HANDLE hnp;
51 HANDLE hFile;
52 static const char obuf[] = "Bit Bucket";
53 static const char obuf2[] = "More bits";
54 char ibuf[32], *pbuf;
55 DWORD written;
56 DWORD readden;
57 DWORD avail;
58 DWORD lpmode;
59 BOOL ret;
60
61 if (pipemode == PIPE_TYPE_BYTE)
62 trace("test_CreateNamedPipe starting in byte mode\n");
63 else
64 trace("test_CreateNamedPipe starting in message mode\n");
65 /* Bad parameter checks */
66 hnp = CreateNamedPipe("not a named pipe", PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
67 /* nMaxInstances */ 1,
68 /* nOutBufSize */ 1024,
69 /* nInBufSize */ 1024,
70 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
71 /* lpSecurityAttrib */ NULL);
72 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME,
73 "CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe\n");
74
75 hnp = CreateNamedPipe(NULL,
76 PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
77 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
78 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
79 "CreateNamedPipe should fail if name is NULL\n");
80
81 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
82 ok(hFile == INVALID_HANDLE_VALUE
83 && GetLastError() == ERROR_FILE_NOT_FOUND,
84 "connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND\n");
85
86 /* Functional checks */
87
88 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, pipemode | PIPE_WAIT,
89 /* nMaxInstances */ 1,
90 /* nOutBufSize */ 1024,
91 /* nInBufSize */ 1024,
92 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
93 /* lpSecurityAttrib */ NULL);
94 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
95
96 ret = WaitNamedPipeA(PIPENAME, 2000);
97 ok(ret, "WaitNamedPipe failed (%d)\n", GetLastError());
98
99 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
100 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
101
102 ok(!WaitNamedPipeA(PIPENAME, 1000), "WaitNamedPipe succeeded\n");
103
104 ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError());
105
106 /* don't try to do i/o if one side couldn't be opened, as it hangs */
107 if (hFile != INVALID_HANDLE_VALUE) {
108 HANDLE hFile2;
109
110 /* Make sure we can read and write a few bytes in both directions */
111 memset(ibuf, 0, sizeof(ibuf));
112 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
113 ok(written == sizeof(obuf), "write file len 1\n");
114 ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
115 ok(readden == sizeof(obuf), "peek 1 got %d bytes\n", readden);
116 ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
117 ok(readden == sizeof(obuf), "read 1 got %d bytes\n", readden);
118 ok(memcmp(obuf, ibuf, written) == 0, "content 1 check\n");
119
120 memset(ibuf, 0, sizeof(ibuf));
121 ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
122 ok(written == sizeof(obuf2), "write file len 2\n");
123 ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
124 ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
125 ok(PeekNamedPipe(hnp, (LPVOID)1, 0, NULL, &readden, NULL), "Peek\n");
126 ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
127 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
128 ok(readden == sizeof(obuf2), "read 2 got %d bytes\n", readden);
129 ok(memcmp(obuf2, ibuf, written) == 0, "content 2 check\n");
130
131 /* Test reading of multiple writes */
132 memset(ibuf, 0, sizeof(ibuf));
133 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n");
134 ok(written == sizeof(obuf), "write file len 3a\n");
135 ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile3b\n");
136 ok(written == sizeof(obuf2), "write file len 3b\n");
137 ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek3\n");
138 if (pipemode == PIPE_TYPE_BYTE) {
139 if (readden != sizeof(obuf)) /* Linux only returns the first message */
140 ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
141 else
142 todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
143 }
144 else
145 {
146 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both messages */
147 ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
148 else
149 todo_wine ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
150 }
151 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
152 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
153 pbuf = ibuf;
154 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 3a check\n");
155 if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
156 pbuf += sizeof(obuf);
157 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 3b check\n");
158 }
159 ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
160 ok(readden == sizeof(obuf) + sizeof(obuf2), "read 3 got %d bytes\n", readden);
161 pbuf = ibuf;
162 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 3a check\n");
163 pbuf += sizeof(obuf);
164 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 3b check\n");
165
166 /* Multiple writes in the reverse direction */
167 memset(ibuf, 0, sizeof(ibuf));
168 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile4a\n");
169 ok(written == sizeof(obuf), "write file len 4a\n");
170 ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile4b\n");
171 ok(written == sizeof(obuf2), "write file len 4b\n");
172 ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek4\n");
173 if (pipemode == PIPE_TYPE_BYTE) {
174 if (readden != sizeof(obuf)) /* Linux only returns the first message */
175 /* should return all 23 bytes */
176 ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
177 else
178 todo_wine ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
179 }
180 else
181 {
182 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both messages */
183 ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
184 else
185 todo_wine ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
186 }
187 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
188 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes available\n", avail);
189 pbuf = ibuf;
190 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "pipe content 4a check\n");
191 if (pipemode == PIPE_TYPE_BYTE && readden >= sizeof(obuf)+sizeof(obuf2)) {
192 pbuf += sizeof(obuf);
193 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "pipe content 4b check\n");
194 }
195 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
196 if (pipemode == PIPE_TYPE_BYTE) {
197 ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %d bytes\n", readden);
198 }
199 else {
200 todo_wine {
201 ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden);
202 }
203 }
204 pbuf = ibuf;
205 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 4a check\n");
206 if (pipemode == PIPE_TYPE_BYTE) {
207 pbuf += sizeof(obuf);
208 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 4b check\n");
209 }
210
211 /* Test reading of multiple writes after a mode change
212 (CreateFile always creates a byte mode pipe) */
213 lpmode = PIPE_READMODE_MESSAGE;
214 if (pipemode == PIPE_TYPE_BYTE) {
215 /* trying to change the client end of a byte pipe to message mode should fail */
216 ok(!SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
217 }
218 else {
219 todo_wine {
220 ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
221 }
222
223 memset(ibuf, 0, sizeof(ibuf));
224 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile5a\n");
225 ok(written == sizeof(obuf), "write file len 3a\n");
226 ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile5b\n");
227 ok(written == sizeof(obuf2), "write file len 3b\n");
228 ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek5\n");
229 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both writes */
230 ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
231 else
232 todo_wine ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
233 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
234 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
235 else
236 todo_wine ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
237 pbuf = ibuf;
238 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
239 ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
240 todo_wine {
241 ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden);
242 }
243 pbuf = ibuf;
244 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
245
246 /* Multiple writes in the reverse direction */
247 /* the write of obuf2 from write4 should still be in the buffer */
248 ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n");
249 todo_wine {
250 ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden);
251 ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail);
252 }
253 if (avail > 0) {
254 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
255 ok(readden == sizeof(obuf2), "read 6a got %d bytes\n", readden);
256 pbuf = ibuf;
257 ok(memcmp(obuf2, pbuf, sizeof(obuf2)) == 0, "content 6a check\n");
258 }
259 memset(ibuf, 0, sizeof(ibuf));
260 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile6a\n");
261 ok(written == sizeof(obuf), "write file len 6a\n");
262 ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile6b\n");
263 ok(written == sizeof(obuf2), "write file len 6b\n");
264 ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6\n");
265 if (readden != sizeof(obuf) + sizeof(obuf2)) /* MacOS returns both writes */
266 ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
267 else
268 todo_wine ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
269 if (avail != sizeof(obuf)) /* older Linux kernels only return the first write here */
270 ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %d bytes available\n", avail);
271 pbuf = ibuf;
272 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
273 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
274 todo_wine {
275 ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden);
276 }
277 pbuf = ibuf;
278 ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
279 }
280
281 /* Picky conformance tests */
282
283 /* Verify that you can't connect to pipe again
284 * until server calls DisconnectNamedPipe+ConnectNamedPipe
285 * or creates a new pipe
286 * case 1: other client not yet closed
287 */
288 hFile2 = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
289 ok(hFile2 == INVALID_HANDLE_VALUE,
290 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
291 ok(GetLastError() == ERROR_PIPE_BUSY,
292 "connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY\n");
293
294 ok(CloseHandle(hFile), "CloseHandle\n");
295
296 /* case 2: other client already closed */
297 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
298 ok(hFile == INVALID_HANDLE_VALUE,
299 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
300 ok(GetLastError() == ERROR_PIPE_BUSY,
301 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
302
303 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
304
305 /* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
306 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
307 ok(hFile == INVALID_HANDLE_VALUE,
308 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail\n");
309 ok(GetLastError() == ERROR_PIPE_BUSY,
310 "connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY\n");
311
312 /* to be complete, we'd call ConnectNamedPipe here and loop,
313 * but by default that's blocking, so we'd either have
314 * to turn on the uncommon nonblocking mode, or
315 * use another thread.
316 */
317 }
318
319 ok(CloseHandle(hnp), "CloseHandle\n");
320
321 trace("test_CreateNamedPipe returning\n");
322 }
323
324 static void test_CreateNamedPipe_instances_must_match(void)
325 {
326 HANDLE hnp, hnp2;
327
328 /* Check no mismatch */
329 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
330 /* nMaxInstances */ 2,
331 /* nOutBufSize */ 1024,
332 /* nInBufSize */ 1024,
333 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
334 /* lpSecurityAttrib */ NULL);
335 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
336
337 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
338 /* nMaxInstances */ 2,
339 /* nOutBufSize */ 1024,
340 /* nInBufSize */ 1024,
341 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
342 /* lpSecurityAttrib */ NULL);
343 ok(hnp2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
344
345 ok(CloseHandle(hnp), "CloseHandle\n");
346 ok(CloseHandle(hnp2), "CloseHandle\n");
347
348 /* Check nMaxInstances */
349 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
350 /* nMaxInstances */ 1,
351 /* nOutBufSize */ 1024,
352 /* nInBufSize */ 1024,
353 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
354 /* lpSecurityAttrib */ NULL);
355 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
356
357 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
358 /* nMaxInstances */ 1,
359 /* nOutBufSize */ 1024,
360 /* nInBufSize */ 1024,
361 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
362 /* lpSecurityAttrib */ NULL);
363 ok(hnp2 == INVALID_HANDLE_VALUE
364 && GetLastError() == ERROR_PIPE_BUSY, "nMaxInstances not obeyed\n");
365
366 ok(CloseHandle(hnp), "CloseHandle\n");
367
368 /* Check PIPE_ACCESS_* */
369 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
370 /* nMaxInstances */ 2,
371 /* nOutBufSize */ 1024,
372 /* nInBufSize */ 1024,
373 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
374 /* lpSecurityAttrib */ NULL);
375 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
376
377 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT,
378 /* nMaxInstances */ 1,
379 /* nOutBufSize */ 1024,
380 /* nInBufSize */ 1024,
381 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
382 /* lpSecurityAttrib */ NULL);
383 ok(hnp2 == INVALID_HANDLE_VALUE
384 && GetLastError() == ERROR_ACCESS_DENIED, "PIPE_ACCESS_* mismatch allowed\n");
385
386 ok(CloseHandle(hnp), "CloseHandle\n");
387
388 /* etc, etc */
389 }
390
391 /** implementation of alarm() */
392 static DWORD CALLBACK alarmThreadMain(LPVOID arg)
393 {
394 DWORD_PTR timeout = (DWORD_PTR) arg;
395 trace("alarmThreadMain\n");
396 if (WaitForSingleObject( alarm_event, timeout ) == WAIT_TIMEOUT)
397 {
398 ok(FALSE, "alarm\n");
399 ExitProcess(1);
400 }
401 return 1;
402 }
403
404 static HANDLE hnp = INVALID_HANDLE_VALUE;
405
406 /** Trivial byte echo server - disconnects after each session */
407 static DWORD CALLBACK serverThreadMain1(LPVOID arg)
408 {
409 int i;
410
411 trace("serverThreadMain1 start\n");
412 /* Set up a simple echo server */
413 hnp = CreateNamedPipe(PIPENAME "serverThreadMain1", PIPE_ACCESS_DUPLEX,
414 PIPE_TYPE_BYTE | PIPE_WAIT,
415 /* nMaxInstances */ 1,
416 /* nOutBufSize */ 1024,
417 /* nInBufSize */ 1024,
418 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
419 /* lpSecurityAttrib */ NULL);
420
421 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
422 for (i = 0; i < NB_SERVER_LOOPS; i++) {
423 char buf[512];
424 DWORD written;
425 DWORD readden;
426 DWORD success;
427
428 /* Wait for client to connect */
429 trace("Server calling ConnectNamedPipe...\n");
430 ok(ConnectNamedPipe(hnp, NULL)
431 || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
432 trace("ConnectNamedPipe returned.\n");
433
434 /* Echo bytes once */
435 memset(buf, 0, sizeof(buf));
436
437 trace("Server reading...\n");
438 success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
439 trace("Server done reading.\n");
440 ok(success, "ReadFile\n");
441 ok(readden, "short read\n");
442
443 trace("Server writing...\n");
444 ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
445 trace("Server done writing.\n");
446 ok(written == readden, "write file len\n");
447
448 /* finish this connection, wait for next one */
449 ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
450 trace("Server done flushing.\n");
451 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
452 trace("Server done disconnecting.\n");
453 }
454 return 0;
455 }
456
457 /** Trivial byte echo server - closes after each connection */
458 static DWORD CALLBACK serverThreadMain2(LPVOID arg)
459 {
460 int i;
461 HANDLE hnpNext = 0;
462
463 trace("serverThreadMain2\n");
464 /* Set up a simple echo server */
465 hnp = CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
466 PIPE_TYPE_BYTE | PIPE_WAIT,
467 /* nMaxInstances */ 2,
468 /* nOutBufSize */ 1024,
469 /* nInBufSize */ 1024,
470 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
471 /* lpSecurityAttrib */ NULL);
472 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
473
474 for (i = 0; i < NB_SERVER_LOOPS; i++) {
475 char buf[512];
476 DWORD written;
477 DWORD readden;
478 DWORD success;
479
480 user_apc_ran = FALSE;
481 if (i == 0 && pQueueUserAPC) {
482 trace("Queueing an user APC\n"); /* verify the pipe is non alerable */
483 ok(pQueueUserAPC(&user_apc, GetCurrentThread(), 0), "QueueUserAPC failed: %d\n", GetLastError());
484 }
485
486 /* Wait for client to connect */
487 trace("Server calling ConnectNamedPipe...\n");
488 ok(ConnectNamedPipe(hnp, NULL)
489 || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe\n");
490 trace("ConnectNamedPipe returned.\n");
491
492 /* Echo bytes once */
493 memset(buf, 0, sizeof(buf));
494
495 trace("Server reading...\n");
496 success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
497 trace("Server done reading.\n");
498 ok(success, "ReadFile\n");
499
500 trace("Server writing...\n");
501 ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile\n");
502 trace("Server done writing.\n");
503 ok(written == readden, "write file len\n");
504
505 /* finish this connection, wait for next one */
506 ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
507 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
508
509 ok(user_apc_ran == FALSE, "UserAPC ran, pipe using alertable io mode\n");
510
511 if (i == 0 && pQueueUserAPC)
512 SleepEx(0, TRUE); /* get rid of apc */
513
514 /* Set up next echo server */
515 hnpNext =
516 CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
517 PIPE_TYPE_BYTE | PIPE_WAIT,
518 /* nMaxInstances */ 2,
519 /* nOutBufSize */ 1024,
520 /* nInBufSize */ 1024,
521 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
522 /* lpSecurityAttrib */ NULL);
523
524 ok(hnpNext != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
525
526 ok(CloseHandle(hnp), "CloseHandle\n");
527 hnp = hnpNext;
528 }
529 return 0;
530 }
531
532 /** Trivial byte echo server - uses overlapped named pipe calls */
533 static DWORD CALLBACK serverThreadMain3(LPVOID arg)
534 {
535 int i;
536 HANDLE hEvent;
537
538 trace("serverThreadMain3\n");
539 /* Set up a simple echo server */
540 hnp = CreateNamedPipe(PIPENAME "serverThreadMain3", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
541 PIPE_TYPE_BYTE | PIPE_WAIT,
542 /* nMaxInstances */ 1,
543 /* nOutBufSize */ 1024,
544 /* nInBufSize */ 1024,
545 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
546 /* lpSecurityAttrib */ NULL);
547 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
548
549 hEvent = CreateEvent(NULL, /* security attribute */
550 TRUE, /* manual reset event */
551 FALSE, /* initial state */
552 NULL); /* name */
553 ok(hEvent != NULL, "CreateEvent\n");
554
555 for (i = 0; i < NB_SERVER_LOOPS; i++) {
556 char buf[512];
557 DWORD written;
558 DWORD readden;
559 DWORD dummy;
560 DWORD success;
561 OVERLAPPED oOverlap;
562 int letWFSOEwait = (i & 2);
563 int letGORwait = (i & 1);
564 DWORD err;
565
566 memset(&oOverlap, 0, sizeof(oOverlap));
567 oOverlap.hEvent = hEvent;
568
569 /* Wait for client to connect */
570 if (i == 0) {
571 trace("Server calling non-overlapped ConnectNamedPipe on overlapped pipe...\n");
572 success = ConnectNamedPipe(hnp, NULL);
573 err = GetLastError();
574 ok(success || (err == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed: %d\n", err);
575 trace("ConnectNamedPipe operation complete.\n");
576 } else {
577 trace("Server calling overlapped ConnectNamedPipe...\n");
578 success = ConnectNamedPipe(hnp, &oOverlap);
579 err = GetLastError();
580 ok(!success && (err == ERROR_IO_PENDING || err == ERROR_PIPE_CONNECTED), "overlapped ConnectNamedPipe\n");
581 trace("overlapped ConnectNamedPipe returned.\n");
582 if (!success && (err == ERROR_IO_PENDING)) {
583 if (letWFSOEwait)
584 {
585 DWORD ret;
586 do {
587 ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
588 } while (ret == WAIT_IO_COMPLETION);
589 ok(ret == 0, "wait ConnectNamedPipe returned %x\n", ret);
590 }
591 success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait);
592 if (!letGORwait && !letWFSOEwait && !success) {
593 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
594 success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE);
595 }
596 }
597 ok(success || (err == ERROR_PIPE_CONNECTED), "GetOverlappedResult ConnectNamedPipe\n");
598 trace("overlapped ConnectNamedPipe operation complete.\n");
599 }
600
601 /* Echo bytes once */
602 memset(buf, 0, sizeof(buf));
603
604 trace("Server reading...\n");
605 success = ReadFile(hnp, buf, sizeof(buf), &readden, &oOverlap);
606 trace("Server ReadFile returned...\n");
607 err = GetLastError();
608 ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile\n");
609 trace("overlapped ReadFile returned.\n");
610 if (!success && (err == ERROR_IO_PENDING)) {
611 if (letWFSOEwait)
612 {
613 DWORD ret;
614 do {
615 ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
616 } while (ret == WAIT_IO_COMPLETION);
617 ok(ret == 0, "wait ReadFile returned %x\n", ret);
618 }
619 success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait);
620 if (!letGORwait && !letWFSOEwait && !success) {
621 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
622 success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE);
623 }
624 }
625 trace("Server done reading.\n");
626 ok(success, "overlapped ReadFile\n");
627
628 trace("Server writing...\n");
629 success = WriteFile(hnp, buf, readden, &written, &oOverlap);
630 trace("Server WriteFile returned...\n");
631 err = GetLastError();
632 ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile\n");
633 trace("overlapped WriteFile returned.\n");
634 if (!success && (err == ERROR_IO_PENDING)) {
635 if (letWFSOEwait)
636 {
637 DWORD ret;
638 do {
639 ret = WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
640 } while (ret == WAIT_IO_COMPLETION);
641 ok(ret == 0, "wait WriteFile returned %x\n", ret);
642 }
643 success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait);
644 if (!letGORwait && !letWFSOEwait && !success) {
645 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult\n");
646 success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE);
647 }
648 }
649 trace("Server done writing.\n");
650 ok(success, "overlapped WriteFile\n");
651 ok(written == readden, "write file len\n");
652
653 /* finish this connection, wait for next one */
654 ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
655 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe\n");
656 }
657 return 0;
658 }
659
660 /** Trivial byte echo server - uses i/o completion ports */
661 static DWORD CALLBACK serverThreadMain4(LPVOID arg)
662 {
663 int i;
664 HANDLE hcompletion;
665 BOOL ret;
666
667 trace("serverThreadMain4\n");
668 /* Set up a simple echo server */
669 hnp = CreateNamedPipe(PIPENAME "serverThreadMain4", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
670 PIPE_TYPE_BYTE | PIPE_WAIT,
671 /* nMaxInstances */ 1,
672 /* nOutBufSize */ 1024,
673 /* nInBufSize */ 1024,
674 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
675 /* lpSecurityAttrib */ NULL);
676 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
677
678 hcompletion = CreateIoCompletionPort(hnp, NULL, 12345, 1);
679 ok(hcompletion != NULL, "CreateIoCompletionPort failed, error=%i\n", GetLastError());
680
681 for (i = 0; i < NB_SERVER_LOOPS; i++) {
682 char buf[512];
683 DWORD written;
684 DWORD readden;
685 DWORD dummy;
686 DWORD success;
687 OVERLAPPED oConnect;
688 OVERLAPPED oRead;
689 OVERLAPPED oWrite;
690 OVERLAPPED *oResult;
691 DWORD err;
692 ULONG_PTR compkey;
693
694 memset(&oConnect, 0, sizeof(oConnect));
695 memset(&oRead, 0, sizeof(oRead));
696 memset(&oWrite, 0, sizeof(oWrite));
697
698 /* Wait for client to connect */
699 trace("Server calling overlapped ConnectNamedPipe...\n");
700 success = ConnectNamedPipe(hnp, &oConnect);
701 err = GetLastError();
702 ok(!success && (err == ERROR_IO_PENDING || err == ERROR_PIPE_CONNECTED),
703 "overlapped ConnectNamedPipe got %u err %u\n", success, err );
704 if (!success && err == ERROR_IO_PENDING) {
705 trace("ConnectNamedPipe GetQueuedCompletionStatus\n");
706 success = GetQueuedCompletionStatus(hcompletion, &dummy, &compkey, &oResult, 0);
707 if (!success)
708 {
709 ok( GetLastError() == WAIT_TIMEOUT,
710 "ConnectNamedPipe GetQueuedCompletionStatus wrong error %u\n", GetLastError());
711 success = GetQueuedCompletionStatus(hcompletion, &dummy, &compkey, &oResult, 10000);
712 }
713 ok(success, "ConnectNamedPipe GetQueuedCompletionStatus failed, errno=%i\n", GetLastError());
714 if (success)
715 {
716 ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey);
717 ok(oResult == &oConnect, "got overlapped pointer %p instead of %p\n", oResult, &oConnect);
718 }
719 }
720 trace("overlapped ConnectNamedPipe operation complete.\n");
721
722 /* Echo bytes once */
723 memset(buf, 0, sizeof(buf));
724
725 trace("Server reading...\n");
726 success = ReadFile(hnp, buf, sizeof(buf), &readden, &oRead);
727 trace("Server ReadFile returned...\n");
728 err = GetLastError();
729 ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile, err=%i\n", err);
730 success = GetQueuedCompletionStatus(hcompletion, &readden, &compkey,
731 &oResult, 10000);
732 ok(success, "ReadFile GetQueuedCompletionStatus failed, errno=%i\n", GetLastError());
733 if (success)
734 {
735 ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey);
736 ok(oResult == &oRead, "got overlapped pointer %p instead of %p\n", oResult, &oRead);
737 }
738 trace("Server done reading.\n");
739
740 trace("Server writing...\n");
741 success = WriteFile(hnp, buf, readden, &written, &oWrite);
742 trace("Server WriteFile returned...\n");
743 err = GetLastError();
744 ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile failed, err=%u\n", err);
745 success = GetQueuedCompletionStatus(hcompletion, &written, &compkey,
746 &oResult, 10000);
747 ok(success, "WriteFile GetQueuedCompletionStatus failed, errno=%i\n", GetLastError());
748 if (success)
749 {
750 ok(compkey == 12345, "got completion key %i instead of 12345\n", (int)compkey);
751 ok(oResult == &oWrite, "got overlapped pointer %p instead of %p\n", oResult, &oWrite);
752 ok(written == readden, "write file len\n");
753 }
754 trace("Server done writing.\n");
755
756 /* finish this connection, wait for next one */
757 ok(FlushFileBuffers(hnp), "FlushFileBuffers\n");
758 success = DisconnectNamedPipe(hnp);
759 ok(success, "DisconnectNamedPipe failed, err %u\n", GetLastError());
760 }
761
762 ret = CloseHandle(hnp);
763 ok(ret, "CloseHandle named pipe failed, err=%i\n", GetLastError());
764 ret = CloseHandle(hcompletion);
765 ok(ret, "CloseHandle completion failed, err=%i\n", GetLastError());
766
767 return 0;
768 }
769
770 static void exercizeServer(const char *pipename, HANDLE serverThread)
771 {
772 int i;
773
774 trace("exercizeServer starting\n");
775 for (i = 0; i < NB_SERVER_LOOPS; i++) {
776 HANDLE hFile=INVALID_HANDLE_VALUE;
777 static const char obuf[] = "Bit Bucket";
778 char ibuf[32];
779 DWORD written;
780 DWORD readden;
781 int loop;
782
783 for (loop = 0; loop < 3; loop++) {
784 DWORD err;
785 trace("Client connecting...\n");
786 /* Connect to the server */
787 hFile = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0,
788 NULL, OPEN_EXISTING, 0, 0);
789 if (hFile != INVALID_HANDLE_VALUE)
790 break;
791 err = GetLastError();
792 if (loop == 0)
793 ok(err == ERROR_PIPE_BUSY || err == ERROR_FILE_NOT_FOUND, "connecting to pipe\n");
794 else
795 ok(err == ERROR_PIPE_BUSY, "connecting to pipe\n");
796 trace("connect failed, retrying\n");
797 Sleep(200);
798 }
799 ok(hFile != INVALID_HANDLE_VALUE, "client opening named pipe\n");
800
801 /* Make sure it can echo */
802 memset(ibuf, 0, sizeof(ibuf));
803 trace("Client writing...\n");
804 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile to client end of pipe\n");
805 ok(written == sizeof(obuf), "write file len\n");
806 trace("Client reading...\n");
807 ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile from client end of pipe\n");
808 ok(readden == sizeof(obuf), "read file len\n");
809 ok(memcmp(obuf, ibuf, written) == 0, "content check\n");
810
811 trace("Client closing...\n");
812 ok(CloseHandle(hFile), "CloseHandle\n");
813 }
814
815 ok(WaitForSingleObject(serverThread,INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject\n");
816 CloseHandle(hnp);
817 trace("exercizeServer returning\n");
818 }
819
820 static void test_NamedPipe_2(void)
821 {
822 HANDLE serverThread;
823 DWORD serverThreadId;
824 HANDLE alarmThread;
825 DWORD alarmThreadId;
826
827 trace("test_NamedPipe_2 starting\n");
828 /* Set up a twenty second timeout */
829 alarm_event = CreateEvent( NULL, TRUE, FALSE, NULL );
830 SetLastError(0xdeadbeef);
831 alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 20000, 0, &alarmThreadId);
832 ok(alarmThread != NULL, "CreateThread failed: %d\n", GetLastError());
833
834 /* The servers we're about to exercise do try to clean up carefully,
835 * but to reduce the chance of a test failure due to a pipe handle
836 * leak in the test code, we'll use a different pipe name for each server.
837 */
838
839 /* Try server #1 */
840 SetLastError(0xdeadbeef);
841 serverThread = CreateThread(NULL, 0, serverThreadMain1, (void *)8, 0, &serverThreadId);
842 ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError());
843 exercizeServer(PIPENAME "serverThreadMain1", serverThread);
844
845 /* Try server #2 */
846 SetLastError(0xdeadbeef);
847 serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId);
848 ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError());
849 exercizeServer(PIPENAME "serverThreadMain2", serverThread);
850
851 /* Try server #3 */
852 SetLastError(0xdeadbeef);
853 serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId);
854 ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError());
855 exercizeServer(PIPENAME "serverThreadMain3", serverThread);
856
857 /* Try server #4 */
858 SetLastError(0xdeadbeef);
859 serverThread = CreateThread(NULL, 0, serverThreadMain4, 0, 0, &serverThreadId);
860 ok(serverThread != NULL, "CreateThread failed: %d\n", GetLastError());
861 exercizeServer(PIPENAME "serverThreadMain4", serverThread);
862
863 ok(SetEvent( alarm_event ), "SetEvent\n");
864 CloseHandle( alarm_event );
865 trace("test_NamedPipe_2 returning\n");
866 }
867
868 static int test_DisconnectNamedPipe(void)
869 {
870 HANDLE hnp;
871 HANDLE hFile;
872 static const char obuf[] = "Bit Bucket";
873 char ibuf[32];
874 DWORD written;
875 DWORD readden;
876 DWORD ret;
877
878 SetLastError(0xdeadbeef);
879 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
880 /* nMaxInstances */ 1,
881 /* nOutBufSize */ 1024,
882 /* nInBufSize */ 1024,
883 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
884 /* lpSecurityAttrib */ NULL);
885 if ((hnp == INVALID_HANDLE_VALUE /* Win98 */ || !hnp /* Win95 */)
886 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
887
888 win_skip("Named pipes are not implemented\n");
889 return 1;
890 }
891
892 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0
893 && GetLastError() == ERROR_PIPE_LISTENING, "WriteFile to not-yet-connected pipe\n");
894 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
895 && GetLastError() == ERROR_PIPE_LISTENING, "ReadFile from not-yet-connected pipe\n");
896
897 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
898 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed\n");
899
900 /* don't try to do i/o if one side couldn't be opened, as it hangs */
901 if (hFile != INVALID_HANDLE_VALUE) {
902
903 /* see what happens if server calls DisconnectNamedPipe
904 * when there are bytes in the pipe
905 */
906
907 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
908 ok(written == sizeof(obuf), "write file len\n");
909 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting\n");
910 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0
911 && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe\n");
912 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
913 && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
914 "ReadFile from disconnected pipe with bytes waiting\n");
915 ok(!DisconnectNamedPipe(hnp) && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
916 "DisconnectNamedPipe worked twice\n");
917 ret = WaitForSingleObject(hFile, 0);
918 ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %X\n", ret);
919 ok(CloseHandle(hFile), "CloseHandle\n");
920 }
921
922 ok(CloseHandle(hnp), "CloseHandle\n");
923
924 return 0;
925 }
926 static void test_CreatePipe(void)
927 {
928 SECURITY_ATTRIBUTES pipe_attr;
929 HANDLE piperead, pipewrite;
930 DWORD written;
931 DWORD read;
932 DWORD i, size;
933 BYTE *buffer;
934 char readbuf[32];
935
936 user_apc_ran = FALSE;
937 if (pQueueUserAPC)
938 ok(pQueueUserAPC(user_apc, GetCurrentThread(), 0), "couldn't create user apc\n");
939
940 pipe_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
941 pipe_attr.bInheritHandle = TRUE;
942 pipe_attr.lpSecurityDescriptor = NULL;
943 ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
944 ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
945 ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
946 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from non empty pipe failed\n");
947 ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %d bytes\n", read);
948 ok(CloseHandle(pipewrite), "CloseHandle for the write pipe failed\n");
949 ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
950
951 /* Now write another chunk*/
952 ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
953 ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
954 ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
955 /* and close the write end, read should still succeed*/
956 ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
957 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe withe with pending data failed\n");
958 ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %d bytes\n", read);
959 /* But now we need to get informed that the pipe is closed */
960 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
961 ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
962
963 /* Try bigger chunks */
964 size = 32768;
965 buffer = HeapAlloc( GetProcessHeap(), 0, size );
966 for (i = 0; i < size; i++) buffer[i] = i;
967 ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, (size + 24)) != 0, "CreatePipe failed\n");
968 ok(WriteFile(pipewrite, buffer, size, &written, NULL), "Write to anonymous pipe failed\n");
969 ok(written == size, "Write to anonymous pipe wrote %d bytes\n", written);
970 /* and close the write end, read should still succeed*/
971 ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
972 memset( buffer, 0, size );
973 ok(ReadFile(piperead, buffer, size, &read, NULL), "Read from broken pipe withe with pending data failed\n");
974 ok(read == size, "Read from anonymous pipe got %d bytes\n", read);
975 for (i = 0; i < size; i++) ok( buffer[i] == (BYTE)i, "invalid data %x at %x\n", buffer[i], i );
976 /* But now we need to get informed that the pipe is closed */
977 ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
978 ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
979 HeapFree(GetProcessHeap(), 0, buffer);
980
981 ok(user_apc_ran == FALSE, "user apc ran, pipe using alertable io mode\n");
982 SleepEx(0, TRUE); /* get rid of apc */
983 }
984
985 struct named_pipe_client_params
986 {
987 DWORD security_flags;
988 HANDLE token;
989 BOOL revert;
990 };
991
992 #define PIPE_NAME "\\\\.\\pipe\\named_pipe_test"
993
994 static DWORD CALLBACK named_pipe_client_func(LPVOID p)
995 {
996 struct named_pipe_client_params *params = p;
997 HANDLE pipe;
998 BOOL ret;
999 const char message[] = "Test";
1000 DWORD bytes_read, bytes_written;
1001 char dummy;
1002 TOKEN_PRIVILEGES *Privileges = NULL;
1003
1004 if (params->token)
1005 {
1006 if (params->revert)
1007 {
1008 /* modify the token so we can tell if the pipe impersonation
1009 * token reverts to the process token */
1010 ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL);
1011 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
1012 }
1013 ret = SetThreadToken(NULL, params->token);
1014 ok(ret, "SetThreadToken failed with error %d\n", GetLastError());
1015 }
1016 else
1017 {
1018 DWORD Size = 0;
1019 HANDLE process_token;
1020
1021 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &process_token);
1022 ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
1023
1024 ret = GetTokenInformation(process_token, TokenPrivileges, NULL, 0, &Size);
1025 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError());
1026 Privileges = HeapAlloc(GetProcessHeap(), 0, Size);
1027 ret = GetTokenInformation(process_token, TokenPrivileges, Privileges, Size, &Size);
1028 ok(ret, "GetTokenInformation(TokenPrivileges) failed with %d\n", GetLastError());
1029
1030 ret = AdjustTokenPrivileges(process_token, TRUE, NULL, 0, NULL, NULL);
1031 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
1032
1033 CloseHandle(process_token);
1034 }
1035
1036 pipe = CreateFile(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, params->security_flags, NULL);
1037 ok(pipe != INVALID_HANDLE_VALUE, "CreateFile for pipe failed with error %d\n", GetLastError());
1038
1039 ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL);
1040 ok(ret, "WriteFile failed with error %d\n", GetLastError());
1041
1042 ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL);
1043 ok(ret, "ReadFile failed with error %d\n", GetLastError());
1044
1045 if (params->token)
1046 {
1047 if (params->revert)
1048 {
1049 ret = RevertToSelf();
1050 ok(ret, "RevertToSelf failed with error %d\n", GetLastError());
1051 }
1052 else
1053 {
1054 ret = AdjustTokenPrivileges(params->token, TRUE, NULL, 0, NULL, NULL);
1055 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
1056 }
1057 }
1058 else
1059 {
1060 HANDLE process_token;
1061
1062 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &process_token);
1063 ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
1064
1065 ret = AdjustTokenPrivileges(process_token, FALSE, Privileges, 0, NULL, NULL);
1066 ok(ret, "AdjustTokenPrivileges failed with error %d\n", GetLastError());
1067
1068 HeapFree(GetProcessHeap(), 0, Privileges);
1069
1070 CloseHandle(process_token);
1071 }
1072
1073 ret = WriteFile(pipe, message, sizeof(message), &bytes_written, NULL);
1074 ok(ret, "WriteFile failed with error %d\n", GetLastError());
1075
1076 ret = ReadFile(pipe, &dummy, sizeof(dummy), &bytes_read, NULL);
1077 ok(ret, "ReadFile failed with error %d\n", GetLastError());
1078
1079 CloseHandle(pipe);
1080
1081 return 0;
1082 }
1083
1084 static HANDLE make_impersonation_token(DWORD Access, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
1085 {
1086 HANDLE ProcessToken;
1087 HANDLE Token = NULL;
1088 BOOL ret;
1089
1090 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken);
1091 ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
1092
1093 ret = pDuplicateTokenEx(ProcessToken, Access, NULL, ImpersonationLevel, TokenImpersonation, &Token);
1094 ok(ret, "DuplicateToken failed with error %d\n", GetLastError());
1095
1096 CloseHandle(ProcessToken);
1097
1098 return Token;
1099 }
1100
1101 static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_flags, BOOL revert, void (*test_func)(int, HANDLE))
1102 {
1103 HANDLE hPipeServer;
1104 BOOL ret;
1105 DWORD dwTid;
1106 HANDLE hThread;
1107 char buffer[256];
1108 DWORD dwBytesRead;
1109 DWORD error;
1110 struct named_pipe_client_params params;
1111 char dummy = 0;
1112 DWORD dwBytesWritten;
1113 HANDLE hToken = NULL;
1114 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
1115 DWORD size;
1116
1117 hPipeServer = CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 100, 100, NMPWAIT_USE_DEFAULT_WAIT, NULL);
1118 ok(hPipeServer != INVALID_HANDLE_VALUE, "CreateNamedPipe failed with error %d\n", GetLastError());
1119
1120 params.security_flags = security_flags;
1121 params.token = hClientToken;
1122 params.revert = revert;
1123 hThread = CreateThread(NULL, 0, named_pipe_client_func, &params, 0, &dwTid);
1124 ok(hThread != NULL, "CreateThread failed with error %d\n", GetLastError());
1125
1126 SetLastError(0xdeadbeef);
1127 ret = ImpersonateNamedPipeClient(hPipeServer);
1128 error = GetLastError();
1129 ok(ret /* win2k3 */ || (error == ERROR_CANNOT_IMPERSONATE),
1130 "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError());
1131
1132 ret = ConnectNamedPipe(hPipeServer, NULL);
1133 ok(ret || (GetLastError() == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed with error %d\n", GetLastError());
1134
1135 ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL);
1136 ok(ret, "ReadFile failed with error %d\n", GetLastError());
1137
1138 ret = ImpersonateNamedPipeClient(hPipeServer);
1139 ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
1140
1141 ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken);
1142 ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
1143
1144 (*test_func)(0, hToken);
1145
1146 ImpersonationLevel = 0xdeadbeef; /* to avoid false positives */
1147 ret = GetTokenInformation(hToken, TokenImpersonationLevel, &ImpersonationLevel, sizeof(ImpersonationLevel), &size);
1148 ok(ret, "GetTokenInformation(TokenImpersonationLevel) failed with error %d\n", GetLastError());
1149 ok(ImpersonationLevel == SecurityImpersonation, "ImpersonationLevel should have been SecurityImpersonation(%d) instead of %d\n", SecurityImpersonation, ImpersonationLevel);
1150
1151 CloseHandle(hToken);
1152
1153 RevertToSelf();
1154
1155 ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL);
1156 ok(ret, "WriteFile failed with error %d\n", GetLastError());
1157
1158 ret = ReadFile(hPipeServer, buffer, sizeof(buffer), &dwBytesRead, NULL);
1159 ok(ret, "ReadFile failed with error %d\n", GetLastError());
1160
1161 ret = ImpersonateNamedPipeClient(hPipeServer);
1162 ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
1163
1164 ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken);
1165 ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
1166
1167 (*test_func)(1, hToken);
1168
1169 CloseHandle(hToken);
1170
1171 RevertToSelf();
1172
1173 ret = WriteFile(hPipeServer, &dummy, sizeof(dummy), &dwBytesWritten, NULL);
1174 ok(ret, "WriteFile failed with error %d\n", GetLastError());
1175
1176 WaitForSingleObject(hThread, INFINITE);
1177
1178 ret = ImpersonateNamedPipeClient(hPipeServer);
1179 ok(ret, "ImpersonateNamedPipeClient failed with error %d\n", GetLastError());
1180
1181 RevertToSelf();
1182
1183 CloseHandle(hThread);
1184 CloseHandle(hPipeServer);
1185 }
1186
1187 static BOOL are_all_privileges_disabled(HANDLE hToken)
1188 {
1189 BOOL ret;
1190 TOKEN_PRIVILEGES *Privileges = NULL;
1191 DWORD Size = 0;
1192 BOOL all_privs_disabled = TRUE;
1193 DWORD i;
1194
1195 ret = GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &Size);
1196 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1197 {
1198 Privileges = HeapAlloc(GetProcessHeap(), 0, Size);
1199 ret = GetTokenInformation(hToken, TokenPrivileges, Privileges, Size, &Size);
1200 if (!ret)
1201 {
1202 HeapFree(GetProcessHeap(), 0, Privileges);
1203 return FALSE;
1204 }
1205 }
1206 else
1207 return FALSE;
1208
1209 for (i = 0; i < Privileges->PrivilegeCount; i++)
1210 {
1211 if (Privileges->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
1212 {
1213 all_privs_disabled = FALSE;
1214 break;
1215 }
1216 }
1217
1218 HeapFree(GetProcessHeap(), 0, Privileges);
1219
1220 return all_privs_disabled;
1221 }
1222
1223 static DWORD get_privilege_count(HANDLE hToken)
1224 {
1225 TOKEN_STATISTICS Statistics;
1226 DWORD Size = sizeof(Statistics);
1227 BOOL ret;
1228
1229 ret = GetTokenInformation(hToken, TokenStatistics, &Statistics, Size, &Size);
1230 ok(ret, "GetTokenInformation(TokenStatistics)\n");
1231 if (!ret) return -1;
1232
1233 return Statistics.PrivilegeCount;
1234 }
1235
1236 static void test_no_sqos_no_token(int call_index, HANDLE hToken)
1237 {
1238 DWORD priv_count;
1239
1240 switch (call_index)
1241 {
1242 case 0:
1243 priv_count = get_privilege_count(hToken);
1244 todo_wine
1245 ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count);
1246 break;
1247 case 1:
1248 priv_count = get_privilege_count(hToken);
1249 ok(priv_count > 0, "privilege count should now be > 0 instead of 0\n");
1250 ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1251 break;
1252 default:
1253 ok(0, "shouldn't happen\n");
1254 }
1255 }
1256
1257 static void test_no_sqos(int call_index, HANDLE hToken)
1258 {
1259 switch (call_index)
1260 {
1261 case 0:
1262 ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1263 break;
1264 case 1:
1265 todo_wine
1266 ok(are_all_privileges_disabled(hToken), "impersonated token should have been modified\n");
1267 break;
1268 default:
1269 ok(0, "shouldn't happen\n");
1270 }
1271 }
1272
1273 static void test_static_context(int call_index, HANDLE hToken)
1274 {
1275 switch (call_index)
1276 {
1277 case 0:
1278 ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1279 break;
1280 case 1:
1281 ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1282 break;
1283 default:
1284 ok(0, "shouldn't happen\n");
1285 }
1286 }
1287
1288 static void test_dynamic_context(int call_index, HANDLE hToken)
1289 {
1290 switch (call_index)
1291 {
1292 case 0:
1293 ok(!are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1294 break;
1295 case 1:
1296 todo_wine
1297 ok(are_all_privileges_disabled(hToken), "impersonated token should have been modified\n");
1298 break;
1299 default:
1300 ok(0, "shouldn't happen\n");
1301 }
1302 }
1303
1304 static void test_dynamic_context_no_token(int call_index, HANDLE hToken)
1305 {
1306 switch (call_index)
1307 {
1308 case 0:
1309 ok(are_all_privileges_disabled(hToken), "token should be a copy of the process one\n");
1310 break;
1311 case 1:
1312 ok(!are_all_privileges_disabled(hToken), "process token modification should have been detected and impersonation token updated\n");
1313 break;
1314 default:
1315 ok(0, "shouldn't happen\n");
1316 }
1317 }
1318
1319 static void test_no_sqos_revert(int call_index, HANDLE hToken)
1320 {
1321 DWORD priv_count;
1322 switch (call_index)
1323 {
1324 case 0:
1325 priv_count = get_privilege_count(hToken);
1326 todo_wine
1327 ok(priv_count == 0, "privilege count should have been 0 instead of %d\n", priv_count);
1328 break;
1329 case 1:
1330 priv_count = get_privilege_count(hToken);
1331 ok(priv_count > 0, "privilege count should now be > 0 instead of 0\n");
1332 ok(!are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1333 break;
1334 default:
1335 ok(0, "shouldn't happen\n");
1336 }
1337 }
1338
1339 static void test_static_context_revert(int call_index, HANDLE hToken)
1340 {
1341 switch (call_index)
1342 {
1343 case 0:
1344 todo_wine
1345 ok(are_all_privileges_disabled(hToken), "privileges should have been disabled\n");
1346 break;
1347 case 1:
1348 todo_wine
1349 ok(are_all_privileges_disabled(hToken), "impersonated token should not have been modified\n");
1350 break;
1351 default:
1352 ok(0, "shouldn't happen\n");
1353 }
1354 }
1355
1356 static void test_dynamic_context_revert(int call_index, HANDLE hToken)
1357 {
1358 switch (call_index)
1359 {
1360 case 0:
1361 todo_wine
1362 ok(are_all_privileges_disabled(hToken), "privileges should have been disabled\n");
1363 break;
1364 case 1:
1365 ok(!are_all_privileges_disabled(hToken), "impersonated token should now be process token\n");
1366 break;
1367 default:
1368 ok(0, "shouldn't happen\n");
1369 }
1370 }
1371
1372 static void test_impersonation(void)
1373 {
1374 HANDLE hClientToken;
1375 HANDLE hProcessToken;
1376 BOOL ret;
1377
1378 if( !pDuplicateTokenEx ) {
1379 skip("DuplicateTokenEx not found\n");
1380 return;
1381 }
1382
1383 ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken);
1384 if (!ret)
1385 {
1386 skip("couldn't open process token, skipping impersonation tests\n");
1387 return;
1388 }
1389
1390 if (!get_privilege_count(hProcessToken) || are_all_privileges_disabled(hProcessToken))
1391 {
1392 skip("token didn't have any privileges or they were all disabled. token not suitable for impersonation tests\n");
1393 CloseHandle(hProcessToken);
1394 return;
1395 }
1396 CloseHandle(hProcessToken);
1397
1398 test_ImpersonateNamedPipeClient(NULL, 0, FALSE, test_no_sqos_no_token);
1399 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1400 test_ImpersonateNamedPipeClient(hClientToken, 0, FALSE, test_no_sqos);
1401 CloseHandle(hClientToken);
1402 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1403 test_ImpersonateNamedPipeClient(hClientToken,
1404 SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION, FALSE,
1405 test_static_context);
1406 CloseHandle(hClientToken);
1407 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1408 test_ImpersonateNamedPipeClient(hClientToken,
1409 SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1410 FALSE, test_dynamic_context);
1411 CloseHandle(hClientToken);
1412 test_ImpersonateNamedPipeClient(NULL,
1413 SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1414 FALSE, test_dynamic_context_no_token);
1415
1416 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1417 test_ImpersonateNamedPipeClient(hClientToken, 0, TRUE, test_no_sqos_revert);
1418 CloseHandle(hClientToken);
1419 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1420 test_ImpersonateNamedPipeClient(hClientToken,
1421 SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION, TRUE,
1422 test_static_context_revert);
1423 CloseHandle(hClientToken);
1424 hClientToken = make_impersonation_token(TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, SecurityImpersonation);
1425 test_ImpersonateNamedPipeClient(hClientToken,
1426 SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION,
1427 TRUE, test_dynamic_context_revert);
1428 CloseHandle(hClientToken);
1429 }
1430
1431 struct overlapped_server_args
1432 {
1433 HANDLE pipe_created;
1434 };
1435
1436 static DWORD CALLBACK overlapped_server(LPVOID arg)
1437 {
1438 OVERLAPPED ol;
1439 HANDLE pipe;
1440 int ret, err;
1441 struct overlapped_server_args *a = arg;
1442 DWORD num;
1443 char buf[100];
1444
1445 pipe = CreateNamedPipeA("\\\\.\\pipe\\my pipe", FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 0, 0, 100000, NULL);
1446 ok(pipe != NULL, "pipe NULL\n");
1447
1448 ol.hEvent = CreateEventA(0, 1, 0, 0);
1449 ok(ol.hEvent != NULL, "event NULL\n");
1450 ret = ConnectNamedPipe(pipe, &ol);
1451 err = GetLastError();
1452 ok(ret == 0, "ret %d\n", ret);
1453 ok(err == ERROR_IO_PENDING, "gle %d\n", err);
1454 SetEvent(a->pipe_created);
1455
1456 ret = WaitForSingleObjectEx(ol.hEvent, INFINITE, 1);
1457 ok(ret == WAIT_OBJECT_0, "ret %x\n", ret);
1458
1459 ret = GetOverlappedResult(pipe, &ol, &num, 1);
1460 ok(ret == 1, "ret %d\n", ret);
1461
1462 /* This should block */
1463 ret = ReadFile(pipe, buf, sizeof(buf), &num, NULL);
1464 ok(ret == 1, "ret %d\n", ret);
1465
1466 DisconnectNamedPipe(pipe);
1467 CloseHandle(ol.hEvent);
1468 CloseHandle(pipe);
1469 return 1;
1470 }
1471
1472 static void test_overlapped(void)
1473 {
1474 DWORD tid, num;
1475 HANDLE thread, pipe;
1476 BOOL ret;
1477 struct overlapped_server_args args;
1478
1479 args.pipe_created = CreateEventA(0, 1, 0, 0);
1480 thread = CreateThread(NULL, 0, overlapped_server, &args, 0, &tid);
1481
1482 WaitForSingleObject(args.pipe_created, INFINITE);
1483 pipe = CreateFileA("\\\\.\\pipe\\my pipe", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1484 ok(pipe != INVALID_HANDLE_VALUE, "cf failed\n");
1485
1486 /* Sleep to try to get the ReadFile in the server to occur before the following WriteFile */
1487 Sleep(1);
1488
1489 ret = WriteFile(pipe, "x", 1, &num, NULL);
1490 ok(ret, "WriteFile failed with error %d\n", GetLastError());
1491
1492 WaitForSingleObject(thread, INFINITE);
1493 CloseHandle(pipe);
1494 CloseHandle(args.pipe_created);
1495 CloseHandle(thread);
1496 }
1497
1498 static void test_NamedPipeHandleState(void)
1499 {
1500 HANDLE server, client;
1501 BOOL ret;
1502 DWORD state, instances, maxCollectionCount, collectDataTimeout;
1503 char userName[MAX_PATH];
1504
1505 server = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX,
1506 /* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_WAIT,
1507 /* nMaxInstances */ 1,
1508 /* nOutBufSize */ 1024,
1509 /* nInBufSize */ 1024,
1510 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
1511 /* lpSecurityAttrib */ NULL);
1512 ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
1513 ret = GetNamedPipeHandleState(server, NULL, NULL, NULL, NULL, NULL, 0);
1514 todo_wine
1515 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1516 ret = GetNamedPipeHandleState(server, &state, &instances, NULL, NULL, NULL,
1517 0);
1518 todo_wine
1519 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1520 if (ret)
1521 {
1522 ok(state == 0, "unexpected state %08x\n", state);
1523 ok(instances == 1, "expected 1 instances, got %d\n", instances);
1524 }
1525 /* Some parameters have no meaning, and therefore can't be retrieved,
1526 * on a local pipe.
1527 */
1528 SetLastError(0xdeadbeef);
1529 ret = GetNamedPipeHandleState(server, &state, &instances,
1530 &maxCollectionCount, &collectDataTimeout, userName,
1531 sizeof(userName) / sizeof(userName[0]));
1532 todo_wine
1533 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1534 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1535 /* A byte-mode pipe server can't be changed to message mode. */
1536 state = PIPE_READMODE_MESSAGE;
1537 SetLastError(0xdeadbeef);
1538 ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
1539 todo_wine
1540 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1541 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1542
1543 client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1544 OPEN_EXISTING, 0, NULL);
1545 ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
1546
1547 state = PIPE_READMODE_BYTE;
1548 ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
1549 todo_wine
1550 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1551 /* A byte-mode pipe client can't be changed to message mode, either. */
1552 state = PIPE_READMODE_MESSAGE;
1553 SetLastError(0xdeadbeef);
1554 ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
1555 todo_wine
1556 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
1557 "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
1558
1559 CloseHandle(client);
1560 CloseHandle(server);
1561
1562 server = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX,
1563 /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_WAIT,
1564 /* nMaxInstances */ 1,
1565 /* nOutBufSize */ 1024,
1566 /* nInBufSize */ 1024,
1567 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
1568 /* lpSecurityAttrib */ NULL);
1569 ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
1570 ret = GetNamedPipeHandleState(server, NULL, NULL, NULL, NULL, NULL, 0);
1571 todo_wine
1572 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1573 ret = GetNamedPipeHandleState(server, &state, &instances, NULL, NULL, NULL,
1574 0);
1575 todo_wine
1576 ok(ret, "GetNamedPipeHandleState failed: %d\n", GetLastError());
1577 if (ret)
1578 {
1579 ok(state == 0, "unexpected state %08x\n", state);
1580 ok(instances == 1, "expected 1 instances, got %d\n", instances);
1581 }
1582 /* In contrast to byte-mode pipes, a message-mode pipe server can be
1583 * changed to byte mode.
1584 */
1585 state = PIPE_READMODE_BYTE;
1586 ret = SetNamedPipeHandleState(server, &state, NULL, NULL);
1587 todo_wine
1588 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1589
1590 client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1591 OPEN_EXISTING, 0, NULL);
1592 ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
1593
1594 state = PIPE_READMODE_MESSAGE;
1595 ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
1596 todo_wine
1597 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1598 /* A message-mode pipe client can also be changed to byte mode.
1599 */
1600 state = PIPE_READMODE_BYTE;
1601 ret = SetNamedPipeHandleState(client, &state, NULL, NULL);
1602 todo_wine
1603 ok(ret, "SetNamedPipeHandleState failed: %d\n", GetLastError());
1604
1605 CloseHandle(client);
1606 CloseHandle(server);
1607 }
1608
1609 START_TEST(pipe)
1610 {
1611 HMODULE hmod;
1612
1613 hmod = GetModuleHandle("advapi32.dll");
1614 pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx");
1615 hmod = GetModuleHandle("kernel32.dll");
1616 pQueueUserAPC = (void *) GetProcAddress(hmod, "QueueUserAPC");
1617
1618 if (test_DisconnectNamedPipe())
1619 return;
1620 test_CreateNamedPipe_instances_must_match();
1621 test_NamedPipe_2();
1622 test_CreateNamedPipe(PIPE_TYPE_BYTE);
1623 test_CreateNamedPipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
1624 test_CreatePipe();
1625 test_impersonation();
1626 test_overlapped();
1627 test_NamedPipeHandleState();
1628 }