Imported Upstream version 5.16.0.100

Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-08-07 15:19:03 +00:00
parent 0a9828183b
commit 7d7f676260
4419 changed files with 170950 additions and 90273 deletions

View File

@ -238,4 +238,10 @@
<data name="InvalidOperation_BufferNotExplicitArray" xml:space="preserve">
<value>This operation may only be performed when the buffer was set using the SetBuffer overload that accepts an array.</value>
</data>
<data name="InvalidOperation_IncorrectToken" xml:space="preserve">
<value>The result of the operation was already consumed and may not be used again.</value>
</data>
<data name="InvalidOperation_MultipleContinuations" xml:space="preserve">
<value>Another continuation was already registered.</value>
</data>
</root>

View File

@ -7,6 +7,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
<OmitResources Condition="'$(TargetGroup)' == 'netfx'">true</OmitResources>
<ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@ -62,6 +63,7 @@
<Compile Include="System\Net\Sockets\MultipleConnectAsync.cs" />
<Compile Include="System\Net\Sockets\OverlappedAsyncResult.cs" />
<Compile Include="System\Net\Sockets\ReceiveMessageOverlappedAsyncResult.cs" />
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.cs" />
<Compile Include="$(CommonPath)\System\IO\StreamHelpers.CopyValidation.cs">
<Link>Common\System\IO\StreamHelpers.CopyValidation.cs</Link>
</Compile>
@ -411,6 +413,7 @@
<Reference Include="System.Threading" />
<Reference Include="System.Threading.Overlapped" />
<Reference Include="System.Threading.Tasks" />
<Reference Include="System.Threading.ThreadPool" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<Reference Include="System.Threading.ThreadPool" />

View File

@ -5,6 +5,7 @@
using System.Diagnostics.Tracing;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Net
{
@ -106,7 +107,7 @@ namespace System.Net
}
buffer = buffer.Slice(offset, Math.Min(count, MaxDumpSize));
byte[] slice = buffer.TryGetArray(out ArraySegment<byte> arraySegment) && arraySegment.Offset == 0 && arraySegment.Count == buffer.Length ?
byte[] slice = MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> arraySegment) && arraySegment.Offset == 0 && arraySegment.Count == buffer.Length ?
arraySegment.Array :
buffer.ToArray();

View File

