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

Commit 6fa001f

Browse files
committed
Make Frame implements IHttpConnectionFeature
Provide RemoteIPAddress as well as RemotePort
1 parent c1b21b8 commit 6fa001f

File tree

10 files changed

+295
-40
lines changed

10 files changed

+295
-40
lines changed

samples/SampleApp/Startup.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IAp
5252
context.Request.Path,
5353
context.Request.QueryString);
5454

55+
var connectionFeature = context.Connection;
56+
Console.WriteLine($"Peer: {connectionFeature.RemoteIpAddress?.ToString()} {connectionFeature.RemotePort}");
57+
Console.WriteLine($"Sock: {connectionFeature.LocalIpAddress?.ToString()} {connectionFeature.LocalPort}");
58+
Console.WriteLine($"IsLocal: {connectionFeature.IsLocal}");
59+
5560
context.Response.ContentLength = 11;
5661
context.Response.ContentType = "text/plain";
5762
await context.Response.WriteAsync("Hello world");

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
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;
56
using System.Threading;
67
using Microsoft.AspNet.Server.Kestrel.Filter;
78
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
@@ -28,6 +29,9 @@ public class Connection : ConnectionContext, IConnectionControl
2829
private readonly object _stateLock = new object();
2930
private ConnectionState _connectionState;
3031

32+
private IPEndPoint _remoteEndPoint;
33+
private IPEndPoint _localEndPoint;
34+
3135
public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
3236
{
3337
_socket = socket;
@@ -46,13 +50,20 @@ public void Start()
4650
// Start socket prior to applying the ConnectionFilter
4751
_socket.ReadStart(_allocCallback, _readCallback, this);
4852

53+
var tcpHandle = _socket as UvTcpHandle;
54+
if (tcpHandle != null)
55+
{
56+
_remoteEndPoint = tcpHandle.GetPeerIPEndPoint();
57+
_localEndPoint = tcpHandle.GetSockIPEndPoint();
58+
}
59+
4960
// Don't initialize _frame until SocketInput and SocketOutput are set to their final values.
5061
if (ConnectionFilter == null)
5162
{
5263
SocketInput = _rawSocketInput;
5364
SocketOutput = _rawSocketOutput;
5465

55-
_frame = new Frame(this);
66+
_frame = CreateFrame();
5667
_frame.Start();
5768
}
5869
else
@@ -94,7 +105,7 @@ private void ApplyConnectionFilter()
94105
SocketInput = filteredStreamAdapter.SocketInput;
95106
SocketOutput = filteredStreamAdapter.SocketOutput;
96107

97-
_frame = new Frame(this);
108+
_frame = CreateFrame();
98109
_frame.Start();
99110
}
100111

@@ -142,6 +153,11 @@ private void OnRead(UvStreamHandle handle, int status)
142153
_rawSocketInput.IncomingComplete(readCount, error);
143154
}
144155

