2007-03-06 11:59:18 +00: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
2008-05-09 17:35:45 +00:00
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
2007-03-06 11:59:18 +00:00
*/
# include <assert.h>
# include <stdarg.h>
# include <stdio.h>
# include <windef.h>
# include <winbase.h>
# include <winsock.h>
# include <wtypes.h>
# include <winerror.h>
# include "wine/test.h"
# define PIPENAME "\\\\.\\PiPe\\tests_pipe.c"
# define NB_SERVER_LOOPS 8
static HANDLE alarm_event ;
2008-05-09 17:35:45 +00:00
static BOOL ( WINAPI * pDuplicateTokenEx ) ( HANDLE , DWORD , LPSECURITY_ATTRIBUTES ,
SECURITY_IMPERSONATION_LEVEL , TOKEN_TYPE , PHANDLE ) ;
2011-10-05 09:35:25 +00:00
static DWORD ( WINAPI * pQueueUserAPC ) ( PAPCFUNC pfnAPC , HANDLE hThread , ULONG_PTR dwData ) ;
2008-05-09 17:35:45 +00:00
2011-10-03 17:58:01 +00:00
static BOOL user_apc_ran ;
static void CALLBACK user_apc ( ULONG_PTR param )
{
user_apc_ran = TRUE ;
}
2007-03-06 11:59:18 +00:00
static void test_CreateNamedPipe ( int pipemode )
{
HANDLE hnp ;
HANDLE hFile ;
static const char obuf [ ] = " Bit Bucket " ;
static const char obuf2 [ ] = " More bits " ;
char ibuf [ 32 ] , * pbuf ;
DWORD written ;
DWORD readden ;
DWORD avail ;
DWORD lpmode ;
2011-10-03 17:58:01 +00:00
BOOL ret ;
2007-03-06 11:59:18 +00:00
if ( pipemode = = PIPE_TYPE_BYTE )
trace ( " test_CreateNamedPipe starting in byte mode \n " ) ;
else
trace ( " test_CreateNamedPipe starting in message mode \n " ) ;
/* Bad parameter checks */
hnp = CreateNamedPipe ( " not a named pipe " , PIPE_ACCESS_DUPLEX , pipemode | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp = = INVALID_HANDLE_VALUE & & GetLastError ( ) = = ERROR_INVALID_NAME ,
" CreateNamedPipe should fail if name doesn't start with \\ \\ . \\ pipe \n " ) ;
hnp = CreateNamedPipe ( NULL ,
PIPE_ACCESS_DUPLEX , pipemode | PIPE_WAIT ,
1 , 1024 , 1024 , NMPWAIT_USE_DEFAULT_WAIT , NULL ) ;
ok ( hnp = = INVALID_HANDLE_VALUE & & GetLastError ( ) = = ERROR_PATH_NOT_FOUND ,
" CreateNamedPipe should fail if name is NULL \n " ) ;
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
ok ( hFile = = INVALID_HANDLE_VALUE
& & GetLastError ( ) = = ERROR_FILE_NOT_FOUND ,
" connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND \n " ) ;
/* Functional checks */
hnp = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , pipemode | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2011-10-03 17:58:01 +00:00
ret = WaitNamedPipeA ( PIPENAME , 2000 ) ;
ok ( ret , " WaitNamedPipe failed (%d) \n " , GetLastError ( ) ) ;
2007-03-06 11:59:18 +00:00
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
2008-05-09 17:35:45 +00:00
ok ( hFile ! = INVALID_HANDLE_VALUE , " CreateFile failed (%d) \n " , GetLastError ( ) ) ;
ok ( ! WaitNamedPipeA ( PIPENAME , 1000 ) , " WaitNamedPipe succeeded \n " ) ;
2011-10-03 17:58:01 +00:00
2008-05-09 17:35:45 +00:00
ok ( GetLastError ( ) = = ERROR_SEM_TIMEOUT , " wrong error %u \n " , GetLastError ( ) ) ;
2007-03-06 11:59:18 +00: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 ) ) ;
ok ( WriteFile ( hnp , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 1 \n " ) ;
ok ( PeekNamedPipe ( hFile , NULL , 0 , NULL , & readden , NULL ) , " Peek \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) , " peek 1 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
ok ( ReadFile ( hFile , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) , " read 1 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
ok ( memcmp ( obuf , ibuf , written ) = = 0 , " content 1 check \n " ) ;
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
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 " ) ;
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf2 ) , " peek 2 got %d bytes \n " , readden ) ;
2009-01-12 12:29:53 +00:00
ok ( PeekNamedPipe ( hnp , ( LPVOID ) 1 , 0 , NULL , & readden , NULL ) , " Peek \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf2 ) , " peek 2 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf2 ) , " read 2 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00: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 ) {
2008-05-09 17:35:45 +00:00
if ( readden ! = sizeof ( obuf ) ) /* Linux only returns the first message */
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek3 got %d bytes \n " , readden ) ;
else
todo_wine ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek3 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
}
else
2008-05-09 17:35:45 +00: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 ) ;
}
2007-03-06 11:59:18 +00:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2008-05-09 17:35:45 +00:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek3 got %d bytes available \n " , avail ) ;
2007-03-06 11:59:18 +00:00
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " pipe content 3a check \n " ) ;
2008-05-09 17:35:45 +00: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 " ) ;
2007-03-06 11:59:18 +00:00
}
ok ( ReadFile ( hFile , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " read 3 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00: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 ) {
2008-05-09 17:35:45 +00:00
if ( readden ! = sizeof ( obuf ) ) /* Linux only returns the first message */
2007-03-06 11:59:18 +00:00
/* should return all 23 bytes */
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek4 got %d bytes \n " , readden ) ;
else
todo_wine ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek4 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
}
else
2008-05-09 17:35:45 +00: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 ) ;
}
2007-03-06 11:59:18 +00:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2008-05-09 17:35:45 +00:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek4 got %d bytes available \n " , avail ) ;
2007-03-06 11:59:18 +00:00
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " pipe content 4a check \n " ) ;
2008-05-09 17:35:45 +00: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 " ) ;
2007-03-06 11:59:18 +00:00
}
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
if ( pipemode = = PIPE_TYPE_BYTE ) {
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) + sizeof ( obuf2 ) , " read 4 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
}
else {
todo_wine {
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) , " read 4 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00: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 " ) ;
}
2008-05-09 17:35:45 +00:00
2007-03-06 11:59:18 +00:00
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 " ) ;
2008-05-09 17:35:45 +00: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 ) ;
2007-03-06 11:59:18 +00:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2008-05-09 17:35:45 +00:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek5 got %d bytes available \n " , avail ) ;
else
todo_wine ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek5 got %d bytes available \n " , avail ) ;
2007-03-06 11:59:18 +00: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 {
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) , " read 5 got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
}
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 5a check \n " ) ;
2008-05-09 17:35:45 +00:00
2007-03-06 11:59:18 +00:00
/* 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 {
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf2 ) , " peek6a got %d bytes \n " , readden ) ;
ok ( avail = = sizeof ( obuf2 ) , " peek6a got %d bytes available \n " , avail ) ;
2007-03-06 11:59:18 +00:00
}
if ( avail > 0 ) {
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf2 ) , " read 6a got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00: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 " ) ;
2008-05-09 17:35:45 +00: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 ) ;
2007-03-06 11:59:18 +00:00
if ( avail ! = sizeof ( obuf ) ) /* older Linux kernels only return the first write here */
2008-05-09 17:35:45 +00:00
ok ( avail = = sizeof ( obuf ) + sizeof ( obuf2 ) , " peek6b got %d bytes available \n " , avail ) ;
2007-03-06 11:59:18 +00: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 {
2008-05-09 17:35:45 +00:00
ok ( readden = = sizeof ( obuf ) , " read 6b got %d bytes \n " , readden ) ;
2007-03-06 11:59:18 +00:00
}
pbuf = ibuf ;
ok ( memcmp ( obuf , pbuf , sizeof ( obuf ) ) = = 0 , " content 6a check \n " ) ;
}
/* 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 ,
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail \n " ) ;
ok ( GetLastError ( ) = = ERROR_PIPE_BUSY ,
" connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY \n " ) ;
ok ( CloseHandle ( hFile ) , " CloseHandle \n " ) ;
/* case 2: other client already closed */
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
ok ( hFile = = INVALID_HANDLE_VALUE ,
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail \n " ) ;
ok ( GetLastError ( ) = = ERROR_PIPE_BUSY ,
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
/* 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 ,
" connecting to named pipe after other client closes but before DisconnectNamedPipe should fail \n " ) ;
ok ( GetLastError ( ) = = ERROR_PIPE_BUSY ,
" connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY \n " ) ;
/* 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 .
*/
}
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
trace ( " test_CreateNamedPipe returning \n " ) ;
}
static void test_CreateNamedPipe_instances_must_match ( void )
{
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 ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
hnp2 = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 2 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp2 ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
ok ( CloseHandle ( hnp2 ) , " CloseHandle \n " ) ;
/* 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 ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
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
& & GetLastError ( ) = = ERROR_PIPE_BUSY , " nMaxInstances not obeyed \n " ) ;
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
/* 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 ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
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
& & GetLastError ( ) = = ERROR_ACCESS_DENIED , " PIPE_ACCESS_* mismatch allowed \n " ) ;
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
/* etc, etc */
}
/** implementation of alarm() */
static DWORD CALLBACK alarmThreadMain ( LPVOID arg )
{
2009-05-17 07:05:22 +00:00
DWORD_PTR timeout = ( DWORD_PTR ) arg ;
2007-03-06 11:59:18 +00:00
trace ( " alarmThreadMain \n " ) ;
if ( WaitForSingleObject ( alarm_event , timeout ) = = WAIT_TIMEOUT )
{
ok ( FALSE , " alarm \n " ) ;
ExitProcess ( 1 ) ;
}
return 1 ;
}
2011-10-03 17:58:01 +00:00
static HANDLE hnp = INVALID_HANDLE_VALUE ;
2007-03-06 11:59:18 +00:00
/** Trivial byte echo server - disconnects after each session */
static DWORD CALLBACK serverThreadMain1 ( LPVOID arg )
{
int i ;
trace ( " serverThreadMain1 start \n " ) ;
/* 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 ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
char buf [ 512 ] ;
DWORD written ;
DWORD readden ;
DWORD success ;
/* Wait for client to connect */
trace ( " Server calling ConnectNamedPipe... \n " ) ;
ok ( ConnectNamedPipe ( hnp , NULL )
| | GetLastError ( ) = = ERROR_PIPE_CONNECTED , " ConnectNamedPipe \n " ) ;
trace ( " ConnectNamedPipe returned. \n " ) ;
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
trace ( " Server reading... \n " ) ;
success = ReadFile ( hnp , buf , sizeof ( buf ) , & readden , NULL ) ;
trace ( " Server done reading. \n " ) ;
ok ( success , " ReadFile \n " ) ;
ok ( readden , " short read \n " ) ;
trace ( " Server writing... \n " ) ;
ok ( WriteFile ( hnp , buf , readden , & written , NULL ) , " WriteFile \n " ) ;
trace ( " Server done writing. \n " ) ;
ok ( written = = readden , " write file len \n " ) ;
/* finish this connection, wait for next one */
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
trace ( " Server done flushing. \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
trace ( " Server done disconnecting. \n " ) ;
}
return 0 ;
}
/** Trivial byte echo server - closes after each connection */
static DWORD CALLBACK serverThreadMain2 ( LPVOID arg )
{
int i ;
HANDLE hnpNext = 0 ;
trace ( " serverThreadMain2 \n " ) ;
/* 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 ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
char buf [ 512 ] ;
DWORD written ;
DWORD readden ;
DWORD success ;
2011-10-03 17:58:01 +00:00
user_apc_ran = FALSE ;
if ( i = = 0 & & pQueueUserAPC ) {
trace ( " Queueing an user APC \n " ) ; /* verify the pipe is non alerable */
ok ( pQueueUserAPC ( & user_apc , GetCurrentThread ( ) , 0 ) , " QueueUserAPC failed: %d \n " , GetLastError ( ) ) ;
}
2007-03-06 11:59:18 +00:00
/* Wait for client to connect */
trace ( " Server calling ConnectNamedPipe... \n " ) ;
ok ( ConnectNamedPipe ( hnp , NULL )
| | GetLastError ( ) = = ERROR_PIPE_CONNECTED , " ConnectNamedPipe \n " ) ;
trace ( " ConnectNamedPipe returned. \n " ) ;
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
trace ( " Server reading... \n " ) ;
success = ReadFile ( hnp , buf , sizeof ( buf ) , & readden , NULL ) ;
trace ( " Server done reading. \n " ) ;
ok ( success , " ReadFile \n " ) ;
trace ( " Server writing... \n " ) ;
ok ( WriteFile ( hnp , buf , readden , & written , NULL ) , " WriteFile \n " ) ;
trace ( " Server done writing. \n " ) ;
ok ( written = = readden , " write file len \n " ) ;
/* finish this connection, wait for next one */
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
2011-10-03 17:58:01 +00:00
ok ( user_apc_ran = = FALSE , " UserAPC ran, pipe using alertable io mode \n " ) ;
if ( i = = 0 & & pQueueUserAPC )
SleepEx ( 0 , TRUE ) ; /* get rid of apc */
2007-03-06 11:59:18 +00: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 ) ;
ok ( hnpNext ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
hnp = hnpNext ;
}
return 0 ;
}
/** Trivial byte echo server - uses overlapped named pipe calls */
static DWORD CALLBACK serverThreadMain3 ( LPVOID arg )
{
int i ;
HANDLE hEvent ;
trace ( " serverThreadMain3 \n " ) ;
/* Set up a simple echo server */
hnp = CreateNamedPipe ( PIPENAME " serverThreadMain3 " , PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED ,
PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
hEvent = CreateEvent ( NULL , /* security attribute */
TRUE , /* manual reset event */
FALSE , /* initial state */
NULL ) ; /* name */
ok ( hEvent ! = NULL , " CreateEvent \n " ) ;
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
char buf [ 512 ] ;
DWORD written ;
DWORD readden ;
DWORD dummy ;
DWORD success ;
OVERLAPPED oOverlap ;
int letWFSOEwait = ( i & 2 ) ;
int letGORwait = ( i & 1 ) ;
2009-05-17 07:05:22 +00:00
DWORD err ;
2007-03-06 11:59:18 +00:00
memset ( & oOverlap , 0 , sizeof ( oOverlap ) ) ;
oOverlap . hEvent = hEvent ;
/* Wait for client to connect */
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
if ( i = = 0 ) {
trace ( " Server calling non-overlapped ConnectNamedPipe on overlapped pipe... \n " ) ;
success = ConnectNamedPipe ( hnp , NULL ) ;
err = GetLastError ( ) ;
ok ( success | | ( err = = ERROR_PIPE_CONNECTED ) , " ConnectNamedPipe failed: %d \n " , err ) ;
trace ( " ConnectNamedPipe operation complete. \n " ) ;
} else {
trace ( " Server calling overlapped ConnectNamedPipe... \n " ) ;
success = ConnectNamedPipe ( hnp , & oOverlap ) ;
err = GetLastError ( ) ;
ok ( ! success & & ( err = = ERROR_IO_PENDING | | err = = ERROR_PIPE_CONNECTED ) , " overlapped ConnectNamedPipe \n " ) ;
trace ( " overlapped ConnectNamedPipe returned. \n " ) ;
if ( ! success & & ( err = = ERROR_IO_PENDING ) ) {
if ( letWFSOEwait )
{
DWORD ret ;
do {
ret = WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) ;
} while ( ret = = WAIT_IO_COMPLETION ) ;
ok ( ret = = 0 , " wait ConnectNamedPipe returned %x \n " , ret ) ;
}
success = GetOverlappedResult ( hnp , & oOverlap , & dummy , letGORwait ) ;
if ( ! letGORwait & & ! letWFSOEwait & & ! success ) {
ok ( GetLastError ( ) = = ERROR_IO_INCOMPLETE , " GetOverlappedResult \n " ) ;
success = GetOverlappedResult ( hnp , & oOverlap , & dummy , TRUE ) ;
}
2009-05-17 07:05:22 +00:00
}
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
ok ( success | | ( err = = ERROR_PIPE_CONNECTED ) , " GetOverlappedResult ConnectNamedPipe \n " ) ;
trace ( " overlapped ConnectNamedPipe operation complete. \n " ) ;
2009-05-17 07:05:22 +00:00
}
2007-03-06 11:59:18 +00:00
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
trace ( " Server reading... \n " ) ;
2009-05-17 07:05:22 +00:00
success = ReadFile ( hnp , buf , sizeof ( buf ) , & readden , & oOverlap ) ;
2007-03-06 11:59:18 +00:00
trace ( " Server ReadFile returned... \n " ) ;
err = GetLastError ( ) ;
ok ( success | | err = = ERROR_IO_PENDING , " overlapped ReadFile \n " ) ;
trace ( " overlapped ReadFile returned. \n " ) ;
2009-05-17 07:05:22 +00:00
if ( ! success & & ( err = = ERROR_IO_PENDING ) ) {
if ( letWFSOEwait )
{
DWORD ret ;
do {
ret = WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) ;
} while ( ret = = WAIT_IO_COMPLETION ) ;
ok ( ret = = 0 , " wait ReadFile returned %x \n " , ret ) ;
}
success = GetOverlappedResult ( hnp , & oOverlap , & readden , letGORwait ) ;
if ( ! letGORwait & & ! letWFSOEwait & & ! success ) {
ok ( GetLastError ( ) = = ERROR_IO_INCOMPLETE , " GetOverlappedResult \n " ) ;
success = GetOverlappedResult ( hnp , & oOverlap , & readden , TRUE ) ;
}
}
2007-03-06 11:59:18 +00:00
trace ( " Server done reading. \n " ) ;
ok ( success , " overlapped ReadFile \n " ) ;
trace ( " Server writing... \n " ) ;
2009-05-17 07:05:22 +00:00
success = WriteFile ( hnp , buf , readden , & written , & oOverlap ) ;
2007-03-06 11:59:18 +00:00
trace ( " Server WriteFile returned... \n " ) ;
err = GetLastError ( ) ;
ok ( success | | err = = ERROR_IO_PENDING , " overlapped WriteFile \n " ) ;
trace ( " overlapped WriteFile returned. \n " ) ;
2009-05-17 07:05:22 +00:00
if ( ! success & & ( err = = ERROR_IO_PENDING ) ) {
if ( letWFSOEwait )
{
DWORD ret ;
do {
ret = WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) ;
} while ( ret = = WAIT_IO_COMPLETION ) ;
ok ( ret = = 0 , " wait WriteFile returned %x \n " , ret ) ;
}
success = GetOverlappedResult ( hnp , & oOverlap , & written , letGORwait ) ;
if ( ! letGORwait & & ! letWFSOEwait & & ! success ) {
ok ( GetLastError ( ) = = ERROR_IO_INCOMPLETE , " GetOverlappedResult \n " ) ;
success = GetOverlappedResult ( hnp , & oOverlap , & written , TRUE ) ;
}
}
2007-03-06 11:59:18 +00:00
trace ( " Server done writing. \n " ) ;
ok ( success , " overlapped WriteFile \n " ) ;
ok ( written = = readden , " write file len \n " ) ;
/* finish this connection, wait for next one */
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
}
return 0 ;
}
2009-05-17 07:05:22 +00:00
/** Trivial byte echo server - uses i/o completion ports */
static DWORD CALLBACK serverThreadMain4 ( LPVOID arg )
{
int i ;
HANDLE hcompletion ;
2011-10-03 17:58:01 +00:00
BOOL ret ;
2009-05-17 07:05:22 +00:00
trace ( " serverThreadMain4 \n " ) ;
/* Set up a simple echo server */
hnp = CreateNamedPipe ( PIPENAME " serverThreadMain4 " , PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED ,
PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
hcompletion = CreateIoCompletionPort ( hnp , NULL , 12345 , 1 ) ;
ok ( hcompletion ! = NULL , " CreateIoCompletionPort failed, error=%i \n " , GetLastError ( ) ) ;
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
char buf [ 512 ] ;
DWORD written ;
DWORD readden ;
DWORD dummy ;
DWORD success ;
OVERLAPPED oConnect ;
OVERLAPPED oRead ;
OVERLAPPED oWrite ;
OVERLAPPED * oResult ;
DWORD err ;
ULONG_PTR compkey ;
memset ( & oConnect , 0 , sizeof ( oConnect ) ) ;
memset ( & oRead , 0 , sizeof ( oRead ) ) ;
memset ( & oWrite , 0 , sizeof ( oWrite ) ) ;
/* Wait for client to connect */
trace ( " Server calling overlapped ConnectNamedPipe... \n " ) ;
success = ConnectNamedPipe ( hnp , & oConnect ) ;
err = GetLastError ( ) ;
ok ( ! success & & ( err = = ERROR_IO_PENDING | | err = = ERROR_PIPE_CONNECTED ) ,
" overlapped ConnectNamedPipe got %u err %u \n " , success , err ) ;
if ( ! success & & err = = ERROR_IO_PENDING ) {
trace ( " ConnectNamedPipe GetQueuedCompletionStatus \n " ) ;
success = GetQueuedCompletionStatus ( hcompletion , & dummy , & compkey , & oResult , 0 ) ;
if ( ! success )
{
ok ( GetLastError ( ) = = WAIT_TIMEOUT ,
" ConnectNamedPipe GetQueuedCompletionStatus wrong error %u \n " , GetLastError ( ) ) ;
success = GetQueuedCompletionStatus ( hcompletion , & dummy , & compkey , & oResult , 10000 ) ;
}
ok ( success , " ConnectNamedPipe GetQueuedCompletionStatus failed, errno=%i \n " , GetLastError ( ) ) ;
if ( success )
{
ok ( compkey = = 12345 , " got completion key %i instead of 12345 \n " , ( int ) compkey ) ;
ok ( oResult = = & oConnect , " got overlapped pointer %p instead of %p \n " , oResult , & oConnect ) ;
}
}
trace ( " overlapped ConnectNamedPipe operation complete. \n " ) ;
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
trace ( " Server reading... \n " ) ;
success = ReadFile ( hnp , buf , sizeof ( buf ) , & readden , & oRead ) ;
trace ( " Server ReadFile returned... \n " ) ;
err = GetLastError ( ) ;
ok ( success | | err = = ERROR_IO_PENDING , " overlapped ReadFile, err=%i \n " , err ) ;
success = GetQueuedCompletionStatus ( hcompletion , & readden , & compkey ,
& oResult , 10000 ) ;
ok ( success , " ReadFile GetQueuedCompletionStatus failed, errno=%i \n " , GetLastError ( ) ) ;
if ( success )
{
ok ( compkey = = 12345 , " got completion key %i instead of 12345 \n " , ( int ) compkey ) ;
ok ( oResult = = & oRead , " got overlapped pointer %p instead of %p \n " , oResult , & oRead ) ;
}
trace ( " Server done reading. \n " ) ;
trace ( " Server writing... \n " ) ;
success = WriteFile ( hnp , buf , readden , & written , & oWrite ) ;
trace ( " Server WriteFile returned... \n " ) ;
err = GetLastError ( ) ;
ok ( success | | err = = ERROR_IO_PENDING , " overlapped WriteFile failed, err=%u \n " , err ) ;
success = GetQueuedCompletionStatus ( hcompletion , & written , & compkey ,
& oResult , 10000 ) ;
ok ( success , " WriteFile GetQueuedCompletionStatus failed, errno=%i \n " , GetLastError ( ) ) ;
if ( success )
{
ok ( compkey = = 12345 , " got completion key %i instead of 12345 \n " , ( int ) compkey ) ;
ok ( oResult = = & oWrite , " got overlapped pointer %p instead of %p \n " , oResult , & oWrite ) ;
ok ( written = = readden , " write file len \n " ) ;
}
trace ( " Server done writing. \n " ) ;
/* finish this connection, wait for next one */
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
success = DisconnectNamedPipe ( hnp ) ;
ok ( success , " DisconnectNamedPipe failed, err %u \n " , GetLastError ( ) ) ;
}
2011-10-03 17:58:01 +00:00
ret = CloseHandle ( hnp ) ;
ok ( ret , " CloseHandle named pipe failed, err=%i \n " , GetLastError ( ) ) ;
ret = CloseHandle ( hcompletion ) ;
ok ( ret , " CloseHandle completion failed, err=%i \n " , GetLastError ( ) ) ;
2009-05-17 07:05:22 +00:00
return 0 ;
}
2007-03-06 11:59:18 +00:00
static void exercizeServer ( const char * pipename , HANDLE serverThread )
{
int i ;
trace ( " exercizeServer starting \n " ) ;
for ( i = 0 ; i < NB_SERVER_LOOPS ; i + + ) {
HANDLE hFile = INVALID_HANDLE_VALUE ;
static const char obuf [ ] = " Bit Bucket " ;
char ibuf [ 32 ] ;
DWORD written ;
DWORD readden ;
int loop ;
for ( loop = 0 ; loop < 3 ; loop + + ) {
DWORD err ;
trace ( " Client connecting... \n " ) ;
/* 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 )
ok ( err = = ERROR_PIPE_BUSY | | err = = ERROR_FILE_NOT_FOUND , " connecting to pipe \n " ) ;
else
ok ( err = = ERROR_PIPE_BUSY , " connecting to pipe \n " ) ;
trace ( " connect failed, retrying \n " ) ;
Sleep ( 200 ) ;
}
ok ( hFile ! = INVALID_HANDLE_VALUE , " client opening named pipe \n " ) ;
/* Make sure it can echo */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
trace ( " Client writing... \n " ) ;
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile to client end of pipe \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len \n " ) ;
trace ( " Client reading... \n " ) ;
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 " ) ;
trace ( " Client closing... \n " ) ;
ok ( CloseHandle ( hFile ) , " CloseHandle \n " ) ;
}
ok ( WaitForSingleObject ( serverThread , INFINITE ) = = WAIT_OBJECT_0 , " WaitForSingleObject \n " ) ;
CloseHandle ( hnp ) ;
trace ( " exercizeServer returning \n " ) ;
}
static void test_NamedPipe_2 ( void )
{
HANDLE serverThread ;
DWORD serverThreadId ;
HANDLE alarmThread ;
DWORD alarmThreadId ;
trace ( " test_NamedPipe_2 starting \n " ) ;
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
/* Set up a twenty second timeout */
2007-03-06 11:59:18 +00:00
alarm_event = CreateEvent ( NULL , TRUE , FALSE , NULL ) ;
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
SetLastError ( 0xdeadbeef ) ;
alarmThread = CreateThread ( NULL , 0 , alarmThreadMain , ( void * ) 20000 , 0 , & alarmThreadId ) ;
ok ( alarmThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2007-03-06 11:59:18 +00:00
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
/* The servers we're about to exercise do try to clean up carefully,
* but to reduce the chance of a test failure due to a pipe handle
2007-03-06 11:59:18 +00:00
* leak in the test code , we ' ll use a different pipe name for each server .
*/
/* Try server #1 */
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
SetLastError ( 0xdeadbeef ) ;
2007-03-06 11:59:18 +00:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain1 , ( void * ) 8 , 0 , & serverThreadId ) ;
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2007-03-06 11:59:18 +00:00
exercizeServer ( PIPENAME " serverThreadMain1 " , serverThread ) ;
/* Try server #2 */
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
SetLastError ( 0xdeadbeef ) ;
2007-03-06 11:59:18 +00:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain2 , 0 , 0 , & serverThreadId ) ;
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2007-03-06 11:59:18 +00:00
exercizeServer ( PIPENAME " serverThreadMain2 " , serverThread ) ;
/* Try server #3 */
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
SetLastError ( 0xdeadbeef ) ;
2007-03-06 11:59:18 +00:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain3 , 0 , 0 , & serverThreadId ) ;
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2007-03-06 11:59:18 +00:00
exercizeServer ( PIPENAME " serverThreadMain3 " , serverThread ) ;
2009-05-17 07:05:22 +00:00
/* Try server #4 */
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
SetLastError ( 0xdeadbeef ) ;
2009-05-17 07:05:22 +00:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain4 , 0 , 0 , & serverThreadId ) ;
Sync advapi32, comctl32, crypt32, cryptui, cryptnet, fusion, gdi32, gdiplus, hlink, imm32, jscript, kernel32, localspl, msacm32, mscms, msi, mstask, msvcrtd, msxml3, ntdll, ole32, pdh, psapi, quartz, rasapi32, riched20 AND rsaenh Winetests.
TBD mshtml, shell32, oleaut32 which still fail to build here
svn path=/trunk/; revision=47931
2010-07-03 12:45:23 +00:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2009-05-17 07:05:22 +00:00
exercizeServer ( PIPENAME " serverThreadMain4 " , serverThread ) ;
2007-03-06 11:59:18 +00:00
ok ( SetEvent ( alarm_event ) , " SetEvent \n " ) ;
CloseHandle ( alarm_event ) ;
trace ( " test_NamedPipe_2 returning \n " ) ;
}
static int test_DisconnectNamedPipe ( void )
{
HANDLE hnp ;
HANDLE hFile ;
static const char obuf [ ] = " Bit Bucket " ;
char ibuf [ 32 ] ;
DWORD written ;
DWORD readden ;
2009-06-23 11:44:23 +00:00
DWORD ret ;
2007-03-06 11:59:18 +00:00
2008-12-23 20:02:47 +00:00
SetLastError ( 0xdeadbeef ) ;
2007-03-06 11:59:18 +00: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-12-23 20:02:47 +00:00
if ( ( hnp = = INVALID_HANDLE_VALUE /* Win98 */ | | ! hnp /* Win95 */ )
& & GetLastError ( ) = = ERROR_CALL_NOT_IMPLEMENTED ) {
win_skip ( " Named pipes are not implemented \n " ) ;
2007-03-06 11:59:18 +00:00
return 1 ;
}
ok ( WriteFile ( hnp , obuf , sizeof ( obuf ) , & written , NULL ) = = 0
& & GetLastError ( ) = = ERROR_PIPE_LISTENING , " WriteFile to not-yet-connected pipe \n " ) ;
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) = = 0
& & GetLastError ( ) = = ERROR_PIPE_LISTENING , " ReadFile from not-yet-connected pipe \n " ) ;
hFile = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , 0 , 0 ) ;
ok ( hFile ! = INVALID_HANDLE_VALUE , " CreateFile failed \n " ) ;
/* don't try to do i/o if one side couldn't be opened, as it hangs */
if ( hFile ! = INVALID_HANDLE_VALUE ) {
/* see what happens if server calls DisconnectNamedPipe
* when there are bytes in the pipe
*/
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 " ) ;
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) = = 0
& & GetLastError ( ) = = ERROR_PIPE_NOT_CONNECTED , " WriteFile to disconnected pipe \n " ) ;
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) = = 0
& & GetLastError ( ) = = ERROR_PIPE_NOT_CONNECTED ,
" ReadFile from disconnected pipe with bytes waiting \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( ! DisconnectNamedPipe ( hnp ) & & GetLastError ( ) = = ERROR_PIPE_NOT_CONNECTED ,
" DisconnectNamedPipe worked twice \n " ) ;
2009-06-23 11:44:23 +00:00
ret = WaitForSingleObject ( hFile , 0 ) ;
ok ( ret = = WAIT_TIMEOUT , " WaitForSingleObject returned %X \n " , ret ) ;
2007-03-06 11:59:18 +00:00
ok ( CloseHandle ( hFile ) , " CloseHandle \n " ) ;
}
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
return 0 ;
}
static void test_CreatePipe ( void )
{
SECURITY_ATTRIBUTES pipe_attr ;
HANDLE piperead , pipewrite ;
DWORD written ;
DWORD read ;
2008-05-09 17:35:45 +00:00
DWORD i , size ;
BYTE * buffer ;
2007-03-06 11:59:18 +00:00
char readbuf [ 32 ] ;
2011-10-03 17:58:01 +00:00
user_apc_ran = FALSE ;
if ( pQueueUserAPC )
ok ( pQueueUserAPC ( user_apc , GetCurrentThread ( ) , 0 ) , " couldn't create user apc \n " ) ;
2008-05-09 17:35:45 +00:00
pipe_attr . nLength = sizeof ( SECURITY_ATTRIBUTES ) ;
pipe_attr . bInheritHandle = TRUE ;
2011-10-03 17:58:01 +00:00
pipe_attr . lpSecurityDescriptor = NULL ;
2007-03-06 11:59:18 +00:00
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 " ) ;
2008-05-09 17:35:45 +00:00
ok ( written = = sizeof ( PIPENAME ) , " Write to anonymous pipe wrote %d bytes \n " , written ) ;
2007-03-06 11:59:18 +00:00
ok ( ReadFile ( piperead , readbuf , sizeof ( readbuf ) , & read , NULL ) , " Read from non empty pipe failed \n " ) ;
2008-05-09 17:35:45 +00:00
ok ( read = = sizeof ( PIPENAME ) , " Read from anonymous pipe got %d bytes \n " , read ) ;
ok ( CloseHandle ( pipewrite ) , " CloseHandle for the write pipe failed \n " ) ;
ok ( CloseHandle ( piperead ) , " CloseHandle for the read pipe failed \n " ) ;
2007-03-06 11:59:18 +00: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 " ) ;
2008-05-09 17:35:45 +00:00
ok ( written = = sizeof ( PIPENAME ) , " Write to anonymous pipe wrote %d bytes \n " , written ) ;
2007-03-06 11:59:18 +00: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 " ) ;
2008-05-09 17:35:45 +00:00
ok ( read = = sizeof ( PIPENAME ) , " Read from anonymous pipe got %d bytes \n " , read ) ;
/* 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 " ) ;
/* Try bigger chunks */
size = 32768 ;
buffer = HeapAlloc ( GetProcessHeap ( ) , 0 , size ) ;
for ( i = 0 ; i < size ; i + + ) buffer [ i ] = i ;
2008-12-23 20:02:47 +00:00
ok ( CreatePipe ( & piperead , & pipewrite , & pipe_attr , ( size + 24 ) ) ! = 0 , " CreatePipe failed \n " ) ;
2008-05-09 17:35:45 +00: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 ) ;
2007-03-06 11:59:18 +00:00
/* 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 " ) ;
2008-05-09 17:35:45 +00:00
ok ( CloseHandle ( piperead ) , " CloseHandle for the read pipe failed \n " ) ;
HeapFree ( GetProcessHeap ( ) , 0 , buffer ) ;
2011-10-03 17:58:01 +00:00
ok ( user_apc_ran = = FALSE , " user apc ran, pipe using alertable io mode \n " ) ;
SleepEx ( 0 , TRUE ) ; /* get rid of apc */
2008-05-09 17:35:45 +00: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 )
{
2009-05-17 07:05:22 +00:00
struct named_pipe_client_params * params = p ;
2008-05-09 17:35:45 +00:00
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 ( ) ) ;
Privileges = HeapAlloc ( GetProcessHeap ( ) , 0 , Size ) ;
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 ( ) ) ;
ret = pDuplicateTokenEx ( ProcessToken , Access , NULL , ImpersonationLevel , TokenImpersonation , & Token ) ;
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-12-23 20:02:47 +00:00
ok ( ret /* win2k3 */ | | ( error = = ERROR_CANNOT_IMPERSONATE ) ,
" ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d \n " , GetLastError ( ) ) ;
2008-05-09 17:35:45 +00: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 ) ;
ImpersonationLevel = 0xdeadbeef ; /* to avoid false positives */
ret = GetTokenInformation ( hToken , TokenImpersonationLevel , & ImpersonationLevel , sizeof ( ImpersonationLevel ) , & size ) ;
ok ( ret , " GetTokenInformation(TokenImpersonationLevel) failed with error %d \n " , GetLastError ( ) ) ;
ok ( ImpersonationLevel = = SecurityImpersonation , " ImpersonationLevel should have been SecurityImpersonation(%d) instead of %d \n " , SecurityImpersonation , ImpersonationLevel ) ;
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 ) ;
if ( ! ret )
{
HeapFree ( GetProcessHeap ( ) , 0 , Privileges ) ;
return FALSE ;
}
}
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 ;
if ( ! pDuplicateTokenEx ) {
skip ( " DuplicateTokenEx not found \n " ) ;
return ;
}
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 ) ;
}
struct overlapped_server_args
{
HANDLE pipe_created ;
} ;
static DWORD CALLBACK overlapped_server ( LPVOID arg )
{
OVERLAPPED ol ;
HANDLE pipe ;
int ret , err ;
2009-05-17 07:05:22 +00:00
struct overlapped_server_args * a = arg ;
2008-05-09 17:35:45 +00:00
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 ) ;
ok ( ret = = WAIT_OBJECT_0 , " ret %x \n " , ret ) ;
ret = GetOverlappedResult ( pipe , & ol , & num , 1 ) ;
ok ( ret = = 1 , " ret %d \n " , ret ) ;
/* This should block */
ret = ReadFile ( pipe , buf , sizeof ( buf ) , & num , NULL ) ;
ok ( ret = = 1 , " ret %d \n " , ret ) ;
DisconnectNamedPipe ( pipe ) ;
CloseHandle ( ol . hEvent ) ;
CloseHandle ( pipe ) ;
return 1 ;
}
static void test_overlapped ( void )
{
DWORD tid , num ;
HANDLE thread , pipe ;
2011-10-03 17:58:01 +00:00
BOOL ret ;
2008-05-09 17:35:45 +00:00
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 ) ;
2011-10-03 17:58:01 +00:00
ok ( ret , " WriteFile failed with error %d \n " , GetLastError ( ) ) ;
2008-05-09 17:35:45 +00:00
WaitForSingleObject ( thread , INFINITE ) ;
CloseHandle ( pipe ) ;
CloseHandle ( args . pipe_created ) ;
CloseHandle ( thread ) ;
2007-03-06 11:59:18 +00:00
}
2009-05-17 07:05:22 +00:00
static void test_NamedPipeHandleState ( void )
{
HANDLE server , client ;
BOOL ret ;
DWORD state , instances , maxCollectionCount , collectDataTimeout ;
char userName [ MAX_PATH ] ;
server = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX ,
/* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( server ! = INVALID_HANDLE_VALUE , " cf failed \n " ) ;
ret = GetNamedPipeHandleState ( server , NULL , NULL , NULL , NULL , NULL , 0 ) ;
todo_wine
ok ( ret , " GetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
ret = GetNamedPipeHandleState ( server , & state , & instances , NULL , NULL , NULL ,
0 ) ;
todo_wine
ok ( ret , " GetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
if ( ret )
{
ok ( state = = 0 , " unexpected state %08x \n " , state ) ;
ok ( instances = = 1 , " expected 1 instances, got %d \n " , instances ) ;
}
/* Some parameters have no meaning, and therefore can't be retrieved,
* on a local pipe .
*/
SetLastError ( 0xdeadbeef ) ;
ret = GetNamedPipeHandleState ( server , & state , & instances ,
& maxCollectionCount , & collectDataTimeout , userName ,
sizeof ( userName ) / sizeof ( userName [ 0 ] ) ) ;
todo_wine
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER ,
" expected ERROR_INVALID_PARAMETER, got %d \n " , GetLastError ( ) ) ;
/* A byte-mode pipe server can't be changed to message mode. */
state = PIPE_READMODE_MESSAGE ;
SetLastError ( 0xdeadbeef ) ;
ret = SetNamedPipeHandleState ( server , & state , NULL , NULL ) ;
todo_wine
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER ,
" expected ERROR_INVALID_PARAMETER, got %d \n " , GetLastError ( ) ) ;
client = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL ,
OPEN_EXISTING , 0 , NULL ) ;
ok ( client ! = INVALID_HANDLE_VALUE , " cf failed \n " ) ;
state = PIPE_READMODE_BYTE ;
ret = SetNamedPipeHandleState ( client , & state , NULL , NULL ) ;
todo_wine
ok ( ret , " SetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
/* A byte-mode pipe client can't be changed to message mode, either. */
state = PIPE_READMODE_MESSAGE ;
SetLastError ( 0xdeadbeef ) ;
ret = SetNamedPipeHandleState ( server , & state , NULL , NULL ) ;
todo_wine
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER ,
" expected ERROR_INVALID_PARAMETER, got %d \n " , GetLastError ( ) ) ;
CloseHandle ( client ) ;
CloseHandle ( server ) ;
server = CreateNamedPipe ( PIPENAME , PIPE_ACCESS_DUPLEX ,
/* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_WAIT ,
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( server ! = INVALID_HANDLE_VALUE , " cf failed \n " ) ;
ret = GetNamedPipeHandleState ( server , NULL , NULL , NULL , NULL , NULL , 0 ) ;
todo_wine
ok ( ret , " GetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
ret = GetNamedPipeHandleState ( server , & state , & instances , NULL , NULL , NULL ,
0 ) ;
todo_wine
ok ( ret , " GetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
if ( ret )
{
ok ( state = = 0 , " unexpected state %08x \n " , state ) ;
ok ( instances = = 1 , " expected 1 instances, got %d \n " , instances ) ;
}
/* In contrast to byte-mode pipes, a message-mode pipe server can be
* changed to byte mode .
*/
state = PIPE_READMODE_BYTE ;
ret = SetNamedPipeHandleState ( server , & state , NULL , NULL ) ;
todo_wine
ok ( ret , " SetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
client = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL ,
OPEN_EXISTING , 0 , NULL ) ;
ok ( client ! = INVALID_HANDLE_VALUE , " cf failed \n " ) ;
state = PIPE_READMODE_MESSAGE ;
ret = SetNamedPipeHandleState ( client , & state , NULL , NULL ) ;
todo_wine
ok ( ret , " SetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
/* A message-mode pipe client can also be changed to byte mode.
*/
state = PIPE_READMODE_BYTE ;
ret = SetNamedPipeHandleState ( client , & state , NULL , NULL ) ;
todo_wine
ok ( ret , " SetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
CloseHandle ( client ) ;
CloseHandle ( server ) ;
}
2007-03-06 11:59:18 +00:00
START_TEST ( pipe )
{
2008-05-09 17:35:45 +00:00
HMODULE hmod ;
hmod = GetModuleHandle ( " advapi32.dll " ) ;
pDuplicateTokenEx = ( void * ) GetProcAddress ( hmod , " DuplicateTokenEx " ) ;
2011-10-03 17:58:01 +00:00
hmod = GetModuleHandle ( " kernel32.dll " ) ;
pQueueUserAPC = ( void * ) GetProcAddress ( hmod , " QueueUserAPC " ) ;
2008-05-09 17:35:45 +00:00
2007-03-06 11:59:18 +00:00
if ( test_DisconnectNamedPipe ( ) )
return ;
test_CreateNamedPipe_instances_must_match ( ) ;
test_NamedPipe_2 ( ) ;
test_CreateNamedPipe ( PIPE_TYPE_BYTE ) ;
test_CreateNamedPipe ( PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE ) ;
test_CreatePipe ( ) ;
2008-05-09 17:35:45 +00:00
test_impersonation ( ) ;
test_overlapped ( ) ;
2009-05-17 07:05:22 +00:00
test_NamedPipeHandleState ( ) ;
2007-03-06 11:59:18 +00:00
}