@ -204,7 +204,7 @@ namespace System.Net.Sockets
#endif
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
// Ask the socket how many bytes are available. If it's
@ -269,7 +269,7 @@ namespace System.Net.Sockets
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@ -281,11 +281,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0 || offset > buffer.Length)
if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (size < 0 || size > buffer.Length - offset)
if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@ -329,7 +329,7 @@ namespace System.Net.Sockets
public override unsafe int ReadByte()
{
int b;
byte b;
return Read(new Span<byte>(&b, 1)) == 0 ? -1 : b;
}
@ -358,7 +358,7 @@ namespace System.Net.Sockets
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@ -370,11 +370,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0 || offset > buffer.Length)
if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (size < 0 || size > buffer.Length - offset)
if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@ -504,7 +504,7 @@ namespace System.Net.Sockets
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@ -516,11 +516,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0 || offset > buffer.Length)
if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (size < 0 || size > buffer.Length - offset)
if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@ -562,7 +562,7 @@ namespace System.Net.Sockets
#endif
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
// Validate input parameters.
@ -609,7 +609,7 @@ namespace System.Net.Sockets
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@ -621,11 +621,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0 || offset > buffer.Length)
if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (size < 0 || size > buffer.Length - offset)
if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@ -664,7 +664,7 @@ namespace System.Net.Sockets
#endif
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
// Validate input parameters.
@ -708,7 +708,7 @@ namespace System.Net.Sockets
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@ -720,26 +720,22 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0 || offset > buffer.Length)
if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (size < 0 || size > buffer.Length - offset)
if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<int>(cancellationToken);
}
try
{
return _streamSocket.ReceiveAsync(
new ArraySegment<byte>(buffer, offset, size),
new Memory<byte>(buffer, offset, size),
SocketFlags.None,
fromNetworkStream: true);
fromNetworkStream: true,
cancellationToken).AsTask();
}
catch (Exception exception) when (!(exception is OutOfMemoryException))
{
@ -749,12 +745,12 @@ namespace System.Net.Sockets
}
}
public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken)
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
{
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@ -764,7 +760,7 @@ namespace System.Net.Sockets
try
{
return _streamSocket.ReceiveAsync(
destination,
buffer,
SocketFlags.None,
fromNetworkStream: true,
cancellationToken: cancellationToken);
@ -797,7 +793,7 @@ namespace System.Net.Sockets
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@ -809,26 +805,21 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0 || offset > buffer.Length)
if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (size < 0 || size > buffer.Length - offset)
if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled(cancellationToken);
}
try
{
return _streamSocket.SendAsync(
new ArraySegment<byte>(buffer, offset, size),
return _streamSocket.SendAsyncForNetworkStream(
new ReadOnlyMemory<byte>(buffer, offset, size),
SocketFlags.None,
fromNetworkStream: true);
cancellationToken).AsTask();
}
catch (Exception exception) when (!(exception is OutOfMemoryException))
{
@ -838,12 +829,12 @@ namespace System.Net.Sockets
}
}
public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
throw new ObjectDisposedException(this.GetType().FullName);
throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@ -852,15 +843,10 @@ namespace System.Net.Sockets
try
{
ValueTask<int> t = _streamSocket.SendAsync(
source,
return _streamSocket.SendAsyncForNetworkStream(
buffer,
SocketFlags.None,
fromNetworkStream: true,
cancellationToken: cancellationToken);
return t.IsCompletedSuccessfully ?
Task.CompletedTask :
t.AsTask();
}
catch (Exception exception) when (!(exception is OutOfMemoryException))
{
@ -870,50 +856,6 @@ namespace System.Net.Sockets
}
}
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
// Validate arguments as would the base CopyToAsync
StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize);
// And bail early if cancellation has already been requested
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled(cancellationToken);
}
// Do the copy. We get a copy buffer from the shared pool, and we pass both it and the
// socket into the copy as part of the event args so as to avoid additional fields in
// the async method's state machine.
return CopyToAsyncCore(
destination,
new AwaitableSocketAsyncEventArgs(_streamSocket, ArrayPool<byte>.Shared.Rent(bufferSize)),
cancellationToken);
}
private static async Task CopyToAsyncCore(Stream destination, AwaitableSocketAsyncEventArgs ea, CancellationToken cancellationToken)
{
try
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
int bytesRead = await ea.ReceiveAsync();
if (bytesRead == 0)
{
break;
}
await destination.WriteAsync(ea.Buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
}
}
finally
{
ArrayPool<byte>.Shared.Return(ea.Buffer, clearArray: true);
ea.Dispose();
}
}
// Flushes data from the stream. This is meaningless for us, so it does nothing.
public override void Flush()
{
@ -959,115 +901,5 @@ namespace System.Net.Sockets
}
}
}
/// <summary>A SocketAsyncEventArgs that can be awaited to get the result of an operation.</summary>
internal sealed class AwaitableSocketAsyncEventArgs : SocketAsyncEventArgs, ICriticalNotifyCompletion
{
/// <summary>Sentinel object used to indicate that the operation has completed prior to OnCompleted being called.</summary>
private static readonly Action s_completedSentinel = () => { };
/// <summary>
/// null if the operation has not completed, <see cref="s_completedSentinel"/> if it has, and another object
/// if OnCompleted was called before the operation could complete, in which case it's the delegate to invoke
/// when the operation does complete.
/// </summary>
private Action _continuation;
/// <summary>Initializes the event args.</summary>
/// <param name="socket">The associated socket.</param>
/// <param name="buffer">The buffer to use for all operations.</param>
public AwaitableSocketAsyncEventArgs(Socket socket, byte[] buffer)
{
Debug.Assert(socket != null);
Debug.Assert(buffer != null && buffer.Length > 0);
// Store the socket into the base's UserToken. This avoids the need for an extra field, at the expense
// of an object=>Socket cast when we need to access it, which is only once per operation.
UserToken = socket;
// Store the buffer for use by all operations with this instance.
SetBuffer(buffer, 0, buffer.Length);
// Hook up the completed event.
Completed += delegate
{
// When the operation completes, see if OnCompleted was already called to hook up a continuation.
// If it was, invoke the continuation.
Action c = _continuation;
if (c != null)
{
c();
}
else
{
// We may be racing with OnCompleted, so check with synchronization, trying to swap in our
// completion sentinel. If we lose the race and OnCompleted did hook up a continuation,
// invoke it. Otherwise, there's nothing more to be done.
Interlocked.CompareExchange(ref _continuation, s_completedSentinel, null)?.Invoke();
}
};
}
/// <summary>Initiates a receive operation on the associated socket.</summary>
/// <returns>This instance.</returns>
public AwaitableSocketAsyncEventArgs ReceiveAsync()
{
if (!Socket.ReceiveAsync(this))
{
_continuation = s_completedSentinel;
}
return this;
}
/// <summary>Gets this instance.</summary>
public AwaitableSocketAsyncEventArgs GetAwaiter() => this;
/// <summary>Gets whether the operation has already completed.</summary>
/// <remarks>
/// This is not a generically usable IsCompleted operation that suggests the whole operation has completed.
/// Rather, it's specifically used as part of the await pattern, and is only usable to determine whether the
/// operation has completed by the time the instance is awaited.
/// </remarks>
public bool IsCompleted => _continuation != null;
/// <summary>Same as <see cref="OnCompleted(Action)"/> </summary>
public void UnsafeOnCompleted(Action continuation) => OnCompleted(continuation);
/// <summary>Queues the provided continuation to be executed once the operation has completed.</summary>
public void OnCompleted(Action continuation)
{
if (ReferenceEquals(_continuation, s_completedSentinel) ||
ReferenceEquals(Interlocked.CompareExchange(ref _continuation, continuation, null), s_completedSentinel))
{
Task.Run(continuation);
}
}
/// <summary>Gets the result of the completion operation.</summary>
/// <returns>Number of bytes transferred.</returns>
/// <remarks>
/// Unlike Task's awaiter's GetResult, this does not block until the operation completes: it must only
/// be used once the operation has completed. This is handled implicitly by await.
/// </remarks>
public int GetResult()
{
_continuation = null;
if (SocketError != SocketError.Success)
{
ThrowIOSocketException();
}
return BytesTransferred;
}
/// <summary>Gets the associated socket.</summary>
internal Socket Socket => (Socket)UserToken; // stored in the base's UserToken to avoid an extra field in the object
/// <summary>Throws an IOException wrapping a SocketException using the current <see cref="SocketError"/>.</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
private void ThrowIOSocketException()
{
var se = new SocketException((int)SocketError);
throw new IOException(SR.Format(SR.net_io_readfailure, se.Message), se);
}
}
}
}

