none
will I receive iocp notification from ConnectNamedPipe when it returns 0 and GetLastError() returns ERROR_PIPE_CONNECTED RRS feed

  • Question

  • I know if ConnectNamedPipe returned TRUE then the operation completed immediately and I'll receive a completion notification

    and if the return value is FALSE and GetLastError() returned ERROR_IO_PENDING then Ithe operation is in progress and I'll receive a notification indicating success or failure

    and if GetLastError() returned errors other than ERROR_IO_PENDING and ERROR_PIPE_CONNECTED then the function failed and I have to post a notification manually as the function won't post a one for me

    but if GetLastError() returned ERROR_PIPE_CONNECTED  will the function schedule a completion notification indicating success ? or I have to notify the user manually ?

    Saturday, November 30, 2019 9:56 AM

All replies

  • If you read the return value description of the ConnectNamedPipe documentation then it should be obvious.

    "If a client connects before the function is called, the function returns zero and GetLastError returns ERROR_PIPE_CONNECTED. This can happen if a client connects in the interval between the call to CreateNamedPipe and the call to ConnectNamedPipe. In this situation, there is a good connection between client and server, even though the function returns zero."

    In other words, this error comes because ConnectNamedPipe was called MORE THAN ONCE for a named pipe. The first one would have returned a TRUE and this is telling you that the named pipe is already connected.

    So yes, you will get a a completion port notification from the call to ConnectNamedPipe that actually succeeds.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Sunday, December 1, 2019 3:23 AM
  • but from this example : Named Pipe Server Using Overlapped I/O

    BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo) 
    { 
       BOOL fConnected, fPendingIO = FALSE; 
     
    // Start an overlapped connection for this pipe instance. 
       fConnected = ConnectNamedPipe(hPipe, lpo); 
     
    // Overlapped ConnectNamedPipe should return zero. 
       if (fConnected) 
       {
          printf("ConnectNamedPipe failed with %d.\n", GetLastError()); 
          return 0;
       }
     
       switch (GetLastError()) 
       { 
       // The overlapped connection in progress. 
          case ERROR_IO_PENDING: 
             fPendingIO = TRUE; 
             break; 
     
       // --> Client is already connected, so signal an event. <--
     
          case ERROR_PIPE_CONNECTED: 
             if (SetEvent(lpo->hEvent)) 
                break; 
     
       // If an error occurs during the connect operation... 
          default: 
          {
             printf("ConnectNamedPipe failed with %d.\n", GetLastError());
             return 0;
          }
       } 
     
       return fPendingIO; 
    }

    so why setting the event manually in case of ERROR_PIPE_CONNECTED ?

    • Edited by cpp-dev Sunday, December 1, 2019 8:41 AM
    Sunday, December 1, 2019 8:38 AM
  • If you look at the IO Completion Port version of that sample, you should notice that it does the same thing.

    If you look at the main function, after it creates the event it will create the named pipe and then call WaitForSingleObjectEx. The event it is waiting on is the event that it just created, but it also put this inside the OVERLAPPED structure that it passed to CreateAndConnectInstance and thus ConnectToNewClient.

    If ConnectToNewClient didn't set the event when it got ERROR_PIPE_CONNECTED then it would block on the WaitForSingleObjectEx call. In truth any method for detecting this situation would work. For example having the ConnectToNewClient and CreateAndConnectInstance returning another value to indicate that the pipe was already connected would also work in this situation if it is checked before the WaitForSingleObjectEx call. However this would result in extra code so using the event itself is simpler.

    So why set the event manually? Developer choice.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Sunday, December 1, 2019 3:19 PM
    Sunday, December 1, 2019 3:19 PM
  • I made an experiment and found that when GetLastError() returns ERROR_PIPE_CONNECTED there will be no notification via io completion ports and I have to notify myself

    how was the experiment :

    I launch the client which tries to connect to the server in a while loop until it succeeds

    I launch the server which creates the named pipe then sleep for a short period before calling ConnectNamedPipe

    as the client connects in the interval between CreateNamedPipe and ConnectNamedPipe the latter returns zero and the error is set to ERROR_PIPE_CONNECTED

    I make sure that that I got the desired error code from GetLastError

    I wait for a completion notification but nothing is being posted

    if I repeat the steps but I start the server firstly and launch the client after the server called ConnectNamedPipe I get the notification

    thus ConnectNamedPipe will schedule a notification if only it returns zero and GetLastError() returns ERROR_IO_PENDING

    even non zero return with overlapped is a failure of the function as per the example and the documentation

    Monday, December 2, 2019 6:09 PM
  • Okay, I think we are not thinking about the same thing here which is why nothing makes sense.

    So let's go back to the IO completion port named pipe sample. This is to see what it actually does when it gets an ERROR_PIPE_CONNECTED error. All I did was to add two printf statements to the case statements in the server's ConnectToNewClient. The modified version of the function looks like:

    BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
    {
        BOOL fConnected, fPendingIO = FALSE;
        Sleep(2000); //make sure the ERROR_PIPE_CONNECTED is triggered
        // Start an overlapped connection for this pipe instance. 
        fConnected = ConnectNamedPipe(hPipe, lpo);
    
        // Overlapped ConnectNamedPipe should return zero. 
        if (fConnected)
        {
            printf("ConnectNamedPipe failed with %d.\n", GetLastError());
            return 0;
        }
    
        switch (GetLastError())
        {
            // The overlapped connection in progress. 
        case ERROR_IO_PENDING:
            _tprintf(TEXT("IO pending\n")); //Added to log this case
            fPendingIO = TRUE;
            break;
    
            // Client is already connected, so signal an event. 
    
        case ERROR_PIPE_CONNECTED:
            _tprintf(TEXT("Pipe already connected\n")); //Added to log this case
            if (SetEvent(lpo->hEvent))
                break;
    
            // If an error occurs during the connect operation... 
        default:
        {
            printf("ConnectNamedPipe failed with %d.\n", GetLastError());
            return 0;
        }
        }
        return fPendingIO;
    }

    If we don't try to get ERROR_PIPE_CONNECTED, the output for this is:

    IO pending
    IO pending
    [000000D0] Default message from client.

    However, if we get the ERROR_PIPE_CONNECTED, the output for this sample is:

    Pipe already connected
    IO pending
    [000000CC] Default message from client.

    So you should see something interesting there. What the sample does is to treat it as a success except that it doesn't complete IO.

    Remember that asynchronous IO can complete synchronously. In this case the client actually connects to the named pipe using CreateFile and this starts off the whole connection process. If enough time passes between when the client connects using CreateFile and when the server finally calls ConnectNamedPipe then the Windows IO subsystem would be able to complete this connection which the client initiated. In this case the server only needs to be told that everything has been connected and it can carry on.

    So you can think of the difference here is ERROR_IO_PENDING is stating that the connection is underway so ask at a later point in time about it and ERROR_PIPE_CONNECTED is saying that the client initiated the connection and so everything has already been connected.

    In other words the server doesn't need the IO completion because there is nothing to do. In the case of ERROR_IO_PENDING it does need the IO completion because it needs to complete the connection operation.

    You can think of this as a similar situation to ReadFile or WriteFile returning TRUE to an asynchronous operation to indicate that it was able to complete the operation and the code doesn't have to wait for results.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Tuesday, December 3, 2019 7:14 PM
    Tuesday, December 3, 2019 7:11 PM