GetSecAttrs() private method

private GetSecAttrs ( HandleInheritability inheritability ) : Interop.Kernel32.SECURITY_ATTRIBUTES
inheritability HandleInheritability
return Interop.Kernel32.SECURITY_ATTRIBUTES
        public AnonymousPipeServerStream(PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity) : base(direction, bufferSize)
        {
            object obj2;

            if (direction == PipeDirection.InOut)
            {
                throw new NotSupportedException(System.SR.GetString("NotSupported_AnonymousPipeUnidirectional"));
            }
            if ((inheritability < HandleInheritability.None) || (inheritability > HandleInheritability.Inheritable))
            {
                throw new ArgumentOutOfRangeException("inheritability", System.SR.GetString("ArgumentOutOfRange_HandleInheritabilityNoneOrInheritable"));
            }
            Microsoft.Win32.UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(inheritability, pipeSecurity, out obj2);
            try
            {
                this.Create(direction, secAttrs, bufferSize);
            }
            finally
            {
                if (obj2 != null)
                {
                    ((GCHandle)obj2).Free();
                }
            }
        }
        // Creates the anonymous pipe. This overload is used in Mono to implement public constructors.
        private void Create(PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity)
        {
            Debug.Assert(direction != PipeDirection.InOut, "Anonymous pipe direction shouldn't be InOut");
            Debug.Assert(bufferSize >= 0, "bufferSize is negative");

            bool           bSuccess;
            SafePipeHandle serverHandle;
            SafePipeHandle newServerHandle;

            // Create the two pipe handles that make up the anonymous pipe.
            GCHandle pinningHandle = default;

            try
            {
                Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(inheritability, pipeSecurity, ref pinningHandle);

                if (direction == PipeDirection.In)
                {
                    bSuccess = Interop.Kernel32.CreatePipe(out serverHandle, out _clientHandle, ref secAttrs, bufferSize);
                }
                else
                {
                    bSuccess = Interop.Kernel32.CreatePipe(out _clientHandle, out serverHandle, ref secAttrs, bufferSize);
                }
            }
            finally
            {
                if (pinningHandle.IsAllocated)
                {
                    pinningHandle.Free();
                }
            }

            if (!bSuccess)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            // Duplicate the server handle to make it not inheritable.  Note: We need to do this so that the child
            // process doesn't end up getting another copy of the server handle.  If it were to get a copy, the
            // OS wouldn't be able to inform the child that the server has closed its handle because it will see
            // that there is still one server handle that is open.
            bSuccess = Interop.Kernel32.DuplicateHandle(Interop.Kernel32.GetCurrentProcess(), serverHandle, Interop.Kernel32.GetCurrentProcess(),
                                                        out newServerHandle, 0, false, Interop.Kernel32.HandleOptions.DUPLICATE_SAME_ACCESS);

            if (!bSuccess)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            // Close the inheritable server handle.
            serverHandle.Dispose();

            InitializeHandle(newServerHandle, false, false);

            State = PipeState.Connected;
        }
