update for HEAD-2003091401
[reactos.git] / apps / tests / pipe / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <time.h>
24 #include <assert.h>
25
26 #ifndef STANDALONE
27 #include "wine/test.h"
28 #else
29 #include <assert.h>
30 #define START_TEST(name) main(int argc, char **argv)
31 #define ok(condition, msg) assert(condition)
32 #define todo_wine
33 #endif
34
35 #ifndef STANDALONE
36 #include <wtypes.h>
37 #include <windef.h>
38 #include <winbase.h>
39 #include <winerror.h>
40 #else
41 #include <windows.h>
42 #endif
43
44 #define PIPENAME "\\\\.\\PiPe\\tests_" __FILE__
45
46 static void msg(const char *s)
47 {
48     DWORD cbWritten;
49     WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), s, strlen(s), &cbWritten, NULL);
50 }
51
52 void test_CreateNamedPipe(void)
53 {
54     HANDLE hnp;
55     HANDLE hFile;
56     const char obuf[] = "Bit Bucket";
57     char ibuf[32];
58     DWORD written;
59     DWORD readden;
60
61     msg("test_CreateNamedPipe starting\n");
62     /* Bad parameter checks */
63     hnp = CreateNamedPipe("not a named pipe", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
64         /* nMaxInstances */ 1,
65         /* nOutBufSize */ 1024,
66         /* nInBufSize */ 1024,
67         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
68         /* lpSecurityAttrib */ NULL);
69
70     if (hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
71         /* Is this the right way to notify user of skipped tests? */
72         ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
73             "CreateNamedPipe not supported on this platform, skipping tests.");
74         return;
75     }
76     ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME,
77         "CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe");
78
79     hnp = CreateNamedPipe(NULL,
80         PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
81         1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
82     ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
83         "CreateNamedPipe should fail if name is NULL");
84
85     hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
86     ok(hFile == INVALID_HANDLE_VALUE
87         && GetLastError() == ERROR_FILE_NOT_FOUND,
88         "connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND");
89
90     /* Functional checks */
91
92     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
93         /* nMaxInstances */ 1,
94         /* nOutBufSize */ 1024,
95         /* nInBufSize */ 1024,
96         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
97         /* lpSecurityAttrib */ NULL);
98     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
99
100     hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
101     todo_wine {
102         ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed");
103     }
104
105     /* don't try to do i/o if one side couldn't be opened, as it hangs */
106     if (hFile != INVALID_HANDLE_VALUE) {
107         HANDLE hFile2;
108
109         /* Make sure we can read and write a few bytes in both directions */
110         memset(ibuf, 0, sizeof(ibuf));
111         ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile");
112         ok(written == sizeof(obuf), "write file len");
113         ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile");
114         ok(readden == sizeof(obuf), "read file len");
115         ok(memcmp(obuf, ibuf, written) == 0, "content check");
116
117         memset(ibuf, 0, sizeof(ibuf));
118         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile");
119         ok(written == sizeof(obuf), "write file len");
120         ok(ReadFile(hnp, ibuf, sizeof(obuf), &readden, NULL), "ReadFile");
121         ok(readden == sizeof(obuf), "read file len");
122         ok(memcmp(obuf, ibuf, written) == 0, "content check");
123
124         /* Picky conformance tests */
125
126         /* Verify that you can't connect to pipe again
127          * until server calls DisconnectNamedPipe+ConnectNamedPipe
128          * or creates a new pipe
129          * case 1: other client not yet closed
130          */
131         hFile2 = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
132         ok(hFile2 == INVALID_HANDLE_VALUE,
133             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
134         ok(GetLastError() == ERROR_PIPE_BUSY,
135             "connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY");
136
137         ok(CloseHandle(hFile), "CloseHandle");
138
139         /* case 2: other client already closed */
140         hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
141         ok(hFile == INVALID_HANDLE_VALUE,
142             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
143         ok(GetLastError() == ERROR_PIPE_BUSY,
144             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY");
145
146         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
147
148         /* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
149         hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
150         ok(hFile == INVALID_HANDLE_VALUE,
151             "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
152         ok(GetLastError() == ERROR_PIPE_BUSY,
153             "connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY");
154
155         /* to be complete, we'd call ConnectNamedPipe here and loop,
156          * but by default that's blocking, so we'd either have
157          * to turn on the uncommon nonblocking mode, or
158          * use another thread.
159          */
160     }
161
162     ok(CloseHandle(hnp), "CloseHandle");
163
164     msg("test_CreateNamedPipe returning\n");
165 }
166
167 void test_CreateNamedPipe_instances_must_match(void)
168 {
169     HANDLE hnp, hnp2;
170
171     /* Check no mismatch */
172     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
173         /* nMaxInstances */ 2,
174         /* nOutBufSize */ 1024,
175         /* nInBufSize */ 1024,
176         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
177         /* lpSecurityAttrib */ NULL);
178     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
179
180     hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
181         /* nMaxInstances */ 2,
182         /* nOutBufSize */ 1024,
183         /* nInBufSize */ 1024,
184         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
185         /* lpSecurityAttrib */ NULL);
186     ok(hnp2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
187
188     ok(CloseHandle(hnp), "CloseHandle");
189     ok(CloseHandle(hnp2), "CloseHandle");
190
191     /* Check nMaxInstances */
192     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
193         /* nMaxInstances */ 1,
194         /* nOutBufSize */ 1024,
195         /* nInBufSize */ 1024,
196         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
197         /* lpSecurityAttrib */ NULL);
198     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
199
200     todo_wine {
201         hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
202             /* nMaxInstances */ 1,
203             /* nOutBufSize */ 1024,
204             /* nInBufSize */ 1024,
205             /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
206             /* lpSecurityAttrib */ NULL);
207         ok(hnp2 == INVALID_HANDLE_VALUE
208             && GetLastError() == ERROR_PIPE_BUSY, "nMaxInstances not obeyed");
209     }
210
211     ok(CloseHandle(hnp), "CloseHandle");
212
213     /* Check PIPE_ACCESS_* */
214     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
215         /* nMaxInstances */ 2,
216         /* nOutBufSize */ 1024,
217         /* nInBufSize */ 1024,
218         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
219         /* lpSecurityAttrib */ NULL);
220     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
221
222     todo_wine {
223         hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT,
224             /* nMaxInstances */ 1,
225             /* nOutBufSize */ 1024,
226             /* nInBufSize */ 1024,
227             /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
228             /* lpSecurityAttrib */ NULL);
229         ok(hnp2 == INVALID_HANDLE_VALUE
230             && GetLastError() == ERROR_ACCESS_DENIED, "PIPE_ACCESS_* mismatch allowed");
231     }
232
233     ok(CloseHandle(hnp), "CloseHandle");
234
235     /* etc, etc */
236 }
237
238 /** implementation of alarm() */
239 static DWORD CALLBACK alarmThreadMain(LPVOID arg)
240 {
241     DWORD timeout = (DWORD) arg;
242     msg("alarmThreadMain\n");
243     Sleep(timeout);
244     ok(FALSE, "alarm");
245     ExitProcess(1);
246     return 1;
247 }
248
249 HANDLE hnp = INVALID_HANDLE_VALUE;
250
251 /** Trivial byte echo server - disconnects after each session */
252 static DWORD CALLBACK serverThreadMain1(LPVOID arg)
253 {
254     int i;
255
256     msg("serverThreadMain1 start\n");
257     /* Set up a simple echo server */
258     hnp = CreateNamedPipe(PIPENAME "serverThreadMain1", PIPE_ACCESS_DUPLEX,
259         PIPE_TYPE_BYTE | PIPE_WAIT,
260         /* nMaxInstances */ 1,
261         /* nOutBufSize */ 1024,
262         /* nInBufSize */ 1024,
263         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
264         /* lpSecurityAttrib */ NULL);
265
266     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
267     for (i = 0; ; i++) {
268         char buf[512];
269         DWORD written;
270         DWORD readden;
271         DWORD success;
272
273         /* Wait for client to connect */
274         msg("Server calling ConnectNamedPipe...\n");
275         ok(ConnectNamedPipe(hnp, NULL)
276             || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe");
277         msg("ConnectNamedPipe returned.\n");
278
279         /* Echo bytes once */
280         memset(buf, 0, sizeof(buf));
281
282         msg("Server reading...\n");
283         success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
284         msg("Server done reading.\n");
285         ok(success, "ReadFile");
286
287         msg("Server writing...\n");
288         ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile");
289         msg("Server done writing.\n");
290         ok(written == readden, "write file len");
291
292         /* finish this connection, wait for next one */
293         ok(FlushFileBuffers(hnp), "FlushFileBuffers");
294         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
295     }
296 }
297
298 /** Trivial byte echo server - closes after each connection */
299 static DWORD CALLBACK serverThreadMain2(LPVOID arg)
300 {
301     int i;
302     HANDLE hnpNext = 0;
303
304     msg("serverThreadMain2\n");
305     /* Set up a simple echo server */
306     hnp = CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
307         PIPE_TYPE_BYTE | PIPE_WAIT,
308         /* nMaxInstances */ 2,
309         /* nOutBufSize */ 1024,
310         /* nInBufSize */ 1024,
311         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
312         /* lpSecurityAttrib */ NULL);
313     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
314
315     for (i = 0; ; i++) {
316         char buf[512];
317         DWORD written;
318         DWORD readden;
319         DWORD success;
320
321         /* Wait for client to connect */
322         msg("Server calling ConnectNamedPipe...\n");
323         ok(ConnectNamedPipe(hnp, NULL)
324             || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe");
325         msg("ConnectNamedPipe returned.\n");
326
327         /* Echo bytes once */
328         memset(buf, 0, sizeof(buf));
329
330         msg("Server reading...\n");
331         success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
332         msg("Server done reading.\n");
333         ok(success, "ReadFile");
334
335         msg("Server writing...\n");
336         ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile");
337         msg("Server done writing.\n");
338         ok(written == readden, "write file len");
339
340         /* finish this connection, wait for next one */
341         ok(FlushFileBuffers(hnp), "FlushFileBuffers");
342         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
343
344         /* Set up next echo server */
345         hnpNext =
346             CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
347             PIPE_TYPE_BYTE | PIPE_WAIT,
348             /* nMaxInstances */ 2,
349             /* nOutBufSize */ 1024,
350             /* nInBufSize */ 1024,
351             /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
352             /* lpSecurityAttrib */ NULL);
353
354         ok(hnpNext != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
355
356         ok(CloseHandle(hnp), "CloseHandle");
357         hnp = hnpNext;
358     }
359 }
360
361 /** Trivial byte echo server - uses overlapped named pipe calls */
362 static DWORD CALLBACK serverThreadMain3(LPVOID arg)
363 {
364     int i;
365     HANDLE hEvent;
366
367     msg("serverThreadMain3\n");
368     /* Set up a simple echo server */
369     hnp = CreateNamedPipe(PIPENAME "serverThreadMain3", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
370         PIPE_TYPE_BYTE | PIPE_WAIT,
371         /* nMaxInstances */ 1,
372         /* nOutBufSize */ 1024,
373         /* nInBufSize */ 1024,
374         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
375         /* lpSecurityAttrib */ NULL);
376     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
377
378     hEvent = CreateEvent(NULL,  // security attribute
379         TRUE,                   // manual reset event 
380         FALSE,                  // initial state 
381         NULL);                  // name
382     ok(hEvent != NULL, "CreateEvent");
383
384     for (i = 0; ; i++) {
385         char buf[512];
386         DWORD written;
387         DWORD readden;
388         DWORD dummy;
389         DWORD success;
390         OVERLAPPED oOverlap;
391         int letWFSOEwait = (i & 2);
392         int letGORwait = (i & 1);
393         DWORD err;
394
395         memset(&oOverlap, 0, sizeof(oOverlap));
396         oOverlap.hEvent = hEvent;
397
398         /* Wait for client to connect */
399         msg("Server calling overlapped ConnectNamedPipe...\n");
400         success = ConnectNamedPipe(hnp, &oOverlap);
401         err = GetLastError();
402         ok(success || err == ERROR_IO_PENDING
403             || err == ERROR_PIPE_CONNECTED, "overlapped ConnectNamedPipe");
404         msg("overlapped ConnectNamedPipe returned.\n");
405         if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
406             ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ConnectNamedPipe");
407         success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait);
408         if (!letGORwait && !letWFSOEwait && !success) {
409             ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
410             success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE);
411         }
412         ok(success, "GetOverlappedResult ConnectNamedPipe");
413         msg("overlapped ConnectNamedPipe operation complete.\n");
414
415         /* Echo bytes once */
416         memset(buf, 0, sizeof(buf));
417
418         msg("Server reading...\n");
419         success = ReadFile(hnp, buf, sizeof(buf), NULL, &oOverlap);
420         msg("Server ReadFile returned...\n");
421         err = GetLastError();
422         ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile");
423         msg("overlapped ReadFile returned.\n");
424         if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
425             ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ReadFile");
426         success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait);
427         if (!letGORwait && !letWFSOEwait && !success) {
428             ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
429             success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE);
430         }
431         msg("Server done reading.\n");
432         ok(success, "overlapped ReadFile");
433
434         msg("Server writing...\n");
435         success = WriteFile(hnp, buf, readden, NULL, &oOverlap);
436         msg("Server WriteFile returned...\n");
437         err = GetLastError();
438         ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile");
439         msg("overlapped WriteFile returned.\n");
440         if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
441             ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait WriteFile");
442         success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait);
443         if (!letGORwait && !letWFSOEwait && !success) {
444             ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
445             success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE);
446         }
447         msg("Server done writing.\n");
448         ok(success, "overlapped WriteFile");
449         ok(written == readden, "write file len");
450
451         /* finish this connection, wait for next one */
452         ok(FlushFileBuffers(hnp), "FlushFileBuffers");
453         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
454     }
455 }
456
457 static void exercizeServer(const char *pipename, HANDLE serverThread)
458 {
459     int i;
460
461     msg("exercizeServer starting\n");
462     for (i = 0; i < 8; i++) {
463         HANDLE hFile;
464         const char obuf[] = "Bit Bucket";
465         char ibuf[32];
466         DWORD written;
467         DWORD readden;
468         int loop;
469
470         for (loop = 0; loop < 3; loop++) {
471             DWORD err;
472             msg("Client connecting...\n");
473             /* Connect to the server */
474             hFile = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0,
475                 NULL, OPEN_EXISTING, 0, 0);
476             if (hFile != INVALID_HANDLE_VALUE)
477                 break;
478             err = GetLastError();
479             if (loop == 0)
480                 ok(err == ERROR_PIPE_BUSY || err == ERROR_FILE_NOT_FOUND, "connecting to pipe");
481             else
482                 ok(err == ERROR_PIPE_BUSY, "connecting to pipe");
483             msg("connect failed, retrying\n");
484             Sleep(200);
485         }
486         ok(hFile != INVALID_HANDLE_VALUE, "client opening named pipe");
487
488         /* Make sure it can echo */
489         memset(ibuf, 0, sizeof(ibuf));
490         msg("Client writing...\n");
491         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile to client end of pipe");
492         ok(written == sizeof(obuf), "write file len");
493         msg("Client reading...\n");
494         ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile from client end of pipe");
495         ok(readden == sizeof(obuf), "read file len");
496         ok(memcmp(obuf, ibuf, written) == 0, "content check");
497
498         msg("Client closing...\n");
499         ok(CloseHandle(hFile), "CloseHandle");
500     }
501
502     ok(TerminateThread(serverThread, 0), "TerminateThread");
503     CloseHandle(hnp);
504     msg("exercizeServer returning\n");
505 }
506
507 void test_NamedPipe_2(void)
508 {
509     HANDLE serverThread;
510     DWORD serverThreadId;
511     HANDLE alarmThread;
512     DWORD alarmThreadId;
513
514     msg("test_NamedPipe_2 starting\n");
515     /* Set up a ten second timeout */
516     alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 10000, 0, &alarmThreadId);
517
518     /* The servers we're about to exercize do try to clean up carefully,
519      * but to reduce the change of a test failure due to a pipe handle
520      * leak in the test code, we'll use a different pipe name for each server.
521      */
522
523     /* Try server #1 */
524     serverThread = CreateThread(NULL, 0, serverThreadMain1, 0, 0, &serverThreadId);
525     ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
526     exercizeServer(PIPENAME "serverThreadMain1", serverThread);
527
528     /* Try server #2 */
529     serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId);
530     ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
531     exercizeServer(PIPENAME "serverThreadMain2", serverThread);
532
533     /* Try server #3 */
534     serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId);
535     ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
536     exercizeServer(PIPENAME "serverThreadMain3", serverThread);
537
538     ok(TerminateThread(alarmThread, 0), "TerminateThread");
539     msg("test_NamedPipe_2 returning\n");
540 }
541
542 void test_DisconnectNamedPipe(void)
543 {
544     HANDLE hnp;
545     HANDLE hFile;
546     const char obuf[] = "Bit Bucket";
547     char ibuf[32];
548     DWORD written;
549     DWORD readden;
550
551     hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
552         /* nMaxInstances */ 1,
553         /* nOutBufSize */ 1024,
554         /* nInBufSize */ 1024,
555         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
556         /* lpSecurityAttrib */ NULL);
557     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
558
559     ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0
560         && GetLastError() == ERROR_PIPE_LISTENING, "WriteFile to not-yet-connected pipe");
561     ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
562         && GetLastError() == ERROR_PIPE_LISTENING, "ReadFile from not-yet-connected pipe");
563
564     hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
565     todo_wine {
566         ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed");
567     }
568
569     /* don't try to do i/o if one side couldn't be opened, as it hangs */
570     if (hFile != INVALID_HANDLE_VALUE) {
571
572         /* see what happens if server calls DisconnectNamedPipe
573          * when there are bytes in the pipe
574          */
575
576         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile");
577         ok(written == sizeof(obuf), "write file len");
578         ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting");
579         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0
580             && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe");
581         ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
582             && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
583             "ReadFile from disconnected pipe with bytes waiting");
584         ok(CloseHandle(hFile), "CloseHandle");
585     }
586
587     ok(CloseHandle(hnp), "CloseHandle");
588
589 }
590
591 START_TEST(pipe)
592 {
593     msg("test 1 of 4:\n");
594     test_DisconnectNamedPipe();
595     msg("test 2 of 4:\n");
596     test_CreateNamedPipe_instances_must_match();
597     msg("test 3 of 4:\n");
598     test_NamedPipe_2();
599     msg("test 4 of 4:\n");
600     test_CreateNamedPipe();
601     msg("all tests done\n");
602 }