You've already forked linux-packaging-mono
Imported Upstream version 5.10.0.47
Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
This commit is contained in:
parent
88ff76fe28
commit
e46a49ecf1
@ -31,10 +31,10 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
|
||||
{8CBA022C-635F-4C8D-9D29-CD8AAC68C8E6}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
|
||||
{BB5C85AD-C51A-4903-80E9-6F6E1AC1AD34}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU
|
||||
{BB5C85AD-C51A-4903-80E9-6F6E1AC1AD34}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU
|
||||
{BB5C85AD-C51A-4903-80E9-6F6E1AC1AD34}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU
|
||||
|
@ -6,6 +6,5 @@
|
||||
<AssemblyKey>MSFT</AssemblyKey>
|
||||
<IsNETCoreApp>true</IsNETCoreApp>
|
||||
<IsUAP>true</IsUAP>
|
||||
<IsNetFxNETStandard>true</IsNetFxNETStandard>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -4,7 +4,6 @@
|
||||
<BuildConfigurations>
|
||||
netcoreapp;
|
||||
uap;
|
||||
netfx;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -7,14 +7,13 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
|
||||
<ItemGroup>
|
||||
<Compile Include="System.Net.Sockets.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
|
||||
<Compile Include="System.Net.Sockets.netcoreapp.cs" />
|
||||
<ProjectReference Include="..\..\System.IO\ref\System.IO.csproj" />
|
||||
<ProjectReference Include="..\..\System.IO.FileSystem.Primitives\ref\System.IO.FileSystem.Primitives.csproj" />
|
||||
<ProjectReference Include="..\..\System.Net.Primitives\ref\System.Net.Primitives.csproj" />
|
||||
|
32
external/corefx/src/System.Net.Sockets/ref/System.Net.Sockets.netcoreapp.cs
vendored
Normal file
32
external/corefx/src/System.Net.Sockets/ref/System.Net.Sockets.netcoreapp.cs
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// 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.
|
||||
// ------------------------------------------------------------------------------
|
||||
// Changes to this file must follow the http://aka.ms/api-review process.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace System.Net.Sockets
|
||||
{
|
||||
public partial class Socket : System.IDisposable
|
||||
{
|
||||
public int Receive(Span<byte> buffer) { throw null; }
|
||||
public int Receive(Span<byte> buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; }
|
||||
public int Receive(Span<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode) { throw null; }
|
||||
public int Send(ReadOnlySpan<byte> buffer) { throw null; }
|
||||
public int Send(ReadOnlySpan<byte> buffer, System.Net.Sockets.SocketFlags socketFlags) { throw null; }
|
||||
public int Send(ReadOnlySpan<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode) { throw null; }
|
||||
}
|
||||
|
||||
public partial static class SocketTaskExtensions
|
||||
{
|
||||
public static System.Threading.Tasks.ValueTask<int> ReceiveAsync(this System.Net.Sockets.Socket socket, System.Memory<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
|
||||
public static System.Threading.Tasks.ValueTask<int> SendAsync(this System.Net.Sockets.Socket socket, System.ReadOnlyMemory<byte> buffer, System.Net.Sockets.SocketFlags socketFlags, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
|
||||
}
|
||||
|
||||
public partial class SocketAsyncEventArgs : System.EventArgs, System.IDisposable
|
||||
{
|
||||
public System.Memory<byte> GetBuffer() { throw null; }
|
||||
public void SetBuffer(System.Memory<byte> buffer) { throw null; }
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
uap-Windows_NT;
|
||||
netcoreapp-Unix;
|
||||
netcoreapp-Windows_NT;
|
||||
netfx-Windows_NT;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -12,8 +12,6 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
|
||||
<PropertyGroup>
|
||||
@ -401,6 +399,7 @@
|
||||
<Reference Include="System.Net.Primitives" />
|
||||
<Reference Include="System.Resources.ResourceManager" />
|
||||
<Reference Include="System.Runtime" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe" />
|
||||
<Reference Include="System.Runtime.Extensions" />
|
||||
<Reference Include="System.Runtime.InteropServices" />
|
||||
<Reference Include="System.Security.Claims" />
|
||||
@ -417,4 +416,4 @@
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
</Project>
|
@ -305,6 +305,34 @@ namespace System.Net.Sockets
|
||||
#endif
|
||||
}
|
||||
|
||||
public override int Read(Span<byte> destination)
|
||||
{
|
||||
if (GetType() != typeof(NetworkStream))
|
||||
{
|
||||
// NetworkStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior
|
||||
// to this Read(Span<byte>) overload being introduced. In that case, this Read(Span<byte>) overload
|
||||
// should use the behavior of Read(byte[],int,int) overload.
|
||||
return base.Read(destination);
|
||||
}
|
||||
|
||||
if (_cleanedUp) throw new ObjectDisposedException(GetType().FullName);
|
||||
if (!CanRead) throw new InvalidOperationException(SR.net_writeonlystream);
|
||||
|
||||
int bytesRead = _streamSocket.Receive(destination, SocketFlags.None, out SocketError errorCode);
|
||||
if (errorCode != SocketError.Success)
|
||||
{
|
||||
var exception = new SocketException((int)errorCode);
|
||||
throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
public override unsafe int ReadByte()
|
||||
{
|
||||
int b;
|
||||
return Read(new Span<byte>(&b, 1)) == 0 ? -1 : b;
|
||||
}
|
||||
|
||||
// Write - provide core Write functionality.
|
||||
//
|
||||
// Provide core write functionality. All we do is call through to the
|
||||
@ -368,6 +396,31 @@ namespace System.Net.Sockets
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> source)
|
||||
{
|
||||
if (GetType() != typeof(NetworkStream))
|
||||
{
|
||||
// NetworkStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior
|
||||
// to this Write(ReadOnlySpan<byte>) overload being introduced. In that case, this Write(ReadOnlySpan<byte>)
|
||||
// overload should use the behavior of Write(byte[],int,int) overload.
|
||||
base.Write(source);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cleanedUp) throw new ObjectDisposedException(GetType().FullName);
|
||||
if (!CanWrite) throw new InvalidOperationException(SR.net_readonlystream);
|
||||
|
||||
_streamSocket.Send(source, SocketFlags.None, out SocketError errorCode);
|
||||
if (errorCode != SocketError.Success)
|
||||
{
|
||||
var exception = new SocketException((int)errorCode);
|
||||
throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
|
||||
}
|
||||
}
|
||||
|
||||
public override unsafe void WriteByte(byte value) =>
|
||||
Write(new ReadOnlySpan<byte>(&value, 1));
|
||||
|
||||
private int _closeTimeout = Socket.DefaultCloseTimeout; // -1 = respect linger options
|
||||
|
||||
public void Close(int timeout)
|
||||
@ -696,6 +749,34 @@ namespace System.Net.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken)
|
||||
{
|
||||
bool canRead = CanRead; // Prevent race with Dispose.
|
||||
if (_cleanedUp)
|
||||
{
|
||||
throw new ObjectDisposedException(this.GetType().FullName);
|
||||
}
|
||||
if (!canRead)
|
||||
{
|
||||
throw new InvalidOperationException(SR.net_writeonlystream);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return _streamSocket.ReceiveAsync(
|
||||
destination,
|
||||
SocketFlags.None,
|
||||
fromNetworkStream: true,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
catch (Exception exception) when (!(exception is OutOfMemoryException))
|
||||
{
|
||||
// Some sort of error occurred on the socket call,
|
||||
// set the SocketException as InnerException and throw.
|
||||
throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception);
|
||||
}
|
||||
}
|
||||
|
||||
// WriteAsync - provide async write functionality.
|
||||
//
|
||||
// This method provides async write functionality. All we do is
|
||||
@ -757,6 +838,38 @@ namespace System.Net.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
|
||||
{
|
||||
bool canWrite = CanWrite; // Prevent race with Dispose.
|
||||
if (_cleanedUp)
|
||||
{
|
||||
throw new ObjectDisposedException(this.GetType().FullName);
|
||||
}
|
||||
if (!canWrite)
|
||||
{
|
||||
throw new InvalidOperationException(SR.net_readonlystream);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ValueTask<int> t = _streamSocket.SendAsync(
|
||||
source,
|
||||
SocketFlags.None,
|
||||
fromNetworkStream: true,
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return t.IsCompletedSuccessfully ?
|
||||
Task.CompletedTask :
|
||||
t.AsTask();
|
||||
}
|
||||
catch (Exception exception) when (!(exception is OutOfMemoryException))
|
||||
{
|
||||
// Some sort of error occurred on the socket call,
|
||||
// set the SocketException as InnerException and throw.
|
||||
throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception);
|
||||
}
|
||||
}
|
||||
|
||||
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
|
||||
{
|
||||
// Validate arguments as would the base CopyToAsync
|
||||
|
@ -2,6 +2,7 @@
|
||||
// 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.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@ -195,17 +196,72 @@ namespace System.Net.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Implements Task-returning ReceiveAsync on top of Begin/EndReceive.</summary>
|
||||
private Task<int> ReceiveAsyncApm(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
internal ValueTask<int> ReceiveAsync(Memory<byte> buffer, SocketFlags socketFlags, bool fromNetworkStream, CancellationToken cancellationToken)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
BeginReceive(buffer.Array, buffer.Offset, buffer.Count, socketFlags, iar =>
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var innerTcs = (TaskCompletionSource<int>)iar.AsyncState;
|
||||
try { innerTcs.TrySetResult(((Socket)innerTcs.Task.AsyncState).EndReceive(iar)); }
|
||||
catch (Exception e) { innerTcs.TrySetException(e); }
|
||||
}, tcs);
|
||||
return tcs.Task;
|
||||
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
|
||||
}
|
||||
|
||||
// TODO https://github.com/dotnet/corefx/issues/24430:
|
||||
// Fully plumb cancellation down into socket operations.
|
||||
|
||||
Int32TaskSocketAsyncEventArgs saea = RentSocketAsyncEventArgs(isReceive: true);
|
||||
if (saea != null)
|
||||
{
|
||||
// We got a cached instance. Configure the buffer and initate the operation.
|
||||
ConfigureBuffer(saea, buffer, socketFlags, wrapExceptionsInIOExceptions: fromNetworkStream);
|
||||
return GetValueTaskForSendReceive(ReceiveAsync(saea), saea, fromNetworkStream, isReceive: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We couldn't get a cached instance, due to a concurrent receive operation on the socket.
|
||||
// Fall back to wrapping APM.
|
||||
return new ValueTask<int>(ReceiveAsyncApm(buffer, socketFlags));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Implements Task-returning ReceiveAsync on top of Begin/EndReceive.</summary>
|
||||
private Task<int> ReceiveAsyncApm(Memory<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
if (buffer.TryGetArray(out ArraySegment<byte> bufferArray))
|
||||
{
|
||||
// We were able to extract the underlying byte[] from the Memory<byte>. Use it.
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
BeginReceive(bufferArray.Array, bufferArray.Offset, bufferArray.Count, socketFlags, iar =>
|
||||
{
|
||||
var innerTcs = (TaskCompletionSource<int>)iar.AsyncState;
|
||||
try { innerTcs.TrySetResult(((Socket)innerTcs.Task.AsyncState).EndReceive(iar)); }
|
||||
catch (Exception e) { innerTcs.TrySetException(e); }
|
||||
}, tcs);
|
||||
return tcs.Task;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We weren't able to extract an underlying byte[] from the Memory<byte>.
|
||||
// Instead read into an ArrayPool array, then copy from that into the memory.
|
||||
byte[] poolArray = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
BeginReceive(poolArray, 0, buffer.Length, socketFlags, iar =>
|
||||
{
|
||||
var state = (Tuple<TaskCompletionSource<int>, Memory<byte>, byte[]>)iar.AsyncState;
|
||||
try
|
||||
{
|
||||
int bytesCopied = ((Socket)state.Item1.Task.AsyncState).EndReceive(iar);
|
||||
new ReadOnlyMemory<byte>(state.Item3, 0, bytesCopied).Span.CopyTo(state.Item2.Span);
|
||||
state.Item1.TrySetResult(bytesCopied);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
state.Item1.TrySetException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(state.Item3);
|
||||
}
|
||||
}, Tuple.Create(tcs, buffer, poolArray));
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
|
||||
internal Task<int> ReceiveAsync(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
|
||||
@ -304,17 +360,70 @@ namespace System.Net.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Implements Task-returning SendAsync on top of Begin/EndSend.</summary>
|
||||
private Task<int> SendAsyncApm(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
internal ValueTask<int> SendAsync(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, bool fromNetworkStream, CancellationToken cancellationToken)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
BeginSend(buffer.Array, buffer.Offset, buffer.Count, socketFlags, iar =>
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
var innerTcs = (TaskCompletionSource<int>)iar.AsyncState;
|
||||
try { innerTcs.TrySetResult(((Socket)innerTcs.Task.AsyncState).EndSend(iar)); }
|
||||
catch (Exception e) { innerTcs.TrySetException(e); }
|
||||
}, tcs);
|
||||
return tcs.Task;
|
||||
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
|
||||
}
|
||||
|
||||
// TODO https://github.com/dotnet/corefx/issues/24430:
|
||||
// Fully plumb cancellation down into socket operations.
|
||||
|
||||
Int32TaskSocketAsyncEventArgs saea = RentSocketAsyncEventArgs(isReceive: false);
|
||||
if (saea != null)
|
||||
{
|
||||
// We got a cached instance. Configure the buffer and initate the operation.
|
||||
ConfigureBuffer(saea, Unsafe.As<ReadOnlyMemory<byte>,Memory<byte>>(ref buffer), socketFlags, wrapExceptionsInIOExceptions: fromNetworkStream);
|
||||
return GetValueTaskForSendReceive(SendAsync(saea), saea, fromNetworkStream, isReceive: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We couldn't get a cached instance, due to a concurrent send operation on the socket.
|
||||
// Fall back to wrapping APM.
|
||||
return new ValueTask<int>(SendAsyncApm(buffer, socketFlags));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Implements Task-returning SendAsync on top of Begin/EndSend.</summary>
|
||||
private Task<int> SendAsyncApm(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
if (buffer.DangerousTryGetArray(out ArraySegment<byte> bufferArray))
|
||||
{
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
BeginSend(bufferArray.Array, bufferArray.Offset, bufferArray.Count, socketFlags, iar =>
|
||||
{
|
||||
var innerTcs = (TaskCompletionSource<int>)iar.AsyncState;
|
||||
try { innerTcs.TrySetResult(((Socket)innerTcs.Task.AsyncState).EndSend(iar)); }
|
||||
catch (Exception e) { innerTcs.TrySetException(e); }
|
||||
}, tcs);
|
||||
return tcs.Task;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We weren't able to extract an underlying byte[] from the Memory<byte>.
|
||||
// Instead read into an ArrayPool array, then copy from that into the memory.
|
||||
byte[] poolArray = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||
buffer.Span.CopyTo(poolArray);
|
||||
var tcs = new TaskCompletionSource<int>(this);
|
||||
BeginSend(poolArray, 0, buffer.Length, socketFlags, iar =>
|
||||
{
|
||||
var state = (Tuple<TaskCompletionSource<int>, byte[]>)iar.AsyncState;
|
||||
try
|
||||
{
|
||||
state.Item1.TrySetResult(((Socket)state.Item1.Task.AsyncState).EndSend(iar));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
state.Item1.TrySetException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(state.Item2);
|
||||
}
|
||||
}, Tuple.Create(tcs, poolArray));
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
|
||||
internal Task<int> SendAsync(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
|
||||
@ -393,14 +502,14 @@ namespace System.Net.Sockets
|
||||
}
|
||||
|
||||
private static void ConfigureBuffer(
|
||||
Int32TaskSocketAsyncEventArgs saea, ArraySegment<byte> buffer, SocketFlags socketFlags, bool wrapExceptionsInIOExceptions)
|
||||
Int32TaskSocketAsyncEventArgs saea, Memory<byte> buffer, SocketFlags socketFlags, bool wrapExceptionsInIOExceptions)
|
||||
{
|
||||
// Configure the buffer. We don't clear the buffers when returning the SAEA to the pool,
|
||||
// so as to minimize overhead if the same buffer is used for subsequent operations (which is likely).
|
||||
// But SAEA doesn't support having both a buffer and a buffer list configured, so clear out a buffer list
|
||||
// if there is one before we set the desired buffer.
|
||||
if (saea.BufferList != null) saea.BufferList = null;
|
||||
saea.SetBuffer(buffer.Array, buffer.Offset, buffer.Count);
|
||||
saea.SetBuffer(buffer);
|
||||
saea.SocketFlags = socketFlags;
|
||||
saea._wrapExceptionsInIOExceptions = wrapExceptionsInIOExceptions;
|
||||
}
|
||||
@ -486,6 +595,48 @@ namespace System.Net.Sockets
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>Gets a value task to represent the operation.</summary>
|
||||
/// <param name="pending">true if the operation completes asynchronously; false if it completed synchronously.</param>
|
||||
/// <param name="saea">The event args instance used with the operation.</param>
|
||||
/// <param name="fromNetworkStream">
|
||||
/// true if the request is coming from NetworkStream, which has special semantics for
|
||||
/// exceptions and cached tasks; otherwise, false.
|
||||
/// </param>
|
||||
/// <param name="isReceive">true if this is a receive; false if this is a send.</param>
|
||||
private ValueTask<int> GetValueTaskForSendReceive(
|
||||
bool pending, Int32TaskSocketAsyncEventArgs saea,
|
||||
bool fromNetworkStream, bool isReceive)
|
||||
{
|
||||
ValueTask<int> t;
|
||||
|
||||
if (pending)
|
||||
{
|
||||
// The operation is completing asynchronously (it may have already completed).
|
||||
// Get the task for the operation, with appropriate synchronization to coordinate
|
||||
// with the async callback that'll be completing the task.
|
||||
bool responsibleForReturningToPool;
|
||||
t = new ValueTask<int>(saea.GetCompletionResponsibility(out responsibleForReturningToPool).Task);
|
||||
if (responsibleForReturningToPool)
|
||||
{
|
||||
// We're responsible for returning it only if the callback has already been invoked
|
||||
// and gotten what it needs from the SAEA; otherwise, the callback will return it.
|
||||
ReturnSocketAsyncEventArgs(saea, isReceive);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The operation completed synchronously. Return a ValueTask for it.
|
||||
t = saea.SocketError == SocketError.Success ?
|
||||
new ValueTask<int>(saea.BytesTransferred) :
|
||||
new ValueTask<int>(Task.FromException<int>(GetException(saea.SocketError, wrapExceptionsInIOExceptions: fromNetworkStream)));
|
||||
|
||||
// There won't be a callback, and we're done with the SAEA, so return it to the pool.
|
||||
ReturnSocketAsyncEventArgs(saea, isReceive);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>Completes the SocketAsyncEventArg's Task with the result of the send or receive, and returns it to the specified pool.</summary>
|
||||
private static void CompleteAccept(Socket s, TaskSocketAsyncEventArgs<Socket> saea)
|
||||
{
|
||||
|
@ -1 +1 @@
|
||||
c07087cce038e6a59b3d3a584b6fd28bf65a5be4
|
||||
b7edd69b9b150d3c51ac0b5efb82a99dbf85290e
|
File diff suppressed because it is too large
Load Diff
@ -104,6 +104,15 @@ namespace System.Net.Sockets
|
||||
get { return _buffer; }
|
||||
}
|
||||
|
||||
public Memory<byte> GetBuffer()
|
||||
{
|
||||
// TODO https://github.com/dotnet/corefx/issues/24429:
|
||||
// Actually support Memory<byte> natively.
|
||||
return _buffer != null ?
|
||||
new Memory<byte>(_buffer, _offset, _count) :
|
||||
Memory<byte>.Empty;
|
||||
}
|
||||
|
||||
public int Offset
|
||||
{
|
||||
get { return _offset; }
|
||||
@ -283,6 +292,18 @@ namespace System.Net.Sockets
|
||||
SetBufferInternal(_buffer, offset, count);
|
||||
}
|
||||
|
||||
public void SetBuffer(Memory<byte> buffer)
|
||||
{
|
||||
if (!buffer.TryGetArray(out ArraySegment<byte> array))
|
||||
{
|
||||
// TODO https://github.com/dotnet/corefx/issues/24429:
|
||||
// Actually support Memory<byte> natively.
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
SetBuffer(array.Array, array.Offset, array.Count);
|
||||
}
|
||||
|
||||
internal bool HasMultipleBuffers
|
||||
{
|
||||
get { return _bufferList != null; }
|
||||
|
@ -16,7 +16,6 @@ namespace System.Net.Sockets
|
||||
{
|
||||
public const bool SupportsMultipleConnectAttempts = false;
|
||||
private static readonly bool SupportsDualModeIPv4PacketInfo = GetPlatformSupportsDualModeIPv4PacketInfo();
|
||||
private static readonly byte[] s_peekBuffer = new byte[1];
|
||||
|
||||
private static bool GetPlatformSupportsDualModeIPv4PacketInfo()
|
||||
{
|
||||
@ -62,24 +61,19 @@ namespace System.Net.Sockets
|
||||
return SafeCloseSocket.CreateSocket(addressFamily, socketType, protocolType, out socket);
|
||||
}
|
||||
|
||||
private static unsafe int Receive(SafeCloseSocket socket, SocketFlags flags, byte[] buffer, int offset, int count, byte[] socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno)
|
||||
private static unsafe int Receive(SafeCloseSocket socket, SocketFlags flags, Span<byte> buffer, byte[] socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno)
|
||||
{
|
||||
Debug.Assert(socketAddress != null || socketAddressLen == 0, $"Unexpected values: socketAddress={socketAddress}, socketAddressLen={socketAddressLen}");
|
||||
|
||||
long received;
|
||||
|
||||
int sockAddrLen = 0;
|
||||
if (socketAddress != null)
|
||||
{
|
||||
sockAddrLen = socketAddressLen;
|
||||
}
|
||||
int sockAddrLen = socketAddress != null ? socketAddressLen : 0;
|
||||
|
||||
fixed (byte* sockAddr = socketAddress)
|
||||
fixed (byte* b = buffer)
|
||||
fixed (byte* b = &buffer.DangerousGetPinnableReference())
|
||||
{
|
||||
var iov = new Interop.Sys.IOVector {
|
||||
Base = (b == null) ? null : &b[offset],
|
||||
Count = (UIntPtr)count
|
||||
Base = b,
|
||||
Count = (UIntPtr)buffer.Length
|
||||
};
|
||||
|
||||
var messageHeader = new Interop.Sys.MessageHeader {
|
||||
@ -109,27 +103,22 @@ namespace System.Net.Sockets
|
||||
return checked((int)received);
|
||||
}
|
||||
|
||||
private static unsafe int Send(SafeCloseSocket socket, SocketFlags flags, byte[] buffer, ref int offset, ref int count, byte[] socketAddress, int socketAddressLen, out Interop.Error errno)
|
||||
private static unsafe int Send(SafeCloseSocket socket, SocketFlags flags, ReadOnlySpan<byte> buffer, ref int offset, ref int count, byte[] socketAddress, int socketAddressLen, out Interop.Error errno)
|
||||
{
|
||||
int sent;
|
||||
|
||||
int sockAddrLen = 0;
|
||||
if (socketAddress != null)
|
||||
{
|
||||
sockAddrLen = socketAddressLen;
|
||||
}
|
||||
|
||||
fixed (byte* sockAddr = socketAddress)
|
||||
fixed (byte* b = buffer)
|
||||
fixed (byte* b = &buffer.DangerousGetPinnableReference())
|
||||
{
|
||||
var iov = new Interop.Sys.IOVector {
|
||||
var iov = new Interop.Sys.IOVector
|
||||
{
|
||||
Base = &b[offset],
|
||||
Count = (UIntPtr)count
|
||||
};
|
||||
|
||||
var messageHeader = new Interop.Sys.MessageHeader {
|
||||
var messageHeader = new Interop.Sys.MessageHeader
|
||||
{
|
||||
SocketAddress = sockAddr,
|
||||
SocketAddressLen = sockAddrLen,
|
||||
SocketAddressLen = socketAddress != null ? socketAddressLen : 0,
|
||||
IOVectors = &iov,
|
||||
IOVectorCount = 1
|
||||
};
|
||||
@ -150,7 +139,6 @@ namespace System.Net.Sockets
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
offset += sent;
|
||||
count -= sent;
|
||||
return sent;
|
||||
@ -265,8 +253,8 @@ namespace System.Net.Sockets
|
||||
}
|
||||
if (available == 0)
|
||||
{
|
||||
// Always request at least one byte.
|
||||
available = 1;
|
||||
// Don't truncate iovecs.
|
||||
available = int.MaxValue;
|
||||
}
|
||||
|
||||
// Pin buffers and set up iovecs.
|
||||
@ -594,17 +582,16 @@ namespace System.Net.Sockets
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryCompleteReceiveFrom(SafeCloseSocket socket, byte[] buffer, int offset, int count, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode)
|
||||
{
|
||||
return TryCompleteReceiveFrom(socket, buffer, null, offset, count, flags, socketAddress, ref socketAddressLen, out bytesReceived, out receivedFlags, out errorCode);
|
||||
}
|
||||
public static bool TryCompleteReceiveFrom(SafeCloseSocket socket, byte[] buffer, int offset, int count, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode) =>
|
||||
TryCompleteReceiveFrom(socket, new Span<byte>(buffer, offset, count), null, flags, socketAddress, ref socketAddressLen, out bytesReceived, out receivedFlags, out errorCode);
|
||||
|
||||
public static bool TryCompleteReceiveFrom(SafeCloseSocket socket, IList<ArraySegment<byte>> buffers, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode)
|
||||
{
|
||||
return TryCompleteReceiveFrom(socket, null, buffers, 0, 0, flags, socketAddress, ref socketAddressLen, out bytesReceived, out receivedFlags, out errorCode);
|
||||
}
|
||||
public static bool TryCompleteReceiveFrom(SafeCloseSocket socket, Span<byte> buffer, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode) =>
|
||||
TryCompleteReceiveFrom(socket, buffer, null, flags, socketAddress, ref socketAddressLen, out bytesReceived, out receivedFlags, out errorCode);
|
||||
|
||||
public static unsafe bool TryCompleteReceiveFrom(SafeCloseSocket socket, byte[] buffer, IList<ArraySegment<byte>> buffers, int offset, int count, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode)
|
||||
public static bool TryCompleteReceiveFrom(SafeCloseSocket socket, IList<ArraySegment<byte>> buffers, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode) =>
|
||||
TryCompleteReceiveFrom(socket, default(Span<byte>), buffers, flags, socketAddress, ref socketAddressLen, out bytesReceived, out receivedFlags, out errorCode);
|
||||
|
||||
public static unsafe bool TryCompleteReceiveFrom(SafeCloseSocket socket, Span<byte> buffer, IList<ArraySegment<byte>> buffers, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -614,16 +601,16 @@ namespace System.Net.Sockets
|
||||
if (buffers != null)
|
||||
{
|
||||
// Receive into a set of buffers
|
||||
Debug.Assert(buffer == null);
|
||||
received = Receive(socket, flags, buffers, socketAddress, ref socketAddressLen, out receivedFlags, out errno);
|
||||
}
|
||||
else if (count == 0)
|
||||
else if (buffer.Length == 0)
|
||||
{
|
||||
// Special case a receive of 0 bytes into a single buffer. A common pattern is to ReceiveAsync 0 bytes in order
|
||||
// to be asynchronously notified when data is available, without needing to dedicate a buffer. Some platforms (e.g. macOS),
|
||||
// however complete a 0-byte read successfully when data isn't available, as the request can logically be satisfied
|
||||
// synchronously. As such, we treat 0 specially, and perform a 1-byte peek.
|
||||
received = Receive(socket, flags | SocketFlags.Peek, s_peekBuffer, 0, s_peekBuffer.Length, socketAddress, ref socketAddressLen, out receivedFlags, out errno);
|
||||
byte oneBytePeekBuffer;
|
||||
received = Receive(socket, flags | SocketFlags.Peek, new Span<byte>(&oneBytePeekBuffer, 1), socketAddress, ref socketAddressLen, out receivedFlags, out errno);
|
||||
if (received > 0)
|
||||
{
|
||||
// Peeked for 1-byte, but the actual request was for 0.
|
||||
@ -633,7 +620,7 @@ namespace System.Net.Sockets
|
||||
else
|
||||
{
|
||||
// Receive > 0 bytes into a single buffer
|
||||
received = Receive(socket, flags, buffer, offset, count, socketAddress, ref socketAddressLen, out receivedFlags, out errno);
|
||||
received = Receive(socket, flags, buffer, socketAddress, ref socketAddressLen, out receivedFlags, out errno);
|
||||
}
|
||||
|
||||
if (received != -1)
|
||||
@ -713,28 +700,30 @@ namespace System.Net.Sockets
|
||||
return TryCompleteSendTo(socket, buffer, null, ref bufferIndex, ref offset, ref count, flags, socketAddress, socketAddressLen, ref bytesSent, out errorCode);
|
||||
}
|
||||
|
||||
public static bool TryCompleteSendTo(SafeCloseSocket socket, ReadOnlySpan<byte> buffer, SocketFlags flags, byte[] socketAddress, int socketAddressLen, ref int bytesSent, out SocketError errorCode)
|
||||
{
|
||||
int bufferIndex = 0, offset = 0, count = buffer.Length;
|
||||
return TryCompleteSendTo(socket, buffer, null, ref bufferIndex, ref offset, ref count, flags, socketAddress, socketAddressLen, ref bytesSent, out errorCode);
|
||||
}
|
||||
|
||||
public static bool TryCompleteSendTo(SafeCloseSocket socket, IList<ArraySegment<byte>> buffers, ref int bufferIndex, ref int offset, SocketFlags flags, byte[] socketAddress, int socketAddressLen, ref int bytesSent, out SocketError errorCode)
|
||||
{
|
||||
int count = 0;
|
||||
return TryCompleteSendTo(socket, null, buffers, ref bufferIndex, ref offset, ref count, flags, socketAddress, socketAddressLen, ref bytesSent, out errorCode);
|
||||
return TryCompleteSendTo(socket, default(ReadOnlySpan<byte>), buffers, ref bufferIndex, ref offset, ref count, flags, socketAddress, socketAddressLen, ref bytesSent, out errorCode);
|
||||
}
|
||||
|
||||
public static bool TryCompleteSendTo(SafeCloseSocket socket, byte[] buffer, IList<ArraySegment<byte>> buffers, ref int bufferIndex, ref int offset, ref int count, SocketFlags flags, byte[] socketAddress, int socketAddressLen, ref int bytesSent, out SocketError errorCode)
|
||||
public static bool TryCompleteSendTo(SafeCloseSocket socket, ReadOnlySpan<byte> buffer, IList<ArraySegment<byte>> buffers, ref int bufferIndex, ref int offset, ref int count, SocketFlags flags, byte[] socketAddress, int socketAddressLen, ref int bytesSent, out SocketError errorCode)
|
||||
{
|
||||
bool successfulSend = false;
|
||||
for (;;)
|
||||
{
|
||||
int sent;
|
||||
Interop.Error errno;
|
||||
try
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
sent = Send(socket, flags, buffer, ref offset, ref count, socketAddress, socketAddressLen, out errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
sent = Send(socket, flags, buffers, ref bufferIndex, ref offset, socketAddress, socketAddressLen, out errno);
|
||||
}
|
||||
sent = buffers != null ?
|
||||
Send(socket, flags, buffers, ref bufferIndex, ref offset, socketAddress, socketAddressLen, out errno) :
|
||||
Send(socket, flags, buffer, ref offset, ref count, socketAddress, socketAddressLen, out errno);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
@ -745,20 +734,21 @@ namespace System.Net.Sockets
|
||||
|
||||
if (sent == -1)
|
||||
{
|
||||
if (errno != Interop.Error.EAGAIN && errno != Interop.Error.EWOULDBLOCK)
|
||||
if (!successfulSend && errno != Interop.Error.EAGAIN && errno != Interop.Error.EWOULDBLOCK)
|
||||
{
|
||||
errorCode = GetSocketErrorForErrorCode(errno);
|
||||
return true;
|
||||
}
|
||||
|
||||
errorCode = SocketError.Success;
|
||||
errorCode = successfulSend ? SocketError.Success : SocketError.WouldBlock;
|
||||
return false;
|
||||
}
|
||||
|
||||
successfulSend = true;
|
||||
bytesSent += sent;
|
||||
|
||||
bool isComplete = sent == 0 ||
|
||||
(buffer != null && count == 0) ||
|
||||
(buffers == null && count == 0) ||
|
||||
(buffers != null && bufferIndex == buffers.Count);
|
||||
if (isComplete)
|
||||
{
|
||||
@ -902,8 +892,8 @@ namespace System.Net.Sockets
|
||||
int bufferIndex = 0;
|
||||
int offset = 0;
|
||||
SocketError errorCode;
|
||||
bool completed = TryCompleteSendTo(handle, bufferList, ref bufferIndex, ref offset, socketFlags, null, 0, ref bytesTransferred, out errorCode);
|
||||
return completed ? errorCode : SocketError.WouldBlock;
|
||||
TryCompleteSendTo(handle, bufferList, ref bufferIndex, ref offset, socketFlags, null, 0, ref bytesTransferred, out errorCode);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public static SocketError Send(SafeCloseSocket handle, byte[] buffer, int offset, int count, SocketFlags socketFlags, out int bytesTransferred)
|
||||
@ -915,8 +905,21 @@ namespace System.Net.Sockets
|
||||
|
||||
bytesTransferred = 0;
|
||||
SocketError errorCode;
|
||||
bool completed = TryCompleteSendTo(handle, buffer, ref offset, ref count, socketFlags, null, 0, ref bytesTransferred, out errorCode);
|
||||
return completed ? errorCode : SocketError.WouldBlock;
|
||||
TryCompleteSendTo(handle, buffer, ref offset, ref count, socketFlags, null, 0, ref bytesTransferred, out errorCode);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public static SocketError Send(SafeCloseSocket handle, ReadOnlySpan<byte> buffer, SocketFlags socketFlags, out int bytesTransferred)
|
||||
{
|
||||
if (!handle.IsNonBlocking)
|
||||
{
|
||||
return handle.AsyncContext.Send(buffer, socketFlags, handle.SendTimeout, out bytesTransferred);
|
||||
}
|
||||
|
||||
bytesTransferred = 0;
|
||||
SocketError errorCode;
|
||||
TryCompleteSendTo(handle, buffer, socketFlags, null, 0, ref bytesTransferred, out errorCode);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public static SocketError SendFile(SafeCloseSocket handle, FileStream fileStream)
|
||||
@ -947,8 +950,8 @@ namespace System.Net.Sockets
|
||||
|
||||
bytesTransferred = 0;
|
||||
SocketError errorCode;
|
||||
bool completed = TryCompleteSendTo(handle, buffer, ref offset, ref count, socketFlags, socketAddress, socketAddressLen, ref bytesTransferred, out errorCode);
|
||||
return completed ? errorCode : SocketError.WouldBlock;
|
||||
TryCompleteSendTo(handle, buffer, ref offset, ref count, socketFlags, socketAddress, socketAddressLen, ref bytesTransferred, out errorCode);
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public static SocketError Receive(SafeCloseSocket handle, IList<ArraySegment<byte>> buffers, ref SocketFlags socketFlags, out int bytesTransferred)
|
||||
@ -983,6 +986,19 @@ namespace System.Net.Sockets
|
||||
return completed ? errorCode : SocketError.WouldBlock;
|
||||
}
|
||||
|
||||
public static SocketError Receive(SafeCloseSocket handle, Span<byte> buffer, SocketFlags socketFlags, out int bytesTransferred)
|
||||
{
|
||||
if (!handle.IsNonBlocking)
|
||||
{
|
||||
return handle.AsyncContext.Receive(buffer, ref socketFlags, handle.ReceiveTimeout, out bytesTransferred);
|
||||
}
|
||||
|
||||
int socketAddressLen = 0;
|
||||
SocketError errorCode;
|
||||
bool completed = TryCompleteReceiveFrom(handle, buffer, socketFlags, null, ref socketAddressLen, out bytesTransferred, out socketFlags, out errorCode);
|
||||
return completed ? errorCode : SocketError.WouldBlock;
|
||||
}
|
||||
|
||||
public static SocketError ReceiveMessageFrom(Socket socket, SafeCloseSocket handle, byte[] buffer, int offset, int count, ref SocketFlags socketFlags, Internals.SocketAddress socketAddress, out Internals.SocketAddress receiveAddress, out IPPacketInformation ipPacketInformation, out int bytesTransferred)
|
||||
{
|
||||
byte[] socketAddressBuffer = socketAddress.Buffer;
|
||||
@ -1044,15 +1060,17 @@ namespace System.Net.Sockets
|
||||
{
|
||||
if (optionName == SocketOptionName.ReceiveTimeout)
|
||||
{
|
||||
// Note, setting a non-infinite timeout will force the handle into nonblocking mode
|
||||
handle.ReceiveTimeout = optionValue == 0 ? -1 : optionValue;
|
||||
err = Interop.Sys.SetReceiveTimeout(handle, optionValue);
|
||||
return GetErrorAndTrackSetting(handle, optionLevel, optionName, err);
|
||||
handle.TrackOption(optionLevel, optionName);
|
||||
return SocketError.Success;
|
||||
}
|
||||
else if (optionName == SocketOptionName.SendTimeout)
|
||||
{
|
||||
// Note, setting a non-infinite timeout will force the handle into nonblocking mode
|
||||
handle.SendTimeout = optionValue == 0 ? -1 : optionValue;
|
||||
err = Interop.Sys.SetSendTimeout(handle, optionValue);
|
||||
return GetErrorAndTrackSetting(handle, optionLevel, optionName, err);
|
||||
handle.TrackOption(optionLevel, optionName);
|
||||
return SocketError.Success;
|
||||
}
|
||||
}
|
||||
else if (optionLevel == SocketOptionLevel.IP)
|
||||
@ -1114,11 +1132,14 @@ namespace System.Net.Sockets
|
||||
|
||||
IPAddress localAddress = optionValue.LocalAddress ?? IPAddress.Any;
|
||||
|
||||
var opt = new Interop.Sys.IPv4MulticastOption {
|
||||
MulticastAddress = unchecked((uint)optionValue.Group.GetAddress()),
|
||||
LocalAddress = unchecked((uint)localAddress.GetAddress()),
|
||||
#pragma warning disable CS0618 // Address is marked obsolete
|
||||
var opt = new Interop.Sys.IPv4MulticastOption
|
||||
{
|
||||
MulticastAddress = unchecked((uint)optionValue.Group.Address),
|
||||
LocalAddress = unchecked((uint)localAddress.Address),
|
||||
InterfaceIndex = optionValue.InterfaceIndex
|
||||
};
|
||||
#pragma warning restore CS0618
|
||||
|
||||
Interop.Error err = Interop.Sys.SetIPv4MulticastOption(handle, optName, &opt);
|
||||
return GetErrorAndTrackSetting(handle, SocketOptionLevel.IP, optionName, err);
|
||||
|
@ -174,23 +174,15 @@ namespace System.Net.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe SocketError Send(SafeCloseSocket handle, byte[] buffer, int offset, int size, SocketFlags socketFlags, out int bytesTransferred)
|
||||
public static unsafe SocketError Send(SafeCloseSocket handle, byte[] buffer, int offset, int size, SocketFlags socketFlags, out int bytesTransferred) =>
|
||||
Send(handle, new ReadOnlySpan<byte>(buffer, offset, size), socketFlags, out bytesTransferred);
|
||||
|
||||
public static unsafe SocketError Send(SafeCloseSocket handle, ReadOnlySpan<byte> buffer, SocketFlags socketFlags, out int bytesTransferred)
|
||||
{
|
||||
int bytesSent;
|
||||
if (buffer.Length == 0)
|
||||
fixed (byte* bufferPtr = &buffer.DangerousGetPinnableReference())
|
||||
{
|
||||
bytesSent = Interop.Winsock.send(handle.DangerousGetHandle(), null, 0, socketFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed (byte* pinnedBuffer = &buffer[0])
|
||||
{
|
||||
bytesSent = Interop.Winsock.send(
|
||||
handle.DangerousGetHandle(),
|
||||
pinnedBuffer + offset,
|
||||
size,
|
||||
socketFlags);
|
||||
}
|
||||
bytesSent = Interop.Winsock.send(handle.DangerousGetHandle(), bufferPtr, buffer.Length, socketFlags);
|
||||
}
|
||||
|
||||
if (bytesSent == (int)SocketError.SocketError)
|
||||
@ -302,19 +294,15 @@ namespace System.Net.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe SocketError Receive(SafeCloseSocket handle, byte[] buffer, int offset, int size, SocketFlags socketFlags, out int bytesTransferred)
|
||||
public static unsafe SocketError Receive(SafeCloseSocket handle, byte[] buffer, int offset, int size, SocketFlags socketFlags, out int bytesTransferred) =>
|
||||
Receive(handle, new Span<byte>(buffer, offset, size), socketFlags, out bytesTransferred);
|
||||
|
||||
public static unsafe SocketError Receive(SafeCloseSocket handle, Span<byte> buffer, SocketFlags socketFlags, out int bytesTransferred)
|
||||
{
|
||||
int bytesReceived;
|
||||
if (buffer?.Length == 0)
|
||||
fixed (byte* bufferPtr = &buffer.DangerousGetPinnableReference())
|
||||
{
|
||||
bytesReceived = Interop.Winsock.recv(handle.DangerousGetHandle(), null, 0, socketFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed (byte* pinnedBuffer = buffer)
|
||||
{
|
||||
bytesReceived = Interop.Winsock.recv(handle.DangerousGetHandle(), pinnedBuffer + offset, size, socketFlags);
|
||||
}
|
||||
bytesReceived = Interop.Winsock.recv(handle.DangerousGetHandle(), bufferPtr, buffer.Length, socketFlags);
|
||||
}
|
||||
|
||||
if (bytesReceived == (int)SocketError.SocketError)
|
||||
@ -335,13 +323,9 @@ namespace System.Net.Sockets
|
||||
|
||||
public static unsafe IPPacketInformation GetIPPacketInformation(Interop.Winsock.ControlDataIPv6* controlBuffer)
|
||||
{
|
||||
IPAddress address = IPAddress.IPv6None;
|
||||
if (controlBuffer->length != UIntPtr.Zero)
|
||||
{
|
||||
var addressArray = new byte[Interop.Winsock.IPv6AddressLength];
|
||||
Marshal.Copy((IntPtr)(controlBuffer->address), addressArray, 0, Interop.Winsock.IPv6AddressLength);
|
||||
address = new IPAddress(addressArray);
|
||||
}
|
||||
IPAddress address = controlBuffer->length != UIntPtr.Zero ?
|
||||
new IPAddress(new Span<byte>(controlBuffer->address, Interop.Winsock.IPv6AddressLength)) :
|
||||
IPAddress.IPv6None;
|
||||
|
||||
return new IPPacketInformation(address, (int)controlBuffer->index);
|
||||
}
|
||||
@ -503,11 +487,15 @@ namespace System.Net.Sockets
|
||||
{
|
||||
Interop.Winsock.IPMulticastRequest ipmr = new Interop.Winsock.IPMulticastRequest();
|
||||
|
||||
ipmr.MulticastAddress = unchecked((int)optionValue.Group.GetAddress());
|
||||
#pragma warning disable CS0618 // Address is marked obsolete
|
||||
ipmr.MulticastAddress = unchecked((int)optionValue.Group.Address);
|
||||
#pragma warning restore CS0618
|
||||
|
||||
if (optionValue.LocalAddress != null)
|
||||
{
|
||||
ipmr.InterfaceAddress = unchecked((int)optionValue.LocalAddress.GetAddress());
|
||||
#pragma warning disable CS0618 // Address is marked obsolete
|
||||
ipmr.InterfaceAddress = unchecked((int)optionValue.LocalAddress.Address);
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
else
|
||||
{ //this structure works w/ interfaces as well
|
||||
|
@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Net.Sockets
|
||||
@ -25,6 +26,8 @@ namespace System.Net.Sockets
|
||||
|
||||
public static Task<int> ReceiveAsync(this Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags) =>
|
||||
socket.ReceiveAsync(buffer, socketFlags, fromNetworkStream: false);
|
||||
public static ValueTask<int> ReceiveAsync(this Socket socket, Memory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) =>
|
||||
socket.ReceiveAsync(buffer, socketFlags, fromNetworkStream: false, cancellationToken: cancellationToken);
|
||||
public static Task<int> ReceiveAsync(this Socket socket, IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) =>
|
||||
socket.ReceiveAsync(buffers, socketFlags);
|
||||
public static Task<SocketReceiveFromResult> ReceiveFromAsync(this Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags, EndPoint remoteEndPoint) =>
|
||||
@ -34,6 +37,8 @@ namespace System.Net.Sockets
|
||||
|
||||
public static Task<int> SendAsync(this Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags) =>
|
||||
socket.SendAsync(buffer, socketFlags, fromNetworkStream: false);
|
||||
public static ValueTask<int> SendAsync(this Socket socket, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) =>
|
||||
socket.SendAsync(buffer, socketFlags, fromNetworkStream: false, cancellationToken: cancellationToken);
|
||||
public static Task<int> SendAsync(this Socket socket, IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) =>
|
||||
socket.SendAsync(buffers, socketFlags);
|
||||
public static Task<int> SendToAsync(this Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags, EndPoint remoteEP) =>
|
||||
|
286
external/corefx/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs
vendored
Normal file
286
external/corefx/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
// 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.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Net.Sockets.Tests
|
||||
{
|
||||
public abstract class Accept<T> : SocketTestHelperBase<T> where T : SocketHelperBase, new()
|
||||
{
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[MemberData(nameof(Loopbacks))]
|
||||
public async Task Accept_Success(IPAddress listenAt)
|
||||
{
|
||||
using (Socket listen = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = listen.BindToAnonymousPort(listenAt);
|
||||
listen.Listen(1);
|
||||
|
||||
Task<Socket> acceptTask = AcceptAsync(listen);
|
||||
Assert.False(acceptTask.IsCompleted);
|
||||
|
||||
using (Socket client = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
await ConnectAsync(client, new IPEndPoint(listenAt, port));
|
||||
Socket accept = await acceptTask;
|
||||
Assert.NotNull(accept);
|
||||
Assert.True(accept.Connected);
|
||||
Assert.Equal(client.LocalEndPoint, accept.RemoteEndPoint);
|
||||
Assert.Equal(accept.LocalEndPoint, client.RemoteEndPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[InlineData(2)]
|
||||
[InlineData(5)]
|
||||
public async Task Accept_ConcurrentAcceptsBeforeConnects_Success(int numberAccepts)
|
||||
{
|
||||
// The SyncForceNonBlocking implementation currently toggles the listener's Blocking setting
|
||||
// back and force on every Accept, which causes pending sync Accepts to return EWOULDBLOCK.
|
||||
// For now, just skip the test for SyncForceNonBlocking.
|
||||
// TODO: Issue #22885
|
||||
if (typeof(T) == typeof(SocketHelperSyncForceNonBlocking))
|
||||
return;
|
||||
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
||||
listener.Listen(numberAccepts);
|
||||
|
||||
var clients = new Socket[numberAccepts];
|
||||
var servers = new Task<Socket>[numberAccepts];
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < numberAccepts; i++)
|
||||
{
|
||||
clients[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
servers[i] = AcceptAsync(listener);
|
||||
}
|
||||
|
||||
foreach (Socket client in clients)
|
||||
{
|
||||
await ConnectAsync(client, listener.LocalEndPoint);
|
||||
}
|
||||
|
||||
await Task.WhenAll(servers);
|
||||
Assert.All(servers, s => Assert.Equal(TaskStatus.RanToCompletion, s.Status));
|
||||
Assert.All(servers, s => Assert.NotNull(s.Result));
|
||||
Assert.All(servers, s => Assert.True(s.Result.Connected));
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (Socket client in clients)
|
||||
{
|
||||
client?.Dispose();
|
||||
}
|
||||
|
||||
foreach (Task<Socket> server in servers)
|
||||
{
|
||||
if (server?.Status == TaskStatus.RanToCompletion)
|
||||
{
|
||||
server.Result.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[InlineData(2)]
|
||||
[InlineData(5)]
|
||||
public async Task Accept_ConcurrentAcceptsAfterConnects_Success(int numberAccepts)
|
||||
{
|
||||
// The SyncForceNonBlocking implementation currently toggles the listener's Blocking setting
|
||||
// back and force on every Accept, which causes pending sync Accepts to return EWOULDBLOCK.
|
||||
// For now, just skip the test for SyncForceNonBlocking.
|
||||
// TODO: Issue #22885
|
||||
if (typeof(T) == typeof(SocketHelperSyncForceNonBlocking))
|
||||
return;
|
||||
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
||||
listener.Listen(numberAccepts);
|
||||
|
||||
var clients = new Socket[numberAccepts];
|
||||
var clientConnects = new Task[numberAccepts];
|
||||
var servers = new Task<Socket>[numberAccepts];
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < numberAccepts; i++)
|
||||
{
|
||||
clients[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
clientConnects[i] = ConnectAsync(clients[i], listener.LocalEndPoint);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberAccepts; i++)
|
||||
{
|
||||
servers[i] = AcceptAsync(listener);
|
||||
}
|
||||
|
||||
await Task.WhenAll(clientConnects);
|
||||
Assert.All(clientConnects, c => Assert.Equal(TaskStatus.RanToCompletion, c.Status));
|
||||
|
||||
await Task.WhenAll(servers);
|
||||
Assert.All(servers, s => Assert.Equal(TaskStatus.RanToCompletion, s.Status));
|
||||
Assert.All(servers, s => Assert.NotNull(s.Result));
|
||||
Assert.All(servers, s => Assert.True(s.Result.Connected));
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (Socket client in clients)
|
||||
{
|
||||
client?.Dispose();
|
||||
}
|
||||
|
||||
foreach (Task<Socket> server in servers)
|
||||
{
|
||||
if (server?.Status == TaskStatus.RanToCompletion)
|
||||
{
|
||||
server.Result.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[ActiveIssue(17209, TestPlatforms.AnyUnix)]
|
||||
public async Task Accept_WithTargetSocket_Success()
|
||||
{
|
||||
if (!SupportsAcceptIntoExistingSocket)
|
||||
return;
|
||||
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = listener.BindToAnonymousPort(IPAddress.Loopback);
|
||||
listener.Listen(1);
|
||||
|
||||
Task<Socket> acceptTask = AcceptAsync(listener, server);
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
|
||||
Socket accepted = await acceptTask;
|
||||
Assert.Same(server, accepted);
|
||||
Assert.True(accepted.Connected);
|
||||
}
|
||||
}
|
||||
|
||||
[ActiveIssue(22808, TargetFrameworkMonikers.NetFramework)]
|
||||
[ActiveIssue(17209, TestPlatforms.AnyUnix)]
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async Task Accept_WithTargetSocket_ReuseAfterDisconnect_Success(bool reuseSocket)
|
||||
{
|
||||
if (!SupportsAcceptIntoExistingSocket)
|
||||
return;
|
||||
|
||||
// APM mode fails currently. Issue: #22764
|
||||
if (typeof(T) == typeof(SocketHelperApm))
|
||||
return;
|
||||
|
||||
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = listener.BindToAnonymousPort(IPAddress.Loopback);
|
||||
listener.Listen(1);
|
||||
|
||||
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
Task<Socket> acceptTask = AcceptAsync(listener, server);
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
|
||||
Socket accepted = await acceptTask;
|
||||
Assert.Same(server, accepted);
|
||||
Assert.True(accepted.Connected);
|
||||
}
|
||||
|
||||
server.Disconnect(reuseSocket);
|
||||
Assert.False(server.Connected);
|
||||
|
||||
if (reuseSocket)
|
||||
{
|
||||
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
Task<Socket> acceptTask = AcceptAsync(listener, server);
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
|
||||
Socket accepted = await acceptTask;
|
||||
Assert.Same(server, accepted);
|
||||
Assert.True(accepted.Connected);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SocketException se = await Assert.ThrowsAsync<SocketException>(() => AcceptAsync(listener, server));
|
||||
Assert.Equal(SocketError.InvalidArgument, se.SocketErrorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[ActiveIssue(17209, TestPlatforms.AnyUnix)]
|
||||
public void Accept_WithAlreadyBoundTargetSocket_Fails()
|
||||
{
|
||||
if (!SupportsAcceptIntoExistingSocket)
|
||||
return;
|
||||
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = listener.BindToAnonymousPort(IPAddress.Loopback);
|
||||
listener.Listen(1);
|
||||
|
||||
server.BindToAnonymousPort(IPAddress.Loopback);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => { AcceptAsync(listener, server); });
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[ActiveIssue(17209, TestPlatforms.AnyUnix)]
|
||||
public async Task Accept_WithInUseTargetSocket_Fails()
|
||||
{
|
||||
if (!SupportsAcceptIntoExistingSocket)
|
||||
return;
|
||||
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = listener.BindToAnonymousPort(IPAddress.Loopback);
|
||||
listener.Listen(1);
|
||||
|
||||
Task<Socket> acceptTask = AcceptAsync(listener, server);
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
|
||||
Socket accepted = await acceptTask;
|
||||
Assert.Same(server, accepted);
|
||||
Assert.True(accepted.Connected);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => { AcceptAsync(listener, server); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AcceptSync : Accept<SocketHelperArraySync> { }
|
||||
public sealed class AcceptSyncForceNonBlocking : Accept<SocketHelperSyncForceNonBlocking> { }
|
||||
public sealed class AcceptApm : Accept<SocketHelperApm> { }
|
||||
public sealed class AcceptTask : Accept<SocketHelperTask> { }
|
||||
public sealed class AcceptEap : Accept<SocketHelperEap> { }
|
||||
}
|
@ -1,410 +0,0 @@
|
||||
// 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.Net.Test.Common;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace System.Net.Sockets.Tests
|
||||
{
|
||||
public class AcceptAsync
|
||||
{
|
||||
private readonly ITestOutputHelper _log;
|
||||
|
||||
public AcceptAsync(ITestOutputHelper output)
|
||||
{
|
||||
_log = TestLogging.GetInstance();
|
||||
}
|
||||
|
||||
public void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
|
||||
{
|
||||
_log.WriteLine("OnAcceptCompleted event handler");
|
||||
EventWaitHandle handle = (EventWaitHandle)args.UserToken;
|
||||
handle.Set();
|
||||
}
|
||||
public void OnConnectCompleted(object sender, SocketAsyncEventArgs args)
|
||||
{
|
||||
_log.WriteLine("OnConnectCompleted event handler");
|
||||
EventWaitHandle handle = (EventWaitHandle)args.UserToken;
|
||||
handle.Set();
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[Trait("IPv4", "true")]
|
||||
public void AcceptAsync_IpV4_Success()
|
||||
{
|
||||
Assert.True(Capability.IPv4Support());
|
||||
|
||||
AutoResetEvent completed = new AutoResetEvent(false);
|
||||
AutoResetEvent completedClient = new AutoResetEvent(false);
|
||||
|
||||
using (Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = sock.BindToAnonymousPort(IPAddress.Loopback);
|
||||
sock.Listen(1);
|
||||
|
||||
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
|
||||
args.Completed += OnAcceptCompleted;
|
||||
args.UserToken = completed;
|
||||
|
||||
Assert.True(sock.AcceptAsync(args));
|
||||
_log.WriteLine("IPv4 Server: Waiting for clients.");
|
||||
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
SocketAsyncEventArgs argsClient = new SocketAsyncEventArgs();
|
||||
argsClient.RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, port);
|
||||
argsClient.Completed += OnConnectCompleted;
|
||||
argsClient.UserToken = completedClient;
|
||||
client.ConnectAsync(argsClient);
|
||||
|
||||
_log.WriteLine("IPv4 Client: Connecting.");
|
||||
Assert.True(completed.WaitOne(5000), "IPv4: Timed out while waiting for connection");
|
||||
|
||||
Assert.Equal<SocketError>(SocketError.Success, args.SocketError);
|
||||
Assert.NotNull(args.AcceptSocket);
|
||||
Assert.True(args.AcceptSocket.Connected, "IPv4 Accept Socket was not connected");
|
||||
Assert.NotNull(args.AcceptSocket.RemoteEndPoint);
|
||||
Assert.Equal(client.LocalEndPoint, args.AcceptSocket.RemoteEndPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[Trait("IPv6", "true")]
|
||||
public void AcceptAsync_IPv6_Success()
|
||||
{
|
||||
Assert.True(Capability.IPv6Support());
|
||||
|
||||
AutoResetEvent completed = new AutoResetEvent(false);
|
||||
AutoResetEvent completedClient = new AutoResetEvent(false);
|
||||
|
||||
using (Socket sock = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = sock.BindToAnonymousPort(IPAddress.IPv6Loopback);
|
||||
sock.Listen(1);
|
||||
|
||||
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
|
||||
args.Completed += OnAcceptCompleted;
|
||||
args.UserToken = completed;
|
||||
|
||||
Assert.True(sock.AcceptAsync(args));
|
||||
_log.WriteLine("IPv6 Server: Waiting for clients.");
|
||||
|
||||
using (Socket client = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
SocketAsyncEventArgs argsClient = new SocketAsyncEventArgs();
|
||||
argsClient.RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Loopback, port);
|
||||
argsClient.Completed += OnConnectCompleted;
|
||||
argsClient.UserToken = completedClient;
|
||||
client.ConnectAsync(argsClient);
|
||||
|
||||
_log.WriteLine("IPv6 Client: Connecting.");
|
||||
Assert.True(completed.WaitOne(5000), "IPv6: Timed out while waiting for connection");
|
||||
|
||||
Assert.Equal<SocketError>(SocketError.Success, args.SocketError);
|
||||
Assert.NotNull(args.AcceptSocket);
|
||||
Assert.True(args.AcceptSocket.Connected, "IPv6 Accept Socket was not connected");
|
||||
Assert.NotNull(args.AcceptSocket.RemoteEndPoint);
|
||||
Assert.Equal(client.LocalEndPoint, args.AcceptSocket.RemoteEndPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[InlineData(2)]
|
||||
[InlineData(5)]
|
||||
public async Task AcceptAsync_ConcurrentAcceptsBeforeConnects_Success(int numberAccepts)
|
||||
{
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
||||
listener.Listen(numberAccepts);
|
||||
|
||||
var clients = new Socket[numberAccepts];
|
||||
var servers = new Task<Socket>[numberAccepts];
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < numberAccepts; i++)
|
||||
{
|
||||
clients[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
servers[i] = listener.AcceptAsync();
|
||||
}
|
||||
|
||||
foreach (Socket client in clients)
|
||||
{
|
||||
client.Connect(listener.LocalEndPoint);
|
||||
}
|
||||
|
||||
await Task.WhenAll(servers);
|
||||
Assert.All(servers, s => Assert.Equal(TaskStatus.RanToCompletion, s.Status));
|
||||
Assert.All(servers, s => Assert.NotNull(s.Result));
|
||||
Assert.All(servers, s => Assert.True(s.Result.Connected));
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (Socket client in clients)
|
||||
{
|
||||
client?.Dispose();
|
||||
}
|
||||
|
||||
foreach (Task<Socket> server in servers)
|
||||
{
|
||||
if (server?.Status == TaskStatus.RanToCompletion)
|
||||
{
|
||||
server.Result.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[InlineData(2)]
|
||||
[InlineData(5)]
|
||||
public async Task AcceptAsync_ConcurrentAcceptsAfterConnects_Success(int numberAccepts)
|
||||
{
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
|
||||
listener.Listen(numberAccepts);
|
||||
|
||||
var clients = new Socket[numberAccepts];
|
||||
var clientConnects = new Task[numberAccepts];
|
||||
var servers = new Task<Socket>[numberAccepts];
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < numberAccepts; i++)
|
||||
{
|
||||
clients[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
clientConnects[i] = clients[i].ConnectAsync(listener.LocalEndPoint);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberAccepts; i++)
|
||||
{
|
||||
servers[i] = listener.AcceptAsync();
|
||||
}
|
||||
|
||||
await Task.WhenAll(clientConnects);
|
||||
Assert.All(clientConnects, c => Assert.Equal(TaskStatus.RanToCompletion, c.Status));
|
||||
|
||||
await Task.WhenAll(servers);
|
||||
Assert.All(servers, s => Assert.Equal(TaskStatus.RanToCompletion, s.Status));
|
||||
Assert.All(servers, s => Assert.NotNull(s.Result));
|
||||
Assert.All(servers, s => Assert.True(s.Result.Connected));
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (Socket client in clients)
|
||||
{
|
||||
client?.Dispose();
|
||||
}
|
||||
|
||||
foreach (Task<Socket> server in servers)
|
||||
{
|
||||
if (server?.Status == TaskStatus.RanToCompletion)
|
||||
{
|
||||
server.Result.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[PlatformSpecific(TestPlatforms.Windows)] // Unix platforms don't yet support receiving data with AcceptAsync.
|
||||
public void AcceptAsync_WithReceiveBuffer_Success()
|
||||
{
|
||||
Assert.True(Capability.IPv4Support());
|
||||
|
||||
AutoResetEvent accepted = new AutoResetEvent(false);
|
||||
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = server.BindToAnonymousPort(IPAddress.Loopback);
|
||||
server.Listen(1);
|
||||
|
||||
const int acceptBufferOverheadSize = 288; // see https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.acceptasync(v=vs.110).aspx
|
||||
const int acceptBufferDataSize = 256;
|
||||
const int acceptBufferSize = acceptBufferOverheadSize + acceptBufferDataSize;
|
||||
|
||||
byte[] sendBuffer = new byte[acceptBufferDataSize];
|
||||
new Random().NextBytes(sendBuffer);
|
||||
|
||||
SocketAsyncEventArgs acceptArgs = new SocketAsyncEventArgs();
|
||||
acceptArgs.Completed += OnAcceptCompleted;
|
||||
acceptArgs.UserToken = accepted;
|
||||
acceptArgs.SetBuffer(new byte[acceptBufferSize], 0, acceptBufferSize);
|
||||
|
||||
Assert.True(server.AcceptAsync(acceptArgs));
|
||||
_log.WriteLine("IPv4 Server: Waiting for clients.");
|
||||
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
client.Send(sendBuffer);
|
||||
client.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
|
||||
Assert.True(
|
||||
accepted.WaitOne(TestSettings.PassingTestTimeout), "Test completed in alotted time");
|
||||
|
||||
Assert.Equal(
|
||||
SocketError.Success, acceptArgs.SocketError);
|
||||
|
||||
Assert.Equal(
|
||||
acceptBufferDataSize, acceptArgs.BytesTransferred);
|
||||
|
||||
Assert.Equal(
|
||||
new ArraySegment<byte>(sendBuffer),
|
||||
new ArraySegment<byte>(acceptArgs.Buffer, 0, acceptArgs.BytesTransferred));
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[PlatformSpecific(TestPlatforms.Windows)] // Unix platforms don't yet support receiving data with AcceptAsync.
|
||||
public void AcceptAsync_WithTooSmallReceiveBuffer_Failure()
|
||||
{
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = server.BindToAnonymousPort(IPAddress.Loopback);
|
||||
server.Listen(1);
|
||||
|
||||
SocketAsyncEventArgs acceptArgs = new SocketAsyncEventArgs();
|
||||
acceptArgs.Completed += OnAcceptCompleted;
|
||||
acceptArgs.UserToken = new ManualResetEvent(false);
|
||||
|
||||
byte[] buffer = new byte[1];
|
||||
acceptArgs.SetBuffer(buffer, 0, buffer.Length);
|
||||
|
||||
AssertExtensions.Throws<ArgumentException>(null, () => server.AcceptAsync(acceptArgs));
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[ActiveIssue(17209, TestPlatforms.AnyUnix)]
|
||||
public void AcceptAsync_WithTargetSocket_Success()
|
||||
{
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = listener.BindToAnonymousPort(IPAddress.Loopback);
|
||||
listener.Listen(1);
|
||||
|
||||
Task<Socket> acceptTask = listener.AcceptAsync(server);
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
Assert.Same(server, acceptTask.Result);
|
||||
}
|
||||
}
|
||||
|
||||
[ActiveIssue(17209, TestPlatforms.AnyUnix)]
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void AcceptAsync_WithTargetSocket_ReuseAfterDisconnect_Success(bool reuseSocket)
|
||||
{
|
||||
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (var saea = new SocketAsyncEventArgs())
|
||||
{
|
||||
int port = listener.BindToAnonymousPort(IPAddress.Loopback);
|
||||
listener.Listen(1);
|
||||
|
||||
var are = new AutoResetEvent(false);
|
||||
saea.Completed += delegate { are.Set(); };
|
||||
saea.AcceptSocket = server;
|
||||
|
||||
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
Assert.True(listener.AcceptAsync(saea));
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
are.WaitOne();
|
||||
Assert.Same(server, saea.AcceptSocket);
|
||||
Assert.True(server.Connected);
|
||||
}
|
||||
|
||||
server.Disconnect(reuseSocket);
|
||||
Assert.False(server.Connected);
|
||||
|
||||
if (reuseSocket)
|
||||
{
|
||||
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
Assert.True(listener.AcceptAsync(saea));
|
||||
client.Connect(IPAddress.Loopback, port);
|
||||
are.WaitOne();
|
||||
Assert.Same(server, saea.AcceptSocket);
|
||||
Assert.True(server.Connected);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (listener.AcceptAsync(saea))
|
||||
{
|
||||
are.WaitOne();
|
||||
}
|
||||
Assert.Equal(SocketError.InvalidArgument, saea.SocketError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[ActiveIssue(17209, TestPlatforms.AnyUnix)]
|
||||
public void AcceptAsync_WithAlreadyBoundTargetSocket_Failed()
|
||||
{
|
||||
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = listener.BindToAnonymousPort(IPAddress.Loopback);
|
||||
listener.Listen(1);
|
||||
|
||||
server.BindToAnonymousPort(IPAddress.Loopback);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => { listener.AcceptAsync(server); });
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[PlatformSpecific(TestPlatforms.AnyUnix)] // Unix platforms don't yet support receiving data with AcceptAsync.
|
||||
public void AcceptAsync_WithReceiveBuffer_Failure()
|
||||
{
|
||||
//
|
||||
// Unix platforms don't yet support receiving data with AcceptAsync.
|
||||
//
|
||||
|
||||
Assert.True(Capability.IPv4Support());
|
||||
|
||||
using (Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
int port = server.BindToAnonymousPort(IPAddress.Loopback);
|
||||
server.Listen(1);
|
||||
|
||||
SocketAsyncEventArgs acceptArgs = new SocketAsyncEventArgs();
|
||||
acceptArgs.Completed += OnAcceptCompleted;
|
||||
acceptArgs.UserToken = new ManualResetEvent(false);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
acceptArgs.SetBuffer(buffer, 0, buffer.Length);
|
||||
|
||||
Assert.Throws<PlatformNotSupportedException>(() => server.AcceptAsync(acceptArgs));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -254,7 +254,7 @@ namespace System.Net.Sockets.Tests
|
||||
public void Send_Buffers_NullBuffers_Throws_ArgumentNull()
|
||||
{
|
||||
SocketError errorCode;
|
||||
Assert.Throws<ArgumentNullException>(() => GetSocket().Send(null, SocketFlags.None, out errorCode));
|
||||
Assert.Throws<ArgumentNullException>(() => GetSocket().Send((IList<ArraySegment<byte>>)null, SocketFlags.None, out errorCode));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -321,7 +321,7 @@ namespace System.Net.Sockets.Tests
|
||||
public void Receive_Buffers_NullBuffers_Throws_ArgumentNull()
|
||||
{
|
||||
SocketError errorCode;
|
||||
Assert.Throws<ArgumentNullException>(() => GetSocket().Receive(null, SocketFlags.None, out errorCode));
|
||||
Assert.Throws<ArgumentNullException>(() => GetSocket().Receive((IList<ArraySegment<byte>>)null, SocketFlags.None, out errorCode));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<BuildConfigurations>
|
||||
netstandard;
|
||||
netcoreapp;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
94
external/corefx/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs
vendored
Normal file
94
external/corefx/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
// 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.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Net.Sockets.Tests
|
||||
{
|
||||
public abstract class Connect<T> : SocketTestHelperBase<T> where T : SocketHelperBase, new()
|
||||
{
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[MemberData(nameof(Loopbacks))]
|
||||
public void Connect_Success(IPAddress listenAt)
|
||||
{
|
||||
int port;
|
||||
using (SocketTestServer.SocketTestServerFactory(SocketImplementationType.Async, listenAt, out port))
|
||||
{
|
||||
using (Socket client = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
Task connectTask = ConnectAsync(client, new IPEndPoint(listenAt, port));
|
||||
Assert.True(connectTask.Wait(TestSettings.PassingTestTimeout), "IPv4: Timed out while waiting for connection");
|
||||
Assert.True(client.Connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Theory]
|
||||
[MemberData(nameof(Loopbacks))]
|
||||
public void Connect_MultipleIPAddresses_Success(IPAddress listenAt)
|
||||
{
|
||||
if (!SupportsMultiConnect)
|
||||
return;
|
||||
|
||||
int port;
|
||||
using (SocketTestServer.SocketTestServerFactory(SocketImplementationType.Async, listenAt, out port))
|
||||
using (Socket client = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
Task connectTask = MultiConnectAsync(client, new IPAddress[] { IPAddress.Loopback, IPAddress.IPv6Loopback }, port);
|
||||
Assert.True(connectTask.Wait(TestSettings.PassingTestTimeout), "Timed out while waiting for connection");
|
||||
Assert.True(client.Connected);
|
||||
}
|
||||
}
|
||||
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
[ActiveIssue(22765, TestPlatforms.AnyUnix)]
|
||||
public async Task Connect_OnConnectedSocket_Fails()
|
||||
{
|
||||
int port;
|
||||
using (SocketTestServer.SocketTestServerFactory(SocketImplementationType.Async, IPAddress.Loopback, out port))
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
await ConnectAsync(client, new IPEndPoint(IPAddress.Loopback, port));
|
||||
|
||||
// In the sync case, we throw a derived exception here, so need to use ThrowsAnyAsync
|
||||
SocketException se = await Assert.ThrowsAnyAsync<SocketException>(() => ConnectAsync(client, new IPEndPoint(IPAddress.Loopback, port)));
|
||||
Assert.Equal(SocketError.IsConnected, se.SocketErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
[PlatformSpecific(TestPlatforms.Windows)] // Unix currently does not support Disconnect
|
||||
[OuterLoop] // TODO: Issue #11345
|
||||
[Fact]
|
||||
public async Task Connect_AfterDisconnect_Fails()
|
||||
{
|
||||
int port;
|
||||
using (SocketTestServer.SocketTestServerFactory(SocketImplementationType.Async, IPAddress.Loopback, out port))
|
||||
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||
{
|
||||
await ConnectAsync(client, new IPEndPoint(IPAddress.Loopback, port));
|
||||
client.Disconnect(reuseSocket: false);
|
||||
|
||||
if (ConnectAfterDisconnectResultsInInvalidOperationException)
|
||||
{
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => ConnectAsync(client, new IPEndPoint(IPAddress.Loopback, port)));
|
||||
}
|
||||
else
|
||||
{
|
||||
SocketException se = await Assert.ThrowsAsync<SocketException>(() => ConnectAsync(client, new IPEndPoint(IPAddress.Loopback, port)));
|
||||
Assert.Equal(SocketError.IsConnected, se.SocketErrorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ConnectSync : Connect<SocketHelperArraySync> { }
|
||||
public sealed class ConnectSyncForceNonBlocking : Connect<SocketHelperSyncForceNonBlocking> { }
|
||||
public sealed class ConnectApm : Connect<SocketHelperApm> { }
|
||||
public sealed class ConnectTask : Connect<SocketHelperTask> { }
|
||||
public sealed class ConnectEap : Connect<SocketHelperEap> { }
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user