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

Commit

Permalink
Add IHttpConnectionFeature.ConnectionId.
Browse files Browse the repository at this point in the history
  • Loading branch information
Tratcher committed Feb 18, 2016
1 parent aa48ad2 commit aef612b
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 117 deletions.
66 changes: 48 additions & 18 deletions src/Microsoft.AspNetCore.Server.Kestrel/Http/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Filter;
Expand All @@ -14,18 +13,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http
{
public class Connection : ConnectionContext, IConnectionControl
{
// Base32 encoding - in ascii sort order for easy text based sorting
private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV";

private static readonly Action<UvStreamHandle, int, object> _readCallback =
(handle, status, state) => ReadCallback(handle, status, state);
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback =
(handle, suggestedsize, state) => AllocCallback(handle, suggestedsize, state);

private static long _lastConnectionId;
// Seed the _lastConnectionId for this application instance with
// the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001
// for a roughly increasing _requestId over restarts
private static long _lastConnectionId = DateTime.UtcNow.Ticks;

private readonly UvStreamHandle _socket;
private Frame _frame;
private ConnectionFilterContext _filterContext;
private LibuvStream _libuvStream;
private readonly long _connectionId;

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

private IPEndPoint _remoteEndPoint;
private IPEndPoint _localEndPoint;

public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
{
_socket = socket;
socket.Connection = this;
ConnectionControl = this;

_connectionId = Interlocked.Increment(ref _lastConnectionId);
ConnectionId = GenerateConnectionId(Interlocked.Increment(ref _lastConnectionId));

_rawSocketInput = new SocketInput(Memory2, ThreadPool);
_rawSocketOutput = new SocketOutput(Thread, _socket, Memory2, this, _connectionId, Log, ThreadPool, WriteReqPool);
_rawSocketOutput = new SocketOutput(Thread, _socket, Memory2, this, ConnectionId, Log, ThreadPool, WriteReqPool);
}

// Internal for testing
Expand All @@ -56,16 +57,16 @@ internal Connection()

public void Start()
{
Log.ConnectionStart(_connectionId);
Log.ConnectionStart(ConnectionId);

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

var tcpHandle = _socket as UvTcpHandle;
if (tcpHandle != null)
{
_remoteEndPoint = tcpHandle.GetPeerIPEndPoint();
_localEndPoint = tcpHandle.GetSockIPEndPoint();
RemoteEndPoint = tcpHandle.GetPeerIPEndPoint();
LocalEndPoint = tcpHandle.GetSockIPEndPoint();
}

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

PrepareRequest = _filterContext.PrepareRequest;

_frame = CreateFrame();
_frame.Start();
}
Expand Down Expand Up @@ -256,12 +259,12 @@ private void OnRead(UvStreamHandle handle, int status)

if (normalRead)
{
Log.ConnectionRead(_connectionId, readCount);
Log.ConnectionRead(ConnectionId, readCount);
}
else
{
_socket.ReadStop();
Log.ConnectionReadFin(_connectionId);
Log.ConnectionReadFin(ConnectionId);
}

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

private Frame CreateFrame()
{
return FrameFactory(this, _remoteEndPoint, _localEndPoint, _filterContext?.PrepareRequest);
return FrameFactory(this);
}

void IConnectionControl.Pause()
{
Log.ConnectionPause(_connectionId);
Log.ConnectionPause(ConnectionId);
_socket.ReadStop();
}

void IConnectionControl.Resume()
{
Log.ConnectionResume(_connectionId);
Log.ConnectionResume(ConnectionId);
_socket.ReadStart(_allocCallback, _readCallback, this);
}

Expand All @@ -307,7 +310,7 @@ void IConnectionControl.End(ProduceEndType endType)
return;
}

Log.ConnectionKeepAlive(_connectionId);
Log.ConnectionKeepAlive(ConnectionId);
break;
case ProduceEndType.SocketShutdown:
case ProduceEndType.SocketDisconnect:
Expand All @@ -318,13 +321,40 @@ void IConnectionControl.End(ProduceEndType endType)
}
_connectionState = ConnectionState.Disconnecting;