156+
private Frame CreateFrame()
157+
{
158+
return new Frame(this, _remoteEndPoint, _localEndPoint);
159+
}
160+
145161
void IConnectionControl.Pause()
146162
{
147163
Log.ConnectionPause(_connectionId);

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66
using System.Collections.Generic;
77
using System.IO;
88
using System.Linq;
9+
using System.Net;
910
using System.Threading.Tasks;
1011
using Microsoft.AspNet.Http;
1112
using Microsoft.AspNet.Http.Features;
1213
using Microsoft.Extensions.Primitives;
1314

1415
namespace Microsoft.AspNet.Server.Kestrel.Http
1516
{
16-
public partial class Frame : IFeatureCollection, IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature
17+
public partial class Frame : IFeatureCollection,
18+
IHttpRequestFeature,
19+
IHttpResponseFeature,
20+
IHttpUpgradeFeature,
21+
IHttpConnectionFeature
1722
{
1823
// NOTE: When feature interfaces are added to or removed from this Frame class implementation,
1924
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
@@ -246,6 +251,16 @@ bool IHttpUpgradeFeature.IsUpgradableRequest
246251

247252
int IFeatureCollection.Revision => _featureRevision;
248253

254+
IPAddress IHttpConnectionFeature.RemoteIpAddress { get; set; }
255+
256+
IPAddress IHttpConnectionFeature.LocalIpAddress { get; set; }
257+
258+
int IHttpConnectionFeature.RemotePort { get; set; }
259+
260+
int IHttpConnectionFeature.LocalPort { get; set; }
261+
262+
bool IHttpConnectionFeature.IsLocal { get; set; }
263+
249264
object IFeatureCollection.this[Type key]
250265
{
251266
get { return FastFeatureGet(key); }

src/Microsoft.AspNet.Server.Kestrel/Http/Frame.Generated.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ private void FastReset()
4545
_currentIHttpRequestFeature = this;
4646
_currentIHttpResponseFeature = this;
4747
_currentIHttpUpgradeFeature = this;
48+
_currentIHttpConnectionFeature = this;
4849

4950
_currentIHttpRequestIdentifierFeature = null;
5051
_currentIServiceProvidersFeature = null;
5152
_currentIHttpRequestLifetimeFeature = null;
52-
_currentIHttpConnectionFeature = null;
5353
_currentIHttpAuthenticationFeature = null;
5454
_currentIQueryFeature = null;
5555
_currentIFormFeature = null;

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

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
using System.Collections.Generic;
66
using System.IO;
77
using System.Linq;
8+
using System.Net;
89
using System.Text;
910
using System.Threading;
1011
using System.Threading.Tasks;
1112
using Microsoft.AspNet.Http;
13+
using Microsoft.AspNet.Http.Features;
1214
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
1315
using Microsoft.Extensions.Logging;
1416
using Microsoft.Extensions.Primitives;
@@ -44,8 +46,22 @@ public partial class Frame : FrameContext, IFrameControl
4446
private bool _autoChunk;
4547
private Exception _applicationException;
4648

47-
public Frame(ConnectionContext context) : base(context)
49+
private readonly IPEndPoint _localEndPoint;
50+
private readonly IPEndPoint _remoteEndPoint;
51+
52+
public Frame(ConnectionContext context)
53+
: this(context, remoteEndPoint: null, localEndPoint: null)
54+
{
55+
}
56+
57+
public Frame(ConnectionContext context,
58+
IPEndPoint remoteEndPoint,
59+
IPEndPoint localEndPoint)
60+
: base(context)
4861
{
62+
_remoteEndPoint = remoteEndPoint;
63+
_localEndPoint = localEndPoint;
64+
4965
FrameControl = this;
5066
Reset();
5167
}
@@ -99,6 +115,21 @@ public void Reset()
99115
ResponseBody = null;
100116
DuplexStream = null;
101117

118+
var httpConnectionFeature = this as IHttpConnectionFeature;
119+
httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address;
120+
httpConnectionFeature.RemotePort = _remoteEndPoint?.Port ?? 0;
121+
122+
httpConnectionFeature.LocalIpAddress = _localEndPoint?.Address;
123+
httpConnectionFeature.LocalPort = _localEndPoint?.Port ?? 0;
124+
125+
if (_remoteEndPoint != null && _localEndPoint != null)
126+
{
127+
httpConnectionFeature.IsLocal = _remoteEndPoint.Address.Equals(_localEndPoint.Address);
128+
}
129+
else
130+
{
131+
httpConnectionFeature.IsLocal = false;
132+
}
102133
}
103134

104135
public void ResetResponseHeaders()
@@ -123,7 +154,7 @@ public void Start()
123154
/// <summary>
124155
/// Should be called when the server wants to initiate a shutdown. The Task returned will
125156
/// become complete when the RequestProcessingAsync function has exited. It is expected that
126-
/// Stop will be called on all active connections, and Task.WaitAll() will be called on every
157+
/// Stop will be called on all active connections, and Task.WaitAll() will be called on every
127158
/// return value.
128159
/// </summary>
129160
public Task Stop()
@@ -136,7 +167,7 @@ public Task Stop()
136167
}
137168

138169
/// <summary>
139-
/// Primary loop which consumes socket input, parses it for protocol framing, and invokes the
170+
/// Primary loop which consumes socket input, parses it for protocol framing, and invokes the
140171
/// application delegate for as long as the socket is intended to remain open.
141172
/// The resulting Task from this loop is preserved in a field which is used when the server needs
142173
/// to drain and close all currently active connections.
@@ -731,7 +762,7 @@ public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders req
731762

732763
if (chSecond != '\n')
733764
{
734-
// "\r" was all by itself, move just after it and try again
765+
// "\r" was all by itself, move just after it and try again
735766
scan = endValue;
736767
scan.Take();
737768
continue;
@@ -740,7 +771,7 @@ public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders req
740771
var chThird = scan.Peek();
741772
if (chThird == ' ' || chThird == '\t')
742773
{
743-
// special case, "\r\n " or "\r\n\t".
774+
// special case, "\r\n " or "\r\n\t".
744775
// this is considered wrapping"linear whitespace" and is actually part of the header value
745776
// continue past this for the next
746777
wrapping = true;

src/Microsoft.AspNet.Server.Kestrel/Networking/Libuv.cs

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ public Libuv()
5656
_uv_req_size = NativeDarwinMonoMethods.uv_req_size;
5757
_uv_ip4_addr = NativeDarwinMonoMethods.uv_ip4_addr;
5858
_uv_ip6_addr = NativeDarwinMonoMethods.uv_ip6_addr;
59+
_uv_tcp_getpeername = NativeDarwinMonoMethods.uv_tcp_getpeername;
60+
_uv_tcp_getsockname = NativeDarwinMonoMethods.uv_tcp_getsockname;
5961
_uv_walk = NativeDarwinMonoMethods.uv_walk;
6062
}
6163
else
@@ -95,6 +97,8 @@ public Libuv()
9597
_uv_req_size = NativeMethods.uv_req_size;
9698
_uv_ip4_addr = NativeMethods.uv_ip4_addr;
9799
_uv_ip6_addr = NativeMethods.uv_ip6_addr;
100+
_uv_tcp_getpeername = NativeMethods.uv_tcp_getpeername;
101+
_uv_tcp_getsockname = NativeMethods.uv_tcp_getsockname;
98102
_uv_walk = NativeMethods.uv_walk;
99103
}
100104
}
@@ -206,9 +210,9 @@ public void tcp_init(UvLoopHandle loop, UvTcpHandle handle)
206210
Check(_uv_tcp_init(loop, handle));
207211
}
208212

