C++ – GetLastError() returns ERROR_BROKEN_PIPE after call to PeekNamedPipe only when using message mode

cnamed-pipeswinapi

I can't figure out why this is happening… I have a Named Pipe server and client application. Both are in read/write mode and transfer data between each other. The server has two threads, one that reads from the pipe and one that writes to it. While the client is writing a bunch of messages, the server's read thread will exit because it's call to PeekNamedPipe is returning false. The return value of GetLastError() is ERROR_BROKEN_PIPE. Neither thread in the server is closing the pipe, and the client is still writing to the pipe, so I don't understand why the pipe is "broken."

If I change the server to BYTE mode, then everything works flawlessly. I am really wanting to use Message mode though so my "messages" do not get grouped together.

If I change the client to BYTE mode and the server to Message mode, it works.

Call to CreateNamedPipe

hPipe = CreateNamedPipe(
    pszPipeName,
    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
    PIPE_WAIT | PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE,
    PIPE_UNLIMITED_INSTANCES,
    dwOutBufferSize,
    dwInBufferSize,
    0,
    NULL);

Call to PeekNamedPipe

while( RunningState == DDCMP_STATE_RUNNING )
{
    if( !PeekNamedPipe(hPipe,NULL,NULL,NULL,&dwBytesAvailable,NULL) || !dwBytesAvailable )
        if( GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_PIPE_NOT_CONNECTED || GetLastError() == ERROR_INVALID_HANDLE )
            break;
        else
        {
            Sleep( 100 );
            continue;
        }

    //call to ReadFile(hPipe,...) with dwBytesAvailable as size, and then processing of data
}

Best Answer

You are calling GetLastError() not only when PeekNamedPipe() fails, but also when it succeeds and returns 0 bytes. You should not be calling GetLastError() in that latter case, as the value will not be meaningful. Use it more like this instead:

while( RunningState == DDCMP_STATE_RUNNING ) 
{ 
    if( !PeekNamedPipe(hPipe, NULL, NULL, NULL, &dwBytesAvailable, NULL) )
    {
        DWORD dwError = GetLastError();

        if( (dwError == ERROR_BROKEN_PIPE) ||
            (dwError == ERROR_PIPE_NOT_CONNECTED) ||
            (dwError == ERROR_INVALID_HANDLE) )
        { 
            break;
        }

        dwBytesAvailable = 0;
    }

    if( !dwBytesAvailable )
    {
        Sleep(100);
        continue;
    }

    //call to ReadFile(hPipe,...) with dwBytesAvailable as size, and then processing of data 
} 
Related Topic