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 System . Threading . Tasks ;
8
7
using Microsoft . AspNetCore . Server . Kestrel . Filter ;
@@ -14,18 +13,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
14
13
{
15
14
public class Connection : ConnectionContext , IConnectionControl
16
15
{
16
+ // Base32 encoding - in ascii sort order for easy text based sorting
17
+ private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV" ;
18
+
17
19
private static readonly Action < UvStreamHandle , int , object > _readCallback =
18
20
( handle , status , state ) => ReadCallback ( handle , status , state ) ;
19
21
private static readonly Func < UvStreamHandle , int , object , Libuv . uv_buf_t > _allocCallback =
20
22
( handle , suggestedsize , state ) => AllocCallback ( handle , suggestedsize , state ) ;
21
23
22
- private static long _lastConnectionId ;
24
+ // Seed the _lastConnectionId for this application instance with
25
+ // the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001
26
+ // for a roughly increasing _requestId over restarts
27
+ private static long _lastConnectionId = DateTime . UtcNow . Ticks ;
23
28
24
29
private readonly UvStreamHandle _socket ;
25
30
private Frame _frame ;
26
31
private ConnectionFilterContext _filterContext ;
27
32
private LibuvStream _libuvStream ;
28
- private readonly long _connectionId ;
29
33
30
34
private readonly SocketInput _rawSocketInput ;
31
35
private readonly SocketOutput _rawSocketOutput ;
@@ -34,19 +38,16 @@ public class Connection : ConnectionContext, IConnectionControl
34
38
private ConnectionState _connectionState ;
35
39
private TaskCompletionSource < object > _socketClosedTcs ;
36
40
37
- private IPEndPoint _remoteEndPoint ;
38
- private IPEndPoint _localEndPoint ;
39
-
40
41
public Connection ( ListenerContext context , UvStreamHandle socket ) : base ( context )
41
42
{
42
43
_socket = socket ;
43
44
socket . Connection = this ;
44
45
ConnectionControl = this ;
45
46
46
- _connectionId = Interlocked . Increment ( ref _lastConnectionId ) ;
47
+ ConnectionId = GenerateConnectionId ( Interlocked . Increment ( ref _lastConnectionId ) ) ;
47
48
48
49
_rawSocketInput = new SocketInput ( Memory2 , ThreadPool ) ;
49
- _rawSocketOutput = new SocketOutput ( Thread , _socket , Memory2 , this , _connectionId , Log , ThreadPool , WriteReqPool ) ;
50
+ _rawSocketOutput = new SocketOutput ( Thread , _socket , Memory2 , this , ConnectionId , Log , ThreadPool , WriteReqPool ) ;
50
51
}
51
52
52
53
// Internal for testing
@@ -56,16 +57,16 @@ internal Connection()
56
57
57
58
public void Start ( )
58
59
{
59
- Log . ConnectionStart ( _connectionId ) ;
60
+ Log . ConnectionStart ( ConnectionId ) ;
60
61
61
62
// Start socket prior to applying the ConnectionFilter
62
63
_socket . ReadStart ( _allocCallback , _readCallback , this ) ;
63
64
64
65
var tcpHandle = _socket as UvTcpHandle ;
65
66
if ( tcpHandle != null )
66
67
{
67
- _remoteEndPoint = tcpHandle . GetPeerIPEndPoint ( ) ;
68
- _localEndPoint = tcpHandle . GetSockIPEndPoint ( ) ;
68
+ RemoteEndPoint = tcpHandle . GetPeerIPEndPoint ( ) ;
69
+ LocalEndPoint = tcpHandle . GetSockIPEndPoint ( ) ;
69
70
}
70
71
71
72
// Don't initialize _frame until SocketInput and SocketOutput are set to their final values.
@@ -218,6 +219,8 @@ private void ApplyConnectionFilter()
218
219
SocketOutput = _rawSocketOutput ;
219
220
}
220
221
222
+ PrepareRequest = _filterContext . PrepareRequest ;
223
+
221
224
_frame = CreateFrame ( ) ;
222
225
_frame . Start ( ) ;
223
226
}
@@ -256,12 +259,12 @@ private void OnRead(UvStreamHandle handle, int status)
256
259
257
260
if ( normalRead )
258
261
{
259
- Log . ConnectionRead ( _connectionId , readCount ) ;
262
+ Log . ConnectionRead ( ConnectionId , readCount ) ;
260
263
}
261
264
else
262
265
{
263
266
_socket . ReadStop ( ) ;
264
- Log . ConnectionReadFin ( _connectionId ) ;
267
+ Log . ConnectionReadFin ( ConnectionId ) ;
265
268
}
266
269
267
270
Exception error = null ;
@@ -280,18 +283,18 @@ private void OnRead(UvStreamHandle handle, int status)
280
283
281
284
private Frame CreateFrame ( )
282
285
{
283
- return FrameFactory ( this , _remoteEndPoint , _localEndPoint , _filterContext ? . PrepareRequest ) ;
286
+ return FrameFactory ( this ) ;
284
287
}
285
288
286
289
void IConnectionControl . Pause ( )
287
290
{
288
- Log . ConnectionPause ( _connectionId ) ;
291
+ Log . ConnectionPause ( ConnectionId ) ;
289
292
_socket . ReadStop ( ) ;
290
293
}
291
294
292
295
void IConnectionControl . Resume ( )
293
296
{
294
- Log . ConnectionResume ( _connectionId ) ;
297
+ Log . ConnectionResume ( ConnectionId ) ;
295
298
_socket . ReadStart ( _allocCallback , _readCallback , this ) ;
296
299
}
297
300
@@ -307,7 +310,7 @@ void IConnectionControl.End(ProduceEndType endType)
307
310
return ;
308
311
}
309
312
310
- Log . ConnectionKeepAlive ( _connectionId ) ;
313
+ Log . ConnectionKeepAlive ( ConnectionId ) ;
311
314
break ;
312
315
case ProduceEndType . SocketShutdown :
313
316
case ProduceEndType . SocketDisconnect :
@@ -318,13 +321,40 @@ void IConnectionControl.End(ProduceEndType endType)
318
321
}
319
322
_connectionState = ConnectionState . Disconnecting ;
320
323
321
- Log . ConnectionDisconnect ( _connectionId ) ;
324
+ Log . ConnectionDisconnect ( ConnectionId ) ;
322
325
_rawSocketOutput . End ( endType ) ;
323
326
break ;
324
327
}
325
328
}
326
329
}
327
330
331
+ private static unsafe string GenerateConnectionId ( long id )
332
+ {
333
+ // The following routine is ~310% faster than calling long.ToString() on x64
334
+ // and ~600% faster than calling long.ToString() on x86 in tight loops of 1 million+ iterations
335
+ // See: https://github.com/aspnet/Hosting/pull/385
336
+
337
+ // stackalloc to allocate array on stack rather than heap
338
+ char * charBuffer = stackalloc char [ 13 ] ;
339
+
340
+ charBuffer [ 0 ] = _encode32Chars [ ( int ) ( id >> 60 ) & 31 ] ;
341
+ charBuffer [ 1 ] = _encode32Chars [ ( int ) ( id >> 55 ) & 31 ] ;
342
+ charBuffer [ 2 ] = _encode32Chars [ ( int ) ( id >> 50 ) & 31 ] ;
343
+ charBuffer [ 3 ] = _encode32Chars [ ( int ) ( id >> 45 ) & 31 ] ;
344
+ charBuffer [ 4 ] = _encode32Chars [ ( int ) ( id >> 40 ) & 31 ] ;
345
+ charBuffer [ 5 ] = _encode32Chars [ ( int ) ( id >> 35 ) & 31 ] ;
346
+ charBuffer [ 6 ] = _encode32Chars [ ( int ) ( id >> 30 ) & 31 ] ;
347
+ charBuffer [ 7 ] = _encode32Chars [ ( int ) ( id >> 25 ) & 31 ] ;
348
+ charBuffer [ 8 ] = _encode32Chars [ ( int ) ( id >> 20 ) & 31 ] ;
349
+ charBuffer [ 9 ] = _encode32Chars [ ( int ) ( id >> 15 ) & 31 ] ;
350
+ charBuffer [ 10 ] = _encode32Chars [ ( int ) ( id >> 10 ) & 31 ] ;
351
+ charBuffer [ 11 ] = _encode32Chars [ ( int ) ( id >> 5 ) & 31 ] ;
352
+ charBuffer [ 12 ] = _encode32Chars [ ( int ) id & 31 ] ;
353
+
354
+ // string ctor overload that takes char*
355
+ return new string ( charBuffer , 0 , 13 ) ;
356
+ }
357
+
328
358
private enum ConnectionState
329
359
{
330
360
CreatingFrame ,
0 commit comments