Today, I ran into an interesting issue.  One of our customers was using the .Net Remoting IPC client in the asp.net application communicating with a local service.  The asp.net application was configured with impersonation.  The IPC client was simply making multiple calls to the remoting service.  Every now and then, the call failed RemotingException with “All pipe instances are busy.” (error=231) and “The system cannot find the file specified.” (error=2).  Upon investigation, the issue seemed to be a race condition issue with creating and closing the Win32 namepiped handle.  Typically, IPC .Net Remoting client will cache and reuse the namedpipe handles.  Since the namedpipe creation is security context sensitive, if the calling thread is impersonated, the namedpipe will not be shared.   Calling remoting service in a tight loop will cause new namedpipe handle to be created and closed.  The issue is repro-able by just a native Win32 namedpipe sample posted on msdn (http://msdn.microsoft.com/en-us/library/aa365588(VS.85).aspx and http://msdn.microsoft.com/en-us/library/aa365592(VS.85).aspx).  I simply put the client into a while loop.  After just a few seconds on my Vista and Windows 2008 machine, the error will occur.

Good news is the workaround is simple.  One should call WaitNamedPipe and retry creating the namedpipe.  One catch is that WaitNamedPipe is also subject to this issue and, sometimes, return immediately with and “The system cannot find the file specified.” (error=2).  You may want to retry the WaitNamedPipe a couple of time before calling recreate the namedpipe handle.  I have a code snippet below that I modified from the sample mentioned above.  With this, the client will run without any issue.  You could adapt this in the Remoting IPC client scenario by Pinvoke WaitNamedPipe in the same manner before retrying invoking the remoting service.

 

//

// PipeClient.cpp : Defines the entry point for the console application.

//

 

#include <windows.h>

#include <stdio.h>

#include <conio.h>

#include <tchar.h>

#include "stdafx.h"

 

#define BUFSIZE 512

 

int _tmain(int argc, TCHAR *argv[])

{

   HANDLE hPipe;

   LPTSTR lpvMessage=TEXT("Default message from client");

   TCHAR chBuf[BUFSIZE];

   BOOL fSuccess;

   DWORD cbRead, cbWritten, dwMode;

   LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");

 

   if( argc > 1 )

      lpvMessage = argv[1];

 

 

   while (1)

   {

// Try to open a named pipe; wait for it, if necessary.

         BOOL bRetried = FALSE;

         while (1)

         {

              hPipe = CreateFile(

                   lpszPipename,   // pipe name

                   GENERIC_READ |  // read and write access

                   GENERIC_WRITE,

                   0,              // no sharing

                   NULL,           // default security attributes

                   OPEN_EXISTING,  // opens existing pipe

                   0,              // default attributes

                   NULL);          // no template file

       

         // Break if the pipe handle is valid.

       

              if (hPipe != INVALID_HANDLE_VALUE)

                   break;

       

              // Exit if an error other than ERROR_PIPE_BUSY occurs.

       

              if (GetLastError() != ERROR_PIPE_BUSY)

              {

                   printf("Could not open pipe");

                   return 0;

              }

 

              if (bRetried)

              {

                   printf("Could not open pipe");

                   return 0;

              }

 

              // Retry for 1000ms

              bRetried = TRUE;

              BOOL bSuccess = FALSE;

              for (INT i = 0 ; i < 10 ; ++i)

              {

                   _tprintf( TEXT("W") );

                   bSuccess = WaitNamedPipe(lpszPipename, 0);

                   if (!bSuccess)

                   {

                         Sleep(100);

                   }

                   else

                         break;

              }

 

              if (!bSuccess)

              {

                   printf("Fail WaitNamedPipe");

                   return 0;

              }

              else

                  _tprintf( TEXT("R") );

         }

       

      // The pipe connected; change to message-read mode.

       

         dwMode = PIPE_READMODE_MESSAGE;

         fSuccess = SetNamedPipeHandleState(

              hPipe,    // pipe handle

              &dwMode,  // new pipe mode

              NULL,     // don't set maximum bytes

              NULL);    // don't set maximum time

         if (!fSuccess)

         {

              printf("SetNamedPipeHandleState failed");

              return 0;

         }

       

      // Send a message to the pipe server.

       

         fSuccess = WriteFile(

              hPipe,                  // pipe handle

              lpvMessage,             // message

              (lstrlen(lpvMessage)+1)*sizeof(TCHAR), // message length

              &cbWritten,             // bytes written

              NULL);                  // not overlapped

         if (!fSuccess)

         {

              printf("WriteFile failed");

              return 0;

         }

       

         do

         {

         // Read from the pipe.

       

              fSuccess = ReadFile(

                   hPipe,    // pipe handle

                   chBuf,    // buffer to receive reply

                   BUFSIZE*sizeof(TCHAR),  // size of buffer

                   &cbRead,  // number of bytes read

                   NULL);    // not overlapped

       

              if (! fSuccess && GetLastError() != ERROR_MORE_DATA)

                   break;

       

              //_tprintf( TEXT("%s\n"), chBuf );

              _tprintf( TEXT(".") );

         } while (!fSuccess);  // repeat loop if ERROR_MORE_DATA

 

         //getch();

       

         CloseHandle(hPipe);

   }

 

   return 0;

}