diff options
author | Stephen Toub <stoub@microsoft.com> | 2017-08-08 15:40:48 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-08 15:40:48 +0300 |
commit | 4a97f92f27d1b0bd2f2c67ffb05e50833d652ae4 (patch) | |
tree | bb3d8224d7eb823d61ef67bf6c5ffe7fe5a68085 /src | |
parent | abc9443560d7a1226d5d1fd75df923d2fb37bf91 (diff) |
Add Span-based overloads to System.Net.Sockets (#22988)
* Add Span-based overloads to System.Net.Sockets
- Socket.Receive/Send
- NetworkStream.Read.Write
* Address PR feedback
Diffstat (limited to 'src')
18 files changed, 535 insertions, 166 deletions
diff --git a/src/System.Net.Sockets/ref/System.Net.Sockets.csproj b/src/System.Net.Sockets/ref/System.Net.Sockets.csproj index 887d4e9d92..534417c088 100644 --- a/src/System.Net.Sockets/ref/System.Net.Sockets.csproj +++ b/src/System.Net.Sockets/ref/System.Net.Sockets.csproj @@ -15,6 +15,7 @@ <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" /> diff --git a/src/System.Net.Sockets/ref/System.Net.Sockets.netcoreapp.cs b/src/System.Net.Sockets/ref/System.Net.Sockets.netcoreapp.cs new file mode 100644 index 0000000000..1de47d9e07 --- /dev/null +++ b/src/System.Net.Sockets/ref/System.Net.Sockets.netcoreapp.cs @@ -0,0 +1,20 @@ +// 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; } + } +} diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs b/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs index ef46091784..91b995198d 100644 --- a/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs +++ b/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs @@ -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) diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index c07087cce0..1fa073a5c5 100644 --- a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -1241,6 +1241,36 @@ namespace System.Net.Sockets return bytesTransferred; } + public int Send(ReadOnlySpan<byte> buffer) => Send(buffer, SocketFlags.None); + + public int Send(ReadOnlySpan<byte> buffer, SocketFlags socketFlags) + { + int bytesTransferred = Send(buffer, socketFlags, out SocketError errorCode); + return errorCode == SocketError.Success ? + bytesTransferred : + throw new SocketException((int)errorCode); + } + + public int Send(ReadOnlySpan<byte> buffer, SocketFlags socketFlags, out SocketError errorCode) + { + if (NetEventSource.IsEnabled) NetEventSource.Enter(this); + if (CleanedUp) throw new ObjectDisposedException(GetType().FullName); + ValidateBlockingMode(); + + int bytesTransferred; + errorCode = SocketPal.Send(_handle, buffer, socketFlags, out bytesTransferred); + + if (errorCode != SocketError.Success) + { + UpdateStatusAfterSocketError(errorCode); + if (NetEventSource.IsEnabled) NetEventSource.Error(this, new SocketException((int)errorCode)); + bytesTransferred = 0; + } + + if (NetEventSource.IsEnabled) NetEventSource.Exit(this, bytesTransferred); + return bytesTransferred; + } + public void SendFile(string fileName) { SendFile(fileName, null, null, TransmitFileOptions.UseDefaultWorkerThread); @@ -1462,6 +1492,36 @@ namespace System.Net.Sockets return bytesTransferred; } + public int Receive(Span<byte> buffer) => Receive(buffer, SocketFlags.None); + + public int Receive(Span<byte> buffer, SocketFlags socketFlags) + { + int bytesTransferred = Receive(buffer, socketFlags, out SocketError errorCode); + return errorCode == SocketError.Success ? + bytesTransferred : + throw new SocketException((int)errorCode); + } + + public int Receive(Span<byte> buffer, SocketFlags socketFlags, out SocketError errorCode) + { + if (NetEventSource.IsEnabled) NetEventSource.Enter(this); + if (CleanedUp) throw new ObjectDisposedException(GetType().FullName); + ValidateBlockingMode(); + + int bytesTransferred; + errorCode = SocketPal.Receive(_handle, buffer, socketFlags, out bytesTransferred); + + if (errorCode != SocketError.Success) + { + UpdateStatusAfterSocketError(errorCode); + if (NetEventSource.IsEnabled) NetEventSource.Error(this, new SocketException((int)errorCode)); + bytesTransferred = 0; + } + + if (NetEventSource.IsEnabled) NetEventSource.Exit(this, bytesTransferred); + return bytesTransferred; + } + public int Receive(IList<ArraySegment<byte>> buffers) { return Receive(buffers, SocketFlags.None); @@ -4629,7 +4689,7 @@ namespace System.Net.Sockets else { int unused; - errorCode = SocketPal.Receive(_handle, null, 0, 0, SocketFlags.None, out unused); + errorCode = SocketPal.Receive(_handle, Array.Empty<byte>(), 0, 0, SocketFlags.None, out unused); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"handle:{_handle} recv():{errorCode}"); if (errorCode != (SocketError)0) diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs index 9ae7c44be7..db4604fe41 100644 --- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs +++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs @@ -3,10 +3,8 @@ // See the LICENSE file in the project root for more information. using Microsoft.Win32.SafeHandles; -using System; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.InteropServices; using System.Threading; namespace System.Net.Sockets @@ -180,62 +178,102 @@ namespace System.Net.Sockets private abstract class WriteOperation : AsyncOperation { - } + } - private sealed class SendOperation : WriteOperation + private abstract class SendOperation : WriteOperation { - public byte[] Buffer; - public int Offset; - public int Count; public SocketFlags Flags; public int BytesTransferred; - public IList<ArraySegment<byte>> Buffers; - public int BufferIndex; + public int Offset; + public int Count; protected sealed override void Abort() { } public Action<int, byte[], int, SocketFlags, SocketError> Callback { - private get { return (Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent; } - set { CallbackOrEvent = value; } + set => CallbackOrEvent = value; + } + + protected sealed override void InvokeCallback() => + ((Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent)(BytesTransferred, SocketAddress, SocketAddressLen, SocketFlags.None, ErrorCode); + } + + private sealed class BufferArraySendOperation : SendOperation + { + public byte[] Buffer; + + protected override bool DoTryComplete(SocketAsyncContext context) + { + int bufferIndex = 0; + return SocketPal.TryCompleteSendTo(context._socket, Buffer, null, ref bufferIndex, ref Offset, ref Count, Flags, SocketAddress, SocketAddressLen, ref BytesTransferred, out ErrorCode); } + } - protected sealed override void InvokeCallback() + private sealed class BufferListSendOperation : SendOperation + { + public IList<ArraySegment<byte>> Buffers; + public int BufferIndex; + + protected override bool DoTryComplete(SocketAsyncContext context) { - Callback(BytesTransferred, SocketAddress, SocketAddressLen, SocketFlags.None, ErrorCode); + return SocketPal.TryCompleteSendTo(context._socket, default(ReadOnlySpan<byte>), Buffers, ref BufferIndex, ref Offset, ref Count, Flags, SocketAddress, SocketAddressLen, ref BytesTransferred, out ErrorCode); } + } + + private sealed unsafe class BufferPtrSendOperation : SendOperation + { + public byte* BufferPtr; + protected override bool DoTryComplete(SocketAsyncContext context) { - return SocketPal.TryCompleteSendTo(context._socket, Buffer, Buffers, ref BufferIndex, ref Offset, ref Count, Flags, SocketAddress, SocketAddressLen, ref BytesTransferred, out ErrorCode); + int bufferIndex = 0; + return SocketPal.TryCompleteSendTo(context._socket, new ReadOnlySpan<byte>(BufferPtr, Offset + Count), null, ref bufferIndex, ref Offset, ref Count, Flags, SocketAddress, SocketAddressLen, ref BytesTransferred, out ErrorCode); } } - private sealed class ReceiveOperation : ReadOperation + private abstract class ReceiveOperation : ReadOperation { - public byte[] Buffer; - public int Offset; - public int Count; public SocketFlags Flags; - public int BytesTransferred; public SocketFlags ReceivedFlags; - public IList<ArraySegment<byte>> Buffers; + public int BytesTransferred; protected sealed override void Abort() { } public Action<int, byte[], int, SocketFlags, SocketError> Callback { - private get { return (Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent; } - set { CallbackOrEvent = value; } + set => CallbackOrEvent = value; } - protected sealed override void InvokeCallback() - { - Callback(BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, ErrorCode); - } - protected override bool DoTryComplete(SocketAsyncContext context) - { - return SocketPal.TryCompleteReceiveFrom(context._socket, Buffer, Buffers, Offset, Count, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode); - } + protected sealed override void InvokeCallback() => + ((Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent)( + BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, ErrorCode); + } + + private sealed class BufferArrayReceiveOperation : ReceiveOperation + { + public byte[] Buffer; + public int Offset; + public int Count; + + protected override bool DoTryComplete(SocketAsyncContext context) => + SocketPal.TryCompleteReceiveFrom(context._socket, new Span<byte>(Buffer, Offset, Count), null, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode); + } + + private sealed class BufferListReceiveOperation : ReceiveOperation + { + public IList<ArraySegment<byte>> Buffers; + + protected override bool DoTryComplete(SocketAsyncContext context) => + SocketPal.TryCompleteReceiveFrom(context._socket, default(Span<byte>), Buffers, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode); + } + + private sealed unsafe class BufferPtrReceiveOperation : ReceiveOperation + { + public byte* BufferPtr; + public int Length; + + protected override bool DoTryComplete(SocketAsyncContext context) => + SocketPal.TryCompleteReceiveFrom(context._socket, new Span<byte>(BufferPtr, Length), null, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode); } private sealed class ReceiveMessageFromOperation : ReadOperation @@ -256,19 +294,15 @@ namespace System.Net.Sockets public Action<int, byte[], int, SocketFlags, IPPacketInformation, SocketError> Callback { - private get { return (Action<int, byte[], int, SocketFlags, IPPacketInformation, SocketError>)CallbackOrEvent; } - set { CallbackOrEvent = value; } + set => CallbackOrEvent = value; } - protected override bool DoTryComplete(SocketAsyncContext context) - { - return SocketPal.TryCompleteReceiveMessageFrom(context._socket, Buffer, Buffers, Offset, Count, Flags, SocketAddress, ref SocketAddressLen, IsIPv4, IsIPv6, out BytesTransferred, out ReceivedFlags, out IPPacketInformation, out ErrorCode); - } + protected override bool DoTryComplete(SocketAsyncContext context) => + SocketPal.TryCompleteReceiveMessageFrom(context._socket, Buffer, Buffers, Offset, Count, Flags, SocketAddress, ref SocketAddressLen, IsIPv4, IsIPv6, out BytesTransferred, out ReceivedFlags, out IPPacketInformation, out ErrorCode); - protected override void InvokeCallback() - { - Callback(BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, IPPacketInformation, ErrorCode); - } + protected override void InvokeCallback() => + ((Action<int, byte[], int, SocketFlags, IPPacketInformation, SocketError>)CallbackOrEvent)( + BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, IPPacketInformation, ErrorCode); } private sealed class AcceptOperation : ReadOperation @@ -277,14 +311,11 @@ namespace System.Net.Sockets public Action<IntPtr, byte[], int, SocketError> Callback { - private get { return (Action<IntPtr, byte[], int, SocketError>)CallbackOrEvent; } - set { CallbackOrEvent = value; } + set => CallbackOrEvent = value; } - protected override void Abort() - { + protected override void Abort() => AcceptedFileDescriptor = (IntPtr)(-1); - } protected override bool DoTryComplete(SocketAsyncContext context) { @@ -293,18 +324,16 @@ namespace System.Net.Sockets return completed; } - protected override void InvokeCallback() - { - Callback(AcceptedFileDescriptor, SocketAddress, SocketAddressLen, ErrorCode); - } + protected override void InvokeCallback() => + ((Action<IntPtr, byte[], int, SocketError>)CallbackOrEvent)( + AcceptedFileDescriptor, SocketAddress, SocketAddressLen, ErrorCode); } private sealed class ConnectOperation : WriteOperation { public Action<SocketError> Callback { - private get { return (Action<SocketError>)CallbackOrEvent; } - set { CallbackOrEvent = value; } + set => CallbackOrEvent = value; } protected override void Abort() { } @@ -316,10 +345,8 @@ namespace System.Net.Sockets return result; } - protected override void InvokeCallback() - { - Callback(ErrorCode); - } + protected override void InvokeCallback() => + ((Action<SocketError>)CallbackOrEvent)(ErrorCode); } private sealed class SendFileOperation : WriteOperation @@ -333,19 +360,14 @@ namespace System.Net.Sockets public Action<long, SocketError> Callback { - private get { return (Action<long, SocketError>)CallbackOrEvent; } - set { CallbackOrEvent = value; } + set => CallbackOrEvent = value; } - protected override void InvokeCallback() - { - Callback(BytesTransferred, ErrorCode); - } + protected override void InvokeCallback() => + ((Action<long, SocketError>)CallbackOrEvent)(BytesTransferred, ErrorCode); - protected override bool DoTryComplete(SocketAsyncContext context) - { - return SocketPal.TryCompleteSendFile(context._socket, FileHandle, ref Offset, ref Count, ref BytesTransferred, out ErrorCode); - } + protected override bool DoTryComplete(SocketAsyncContext context) => + SocketPal.TryCompleteSendFile(context._socket, FileHandle, ref Offset, ref Count, ref BytesTransferred, out ErrorCode); } private enum QueueState @@ -786,6 +808,12 @@ namespace System.Net.Sockets return ReceiveFrom(buffer, offset, count, ref flags, null, ref socketAddressLen, timeout, out bytesReceived); } + public SocketError Receive(Span<byte> buffer, ref SocketFlags flags, int timeout, out int bytesReceived) + { + int socketAddressLen = 0; + return ReceiveFrom(buffer, ref flags, null, ref socketAddressLen, timeout, out bytesReceived); + } + public SocketError ReceiveAsync(byte[] buffer, int offset, int count, SocketFlags flags, out int bytesReceived, out SocketFlags receivedFlags, Action<int, byte[], int, SocketFlags, SocketError> callback) { int socketAddressLen = 0; @@ -814,7 +842,7 @@ namespace System.Net.Sockets @event = new ManualResetEventSlim(false, 0); - operation = new ReceiveOperation + operation = new BufferArrayReceiveOperation { Event = @event, Buffer = buffer, @@ -853,10 +881,78 @@ namespace System.Net.Sockets } finally { - if (@event != null) @event.Dispose(); + @event?.Dispose(); } } + public unsafe SocketError ReceiveFrom(Span<byte> buffer, ref SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, int timeout, out int bytesReceived) + { + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); + + fixed (byte* bufferPtr = &buffer.DangerousGetPinnableReference()) + { + ManualResetEventSlim @event = null; + try + { + ReceiveOperation operation; + lock (_receiveQueue.QueueLock) + { + SocketFlags receivedFlags; + SocketError errorCode; + + if (_receiveQueue.IsEmpty && + SocketPal.TryCompleteReceiveFrom(_socket, buffer, flags, socketAddress, ref socketAddressLen, out bytesReceived, out receivedFlags, out errorCode)) + { + flags = receivedFlags; + return errorCode; + } + + @event = new ManualResetEventSlim(false, 0); + + operation = new BufferPtrReceiveOperation + { + Event = @event, + BufferPtr = bufferPtr, + Length = buffer.Length, + Flags = flags, + SocketAddress = socketAddress, + SocketAddressLen = socketAddressLen, + }; + + bool isStopped; + while (!TryBeginOperation(ref _receiveQueue, operation, Interop.Sys.SocketEvents.Read, maintainOrder: true, isStopped: out isStopped)) + { + if (isStopped) + { + flags = operation.ReceivedFlags; + bytesReceived = operation.BytesTransferred; + return SocketError.Interrupted; + } + + if (operation.TryComplete(this)) + { + socketAddressLen = operation.SocketAddressLen; + flags = operation.ReceivedFlags; + bytesReceived = operation.BytesTransferred; + return operation.ErrorCode; + } + } + } + + bool signaled = operation.Wait(timeout); + socketAddressLen = operation.SocketAddressLen; + flags = operation.ReceivedFlags; + bytesReceived = operation.BytesTransferred; + return signaled ? operation.ErrorCode : SocketError.TimedOut; + } + finally + { + @event?.Dispose(); + } + } + } + + public SocketError ReceiveFromAsync(byte[] buffer, int offset, int count, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, Action<int, byte[], int, SocketFlags, SocketError> callback) { SetNonBlocking(); @@ -872,7 +968,7 @@ namespace System.Net.Sockets return errorCode; } - var operation = new ReceiveOperation + var operation = new BufferArrayReceiveOperation { Callback = callback, Buffer = buffer, @@ -941,7 +1037,7 @@ namespace System.Net.Sockets @event = new ManualResetEventSlim(false, 0); - operation = new ReceiveOperation + operation = new BufferListReceiveOperation { Event = @event, Buffers = buffers, @@ -979,7 +1075,7 @@ namespace System.Net.Sockets } finally { - if (@event != null) @event.Dispose(); + @event?.Dispose(); } } @@ -999,7 +1095,7 @@ namespace System.Net.Sockets return errorCode; } - operation = new ReceiveOperation + operation = new BufferListReceiveOperation { Callback = callback, Buffers = buffers, @@ -1102,7 +1198,7 @@ namespace System.Net.Sockets } finally { - if (@event != null) @event.Dispose(); + @event?.Dispose(); } } @@ -1163,6 +1259,9 @@ namespace System.Net.Sockets } } + public SocketError Send(ReadOnlySpan<byte> buffer, SocketFlags flags, int timeout, out int bytesSent) => + SendTo(buffer, flags, null, 0, timeout, out bytesSent); + public SocketError Send(byte[] buffer, int offset, int count, SocketFlags flags, int timeout, out int bytesSent) { return SendTo(buffer, offset, count, flags, null, 0, timeout, out bytesSent); @@ -1181,7 +1280,7 @@ namespace System.Net.Sockets ManualResetEventSlim @event = null; try { - SendOperation operation; + BufferArraySendOperation operation; lock (_sendQueue.QueueLock) { @@ -1196,7 +1295,7 @@ namespace System.Net.Sockets @event = new ManualResetEventSlim(false, 0); - operation = new SendOperation + operation = new BufferArraySendOperation { Event = @event, Buffer = buffer, @@ -1231,7 +1330,72 @@ namespace System.Net.Sockets } finally { - if (@event != null) @event.Dispose(); + @event?.Dispose(); + } + } + + public unsafe SocketError SendTo(ReadOnlySpan<byte> buffer, SocketFlags flags, byte[] socketAddress, int socketAddressLen, int timeout, out int bytesSent) + { + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); + + fixed (byte* bufferPtr = &buffer.DangerousGetPinnableReference()) + { + ManualResetEventSlim @event = null; + try + { + BufferPtrSendOperation operation; + + lock (_sendQueue.QueueLock) + { + bytesSent = 0; + SocketError errorCode; + + int bufferIndexIgnored = 0, offset = 0, count = buffer.Length; + if (_sendQueue.IsEmpty && + SocketPal.TryCompleteSendTo(_socket, buffer, null, ref bufferIndexIgnored, ref offset, ref count, flags, socketAddress, socketAddressLen, ref bytesSent, out errorCode)) + { + return errorCode; + } + + @event = new ManualResetEventSlim(false, 0); + + operation = new BufferPtrSendOperation + { + Event = @event, + BufferPtr = bufferPtr, + Offset = offset, + Count = count, + Flags = flags, + SocketAddress = socketAddress, + SocketAddressLen = socketAddressLen, + BytesTransferred = bytesSent + }; + + bool isStopped; + while (!TryBeginOperation(ref _sendQueue, operation, Interop.Sys.SocketEvents.Write, maintainOrder: true, isStopped: out isStopped)) + { + if (isStopped) + { + bytesSent = operation.BytesTransferred; + return SocketError.Interrupted; + } + + if (operation.TryComplete(this)) + { + bytesSent = operation.BytesTransferred; + return operation.ErrorCode; + } + } + } + + bool signaled = operation.Wait(timeout); + bytesSent = operation.BytesTransferred; + return signaled ? operation.ErrorCode : SocketError.TimedOut; + } + finally + { + @event?.Dispose(); + } } } @@ -1251,7 +1415,7 @@ namespace System.Net.Sockets return errorCode; } - var operation = new SendOperation + var operation = new BufferArraySendOperation { Callback = callback, Buffer = buffer, @@ -1300,7 +1464,7 @@ namespace System.Net.Sockets ManualResetEventSlim @event = null; try { - SendOperation operation; + BufferListSendOperation operation; lock (_sendQueue.QueueLock) { @@ -1317,7 +1481,7 @@ namespace System.Net.Sockets @event = new ManualResetEventSlim(false, 0); - operation = new SendOperation + operation = new BufferListSendOperation { Event = @event, Buffers = buffers, @@ -1352,12 +1516,10 @@ namespace System.Net.Sockets } finally { - if (@event != null) @event.Dispose(); + @event?.Dispose(); } } - - public SocketError SendToAsync(IList<ArraySegment<byte>> buffers, SocketFlags flags, byte[] socketAddress, ref int socketAddressLen, out int bytesSent, Action<int, byte[], int, SocketFlags, SocketError> callback) { SetNonBlocking(); @@ -1376,7 +1538,7 @@ namespace System.Net.Sockets return errorCode; } - var operation = new SendOperation + var operation = new BufferListSendOperation { Callback = callback, Buffers = buffers, @@ -1461,7 +1623,7 @@ namespace System.Net.Sockets } finally { - if (@event != null) @event.Dispose(); + @event?.Dispose(); } } diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs index da9f521e9b..013d67d698 100644 --- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs +++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs @@ -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; @@ -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,13 +700,19 @@ 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) { for (;;) { @@ -727,14 +720,9 @@ namespace System.Net.Sockets 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) { @@ -758,7 +746,7 @@ namespace System.Net.Sockets bytesSent += sent; bool isComplete = sent == 0 || - (buffer != null && count == 0) || + (buffers == null && count == 0) || (buffers != null && bufferIndex == buffers.Count); if (isComplete) { @@ -919,6 +907,19 @@ namespace System.Net.Sockets return completed ? errorCode : SocketError.WouldBlock; } + 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; + bool completed = TryCompleteSendTo(handle, buffer, socketFlags, null, 0, ref bytesTransferred, out errorCode); + return completed ? errorCode : SocketError.WouldBlock; + } + public static SocketError SendFile(SafeCloseSocket handle, FileStream fileStream) { long offset = 0; @@ -983,6 +984,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; diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs index ac8460a650..a82ed56783 100644 --- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs +++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs @@ -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) - { - bytesReceived = Interop.Winsock.recv(handle.DangerousGetHandle(), null, 0, socketFlags); - } - else + fixed (byte* bufferPtr = &buffer.DangerousGetPinnableReference()) { - 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) diff --git a/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs b/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs index b59fce72a4..c558af1fbf 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs +++ b/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs @@ -277,7 +277,7 @@ namespace System.Net.Sockets.Tests } } - public sealed class AcceptSync : Accept<SocketHelperSync> { } + public sealed class AcceptSync : Accept<SocketHelperArraySync> { } public sealed class AcceptSyncForceNonBlocking : Accept<SocketHelperSyncForceNonBlocking> { } public sealed class AcceptApm : Accept<SocketHelperApm> { } public sealed class AcceptTask : Accept<SocketHelperTask> { } diff --git a/src/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs b/src/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs index 9784c5d1b5..436e324462 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs +++ b/src/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs @@ -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] diff --git a/src/System.Net.Sockets/tests/FunctionalTests/Configurations.props b/src/System.Net.Sockets/tests/FunctionalTests/Configurations.props index c398e42e89..77a4b65bc9 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/Configurations.props +++ b/src/System.Net.Sockets/tests/FunctionalTests/Configurations.props @@ -3,6 +3,7 @@ <PropertyGroup> <BuildConfigurations> netstandard; + netcoreapp; </BuildConfigurations> </PropertyGroup> </Project>
\ No newline at end of file diff --git a/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs b/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs index e2cf74039b..4b1c372ecc 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs +++ b/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs @@ -86,7 +86,7 @@ namespace System.Net.Sockets.Tests } } - public sealed class ConnectSync : Connect<SocketHelperSync> { } + public sealed class ConnectSync : Connect<SocketHelperArraySync> { } public sealed class ConnectSyncForceNonBlocking : Connect<SocketHelperSyncForceNonBlocking> { } public sealed class ConnectApm : Connect<SocketHelperApm> { } public sealed class ConnectTask : Connect<SocketHelperTask> { } diff --git a/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs index e6e36ae068..d4a50d03a6 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs +++ b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs @@ -10,7 +10,7 @@ using Xunit; namespace System.Net.Sockets.Tests { - public class NetworkStreamTest + public partial class NetworkStreamTest { [Fact] public void Ctor_NullSocket_ThrowsArgumentNullExceptions() @@ -455,7 +455,7 @@ namespace System.Net.Sockets.Tests } [Fact] - public async Task ReadWrite_Success() + public async Task ReadWrite_Array_Success() { await RunWithConnectedNetworkStreamsAsync((server, client) => { diff --git a/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs new file mode 100644 index 0000000000..6b4b23dc65 --- /dev/null +++ b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs @@ -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. + +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace System.Net.Sockets.Tests +{ + public partial class NetworkStreamTest + { + [Fact] + public async Task ReadWrite_Span_Success() + { + await RunWithConnectedNetworkStreamsAsync((server, client) => + { + var clientData = new byte[] { 42 }; + + client.Write((ReadOnlySpan<byte>)clientData); + + var serverData = new byte[clientData.Length]; + Assert.Equal(serverData.Length, server.Read((Span<byte>)serverData)); + + Assert.Equal(clientData, serverData); + return Task.CompletedTask; + }); + } + } +} diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.cs b/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.cs index b826b8d7ad..1bb887ce0e 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.cs +++ b/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.cs @@ -991,7 +991,7 @@ namespace System.Net.Sockets.Tests } } - public sealed class SendReceiveSync : SendReceive<SocketHelperSync> { } + public sealed class SendReceiveSync : SendReceive<SocketHelperArraySync> { } public sealed class SendReceiveSyncForceNonBlocking : SendReceive<SocketHelperSyncForceNonBlocking> { } public sealed class SendReceiveApm : SendReceive<SocketHelperApm> { } public sealed class SendReceiveTask : SendReceive<SocketHelperTask> { } diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs new file mode 100644 index 0000000000..e9ca3f6553 --- /dev/null +++ b/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs @@ -0,0 +1,9 @@ +// 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. + +namespace System.Net.Sockets.Tests +{ + public sealed class SendReceiveSpanSync : SendReceive<SocketHelperSpanSync> { } + public sealed class SendReceiveSpanSyncForceNonBlocking : SendReceive<SocketHelperSpanSyncForceNonBlocking> { } +} diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs b/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs index 4b470e1f14..409e66a866 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs +++ b/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs @@ -32,7 +32,7 @@ namespace System.Net.Sockets.Tests public virtual bool SupportsAcceptIntoExistingSocket => true; } - public class SocketHelperSync : SocketHelperBase + public class SocketHelperArraySync : SocketHelperBase { public override Task<Socket> AcceptAsync(Socket s) => Task.Run(() => s.Accept()); @@ -68,7 +68,7 @@ namespace System.Net.Sockets.Tests public override bool SupportsAcceptIntoExistingSocket => false; } - public sealed class SocketHelperSyncForceNonBlocking : SocketHelperSync + public sealed class SocketHelperSyncForceNonBlocking : SocketHelperArraySync { public override Task<Socket> AcceptAsync(Socket s) => Task.Run(() => { s.ForceNonBlocking(true); Socket accepted = s.Accept(); accepted.ForceNonBlocking(true); return accepted; }); diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs new file mode 100644 index 0000000000..19043e1807 --- /dev/null +++ b/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs @@ -0,0 +1,24 @@ +// 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; + +namespace System.Net.Sockets.Tests +{ + public class SocketHelperSpanSync : SocketHelperArraySync + { + public override Task<int> ReceiveAsync(Socket s, ArraySegment<byte> buffer) => + Task.Run(() => s.Receive((Span<byte>)buffer, SocketFlags.None)); + public override Task<int> SendAsync(Socket s, ArraySegment<byte> buffer) => + Task.Run(() => s.Send((ReadOnlySpan<byte>)buffer, SocketFlags.None)); + } + + public sealed class SocketHelperSpanSyncForceNonBlocking : SocketHelperSpanSync + { + public override Task<Socket> AcceptAsync(Socket s) => + Task.Run(() => { s.ForceNonBlocking(true); Socket accepted = s.Accept(); accepted.ForceNonBlocking(true); return accepted; }); + public override Task ConnectAsync(Socket s, EndPoint endPoint) => + Task.Run(() => { s.ForceNonBlocking(true); s.Connect(endPoint); }); + } +} diff --git a/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj index 8d3f24aca7..15b1ba6122 100644 --- a/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj +++ b/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj @@ -6,6 +6,8 @@ </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Debug|AnyCPU'" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Release|AnyCPU'" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Debug|AnyCPU'" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Release|AnyCPU'" /> <ItemGroup> <Compile Include="Accept.cs" /> <Compile Include="AgnosticListenerTest.cs" /> @@ -22,6 +24,7 @@ <Compile Include="LingerStateTest.cs" /> <Compile Include="LoggingTest.cs" /> <Compile Include="NetworkStreamTest.cs" /> + <Compile Include="NetworkStreamTest.netcoreapp.cs" Condition="'$(TargetGroup)' != 'netstandard'" /> <Compile Include="ReceiveMessageFrom.cs" /> <Compile Include="ReceiveMessageFromAsync.cs" /> <Compile Include="SelectTest.cs" /> @@ -29,8 +32,10 @@ <Compile Include="SendPacketsElementTest.cs" /> <Compile Include="SendFile.cs" /> <Compile Include="OSSupport.cs" /> - <Compile Include="SocketTestHelper.cs" /> <Compile Include="SendReceive.cs" /> + <Compile Include="SendReceive.netcoreapp.cs" Condition="'$(TargetGroup)' != 'netstandard'" /> + <Compile Include="SocketTestHelper.cs" /> + <Compile Include="SocketTestHelper.netcoreapp.cs" Condition="'$(TargetGroup)' != 'netstandard'" /> <Compile Include="SelectAndPollTests.cs" /> <Compile Include="SocketInformationTest.cs" /> <Compile Include="TcpListenerTest.cs" /> |