209-
protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref sockaddr addr, int flags);
213+
protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags);
210214
protected uv_tcp_bind_func _uv_tcp_bind;
211-
public void tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags)
215+
public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags)
212216
{
213217
handle.Validate();
214218
Check(_uv_tcp_bind(handle, ref addr, flags));
@@ -365,16 +369,16 @@ public int req_size(RequestType reqType)
365369
return _uv_req_size(reqType);
366370
}
367371

368-
protected delegate int uv_ip4_addr_func(string ip, int port, out sockaddr addr);
372+
protected delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr);
369373
protected uv_ip4_addr_func _uv_ip4_addr;
370-
public int ip4_addr(string ip, int port, out sockaddr addr, out Exception error)
374+
public int ip4_addr(string ip, int port, out SockAddr addr, out Exception error)
371375
{
372376
return Check(_uv_ip4_addr(ip, port, out addr), out error);
373377
}
374378

375-
protected delegate int uv_ip6_addr_func(string ip, int port, out sockaddr addr);
379+
protected delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr);
376380
protected uv_ip6_addr_func _uv_ip6_addr;
377-
public int ip6_addr(string ip, int port, out sockaddr addr, out Exception error)
381+
public int ip6_addr(string ip, int port, out SockAddr addr, out Exception error)
378382
{
379383
return Check(_uv_ip6_addr(ip, port, out addr), out error);
380384
}
@@ -388,24 +392,25 @@ unsafe public void walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg)
388392
_uv_walk(loop, walk_cb, arg);
389393
}
390394

