Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit aef612b

Browse files
committed
Add IHttpConnectionFeature.ConnectionId.
1 parent aa48ad2 commit aef612b

File tree

14 files changed

+145
-117
lines changed

14 files changed

+145
-117
lines changed

src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5-
using System.Net;
65
using System.Threading;
76
using System.Threading.Tasks;
87
using Microsoft.AspNetCore.Server.Kestrel.Filter;
@@ -14,18 +13,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
1413
{
1514
public class Connection : ConnectionContext, IConnectionControl
1615
{
16+
// Base32 encoding - in ascii sort order for easy text based sorting
17+
private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
18+
1719
private static readonly Action<UvStreamHandle, int, object> _readCallback =
1820
(handle, status, state) => ReadCallback(handle, status, state);
1921
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback =
2022
(handle, suggestedsize, state) => AllocCallback(handle, suggestedsize, state);
2123

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;
2328

2429
private readonly UvStreamHandle _socket;
2530
private Frame _frame;
2631
private ConnectionFilterContext _filterContext;
2732
private LibuvStream _libuvStream;
28-
private readonly long _connectionId;
2933

3034
private readonly SocketInput _rawSocketInput;
3135
private readonly SocketOutput _rawSocketOutput;
@@ -34,19 +38,16 @@ public class Connection : ConnectionContext, IConnectionControl
3438
private ConnectionState _connectionState;
3539
private TaskCompletionSource<object> _socketClosedTcs;
3640

37-
private IPEndPoint _remoteEndPoint;
38-
private IPEndPoint _localEndPoint;
39-
4041
public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
4142
{
4243
_socket = socket;
4344
socket.Connection = this;
4445
ConnectionControl = this;
4546

46-
_connectionId = Interlocked.Increment(ref _lastConnectionId);
47+
ConnectionId = GenerateConnectionId(Interlocked.Increment(ref _lastConnectionId));
4748

4849
_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);
5051
}
5152

5253
// Internal for testing
@@ -56,16 +57,16 @@ internal Connection()
5657

5758
public void Start()
5859
{
59-
Log.ConnectionStart(_connectionId);
60+
Log.ConnectionStart(ConnectionId);
6061

6162
// Start socket prior to applying the ConnectionFilter
6263
_socket.ReadStart(_allocCallback, _readCallback, this);
6364

6465
var tcpHandle = _socket as UvTcpHandle;
6566
if (tcpHandle != null)
6667
{
67-
_remoteEndPoint = tcpHandle.GetPeerIPEndPoint();
68-
_localEndPoint = tcpHandle.GetSockIPEndPoint();
68+
RemoteEndPoint = tcpHandle.GetPeerIPEndPoint();
69+
LocalEndPoint = tcpHandle.GetSockIPEndPoint();
6970
}
7071

7172
// Don't initialize _frame until SocketInput and SocketOutput are set to their final values.
@@ -218,6 +219,8 @@ private void ApplyConnectionFilter()
218219
SocketOutput = _rawSocketOutput;
219220
}
220221

222+
PrepareRequest = _filterContext.PrepareRequest;
223+
221224
_frame = CreateFrame();
222225
_frame.Start();
223226
}
@@ -256,12 +259,12 @@ private void OnRead(UvStreamHandle handle, int status)
256259

257260
if (normalRead)
258261
{
259-
Log.ConnectionRead(_connectionId, readCount);
262+
Log.ConnectionRead(ConnectionId, readCount);
260263
}
261264
else
262265
{
263266
_socket.ReadStop();
264-
Log.ConnectionReadFin(_connectionId);
267+
Log.ConnectionReadFin(ConnectionId);
265268
}
266269

267270
Exception error = null;
@@ -280,18 +283,18 @@ private void OnRead(UvStreamHandle handle, int status)
280283

281284
private Frame CreateFrame()
282285
{
283-
return FrameFactory(this, _remoteEndPoint, _localEndPoint, _filterContext?.PrepareRequest);
286+
return FrameFactory(this);
284287
}
285288

286289
void IConnectionControl.Pause()
287290
{
288-
Log.ConnectionPause(_connectionId);
291+
Log.ConnectionPause(ConnectionId);
289292
_socket.ReadStop();
290293
}
291294

