-
Notifications
You must be signed in to change notification settings - Fork 9.8k
/
SocketTransportOptions.cs
170 lines (151 loc) · 6.59 KB
/
SocketTransportOptions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// 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.Net;
using System.Net.Sockets;
using Microsoft.AspNetCore.Connections;
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 <see cref="Environment.ProcessorCount" /> rounded down and clamped between 1 and 16.
/// </remarks>
public int IOQueueCount { get; set; } = Math.Min(Environment.ProcessorCount, 16);
/// <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 Func<MemoryPool<byte>> MemoryPoolFactory { get; set; } = System.Buffers.PinnedBlockMemoryPoolFactory.Create;
}