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

Commit f1e1d3a

Browse files
committed
Add IHttpConnectionFeature.ConnectionId.
1 parent f89c959 commit f1e1d3a

File tree

15 files changed

+146
-119
lines changed

15 files changed

+146
-119
lines changed

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

Lines changed: 48 additions & 19 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 Microsoft.AspNetCore.Server.Kestrel.Filter;
87
using Microsoft.AspNetCore.Server.Kestrel.Infrastructure;
@@ -13,51 +12,53 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
1312
{
1413
public class Connection : ConnectionContext, IConnectionControl
1514
{
15+
// Base32 encoding - in ascii sort order for easy text based sorting
16+
private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
17+
1618
private static readonly Action<UvStreamHandle, int, object> _readCallback =
1719
(handle, status, state) => ReadCallback(handle, status, state);
1820
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback =
1921
(handle, suggestedsize, state) => AllocCallback(handle, suggestedsize, state);
2022

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

2328
private readonly UvStreamHandle _socket;
2429
private Frame _frame;
2530
private ConnectionFilterContext _filterContext;
2631
private LibuvStream _libuvStream;
27-
private readonly long _connectionId;
2832

2933
private readonly SocketInput _rawSocketInput;
3034
private readonly SocketOutput _rawSocketOutput;
3135

3236
private readonly object _stateLock = new object();
3337
private ConnectionState _connectionState;
3438

35-
private IPEndPoint _remoteEndPoint;
36-
private IPEndPoint _localEndPoint;
37-
3839
public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
3940
{
4041
_socket = socket;
4142
ConnectionControl = this;
4243

43-
_connectionId = Interlocked.Increment(ref _lastConnectionId);
44+
ConnectionId = GenerateConnectionId(Interlocked.Increment(ref _lastConnectionId));
4445

4546
_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);
4748
}
4849

4950
public void Start()
5051
{
51-
Log.ConnectionStart(_connectionId);
52+
Log.ConnectionStart(ConnectionId);
5253

5354
// Start socket prior to applying the ConnectionFilter
5455
_socket.ReadStart(_allocCallback, _readCallback, this);
5556

5657
var tcpHandle = _socket as UvTcpHandle;
5758
if (tcpHandle != null)
5859
{
59-
_remoteEndPoint = tcpHandle.GetPeerIPEndPoint();
60-
_localEndPoint = tcpHandle.GetSockIPEndPoint();
60+
RemoteEndPoint = tcpHandle.GetPeerIPEndPoint();
61+
LocalEndPoint = tcpHandle.GetSockIPEndPoint();
6162
}
6263

6364
// Don't initialize _frame until SocketInput and SocketOutput are set to their final values.
@@ -78,6 +79,7 @@ public void Start()
7879
Connection = _libuvStream,
7980
Address = ServerAddress
8081
};
82+
PrepareRequest = _filterContext.PrepareRequest;
8183

8284
try
8385
{
@@ -170,12 +172,12 @@ private void OnRead(UvStreamHandle handle, int status)
170172

171173
if (normalRead)
172174
{
173-
Log.ConnectionRead(_connectionId, readCount);
175+
Log.ConnectionRead(ConnectionId, readCount);
174176
}
175177
else
176178
{
177179
_socket.ReadStop();
178-
Log.ConnectionReadFin(_connectionId);
180+
Log.ConnectionReadFin(ConnectionId);
179181
}
180182

181183
Exception error = null;
@@ -194,18 +196,18 @@ private void OnRead(UvStreamHandle handle, int status)
194196

195197
private Frame CreateFrame()
196198
{
197-
return FrameFactory(this, _remoteEndPoint, _localEndPoint, _filterContext?.PrepareRequest);
199+
return FrameFactory(this);
198200
}
199201

200202
void IConnectionControl.Pause()
201203
{
202-
Log.ConnectionPause(_connectionId);
204+
Log.ConnectionPause(ConnectionId);
203205
_socket.ReadStop();
204206
}
205207

206208
void IConnectionControl.Resume()
207209
{
208-
Log.ConnectionResume(_connectionId);
210+
Log.ConnectionResume(ConnectionId);
209211
_socket.ReadStart(_allocCallback, _readCallback, this);
210212
}
211213

@@ -222,7 +224,7 @@ void IConnectionControl.End(ProduceEndType endType)
222224
}
223225
_connectionState = ConnectionState.Shutdown;
224226

225-
Log.ConnectionWriteFin(_connectionId);
227+
Log.ConnectionWriteFin(ConnectionId);
226228
_rawSocketOutput.End(endType);
227229
break;
228230
case ProduceEndType.ConnectionKeepAlive:
@@ -231,7 +233,7 @@ void IConnectionControl.End(ProduceEndType endType)
231233
return;
232234
}
233235