Log.ConnectionDisconnect(_connectionId);
Log.ConnectionDisconnect(ConnectionId);
_rawSocketOutput.End(endType);
break;
}
}
}

private static unsafe string GenerateConnectionId(long id)
{
// The following routine is ~310% faster than calling long.ToString() on x64
// and ~600% faster than calling long.ToString() on x86 in tight loops of 1 million+ iterations
// See: https://github.com/aspnet/Hosting/pull/385

// stackalloc to allocate array on stack rather than heap
char* charBuffer = stackalloc char[13];

charBuffer[0] = _encode32Chars[(int)(id >> 60) & 31];
charBuffer[1] = _encode32Chars[(int)(id >> 55) & 31];
charBuffer[2] = _encode32Chars[(int)(id >> 50) & 31];
charBuffer[3] = _encode32Chars[(int)(id >> 45) & 31];
charBuffer[4] = _encode32Chars[(int)(id >> 40) & 31];
charBuffer[5] = _encode32Chars[(int)(id >> 35) & 31];
charBuffer[6] = _encode32Chars[(int)(id >> 30) & 31];
charBuffer[7] = _encode32Chars[(int)(id >> 25) & 31];
charBuffer[8] = _encode32Chars[(int)(id >> 20) & 31];
charBuffer[9] = _encode32Chars[(int)(id >> 15) & 31];
charBuffer[10] = _encode32Chars[(int)(id >> 10) & 31];
charBuffer[11] = _encode32Chars[(int)(id >> 5) & 31];
charBuffer[12] = _encode32Chars[(int)id & 31];

// string ctor overload that takes char*
return new string(charBuffer, 0, 13);
}

