| File: SocketTransportOptions.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.Net; using System.Net.Sockets; using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Server.Kestrel.Internal; namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets; /// <summary> /// Options for socket based transports. /// </summary> public class SocketTransportOptions { private const string FinOnErrorSwitch = "Microsoft.AspNetCore.Server.Kestrel.FinOnError"; private static readonly bool _finOnError; static SocketTransportOptions() { AppContext.TryGetSwitch(FinOnErrorSwitch, out _finOnError); } // Opt-out flag for back compat. Remove in 9.0 (or make public). internal bool FinOnError { get; set; } = _finOnError; /// <summary> /// The number of I/O queues used to process requests. Set to 0 to directly schedule I/O to the ThreadPool. /// </summary> /// <remarks> /// Defaults to a value based on and limited to <see cref="Environment.ProcessorCount" />. /// </remarks> public int IOQueueCount { get; set; } = Internal.IOQueue.DefaultCount; /// <summary> /// Wait until there is data available to allocate a buffer. Setting this to false can increase throughput at the cost of increased memory usage. /// </summary> /// <remarks> /// Defaults to true. /// </remarks> public bool WaitForDataBeforeAllocatingBuffer { get; set; } = true; /// <summary> /// Set to false to enable Nagle's algorithm for all connections. /// </summary> /// <remarks> /// Defaults to true. /// </remarks> public bool NoDelay { get; set; } = true; /// <summary> /// The maximum length of the pending connection queue. /// </summary> /// <remarks> /// Defaults to 512 pending connections. /// </remarks> public int Backlog { get; set; } = 512; /// <summary> /// Gets or sets the maximum unconsumed incoming bytes the transport will buffer. /// <para> /// A value of <see langword="null"/> or 0 disables backpressure entirely allowing unlimited buffering. /// Unlimited server buffering is a security risk given untrusted clients. /// </para> /// </summary> /// <remarks> /// Defaults to 1 MiB. /// </remarks> public long? MaxReadBufferSize { get; set; } = 1024 * 1024; /// <summary> /// Gets or sets the maximum outgoing bytes the transport will buffer before applying write backpressure. /// <para> /// A value of <see langword="null"/> or 0 disables backpressure entirely allowing unlimited buffering. /// Unlimited server buffering is a security risk given untrusted clients. /// </para> /// </summary> /// <remarks> /// Defaults to 64 KiB. /// </remarks> public long? MaxWriteBufferSize { get; set; } = 64 * 1024; /// <summary> /// Inline application and transport continuations instead of dispatching to the threadpool. /// </summary> /// <remarks> /// This will run application code on the IO thread which is why this is unsafe. /// It is recommended to set the DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS environment variable to '1' when using this setting to also inline the completions /// at the runtime layer as well. /// This setting can make performance worse if there is expensive work that will end up holding onto the IO thread for longer than needed. /// Test to make sure this setting helps performance. /// </remarks> /// <remarks> /// Defaults to false. /// </remarks> public bool UnsafePreferInlineScheduling { get; set; } /// <summary> /// A function used to create a new <see cref="Socket"/> to listen with. If /// not set, <see cref="CreateDefaultBoundListenSocket" /> is used. /// </summary> /// <remarks> /// Implementors are expected to call <see cref="Socket.Bind"/> on the /// <see cref="Socket"/>. Please note that <see cref="CreateDefaultBoundListenSocket"/> /// calls <see cref="Socket.Bind"/> as part of its implementation, so implementors /// using this method do not need to call it again. /// </remarks> /// <remarks> /// Defaults to <see cref="CreateDefaultBoundListenSocket"/>. /// </remarks> public Func<EndPoint, Socket> CreateBoundListenSocket { get; set; } = CreateDefaultBoundListenSocket; /// <summary> /// Creates a default instance of <see cref="Socket"/> for the given <see cref="EndPoint"/> /// that can be used by a connection listener to listen for inbound requests. <see cref="Socket.Bind"/> /// is called by this method. /// </summary> /// <param name="endpoint"> /// An <see cref="EndPoint"/>. /// </param> /// <returns> /// A <see cref="Socket"/> instance. /// </returns> public static Socket CreateDefaultBoundListenSocket(EndPoint endpoint) { Socket listenSocket; switch (endpoint) { case FileHandleEndPoint fileHandle: // We're passing "ownsHandle: false" to avoid side-effects on the // handle when disposing the socket. // // When the non-owning SafeSocketHandle gets disposed (on .NET 7+), // on-going async operations are aborted. listenSocket = new Socket( new SafeSocketHandle((IntPtr)fileHandle.FileHandle, ownsHandle: false) ); break; case UnixDomainSocketEndPoint unix: listenSocket = new Socket(unix.AddressFamily, SocketType.Stream, ProtocolType.Unspecified); break; case IPEndPoint ip: listenSocket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Kestrel expects IPv6Any to bind to both IPv6 and IPv4 if (ip.Address.Equals(IPAddress.IPv6Any)) { listenSocket.DualMode = true; } break; default: listenSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); break; } // we only call Bind on sockets that were _not_ created // using a file handle; the handle is already bound // to an underlying socket so doing it again causes the // underlying PAL call to throw if (!(endpoint is FileHandleEndPoint)) { listenSocket.Bind(endpoint); } return listenSocket; } internal IMemoryPoolFactory<byte> MemoryPoolFactory { get; set; } = DefaultSimpleMemoryPoolFactory.Instance; }