234-
Log.ConnectionKeepAlive(_connectionId);
236+
Log.ConnectionKeepAlive(ConnectionId);
235237
break;
236238
case ProduceEndType.SocketDisconnect:
237239
if (_connectionState == ConnectionState.Disconnected)
@@ -240,13 +242,40 @@ void IConnectionControl.End(ProduceEndType endType)
240242
}
241243
_connectionState = ConnectionState.Disconnected;
242244

243-
Log.ConnectionDisconnect(_connectionId);
245+
Log.ConnectionDisconnect(ConnectionId);
244246
_rawSocketOutput.End(endType);
245247
break;
246248
}
247249
}
248250
}
249251

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+
250279
private enum ConnectionState
251280
{
252281
Open,

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
@@ -71,26 +71,11 @@ public abstract partial class Frame : FrameContext, IFrameControl
7171

7272
private HttpVersionType _httpVersion;
7373

74-
private readonly IPEndPoint _localEndPoint;
75-
private readonly IPEndPoint _remoteEndPoint;
76-
private readonly Action<IFeatureCollection> _prepareRequest;
77-
7874
private readonly string _pathBase;
7975

8076
public Frame(ConnectionContext context)
81-
: this(context, remoteEndPoint: null, localEndPoint: null, prepareRequest: null)
82-
{
83-
}
84-
85-
public Frame(ConnectionContext context,
86-
IPEndPoint remoteEndPoint,
87-
IPEndPoint localEndPoint,
88-
Action<IFeatureCollection> prepareRequest)
8977
: base(context)
9078
{
91-
_remoteEndPoint = remoteEndPoint;
92-
_localEndPoint = localEndPoint;
93-
_prepareRequest = prepareRequest;
9479
_pathBase = context.ServerAddress.PathBase;
9580
if (ReuseStreams)
9681
{
@@ -227,13 +212,15 @@ public void Reset()
227212
DuplexStream = null;
228213

229214
var httpConnectionFeature = this as IHttpConnectionFeature;
230-
httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address;
231-
httpConnectionFeature.RemotePort = _remoteEndPoint?.Port ?? 0;
215+
httpConnectionFeature.RemoteIpAddress = RemoteEndPoint?.Address;
216+
httpConnectionFeature.RemotePort = RemoteEndPoint?.Port ?? 0;
217+
218+
httpConnectionFeature.LocalIpAddress = LocalEndPoint?.Address;
219+
httpConnectionFeature.LocalPort = LocalEndPoint?.Port ?? 0;
232220

233-
httpConnectionFeature.LocalIpAddress = _localEndPoint?.Address;
234-
httpConnectionFeature.LocalPort = _localEndPoint?.Port ?? 0;
221+
httpConnectionFeature.ConnectionId = ConnectionId;
235222

236-
_prepareRequest?.Invoke(this);
223+
PrepareRequest?.Invoke(this);
237224

238225
_manuallySetRequestAbortToken = null;
239226
_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 ApplicationError(Exception ex);
3737
}

0 commit comments

Comments
 (0)