2003-02-19 23:06:36 +01:00
/*
* Unit tests for named pipe functions in Wine
*
* Copyright ( c ) 2002 Dan Kegel
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
2006-05-18 14:49:52 +02:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
2003-02-19 23:06:36 +01:00
*/
2003-09-06 01:08:26 +02:00
# include <assert.h>
# include <stdarg.h>
2003-02-19 23:06:36 +01:00
# include <stdio.h>
2003-09-06 01:08:26 +02:00
# include <windef.h>
# include <winbase.h>
# include <winsock.h>
2003-02-25 04:56:43 +01:00
# include <wtypes.h>
2003-02-19 23:06:36 +01:00
# include <winerror.h>
2005-05-25 11:54:51 +02:00
# include "wine/test.h"
2004-05-24 21:06:52 +02:00
# define PIPENAME "\\\\.\\PiPe\\tests_pipe.c"
2003-02-19 23:06:36 +01:00
2004-05-04 02:43:46 +02:00
# define NB_SERVER_LOOPS 8
static HANDLE alarm_event ;
2007-03-16 22:37:46 +01:00
static BOOL ( WINAPI * pDuplicateTokenEx ) ( HANDLE , DWORD , LPSECURITY_ATTRIBUTES ,
SECURITY_IMPERSONATION_LEVEL , TOKEN_TYPE , PHANDLE ) ;
2004-05-04 02:43:46 +02:00
2004-12-13 22:19:01 +01:00
static void test_CreateNamedPipe ( int pipemode )
2003-02-19 23:06:36 +01:00
{
HANDLE hnp ;
HANDLE hFile ;
2004-05-04 06:13:05 +02:00
static const char obuf [ ] = " Bit Bucket " ;
static const char obuf2 [ ] = " More bits " ;
2004-04-27 01:30:51 +02:00
char ibuf [ 32 ] , * pbuf ;
2003-02-19 23:06:36 +01:00
DWORD written ;
2003-05-16 00:52:41 +02:00
DWORD readden ;
2004-04-27 01:30:51 +02:00
DWORD avail ;
DWORD lpmode ;
2003-02-19 23:06:36 +01:00
2004-04-27 01:30:51 +02:00
if ( pipemode = = PIPE_TYPE_BYTE )
trace ( " test_CreateNamedPipe starting in byte mode \n " ) ;
else
trace ( " test_CreateNamedPipe starting in message mode \n " ) ;
2003-02-19 23:06:36 +01:00
/* Bad parameter checks */
2004-04-27 01:30:51 +02:00
hnp = CreateNamedPipe ( " not a named pipe " , PIPE_ACCESS_DUPLEX , pipemode | PIPE_WAIT ,
2003-02-19 23:06:36 +01:00
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
if ( hnp = = INVALID_HANDLE_VALUE & & GetLastError ( ) = = ERROR_CALL_NOT_IMPLEMENTED ) {
/* Is this the right way to notify user of skipped tests? */
2003-05-16 00:52:41 +02:00
ok ( hnp = = INVALID_HANDLE_VALUE & & GetLastError ( ) = = ERROR_CALL_NOT_IMPLEMENTED ,
2004-02-06 06:24:34 +01:00
" CreateNamedPipe not supported on this platform, skipping tests. \n " ) ;
2003-02-19 23:06:36 +01:00
return ;
}
ok ( hnp = = INVALID_HANDLE_VALUE & & GetLastError ( ) = = ERROR_INVALID_NAME ,
2004-02-06 06:24:34 +01:00
" CreateNamedPipe should fail if name doesn't start with \\ \\ . \\ pipe \n " ) ;
2003-02-19 23:06:36 +01:00
2003-05-16 00:52:41 +02:00
hnp = CreateNamedPipe ( NULL ,
2004-04-27 01:30:51 +02:00
PIPE_ACCESS_DUPLEX , pipemode | PIPE_WAIT ,
2003-02-19 23:06:36 +01:00
1 , 1024 , 1024 , NMPWAIT_USE_DEFAULT_WAIT , NULL ) ;
ok ( hnp = = INVALID_HANDLE_VALUE & & GetLastError ( ) = = ERROR_PATH_NOT_FOUND ,
2004-02-06 06:24:34 +01:00
" CreateNamedPipe should fail if name is NULL \n " ) ;
2003-02-19 23:06:36 +01:00
2003-05-16 00:52:41 +02:00
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
ok ( hFile = = INVALID_HANDLE_VALUE
& & GetLastError ( ) = = ERROR_FILE_NOT_FOUND ,
2004-02-06 06:24:34 +01:00
" connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND \n " ) ;
2003-02-25 04:56:43 +01:00
2003-02-19 23:06:36 +01:00
/* Functional checks */
2004-04-27 01:30:51 +02:00
hnp = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , pipemode | PIPE_WAIT ,
2003-05-16 00:52:41 +02:00
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-05-16 00:52:41 +02:00
2007-01-04 10:54:10 +01:00
ok ( WaitNamedPipeA ( PIPENAME , 2000 ) , " WaitNamedPipe failed (%d) \n " , GetLastError ( ) ) ;
2005-12-05 13:09:35 +01:00
2003-05-16 00:52:41 +02:00
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
2007-01-04 10:54:10 +01:00
ok ( hFile ! = INVALID_HANDLE_VALUE , " CreateFile failed (%d) \n " , GetLastError ( ) ) ;
2003-05-16 00:52:41 +02:00
2007-04-17 22:07:07 +02:00
ok ( ! WaitNamedPipeA ( PIPENAME , 1000 ) , " WaitNamedPipe succeeded \n " ) ;
ok ( GetLastError ( ) = = ERROR_SEM_TIMEOUT , " wrong error %u \n " , GetLastError ( ) ) ;
2003-05-16 00:52:41 +02:00
/* don't try to do i/o if one side couldn't be opened, as it hangs */
if ( hFile ! = INVALID_HANDLE_VALUE ) {
HANDLE hFile2 ;
/* Make sure we can read and write a few bytes in both directions */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
2004-02-06 06:24:34 +01:00
ok ( WriteFile ( hnp , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile \n " ) ;
2004-04-27 01:30:51 +02:00
ok ( written = = sizeof ( obuf ) , " write file len 1 \n " ) ;
ok ( PeekNamedPipe ( hFile , NULL , 0 , NULL , & readden , NULL ) , " Peek \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) , " peek 1 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
ok ( ReadFile ( hFile , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) , " read 1 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
ok ( memcmp ( obuf , ibuf , written ) = = 0 , " content 1 check \n " ) ;
2003-05-16 00:52:41 +02:00
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
2004-04-27 01:30:51 +02:00
ok ( WriteFile ( hFile , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 2 \n " ) ;
ok ( PeekNamedPipe ( hnp , NULL , 0 , NULL , & readden , NULL ) , " Peek \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf2 ) , " peek 2 got %d bytes \n " , readden ) ;
2005-03-23 12:58:32 +01:00
ok ( PeekNamedPipe ( hnp , ( LPVOID ) 1 , 0 , NULL , & readden , NULL ) , " Peek \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf2 ) , " peek 2 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf2 ) , " read 2 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
ok ( memcmp ( obuf2 , ibuf , written ) = = 0 , " content 2 check \n " ) ;
/* Test reading of multiple writes */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hnp , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile3a \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 3a \n " ) ;
ok ( WriteFile ( hnp , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile3b \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 3b \n " ) ;
ok ( PeekNamedPipe ( hFile , ibuf , sizeof ( ibuf ) , & readden , & avail , NULL ) , " Peek3 \n " ) ;
if ( pipemode = = PIPE_TYPE_BYTE ) {
2006-11-09 15:40:36 +01:00
if ( readden ! = sizeof ( obuf ) ) /* Linux only returns the first message */
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek3 got %d bytes \n " , readden ) ;
2006-11-09 15:40:36 +01:00
else
todo_wine ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek3 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
}
else
2006-11-09 15:40:36 +01:00
{
if ( readden ! = sizeof ( obuf ) + sizeof ( obuf2 ) ) /* MacOS returns both messages */
ok ( readden = = sizeof ( obuf ) , " peek3 got %d bytes \n " , readden ) ;
else
todo_wine ok ( readden = = sizeof ( obuf ) , " peek3 got %d bytes \n " , readden ) ;
}
2005-03-24 20:05:02 +01:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2006-10-10 01:06:48 +02:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek3 got %d bytes available \n " , avail ) ;
2004-04-27 01:30:51 +02:00
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " pipe content 3a check \n " ) ;
2006-11-09 15:40:36 +01:00
if ( pipemode = = PIPE_TYPE_BYTE & & readden > = sizeof ( obuf ) + sizeof ( obuf2 ) ) {
pbuf + = sizeof ( obuf ) ;
ok ( memcmp ( obuf2 , pbuf , sizeof ( obuf2 ) ) = = 0 , " pipe content 3b check \n " ) ;
2004-04-27 01:30:51 +02:00
}
ok ( ReadFile ( hFile , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " read 3 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 3a check \n " ) ;
pbuf + = sizeof ( obuf ) ;
ok ( memcmp ( obuf2 , pbuf , sizeof ( obuf2 ) ) = = 0 , " content 3b check \n " ) ;
/* Multiple writes in the reverse direction */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile4a \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 4a \n " ) ;
ok ( WriteFile ( hFile , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile4b \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 4b \n " ) ;
ok ( PeekNamedPipe ( hnp , ibuf , sizeof ( ibuf ) , & readden , & avail , NULL ) , " Peek4 \n " ) ;
if ( pipemode = = PIPE_TYPE_BYTE ) {
2006-11-09 15:40:36 +01:00
if ( readden ! = sizeof ( obuf ) ) /* Linux only returns the first message */
2004-04-27 01:30:51 +02:00
/* should return all 23 bytes */
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek4 got %d bytes \n " , readden ) ;
2006-11-09 15:40:36 +01:00
else
todo_wine ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek4 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
}
else
2006-11-09 15:40:36 +01:00
{
if ( readden ! = sizeof ( obuf ) + sizeof ( obuf2 ) ) /* MacOS returns both messages */
ok ( readden = = sizeof ( obuf ) , " peek4 got %d bytes \n " , readden ) ;
else
todo_wine ok ( readden = = sizeof ( obuf ) , " peek4 got %d bytes \n " , readden ) ;
}
2005-03-24 20:05:02 +01:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2006-10-10 01:06:48 +02:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek4 got %d bytes available \n " , avail ) ;
2004-04-27 01:30:51 +02:00
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " pipe content 4a check \n " ) ;
2006-11-09 15:40:36 +01:00
if ( pipemode = = PIPE_TYPE_BYTE & & readden > = sizeof ( obuf ) + sizeof ( obuf2 ) ) {
pbuf + = sizeof ( obuf ) ;
ok ( memcmp ( obuf2 , pbuf , sizeof ( obuf2 ) ) = = 0 , " pipe content 4b check \n " ) ;
2004-04-27 01:30:51 +02:00
}
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
if ( pipemode = = PIPE_TYPE_BYTE ) {
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " read 4 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
}
else {
todo_wine {
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) , " read 4 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
}
}
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 4a check \n " ) ;
if ( pipemode = = PIPE_TYPE_BYTE ) {
pbuf + = sizeof ( obuf ) ;
ok ( memcmp ( obuf2 , pbuf , sizeof ( obuf2 ) ) = = 0 , " content 4b check \n " ) ;
}
/* Test reading of multiple writes after a mode change
( CreateFile always creates a byte mode pipe ) */
lpmode = PIPE_READMODE_MESSAGE ;
if ( pipemode = = PIPE_TYPE_BYTE ) {
/* trying to change the client end of a byte pipe to message mode should fail */
ok ( ! SetNamedPipeHandleState ( hFile , & lpmode , NULL , NULL ) , " Change mode \n " ) ;
}
else {
todo_wine {
ok ( SetNamedPipeHandleState ( hFile , & lpmode , NULL , NULL ) , " Change mode \n " ) ;
}
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hnp , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile5a \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 3a \n " ) ;
ok ( WriteFile ( hnp , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile5b \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 3b \n " ) ;
ok ( PeekNamedPipe ( hFile , ibuf , sizeof ( ibuf ) , & readden , & avail , NULL ) , " Peek5 \n " ) ;
2006-11-09 15:40:36 +01:00
if ( readden ! = sizeof ( obuf ) + sizeof ( obuf2 ) ) /* MacOS returns both writes */
ok ( readden = = sizeof ( obuf ) , " peek5 got %d bytes \n " , readden ) ;
else
todo_wine ok ( readden = = sizeof ( obuf ) , " peek5 got %d bytes \n " , readden ) ;
2005-03-24 20:05:02 +01:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2006-10-10 01:06:48 +02:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek5 got %d bytes available \n " , avail ) ;
2006-11-09 15:40:36 +01:00
else
todo_wine ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek5 got %d bytes available \n " , avail ) ;
2004-04-27 01:30:51 +02:00
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 5a check \n " ) ;
ok ( ReadFile ( hFile , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
todo_wine {
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) , " read 5 got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
}
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 5a check \n " ) ;
/* Multiple writes in the reverse direction */
/* the write of obuf2 from write4 should still be in the buffer */
ok ( PeekNamedPipe ( hnp , ibuf , sizeof ( ibuf ) , & readden , & avail , NULL ) , " Peek6a \n " ) ;
todo_wine {
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf2 ) , " peek6a got %d bytes \n " , readden ) ;
ok ( avail = = sizeof ( obuf2 ) , " peek6a got %d bytes available \n " , avail ) ;
2004-04-27 01:30:51 +02:00
}
if ( avail > 0 ) {
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf2 ) , " read 6a got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
pbuf = ibuf ;
ok ( memcmp ( obuf2 , pbuf , sizeof ( obuf2 ) ) = = 0 , " content 6a check \n " ) ;
}
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile6a \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 6a \n " ) ;
ok ( WriteFile ( hFile , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile6b \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 6b \n " ) ;
ok ( PeekNamedPipe ( hnp , ibuf , sizeof ( ibuf ) , & readden , & avail , NULL ) , " Peek6 \n " ) ;
2006-11-09 15:40:36 +01:00
if ( readden ! = sizeof ( obuf ) + sizeof ( obuf2 ) ) /* MacOS returns both writes */
ok ( readden = = sizeof ( obuf ) , " peek6 got %d bytes \n " , readden ) ;
else
todo_wine ok ( readden = = sizeof ( obuf ) , " peek6 got %d bytes \n " , readden ) ;
2005-03-24 20:05:02 +01:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2006-10-10 01:06:48 +02:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek6b got %d bytes available \n " , avail ) ;
2004-04-27 01:30:51 +02:00
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 6a check \n " ) ;
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
todo_wine {
2006-10-10 01:06:48 +02:00
ok ( readden = = sizeof ( obuf ) , " read 6b got %d bytes \n " , readden ) ;
2004-04-27 01:30:51 +02:00
}
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 6a check \n " ) ;
}
2003-05-16 00:52:41 +02:00
/* Picky conformance tests */
/* Verify that you can't connect to pipe again
* until server calls DisconnectNamedPipe + ConnectNamedPipe
* or creates a new pipe
* case 1 : other client not yet closed
*/
hFile2 = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
ok ( hFile2 = = INVALID_HANDLE_VALUE ,
2004-02-06 06:24:34 +01:00
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( GetLastError ( ) = = ERROR_PIPE_BUSY ,
2004-02-06 06:24:34 +01:00
" connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY \n " ) ;
2003-05-16 00:52:41 +02:00
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hFile ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
/* case 2: other client already closed */
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
ok ( hFile = = INVALID_HANDLE_VALUE ,
2004-02-06 06:24:34 +01:00
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( GetLastError ( ) = = ERROR_PIPE_BUSY ,
2004-02-06 06:24:34 +01:00
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY \n " ) ;
2003-05-16 00:52:41 +02:00
2004-02-06 06:24:34 +01:00
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
2003-05-16 00:52:41 +02:00
/* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
ok ( hFile = = INVALID_HANDLE_VALUE ,
2004-02-06 06:24:34 +01:00
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( GetLastError ( ) = = ERROR_PIPE_BUSY ,
2004-02-06 06:24:34 +01:00
" connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY \n " ) ;
2003-05-16 00:52:41 +02:00
/* to be complete, we'd call ConnectNamedPipe here and loop,
* but by default that ' s blocking , so we ' d either have
* to turn on the uncommon nonblocking mode , or
* use another thread .
*/
}
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
2003-05-20 05:58:35 +02:00
trace ( " test_CreateNamedPipe returning \n " ) ;
2003-05-16 00:52:41 +02:00
}
2005-06-20 17:35:54 +02:00
static void test_CreateNamedPipe_instances_must_match ( void )
2003-05-16 00:52:41 +02:00
{
HANDLE hnp , hnp2 ;
/* Check no mismatch */
hnp = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 2 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-05-16 00:52:41 +02:00
hnp2 = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 2 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp2 ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-05-16 00:52:41 +02:00
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
ok ( CloseHandle ( hnp2 ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
/* Check nMaxInstances */
hnp = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-05-16 00:52:41 +02:00
hnp2 = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp2 = = INVALID_HANDLE_VALUE
2004-02-06 06:24:34 +01:00
& & GetLastError ( ) = = ERROR_PIPE_BUSY , " nMaxInstances not obeyed \n " ) ;
2003-05-16 00:52:41 +02:00
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
/* Check PIPE_ACCESS_* */
hnp = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 2 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-05-16 00:52:41 +02:00
hnp2 = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_INBOUND , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp2 = = INVALID_HANDLE_VALUE
2004-02-06 06:24:34 +01:00
& & GetLastError ( ) = = ERROR_ACCESS_DENIED , " PIPE_ACCESS_* mismatch allowed \n " ) ;
2003-05-16 00:52:41 +02:00
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
/* etc, etc */
}
/** implementation of alarm() */
static DWORD CALLBACK alarmThreadMain ( LPVOID arg )
{
2009-01-03 20:17:31 +01:00
DWORD_PTR timeout = ( DWORD_PTR ) arg ;
2003-05-20 05:58:35 +02:00
trace ( " alarmThreadMain \n " ) ;
2004-05-04 02:43:46 +02:00
if ( WaitForSingleObject ( alarm_event , timeout ) = = WAIT_TIMEOUT )
{
ok ( FALSE , " alarm \n " ) ;
ExitProcess ( 1 ) ;
}
2003-05-16 00:52:41 +02:00
return 1 ;
}
HANDLE hnp = INVALID_HANDLE_VALUE ;
/** Trivial byte echo server - disconnects after each session */
static DWORD CALLBACK serverThreadMain1 ( LPVOID arg )
{
int i ;
2003-05-20 05:58:35 +02:00
trace ( " serverThreadMain1 start \n " ) ;
2003-05-16 00:52:41 +02:00
/* Set up a simple echo server */
hnp = CreateNamedPipe ( PIPENAME " serverThreadMain1 " , PIPE_ACCESS_DUPLEX ,
PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2004-05-04 02:43:46 +02:00
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
2003-05-16 00:52:41 +02:00
char buf [ 512 ] ;
DWORD written ;
DWORD readden ;
DWORD success ;
/* Wait for client to connect */
2003-05-20 05:58:35 +02:00
trace ( " Server calling ConnectNamedPipe... \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( ConnectNamedPipe ( hnp , NULL )
2004-02-06 06:24:34 +01:00
| | GetLastError ( ) = = ERROR_PIPE_CONNECTED , " ConnectNamedPipe \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " ConnectNamedPipe returned. \n " ) ;
2003-05-16 00:52:41 +02:00
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server reading... \n " ) ;
2003-05-16 00:52:41 +02:00
success = ReadFile ( hnp , buf , sizeof ( buf ) , & readden , NULL ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server done reading. \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( success , " ReadFile \n " ) ;
ok ( readden , " short read \n " ) ;
2003-05-16 00:52:41 +02:00
2003-05-20 05:58:35 +02:00
trace ( " Server writing... \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( WriteFile ( hnp , buf , readden , & written , NULL ) , " WriteFile \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server done writing. \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( written = = readden , " write file len \n " ) ;
2003-05-16 00:52:41 +02:00
/* finish this connection, wait for next one */
2004-02-06 06:24:34 +01:00
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server done flushing. \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server done disconnecting. \n " ) ;
2003-05-16 00:52:41 +02:00
}
2004-05-04 02:43:46 +02:00
return 0 ;
2003-05-16 00:52:41 +02:00
}
/** Trivial byte echo server - closes after each connection */
static DWORD CALLBACK serverThreadMain2 ( LPVOID arg )
{
int i ;
HANDLE hnpNext = 0 ;
2003-05-20 05:58:35 +02:00
trace ( " serverThreadMain2 \n " ) ;
2003-05-16 00:52:41 +02:00
/* Set up a simple echo server */
hnp = CreateNamedPipe ( PIPENAME " serverThreadMain2 " , PIPE_ACCESS_DUPLEX ,
PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 2 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-05-16 00:52:41 +02:00
2004-05-04 02:43:46 +02:00
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
2003-05-16 00:52:41 +02:00
char buf [ 512 ] ;
DWORD written ;
DWORD readden ;
DWORD success ;
/* Wait for client to connect */
2003-05-20 05:58:35 +02:00
trace ( " Server calling ConnectNamedPipe... \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( ConnectNamedPipe ( hnp , NULL )
2004-02-06 06:24:34 +01:00
| | GetLastError ( ) = = ERROR_PIPE_CONNECTED , " ConnectNamedPipe \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " ConnectNamedPipe returned. \n " ) ;
2003-05-16 00:52:41 +02:00
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server reading... \n " ) ;
2003-05-16 00:52:41 +02:00
success = ReadFile ( hnp , buf , sizeof ( buf ) , & readden , NULL ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server done reading. \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( success , " ReadFile \n " ) ;
2003-05-16 00:52:41 +02:00
2003-05-20 05:58:35 +02:00
trace ( " Server writing... \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( WriteFile ( hnp , buf , readden , & written , NULL ) , " WriteFile \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server done writing. \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( written = = readden , " write file len \n " ) ;
2003-05-16 00:52:41 +02:00
/* finish this connection, wait for next one */
2004-02-06 06:24:34 +01:00
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
2003-05-16 00:52:41 +02:00
/* Set up next echo server */
hnpNext =
CreateNamedPipe ( PIPENAME " serverThreadMain2 " , PIPE_ACCESS_DUPLEX ,
PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 2 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnpNext ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-05-16 00:52:41 +02:00
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
hnp = hnpNext ;
}
2004-05-04 02:43:46 +02:00
return 0 ;
2003-05-16 00:52:41 +02:00
}
/** Trivial byte echo server - uses overlapped named pipe calls */
static DWORD CALLBACK serverThreadMain3 ( LPVOID arg )
{
int i ;
HANDLE hEvent ;
2003-05-20 05:58:35 +02:00
trace ( " serverThreadMain3 \n " ) ;
2003-05-16 00:52:41 +02:00
/* Set up a simple echo server */
hnp = CreateNamedPipe ( PIPENAME " serverThreadMain3 " , PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED ,
PIPE_TYPE_BYTE | PIPE_WAIT ,
2003-02-19 23:06:36 +01:00
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2004-02-06 06:24:34 +01:00
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2003-02-19 23:06:36 +01:00
2003-05-16 00:52:41 +02:00
hEvent = CreateEvent ( NULL , /* security attribute */
TRUE , /* manual reset event */
FALSE , /* initial state */
NULL ) ; /* name */
2004-02-06 06:24:34 +01:00
ok ( hEvent ! = NULL , " CreateEvent \n " ) ;
2003-05-16 00:52:41 +02:00
2004-05-04 02:43:46 +02:00
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
2003-05-16 00:52:41 +02:00
char buf [ 512 ] ;
DWORD written ;
DWORD readden ;
DWORD dummy ;
DWORD success ;
OVERLAPPED oOverlap ;
int letWFSOEwait = ( i & 2 ) ;
int letGORwait = ( i & 1 ) ;
DWORD err ;
memset ( & oOverlap , 0 , sizeof ( oOverlap ) ) ;
oOverlap . hEvent = hEvent ;
/* Wait for client to connect */
2003-05-20 05:58:35 +02:00
trace ( " Server calling overlapped ConnectNamedPipe... \n " ) ;
2003-05-16 00:52:41 +02:00
success = ConnectNamedPipe ( hnp , & oOverlap ) ;
err = GetLastError ( ) ;
ok ( success | | err = = ERROR_IO_PENDING
2004-02-06 06:24:34 +01:00
| | err = = ERROR_PIPE_CONNECTED , " overlapped ConnectNamedPipe \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " overlapped ConnectNamedPipe returned. \n " ) ;
2003-05-16 00:52:41 +02:00
if ( ! success & & ( err = = ERROR_IO_PENDING ) & & letWFSOEwait )
2004-02-06 06:24:34 +01:00
ok ( WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) = = 0 , " wait ConnectNamedPipe \n " ) ;
2003-05-16 00:52:41 +02:00
success = GetOverlappedResult ( hnp , & oOverlap , & dummy , letGORwait ) ;
if ( ! letGORwait & & ! letWFSOEwait & & ! success ) {
2004-02-06 06:24:34 +01:00
ok ( GetLastError ( ) = = ERROR_IO_INCOMPLETE , " GetOverlappedResult \n " ) ;
2003-05-16 00:52:41 +02:00
success = GetOverlappedResult ( hnp , & oOverlap , & dummy , TRUE ) ;
}
2004-02-06 06:24:34 +01:00
ok ( success , " GetOverlappedResult ConnectNamedPipe \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " overlapped ConnectNamedPipe operation complete. \n " ) ;
2003-05-16 00:52:41 +02:00
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server reading... \n " ) ;
2003-05-16 00:52:41 +02:00
success = ReadFile ( hnp , buf , sizeof ( buf ) , NULL , & oOverlap ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server ReadFile returned... \n " ) ;
2003-05-16 00:52:41 +02:00
err = GetLastError ( ) ;
2004-02-06 06:24:34 +01:00
ok ( success | | err = = ERROR_IO_PENDING , " overlapped ReadFile \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " overlapped ReadFile returned. \n " ) ;
2003-05-16 00:52:41 +02:00
if ( ! success & & ( err = = ERROR_IO_PENDING ) & & letWFSOEwait )
2004-02-06 06:24:34 +01:00
ok ( WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) = = 0 , " wait ReadFile \n " ) ;
2003-05-16 00:52:41 +02:00
success = GetOverlappedResult ( hnp , & oOverlap , & readden , letGORwait ) ;
if ( ! letGORwait & & ! letWFSOEwait & & ! success ) {
2004-02-06 06:24:34 +01:00
ok ( GetLastError ( ) = = ERROR_IO_INCOMPLETE , " GetOverlappedResult \n " ) ;
2003-05-16 00:52:41 +02:00
success = GetOverlappedResult ( hnp , & oOverlap , & readden , TRUE ) ;
}
2003-05-20 05:58:35 +02:00
trace ( " Server done reading. \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( success , " overlapped ReadFile \n " ) ;
2003-05-16 00:52:41 +02:00
2003-05-20 05:58:35 +02:00
trace ( " Server writing... \n " ) ;
2003-05-16 00:52:41 +02:00
success = WriteFile ( hnp , buf , readden , NULL , & oOverlap ) ;
2003-05-20 05:58:35 +02:00
trace ( " Server WriteFile returned... \n " ) ;
2003-05-16 00:52:41 +02:00
err = GetLastError ( ) ;
2004-02-06 06:24:34 +01:00
ok ( success | | err = = ERROR_IO_PENDING , " overlapped WriteFile \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " overlapped WriteFile returned. \n " ) ;
2003-05-16 00:52:41 +02:00
if ( ! success & & ( err = = ERROR_IO_PENDING ) & & letWFSOEwait )
2004-02-06 06:24:34 +01:00
ok ( WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) = = 0 , " wait WriteFile \n " ) ;
2003-05-16 00:52:41 +02:00
success = GetOverlappedResult ( hnp , & oOverlap , & written , letGORwait ) ;
if ( ! letGORwait & & ! letWFSOEwait & & ! success ) {
2004-02-06 06:24:34 +01:00
ok ( GetLastError ( ) = = ERROR_IO_INCOMPLETE , " GetOverlappedResult \n " ) ;
2003-05-16 00:52:41 +02:00
success = GetOverlappedResult ( hnp , & oOverlap , & written , TRUE ) ;
}
2003-05-20 05:58:35 +02:00
trace ( " Server done writing. \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( success , " overlapped WriteFile \n " ) ;
ok ( written = = readden , " write file len \n " ) ;
2003-05-16 00:52:41 +02:00
/* finish this connection, wait for next one */
2004-02-06 06:24:34 +01:00
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
2003-05-16 00:52:41 +02:00
}
2004-05-04 02:43:46 +02:00
return 0 ;
2003-05-16 00:52:41 +02:00
}
static void exercizeServer ( const char * pipename , HANDLE serverThread )
{
int i ;
2003-05-20 05:58:35 +02:00
trace ( " exercizeServer starting \n " ) ;
2004-05-04 02:43:46 +02:00
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
2003-05-21 20:23:20 +02:00
HANDLE hFile = INVALID_HANDLE_VALUE ;
2004-05-04 06:13:05 +02:00
static const char obuf [ ] = " Bit Bucket " ;
2003-05-16 00:52:41 +02:00
char ibuf [ 32 ] ;
DWORD written ;
DWORD readden ;
int loop ;
for ( loop = 0 ; loop < 3 ; loop + + ) {
DWORD err ;
2003-05-20 05:58:35 +02:00
trace ( " Client connecting... \n " ) ;
2003-05-16 00:52:41 +02:00
/* Connect to the server */
hFile = CreateFileA ( pipename , GENERIC_READ | GENERIC_WRITE , 0 ,
NULL , OPEN_EXISTING , 0 , 0 ) ;
if ( hFile ! = INVALID_HANDLE_VALUE )
break ;
err = GetLastError ( ) ;
if ( loop = = 0 )
2004-02-06 06:24:34 +01:00
ok ( err = = ERROR_PIPE_BUSY | | err = = ERROR_FILE_NOT_FOUND , " connecting to pipe \n " ) ;
2003-05-16 00:52:41 +02:00
else
2004-02-06 06:24:34 +01:00
ok ( err = = ERROR_PIPE_BUSY , " connecting to pipe \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " connect failed, retrying \n " ) ;
2003-05-16 00:52:41 +02:00
Sleep ( 200 ) ;
}
2004-02-06 06:24:34 +01:00
ok ( hFile ! = INVALID_HANDLE_VALUE , " client opening named pipe \n " ) ;
2003-05-16 00:52:41 +02:00
/* Make sure it can echo */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
2003-05-20 05:58:35 +02:00
trace ( " Client writing... \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile to client end of pipe \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len \n " ) ;
2003-05-20 05:58:35 +02:00
trace ( " Client reading... \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( ReadFile ( hFile , ibuf , sizeof ( obuf ) , & readden , NULL ) , " ReadFile from client end of pipe \n " ) ;
ok ( readden = = sizeof ( obuf ) , " read file len \n " ) ;
ok ( memcmp ( obuf , ibuf , written ) = = 0 , " content check \n " ) ;
2003-05-16 00:52:41 +02:00
2003-05-20 05:58:35 +02:00
trace ( " Client closing... \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hFile ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
}
2004-05-04 02:43:46 +02:00
ok ( WaitForSingleObject ( serverThread , INFINITE ) = = WAIT_OBJECT_0 , " WaitForSingleObject \n " ) ;
2003-05-16 00:52:41 +02:00
CloseHandle ( hnp ) ;
2003-05-20 05:58:35 +02:00
trace ( " exercizeServer returning \n " ) ;
2003-05-16 00:52:41 +02:00
}
2004-05-04 06:13:05 +02:00
static void test_NamedPipe_2 ( void )
2003-05-16 00:52:41 +02:00
{
HANDLE serverThread ;
DWORD serverThreadId ;
HANDLE alarmThread ;
DWORD alarmThreadId ;
2003-05-20 05:58:35 +02:00
trace ( " test_NamedPipe_2 starting \n " ) ;
2003-05-16 00:52:41 +02:00
/* Set up a ten second timeout */
2004-05-04 02:43:46 +02:00
alarm_event = CreateEvent ( NULL , TRUE , FALSE , NULL ) ;
2003-05-16 00:52:41 +02:00
alarmThread = CreateThread ( NULL , 0 , alarmThreadMain , ( void * ) 10000 , 0 , & alarmThreadId ) ;
/* The servers we're about to exercize do try to clean up carefully,
* but to reduce the change of a test failure due to a pipe handle
* leak in the test code , we ' ll use a different pipe name for each server .
*/
/* Try server #1 */
2004-05-04 02:43:46 +02:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain1 , ( void * ) 8 , 0 , & serverThreadId ) ;
2004-02-06 06:24:34 +01:00
ok ( serverThread ! = INVALID_HANDLE_VALUE , " CreateThread \n " ) ;
2003-05-16 00:52:41 +02:00
exercizeServer ( PIPENAME " serverThreadMain1 " , serverThread ) ;
/* Try server #2 */
serverThread = CreateThread ( NULL , 0 , serverThreadMain2 , 0 , 0 , & serverThreadId ) ;
2004-02-06 06:24:34 +01:00
ok ( serverThread ! = INVALID_HANDLE_VALUE , " CreateThread \n " ) ;
2003-05-16 00:52:41 +02:00
exercizeServer ( PIPENAME " serverThreadMain2 " , serverThread ) ;
if ( 0 ) /* overlapped pipe server doesn't work yet - it randomly fails */
{
/* Try server #3 */
serverThread = CreateThread ( NULL , 0 , serverThreadMain3 , 0 , 0 , & serverThreadId ) ;
2004-02-06 06:24:34 +01:00
ok ( serverThread ! = INVALID_HANDLE_VALUE , " CreateThread \n " ) ;
2003-05-16 00:52:41 +02:00
exercizeServer ( PIPENAME " serverThreadMain3 " , serverThread ) ;
}
2004-05-04 02:43:46 +02:00
ok ( SetEvent ( alarm_event ) , " SetEvent \n " ) ;
CloseHandle ( alarm_event ) ;
2003-05-20 05:58:35 +02:00
trace ( " test_NamedPipe_2 returning \n " ) ;
2003-05-16 00:52:41 +02:00
}
2005-03-22 22:14:00 +01:00
static int test_DisconnectNamedPipe ( void )
2003-05-16 00:52:41 +02:00
{
HANDLE hnp ;
HANDLE hFile ;
2004-05-04 06:13:05 +02:00
static const char obuf [ ] = " Bit Bucket " ;
2003-05-16 00:52:41 +02:00
char ibuf [ 32 ] ;
DWORD written ;
DWORD readden ;
2008-09-13 14:05:12 +02:00
SetLastError ( 0xdeadbeef ) ;
2003-05-16 00:52:41 +02:00
hnp = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
2008-09-13 14:05:12 +02:00
if ( ( hnp = = INVALID_HANDLE_VALUE /* Win98 */ | | ! hnp /* Win95 */ )
& & GetLastError ( ) = = ERROR_CALL_NOT_IMPLEMENTED ) {
win_skip ( " Named pipes are not implemented \n " ) ;
2005-03-22 22:14:00 +01:00
return 1 ;
}
2003-05-16 00:52:41 +02:00
ok ( WriteFile ( hnp , obuf , sizeof ( obuf ) , & written , NULL ) = = 0
2004-02-06 06:24:34 +01:00
& & GetLastError ( ) = = ERROR_PIPE_LISTENING , " WriteFile to not-yet-connected pipe \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) = = 0
2004-02-06 06:24:34 +01:00
& & GetLastError ( ) = = ERROR_PIPE_LISTENING , " ReadFile from not-yet-connected pipe \n " ) ;
2003-05-16 00:52:41 +02:00
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
2004-02-06 06:24:34 +01:00
ok ( hFile ! = INVALID_HANDLE_VALUE , " CreateFile failed \n " ) ;
2003-02-19 23:06:36 +01:00
/* don't try to do i/o if one side couldn't be opened, as it hangs */
if ( hFile ! = INVALID_HANDLE_VALUE ) {
2003-05-16 00:52:41 +02:00
/* see what happens if server calls DisconnectNamedPipe
* when there are bytes in the pipe
*/
2004-02-06 06:24:34 +01:00
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe while messages waiting \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) = = 0
2004-02-06 06:24:34 +01:00
& & GetLastError ( ) = = ERROR_PIPE_NOT_CONNECTED , " WriteFile to disconnected pipe \n " ) ;
2003-05-16 00:52:41 +02:00
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) = = 0
& & GetLastError ( ) = = ERROR_PIPE_NOT_CONNECTED ,
2004-02-06 06:24:34 +01:00
" ReadFile from disconnected pipe with bytes waiting \n " ) ;
2007-04-16 14:51:29 +02:00
ok ( ! DisconnectNamedPipe ( hnp ) & & GetLastError ( ) = = ERROR_PIPE_NOT_CONNECTED ,
" DisconnectNamedPipe worked twice \n " ) ;
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hFile ) , " CloseHandle \n " ) ;
2003-02-19 23:06:36 +01:00
}
2004-02-06 06:24:34 +01:00
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
2005-03-22 22:14:00 +01:00
return 0 ;
2003-02-19 23:06:36 +01:00
}
2005-06-05 19:57:10 +02:00
static void test_CreatePipe ( void )
{
SECURITY_ATTRIBUTES pipe_attr ;
HANDLE piperead , pipewrite ;
DWORD written ;
DWORD read ;
2007-01-12 20:59:22 +01:00
DWORD i , size ;
BYTE * buffer ;
2005-06-05 19:57:10 +02:00
char readbuf [ 32 ] ;
pipe_attr . nLength = sizeof ( SECURITY_ATTRIBUTES ) ;
pipe_attr . bInheritHandle = TRUE ;
pipe_attr . lpSecurityDescriptor = NULL ;
ok ( CreatePipe ( & piperead , & pipewrite , & pipe_attr , 0 ) ! = 0 , " CreatePipe failed \n " ) ;
ok ( WriteFile ( pipewrite , PIPENAME , sizeof ( PIPENAME ) , & written , NULL ) , " Write to anonymous pipe failed \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( written = = sizeof ( PIPENAME ) , " Write to anonymous pipe wrote %d bytes \n " , written ) ;
2005-06-05 19:57:10 +02:00
ok ( ReadFile ( piperead , readbuf , sizeof ( readbuf ) , & read , NULL ) , " Read from non empty pipe failed \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( read = = sizeof ( PIPENAME ) , " Read from anonymous pipe got %d bytes \n " , read ) ;
2007-01-12 20:59:22 +01:00
ok ( CloseHandle ( pipewrite ) , " CloseHandle for the write pipe failed \n " ) ;
ok ( CloseHandle ( piperead ) , " CloseHandle for the read pipe failed \n " ) ;
2005-06-05 19:57:10 +02:00
/* Now write another chunk*/
ok ( CreatePipe ( & piperead , & pipewrite , & pipe_attr , 0 ) ! = 0 , " CreatePipe failed \n " ) ;
ok ( WriteFile ( pipewrite , PIPENAME , sizeof ( PIPENAME ) , & written , NULL ) , " Write to anonymous pipe failed \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( written = = sizeof ( PIPENAME ) , " Write to anonymous pipe wrote %d bytes \n " , written ) ;
2005-06-05 19:57:10 +02:00
/* and close the write end, read should still succeed*/
ok ( CloseHandle ( pipewrite ) , " CloseHandle for the Write Pipe failed \n " ) ;
ok ( ReadFile ( piperead , readbuf , sizeof ( readbuf ) , & read , NULL ) , " Read from broken pipe withe with pending data failed \n " ) ;
2006-10-10 01:06:48 +02:00
ok ( read = = sizeof ( PIPENAME ) , " Read from anonymous pipe got %d bytes \n " , read ) ;
2005-06-05 19:57:10 +02:00
/* But now we need to get informed that the pipe is closed */
2005-11-14 16:11:11 +01:00
ok ( ReadFile ( piperead , readbuf , sizeof ( readbuf ) , & read , NULL ) = = 0 , " Broken pipe not detected \n " ) ;
2007-01-12 20:59:22 +01:00
ok ( CloseHandle ( piperead ) , " CloseHandle for the read pipe failed \n " ) ;
/* Try bigger chunks */
size = 32768 ;
buffer = HeapAlloc ( GetProcessHeap ( ) , 0 , size ) ;
for ( i = 0 ; i < size ; i + + ) buffer [ i ] = i ;
2008-11-14 14:00:12 +01:00
ok ( CreatePipe ( & piperead , & pipewrite , & pipe_attr , ( size + 24 ) ) ! = 0 , " CreatePipe failed \n " ) ;
2007-01-12 20:59:22 +01:00
ok ( WriteFile ( pipewrite , buffer , size , & written , NULL ) , " Write to anonymous pipe failed \n " ) ;
ok ( written = = size , " Write to anonymous pipe wrote %d bytes \n " , written ) ;
/* and close the write end, read should still succeed*/
ok ( CloseHandle ( pipewrite ) , " CloseHandle for the Write Pipe failed \n " ) ;
memset ( buffer , 0 , size ) ;
ok ( ReadFile ( piperead , buffer , size , & read , NULL ) , " Read from broken pipe withe with pending data failed \n " ) ;
ok ( read = = size , " Read from anonymous pipe got %d bytes \n " , read ) ;
for ( i = 0 ; i < size ; i + + ) ok ( buffer [ i ] = = ( BYTE ) i , " invalid data %x at %x \n " , buffer [ i ] , i ) ;
/* But now we need to get informed that the pipe is closed */
ok ( ReadFile ( piperead , readbuf , sizeof ( readbuf ) , & read , NULL ) = = 0 , " Broken pipe not detected \n " ) ;
ok ( CloseHandle ( piperead ) , " CloseHandle for the read pipe failed \n " ) ;
2007-10-20 21:22:26 +02:00
HeapFree ( GetProcessHeap ( ) , 0 , buffer ) ;
2005-06-05 19:57:10 +02:00
}
2003-02-19 23:06:36 +01:00
2007-03-06 19:00:15 +01:00
struct named_pipe_client_params
{
DWORD security_flags ;
HANDLE token ;
BOOL revert ;
} ;
# define PIPE_NAME "\\\\.\\pipe\\named_pipe_test"
static DWORD CALLBACK named_pipe_client_func ( LPVOID p )
{
struct named_pipe_client_params * params = ( struct named_pipe_client_params * ) p ;
HANDLE pipe ;
BOOL ret ;
const char message [ ] = " Test " ;
DWORD bytes_read , bytes_written ;
char dummy ;
TOKEN_PRIVILEGES * Privileges = NULL ;
if ( params - > token )
{
if ( params - > revert )
{
/* modify the token so we can tell if the pipe impersonation
* token reverts to the process token */
ret = AdjustTokenPrivileges ( params - > token , TRUE , NULL , 0 , NULL , NULL ) ;
ok ( ret , " AdjustTokenPrivileges failed with error %d \n " , GetLastError ( ) ) ;
}
ret = SetThreadToken ( NULL , params - > token ) ;
ok ( ret , " SetThreadToken failed with error %d \n " , GetLastError ( ) ) ;
}
else
{
DWORD Size = 0 ;
HANDLE process_token ;
ret = OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES , & process_token ) ;
ok ( ret , " OpenProcessToken failed with error %d \n " , GetLastError ( ) ) ;
ret = GetTokenInformation ( process_token , TokenPrivileges , NULL , 0 , & Size ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INSUFFICIENT_BUFFER , " GetTokenInformation(TokenPrivileges) failed with %d \n " , GetLastError ( ) ) ;
2007-06-27 00:12:59 +02:00
Privileges = HeapAlloc ( GetProcessHeap ( ) , 0 , Size ) ;
2007-03-06 19:00:15 +01:00
ret = GetTokenInformation ( process_token , TokenPrivileges , Privileges , Size , & Size ) ;
ok ( ret , " GetTokenInformation(TokenPrivileges) failed with %d \n " , GetLastError ( ) ) ;
ret = AdjustTokenPrivileges ( process_token , TRUE , NULL , 0 , NULL , NULL ) ;
ok ( ret , " AdjustTokenPrivileges failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( process_token ) ;
}
pipe = CreateFile ( PIPE_NAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , params - > security_flags , NULL ) ;
ok ( pipe ! = INVALID_HANDLE_VALUE , " CreateFile for pipe failed with error %d \n " , GetLastError ( ) ) ;
ret = WriteFile ( pipe , message , sizeof ( message ) , & bytes_written , NULL ) ;
ok ( ret , " WriteFile failed with error %d \n " , GetLastError ( ) ) ;
ret = ReadFile ( pipe , & dummy , sizeof ( dummy ) , & bytes_read , NULL ) ;
ok ( ret , " ReadFile failed with error %d \n " , GetLastError ( ) ) ;
if ( params - > token )
{
if ( params - > revert )
{
ret = RevertToSelf ( ) ;
ok ( ret , " RevertToSelf failed with error %d \n " , GetLastError ( ) ) ;
}
else
{
ret = AdjustTokenPrivileges ( params - > token , TRUE , NULL , 0 , NULL , NULL ) ;
ok ( ret , " AdjustTokenPrivileges failed with error %d \n " , GetLastError ( ) ) ;
}
}
else
{
HANDLE process_token ;
ret = OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_ADJUST_PRIVILEGES , & process_token ) ;
ok ( ret , " OpenProcessToken failed with error %d \n " , GetLastError ( ) ) ;
ret = AdjustTokenPrivileges ( process_token , FALSE , Privileges , 0 , NULL , NULL ) ;
ok ( ret , " AdjustTokenPrivileges failed with error %d \n " , GetLastError ( ) ) ;
HeapFree ( GetProcessHeap ( ) , 0 , Privileges ) ;
CloseHandle ( process_token ) ;
}
ret = WriteFile ( pipe , message , sizeof ( message ) , & bytes_written , NULL ) ;
ok ( ret , " WriteFile failed with error %d \n " , GetLastError ( ) ) ;
ret = ReadFile ( pipe , & dummy , sizeof ( dummy ) , & bytes_read , NULL ) ;
ok ( ret , " ReadFile failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( pipe ) ;
return 0 ;
}
static HANDLE make_impersonation_token ( DWORD Access , SECURITY_IMPERSONATION_LEVEL ImpersonationLevel )
{
HANDLE ProcessToken ;
HANDLE Token = NULL ;
BOOL ret ;
ret = OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_DUPLICATE , & ProcessToken ) ;
ok ( ret , " OpenProcessToken failed with error %d \n " , GetLastError ( ) ) ;
2007-03-16 22:37:46 +01:00
ret = pDuplicateTokenEx ( ProcessToken , Access , NULL , ImpersonationLevel , TokenImpersonation , & Token ) ;
2007-03-06 19:00:15 +01:00
ok ( ret , " DuplicateToken failed with error %d \n " , GetLastError ( ) ) ;
CloseHandle ( ProcessToken ) ;
return Token ;
}
static void test_ImpersonateNamedPipeClient ( HANDLE hClientToken , DWORD security_flags , BOOL revert , void ( * test_func ) ( int , HANDLE ) )
{
HANDLE hPipeServer ;
BOOL ret ;
DWORD dwTid ;
HANDLE hThread ;
char buffer [ 256 ] ;
DWORD dwBytesRead ;
DWORD error ;
struct named_pipe_client_params params ;
char dummy = 0 ;
DWORD dwBytesWritten ;
HANDLE hToken = NULL ;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel ;
DWORD size ;
hPipeServer = CreateNamedPipe ( PIPE_NAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT , 1 , 100 , 100 , NMPWAIT_USE_DEFAULT_WAIT , NULL ) ;
ok ( hPipeServer ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed with error %d \n " , GetLastError ( ) ) ;
params . security_flags = security_flags ;
params . token = hClientToken ;
params . revert = revert ;
hThread = CreateThread ( NULL , 0 , named_pipe_client_func , & params , 0 , & dwTid ) ;
ok ( hThread ! = NULL , " CreateThread failed with error %d \n " , GetLastError ( ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = ImpersonateNamedPipeClient ( hPipeServer ) ;
error = GetLastError ( ) ;
2008-11-17 13:16:26 +01:00
ok ( ret /* win2k3 */ | | ( error = = ERROR_CANNOT_IMPERSONATE ) ,
2008-09-02 08:02:39 +02:00
" ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d \n " , GetLastError ( ) ) ;
2007-03-06 19:00:15 +01:00
ret = ConnectNamedPipe ( hPipeServer , NULL ) ;
ok ( ret | | ( GetLastError ( ) = = ERROR_PIPE_CONNECTED ) , " ConnectNamedPipe failed with error %d \n " , GetLastError ( ) ) ;
ret = ReadFile ( hPipeServer , buffer , sizeof ( buffer ) , & dwBytesRead , NULL ) ;
ok ( ret , " ReadFile failed with error %d \n " , GetLastError ( ) ) ;
ret = ImpersonateNamedPipeClient ( hPipeServer ) ;
ok ( ret , " ImpersonateNamedPipeClient failed with error %d \n " , GetLastError ( ) ) ;
ret = OpenThreadToken ( GetCurrentThread ( ) , TOKEN_QUERY , FALSE , & hToken ) ;
ok ( ret , " OpenThreadToken failed with error %d \n " , GetLastError ( ) ) ;
( * test_func ) ( 0 , hToken ) ;
2007-08-15 17:08:50 +02:00
ImpersonationLevel = 0xdeadbeef ; /* to avoid false positives */
2007-03-06 19:00:15 +01:00
ret = GetTokenInformation ( hToken , TokenImpersonationLevel , & ImpersonationLevel , sizeof ( ImpersonationLevel ) , & size ) ;
ok ( ret , " GetTokenInformation(TokenImpersonationLevel) failed with error %d \n " , GetLastError ( ) ) ;
2007-08-15 17:08:50 +02:00
ok ( ImpersonationLevel = = SecurityImpersonation , " ImpersonationLevel should have been SecurityImpersonation(%d) instead of %d \n " , SecurityImpersonation , ImpersonationLevel ) ;
2007-03-06 19:00:15 +01:00
CloseHandle ( hToken ) ;
RevertToSelf ( ) ;
ret = WriteFile ( hPipeServer , & dummy , sizeof ( dummy ) , & dwBytesWritten , NULL ) ;
ok ( ret , " WriteFile failed with error %d \n " , GetLastError ( ) ) ;
ret = ReadFile ( hPipeServer , buffer , sizeof ( buffer ) , & dwBytesRead , NULL ) ;
ok ( ret , " ReadFile failed with error %d \n " , GetLastError ( ) ) ;
ret = ImpersonateNamedPipeClient ( hPipeServer ) ;
ok ( ret , " ImpersonateNamedPipeClient failed with error %d \n " , GetLastError ( ) ) ;
ret = OpenThreadToken ( GetCurrentThread ( ) , TOKEN_QUERY , FALSE , & hToken ) ;
ok ( ret , " OpenThreadToken failed with error %d \n " , GetLastError ( ) ) ;
( * test_func ) ( 1 , hToken ) ;
CloseHandle ( hToken ) ;
RevertToSelf ( ) ;
ret = WriteFile ( hPipeServer , & dummy , sizeof ( dummy ) , & dwBytesWritten , NULL ) ;
ok ( ret , " WriteFile failed with error %d \n " , GetLastError ( ) ) ;
WaitForSingleObject ( hThread , INFINITE ) ;
ret = ImpersonateNamedPipeClient ( hPipeServer ) ;
ok ( ret , " ImpersonateNamedPipeClient failed with error %d \n " , GetLastError ( ) ) ;
RevertToSelf ( ) ;
CloseHandle ( hThread ) ;
CloseHandle ( hPipeServer ) ;
}
static BOOL are_all_privileges_disabled ( HANDLE hToken )
{
BOOL ret ;
TOKEN_PRIVILEGES * Privileges = NULL ;
DWORD Size = 0 ;
BOOL all_privs_disabled = TRUE ;
DWORD i ;
ret = GetTokenInformation ( hToken , TokenPrivileges , NULL , 0 , & Size ) ;
if ( ! ret & & GetLastError ( ) = = ERROR_INSUFFICIENT_BUFFER )
{
Privileges = HeapAlloc ( GetProcessHeap ( ) , 0 , Size ) ;
ret = GetTokenInformation ( hToken , TokenPrivileges , Privileges , Size , & Size ) ;
2007-10-20 21:22:26 +02:00
if ( ! ret )
{
HeapFree ( GetProcessHeap ( ) , 0 , Privileges ) ;
return FALSE ;
}
2007-03-06 19:00:15 +01:00
}
else
return FALSE ;
for ( i = 0 ; i < Privileges - > PrivilegeCount ; i + + )
{
if ( Privileges - > Privileges [ i ] . Attributes & SE_PRIVILEGE_ENABLED )
{
all_privs_disabled = FALSE ;
break ;
}
}
HeapFree ( GetProcessHeap ( ) , 0 , Privileges ) ;
return all_privs_disabled ;
}
static DWORD get_privilege_count ( HANDLE hToken )
{
TOKEN_STATISTICS Statistics ;
DWORD Size = sizeof ( Statistics ) ;
BOOL ret ;
ret = GetTokenInformation ( hToken , TokenStatistics , & Statistics , Size , & Size ) ;
ok ( ret , " GetTokenInformation(TokenStatistics) \n " ) ;
if ( ! ret ) return - 1 ;
return Statistics . PrivilegeCount ;
}
static void test_no_sqos_no_token ( int call_index , HANDLE hToken )
{
DWORD priv_count ;
switch ( call_index )
{
case 0 :
priv_count = get_privilege_count ( hToken ) ;
todo_wine
ok ( priv_count = = 0 , " privilege count should have been 0 instead of %d \n " , priv_count ) ;
break ;
case 1 :
priv_count = get_privilege_count ( hToken ) ;
ok ( priv_count > 0 , " privilege count should now be > 0 instead of 0 \n " ) ;
ok ( ! are_all_privileges_disabled ( hToken ) , " impersonated token should not have been modified \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_no_sqos ( int call_index , HANDLE hToken )
{
switch ( call_index )
{
case 0 :
ok ( ! are_all_privileges_disabled ( hToken ) , " token should be a copy of the process one \n " ) ;
break ;
case 1 :
todo_wine
ok ( are_all_privileges_disabled ( hToken ) , " impersonated token should have been modified \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_static_context ( int call_index , HANDLE hToken )
{
switch ( call_index )
{
case 0 :
ok ( ! are_all_privileges_disabled ( hToken ) , " token should be a copy of the process one \n " ) ;
break ;
case 1 :
ok ( ! are_all_privileges_disabled ( hToken ) , " impersonated token should not have been modified \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_dynamic_context ( int call_index , HANDLE hToken )
{
switch ( call_index )
{
case 0 :
ok ( ! are_all_privileges_disabled ( hToken ) , " token should be a copy of the process one \n " ) ;
break ;
case 1 :
todo_wine
ok ( are_all_privileges_disabled ( hToken ) , " impersonated token should have been modified \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_dynamic_context_no_token ( int call_index , HANDLE hToken )
{
switch ( call_index )
{
case 0 :
ok ( are_all_privileges_disabled ( hToken ) , " token should be a copy of the process one \n " ) ;
break ;
case 1 :
ok ( ! are_all_privileges_disabled ( hToken ) , " process token modification should have been detected and impersonation token updated \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_no_sqos_revert ( int call_index , HANDLE hToken )
{
DWORD priv_count ;
switch ( call_index )
{
case 0 :
priv_count = get_privilege_count ( hToken ) ;
todo_wine
ok ( priv_count = = 0 , " privilege count should have been 0 instead of %d \n " , priv_count ) ;
break ;
case 1 :
priv_count = get_privilege_count ( hToken ) ;
ok ( priv_count > 0 , " privilege count should now be > 0 instead of 0 \n " ) ;
ok ( ! are_all_privileges_disabled ( hToken ) , " impersonated token should not have been modified \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_static_context_revert ( int call_index , HANDLE hToken )
{
switch ( call_index )
{
case 0 :
todo_wine
ok ( are_all_privileges_disabled ( hToken ) , " privileges should have been disabled \n " ) ;
break ;
case 1 :
todo_wine
ok ( are_all_privileges_disabled ( hToken ) , " impersonated token should not have been modified \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_dynamic_context_revert ( int call_index , HANDLE hToken )
{
switch ( call_index )
{
case 0 :
todo_wine
ok ( are_all_privileges_disabled ( hToken ) , " privileges should have been disabled \n " ) ;
break ;
case 1 :
ok ( ! are_all_privileges_disabled ( hToken ) , " impersonated token should now be process token \n " ) ;
break ;
default :
ok ( 0 , " shouldn't happen \n " ) ;
}
}
static void test_impersonation ( void )
{
HANDLE hClientToken ;
HANDLE hProcessToken ;
BOOL ret ;
2007-03-16 22:37:46 +01:00
if ( ! pDuplicateTokenEx ) {
skip ( " DuplicateTokenEx not found \n " ) ;
return ;
}
2007-03-06 19:00:15 +01:00
ret = OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_QUERY , & hProcessToken ) ;
if ( ! ret )
{
skip ( " couldn't open process token, skipping impersonation tests \n " ) ;
return ;
}
if ( ! get_privilege_count ( hProcessToken ) | | are_all_privileges_disabled ( hProcessToken ) )
{
skip ( " token didn't have any privileges or they were all disabled. token not suitable for impersonation tests \n " ) ;
CloseHandle ( hProcessToken ) ;
return ;
}
CloseHandle ( hProcessToken ) ;
test_ImpersonateNamedPipeClient ( NULL , 0 , FALSE , test_no_sqos_no_token ) ;
hClientToken = make_impersonation_token ( TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , SecurityImpersonation ) ;
test_ImpersonateNamedPipeClient ( hClientToken , 0 , FALSE , test_no_sqos ) ;
CloseHandle ( hClientToken ) ;
hClientToken = make_impersonation_token ( TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , SecurityImpersonation ) ;
test_ImpersonateNamedPipeClient ( hClientToken ,
SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION , FALSE ,
test_static_context ) ;
CloseHandle ( hClientToken ) ;
hClientToken = make_impersonation_token ( TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , SecurityImpersonation ) ;
test_ImpersonateNamedPipeClient ( hClientToken ,
SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION ,
FALSE , test_dynamic_context ) ;
CloseHandle ( hClientToken ) ;
test_ImpersonateNamedPipeClient ( NULL ,
SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION ,
FALSE , test_dynamic_context_no_token ) ;
hClientToken = make_impersonation_token ( TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , SecurityImpersonation ) ;
test_ImpersonateNamedPipeClient ( hClientToken , 0 , TRUE , test_no_sqos_revert ) ;
CloseHandle ( hClientToken ) ;
hClientToken = make_impersonation_token ( TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , SecurityImpersonation ) ;
test_ImpersonateNamedPipeClient ( hClientToken ,
SECURITY_SQOS_PRESENT | SECURITY_IMPERSONATION , TRUE ,
test_static_context_revert ) ;
CloseHandle ( hClientToken ) ;
hClientToken = make_impersonation_token ( TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY , SecurityImpersonation ) ;
test_ImpersonateNamedPipeClient ( hClientToken ,
SECURITY_SQOS_PRESENT | SECURITY_CONTEXT_TRACKING | SECURITY_IMPERSONATION ,
TRUE , test_dynamic_context_revert ) ;
CloseHandle ( hClientToken ) ;
}
2007-07-16 13:12:18 +02:00
struct overlapped_server_args
{
HANDLE pipe_created ;
} ;
static DWORD CALLBACK overlapped_server ( LPVOID arg )
{
OVERLAPPED ol ;
HANDLE pipe ;
int ret , err ;
struct overlapped_server_args * a = ( struct overlapped_server_args * ) arg ;
DWORD num ;
char buf [ 100 ] ;
pipe = CreateNamedPipeA ( " \\ \\ . \\ pipe \\ my pipe " , FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX , PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE , 1 , 0 , 0 , 100000 , NULL ) ;
ok ( pipe ! = NULL , " pipe NULL \n " ) ;
ol . hEvent = CreateEventA ( 0 , 1 , 0 , 0 ) ;
ok ( ol . hEvent ! = NULL , " event NULL \n " ) ;
ret = ConnectNamedPipe ( pipe , & ol ) ;
err = GetLastError ( ) ;
ok ( ret = = 0 , " ret %d \n " , ret ) ;
ok ( err = = ERROR_IO_PENDING , " gle %d \n " , err ) ;
SetEvent ( a - > pipe_created ) ;
ret = WaitForSingleObjectEx ( ol . hEvent , INFINITE , 1 ) ;
2007-07-16 16:14:45 +02:00
ok ( ret = = WAIT_OBJECT_0 , " ret %x \n " , ret ) ;
2007-07-16 13:12:18 +02:00
ret = GetOverlappedResult ( pipe , & ol , & num , 1 ) ;
ok ( ret = = 1 , " ret %d \n " , ret ) ;
/* This should block */
ret = ReadFile ( pipe , buf , sizeof ( buf ) , & num , NULL ) ;
2007-07-16 15:27:53 +02:00
ok ( ret = = 1 , " ret %d \n " , ret ) ;
2007-07-16 13:12:18 +02:00
DisconnectNamedPipe ( pipe ) ;
CloseHandle ( ol . hEvent ) ;
CloseHandle ( pipe ) ;
return 1 ;
}
static void test_overlapped ( void )
{
DWORD tid , num ;
HANDLE thread , pipe ;
int ret ;
struct overlapped_server_args args ;
args . pipe_created = CreateEventA ( 0 , 1 , 0 , 0 ) ;
thread = CreateThread ( NULL , 0 , overlapped_server , & args , 0 , & tid ) ;
WaitForSingleObject ( args . pipe_created , INFINITE ) ;
pipe = CreateFileA ( " \\ \\ . \\ pipe \\ my pipe " , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , NULL ) ;
ok ( pipe ! = INVALID_HANDLE_VALUE , " cf failed \n " ) ;
/* Sleep to try to get the ReadFile in the server to occur before the following WriteFile */
Sleep ( 1 ) ;
ret = WriteFile ( pipe , " x " , 1 , & num , NULL ) ;
2007-07-16 15:27:53 +02:00
ok ( ret = = 1 , " ret %d \n " , ret ) ;
2007-07-16 13:12:18 +02:00
WaitForSingleObject ( thread , INFINITE ) ;
CloseHandle ( pipe ) ;
CloseHandle ( args . pipe_created ) ;
CloseHandle ( thread ) ;
}
2003-02-19 23:06:36 +01:00
START_TEST ( pipe )
{
2007-03-16 22:37:46 +01:00
HMODULE hmod ;
hmod = GetModuleHandle ( " advapi32.dll " ) ;
pDuplicateTokenEx = ( void * ) GetProcAddress ( hmod , " DuplicateTokenEx " ) ;
2005-03-22 22:14:00 +01:00
if ( test_DisconnectNamedPipe ( ) )
return ;
2003-05-16 00:52:41 +02:00
test_CreateNamedPipe_instances_must_match ( ) ;
test_NamedPipe_2 ( ) ;
2004-04-27 01:30:51 +02:00
test_CreateNamedPipe ( PIPE_TYPE_BYTE ) ;
test_CreateNamedPipe ( PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE ) ;
2005-06-05 19:57:10 +02:00
test_CreatePipe ( ) ;
2007-03-06 19:00:15 +01:00
test_impersonation ( ) ;
2007-07-16 13:12:18 +02:00
test_overlapped ( ) ;
2003-02-19 23:06:36 +01:00
}