Example #3
0
        public NamedPipeServerStream(string pipeName, PipeDirection direction, int maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, int inBufferSize, int outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights) : base(direction, transmissionMode, outBufferSize)
        {
            if (pipeName == null)
            {
                throw new ArgumentNullException("pipeName");
            }
            if (pipeName.Length == 0)
            {
                throw new ArgumentException(System.SR.GetString("Argument_NeedNonemptyPipeName"));
            }
            if ((options & ~(PipeOptions.Asynchronous | PipeOptions.WriteThrough)) != PipeOptions.None)
            {
                throw new ArgumentOutOfRangeException("options", System.SR.GetString("ArgumentOutOfRange_OptionsInvalid"));
            }
            if (inBufferSize < 0)
            {
                throw new ArgumentOutOfRangeException("inBufferSize", System.SR.GetString("ArgumentOutOfRange_NeedNonNegNum"));
            }
            if (((maxNumberOfServerInstances < 1) || (maxNumberOfServerInstances > 0xfe)) && (maxNumberOfServerInstances != -1))
            {
                throw new ArgumentOutOfRangeException("maxNumberOfServerInstances", System.SR.GetString("ArgumentOutOfRange_MaxNumServerInstances"));
            }
            if ((inheritability < HandleInheritability.None) || (inheritability > HandleInheritability.Inheritable))
            {
                throw new ArgumentOutOfRangeException("inheritability", System.SR.GetString("ArgumentOutOfRange_HandleInheritabilityNoneOrInheritable"));
            }
            if ((additionalAccessRights & ~(PipeAccessRights.AccessSystemSecurity | PipeAccessRights.TakeOwnership | PipeAccessRights.ChangePermissions)) != 0)
            {
                throw new ArgumentOutOfRangeException("additionalAccessRights", System.SR.GetString("ArgumentOutOfRange_AdditionalAccessLimited"));
            }
            if (Environment.OSVersion.Platform == PlatformID.Win32Windows)
            {
                throw new PlatformNotSupportedException(System.SR.GetString("PlatformNotSupported_NamedPipeServers"));
            }
            string fullPath = Path.GetFullPath(@"\\.\pipe\" + pipeName);

            if (string.Compare(fullPath, @"\\.\pipe\anonymous", StringComparison.OrdinalIgnoreCase) == 0)
            {
                throw new ArgumentOutOfRangeException("pipeName", System.SR.GetString("ArgumentOutOfRange_AnonymousReserved"));
            }
            object pinningHandle = null;

            Microsoft.Win32.UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(inheritability, pipeSecurity, out pinningHandle);
            try
            {
                this.Create(fullPath, direction, maxNumberOfServerInstances, transmissionMode, options, inBufferSize, outBufferSize, additionalAccessRights, secAttrs);
            }
            finally
            {
                if (pinningHandle != null)
                {
                    ((GCHandle)pinningHandle).Free();
                }
            }
        }
Example #4
0
        public void Connect(int timeout)
        {
            this.CheckConnectOperationsClient();
            if ((timeout < 0) && (timeout != -1))
            {
                throw new ArgumentOutOfRangeException("timeout", System.SR.GetString("ArgumentOutOfRange_InvalidTimeout"));
            }
            Microsoft.Win32.UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(this.m_inheritability);
            int pipeOptions = (int)this.m_pipeOptions;

            if (this.m_impersonationLevel != TokenImpersonationLevel.None)
            {
                pipeOptions |= 0x100000;
                pipeOptions |= ((int)(this.m_impersonationLevel - 1)) << 0x10;
            }
            int tickCount = Environment.TickCount;
            int num3      = 0;

Label_005C:
            if (!Microsoft.Win32.UnsafeNativeMethods.WaitNamedPipe(this.m_normalizedPipePath, timeout - num3))
            {
                int errorCode = Marshal.GetLastWin32Error();
                switch (errorCode)
                {
                case 2:
                    goto Label_00EF;

                case 0:
                    goto Label_0105;
                }
                System.IO.__Error.WinIOError(errorCode, string.Empty);
            }
            SafePipeHandle handle = Microsoft.Win32.UnsafeNativeMethods.CreateNamedPipeClient(this.m_normalizedPipePath, this.m_access, FileShare.None, secAttrs, FileMode.Open, pipeOptions, Microsoft.Win32.UnsafeNativeMethods.NULL);

            if (handle.IsInvalid)
            {
                int num5 = Marshal.GetLastWin32Error();
                if (num5 == 0xe7)
                {
                    goto Label_00EF;
                }
                System.IO.__Error.WinIOError(num5, string.Empty);
            }
            base.InitializeHandle(handle, false, (this.m_pipeOptions & PipeOptions.Asynchronous) != PipeOptions.None);
            base.State = PipeState.Connected;
            return;

Label_00EF:
            if ((timeout == -1) || ((num3 = Environment.TickCount - tickCount) < timeout))
            {
                goto Label_005C;
            }
Label_0105:
            throw new TimeoutException();
        }
Example #5
0
        private void Create(string pipeName, PipeDirection direction, int maxNumberOfServerInstances,
                            PipeTransmissionMode transmissionMode, PipeOptions options, int inBufferSize, int outBufferSize,
                            HandleInheritability inheritability)
        {
            Debug.Assert(pipeName != null && pipeName.Length != 0, "fullPipeName is null or empty");
            Debug.Assert(direction >= PipeDirection.In && direction <= PipeDirection.InOut, "invalid pipe direction");
            Debug.Assert(inBufferSize >= 0, "inBufferSize is negative");
            Debug.Assert(outBufferSize >= 0, "outBufferSize is negative");
            Debug.Assert((maxNumberOfServerInstances >= 1 && maxNumberOfServerInstances <= 254) || (maxNumberOfServerInstances == MaxAllowedServerInstances), "maxNumberOfServerInstances is invalid");
            Debug.Assert(transmissionMode >= PipeTransmissionMode.Byte && transmissionMode <= PipeTransmissionMode.Message, "transmissionMode is out of range");

            string fullPipeName = Path.GetFullPath(@"\\.\pipe\" + pipeName);

            // Make sure the pipe name isn't one of our reserved names for anonymous pipes.
            if (String.Equals(fullPipeName, @"\\.\pipe\anonymous", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentOutOfRangeException(nameof(pipeName), SR.ArgumentOutOfRange_AnonymousReserved);
            }


            int openMode = ((int)direction) |
                           (maxNumberOfServerInstances == 1 ? Interop.mincore.FileOperations.FILE_FLAG_FIRST_PIPE_INSTANCE : 0) |
                           (int)options;

            // We automatically set the ReadMode to match the TransmissionMode.
            int pipeModes = (int)transmissionMode << 2 | (int)transmissionMode << 1;

            // Convert -1 to 255 to match win32 (we asserted that it is between -1 and 254).
            if (maxNumberOfServerInstances == MaxAllowedServerInstances)
            {
                maxNumberOfServerInstances = 255;
            }

            Interop.mincore.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(inheritability);
            SafePipeHandle handle = Interop.mincore.CreateNamedPipe(fullPipeName, openMode, pipeModes,
                                                                    maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, ref secAttrs);

            if (handle.IsInvalid)
            {
                throw Win32Marshal.GetExceptionForLastWin32Error();
            }

            InitializeHandle(handle, false, (options & PipeOptions.Asynchronous) != 0);
        }
        // Waits for a pipe instance to become available. This method may return before WaitForConnection is called
        // on the server end, but WaitForConnection will not return until we have returned.  Any data written to the
        // pipe by us after we have connected but before the server has called WaitForConnection will be available
        // to the server after it calls WaitForConnection.
        private bool TryConnect(int timeout, CancellationToken cancellationToken)
        {
            Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability);

            // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag.
            // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to
            // CreateNamedPipeClient that were not defined in the enumeration.
            int _pipeFlags = (int)(_pipeOptions & ~PipeOptions.CurrentUserOnly);

            if (_impersonationLevel != TokenImpersonationLevel.None)
            {
                _pipeFlags |= Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT;
                _pipeFlags |= (((int)_impersonationLevel - 1) << 16);
            }

            int access = 0;

            if ((PipeDirection.In & _direction) != 0)
            {
                access |= Interop.Kernel32.GenericOperations.GENERIC_READ;
            }
            if ((PipeDirection.Out & _direction) != 0)
            {
                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
                                                                           ref secAttrs,  // security attributes
                                                                           FileMode.Open, // open existing
                                                                           _pipeFlags,    // impersonation flags
                                                                           IntPtr.Zero);  // template file: null

            if (handle.IsInvalid)
            {
                int errorCode = Marshal.GetLastWin32Error();

                if (errorCode != Interop.Errors.ERROR_PIPE_BUSY &&
                    errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }

                if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout))
                {
                    errorCode = Marshal.GetLastWin32Error();

                    // Server is not yet created or a timeout occurred before a pipe instance was available.
                    if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND ||
                        errorCode == Interop.Errors.ERROR_SEM_TIMEOUT)
                    {
                        return(false);
                    }

                    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!
            InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0);
            State = PipeState.Connected;
            ValidateRemotePipeUser();
            return(true);
        }
        private void Create(string pipeName, PipeDirection direction, int maxNumberOfServerInstances,
                            PipeTransmissionMode transmissionMode, PipeOptions options, int inBufferSize, int outBufferSize,
                            HandleInheritability inheritability)
        {
            Debug.Assert(pipeName != null && pipeName.Length != 0, "fullPipeName is null or empty");
            Debug.Assert(direction >= PipeDirection.In && direction <= PipeDirection.InOut, "invalid pipe direction");
            Debug.Assert(inBufferSize >= 0, "inBufferSize is negative");
            Debug.Assert(outBufferSize >= 0, "outBufferSize is negative");
            Debug.Assert((maxNumberOfServerInstances >= 1 && maxNumberOfServerInstances <= 254) || (maxNumberOfServerInstances == MaxAllowedServerInstances), "maxNumberOfServerInstances is invalid");
            Debug.Assert(transmissionMode >= PipeTransmissionMode.Byte && transmissionMode <= PipeTransmissionMode.Message, "transmissionMode is out of range");

            string fullPipeName = Path.GetFullPath(@"\\.\pipe\" + pipeName);

            // Make sure the pipe name isn't one of our reserved names for anonymous pipes.
            if (String.Equals(fullPipeName, @"\\.\pipe\anonymous", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentOutOfRangeException(nameof(pipeName), SR.ArgumentOutOfRange_AnonymousReserved);
            }

            PipeSecurity pipeSecurity = null;

            if (IsCurrentUserOnly)
            {
                using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())
                {
                    SecurityIdentifier identifier = currentIdentity.Owner;
                    PipeAccessRule     rule       = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite, AccessControlType.Allow);
                    pipeSecurity = new PipeSecurity();

                    pipeSecurity.AddAccessRule(rule);
                    pipeSecurity.SetOwner(identifier);
                }

                // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag.
                // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to CreateNamedPipe
                // that were not defined in the enumeration.
                options &= ~PipeOptions.CurrentUserOnly;
            }

            int openMode = ((int)direction) |
                           (maxNumberOfServerInstances == 1 ? Interop.Kernel32.FileOperations.FILE_FLAG_FIRST_PIPE_INSTANCE : 0) |
                           (int)options;

            // We automatically set the ReadMode to match the TransmissionMode.
            int pipeModes = (int)transmissionMode << 2 | (int)transmissionMode << 1;

            // Convert -1 to 255 to match win32 (we asserted that it is between -1 and 254).
            if (maxNumberOfServerInstances == MaxAllowedServerInstances)
            {
                maxNumberOfServerInstances = 255;
            }

            var pinningHandle = new GCHandle();

            try
            {
                Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(inheritability, pipeSecurity, ref pinningHandle);
                SafePipeHandle handle = Interop.Kernel32.CreateNamedPipe(fullPipeName, openMode, pipeModes,
                                                                         maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, ref secAttrs);

                if (handle.IsInvalid)
                {
                    throw Win32Marshal.GetExceptionForLastWin32Error();
                }

                InitializeHandle(handle, false, (options & PipeOptions.Asynchronous) != 0);
            }
            finally
            {
                if (pinningHandle.IsAllocated)
                {
                    pinningHandle.Free();
                }
            }
        }