View File

@ -5,8 +5,7 @@
using Microsoft.Win32.SafeHandles;
using System.Collections;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Net.Sockets
@ -285,10 +284,14 @@ namespace System.Net.Sockets
}
internal ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle()
internal ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle() =>
_handle.GetThreadPoolBoundHandle() ??
GetOrAllocateThreadPoolBoundHandleSlow();
[MethodImpl(MethodImplOptions.NoInlining)]
internal ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandleSlow()
{
// There is a known bug that exists through Windows 7 with UDP and
// SetFileCompletionNotificationModes.
// There is a known bug that exists through Windows 7 with UDP and SetFileCompletionNotificationModes.
// So, don't try to enable skipping the completion port on success in this case.
bool trySkipCompletionPortOnSuccess = !(CompletionPortHelper.PlatformHasUdpIssue && _protocolType == ProtocolType.Udp);
return _handle.GetOrAllocateThreadPoolBoundHandle(trySkipCompletionPortOnSuccess);

View File

@ -1 +1 @@
10bd970a50210617dd5f2e7f0b1355084b3ba7a2
fa85ae8d57cb300ecf620af894910a21f5984eb7

View File

@ -286,11 +286,21 @@ namespace System.Net.Sockets
//
// Start the event loop on its own thread.
//
Task.Factory.StartNew(
EventLoop,
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
bool suppressFlow = !ExecutionContext.IsFlowSuppressed();
try
{
if (suppressFlow) ExecutionContext.SuppressFlow();
Task.Factory.StartNew(
s => ((SocketAsyncEngine)s).EventLoop(),
this,
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
finally
{
if (suppressFlow) ExecutionContext.RestoreFlow();
}
}
catch
{

View File

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace System.Net.Sockets
@ -70,6 +71,7 @@ namespace System.Net.Sockets
internal Internals.SocketAddress _socketAddress;
// Misc state variables.
private readonly bool _flowExecutionContext;
private ExecutionContext _context;
private static readonly ContextCallback s_executionCallback = ExecutionCallback;
private Socket _currentSocket;
@ -84,8 +86,18 @@ namespace System.Net.Sockets
private MultipleConnectAsync _multipleConnect;
public SocketAsyncEventArgs()
public SocketAsyncEventArgs() : this(flowExecutionContext: true)
{
}
/// <summary>Initialize the SocketAsyncEventArgs</summary>
/// <param name="flowExecutionContext">
/// Whether to capture and flow ExecutionContext. ExecutionContext flow should only
/// be disabled if it's going to be handled by higher layers.
/// </param>
internal SocketAsyncEventArgs(bool flowExecutionContext)
{
_flowExecutionContext = flowExecutionContext;
InitializeInternals();
}
@ -106,7 +118,7 @@ namespace System.Net.Sockets
{
if (_bufferIsExplicitArray)
{
bool success = _buffer.TryGetArray(out ArraySegment<byte> arraySegment);
bool success = MemoryMarshal.TryGetArray(_buffer, out ArraySegment<byte> arraySegment);
Debug.Assert(success);
return arraySegment.Array;
}
@ -519,13 +531,17 @@ namespace System.Net.Sockets
_context = null;
}
// Capture execution context if none already.
if (_context == null)
// Capture execution context if necessary.
if (_flowExecutionContext && _context == null)
{
_context = ExecutionContext.Capture();
}
StartOperationCommonCore();
}
partial void StartOperationCommonCore();
internal void StartOperationAccept()
{
// AcceptEx needs a single buffer that's the size of two native sockaddr buffers with 16

View File

@ -47,7 +47,7 @@ namespace System.Net.Sockets
return default(IPPacketInformation);
}
Interop.Sys.IPPacketInformation nativePacketInfo;
Interop.Sys.IPPacketInformation nativePacketInfo = default;
if (!Interop.Sys.TryGetIPPacketInformation(messageHeader, isIPv4, &nativePacketInfo))
{
return default(IPPacketInformation);
@ -65,7 +65,7 @@ namespace System.Net.Sockets
{
Debug.Assert(socketAddress != null || socketAddressLen == 0, $"Unexpected values: socketAddress={socketAddress}, socketAddressLen={socketAddressLen}");
long received;
long received = 0;
int sockAddrLen = socketAddress != null ? socketAddressLen : 0;
fixed (byte* sockAddr = socketAddress)
@ -123,7 +123,7 @@ namespace System.Net.Sockets
IOVectorCount = 1
};
long bytesSent;
long bytesSent = 0;
errno = Interop.Sys.SendMessage(
socket.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
&messageHeader,
@ -186,7 +186,7 @@ namespace System.Net.Sockets
IOVectorCount = iovCount
};
long bytesSent;
long bytesSent = 0;
errno = Interop.Sys.SendMessage(
socket.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
&messageHeader,
@ -244,7 +244,7 @@ namespace System.Net.Sockets
private static unsafe int Receive(SafeCloseSocket socket, SocketFlags flags, IList<ArraySegment<byte>> buffers, byte[] socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno)
{
int available;
int available = 0;
errno = Interop.Sys.GetBytesAvailable(socket, &available);
if (errno != Interop.Error.SUCCESS)
{
@ -353,7 +353,7 @@ namespace System.Net.Sockets
Interop.Sys.MessageHeader messageHeader;
long received;
long received = 0;
fixed (byte* rawSocketAddress = socketAddress)
fixed (byte* b = &MemoryMarshal.GetReference(buffer))
{
@ -432,7 +432,7 @@ namespace System.Net.Sockets
ControlBufferLen = cmsgBufferLen
};
long received;
long received = 0;
errno = Interop.Sys.ReceiveMessage(
socket.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
&messageHeader,
@ -470,7 +470,7 @@ namespace System.Net.Sockets
public static unsafe bool TryCompleteAccept(SafeCloseSocket socket, byte[] socketAddress, ref int socketAddressLen, out IntPtr acceptedFd, out SocketError errorCode)
{
IntPtr fd;
IntPtr fd = IntPtr.Zero;
Interop.Error errno;
int sockAddrLen = socketAddressLen;
fixed (byte* rawSocketAddress = socketAddress)
@ -545,7 +545,7 @@ namespace System.Net.Sockets
public static unsafe bool TryCompleteConnect(SafeCloseSocket socket, int socketAddressLen, out SocketError errorCode)
{
Interop.Error socketError;
Interop.Error socketError = default;
Interop.Error err;
try
{
@ -864,7 +864,7 @@ namespace System.Net.Sockets
{
if (!handle.IsNonBlocking)
{
return handle.AsyncContext.Connect(socketAddress, socketAddressLen, -1);
return handle.AsyncContext.Connect(socketAddress, socketAddressLen);
}
SocketError errorCode;
@ -1097,17 +1097,15 @@ 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;
handle.TrackOption(optionLevel, optionName);
return SocketError.Success;
err = Interop.Sys.SetReceiveTimeout(handle, optionValue);
return GetErrorAndTrackSetting(handle, optionLevel, optionName, err);
}
else if (optionName == SocketOptionName.SendTimeout)
{
// Note, setting a non-infinite timeout will force the handle into nonblocking mode
handle.SendTimeout = optionValue == 0 ? -1 : optionValue;
handle.TrackOption(optionLevel, optionName);
return SocketError.Success;
err = Interop.Sys.SetSendTimeout(handle, optionValue);
return GetErrorAndTrackSetting(handle, optionLevel, optionName, err);
}
}
else if (optionLevel == SocketOptionLevel.IP)
@ -1307,7 +1305,7 @@ namespace System.Net.Sockets
Interop.Sys.MulticastOption.MULTICAST_ADD :
Interop.Sys.MulticastOption.MULTICAST_DROP;
Interop.Sys.IPv4MulticastOption opt;
Interop.Sys.IPv4MulticastOption opt = default;
Interop.Error err = Interop.Sys.GetIPv4MulticastOption(handle, optName, &opt);
if (err != Interop.Error.SUCCESS)
{
@ -1332,7 +1330,7 @@ namespace System.Net.Sockets
Interop.Sys.MulticastOption.MULTICAST_ADD :
Interop.Sys.MulticastOption.MULTICAST_DROP;
Interop.Sys.IPv6MulticastOption opt;
Interop.Sys.IPv6MulticastOption opt = default;
Interop.Error err = Interop.Sys.GetIPv6MulticastOption(handle, optName, &opt);
if (err != Interop.Error.SUCCESS)
{

View File

@ -36,9 +36,9 @@ namespace System.Net.Sockets
socket.ReceiveMessageFromAsync(buffer, socketFlags, remoteEndPoint);
public static Task<int> SendAsync(this Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags) =>
socket.SendAsync(buffer, socketFlags, fromNetworkStream: false);
socket.SendAsync(buffer, socketFlags);
public static ValueTask<int> SendAsync(this Socket socket, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) =>
socket.SendAsync(buffer, socketFlags, fromNetworkStream: false, cancellationToken: cancellationToken);
socket.SendAsync(buffer, socketFlags, 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) =>

View File

@ -316,8 +316,18 @@ namespace System.Net.Sockets
throw new ArgumentOutOfRangeException(nameof(port));
}
TcpListener listener = new TcpListener(IPAddress.IPv6Any, port);
listener.Server.DualMode = true;
TcpListener listener;
if (Socket.OSSupportsIPv6)
{
// If OS supports IPv6 use dual mode so both address families work.
listener = new TcpListener(IPAddress.IPv6Any, port);
listener.Server.DualMode = true;
}
else
{
// If not, fall-back to old IPv4.
listener = new TcpListener(IPAddress.Any , port);
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, port);

View File

@ -60,7 +60,7 @@ namespace System.Net.Sockets
// Validate the address family.
if (family != AddressFamily.InterNetwork && family != AddressFamily.InterNetworkV6)
{
throw new ArgumentException(SR.net_protocol_invalid_family, nameof(family));
throw new ArgumentException(SR.Format(SR.net_protocol_invalid_family, "UDP"), nameof(family));
}
IPEndPoint localEP;

View File

@ -8,18 +8,12 @@ using System.Text;
namespace System.Net.Sockets
{
/// <summary>Represents a Unix Domain Socket endpoint as a path.</summary>
public sealed class UnixDomainSocketEndPoint : EndPoint
public sealed partial class UnixDomainSocketEndPoint : EndPoint
{
private const AddressFamily EndPointAddressFamily = AddressFamily.Unix;
private static readonly Encoding s_pathEncoding = Encoding.UTF8;
private static readonly int s_nativePathOffset;
private static readonly int s_nativePathLength;
private static readonly int s_nativeAddressSize;
private readonly string _path;
private readonly byte[] _encodedPath;
static UnixDomainSocketEndPoint()
{
Interop.Sys.GetDomainSocketSizes(out s_nativePathOffset, out s_nativePathLength, out s_nativeAddressSize);
@ -29,107 +23,7 @@ namespace System.Net.Sockets
Debug.Assert(s_nativePathLength >= 92, "Expected max path length to be at least 92"); // per http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_un.h.html
}
public UnixDomainSocketEndPoint(string path)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
// Pathname socket addresses should be null-terminated.
// Linux abstract socket addresses start with a zero byte, they must not be null-terminated.
bool isAbstract = IsAbstract(path);
int bufferLength = s_pathEncoding.GetByteCount(path);
if (!isAbstract)
{
// for null terminator
bufferLength++;
}
if (path.Length == 0 || bufferLength > s_nativePathLength)
{
throw new ArgumentOutOfRangeException(
nameof(path), path,
SR.Format(SR.ArgumentOutOfRange_PathLengthInvalid, path, s_nativePathLength));
}
_path = path;
_encodedPath = new byte[bufferLength];
int bytesEncoded = s_pathEncoding.GetBytes(path, 0, path.Length, _encodedPath, 0);
Debug.Assert(bufferLength - (isAbstract ? 0 : 1) == bytesEncoded);
}
internal UnixDomainSocketEndPoint(SocketAddress socketAddress)
{
if (socketAddress == null)
{
throw new ArgumentNullException(nameof(socketAddress));
}
if (socketAddress.Family != EndPointAddressFamily ||
socketAddress.Size > s_nativeAddressSize)
{
throw new ArgumentOutOfRangeException(nameof(socketAddress));
}
if (socketAddress.Size > s_nativePathOffset)
{
_encodedPath = new byte[socketAddress.Size - s_nativePathOffset];
for (int i = 0; i < _encodedPath.Length; i++)
{
_encodedPath[i] = socketAddress[s_nativePathOffset + i];
}
// Strip trailing null of pathname socket addresses.
int length = _encodedPath.Length;
if (!IsAbstract(_encodedPath))
{
// Since this isn't an abstract path, we're sure our first byte isn't 0.
while (_encodedPath[length - 1] == 0)
{
length--;
}
}
_path = s_pathEncoding.GetString(_encodedPath, 0, length);
}
else
{
_encodedPath = Array.Empty<byte>();
_path = string.Empty;
}
}
public override SocketAddress Serialize()
{
var result = new SocketAddress(AddressFamily.Unix, s_nativePathOffset + _encodedPath.Length);
for (int index = 0; index < _encodedPath.Length; index++)
{
result[s_nativePathOffset + index] = _encodedPath[index];
}
return result;
}
public override EndPoint Create(SocketAddress socketAddress) => new UnixDomainSocketEndPoint(socketAddress);
public override AddressFamily AddressFamily => EndPointAddressFamily;
public override string ToString()
{
bool isAbstract = IsAbstract(_path);
if (isAbstract)
{
return "@" + _path.Substring(1);
}
else
{
return _path;
}
}
private static bool IsAbstract(string path) => path.Length > 0 && path[0] == '\0';
private static bool IsAbstract(byte[] encodedPath) => encodedPath.Length > 0 && encodedPath[0] == 0;
private SocketAddress CreateSocketAddressForSerialize() =>
new SocketAddress(AddressFamily.Unix, s_nativePathOffset + _encodedPath.Length);
}
}

View File

@ -5,11 +5,22 @@
namespace System.Net.Sockets
{
/// <summary>Represents a Unix Domain Socket endpoint as a path.</summary>
public sealed class UnixDomainSocketEndPoint : EndPoint
public sealed partial class UnixDomainSocketEndPoint : EndPoint
{
public UnixDomainSocketEndPoint(string path)
{
throw new PlatformNotSupportedException();
}
private static readonly int s_nativePathOffset = 2; // sizeof(sun_family)
private static readonly int s_nativePathLength = 108; // sizeof(sun_path)
private static readonly int s_nativeAddressSize = s_nativePathOffset + s_nativePathLength; // sizeof(sockaddr_un)
private SocketAddress CreateSocketAddressForSerialize() =>
new SocketAddress(AddressFamily.Unix, s_nativeAddressSize);
// from afunix.h:
//#define UNIX_PATH_MAX 108
//typedef struct sockaddr_un
//{
// ADDRESS_FAMILY sun_family; /* AF_UNIX */
// char sun_path[UNIX_PATH_MAX]; /* pathname */
//}
//SOCKADDR_UN, *PSOCKADDR_UN;
}
}

View File

@ -0,0 +1,140 @@
// 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.Diagnostics;
using System.Text;
namespace System.Net.Sockets
{
/// <summary>Represents a Unix Domain Socket endpoint as a path.</summary>
public sealed partial class UnixDomainSocketEndPoint : EndPoint
{
private const AddressFamily EndPointAddressFamily = AddressFamily.Unix;
private static readonly Encoding s_pathEncoding = Encoding.UTF8;
private static readonly Lazy<bool> s_udsSupported = new Lazy<bool>(() =>
{
try
{
new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified).Dispose();
return true;
}
catch
{
return false;
}
});
private readonly string _path;
private readonly byte[] _encodedPath;
public UnixDomainSocketEndPoint(string path)
{
if (path == null)
{
throw new ArgumentNullException(nameof(path));
}
// Pathname socket addresses should be null-terminated.
// Linux abstract socket addresses start with a zero byte, they must not be null-terminated.
bool isAbstract = IsAbstract(path);
int bufferLength = s_pathEncoding.GetByteCount(path);
if (!isAbstract)
{
// for null terminator
bufferLength++;
}
if (path.Length == 0 || bufferLength > s_nativePathLength)
{
throw new ArgumentOutOfRangeException(
nameof(path), path,
SR.Format(SR.ArgumentOutOfRange_PathLengthInvalid, path, s_nativePathLength));
}
_path = path;
_encodedPath = new byte[bufferLength];
int bytesEncoded = s_pathEncoding.GetBytes(path, 0, path.Length, _encodedPath, 0);
Debug.Assert(bufferLength - (isAbstract ? 0 : 1) == bytesEncoded);
if (!s_udsSupported.Value)
{
throw new PlatformNotSupportedException();
}
}
internal UnixDomainSocketEndPoint(SocketAddress socketAddress)
{
if (socketAddress == null)
{
throw new ArgumentNullException(nameof(socketAddress));
}
if (socketAddress.Family != EndPointAddressFamily ||
socketAddress.Size > s_nativeAddressSize)
{
throw new ArgumentOutOfRangeException(nameof(socketAddress));
}
if (socketAddress.Size > s_nativePathOffset)
{
_encodedPath = new byte[socketAddress.Size - s_nativePathOffset];
for (int i = 0; i < _encodedPath.Length; i++)
{
_encodedPath[i] = socketAddress[s_nativePathOffset + i];
}
// Strip trailing null of pathname socket addresses.
int length = _encodedPath.Length;
if (!IsAbstract(_encodedPath))
{
// Since this isn't an abstract path, we're sure our first byte isn't 0.
while (_encodedPath[length - 1] == 0)
{
length--;
}
}
_path = s_pathEncoding.GetString(_encodedPath, 0, length);
}
else
{
_encodedPath = Array.Empty<byte>();
_path = string.Empty;
}
}
public override SocketAddress Serialize()
{
SocketAddress result = CreateSocketAddressForSerialize();
for (int index = 0; index < _encodedPath.Length; index++)
{
result[s_nativePathOffset + index] = _encodedPath[index];
}
return result;
}
public override EndPoint Create(SocketAddress socketAddress) => new UnixDomainSocketEndPoint(socketAddress);
public override AddressFamily AddressFamily => EndPointAddressFamily;
public override string ToString()
{
bool isAbstract = IsAbstract(_path);
if (isAbstract)
{
return "@" + _path.Substring(1);
}
else
{
return _path;
}
}
private static bool IsAbstract(string path) => path.Length > 0 && path[0] == '\0';
private static bool IsAbstract(byte[] encodedPath) => encodedPath.Length > 0 && encodedPath[0] == 0;
}
}

View File

@ -276,6 +276,30 @@ namespace System.Net.Sockets.Tests
Assert.Throws<InvalidOperationException>(() => { AcceptAsync(listener, server); });
}
}
[Fact]
public async Task AcceptAsync_MultipleAcceptsThenDispose_AcceptsThrowAfterDispose()
{
if (UsesSync)
{
return;
}
for (int i = 0; i < 100; i++)
{
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
listener.Listen(2);
Task accept1 = AcceptAsync(listener);
Task accept2 = AcceptAsync(listener);
listener.Dispose();
await Assert.ThrowsAnyAsync<Exception>(() => accept1);
await Assert.ThrowsAnyAsync<Exception>(() => accept2);
}
}
}
}
public sealed class AcceptSync : Accept<SocketHelperArraySync> { }

View File

@ -44,9 +44,7 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[ActiveIssue(22765, TestPlatforms.AnyUnix)]
public async Task Connect_OnConnectedSocket_Fails()
{
int port;

Some files were not shown because too many files have changed in this diff Show More