| File: Internal\SocketSender.cs | Web Access |
| Project: src\aspnetcore\src\Servers\Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj (Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; using System.Diagnostics; using System.IO.Pipelines; using System.Net.Sockets; using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal; internal sealed class SocketSender : SocketAwaitableEventArgs { private List<ArraySegment<byte>>? _bufferList; public SocketSender(PipeScheduler scheduler) : base(scheduler) { } public ValueTask<SocketOperationResult> SendAsync(Socket socket, in ReadOnlySequence<byte> buffers) { if (buffers.IsSingleSegment) { return SendAsync(socket, buffers.First); } SetBufferList(buffers); if (socket.SendAsync(this)) { return new ValueTask<SocketOperationResult>(this, 0); } var bytesTransferred = BytesTransferred; var error = SocketError; return error == SocketError.Success ? new ValueTask<SocketOperationResult>(new SocketOperationResult(bytesTransferred)) : new ValueTask<SocketOperationResult>(new SocketOperationResult(CreateException(error))); } public void Reset() { // We clear the buffer and buffer list before we put it back into the pool // it's a small performance hit but it removes the confusion when looking at dumps to see this still // holds onto the buffer when it's back in the pool if (BufferList != null) { BufferList = null; _bufferList?.Clear(); } else { SetBuffer(null, 0, 0); } } private ValueTask<SocketOperationResult> SendAsync(Socket socket, ReadOnlyMemory<byte> memory) { SetBuffer(MemoryMarshal.AsMemory(memory)); if (socket.SendAsync(this)) { return new ValueTask<SocketOperationResult>(this, 0); } var bytesTransferred = BytesTransferred; var error = SocketError; return error == SocketError.Success ? new ValueTask<SocketOperationResult>(new SocketOperationResult(bytesTransferred)) : new ValueTask<SocketOperationResult>(new SocketOperationResult(CreateException(error))); } private void SetBufferList(in ReadOnlySequence<byte> buffer) { Debug.Assert(!buffer.IsEmpty); Debug.Assert(!buffer.IsSingleSegment); if (_bufferList == null) { _bufferList = new List<ArraySegment<byte>>(); } foreach (var b in buffer) { _bufferList.Add(b.GetArray()); } // The act of setting this list, sets the buffers in the internal buffer list BufferList = _bufferList; } }