{
[DllImport(Libraries.Kernel32, EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)]
internal static extern SafePipeHandle CreateNamedPipeClient(
- string lpFileName,
+ string? lpFileName,
int dwDesiredAccess,
System.IO.FileShare dwShareMode,
ref SECURITY_ATTRIBUTES secAttrs,
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, EntryPoint = "WaitNamedPipeW")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool WaitNamedPipe(string name, int timeout);
+ internal static extern bool WaitNamedPipe(string? name, int timeout);
}
}
public virtual System.IO.Pipes.PipeTransmissionMode ReadMode { get { throw null; } set { } }
public Microsoft.Win32.SafeHandles.SafePipeHandle SafePipeHandle { get { throw null; } }
public virtual System.IO.Pipes.PipeTransmissionMode TransmissionMode { get { throw null; } }
- public override System.IAsyncResult BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) { throw null; }
- public override System.IAsyncResult BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) { throw null; }
+ public override System.IAsyncResult BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback? callback, object? state) { throw null; }
+ public override System.IAsyncResult BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback? callback, object? state) { throw null; }
protected internal virtual void CheckPipePropertyOperations() { }
protected internal void CheckReadOperations() { }
protected internal void CheckWriteOperations() { }
public override int EndRead(System.IAsyncResult asyncResult) { throw null; }
public override void EndWrite(System.IAsyncResult asyncResult) { }
public override void Flush() { }
- protected void InitializeHandle(Microsoft.Win32.SafeHandles.SafePipeHandle handle, bool isExposed, bool isAsync) { }
+ public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
+ protected void InitializeHandle(Microsoft.Win32.SafeHandles.SafePipeHandle? handle, bool isExposed, bool isAsync) { }
public override int Read(byte[] buffer, int offset, int count) { throw null; }
public override int Read(System.Span<byte> buffer) { throw null; }
public override System.Threading.Tasks.Task<int> ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Include="System.IO.Pipes.cs" />
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
using System;
using System.Diagnostics;
using System.Net.Sockets;
// and operations that should go through the Socket to be done via _namedPipeSocket. We keep the
// Socket's SafeHandle alive as long as this SafeHandle is alive.
- private Socket _namedPipeSocket;
- private SafeHandle _namedPipeSocketHandle;
+ private Socket? _namedPipeSocket;
+ private SafeHandle? _namedPipeSocketHandle;
internal SafePipeHandle(Socket namedPipeSocket) : base(ownsHandle: true)
{
SetHandle(_namedPipeSocketHandle.DangerousGetHandle());
}
- internal Socket NamedPipeSocket => _namedPipeSocket;
- internal SafeHandle NamedPipeSocketHandle => _namedPipeSocketHandle;
+ internal Socket? NamedPipeSocket => _namedPipeSocket;
+ internal SafeHandle? NamedPipeSocketHandle => _namedPipeSocketHandle;
protected override void Dispose(bool disposing)
{
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#nullable enable
using System;
using System.Runtime.InteropServices;
using System.Security;
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OmitTransitiveCompileReferences>true</OmitTransitiveCompileReferences>
<TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix</TargetFrameworks>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<!-- Compiled Source Files -->
<ItemGroup>
Create(direction, inheritability, bufferSize, null);
}
- private void Create(PipeDirection direction, HandleInheritability inheritability, int bufferSize, PipeSecurity pipeSecurity)
+ 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");
/// </summary>
public sealed partial class AnonymousPipeServerStream : PipeStream
{
- private SafePipeHandle _clientHandle;
+ private SafePipeHandle _clientHandle = null!;
private bool _clientHandleExposed;
public AnonymousPipeServerStream()
// Using RunContinuationsAsynchronously for compat reasons (old API used ThreadPool.QueueUserWorkItem for continuations)
internal ConnectionCompletionSource(NamedPipeServerStream server)
- : base(server._threadPoolBinding, ReadOnlyMemory<byte>.Empty)
+ : base(server._threadPoolBinding!, ReadOnlyMemory<byte>.Empty)
{
_serverStream = server;
}
// immediately if it isn't. The only delay will be between the time the server
// has called Bind and Listen, with the latter immediately following the former.
var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
- SafePipeHandle clientHandle = null;
+ SafePipeHandle? clientHandle = null;
try
{
socket.Connect(new UnixDomainSocketEndPoint(_normalizedPipePath));
// access request before calling NTCreateFile, so all NamedPipeClientStreams can read
// this if they are created (on WinXP SP2 at least)]
uint numInstances;
- if (!Interop.Kernel32.GetNamedPipeHandleStateW(InternalHandle, null, &numInstances, null, null, null, 0))
+ if (!Interop.Kernel32.GetNamedPipeHandleStateW(InternalHandle!, null, &numInstances, null, null, null, 0))
{
throw WinIOError(Marshal.GetLastWin32Error());
}
return;
PipeSecurity accessControl = this.GetAccessControl();
- IdentityReference remoteOwnerSid = accessControl.GetOwner(typeof(SecurityIdentifier));
+ IdentityReference? remoteOwnerSid = accessControl.GetOwner(typeof(SecurityIdentifier));
using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())
{
- SecurityIdentifier currentUserSid = currentIdentity.Owner;
+ SecurityIdentifier? currentUserSid = currentIdentity.Owner;
if (remoteOwnerSid != currentUserSid)
{
State = PipeState.Closed;
// Maximum interval in milliseconds between which cancellation is checked.
// Used by ConnectInternal. 50ms is fairly responsive time but really long time for processor.
private const int CancellationCheckInterval = 50;
- private readonly string _normalizedPipePath;
+ private readonly string? _normalizedPipePath;
private readonly TokenImpersonationLevel _impersonationLevel;
private readonly PipeOptions _pipeOptions;
private readonly HandleInheritability _inheritability;
{
public sealed partial class NamedPipeServerStream : PipeStream
{
- private SharedServer _instance;
+ private SharedServer? _instance;
private PipeDirection _direction;
private PipeOptions _options;
private int _inBufferSize;
// Use and block on AcceptAsync() rather than using Accept() in order to provide
// behavior more akin to Windows if the Stream is closed while a connection is pending.
- Socket accepted = _instance.ListeningSocket.AcceptAsync().GetAwaiter().GetResult();
+ Socket accepted = _instance!.ListeningSocket.AcceptAsync().GetAwaiter().GetResult();
HandleAcceptedSocket(accepted);
}
WaitForConnectionAsyncCore();
async Task WaitForConnectionAsyncCore() =>
- HandleAcceptedSocket(await _instance.ListeningSocket.AcceptAsync().ConfigureAwait(false));
+ HandleAcceptedSocket(await _instance!.ListeningSocket.AcceptAsync().ConfigureAwait(false));
}
private void HandleAcceptedSocket(Socket acceptedSocket)
{
CheckDisconnectOperations();
State = PipeState.Disconnected;
- InternalHandle.Dispose();
+ InternalHandle!.Dispose();
InitializeHandle(null, false, false);
}
{
CheckWriteOperations();
- SafeHandle handle = InternalHandle?.NamedPipeSocketHandle;
+ SafeHandle? handle = InternalHandle?.NamedPipeSocketHandle;
if (handle == null)
{
throw new InvalidOperationException(SR.InvalidOperation_PipeHandleNotSet);
public void RunAsClient(PipeStreamImpersonationWorker impersonationWorker)
{
CheckWriteOperations();
- SafeHandle handle = InternalHandle?.NamedPipeSocketHandle;
+ SafeHandle? handle = InternalHandle?.NamedPipeSocketHandle;
if (handle == null)
{
throw new InvalidOperationException(SR.InvalidOperation_PipeHandleNotSet);
lock (s_servers)
{
- SharedServer server;
+ SharedServer? server;
if (s_servers.TryGetValue(path, out server))
{
// On Windows, if a subsequent server stream is created for the same pipe and with a different
{
Interop.Kernel32.LoadLibraryEx("sspicli.dll", IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_SEARCH_SYSTEM32);
- if (Interop.Kernel32.GetNamedPipeHandleStateW(InternalHandle, null, null, null, null, userName, userNameMaxLength))
+ if (Interop.Kernel32.GetNamedPipeHandleStateW(InternalHandle!, null, null, null, null, userName, userNameMaxLength))
{
return new string(userName);
}
// This overload is used in Mono to implement public constructors.
private void Create(string pipeName, PipeDirection direction, int maxNumberOfServerInstances,
PipeTransmissionMode transmissionMode, PipeOptions options, int inBufferSize, int outBufferSize,
- PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights)
+ PipeSecurity? pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights)
{
Debug.Assert(pipeName != null && pipeName.Length != 0, "fullPipeName is null or empty");
Debug.Assert(direction >= PipeDirection.In && direction <= PipeDirection.InOut, "invalid pipe direction");
using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())
{
- SecurityIdentifier identifier = currentIdentity.Owner;
+ SecurityIdentifier identifier = currentIdentity.Owner!;
// Grant full control to the owner so multiple servers can be opened.
// Full control is the default per MSDN docs for CreateNamedPipe.
}
else
{
- if (!Interop.Kernel32.ConnectNamedPipe(InternalHandle, IntPtr.Zero))
+ if (!Interop.Kernel32.ConnectNamedPipe(InternalHandle!, IntPtr.Zero))
{
int errorCode = Marshal.GetLastWin32Error();
if (!IsAsync)
{
- return Task.Factory.StartNew(s => ((NamedPipeServerStream)s).WaitForConnection(),
+ return Task.Factory.StartNew(s => ((NamedPipeServerStream)s!).WaitForConnection(),
this, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
}
CheckDisconnectOperations();
// Disconnect the pipe.
- if (!Interop.Kernel32.DisconnectNamedPipe(InternalHandle))
+ if (!Interop.Kernel32.DisconnectNamedPipe(InternalHandle!))
{
throw Win32Marshal.GetExceptionForLastWin32Error();
}
const uint UserNameMaxLength = Interop.Kernel32.CREDUI_MAX_USERNAME_LENGTH + 1;
char* userName = stackalloc char[(int)UserNameMaxLength]; // ~1K
- if (Interop.Kernel32.GetNamedPipeHandleStateW(InternalHandle, null, null, null, null, userName, UserNameMaxLength))
+ if (Interop.Kernel32.GetNamedPipeHandleStateW(InternalHandle!, null, null, null, null, userName, UserNameMaxLength))
{
return new string(userName);
}
private static readonly RuntimeHelpers.TryCode tryCode = new RuntimeHelpers.TryCode(ImpersonateAndTryCode);
private static readonly RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(RevertImpersonationOnBackout);
- private static void ImpersonateAndTryCode(object helper)
+ private static void ImpersonateAndTryCode(object? helper)
{
- ExecuteHelper execHelper = (ExecuteHelper)helper;
+ ExecuteHelper execHelper = (ExecuteHelper)helper!;
- if (Interop.Advapi32.ImpersonateNamedPipeClient(execHelper._handle))
+ if (Interop.Advapi32.ImpersonateNamedPipeClient(execHelper._handle!))
{
execHelper._mustRevert = true;
}
}
}
- private static void RevertImpersonationOnBackout(object helper, bool exceptionThrown)
+ private static void RevertImpersonationOnBackout(object? helper, bool exceptionThrown)
{
- ExecuteHelper execHelper = (ExecuteHelper)helper;
+ ExecuteHelper execHelper = (ExecuteHelper)helper!;
if (execHelper._mustRevert)
{
internal class ExecuteHelper
{
internal PipeStreamImpersonationWorker _userCode;
- internal SafePipeHandle _handle;
+ internal SafePipeHandle? _handle;
internal bool _mustRevert;
internal int _impersonateErrorCode;
internal int _revertImpersonateErrorCode;
- internal ExecuteHelper(PipeStreamImpersonationWorker userCode, SafePipeHandle handle)
+ internal ExecuteHelper(PipeStreamImpersonationWorker userCode, SafePipeHandle? handle)
{
_userCode = userCode;
_handle = handle;
var completionSource = new ConnectionCompletionSource(this);
- if (!Interop.Kernel32.ConnectNamedPipe(InternalHandle, completionSource.Overlapped))
+ if (!Interop.Kernel32.ConnectNamedPipe(InternalHandle!, completionSource.Overlapped))
{
int errorCode = Marshal.GetLastWin32Error();
_pinnedMemory = bufferToPin.Pin();
_overlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) =>
{
- var completionSource = (PipeCompletionSource<TResult>)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped);
+ var completionSource = (PipeCompletionSource<TResult>)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped)!;
Debug.Assert(completionSource.Overlapped == pOverlapped);
completionSource.AsyncCallback(errorCode, numBytes);
if (state == NoResult)
{
// Register the cancellation
- _cancellationRegistration = cancellationToken.UnsafeRegister(thisRef => ((PipeCompletionSource<TResult>)thisRef).Cancel(), this);
+ _cancellationRegistration = cancellationToken.UnsafeRegister(thisRef => ((PipeCompletionSource<TResult>)thisRef!).Cancel(), this);
// Grab the state for case if IO completed while we were setting the registration.
state = Interlocked.Exchange(ref _state, NoResult);
for (int i = 0; i < rules.Count; i++)
{
- PipeAccessRule fsrule = rules[i] as PipeAccessRule;
+ PipeAccessRule? fsrule = rules[i] as PipeAccessRule;
if ((fsrule != null) && (fsrule.PipeAccessRights == rule.PipeAccessRights)
&& (fsrule.IdentityReference == rule.IdentityReference)
for (int i = 0; i < rules.Count; i++)
{
- PipeAccessRule fsrule = rules[i] as PipeAccessRule;
+ PipeAccessRule? fsrule = rules[i] as PipeAccessRule;
if ((fsrule != null) && (fsrule.PipeAccessRights == rule.PipeAccessRights)
&& (fsrule.IdentityReference == rule.IdentityReference)
private unsafe int ReadCore(Span<byte> buffer)
{
+ Debug.Assert(_handle != null);
DebugAssertHandleValid(_handle);
// For named pipes, receive on the socket.
- Socket socket = _handle.NamedPipeSocket;
+ Socket? socket = _handle.NamedPipeSocket;
if (socket != null)
{
// For a blocking socket, we could simply use the same Read syscall as is done
private unsafe void WriteCore(ReadOnlySpan<byte> buffer)
{
+ Debug.Assert(_handle != null);
DebugAssertHandleValid(_handle);
// For named pipes, send to the socket.
- Socket socket = _handle.NamedPipeSocket;
+ Socket? socket = _handle.NamedPipeSocket;
if (socket != null)
{
// For a blocking socket, we could simply use the same Write syscall as is done
try
{
- return await InternalHandle.NamedPipeSocket.ReceiveAsync(destination, SocketFlags.None, cancellationToken).ConfigureAwait(false);
+ return await InternalHandle!.NamedPipeSocket.ReceiveAsync(destination, SocketFlags.None, cancellationToken).ConfigureAwait(false);
}
catch (SocketException e)
{
{
while (source.Length > 0)
{
- int bytesWritten = await _handle.NamedPipeSocket.SendAsync(source, SocketFlags.None, cancellationToken).ConfigureAwait(false);
+ int bytesWritten = await _handle!.NamedPipeSocket.SendAsync(source, SocketFlags.None, cancellationToken).ConfigureAwait(false);
Debug.Assert(bytesWritten > 0 && bytesWritten <= source.Length);
source = source.Slice(bytesWritten);
}
/// semaphore. Since we don't delegate to the base stream for Read/WriteAsync due
/// to having specialized support for cancellation, we do the same serialization here.
/// </summary>
- private SemaphoreSlim _asyncActiveSemaphore;
+ private SemaphoreSlim? _asyncActiveSemaphore;
private SemaphoreSlim EnsureAsyncActiveSemaphoreInitialized()
{
}
}
- internal static Exception CreateExceptionForLastError(string pipeName = null)
+ internal static Exception CreateExceptionForLastError(string? pipeName = null)
{
Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
return error.Error == Interop.Error.ENOTSUP ?
public abstract partial class PipeStream : Stream
{
internal const bool CheckOperationsRequiresSetHandle = true;
- internal ThreadPoolBoundHandle _threadPoolBinding;
+ internal ThreadPoolBoundHandle? _threadPoolBinding;
internal static string GetPipePath(string serverName, string pipeName)
{
private unsafe int ReadCore(Span<byte> buffer)
{
int errorCode = 0;
- int r = ReadFileNative(_handle, buffer, null, out errorCode);
+ int r = ReadFileNative(_handle!, buffer, null, out errorCode);
if (r == -1)
{
int r;
unsafe
{
- r = ReadFileNative(_handle, buffer.Span, completionSource.Overlapped, out errorCode);
+ r = ReadFileNative(_handle!, buffer.Span, completionSource.Overlapped, out errorCode);
}
// ReadFile, the OS version, will return 0 on failure, but this ReadFileNative wrapper
private unsafe void WriteCore(ReadOnlySpan<byte> buffer)
{
int errorCode = 0;
- int r = WriteFileNative(_handle, buffer, null, out errorCode);
+ int r = WriteFileNative(_handle!, buffer, null, out errorCode);
if (r == -1)
{
int r;
unsafe
{
- r = WriteFileNative(_handle, buffer.Span, completionSource.Overlapped, out errorCode);
+ r = WriteFileNative(_handle!, buffer.Span, completionSource.Overlapped, out errorCode);
}
// WriteFile, the OS version, will return 0 on failure, but this WriteFileNative
}
// Block until other end of the pipe has read everything.
- if (!Interop.Kernel32.FlushFileBuffers(_handle))
+ if (!Interop.Kernel32.FlushFileBuffers(_handle!))
{
throw WinIOError(Marshal.GetLastWin32Error());
}
if (_isFromExistingHandle)
{
uint pipeFlags;
- if (!Interop.Kernel32.GetNamedPipeInfo(_handle, &pipeFlags, null, null, null))
+ if (!Interop.Kernel32.GetNamedPipeInfo(_handle!, &pipeFlags, null, null, null))
{
throw WinIOError(Marshal.GetLastWin32Error());
}
}
uint inBufferSize;
- if (!Interop.Kernel32.GetNamedPipeInfo(_handle, null, null, &inBufferSize, null))
+ if (!Interop.Kernel32.GetNamedPipeInfo(_handle!, null, null, &inBufferSize, null))
{
throw WinIOError(Marshal.GetLastWin32Error());
}
{
outBufferSize = _outBufferSize;
}
- else if (!Interop.Kernel32.GetNamedPipeInfo(_handle, null, &outBufferSize, null, null))
+ else if (!Interop.Kernel32.GetNamedPipeInfo(_handle!, null, &outBufferSize, null, null))
{
throw WinIOError(Marshal.GetLastWin32Error());
}
unsafe
{
int pipeReadType = (int)value << 1;
- if (!Interop.Kernel32.SetNamedPipeHandleState(_handle, &pipeReadType, IntPtr.Zero, IntPtr.Zero))
+ if (!Interop.Kernel32.SetNamedPipeHandleState(_handle!, &pipeReadType, IntPtr.Zero, IntPtr.Zero))
{
throw WinIOError(Marshal.GetLastWin32Error());
}
return secAttrs;
}
- internal static unsafe Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability, PipeSecurity pipeSecurity, ref GCHandle pinningHandle)
+ internal static unsafe Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability, PipeSecurity? pipeSecurity, ref GCHandle pinningHandle)
{
Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(inheritability);
// For invalid handles, detect the error and mark our handle
// as invalid to give slightly better error messages. Also
// help ensure we avoid handle recycling bugs.
- _handle.SetHandleAsInvalid();
+ _handle!.SetHandleAsInvalid();
_state = PipeState.Broken;
break;
}
internal const string AnonymousPipeName = "anonymous";
private static readonly Task<int> s_zeroTask = Task.FromResult(0);
- private SafePipeHandle _handle;
+ private SafePipeHandle? _handle;
private bool _canRead;
private bool _canWrite;
private bool _isAsync;
// Once a PipeStream has a handle ready, it should call this method to set up the PipeStream. If
// the pipe is in a connected state already, it should also set the IsConnected (protected) property.
// This method may also be called to uninitialize a handle, setting it to null.
- protected void InitializeHandle(SafePipeHandle handle, bool isExposed, bool isAsync)
+ protected void InitializeHandle(SafePipeHandle? handle, bool isExposed, bool isAsync)
{
if (isAsync && handle != null)
{
return ReadAsyncCore(buffer, cancellationToken);
}
- public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
if (_isAsync)
return TaskToApm.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), callback, state);
return new ValueTask(WriteAsyncCore(buffer, cancellationToken));
}
- public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
if (_isAsync)
return TaskToApm.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), callback, state);
}
}
- internal SafePipeHandle InternalHandle
+ internal SafePipeHandle? InternalHandle
{
get
{
private int _numBytes; // number of buffer read OR written
internal ReadWriteCompletionSource(PipeStream stream, ReadOnlyMemory<byte> bufferToPin, bool isWrite)
- : base(stream._threadPoolBinding, bufferToPin)
+ : base(stream._threadPoolBinding!, bufferToPin)
{
_pipeStream = stream;
_isWrite = isWrite;