The following code results in the "client" call to TransactNamedPipe() returning immediately with GetLastError() returning ERROR_IO_PENDING; all of which, I believe, is correct from the client's point of view. The client then proceeds to wait on the overlapped event.
However, the "server" listener thread never returns from its call to GetQueuedCompletionStatus(), and hence, never processes the client request.
Why isn't my client request making it thru to the listener?
Thanks in advance.
#include "stdafx.h"
#include <windows.h>
#define PIPE_NAME _T( "\\\\.\\pipe\\pipe1" )
#define PIPE_TIMEOUT 5000
#define BUF_SIZE 4096
static DWORD listenerThreadProc( void *pData );
static void closeHandle( HANDLE &hObj );
HANDLE g_hPipe = NULL;
HANDLE g_hIoCompletionPort = NULL;
HANDLE g_hListenerThread = NULL;
enum TIoState { iosRead = 0, iosWrite };
int _tmain( int argc, _TCHAR* argv[] )
{
UNREFERENCED_PARAMETER( argc );
UNREFERENCED_PARAMETER( argv );
int result = 1;
DWORD lastError = 0;
OVERLAPPED overlapped = {0};
HANDLE hPipe = NULL;
HANDLE hClientRequestEvent = NULL;
g_hPipe = CreateNamedPipe(
PIPE_NAME,
PIPE_ACCESS_DUPLEX |
FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUF_SIZE,
BUF_SIZE,
PIPE_TIMEOUT,
NULL );
if ( INVALID_HANDLE_VALUE == g_hPipe )
{
_tprintf(_T( "Failed to create \"%s\" pipe. Error = %d." ),
PIPE_NAME,
GetLastError() );
goto DONE;
}
g_hIoCompletionPort = CreateIoCompletionPort(
g_hPipe,
NULL,
iosRead,
0 );
if ( NULL == g_hIoCompletionPort )
{
_tprintf(_T( "Failed to create the IO completion port. Error = %d." ),
GetLastError() );
goto DONE;
}
g_hListenerThread =
CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)listenerThreadProc,
(LPVOID)NULL,
0,
NULL
);
if ( NULL == g_hListenerThread )
{
_tprintf( _T( "Failed to create listener thread. Error = %d." ), GetLastError() );
goto DONE;
}
Sleep( 1000 );
hPipe = CreateFile(
PIPE_NAME,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OVERLAPPED,
NULL );
if ( INVALID_HANDLE_VALUE == hPipe )
{
_tprintf(_T( "Failed to open server pipe. Error = %d." ),
GetLastError() );
goto DONE;
}
DWORD dwMode = PIPE_READMODE_MESSAGE;
BOOL retVal = SetNamedPipeHandleState(
hPipe,
&dwMode,
NULL,
NULL );
if ( !retVal )
{
_tprintf(_T( "Failed to set server pipe mode. Error = %d." ),
GetLastError() );
goto DONE;
}
hClientRequestEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if ( NULL == hClientRequestEvent )
{
_tprintf(_T( "Failed to create client event. Error = %d." ),
GetLastError() );
goto DONE;
}
overlapped.hEvent = hClientRequestEvent;
BYTE response[35] = {0};
DWORD cbRead = 0;
retVal = TransactNamedPipe(
hPipe,
(LPVOID) _T( "aaa" ),
4 * sizeof( _TCHAR ),
response,
35,
&cbRead,
&overlapped );
lastError = GetLastError();
if ( !retVal && ERROR_IO_PENDING != lastError )
{
_tprintf(_T( "TransactNamedPipe() failed. Error = %d." ),
lastError );
goto DONE;
}
bool clientSuccess = false;
DWORD dwResult = WaitForSingleObject( hClientRequestEvent, 3000 );
switch ( dwResult )
{
case WAIT_OBJECT_0 : clientSuccess = true; break;
case WAIT_TIMEOUT :
_tprintf( _T( "Client timed out waiting for response.\n" ) );
goto DONE;
case WAIT_ABANDONED :
case WAIT_FAILED :
default :
_tprintf( _T( "Client failed waiting for response.\n" ) );
goto DONE;
}
result = ( clientSuccess ? 0 : 1 );
DONE:
closeHandle( hClientRequestEvent );
closeHandle( hPipe );
closeHandle( g_hListenerThread );
closeHandle( g_hPipe );
closeHandle( g_hIoCompletionPort );
return result;
}
void closeHandle( HANDLE &hObj )
{
if ( !( NULL == hObj || INVALID_HANDLE_VALUE == hObj ) )
{
CloseHandle( hObj );
hObj = NULL;
}
}
DWORD listenerThreadProc( void *pData )
{
HANDLE hListenerThread = GetCurrentThread();
_tprintf( _T( "Listener thread %x started." ), hListenerThread );
DWORD result = 1;
BOOL bSuccess = FALSE;
DWORD bytesCopied = 0;
DWORD completionKey = 0;
DWORD lastError = 0;
OVERLAPPED * pOverlap = NULL;
while ( true )
{
bSuccess = GetQueuedCompletionStatus(
g_hIoCompletionPort,
&bytesCopied,
&completionKey,
(LPOVERLAPPED*)&pOverlap,
INFINITE );
if( !bSuccess )
{
lastError = GetLastError();
_tprintf(_T( "Listener thread %x - GetQueuedCompletionStatus() failed")
_T(". Error = %d." ),
hListenerThread,
lastError );
if ( NULL == pOverlap && ERROR_ABANDONED_WAIT_0 == lastError )
{
_tprintf(_T( "Listener thread %x - The IO completion port was")
_T(" closed prematurely." ),
hListenerThread );
}
break;
}
else
{
_tprintf(_T( "Listener thread %x processing request..." ),
hListenerThread );
if ( NULL != pOverlap )
{
DWORD numBytesWritten = 0;
if ( !WriteFile(g_hPipe,
(LPCVOID)_T( "xxx" ),
4 * sizeof( _TCHAR ),
&numBytesWritten,
(LPOVERLAPPED)pOverlap ) )
{
_tprintf(_T( "Listener thread %x - WriteFile() failed. ")
_T("Error = %d." ),
hListenerThread,
GetLastError() );
}
}
else
_tprintf(_T( "Listener thread %x - GetQueuedCompletionStatus() ")
_T("returned a null LPPIPE_INST instance." ),
hListenerThread );
_tprintf(_T( "Listener thread %x done processing request." ),
hListenerThread );
}
}
result = 0;
_tprintf( _T( "Listener thread %x stopped." ), hListenerThread );
return result;
}