Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Kernel32
{
[Flags]
internal enum FileCompletionNotificationModes : byte
{
None = 0,
SkipCompletionPortOnSuccess = 1,
SkipSetEventOnHandle = 2
}

[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static unsafe extern bool SetFileCompletionNotificationModes(SafeHandle handle, FileCompletionNotificationModes flags);
}
}
19 changes: 19 additions & 0 deletions src/Common/src/System/Net/CompletionPortHelper.Uap.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Runtime.InteropServices;

namespace System.Net.Sockets
{
internal static class CompletionPortHelper
{
internal static bool SkipCompletionPortOnSuccess(SafeHandle handle)
{
// SetFileCompletionNotificationModes is not supported on UAP.
return false;
}

internal static readonly bool PlatformHasUdpIssue = false;
}
}
31 changes: 31 additions & 0 deletions src/Common/src/System/Net/CompletionPortHelper.Windows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Runtime.InteropServices;

namespace System.Net.Sockets
{
internal static class CompletionPortHelper
{
internal static bool SkipCompletionPortOnSuccess(SafeHandle handle)
{
return Interop.Kernel32.SetFileCompletionNotificationModes(handle,
Interop.Kernel32.FileCompletionNotificationModes.SkipCompletionPortOnSuccess |
Interop.Kernel32.FileCompletionNotificationModes.SkipSetEventOnHandle);
}

// There's a bug with using SetFileCompletionNotificationModes with UDP on Windows 7 and before.
// This check tells us if the problem exists on the platform we're running on.
internal static readonly bool PlatformHasUdpIssue = CheckIfPlatformHasUdpIssue();

private static bool CheckIfPlatformHasUdpIssue()
{
Version osVersion = Environment.OSVersion.Version;

// 6.1 == Windows 7
return (osVersion.Major < 6 ||
(osVersion.Major == 6 && osVersion.Minor <= 1));
}
}
}
27 changes: 23 additions & 4 deletions src/Common/src/System/Net/SafeCloseSocket.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
// See the LICENSE file in the project root for more information.

using Microsoft.Win32.SafeHandles;

using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;

Expand All @@ -19,6 +17,7 @@ internal partial class SafeCloseSocket :
#endif
{
private ThreadPoolBoundHandle _iocpBoundHandle;
private bool _skipCompletionPortOnSuccess;
private object _iocpBindingLock = new object();

public ThreadPoolBoundHandle IOCPBoundHandle
Expand All @@ -30,7 +29,7 @@ public ThreadPoolBoundHandle IOCPBoundHandle
}

// Binds the Socket Win32 Handle to the ThreadPool's CompletionPort.
public ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle()
public ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle(bool trySkipCompletionPortOnSuccess)
{
if (_released)
{
Expand All @@ -49,26 +48,46 @@ public ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle()
// Bind the socket native _handle to the ThreadPool.
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "calling ThreadPool.BindHandle()");

ThreadPoolBoundHandle boundHandle;
try
{
// The handle (this) may have been already released:
// E.g.: The socket has been disposed in the main thread. A completion callback may
// attempt starting another operation.
_iocpBoundHandle = ThreadPoolBoundHandle.BindHandle(this);
boundHandle = ThreadPoolBoundHandle.BindHandle(this);
}
catch (Exception exception)
{
if (ExceptionCheck.IsFatal(exception)) throw;
CloseAsIs();
throw;
}

// Try to disable completions for synchronous success, if requested
if (trySkipCompletionPortOnSuccess &&
CompletionPortHelper.SkipCompletionPortOnSuccess(boundHandle.Handle))
{
_skipCompletionPortOnSuccess = true;
}

// Don't set this until after we've configured the handle above (if we did)
_iocpBoundHandle = boundHandle;
}
}
}

return _iocpBoundHandle;
}

public bool SkipCompletionPortOnSuccess
{
get
{
Debug.Assert(_iocpBoundHandle != null);
return _skipCompletionPortOnSuccess;
}
}