Example #8
0
        private bool TryConnect(int timeout, CancellationToken cancellationToken)
        {
            Interop.mincore.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability);

            int _pipeFlags = (int)_pipeOptions;

            if (_impersonationLevel != TokenImpersonationLevel.None)
            {
                _pipeFlags |= Interop.mincore.SecurityOptions.SECURITY_SQOS_PRESENT;
                _pipeFlags |= (((int)_impersonationLevel - 1) << 16);
            }

            if (!Interop.mincore.WaitNamedPipe(_normalizedPipePath, timeout))
            {
                int errorCode = Marshal.GetLastWin32Error();

                // Server is not yet created
                if (errorCode == Interop.mincore.Errors.ERROR_FILE_NOT_FOUND)
                {
                    return(false);
                }

                // The timeout has expired.
                if (errorCode == Interop.mincore.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)
            {
                access |= Interop.mincore.GenericOperations.GENERIC_READ;
            }
            if ((PipeDirection.Out & _direction) != 0)
            {
                access |= Interop.mincore.GenericOperations.GENERIC_WRITE;
            }
            SafePipeHandle handle = Interop.mincore.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)
            {
                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.mincore.Errors.ERROR_PIPE_BUSY)
                {
                    return(false);
                }

                throw Win32Marshal.GetExceptionForWin32Error(errorCode);
            }

            // Success!
            InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0);
            State = PipeState.Connected;

            return(true);
        }
