Switch WaitNamedPipe and CreateNamedPipeClient invocation ordering. (dotnet/corefx...
authorJiri Appl <jiria@microsoft.com>
Fri, 13 Oct 2017 20:42:43 +0000 (13:42 -0700)
committerPaulo Janotti <pauloja@microsoft.com>
Fri, 13 Oct 2017 20:42:43 +0000 (13:42 -0700)
* Switch WaitNamedPipe and CreateNamedPipeClient invocation ordering.

We need to do this as WaitNamedPipe is not supported in Windows Containers.
By default using CreateNamedPipeClient first with call to WaitNamedPipe as
a fallback only will allow us to use NamedPipeClientStream inside Windows
Containers.

* Integrate feedback from PR.

Commit migrated from https://github.com/dotnet/corefx/commit/e003701727df908d6eb7ba7b814c74924c498377

src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Windows.cs

index 861ac5e..a48e566 100644 (file)
@@ -33,31 +33,6 @@ namespace System.IO.Pipes
                 _pipeFlags |= (((int)_impersonationLevel - 1) << 16);
             }
 
-            if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout))
-            {
-                int errorCode = Marshal.GetLastWin32Error();
-
-                // Server is not yet created
-                if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
-                {
-                    return false;
-                }
-
-                // The timeout has expired.
-                if (errorCode == Interop.Errors.ERROR_SUCCESS)
-                {
-                    if (cancellationToken.CanBeCanceled)
-                    {
-                        // It may not be real timeout.
-                        return false;
-                    }
-                    throw new TimeoutException();
-                }
-
-                throw Win32Marshal.GetExceptionForWin32Error(errorCode);
-            }
-
-            // Pipe server should be free.  Let's try to connect to it.
             int access = 0;
             if ((PipeDirection.In & _direction) != 0)
             {
@@ -67,6 +42,8 @@ namespace System.IO.Pipes
             {
                 access |= Interop.Kernel32.GenericOperations.GENERIC_WRITE;
             }
+
+            // Let's try to connect first
             SafePipeHandle handle = Interop.Kernel32.CreateNamedPipeClient(_normalizedPipePath,
                                         access,           // read and write access
                                         0,                  // sharing: none
@@ -79,14 +56,58 @@ namespace System.IO.Pipes
             {
                 int errorCode = Marshal.GetLastWin32Error();
 
-                // Handle the possible race condition of someone else connecting to the server 
-                // between our calls to WaitNamedPipe & CreateFile.
-                if (errorCode == Interop.Errors.ERROR_PIPE_BUSY)
+                if (errorCode != Interop.Errors.ERROR_PIPE_BUSY &&
+                    errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
+                {
+                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+                }
+
+                if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout))
                 {
-                    return false;
+                    errorCode = Marshal.GetLastWin32Error();
+
+                    // Server is not yet created
+                    if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
+                    {
+                        return false;
+                    }
+
+                    // The timeout has expired.
+                    if (errorCode == Interop.Errors.ERROR_SUCCESS)
+                    {
+                        if (cancellationToken.CanBeCanceled)
+                        {
+                            // It may not be real timeout.
+                            return false;
+                        }
+                        throw new TimeoutException();
+                    }
+
+                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                 }
 
-                throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+                // Pipe server should be free.  Let's try to connect to it.
+                handle = Interop.Kernel32.CreateNamedPipeClient(_normalizedPipePath,
+                                            access,           // read and write access
+                                            0,                  // sharing: none
+                                            ref secAttrs,           // security attributes
+                                            FileMode.Open,      // open existing 
+                                            _pipeFlags,         // impersonation flags
+                                            IntPtr.Zero);  // template file: null
+
+                if (handle.IsInvalid)
+                {
+                    errorCode = Marshal.GetLastWin32Error();
+
+                    // Handle the possible race condition of someone else connecting to the server 
+                    // between our calls to WaitNamedPipe & CreateFile.
+                    if (errorCode == Interop.Errors.ERROR_PIPE_BUSY)
+                    {
+                        return false;
+                    }
+
+                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+                }
             }
 
             // Success!