private enum ConnectionState
{
CreatingFrame,
Expand Down
18 changes: 18 additions & 0 deletions src/Microsoft.AspNetCore.Server.Kestrel/Http/ConnectionContext.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Net;
using Microsoft.AspNetCore.Http.Features;

namespace Microsoft.AspNetCore.Server.Kestrel.Http
{
public class ConnectionContext : ListenerContext
Expand All @@ -18,10 +22,24 @@ public ConnectionContext(ConnectionContext context) : base(context)
SocketInput = context.SocketInput;
SocketOutput = context.SocketOutput;
ConnectionControl = context.ConnectionControl;
RemoteEndPoint = context.RemoteEndPoint;
LocalEndPoint = context.LocalEndPoint;
ConnectionId = context.ConnectionId;
PrepareRequest = context.PrepareRequest;
}

public SocketInput SocketInput { get; set; }

public ISocketOutput SocketOutput { get; set; }

public IConnectionControl ConnectionControl { get; set; }

public IPEndPoint RemoteEndPoint { get; set; }

public IPEndPoint LocalEndPoint { get; set; }

public string ConnectionId { get; set; }

public Action<IFeatureCollection> PrepareRequest { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ bool IHttpUpgradeFeature.IsUpgradableRequest

int IHttpConnectionFeature.LocalPort { get; set; }

string IHttpConnectionFeature.ConnectionId { get; set; }

object IFeatureCollection.this[Type key]
{
get { return FastFeatureGet(key); }
Expand Down
27 changes: 7 additions & 20 deletions src/Microsoft.AspNetCore.Server.Kestrel/Http/Frame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,11 @@ public abstract partial class Frame : FrameContext, IFrameControl

private HttpVersionType _httpVersion;

private readonly IPEndPoint _localEndPoint;
private readonly IPEndPoint _remoteEndPoint;
private readonly Action<IFeatureCollection> _prepareRequest;

private readonly string _pathBase;

public Frame(ConnectionContext context)
: this(context, remoteEndPoint: null, localEndPoint: null, prepareRequest: null)
{
}

public Frame(ConnectionContext context,
IPEndPoint remoteEndPoint,
IPEndPoint localEndPoint,
Action<IFeatureCollection> prepareRequest)
: base(context)
{
_remoteEndPoint = remoteEndPoint;
_localEndPoint = localEndPoint;
_prepareRequest = prepareRequest;
_pathBase = context.ServerAddress.PathBase;

FrameControl = this;
Expand Down Expand Up @@ -249,13 +234,15 @@ public void Reset()
ReasonPhrase = null;

var httpConnectionFeature = this as IHttpConnectionFeature;
httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address;
httpConnectionFeature.RemotePort = _remoteEndPoint?.Port ?? 0;
httpConnectionFeature.RemoteIpAddress = RemoteEndPoint?.Address;
httpConnectionFeature.RemotePort = RemoteEndPoint?.Port ?? 0;

httpConnectionFeature.LocalIpAddress = LocalEndPoint?.Address;
httpConnectionFeature.LocalPort = LocalEndPoint?.Port ?? 0;

httpConnectionFeature.LocalIpAddress = _localEndPoint?.Address;
httpConnectionFeature.LocalPort = _localEndPoint?.Port ?? 0;
httpConnectionFeature.ConnectionId = ConnectionId;

_prepareRequest?.Invoke(this);
PrepareRequest?.Invoke(this);

_manuallySetRequestAbortToken = null;
_abortedCts = null;
Expand Down
11 changes: 1 addition & 10 deletions src/Microsoft.AspNetCore.Server.Kestrel/Http/FrameOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,7 @@ public class Frame<TContext> : Frame

public Frame(IHttpApplication<TContext> application,
ConnectionContext context)
: this(application, context, remoteEndPoint: null, localEndPoint: null, prepareRequest: null)
{
}

public Frame(IHttpApplication<TContext> application,
ConnectionContext context,
IPEndPoint remoteEndPoint,
IPEndPoint localEndPoint,
Action<IFeatureCollection> prepareRequest)
: base(context, remoteEndPoint, localEndPoint, prepareRequest)
: base(context)
{
_application = application;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class SocketOutput : ISocketOutput
private readonly KestrelThread _thread;
private readonly UvStreamHandle _socket;
private readonly Connection _connection;
private readonly long _connectionId;
private readonly string _connectionId;
private readonly IKestrelTrace _log;
private readonly IThreadPool _threadPool;

Expand Down Expand Up @@ -58,7 +58,7 @@ public SocketOutput(
UvStreamHandle socket,
MemoryPool2 memory,
Connection connection,
long connectionId,
string connectionId,
IKestrelTrace log,
IThreadPool threadPool,
Queue<UvWriteReq> writeReqPool)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Infrastructure
{
public interface IKestrelTrace : ILogger
{
void ConnectionStart(long connectionId);
void ConnectionStart(string connectionId);

void ConnectionStop(long connectionId);
void ConnectionStop(string connectionId);

void ConnectionRead(long connectionId, int count);
void ConnectionRead(string connectionId, int count);

void ConnectionPause(long connectionId);
void ConnectionPause(string connectionId);

void ConnectionResume(long connectionId);
void ConnectionResume(string connectionId);

void ConnectionReadFin(long connectionId);
void ConnectionReadFin(string connectionId);

void ConnectionWriteFin(long connectionId);
void ConnectionWriteFin(string connectionId);

void ConnectionWroteFin(long connectionId, int status);
void ConnectionWroteFin(string connectionId, int status);

void ConnectionKeepAlive(long connectionId);
void ConnectionKeepAlive(string connectionId);

void ConnectionDisconnect(long connectionId);
void ConnectionDisconnect(string connectionId);

void ConnectionWrite(long connectionId, int count);
void ConnectionWrite(string connectionId, int count);

void ConnectionWriteCallback(long connectionId, int status);
void ConnectionWriteCallback(string connectionId, int status);

void ConnectionError(long connectionId, Exception ex);
void ConnectionError(string connectionId, Exception ex);

void ConnectionDisconnectedWrite(long connectionId, int count, Exception ex);
void ConnectionDisconnectedWrite(string connectionId, int count, Exception ex);

void NotAllConnectionsClosedGracefully();

Expand Down
Loading

0 comments on commit aef612b

Please sign in to comment.