/// <summary> /// Helper method to create a PowerShell transport named pipe via native API, along /// with a returned .Net NamedPipeServerStream object wrapping the named pipe. /// </summary> /// <param name="serverName">Named pipe server name.</param> /// <param name="namespaceName">Named pipe namespace name.</param> /// <param name="coreName">Named pipe core name.</param> /// <param name="securityDesc"></param> /// <returns>NamedPipeServerStream</returns> private NamedPipeServerStream CreateNamedPipe( string serverName, string namespaceName, string coreName, CommonSecurityDescriptor securityDesc) { if (serverName == null) { throw new PSArgumentNullException("serverName"); } if (namespaceName == null) { throw new PSArgumentNullException("namespaceName"); } if (coreName == null) { throw new PSArgumentNullException("coreName"); } string fullPipeName = @"\\" + serverName + @"\" + namespaceName + @"\" + coreName; // Create optional security attributes based on provided PipeSecurity. NamedPipeNative.SECURITY_ATTRIBUTES securityAttributes = null; GCHandle?securityDescHandle = null; if (securityDesc != null) { byte[] securityDescBuffer = new byte[securityDesc.BinaryLength]; securityDesc.GetBinaryForm(securityDescBuffer, 0); securityDescHandle = GCHandle.Alloc(securityDescBuffer, GCHandleType.Pinned); securityAttributes = NamedPipeNative.GetSecurityAttributes(securityDescHandle.Value); } // Create named pipe. SafePipeHandle pipeHandle = NamedPipeNative.CreateNamedPipe( fullPipeName, NamedPipeNative.PIPE_ACCESS_DUPLEX | NamedPipeNative.FILE_FLAG_FIRST_PIPE_INSTANCE | NamedPipeNative.FILE_FLAG_OVERLAPPED, NamedPipeNative.PIPE_TYPE_MESSAGE | NamedPipeNative.PIPE_READMODE_MESSAGE, 1, _namedPipeBufferSizeForRemoting, _namedPipeBufferSizeForRemoting, 0, securityAttributes); int lastError = Marshal.GetLastWin32Error(); if (securityDescHandle != null) { securityDescHandle.Value.Free(); } if (pipeHandle.IsInvalid) { throw new PSInvalidOperationException( StringUtil.Format(RemotingErrorIdStrings.CannotCreateNamedPipe, lastError)); } // Create the .Net NamedPipeServerStream wrapper. try { return(new NamedPipeServerStream( PipeDirection.InOut, true, // IsAsync false, // IsConnected pipeHandle)); } catch (Exception) { pipeHandle.Dispose(); throw; } }
/// <summary> /// Helper method to open a named pipe via native APIs and return in /// .Net NamedPipeClientStream wrapper object. /// </summary> protected override NamedPipeClientStream DoConnect(int timeout) { // Create pipe flags. uint pipeFlags = NamedPipeNative.FILE_FLAG_OVERLAPPED; // // WaitNamedPipe API is not supported by Windows Server container now, so we need to repeatedly // attempt connection to pipe server until timeout expires. // int startTime = Environment.TickCount; int elapsedTime = 0; SafePipeHandle pipeHandle = null; do { // Get handle to pipe. pipeHandle = NamedPipeNative.CreateFile( _pipeName, NamedPipeNative.GENERIC_READ | NamedPipeNative.GENERIC_WRITE, 0, IntPtr.Zero, NamedPipeNative.OPEN_EXISTING, pipeFlags, IntPtr.Zero); int lastError = Marshal.GetLastWin32Error(); if (pipeHandle.IsInvalid) { if (lastError == NamedPipeNative.ERROR_FILE_NOT_FOUND) { elapsedTime = unchecked (Environment.TickCount - startTime); Thread.Sleep(100); continue; } else { throw new PSInvalidOperationException( StringUtil.Format(RemotingErrorIdStrings.CannotConnectContainerNamedPipe, lastError)); } } else { break; } } while (elapsedTime < timeout); try { return(new NamedPipeClientStream( PipeDirection.InOut, true, true, pipeHandle)); } catch (Exception e) { CommandProcessorBase.CheckForSevereException(e); pipeHandle.Dispose(); throw; } }