292295
void IConnectionControl.Resume()
293296
{
294-
Log.ConnectionResume(_connectionId);
297+
Log.ConnectionResume(ConnectionId);
295298
_socket.ReadStart(_allocCallback, _readCallback, this);
296299
}
297300

@@ -307,7 +310,7 @@ void IConnectionControl.End(ProduceEndType endType)
307310
return;
308311
}
309312

310-
Log.ConnectionKeepAlive(_connectionId);
313+
Log.ConnectionKeepAlive(ConnectionId);
311314
break;
312315
case ProduceEndType.SocketShutdown:
313316
case ProduceEndType.SocketDisconnect:
@@ -318,13 +321,40 @@ void IConnectionControl.End(ProduceEndType endType)
318321
}
319322
_connectionState = ConnectionState.Disconnecting;
320323

321-
Log.ConnectionDisconnect(_connectionId);
324+
Log.ConnectionDisconnect(ConnectionId);
322325
_rawSocketOutput.End(endType);
323326
break;
324327
}
325328
}
326329
}
327330

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+
328358
private enum ConnectionState
329359
{
330360
CreatingFrame,

src/Microsoft.AspNetCore.Server.Kestrel/Http/ConnectionContext.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
5+
using System.Net;
6+
using Microsoft.AspNetCore.Http.Features;
7+
48
namespace Microsoft.AspNetCore.Server.Kestrel.Http
59
{
610
public class ConnectionContext : ListenerContext
@@ -18,10 +22,24 @@ public ConnectionContext(ConnectionContext context) : base(context)
1822
SocketInput = context.SocketInput;
1923
SocketOutput = context.SocketOutput;
2024
ConnectionControl = context.ConnectionControl;
25+
RemoteEndPoint = context.RemoteEndPoint;
26+
LocalEndPoint = context.LocalEndPoint;
27+
ConnectionId = context.ConnectionId;
28+
PrepareRequest = context.PrepareRequest;
2129
}
2230

2331
public SocketInput SocketInput { get; set; }
32+
2433
public ISocketOutput SocketOutput { get; set; }
34+
2535
public IConnectionControl ConnectionControl { get; set; }
36+
37+
public IPEndPoint RemoteEndPoint { get; set; }
38+
39+
public IPEndPoint LocalEndPoint { get; set; }
40+
41+
public string ConnectionId { get; set; }
42+
43+
public Action<IFeatureCollection> PrepareRequest { get; set; }
2644
}
2745
}

src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.FeatureCollection.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ bool IHttpUpgradeFeature.IsUpgradableRequest
272272

273273
int IHttpConnectionFeature.LocalPort { get; set; }
274274