391-
public uv_buf_t buf_init(IntPtr memory, int len)
395+
public delegate int uv_tcp_getsockname_func(UvTcpHandle handle, out SockAddr addr, ref int namelen);
396+
protected uv_tcp_getsockname_func _uv_tcp_getsockname;
397+
public void tcp_getsockname(UvTcpHandle handle, out SockAddr addr, ref int namelen)
392398
{
393-
return new uv_buf_t(memory, len, IsWindows);
399+
handle.Validate();
400+
Check(_uv_tcp_getsockname(handle, out addr, ref namelen));
394401
}
395402

396-
public struct sockaddr
403+
public delegate int uv_tcp_getpeername_func(UvTcpHandle handle, out SockAddr addr, ref int namelen);
404+
protected uv_tcp_getpeername_func _uv_tcp_getpeername;
405+
public void tcp_getpeername(UvTcpHandle handle, out SockAddr addr, ref int namelen)
397406
{
398-
// this type represents native memory occupied by sockaddr struct
399-
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
400-
// although the c/c++ header defines it as a 2-byte short followed by a 14-byte array,
401-
// the simplest way to reserve the same size in c# is with four nameless long values
402-
403-
private long _field0;
404-
private long _field1;
405-
private long _field2;
406-
private long _field3;
407+
handle.Validate();
408+
Check(_uv_tcp_getpeername(handle, out addr, ref namelen));
409+
}
407410

408-
public sockaddr(long ignored) { _field3 = _field0 = _field1 = _field2 = _field3 = 0; }
411+
public uv_buf_t buf_init(IntPtr memory, int len)
412+
{
413+
return new uv_buf_t(memory, len, IsWindows);
409414
}
410415

411416
public struct uv_buf_t
@@ -504,7 +509,7 @@ private static class NativeMethods
504509
public static extern int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
505510

506511
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
507-
public static extern int uv_tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags);
512+
public static extern int uv_tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags);
508513

509514
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
510515
public static extern int uv_tcp_open(UvTcpHandle handle, IntPtr hSocket);
@@ -564,10 +569,16 @@ private static class NativeMethods
564569
public static extern int uv_req_size(RequestType reqType);
565570

566571
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
567-
public static extern int uv_ip4_addr(string ip, int port, out sockaddr addr);
572+
public static extern int uv_ip4_addr(string ip, int port, out SockAddr addr);
568573

569574
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
570-
public static extern int uv_ip6_addr(string ip, int port, out sockaddr addr);
575+
public static extern int uv_ip6_addr(string ip, int port, out SockAddr addr);
576+
577+
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
578+
public static extern int uv_tcp_getsockname(UvTcpHandle handle, out SockAddr name, ref int namelen);
579+
580+
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
581+
public static extern int uv_tcp_getpeername(UvTcpHandle handle, out SockAddr name, ref int namelen);
571582

572583
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
573584
unsafe public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
@@ -606,7 +617,7 @@ private static class NativeDarwinMonoMethods
606617
public static extern int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
607618

608619
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
609-
public static extern int uv_tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags);
620+
public static extern int uv_tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags);
610621

611622
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
612623
public static extern int uv_tcp_open(UvTcpHandle handle, IntPtr hSocket);
@@ -666,10 +677,16 @@ private static class NativeDarwinMonoMethods
666677
public static extern int uv_req_size(RequestType reqType);
667678

668679
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
669-
public static extern int uv_ip4_addr(string ip, int port, out sockaddr addr);
680+
public static extern int uv_ip4_addr(string ip, int port, out SockAddr addr);
681+
682+
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
683+
public static extern int uv_ip6_addr(string ip, int port, out SockAddr addr);
684+
685+
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
686+
public static extern int uv_tcp_getsockname(UvTcpHandle handle, out SockAddr name, ref int namelen);
670687

671688
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
672-
public static extern int uv_ip6_addr(string ip, int port, out sockaddr addr);
689+
public static extern int uv_tcp_getpeername(UvTcpHandle handle, out SockAddr name, ref int namelen);
673690

674691
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
675692
unsafe public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);

0 commit comments

Comments
 (0)