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 <stdarg.h>
2003-02-19 23:06:36 +01:00
# include <stdio.h>
2003-09-06 01:08:26 +02:00
2013-09-18 08:54:32 +02:00
# include "ntstatus.h"
# define WIN32_NO_STATUS
2013-10-21 10:02:23 +02:00
# include "windef.h"
# include "winbase.h"
# include "winternl.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 ) ;
2011-10-04 22:45:49 +02:00
static DWORD ( WINAPI * pQueueUserAPC ) ( PAPCFUNC pfnAPC , HANDLE hThread , ULONG_PTR dwData ) ;
2007-03-16 22:37:46 +01:00
2011-08-22 11:02:51 +02:00
static BOOL user_apc_ran ;
static void CALLBACK user_apc ( ULONG_PTR param )
{
user_apc_ran = TRUE ;
}
2004-05-04 02:43:46 +02:00
2014-09-04 17:24:12 +02:00
enum rpcThreadOp
{
RPC_READFILE
} ;
struct rpcThreadArgs
{
ULONG_PTR returnValue ;
DWORD lastError ;
enum rpcThreadOp op ;
ULONG_PTR args [ 5 ] ;
} ;
static DWORD CALLBACK rpcThreadMain ( LPVOID arg )
{
struct rpcThreadArgs * rpcargs = ( struct rpcThreadArgs * ) arg ;
trace ( " rpcThreadMain starting \n " ) ;
SetLastError ( rpcargs - > lastError ) ;
switch ( rpcargs - > op )
{
case RPC_READFILE :
rpcargs - > returnValue = ( ULONG_PTR ) ReadFile ( ( HANDLE ) rpcargs - > args [ 0 ] , /* hFile */
( LPVOID ) rpcargs - > args [ 1 ] , /* buffer */
( DWORD ) rpcargs - > args [ 2 ] , /* bytesToRead */
( LPDWORD ) rpcargs - > args [ 3 ] , /* bytesRead */
( LPOVERLAPPED ) rpcargs - > args [ 4 ] ) ; /* overlapped */
break ;
default :
SetLastError ( ERROR_CALL_NOT_IMPLEMENTED ) ;
rpcargs - > returnValue = 0 ;
break ;
}
rpcargs - > lastError = GetLastError ( ) ;
trace ( " rpcThreadMain returning \n " ) ;
return 0 ;
}
/* Runs ReadFile(...) from a different thread */
static BOOL RpcReadFile ( HANDLE hFile , LPVOID buffer , DWORD bytesToRead , LPDWORD bytesRead , LPOVERLAPPED overlapped )
{
struct rpcThreadArgs rpcargs ;
HANDLE thread ;
2015-01-20 23:56:41 +01:00
DWORD threadId , ret ;
2014-09-04 17:24:12 +02:00
rpcargs . returnValue = 0 ;
rpcargs . lastError = GetLastError ( ) ;
rpcargs . op = RPC_READFILE ;
rpcargs . args [ 0 ] = ( ULONG_PTR ) hFile ;
rpcargs . args [ 1 ] = ( ULONG_PTR ) buffer ;
rpcargs . args [ 2 ] = ( ULONG_PTR ) bytesToRead ;
rpcargs . args [ 3 ] = ( ULONG_PTR ) bytesRead ;
rpcargs . args [ 4 ] = ( ULONG_PTR ) overlapped ;
thread = CreateThread ( NULL , 0 , rpcThreadMain , ( void * ) & rpcargs , 0 , & threadId ) ;
ok ( thread ! = NULL , " CreateThread failed. %d \n " , GetLastError ( ) ) ;
2015-01-20 23:56:41 +01:00
ret = WaitForSingleObject ( thread , INFINITE ) ;
ok ( ret = = WAIT_OBJECT_0 , " WaitForSingleObject failed with %d. \n " , GetLastError ( ) ) ;
2014-09-04 17:24:12 +02:00
CloseHandle ( thread ) ;
SetLastError ( rpcargs . lastError ) ;
return ( BOOL ) rpcargs . returnValue ;
}
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 ;
2011-01-11 20:30:00 +01:00
BOOL ret ;
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 " ) ;
2014-05-31 02:44:36 +02:00
2014-09-28 23:53:46 +02:00
/* Wait for nonexistent pipe */
2014-05-31 02:44:36 +02:00
ret = WaitNamedPipeA ( PIPENAME , 2000 ) ;
2014-09-28 23:53:46 +02:00
ok ( ret = = 0 , " WaitNamedPipe returned %d for nonexistent pipe \n " , ret ) ;
2014-05-31 02:44:36 +02:00
ok ( GetLastError ( ) = = ERROR_FILE_NOT_FOUND , " wrong error %u \n " , GetLastError ( ) ) ;
2003-02-19 23:06:36 +01:00
/* Bad parameter checks */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( " 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 ) ;
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
2011-10-12 14:50:40 +02:00
if ( pipemode = = PIPE_TYPE_BYTE )
{
/* Bad parameter checks */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_READMODE_MESSAGE ,
2011-10-12 14:50:40 +02:00
/* nMaxInstances */ 1 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp = = INVALID_HANDLE_VALUE & & GetLastError ( ) = = ERROR_INVALID_PARAMETER ,
" CreateNamedPipe should fail with PIPE_TYPE_BYTE | PIPE_READMODE_MESSAGE \n " ) ;
}
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( 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 */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( 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
2011-01-11 20:30:00 +01:00
ret = WaitNamedPipeA ( PIPENAME , 2000 ) ;
ok ( ret , " 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 " ) ;
2011-01-11 20:30:00 +01:00
2007-04-17 22:07:07 +02:00
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 " ) ;
2014-09-04 17:06:12 +02:00
ok ( written = = sizeof ( obuf ) , " write file len \n " ) ;
ok ( ReadFile ( hFile , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
ok ( readden = = sizeof ( obuf ) , " read got %d bytes \n " , readden ) ;
ok ( memcmp ( obuf , ibuf , written ) = = 0 , " content check \n " ) ;
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hFile , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len \n " ) ;
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
ok ( readden = = sizeof ( obuf2 ) , " read got %d bytes \n " , readden ) ;
ok ( memcmp ( obuf2 , ibuf , written ) = = 0 , " content check \n " ) ;
/* Now the same again, but with an additional call to PeekNamedPipe */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
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 " ) ;
2014-09-04 17:14:19 +02:00
/* Test how ReadFile behaves when the buffer is not big enough for the whole message */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hnp , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len \n " ) ;
ok ( ReadFile ( hFile , ibuf , 4 , & readden , NULL ) , " ReadFile \n " ) ;
ok ( readden = = 4 , " read got %d bytes \n " , readden ) ;
ok ( ReadFile ( hFile , ibuf + 4 , sizeof ( ibuf ) - 4 , & readden , NULL ) , " ReadFile \n " ) ;
ok ( readden = = sizeof ( obuf2 ) - 4 , " read got %d bytes \n " , readden ) ;
ok ( memcmp ( obuf2 , ibuf , written ) = = 0 , " content check \n " ) ;
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len \n " ) ;
if ( pipemode = = PIPE_TYPE_BYTE )
{
ok ( ReadFile ( hnp , ibuf , 4 , & readden , NULL ) , " ReadFile \n " ) ;
}
else
{
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hnp , ibuf , 4 , & readden , NULL ) , " ReadFile \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error \n " ) ;
}
ok ( readden = = 4 , " read got %d bytes \n " , readden ) ;
ok ( ReadFile ( hnp , ibuf + 4 , sizeof ( ibuf ) - 4 , & readden , NULL ) , " ReadFile \n " ) ;
ok ( readden = = sizeof ( obuf ) - 4 , " read got %d bytes \n " , readden ) ;
ok ( memcmp ( obuf , ibuf , written ) = = 0 , " content check \n " ) ;
/* Similar to above, but use a read buffer size small enough to read in three parts */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hFile , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len \n " ) ;
if ( pipemode = = PIPE_TYPE_BYTE )
{
ok ( ReadFile ( hnp , ibuf , 4 , & readden , NULL ) , " ReadFile \n " ) ;
ok ( readden = = 4 , " read got %d bytes \n " , readden ) ;
ok ( ReadFile ( hnp , ibuf + 4 , 4 , & readden , NULL ) , " ReadFile \n " ) ;
}
else
{
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hnp , ibuf , 4 , & readden , NULL ) , " ReadFile \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error \n " ) ;
ok ( readden = = 4 , " read got %d bytes \n " , readden ) ;
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hnp , ibuf + 4 , 4 , & readden , NULL ) , " ReadFile \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error \n " ) ;
}
ok ( readden = = 4 , " read got %d bytes \n " , readden ) ;
ok ( ReadFile ( hnp , ibuf + 8 , sizeof ( ibuf ) - 8 , & readden , NULL ) , " ReadFile \n " ) ;
ok ( readden = = sizeof ( obuf2 ) - 8 , " read got %d bytes \n " , readden ) ;
ok ( memcmp ( obuf2 , ibuf , written ) = = 0 , " content check \n " ) ;
2004-04-27 01:30:51 +02:00
/* 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 ) {
2014-07-30 18:00:19 +02:00
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
{
2014-07-30 18:00:19 +02:00
ok ( readden = = sizeof ( obuf ) , " peek3 got %d bytes \n " , readden ) ;
2006-11-09 15:40:36 +01:00
}
2014-07-30 18:00:19 +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 ) {
2014-07-30 18:00:19 +02:00
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
{
2014-07-30 18:00:19 +02:00
ok ( readden = = sizeof ( obuf ) , " peek4 got %d bytes \n " , readden ) ;
2006-11-09 15:40:36 +01:00
}
2014-07-30 18:00:19 +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 {
2014-08-21 05:41:15 +02:00
ok ( SetNamedPipeHandleState ( hFile , & lpmode , NULL , NULL ) , " Change mode \n " ) ;
2004-04-27 01:30:51 +02: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 " ) ;
2014-07-30 18:00:19 +02:00
ok ( readden = = sizeof ( obuf ) , " peek5 got %d bytes \n " , readden ) ;
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 " ) ;
2014-09-04 17:10:45 +02:00
if ( readden < = sizeof ( obuf ) )
ok ( ReadFile ( hFile , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2004-04-27 01:30:51 +02: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 {
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 " ) ;
2014-07-30 18:00:19 +02:00
ok ( readden = = sizeof ( obuf ) , " peek6 got %d bytes \n " , readden ) ;
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 " ) ;
2014-09-04 17:10:45 +02:00
if ( readden < = sizeof ( obuf ) )
ok ( ReadFile ( hnp , ibuf , sizeof ( ibuf ) , & readden , NULL ) , " ReadFile \n " ) ;
2014-09-04 17:16:33 +02:00
/* Test how ReadFile behaves when the buffer is not big enough for the whole message */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hnp , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile 7 \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 7 \n " ) ;
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hFile , ibuf , 4 , & readden , NULL ) , " ReadFile 7 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 7 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 7 \n " , readden ) ;
ok ( ReadFile ( hFile , ibuf + 4 , sizeof ( ibuf ) - 4 , & readden , NULL ) , " ReadFile 7 \n " ) ;
ok ( readden = = sizeof ( obuf2 ) - 4 , " read got %d bytes 7 \n " , readden ) ;
ok ( memcmp ( obuf2 , ibuf , written ) = = 0 , " content check 7 \n " ) ;
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile 8 \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 8 \n " ) ;
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hnp , ibuf , 4 , & readden , NULL ) , " ReadFile 8 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 8 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 8 \n " , readden ) ;
ok ( ReadFile ( hnp , ibuf + 4 , sizeof ( ibuf ) - 4 , & readden , NULL ) , " ReadFile 8 \n " ) ;
ok ( readden = = sizeof ( obuf ) - 4 , " read got %d bytes 8 \n " , readden ) ;
ok ( memcmp ( obuf , ibuf , written ) = = 0 , " content check 8 \n " ) ;
2014-09-04 17:24:12 +02:00
/* The following test shows that when doing a partial read of a message, the rest
* is still in the pipe , and can be received from a second thread . This shows
* especially that the content is _not_ stored in thread - local - storage until it is
* completely transmitted . The same method works even across multiple processes . */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hnp , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile 9 \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 9 \n " ) ;
ok ( WriteFile ( hnp , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile 9 \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 9 \n " ) ;
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hFile , ibuf , 4 , & readden , NULL ) , " ReadFile 9 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 9 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 9 \n " , readden ) ;
SetLastError ( 0xdeadbeef ) ;
ret = RpcReadFile ( hFile , ibuf + 4 , 4 , & readden , NULL ) ;
todo_wine
ok ( ! ret , " RpcReadFile 9 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 9 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 9 \n " , readden ) ;
ret = RpcReadFile ( hFile , ibuf + 8 , sizeof ( ibuf ) , & readden , NULL ) ;
ok ( ret , " RpcReadFile 9 \n " ) ;
todo_wine
ok ( readden = = sizeof ( obuf ) - 8 , " read got %d bytes 9 \n " , readden ) ;
ok ( memcmp ( obuf , ibuf , sizeof ( obuf ) ) = = 0 , " content check 9 \n " ) ;
if ( readden < = sizeof ( obuf ) - 8 ) /* blocks forever if second part was already received */
{
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = RpcReadFile ( hFile , ibuf , 4 , & readden , NULL ) ;
ok ( ! ret , " RpcReadFile 9 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 9 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 9 \n " , readden ) ;
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hFile , ibuf + 4 , 4 , & readden , NULL ) , " ReadFile 9 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 9 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 9 \n " , readden ) ;
ret = RpcReadFile ( hFile , ibuf + 8 , sizeof ( ibuf ) , & readden , NULL ) ;
ok ( ret , " RpcReadFile 9 \n " ) ;
ok ( readden = = sizeof ( obuf2 ) - 8 , " read got %d bytes 9 \n " , readden ) ;
ok ( memcmp ( obuf2 , ibuf , sizeof ( obuf2 ) ) = = 0 , " content check 9 \n " ) ;
}
/* Now the reverse direction */
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
ok ( WriteFile ( hFile , obuf2 , sizeof ( obuf2 ) , & written , NULL ) , " WriteFile 10 \n " ) ;
ok ( written = = sizeof ( obuf2 ) , " write file len 10 \n " ) ;
ok ( WriteFile ( hFile , obuf , sizeof ( obuf ) , & written , NULL ) , " WriteFile 10 \n " ) ;
ok ( written = = sizeof ( obuf ) , " write file len 10 \n " ) ;
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hnp , ibuf , 4 , & readden , NULL ) , " ReadFile 10 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 10 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 10 \n " , readden ) ;
SetLastError ( 0xdeadbeef ) ;
ret = RpcReadFile ( hnp , ibuf + 4 , 4 , & readden , NULL ) ;
todo_wine
ok ( ! ret , " RpcReadFile 10 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 10 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 10 \n " , readden ) ;
ret = RpcReadFile ( hnp , ibuf + 8 , sizeof ( ibuf ) , & readden , NULL ) ;
ok ( ret , " RpcReadFile 10 \n " ) ;
todo_wine
ok ( readden = = sizeof ( obuf2 ) - 8 , " read got %d bytes 10 \n " , readden ) ;
ok ( memcmp ( obuf2 , ibuf , sizeof ( obuf2 ) ) = = 0 , " content check 10 \n " ) ;
if ( readden < = sizeof ( obuf2 ) - 8 ) /* blocks forever if second part was already received */
{
memset ( ibuf , 0 , sizeof ( ibuf ) ) ;
SetLastError ( 0xdeadbeef ) ;
ret = RpcReadFile ( hnp , ibuf , 4 , & readden , NULL ) ;
ok ( ! ret , " RpcReadFile 10 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 10 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 10 \n " , readden ) ;
SetLastError ( 0xdeadbeef ) ;
todo_wine
ok ( ! ReadFile ( hnp , ibuf + 4 , 4 , & readden , NULL ) , " ReadFile 10 \n " ) ;
todo_wine
ok ( GetLastError ( ) = = ERROR_MORE_DATA , " wrong error 10 \n " ) ;
ok ( readden = = 4 , " read got %d bytes 10 \n " , readden ) ;
ret = RpcReadFile ( hnp , ibuf + 8 , sizeof ( ibuf ) , & readden , NULL ) ;
ok ( ret , " RpcReadFile 10 \n " ) ;
ok ( readden = = sizeof ( obuf ) - 8 , " read got %d bytes 10 \n " , readden ) ;
ok ( memcmp ( obuf , ibuf , sizeof ( obuf ) ) = = 0 , " content check 10 \n " ) ;
}
2004-04-27 01:30:51 +02:00
}
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 */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
2003-05-16 00:52:41 +02:00
/* 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
2013-10-21 10:02:23 +02:00
hnp2 = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
2003-05-16 00:52:41 +02:00
/* 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 */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | 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
2013-10-21 10:02:23 +02:00
hnp2 = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
2003-05-16 00:52:41 +02:00
/* 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_* */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
2003-05-16 00:52:41 +02:00
/* 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
2013-10-21 10:02:23 +02:00
hnp2 = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_INBOUND , PIPE_TYPE_BYTE | PIPE_WAIT ,
2011-09-26 13:57:29 +02:00
/* nMaxInstances */ 2 ,
2003-05-16 00:52:41 +02:00
/* 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
2011-09-26 13:57:29 +02:00
/* check everything else */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
2011-09-26 13:57:29 +02:00
/* nMaxInstances */ 4 ,
/* nOutBufSize */ 1024 ,
/* nInBufSize */ 1024 ,
/* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
2013-10-21 10:02:23 +02:00
hnp2 = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_MESSAGE ,
2011-09-26 13:57:29 +02:00
/* nMaxInstances */ 3 ,
/* nOutBufSize */ 102 ,
/* nInBufSize */ 24 ,
/* nDefaultWait */ 1234 ,
/* lpSecurityAttrib */ NULL ) ;
ok ( hnp2 ! = INVALID_HANDLE_VALUE , " CreateNamedPipe failed \n " ) ;
ok ( CloseHandle ( hnp ) , " CloseHandle \n " ) ;
ok ( CloseHandle ( hnp2 ) , " CloseHandle \n " ) ;
2003-05-16 00:52:41 +02:00
}
/** 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 ;
}
2010-10-01 13:36:35 +02:00
static HANDLE hnp = INVALID_HANDLE_VALUE ;
2003-05-16 00:52:41 +02:00
/** 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 */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME " serverThreadMain1 " , PIPE_ACCESS_DUPLEX ,
2003-05-16 00:52:41 +02:00
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 ;
2013-11-19 01:05:54 +01:00
BOOL success ;
2003-05-16 00:52:41 +02:00
/* 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 */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME " serverThreadMain2 " , PIPE_ACCESS_DUPLEX ,
2003-05-16 00:52:41 +02:00
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 ;
2013-11-19 01:05:54 +01:00
DWORD ret ;
BOOL success ;
2003-05-16 00:52:41 +02:00
2011-08-22 11:02:51 +02:00
user_apc_ran = FALSE ;
if ( i = = 0 & & pQueueUserAPC ) {
trace ( " Queueing an user APC \n " ) ; /* verify the pipe is non alerable */
2013-11-19 01:05:54 +01:00
ret = pQueueUserAPC ( & user_apc , GetCurrentThread ( ) , 0 ) ;
ok ( ret , " QueueUserAPC failed: %d \n " , GetLastError ( ) ) ;
2011-08-22 11:02:51 +02:00
}
2003-05-16 00:52:41 +02:00
/* 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
2011-08-22 11:02:51 +02: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 */
2003-05-16 00:52:41 +02:00
/* Set up next echo server */
hnpNext =
2013-10-21 10:02:23 +02:00
CreateNamedPipeA ( PIPENAME " serverThreadMain2 " , PIPE_ACCESS_DUPLEX ,
2003-05-16 00:52:41 +02:00
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 */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME " serverThreadMain3 " , PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED ,
2003-05-16 00:52:41 +02:00
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
2013-10-21 10:02:23 +02:00
hEvent = CreateEventW ( NULL , /* security attribute */
2003-05-16 00:52:41 +02:00
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 ;
2013-11-19 01:05:54 +01:00
BOOL success ;
2003-05-16 00:52:41 +02:00
OVERLAPPED oOverlap ;
int letWFSOEwait = ( i & 2 ) ;
int letGORwait = ( i & 1 ) ;
2009-02-19 23:49:55 +01:00
DWORD err ;
2003-05-16 00:52:41 +02:00
memset ( & oOverlap , 0 , sizeof ( oOverlap ) ) ;
oOverlap . hEvent = hEvent ;
/* Wait for client to connect */
2010-05-22 20:00:59 +02: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-02-19 23:49:55 +01:00
}
2010-05-22 20:00:59 +02:00
ok ( success | | ( err = = ERROR_PIPE_CONNECTED ) , " GetOverlappedResult ConnectNamedPipe \n " ) ;
trace ( " overlapped ConnectNamedPipe operation complete. \n " ) ;
2009-02-19 23:49:55 +01:00
}
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 " ) ;
2009-02-19 23:49:55 +01:00
success = ReadFile ( hnp , buf , sizeof ( buf ) , & readden , & 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 " ) ;
2009-02-19 23:49:55 +01: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 ) ;
}
}
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 " ) ;
2009-02-19 23:49:55 +01:00
success = WriteFile ( hnp , buf , readden , & written , & 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 " ) ;
2009-02-19 23:49:55 +01: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 ) ;
}
}
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
}
2009-02-20 20:39:44 +01:00
/** Trivial byte echo server - uses i/o completion ports */
static DWORD CALLBACK serverThreadMain4 ( LPVOID arg )
{
int i ;
HANDLE hcompletion ;
2011-01-11 20:30:00 +01:00
BOOL ret ;
2009-02-20 20:39:44 +01:00
trace ( " serverThreadMain4 \n " ) ;
/* Set up a simple echo server */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME " serverThreadMain4 " , PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED ,
2009-02-20 20:39:44 +01:00
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 ;
2013-11-19 01:05:54 +01:00
BOOL success ;
2009-02-20 20:39:44 +01:00
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 ( ) ;
2009-03-04 15:45:48 +01:00
ok ( ! success & & ( err = = ERROR_IO_PENDING | | err = = ERROR_PIPE_CONNECTED ) ,
" overlapped ConnectNamedPipe got %u err %u \n " , success , err ) ;
2009-02-20 20:39:44 +01:00
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 ( ) ;
2009-03-04 15:45:48 +01:00
ok ( success | | err = = ERROR_IO_PENDING , " overlapped WriteFile failed, err=%u \n " , err ) ;
2009-02-20 20:39:44 +01:00
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 " ) ;
2009-03-04 15:45:48 +01:00
success = DisconnectNamedPipe ( hnp ) ;
ok ( success , " DisconnectNamedPipe failed, err %u \n " , GetLastError ( ) ) ;
2009-02-20 20:39:44 +01:00
}
2011-01-11 20:30:00 +01: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-02-20 20:39:44 +01:00
return 0 ;
}
2012-06-14 20:38:19 +02:00
static int completion_called ;
static DWORD completion_errorcode ;
static DWORD completion_num_bytes ;
static LPOVERLAPPED completion_lpoverlapped ;
static VOID WINAPI completion_routine ( DWORD errorcode , DWORD num_bytes , LPOVERLAPPED lpoverlapped )
{
completion_called + + ;
completion_errorcode = errorcode ;
completion_num_bytes = num_bytes ;
completion_lpoverlapped = lpoverlapped ;
SetEvent ( lpoverlapped - > hEvent ) ;
}
/** Trivial byte echo server - uses ReadFileEx/WriteFileEx */
static DWORD CALLBACK serverThreadMain5 ( LPVOID arg )
{
int i ;
HANDLE hEvent ;
trace ( " serverThreadMain5 \n " ) ;
/* Set up a simple echo server */
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME " serverThreadMain5 " , PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED ,
2012-06-14 20:38:19 +02:00
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 " ) ;
2013-10-21 10:02:23 +02:00
hEvent = CreateEventW ( NULL , /* security attribute */
2012-06-14 20:38:19 +02:00
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 readden ;
2013-11-19 01:05:54 +01:00
BOOL success ;
2012-06-14 20:38:19 +02:00
OVERLAPPED oOverlap ;
DWORD err ;
memset ( & oOverlap , 0 , sizeof ( oOverlap ) ) ;
oOverlap . hEvent = hEvent ;
/* Wait for client to connect */
trace ( " Server calling ConnectNamedPipe... \n " ) ;
success = ConnectNamedPipe ( hnp , NULL ) ;
err = GetLastError ( ) ;
ok ( success | | ( err = = ERROR_PIPE_CONNECTED ) , " ConnectNamedPipe failed: %d \n " , err ) ;
trace ( " ConnectNamedPipe operation complete. \n " ) ;
/* Echo bytes once */
memset ( buf , 0 , sizeof ( buf ) ) ;
trace ( " Server reading... \n " ) ;
completion_called = 0 ;
ResetEvent ( hEvent ) ;
success = ReadFileEx ( hnp , buf , sizeof ( buf ) , & oOverlap , completion_routine ) ;
trace ( " Server ReadFileEx returned... \n " ) ;
ok ( success , " ReadFileEx failed, err=%i \n " , GetLastError ( ) ) ;
ok ( completion_called = = 0 , " completion routine called before ReadFileEx return \n " ) ;
trace ( " ReadFileEx returned. \n " ) ;
if ( success ) {
DWORD ret ;
do {
ret = WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) ;
} while ( ret = = WAIT_IO_COMPLETION ) ;
ok ( ret = = 0 , " wait ReadFileEx returned %x \n " , ret ) ;
}
ok ( completion_called = = 1 , " completion routine called %i times \n " , completion_called ) ;
ok ( completion_errorcode = = ERROR_SUCCESS , " completion routine got error %d \n " , completion_errorcode ) ;
2012-06-18 11:38:38 +02:00
ok ( completion_num_bytes ! = 0 , " read 0 bytes \n " ) ;
2012-06-14 20:38:19 +02:00
ok ( completion_lpoverlapped = = & oOverlap , " got wrong overlapped pointer %p \n " , completion_lpoverlapped ) ;
readden = completion_num_bytes ;
trace ( " Server done reading. \n " ) ;
trace ( " Server writing... \n " ) ;
completion_called = 0 ;
ResetEvent ( hEvent ) ;
success = WriteFileEx ( hnp , buf , readden , & oOverlap , completion_routine ) ;
trace ( " Server WriteFileEx returned... \n " ) ;
ok ( success , " WriteFileEx failed, err=%i \n " , GetLastError ( ) ) ;
ok ( completion_called = = 0 , " completion routine called before ReadFileEx return \n " ) ;
trace ( " overlapped WriteFile returned. \n " ) ;
if ( success ) {
DWORD ret ;
do {
ret = WaitForSingleObjectEx ( hEvent , INFINITE , TRUE ) ;
} while ( ret = = WAIT_IO_COMPLETION ) ;
ok ( ret = = 0 , " wait WriteFileEx returned %x \n " , ret ) ;
}
trace ( " Server done writing. \n " ) ;
ok ( completion_called = = 1 , " completion routine called %i times \n " , completion_called ) ;
ok ( completion_errorcode = = ERROR_SUCCESS , " completion routine got error %d \n " , completion_errorcode ) ;
ok ( completion_num_bytes = = readden , " read %i bytes wrote %i \n " , readden , completion_num_bytes ) ;
ok ( completion_lpoverlapped = = & oOverlap , " got wrong overlapped pointer %p \n " , completion_lpoverlapped ) ;
/* finish this connection, wait for next one */
ok ( FlushFileBuffers ( hnp ) , " FlushFileBuffers \n " ) ;
ok ( DisconnectNamedPipe ( hnp ) , " DisconnectNamedPipe \n " ) ;
}
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 " ) ;
2010-04-30 18:38:59 +02:00
/* Set up a twenty second timeout */
2013-10-21 10:02:23 +02:00
alarm_event = CreateEventW ( NULL , TRUE , FALSE , NULL ) ;
2010-05-22 21:06:32 +02:00
SetLastError ( 0xdeadbeef ) ;
2010-04-30 18:38:59 +02:00
alarmThread = CreateThread ( NULL , 0 , alarmThreadMain , ( void * ) 20000 , 0 , & alarmThreadId ) ;
2010-05-22 21:06:32 +02:00
ok ( alarmThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2003-05-16 00:52:41 +02:00
2010-05-22 21:06:32 +02: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
2003-05-16 00:52:41 +02:00
* leak in the test code , we ' ll use a different pipe name for each server .
*/
/* Try server #1 */
2010-05-22 21:06:32 +02:00
SetLastError ( 0xdeadbeef ) ;
2004-05-04 02:43:46 +02:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain1 , ( void * ) 8 , 0 , & serverThreadId ) ;
2010-05-22 21:06:32 +02:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2003-05-16 00:52:41 +02:00
exercizeServer ( PIPENAME " serverThreadMain1 " , serverThread ) ;
/* Try server #2 */
2010-05-22 21:06:32 +02:00
SetLastError ( 0xdeadbeef ) ;
2003-05-16 00:52:41 +02:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain2 , 0 , 0 , & serverThreadId ) ;
2010-05-22 21:06:32 +02:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2003-05-16 00:52:41 +02:00
exercizeServer ( PIPENAME " serverThreadMain2 " , serverThread ) ;
/* Try server #3 */
2010-05-22 21:06:32 +02:00
SetLastError ( 0xdeadbeef ) ;
2003-05-16 00:52:41 +02:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain3 , 0 , 0 , & serverThreadId ) ;
2010-05-22 21:06:32 +02:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2003-05-16 00:52:41 +02:00
exercizeServer ( PIPENAME " serverThreadMain3 " , serverThread ) ;
2009-02-20 20:39:44 +01:00
/* Try server #4 */
2010-05-22 21:06:32 +02:00
SetLastError ( 0xdeadbeef ) ;
2009-02-20 20:39:44 +01:00
serverThread = CreateThread ( NULL , 0 , serverThreadMain4 , 0 , 0 , & serverThreadId ) ;
2010-05-22 21:06:32 +02:00
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
2009-02-20 20:39:44 +01:00
exercizeServer ( PIPENAME " serverThreadMain4 " , serverThread ) ;
2012-06-14 20:38:19 +02:00
/* Try server #5 */
SetLastError ( 0xdeadbeef ) ;
serverThread = CreateThread ( NULL , 0 , serverThreadMain5 , 0 , 0 , & serverThreadId ) ;
ok ( serverThread ! = NULL , " CreateThread failed: %d \n " , GetLastError ( ) ) ;
exercizeServer ( PIPENAME " serverThreadMain5 " , 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 ;
2009-06-08 23:23:36 +02:00
DWORD ret ;
2003-05-16 00:52:41 +02:00
2008-09-13 14:05:12 +02:00
SetLastError ( 0xdeadbeef ) ;
2013-10-21 10:02:23 +02:00
hnp = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_WAIT ,
2003-05-16 00:52:41 +02:00
/* 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 " ) ;
2009-06-08 23:23:36 +02:00
ret = WaitForSingleObject ( hFile , 0 ) ;
ok ( ret = = WAIT_TIMEOUT , " WaitForSingleObject returned %X \n " , ret ) ;
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 ] ;
2011-08-22 11:02:51 +02:00
user_apc_ran = FALSE ;
if ( pQueueUserAPC )
ok ( pQueueUserAPC ( user_apc , GetCurrentThread ( ) , 0 ) , " couldn't create user apc \n " ) ;
2005-06-05 19:57:10 +02:00
pipe_attr . nLength = sizeof ( SECURITY_ATTRIBUTES ) ;
pipe_attr . bInheritHandle = TRUE ;
2011-08-22 11:02:51 +02:00
pipe_attr . lpSecurityDescriptor = NULL ;
2005-06-05 19:57:10 +02: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 " ) ;
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 ) ;
2011-08-22 11:02:51 +02:00
ok ( user_apc_ran = = FALSE , " user apc ran, pipe using alertable io mode \n " ) ;
SleepEx ( 0 , TRUE ) ; /* get rid of apc */
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 )
{
2009-03-11 09:39:16 +01:00
struct named_pipe_client_params * params = p ;
2007-03-06 19:00:15 +01: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 ( ) ) ;
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 ) ;
}
2013-10-21 10:02:23 +02:00
pipe = CreateFileA ( PIPE_NAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL , OPEN_EXISTING , params - > security_flags , NULL ) ;
2007-03-06 19:00:15 +01:00
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 ;
2013-10-21 10:02:23 +02:00
hPipeServer = CreateNamedPipeA ( PIPE_NAME , PIPE_ACCESS_DUPLEX , PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT , 1 , 100 , 100 , NMPWAIT_USE_DEFAULT_WAIT , NULL ) ;
2007-03-06 19:00:15 +01:00
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 ;
2009-03-11 09:39:16 +01:00
struct overlapped_server_args * a = arg ;
2007-07-16 13:12:18 +02: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 ) ;
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 ;
2011-01-12 20:54:24 +01:00
BOOL ret ;
2007-07-16 13:12:18 +02: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-01-12 20:54:24 +01:00
ok ( ret , " WriteFile failed with error %d \n " , GetLastError ( ) ) ;
2007-07-16 13:12:18 +02:00
WaitForSingleObject ( thread , INFINITE ) ;
CloseHandle ( pipe ) ;
CloseHandle ( args . pipe_created ) ;
CloseHandle ( thread ) ;
}
2009-02-11 19:12:31 +01:00
static void test_NamedPipeHandleState ( void )
{
HANDLE server , client ;
BOOL ret ;
DWORD state , instances , maxCollectionCount , collectDataTimeout ;
char userName [ MAX_PATH ] ;
2013-10-21 10:02:23 +02:00
server = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX ,
2009-02-11 19:12:31 +01:00
/* 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 " ) ;
2013-10-21 10:02:23 +02:00
ret = GetNamedPipeHandleStateA ( server , NULL , NULL , NULL , NULL , NULL , 0 ) ;
2009-02-11 19:12:31 +01:00
ok ( ret , " GetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
2013-10-21 10:02:23 +02:00
ret = GetNamedPipeHandleStateA ( server , & state , & instances , NULL , NULL , NULL ,
2009-02-11 19:12:31 +01:00
0 ) ;
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 ) ;
2013-10-21 10:02:23 +02:00
ret = GetNamedPipeHandleStateA ( server , & state , & instances ,
2009-02-11 19:12:31 +01:00
& 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 ) ;
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 ) ;
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 ) ;
ok ( ! ret & & GetLastError ( ) = = ERROR_INVALID_PARAMETER ,
" expected ERROR_INVALID_PARAMETER, got %d \n " , GetLastError ( ) ) ;
CloseHandle ( client ) ;
CloseHandle ( server ) ;
2013-10-21 10:02:23 +02:00
server = CreateNamedPipeA ( PIPENAME , PIPE_ACCESS_DUPLEX ,
2009-02-11 19:12:31 +01:00
/* 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 " ) ;
2013-10-21 10:02:23 +02:00
ret = GetNamedPipeHandleStateA ( server , NULL , NULL , NULL , NULL , NULL , 0 ) ;
2009-02-11 19:12:31 +01:00
ok ( ret , " GetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
2013-10-21 10:02:23 +02:00
ret = GetNamedPipeHandleStateA ( server , & state , & instances , NULL , NULL , NULL ,
2009-02-11 19:12:31 +01:00
0 ) ;
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 ) ;
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 ) ;
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 ) ;
ok ( ret , " SetNamedPipeHandleState failed: %d \n " , GetLastError ( ) ) ;
CloseHandle ( client ) ;
CloseHandle ( server ) ;
}
2012-06-14 21:35:27 +02:00
static void test_readfileex_pending ( void )
{
HANDLE server , client , event ;
BOOL ret ;
DWORD err , wait , num_bytes ;
OVERLAPPED overlapped ;
char read_buf [ 1024 ] ;
char write_buf [ 1024 ] ;
2012-06-20 20:10:12 +02:00
const char test_string [ ] = " test " ;
2012-06-14 21:35:27 +02:00
int i ;
2013-10-21 10:02:23 +02:00
server = CreateNamedPipeA ( PIPENAME , FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX ,
2012-06-14 21:35:27 +02:00
/* 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 " ) ;
event = CreateEventA ( NULL , TRUE , FALSE , NULL ) ;
ok ( event ! = NULL , " CreateEventA failed \n " ) ;
memset ( & overlapped , 0 , sizeof ( overlapped ) ) ;
overlapped . hEvent = event ;
ret = ConnectNamedPipe ( server , & overlapped ) ;
err = GetLastError ( ) ;
ok ( ret = = FALSE , " ConnectNamedPipe succeeded \n " ) ;
ok ( err = = ERROR_IO_PENDING , " ConnectNamedPipe set error %i \n " , err ) ;
wait = WaitForSingleObject ( event , 0 ) ;
ok ( wait = = WAIT_TIMEOUT , " WaitForSingleObject returned %x \n " , wait ) ;
client = CreateFileA ( PIPENAME , GENERIC_READ | GENERIC_WRITE , 0 , NULL ,
OPEN_EXISTING , 0 , NULL ) ;
ok ( client ! = INVALID_HANDLE_VALUE , " cf failed \n " ) ;
wait = WaitForSingleObject ( event , 0 ) ;
ok ( wait = = WAIT_OBJECT_0 , " WaitForSingleObject returned %x \n " , wait ) ;
/* Start a read that can't complete immediately. */
completion_called = 0 ;
ResetEvent ( event ) ;
ret = ReadFileEx ( server , read_buf , sizeof ( read_buf ) , & overlapped , completion_routine ) ;
2012-06-14 21:42:47 +02:00
ok ( ret = = TRUE , " ReadFileEx failed, err=%i \n " , GetLastError ( ) ) ;
2012-06-14 21:35:27 +02:00
ok ( completion_called = = 0 , " completion routine called before ReadFileEx returned \n " ) ;
2012-06-20 20:10:12 +02:00
ret = WriteFile ( client , test_string , strlen ( test_string ) , & num_bytes , NULL ) ;
2012-06-14 21:35:27 +02:00
ok ( ret = = TRUE , " WriteFile failed \n " ) ;
2012-06-20 20:10:12 +02:00
ok ( num_bytes = = strlen ( test_string ) , " only %i bytes written \n " , num_bytes ) ;
2012-06-14 21:35:27 +02:00
ok ( completion_called = = 0 , " completion routine called during WriteFile \n " ) ;
wait = WaitForSingleObjectEx ( event , 0 , TRUE ) ;
ok ( wait = = WAIT_IO_COMPLETION | | wait = = WAIT_OBJECT_0 , " WaitForSingleObjectEx returned %x \n " , wait ) ;
ok ( completion_called = = 1 , " completion not called after writing pipe \n " ) ;
ok ( completion_errorcode = = 0 , " completion called with error %x \n " , completion_errorcode ) ;
2012-06-20 20:10:12 +02:00
ok ( completion_num_bytes = = strlen ( test_string ) , " ReadFileEx returned only %d bytes \n " , completion_num_bytes ) ;
2012-06-14 21:35:27 +02:00
ok ( completion_lpoverlapped = = & overlapped , " completion called with wrong overlapped pointer \n " ) ;
2012-06-20 20:10:12 +02:00
ok ( ! memcmp ( test_string , read_buf , strlen ( test_string ) ) , " ReadFileEx read wrong bytes \n " ) ;
2012-06-14 21:35:27 +02:00
/* Make writes until the pipe is full and the write fails */
memset ( write_buf , 0xaa , sizeof ( write_buf ) ) ;
for ( i = 0 ; i < 256 ; i + + )
{
completion_called = 0 ;
ResetEvent ( event ) ;
ret = WriteFileEx ( server , write_buf , sizeof ( write_buf ) , & overlapped , completion_routine ) ;
err = GetLastError ( ) ;
ok ( completion_called = = 0 , " completion routine called during WriteFileEx \n " ) ;
wait = WaitForSingleObjectEx ( event , 0 , TRUE ) ;
if ( wait = = WAIT_TIMEOUT )
/* write couldn't complete immediately, presumably the pipe is full */
break ;
ok ( wait = = WAIT_IO_COMPLETION | | wait = = WAIT_OBJECT_0 , " WaitForSingleObject returned %x \n " , wait ) ;
ok ( ret = = TRUE , " WriteFileEx failed, err=%i \n " , err ) ;
ok ( completion_errorcode = = 0 , " completion called with error %x \n " , completion_errorcode ) ;
ok ( completion_lpoverlapped = = & overlapped , " completion called with wrong overlapped pointer \n " ) ;
}
2012-06-14 21:42:47 +02:00
ok ( ret = = TRUE , " WriteFileEx failed, err=%i \n " , err ) ;
2012-06-14 21:35:27 +02:00
ok ( completion_called = = 0 , " completion routine called but wait timed out \n " ) ;
ok ( completion_errorcode = = 0 , " completion called with error %x \n " , completion_errorcode ) ;
ok ( completion_lpoverlapped = = & overlapped , " completion called with wrong overlapped pointer \n " ) ;
/* free up some space in the pipe */
2015-02-24 13:55:09 +01:00
for ( i = 0 ; i < 256 ; i + + )
2014-07-30 18:00:19 +02:00
{
ret = ReadFile ( client , read_buf , sizeof ( read_buf ) , & num_bytes , NULL ) ;
ok ( ret = = TRUE , " ReadFile failed \n " ) ;
2015-02-24 13:55:09 +01:00
2014-07-30 18:00:19 +02:00
ok ( completion_called = = 0 , " completion routine called during ReadFile \n " ) ;
2015-02-24 13:55:09 +01:00
2014-07-30 18:00:19 +02:00
wait = WaitForSingleObjectEx ( event , 0 , TRUE ) ;
2015-02-24 13:55:09 +01:00
ok ( wait = = WAIT_IO_COMPLETION | | wait = = WAIT_OBJECT_0 | | wait = = WAIT_TIMEOUT ,
" WaitForSingleObject returned %x \n " , wait ) ;
if ( wait ! = WAIT_TIMEOUT ) break ;
2014-07-30 18:00:19 +02:00
}
2012-06-14 21:35:27 +02:00
ok ( completion_called = = 1 , " completion routine not called \n " ) ;
ok ( completion_errorcode = = 0 , " completion called with error %x \n " , completion_errorcode ) ;
ok ( completion_lpoverlapped = = & overlapped , " completion called with wrong overlapped pointer \n " ) ;
2013-09-18 08:54:32 +02:00
num_bytes = 0xdeadbeef ;
SetLastError ( 0xdeadbeef ) ;
ret = ReadFile ( INVALID_HANDLE_VALUE , read_buf , 0 , & num_bytes , NULL ) ;
ok ( ! ret , " ReadFile should fail \n " ) ;
ok ( GetLastError ( ) = = ERROR_INVALID_HANDLE , " wrong error %u \n " , GetLastError ( ) ) ;
ok ( num_bytes = = 0 , " expected 0, got %u \n " , num_bytes ) ;
S ( U ( overlapped ) ) . Offset = 0 ;
S ( U ( overlapped ) ) . OffsetHigh = 0 ;
overlapped . Internal = - 1 ;
overlapped . InternalHigh = - 1 ;
overlapped . hEvent = event ;
num_bytes = 0xdeadbeef ;
SetLastError ( 0xdeadbeef ) ;
ret = ReadFile ( server , read_buf , 0 , & num_bytes , & overlapped ) ;
2015-03-04 09:39:10 +01:00
ok ( ! ret , " ReadFile should fail \n " ) ;
2013-09-18 08:54:32 +02:00
todo_wine
ok ( GetLastError ( ) = = ERROR_IO_PENDING , " expected ERROR_IO_PENDING, got %d \n " , GetLastError ( ) ) ;
ok ( num_bytes = = 0 , " bytes %u \n " , num_bytes ) ;
ok ( ( NTSTATUS ) overlapped . Internal = = STATUS_PENDING , " expected STATUS_PENDING, got %#lx \n " , overlapped . Internal ) ;
2013-09-18 08:55:20 +02:00
todo_wine
2013-09-18 08:54:32 +02:00
ok ( overlapped . InternalHigh = = - 1 , " expected -1, got %lu \n " , overlapped . InternalHigh ) ;
wait = WaitForSingleObject ( event , 100 ) ;
ok ( wait = = WAIT_TIMEOUT , " WaitForSingleObject returned %x \n " , wait ) ;
num_bytes = 0xdeadbeef ;
ret = WriteFile ( client , test_string , 1 , & num_bytes , NULL ) ;
ok ( ret , " WriteFile failed \n " ) ;
ok ( num_bytes = = 1 , " bytes %u \n " , num_bytes ) ;
2013-09-18 08:55:20 +02:00
wait = WaitForSingleObject ( event , 100 ) ;
todo_wine
2013-09-18 08:54:32 +02:00
ok ( wait = = WAIT_OBJECT_0 , " WaitForSingleObject returned %x \n " , wait ) ;
ok ( num_bytes = = 1 , " bytes %u \n " , num_bytes ) ;
todo_wine
ok ( ( NTSTATUS ) overlapped . Internal = = STATUS_SUCCESS , " expected STATUS_SUCCESS, got %#lx \n " , overlapped . Internal ) ;
ok ( overlapped . InternalHigh = = 0 , " expected 0, got %lu \n " , overlapped . InternalHigh ) ;
/* read the pending byte and clear the pipe */
num_bytes = 0xdeadbeef ;
ret = ReadFile ( server , read_buf , 1 , & num_bytes , & overlapped ) ;
ok ( ret , " ReadFile failed \n " ) ;
ok ( num_bytes = = 1 , " bytes %u \n " , num_bytes ) ;
2012-06-14 21:35:27 +02:00
CloseHandle ( client ) ;
CloseHandle ( server ) ;
CloseHandle ( event ) ;
}
2003-02-19 23:06:36 +01:00
START_TEST ( pipe )
{
2007-03-16 22:37:46 +01:00
HMODULE hmod ;
2013-10-21 10:02:23 +02:00
hmod = GetModuleHandleA ( " advapi32.dll " ) ;
2007-03-16 22:37:46 +01:00
pDuplicateTokenEx = ( void * ) GetProcAddress ( hmod , " DuplicateTokenEx " ) ;
2013-10-21 10:02:23 +02:00
hmod = GetModuleHandleA ( " kernel32.dll " ) ;
2011-08-22 11:02:51 +02:00
pQueueUserAPC = ( void * ) GetProcAddress ( hmod , " QueueUserAPC " ) ;
2007-03-16 22:37:46 +01:00
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 ( ) ;
2009-02-11 19:12:31 +01:00
test_NamedPipeHandleState ( ) ;
2012-06-14 21:35:27 +02:00
test_readfileex_pending ( ) ;
2003-02-19 23:06:36 +01:00
}