275+
string IHttpConnectionFeature.ConnectionId { get; set; }
276+
275277
object IFeatureCollection.this[Type key]
276278
{
277279
get { return FastFeatureGet(key); }

src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,11 @@ public abstract partial class Frame : FrameContext, IFrameControl
6767

6868
private HttpVersionType _httpVersion;
6969

70-
private readonly IPEndPoint _localEndPoint;
71-
private readonly IPEndPoint _remoteEndPoint;
72-
private readonly Action<IFeatureCollection> _prepareRequest;
73-
7470
private readonly string _pathBase;
7571

7672
public Frame(ConnectionContext context)
77-
: this(context, remoteEndPoint: null, localEndPoint: null, prepareRequest: null)
78-
{
79-
}
80-
81-
public Frame(ConnectionContext context,
82-
IPEndPoint remoteEndPoint,
83-
IPEndPoint localEndPoint,
84-
Action<IFeatureCollection> prepareRequest)
8573
: base(context)
8674
{
87-
_remoteEndPoint = remoteEndPoint;
88-
_localEndPoint = localEndPoint;
89-
_prepareRequest = prepareRequest;
9075
_pathBase = context.ServerAddress.PathBase;
9176

9277
FrameControl = this;
@@ -249,13 +234,15 @@ public void Reset()
249234
ReasonPhrase = null;
250235

251236
var httpConnectionFeature = this as IHttpConnectionFeature;
252-
httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address;
253-
httpConnectionFeature.RemotePort = _remoteEndPoint?.Port ?? 0;
237+
httpConnectionFeature.RemoteIpAddress = RemoteEndPoint?.Address;
238+
httpConnectionFeature.RemotePort = RemoteEndPoint?.Port ?? 0;
239+
240+
httpConnectionFeature.LocalIpAddress = LocalEndPoint?.Address;
241+
httpConnectionFeature.LocalPort = LocalEndPoint?.Port ?? 0;
254242

255-
httpConnectionFeature.LocalIpAddress = _localEndPoint?.Address;
256-
httpConnectionFeature.LocalPort = _localEndPoint?.Port ?? 0;
243+
httpConnectionFeature.ConnectionId = ConnectionId;
257244

258-
_prepareRequest?.Invoke(this);
245+
PrepareRequest?.Invoke(this);
259246

260247
_manuallySetRequestAbortToken = null;
261248
_abortedCts = null;

src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameOfT.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,7 @@ public class Frame<TContext> : Frame
1717

1818
public Frame(IHttpApplication<TContext> application,
1919
ConnectionContext context)
20-
: this(application, context, remoteEndPoint: null, localEndPoint: null, prepareRequest: null)
21-
{
22-
}
23-
24-
public Frame(IHttpApplication<TContext> application,
25-
ConnectionContext context,
26-
IPEndPoint remoteEndPoint,
27-
IPEndPoint localEndPoint,
28-
Action<IFeatureCollection> prepareRequest)
29-
: base(context, remoteEndPoint, localEndPoint, prepareRequest)
20+
: base(context)
3021
{
3122
_application = application;
3223
}

src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketOutput.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class SocketOutput : ISocketOutput
2626
private readonly KestrelThread _thread;
2727
private readonly UvStreamHandle _socket;
2828
private readonly Connection _connection;
29-
private readonly long _connectionId;
29+
private readonly string _connectionId;
3030
private readonly IKestrelTrace _log;
3131
private readonly IThreadPool _threadPool;
3232

@@ -58,7 +58,7 @@ public SocketOutput(
5858
UvStreamHandle socket,
5959
MemoryPool2 memory,
6060
Connection connection,
61-
long connectionId,
61+
string connectionId,
6262
IKestrelTrace log,
6363
IThreadPool threadPool,
6464
Queue<UvWriteReq> writeReqPool)

src/Microsoft.AspNetCore.Server.Kestrel/Infrastructure/IKestrelTrace.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
55
{
66
public interface IKestrelTrace : ILogger
77
{
8-
void ConnectionStart(long connectionId);
8+
void ConnectionStart(string connectionId);
99

10-
void ConnectionStop(long connectionId);
10+
void ConnectionStop(string connectionId);
1111

12-
void ConnectionRead(long connectionId, int count);
12+
void ConnectionRead(string connectionId, int count);
1313

14-
void ConnectionPause(long connectionId);
14+
void ConnectionPause(string connectionId);
1515

16-
void ConnectionResume(long connectionId);
16+
void ConnectionResume(string connectionId);
1717

18-
void ConnectionReadFin(long connectionId);
18+
void ConnectionReadFin(string connectionId);
1919

20-
void ConnectionWriteFin(long connectionId);
20+
void ConnectionWriteFin(string connectionId);
2121

22-
void ConnectionWroteFin(long connectionId, int status);
22+
void ConnectionWroteFin(string connectionId, int status);
2323

24-
void ConnectionKeepAlive(long connectionId);
24+
void ConnectionKeepAlive(string connectionId);
2525

26-
void ConnectionDisconnect(long connectionId);
26+
void ConnectionDisconnect(string connectionId);
2727

28-
void ConnectionWrite(long connectionId, int count);
28+
void ConnectionWrite(string connectionId, int count);
2929

30-
void ConnectionWriteCallback(long connectionId, int status);
30+
void ConnectionWriteCallback(string connectionId, int status);
3131

32-
void ConnectionError(long connectionId, Exception ex);
32+
void ConnectionError(string connectionId, Exception ex);
3333

34-
void ConnectionDisconnectedWrite(long connectionId, int count, Exception ex);
34+
void ConnectionDisconnectedWrite(string connectionId, int count, Exception ex);
3535

3636
void NotAllConnectionsClosedGracefully();
3737

0 commit comments

Comments
 (0)