internal static unsafe SafeCloseSocket CreateWSASocket(byte* pinnedBuffer)
{
return CreateSocket(InnerSafeCloseSocket.CreateWSASocket(pinnedBuffer));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@
<Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Windows.cs">
<Link>Common\System\Net\ContextAwareResult.Windows.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\CompletionPortHelper.Windows.cs">
<Link>Common\System\Net\CompletionPortHelper.Windows.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\LazyAsyncResult.cs">
<Link>Common\System\Net\LazyAsyncResult.cs</Link>
</Compile>
Expand Down Expand Up @@ -197,6 +200,9 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.LocalFree.cs">
<Link>Interop\Windows\kernel32\Interop.LocalFree.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetFileCompletionNotificationModes.cs">
<Link>Interop\Windows\kernel32\Interop.SetFileCompletionNotificationModes.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.accept.cs">
<Link>Interop\Windows\Winsock\Interop.accept.cs</Link>
</Compile>
Expand Down
9 changes: 9 additions & 0 deletions src/System.Net.Sockets/src/System.Net.Sockets.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -282,15 +282,24 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.LocalFree.cs">
<Link>Common\Interop\Windows\kernel32\Interop.LocalFree.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetFileCompletionNotificationModes.cs">
<Link>Interop\Windows\kernel32\Interop.SetFileCompletionNotificationModes.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Windows.cs">
<Link>Common\System\Net\ContextAwareResult.Windows.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\CompletionPortHelper.Windows.cs">
<Link>Common\System\Net\CompletionPortHelper.Windows.cs</Link>
</Compile>
</ItemGroup>
<!-- Windows : Win32 + WinRT -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(EnableWinRT)' == 'true'">
<Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Uap.cs">
<Link>Common\System\Net\ContextAwareResult.Uap.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\CompletionPortHelper.Uap.cs">
<Link>Common\System\Net\CompletionPortHelper.Uap.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="System\Net\Sockets\AcceptOverlappedAsyncResult.Unix.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,10 @@ public BaseOverlappedAsyncResult(Socket socket, Object asyncState, AsyncCallback
if (NetEventSource.IsEnabled) NetEventSource.Info(this, socket);
}

public void CompletionCallback(int numBytes, SocketError errorCode)
protected void CompletionCallback(int numBytes, SocketError errorCode)
{
ErrorCode = (int)errorCode;
InvokeCallback(PostCompletion(numBytes));
}

private void ReleaseUnmanagedStructures()
{
// NOTE: this method needs to exist to conform to the contract expected by the
// platform-independent code in BaseOverlappedAsyncResult.CheckAsyncCallOverlappedResult.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,6 @@ internal BaseOverlappedAsyncResult(Socket socket, Object asyncState, AsyncCallba
if (NetEventSource.IsEnabled) NetEventSource.Info(this, socket);
}

internal SafeNativeOverlapped NativeOverlapped
{
get
{
return _nativeOverlapped;
}
}

// SetUnmanagedStructures
//
// This needs to be called for overlapped IO to function properly.
Expand All @@ -59,14 +51,15 @@ internal void SetUnmanagedStructures(object objectsToPin)
throw new ObjectDisposedException(s.GetType().FullName);
}

ThreadPoolBoundHandle boundHandle = s.SafeHandle.GetOrAllocateThreadPoolBoundHandle();
ThreadPoolBoundHandle boundHandle = s.GetOrAllocateThreadPoolBoundHandle();

unsafe
{
NativeOverlapped* overlapped = boundHandle.AllocateNativeOverlapped(s_ioCallback, this, objectsToPin);
_nativeOverlapped = new SafeNativeOverlapped(s.SafeHandle, overlapped);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"{boundHandle}::AllocateNativeOverlapped. return={_nativeOverlapped}");
}

if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"{boundHandle}::AllocateNativeOverlapped. return={_nativeOverlapped}");
}

