2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
4
using System ;
5
- using System . Net ;
6
5
using System . Threading ;
7
6
using Microsoft . AspNetCore . Server . Kestrel . Filter ;
8
7
using Microsoft . AspNetCore . Server . Kestrel . Infrastructure ;
@@ -13,51 +12,53 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
13
12
{
14
13
public class Connection : ConnectionContext , IConnectionControl
15
14
{
15
+ // Base32 encoding - in ascii sort order for easy text based sorting
16
+ private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV" ;
17
+
16
18
private static readonly Action < UvStreamHandle , int , object > _readCallback =
17
19
( handle , status , state ) => ReadCallback ( handle , status , state ) ;
18
20
private static readonly Func < UvStreamHandle , int , object , Libuv . uv_buf_t > _allocCallback =
19
21
( handle , suggestedsize , state ) => AllocCallback ( handle , suggestedsize , state ) ;
20
22
21
- private static long _lastConnectionId ;
23
+ // Seed the _lastConnectionId for this application instance with
24
+ // the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001
25
+ // for a roughly increasing _requestId over restarts
26
+ private static long _lastConnectionId = DateTime . UtcNow . Ticks ;
22
27
23
28
private readonly UvStreamHandle _socket ;
24
29
private Frame _frame ;
25
30
private ConnectionFilterContext _filterContext ;
26
31
private LibuvStream _libuvStream ;
27
- private readonly long _connectionId ;
28
32
29
33
private readonly SocketInput _rawSocketInput ;
30
34
private readonly SocketOutput _rawSocketOutput ;
31
35
32
36
private readonly object _stateLock = new object ( ) ;
33
37
private ConnectionState _connectionState ;
34
38
35
- private IPEndPoint _remoteEndPoint ;
36
- private IPEndPoint _localEndPoint ;
37
-
38
39
public Connection ( ListenerContext context , UvStreamHandle socket ) : base ( context )
39
40
{
40
41
_socket = socket ;
41
42
ConnectionControl = this ;
42
43
43
- _connectionId = Interlocked . Increment ( ref _lastConnectionId ) ;
44
+ ConnectionId = GenerateConnectionId ( Interlocked . Increment ( ref _lastConnectionId ) ) ;
44
45
45
46
_rawSocketInput = new SocketInput ( Memory2 , ThreadPool ) ;
46
- _rawSocketOutput = new SocketOutput ( Thread , _socket , Memory2 , this , _connectionId , Log , ThreadPool , WriteReqPool ) ;
47
+ _rawSocketOutput = new SocketOutput ( Thread , _socket , Memory2 , this , ConnectionId , Log , ThreadPool , WriteReqPool ) ;
47
48
}
48
49
49
50
public void Start ( )
50
51
{
51
- Log . ConnectionStart ( _connectionId ) ;
52
+ Log . ConnectionStart ( ConnectionId ) ;
52
53
53
54
// Start socket prior to applying the ConnectionFilter
54
55
_socket . ReadStart ( _allocCallback , _readCallback , this ) ;
55
56
56
57
var tcpHandle = _socket as UvTcpHandle ;
57
58
if ( tcpHandle != null )
58
59
{
59
- _remoteEndPoint = tcpHandle . GetPeerIPEndPoint ( ) ;
60
- _localEndPoint = tcpHandle . GetSockIPEndPoint ( ) ;
60
+ RemoteEndPoint = tcpHandle . GetPeerIPEndPoint ( ) ;
61
+ LocalEndPoint = tcpHandle . GetSockIPEndPoint ( ) ;
61
62
}
62
63
63
64
// Don't initialize _frame until SocketInput and SocketOutput are set to their final values.
@@ -78,6 +79,7 @@ public void Start()
78
79
Connection = _libuvStream ,
79
80
Address = ServerAddress
80
81
} ;
82
+ PrepareRequest = _filterContext . PrepareRequest ;
81
83
82
84
try
83
85
{
@@ -170,12 +172,12 @@ private void OnRead(UvStreamHandle handle, int status)
170
172
171
173
if ( normalRead )
172
174
{
173
- Log . ConnectionRead ( _connectionId , readCount ) ;
175
+ Log . ConnectionRead ( ConnectionId , readCount ) ;
174
176
}
175
177
else
176
178
{
177
179
_socket . ReadStop ( ) ;
178
- Log . ConnectionReadFin ( _connectionId ) ;
180
+ Log . ConnectionReadFin ( ConnectionId ) ;
179
181
}
180
182
181
183
Exception error = null ;
@@ -194,18 +196,18 @@ private void OnRead(UvStreamHandle handle, int status)
194
196
195
197
private Frame CreateFrame ( )
196
198
{
197
- return FrameFactory ( this , _remoteEndPoint , _localEndPoint , _filterContext ? . PrepareRequest ) ;
199
+ return FrameFactory ( this ) ;
198
200
}
199
201
200
202
void IConnectionControl . Pause ( )
201
203
{
202
- Log . ConnectionPause ( _connectionId ) ;
204
+ Log . ConnectionPause ( ConnectionId ) ;
203
205
_socket . ReadStop ( ) ;
204
206
}
205
207
206
208
void IConnectionControl . Resume ( )
207
209
{
208
- Log . ConnectionResume ( _connectionId ) ;
210
+ Log . ConnectionResume ( ConnectionId ) ;
209
211
_socket . ReadStart ( _allocCallback , _readCallback , this ) ;
210
212
}
211
213
@@ -222,7 +224,7 @@ void IConnectionControl.End(ProduceEndType endType)
222
224
}
223
225
_connectionState = ConnectionState . Shutdown ;
224
226
225
- Log . ConnectionWriteFin ( _connectionId ) ;
227
+ Log . ConnectionWriteFin ( ConnectionId ) ;
226
228
_rawSocketOutput . End ( endType ) ;
227
229
break ;
228
230
case ProduceEndType . ConnectionKeepAlive :
@@ -231,7 +233,7 @@ void IConnectionControl.End(ProduceEndType endType)
231
233
return ;
232
234
}
233
235
234
- Log . ConnectionKeepAlive ( _connectionId ) ;
236
+ Log . ConnectionKeepAlive ( ConnectionId ) ;
235
237
break ;
236
238
case ProduceEndType . SocketDisconnect :
237
239
if ( _connectionState == ConnectionState . Disconnected )
@@ -240,13 +242,40 @@ void IConnectionControl.End(ProduceEndType endType)
240
242
}
241
243
_connectionState = ConnectionState . Disconnected ;
242
244
243
- Log . ConnectionDisconnect ( _connectionId ) ;
245
+ Log . ConnectionDisconnect ( ConnectionId ) ;
244
246
_rawSocketOutput . End ( endType ) ;
245
247
break ;
246
248
}
247
249
}
248
250
}
249
251
252
+ private static unsafe string GenerateConnectionId ( long id )
253
+ {
254
+ // The following routine is ~310% faster than calling long.ToString() on x64
255
+ // and ~600% faster than calling long.ToString() on x86 in tight loops of 1 million+ iterations
256
+ // See: https://github.com/aspnet/Hosting/pull/385
257
+
258
+ // stackalloc to allocate array on stack rather than heap
259
+ char * charBuffer = stackalloc char [ 13 ] ;
260
+
261
+ charBuffer [ 0 ] = _encode32Chars [ ( int ) ( id >> 60 ) & 31 ] ;
262
+ charBuffer [ 1 ] = _encode32Chars [ ( int ) ( id >> 55 ) & 31 ] ;
263
+ charBuffer [ 2 ] = _encode32Chars [ ( int ) ( id >> 50 ) & 31 ] ;
264
+ charBuffer [ 3 ] = _encode32Chars [ ( int ) ( id >> 45 ) & 31 ] ;
265
+ charBuffer [ 4 ] = _encode32Chars [ ( int ) ( id >> 40 ) & 31 ] ;
266
+ charBuffer [ 5 ] = _encode32Chars [ ( int ) ( id >> 35 ) & 31 ] ;
267
+ charBuffer [ 6 ] = _encode32Chars [ ( int ) ( id >> 30 ) & 31 ] ;
268
+ charBuffer [ 7 ] = _encode32Chars [ ( int ) ( id >> 25 ) & 31 ] ;
269
+ charBuffer [ 8 ] = _encode32Chars [ ( int ) ( id >> 20 ) & 31 ] ;
270
+ charBuffer [ 9 ] = _encode32Chars [ ( int ) ( id >> 15 ) & 31 ] ;
271
+ charBuffer [ 10 ] = _encode32Chars [ ( int ) ( id >> 10 ) & 31 ] ;
272
+ charBuffer [ 11 ] = _encode32Chars [ ( int ) ( id >> 5 ) & 31 ] ;
273
+ charBuffer [ 12 ] = _encode32Chars [ ( int ) id & 31 ] ;
274
+
275
+ // string ctor overload that takes char*
276
+ return new string ( charBuffer , 0 , 13 ) ;
277
+ }
278
+
250
279
private enum ConnectionState
251
280
{
252
281
Open ,
0 commit comments