Example #9
0
        private void ConnectInternal(int timeout, CancellationToken cancellationToken, int startTime)
        {
            Interop.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability);

            int _pipeFlags = (int)_pipeOptions;

            if (_impersonationLevel != TokenImpersonationLevel.None)
            {
                _pipeFlags |= Interop.SECURITY_SQOS_PRESENT;
                _pipeFlags |= (((int)_impersonationLevel - 1) << 16);
            }

            // This is the main connection loop. It will loop until the timeout expires.  Most of the
            // time, we will be waiting in the WaitNamedPipe win32 blocking function; however, there are
            // cases when we will need to loop: 1) The server is not created (WaitNamedPipe returns
            // straight away in such cases), and 2) when another client connects to our server in between
            // our WaitNamedPipe and CreateFile calls.
            int elapsed = 0;

            do
            {
                // We want any other exception and and success to have priority over cancellation.
                cancellationToken.ThrowIfCancellationRequested();

                // Wait for pipe to become free (this will block unless the pipe does not exist).
                int timeLeft = timeout - elapsed;
                int waitTime;
                if (cancellationToken.CanBeCanceled)
                {
                    waitTime = Math.Min(CancellationCheckInterval, timeLeft);
                }
                else
                {
                    waitTime = timeLeft;
                }

                if (!Interop.mincore.WaitNamedPipe(_normalizedPipePath, waitTime))
                {
                    int errorCode = Marshal.GetLastWin32Error();

                    // Server is not yet created so let's keep looping.
                    if (errorCode == Interop.ERROR_FILE_NOT_FOUND)
                    {
                        continue;
                    }

                    // The timeout has expired.
                    if (errorCode == Interop.ERROR_SUCCESS)
                    {
                        if (cancellationToken.CanBeCanceled)
                        {
                            // It may not be real timeout and only checking for cancellation
                            // let the while condition check it and decide
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }

                // Pipe server should be free.  Let's try to connect to it.
                int access = 0;
                if ((PipeDirection.In & _direction) != 0)
                {
                    access |= Interop.GENERIC_READ;
                }
                if ((PipeDirection.Out & _direction) != 0)
                {
                    access |= Interop.GENERIC_WRITE;
                }
                SafePipeHandle handle = Interop.mincore.CreateNamedPipeClient(_normalizedPipePath,
                                                                              access,        // read and write access
                                                                              0,             // sharing: none
                                                                              ref secAttrs,  // security attributes
                                                                              FileMode.Open, // open existing
                                                                              _pipeFlags,    // impersonation flags
                                                                              Interop.NULL); // template file: null

                if (handle.IsInvalid)
                {
                    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.ERROR_PIPE_BUSY)
                    {
                        continue;
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }

                // Success!
                InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0);
                State = PipeState.Connected;

                return;
            }while (timeout == Timeout.Infinite || (elapsed = unchecked (Environment.TickCount - startTime)) < timeout);
            // BUGBUG: SerialPort does not use unchecked arithmetic when calculating elapsed times.  This is needed
            //         because Environment.TickCount can overflow (though only every 49.7 days).

            throw new TimeoutException();
        }
        // Waits for a pipe instance to become available. This method may return before WaitForConnection is called
        // on the server end, but WaitForConnection will not return until we have returned.  Any data written to the
        // pipe by us after we have connected but before the server has called WaitForConnection will be available
        // to the server after it calls WaitForConnection.
        private bool TryConnect(int timeout, CancellationToken cancellationToken)
        {
            Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability);

            // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag.
            // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to
            // CreateNamedPipeClient that were not defined in the enumeration.
            int _pipeFlags = (int)(_pipeOptions & ~PipeOptions.CurrentUserOnly);

            if (_impersonationLevel != TokenImpersonationLevel.None)
            {
                _pipeFlags |= Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT;
                _pipeFlags |= (((int)_impersonationLevel - 1) << 16);
            }

            int access = 0;

            if ((PipeDirection.In & _direction) != 0)
            {
                access |= Interop.Kernel32.GenericOperations.GENERIC_READ;
            }
            if ((PipeDirection.Out & _direction) != 0)
            {
                access |= Interop.Kernel32.GenericOperations.GENERIC_WRITE;
            }

            SafePipeHandle handle = CreateNamedPipeClient(_normalizedPipePath, ref secAttrs, _pipeFlags, access);

            if (handle.IsInvalid)
            {
                int errorCode = Marshal.GetLastPInvokeError();

                // CreateFileW: "If the CreateNamedPipe function was not successfully called on the server prior to this operation,
                // a pipe will not exist and CreateFile will fail with ERROR_FILE_NOT_FOUND"
                // WaitNamedPipeW: "If no instances of the specified named pipe exist,
                // the WaitNamedPipe function returns immediately, regardless of the time-out value."
                // We know that no instances exist, so we just quit without calling WaitNamedPipeW.
                if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
                {
                    return(false);
                }

                if (errorCode != Interop.Errors.ERROR_PIPE_BUSY)
                {
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }

                if (!Interop.Kernel32.WaitNamedPipe(_normalizedPipePath, timeout))
                {
                    errorCode = Marshal.GetLastPInvokeError();

                    if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND || // server has been closed
                        errorCode == Interop.Errors.ERROR_SEM_TIMEOUT)
                    {
                        return(false);
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }

                // Pipe server should be free. Let's try to connect to it.
                handle = CreateNamedPipeClient(_normalizedPipePath, ref secAttrs, _pipeFlags, access);

                if (handle.IsInvalid)
                {
                    errorCode = Marshal.GetLastPInvokeError();

                    // WaitNamedPipe: "A subsequent CreateFile call to the pipe can fail,
                    // because the instance was closed by the server or opened by another client."
                    if (errorCode == Interop.Errors.ERROR_PIPE_BUSY ||    // opened by another client
                        errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND) // server has been closed
                    {
                        return(false);
                    }

                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }
            }

            // Success!
            InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0);
            State = PipeState.Connected;
            ValidateRemotePipeUser();
            return(true);