private static unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped)
Expand All @@ -78,8 +71,6 @@ private static unsafe void CompletionPortCallback(uint errorCode, uint numBytes,
#endif
BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped);

object returnObject = null;

if (asyncResult.InternalPeekCompleted)
{
NetEventSource.Fail(null, $"asyncResult.IsCompleted: {asyncResult}");
Expand Down Expand Up @@ -115,7 +106,7 @@ private static unsafe void CompletionPortCallback(uint errorCode, uint numBytes,
SocketFlags ignore;
bool success = Interop.Winsock.WSAGetOverlappedResult(
socket.SafeHandle,
asyncResult.NativeOverlapped,
asyncResult._nativeOverlapped,
out numBytes,
false,
out ignore);
Expand All @@ -135,15 +126,23 @@ private static unsafe void CompletionPortCallback(uint errorCode, uint numBytes,
}
}
}
asyncResult.ErrorCode = (int)socketError;
returnObject = asyncResult.PostCompletion((int)numBytes);
asyncResult.ReleaseUnmanagedStructures();
asyncResult.InvokeCallback(returnObject);

// Set results and invoke callback
asyncResult.CompletionCallback((int)numBytes, socketError);
#if DEBUG
}
#endif
}

// Called either synchronously from SocketPal async routines or asynchronously via CompletionPortCallback above.
private void CompletionCallback(int numBytes, SocketError socketError)
{
ReleaseUnmanagedStructures();

ErrorCode = (int)socketError;
InvokeCallback(PostCompletion(numBytes));
}

// The following property returns the Win32 unsafe pointer to
// whichever Overlapped structure we're using for IO.
internal SafeHandle OverlappedHandle
Expand All @@ -157,7 +156,46 @@ internal SafeHandle OverlappedHandle
}
}

private void ReleaseUnmanagedStructures()
// Check the result of the overlapped operation.
// Handle synchronous success by completing the asyncResult here.
// Handle synchronous failure by cleaning up and returning a SocketError.
internal SocketError ProcessOverlappedResult(bool success, int bytesTransferred)
{
if (success)
{
// Synchronous success.
Socket socket = (Socket)AsyncObject;
if (socket.SafeHandle.SkipCompletionPortOnSuccess)
{
// The socket handle is configured to skip completion on success,
// so we can complete this asyncResult right now.
CompletionCallback(bytesTransferred, SocketError.Success);
return SocketError.Success;
}

// Socket handle is going to post a completion to the completion port (may have done so already).
// Return pending and we will continue in the completion port callback.
return SocketError.IOPending;
}

// Get the socket error (which may be IOPending)
SocketError errorCode = SocketPal.GetLastSocketError();

if (errorCode == SocketError.IOPending)
{
// Operation is pending.
// We will continue when the completion arrives (may have already at this point).
return SocketError.IOPending;
}

// Synchronous failure.
// Release overlapped and pinned structures.
ReleaseUnmanagedStructures();

return errorCode;
}

internal void ReleaseUnmanagedStructures()
{
if (Interlocked.Decrement(ref _cleanupCount) == 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,5 @@ internal int InternalWaitForCompletionInt32Result()
base.InternalWaitForCompletion();
return _numBytes;
}

// This method is called after an asynchronous call is made for the user.
// It checks and acts accordingly if the IO:
// 1) completed synchronously.
// 2) was pended.
// 3) failed.
internal unsafe SocketError CheckAsyncCallOverlappedResult(SocketError errorCode)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(this, errorCode);

if (errorCode == SocketError.Success || errorCode == SocketError.IOPending)
{
// Ignore cases in which a completion packet will be queued:
// we'll deal with this IO in the callback.
return SocketError.Success;
}

// In the remaining cases a completion packet will NOT be queued:
// we have to call the callback explicitly signaling an error.
ErrorCode = (int)errorCode;
Result = -1;

ReleaseUnmanagedStructures(); // Additional release for the completion that won't happen.
return errorCode;
}
}
}
Loading