diff --git a/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs b/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs index e7163b7ece..d6fedc0518 100644 --- a/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs +++ b/src/Kestrel.Core/Internal/Http/HttpUpgradeStream.cs @@ -145,6 +145,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return _requestStream.ReadAsync(buffer, offset, count, cancellationToken); } +#if NETCOREAPP2_1 + public override ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default) + { + return _requestStream.ReadAsync(destination, cancellationToken); + } +#endif + public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) { return _requestStream.CopyToAsync(destination, bufferSize, cancellationToken); @@ -155,6 +162,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return _responseStream.WriteAsync(buffer, offset, count, cancellationToken); } +#if NETCOREAPP2_1 + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + { + return _responseStream.WriteAsync(source, cancellationToken); + } +#endif + public override long Seek(long offset, SeekOrigin origin) { return _requestStream.Seek(offset, origin); diff --git a/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs b/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs index a1c87ad8c8..9485392825 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/WrappingStream.cs @@ -68,6 +68,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _inner.ReadAsync(buffer, offset, count, cancellationToken); +#if NETCOREAPP2_1 + public override ValueTask ReadAsync(Memory destination, CancellationToken cancellationToken = default) + => _inner.ReadAsync(destination, cancellationToken); +#endif + public override int ReadByte() => _inner.ReadByte(); @@ -83,6 +88,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _inner.WriteAsync(buffer, offset, count, cancellationToken); +#if NETCOREAPP2_1 + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + => _inner.WriteAsync(source, cancellationToken); +#endif + public override void WriteByte(byte value) => _inner.WriteByte(value); diff --git a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs index 7423b0d67a..4c067e8cb6 100644 --- a/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs +++ b/src/Kestrel.Transport.Sockets/Internal/SocketConnection.cs @@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal internal sealed class SocketConnection : TransportConnection, IDisposable { private static readonly int MinAllocBufferSize = KestrelMemoryPool.MinimumSegmentSize / 2; + private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); private readonly Socket _socket; private readonly PipeScheduler _scheduler; @@ -54,8 +55,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal ConnectionClosed = _connectionClosedTokenSource.Token; - _receiver = new SocketReceiver(_socket, _scheduler); - _sender = new SocketSender(_socket, _scheduler); + // On *nix platforms, Sockets already dispatches to the ThreadPool. + // Yes, the IOQueues are still used for the PipeSchedulers. This is intentional. + // https://github.com/aspnet/KestrelHttpServer/issues/2573 + var awaiterScheduler = IsWindows ? _scheduler : PipeScheduler.Inline; + + _receiver = new SocketReceiver(_socket, awaiterScheduler); + _sender = new SocketSender(_socket, awaiterScheduler); } public override MemoryPool MemoryPool { get; } diff --git a/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs b/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs index 9d2e7e0182..2d26f8f398 100644 --- a/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs +++ b/src/Kestrel.Transport.Sockets/Properties/SocketsStrings.Designer.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets = new ResourceManager("Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketsStrings", typeof(SocketsStrings).GetTypeInfo().Assembly); /// - /// Only ListenType.IPEndPoint is supported. + /// Only ListenType.IPEndPoint is supported by the Socket Transport. https://go.microsoft.com/fwlink/?linkid=874850 /// internal static string OnlyIPEndPointsSupported { @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets } /// - /// Only ListenType.IPEndPoint is supported. + /// Only ListenType.IPEndPoint is supported by the Socket Transport. https://go.microsoft.com/fwlink/?linkid=874850 /// internal static string FormatOnlyIPEndPointsSupported() => GetString("OnlyIPEndPointsSupported"); diff --git a/src/Kestrel.Transport.Sockets/SocketsStrings.resx b/src/Kestrel.Transport.Sockets/SocketsStrings.resx index 79cd2d7303..52b26c66bc 100644 --- a/src/Kestrel.Transport.Sockets/SocketsStrings.resx +++ b/src/Kestrel.Transport.Sockets/SocketsStrings.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Only ListenType.IPEndPoint is supported. + Only ListenType.IPEndPoint is supported by the Socket Transport. https://go.microsoft.com/fwlink/?linkid=874850 Transport is already bound.