Make Frame implements IHttpConnectionFeature
Provide RemoteIPAddress as well as RemotePort
This commit is contained in:
parent
cb623e55f1
commit
e9a6061023
|
|
@ -52,6 +52,11 @@ namespace SampleApp
|
|||
context.Request.Path,
|
||||
context.Request.QueryString);
|
||||
|
||||
var connectionFeature = context.Connection;
|
||||
Console.WriteLine($"Peer: {connectionFeature.RemoteIpAddress?.ToString()} {connectionFeature.RemotePort}");
|
||||
Console.WriteLine($"Sock: {connectionFeature.LocalIpAddress?.ToString()} {connectionFeature.LocalPort}");
|
||||
Console.WriteLine($"IsLocal: {connectionFeature.IsLocal}");
|
||||
|
||||
context.Response.ContentLength = 11;
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Hello world");
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// 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 Microsoft.AspNet.Server.Kestrel.Filter;
|
||||
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
|
||||
|
|
@ -28,6 +29,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
private readonly object _stateLock = new object();
|
||||
private ConnectionState _connectionState;
|
||||
|
||||
private IPEndPoint _remoteEndPoint;
|
||||
private IPEndPoint _localEndPoint;
|
||||
|
||||
public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
|
||||
{
|
||||
_socket = socket;
|
||||
|
|
@ -46,13 +50,20 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
// 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();
|
||||
}
|
||||
|
||||
// Don't initialize _frame until SocketInput and SocketOutput are set to their final values.
|
||||
if (ConnectionFilter == null)
|
||||
{
|
||||
SocketInput = _rawSocketInput;
|
||||
SocketOutput = _rawSocketOutput;
|
||||
|
||||
_frame = new Frame(this);
|
||||
_frame = CreateFrame();
|
||||
_frame.Start();
|
||||
}
|
||||
else
|
||||
|
|
@ -94,7 +105,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
SocketInput = filteredStreamAdapter.SocketInput;
|
||||
SocketOutput = filteredStreamAdapter.SocketOutput;
|
||||
|
||||
_frame = new Frame(this);
|
||||
_frame = CreateFrame();
|
||||
_frame.Start();
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +153,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
_rawSocketInput.IncomingComplete(readCount, error);
|
||||
}
|
||||
|
||||
private Frame CreateFrame()
|
||||
{
|
||||
return new Frame(this, _remoteEndPoint, _localEndPoint);
|
||||
}
|
||||
|
||||
void IConnectionControl.Pause()
|
||||
{
|
||||
Log.ConnectionPause(_connectionId);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
|
|
@ -13,7 +14,11 @@ using Microsoft.Extensions.Primitives;
|
|||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||
{
|
||||
public partial class Frame : IFeatureCollection, IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature
|
||||
public partial class Frame : IFeatureCollection,
|
||||
IHttpRequestFeature,
|
||||
IHttpResponseFeature,
|
||||
IHttpUpgradeFeature,
|
||||
IHttpConnectionFeature
|
||||
{
|
||||
// NOTE: When feature interfaces are added to or removed from this Frame class implementation,
|
||||
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
||||
|
|
@ -246,6 +251,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
|
||||
int IFeatureCollection.Revision => _featureRevision;
|
||||
|
||||
IPAddress IHttpConnectionFeature.RemoteIpAddress { get; set; }
|
||||
|
||||
IPAddress IHttpConnectionFeature.LocalIpAddress { get; set; }
|
||||
|
||||
int IHttpConnectionFeature.RemotePort { get; set; }
|
||||
|
||||
int IHttpConnectionFeature.LocalPort { get; set; }
|
||||
|
||||
bool IHttpConnectionFeature.IsLocal { get; set; }
|
||||
|
||||
object IFeatureCollection.this[Type key]
|
||||
{
|
||||
get { return FastFeatureGet(key); }
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
_currentIHttpRequestFeature = this;
|
||||
_currentIHttpResponseFeature = this;
|
||||
_currentIHttpUpgradeFeature = this;
|
||||
_currentIHttpConnectionFeature = this;
|
||||
|
||||
_currentIHttpRequestIdentifierFeature = null;
|
||||
_currentIServiceProvidersFeature = null;
|
||||
_currentIHttpRequestLifetimeFeature = null;
|
||||
_currentIHttpConnectionFeature = null;
|
||||
_currentIHttpAuthenticationFeature = null;
|
||||
_currentIQueryFeature = null;
|
||||
_currentIFormFeature = null;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
|
@ -44,8 +46,22 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
private bool _autoChunk;
|
||||
private Exception _applicationException;
|
||||
|
||||
public Frame(ConnectionContext context) : base(context)
|
||||
private readonly IPEndPoint _localEndPoint;
|
||||
private readonly IPEndPoint _remoteEndPoint;
|
||||
|
||||
public Frame(ConnectionContext context)
|
||||
: this(context, remoteEndPoint: null, localEndPoint: null)
|
||||
{
|
||||
}
|
||||
|
||||
public Frame(ConnectionContext context,
|
||||
IPEndPoint remoteEndPoint,
|
||||
IPEndPoint localEndPoint)
|
||||
: base(context)
|
||||
{
|
||||
_remoteEndPoint = remoteEndPoint;
|
||||
_localEndPoint = localEndPoint;
|
||||
|
||||
FrameControl = this;
|
||||
Reset();
|
||||
}
|
||||
|
|
@ -99,6 +115,21 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
ResponseBody = null;
|
||||
DuplexStream = null;
|
||||
|
||||
var httpConnectionFeature = this as IHttpConnectionFeature;
|
||||
httpConnectionFeature.RemoteIpAddress = _remoteEndPoint?.Address;
|
||||
httpConnectionFeature.RemotePort = _remoteEndPoint?.Port ?? 0;
|
||||
|
||||
httpConnectionFeature.LocalIpAddress = _localEndPoint?.Address;
|
||||
httpConnectionFeature.LocalPort = _localEndPoint?.Port ?? 0;
|
||||
|
||||
if (_remoteEndPoint != null && _localEndPoint != null)
|
||||
{
|
||||
httpConnectionFeature.IsLocal = _remoteEndPoint.Address.Equals(_localEndPoint.Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpConnectionFeature.IsLocal = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetResponseHeaders()
|
||||
|
|
@ -123,7 +154,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
/// <summary>
|
||||
/// Should be called when the server wants to initiate a shutdown. The Task returned will
|
||||
/// become complete when the RequestProcessingAsync function has exited. It is expected that
|
||||
/// Stop will be called on all active connections, and Task.WaitAll() will be called on every
|
||||
/// Stop will be called on all active connections, and Task.WaitAll() will be called on every
|
||||
/// return value.
|
||||
/// </summary>
|
||||
public Task Stop()
|
||||
|
|
@ -136,7 +167,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Primary loop which consumes socket input, parses it for protocol framing, and invokes the
|
||||
/// Primary loop which consumes socket input, parses it for protocol framing, and invokes the
|
||||
/// application delegate for as long as the socket is intended to remain open.
|
||||
/// The resulting Task from this loop is preserved in a field which is used when the server needs
|
||||
/// to drain and close all currently active connections.
|
||||
|
|
@ -731,7 +762,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
|
||||
if (chSecond != '\n')
|
||||
{
|
||||
// "\r" was all by itself, move just after it and try again
|
||||
// "\r" was all by itself, move just after it and try again
|
||||
scan = endValue;
|
||||
scan.Take();
|
||||
continue;
|
||||
|
|
@ -740,7 +771,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
var chThird = scan.Peek();
|
||||
if (chThird == ' ' || chThird == '\t')
|
||||
{
|
||||
// special case, "\r\n " or "\r\n\t".
|
||||
// special case, "\r\n " or "\r\n\t".
|
||||
// this is considered wrapping"linear whitespace" and is actually part of the header value
|
||||
// continue past this for the next
|
||||
wrapping = true;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
_uv_req_size = NativeDarwinMonoMethods.uv_req_size;
|
||||
_uv_ip4_addr = NativeDarwinMonoMethods.uv_ip4_addr;
|
||||
_uv_ip6_addr = NativeDarwinMonoMethods.uv_ip6_addr;
|
||||
_uv_tcp_getpeername = NativeDarwinMonoMethods.uv_tcp_getpeername;
|
||||
_uv_tcp_getsockname = NativeDarwinMonoMethods.uv_tcp_getsockname;
|
||||
_uv_walk = NativeDarwinMonoMethods.uv_walk;
|
||||
}
|
||||
else
|
||||
|
|
@ -95,6 +97,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
_uv_req_size = NativeMethods.uv_req_size;
|
||||
_uv_ip4_addr = NativeMethods.uv_ip4_addr;
|
||||
_uv_ip6_addr = NativeMethods.uv_ip6_addr;
|
||||
_uv_tcp_getpeername = NativeMethods.uv_tcp_getpeername;
|
||||
_uv_tcp_getsockname = NativeMethods.uv_tcp_getsockname;
|
||||
_uv_walk = NativeMethods.uv_walk;
|
||||
}
|
||||
}
|
||||
|
|
@ -206,9 +210,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
Check(_uv_tcp_init(loop, handle));
|
||||
}
|
||||
|
||||
protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref sockaddr addr, int flags);
|
||||
protected delegate int uv_tcp_bind_func(UvTcpHandle handle, ref SockAddr addr, int flags);
|
||||
protected uv_tcp_bind_func _uv_tcp_bind;
|
||||
public void tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags)
|
||||
public void tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags)
|
||||
{
|
||||
handle.Validate();
|
||||
Check(_uv_tcp_bind(handle, ref addr, flags));
|
||||
|
|
@ -365,16 +369,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
return _uv_req_size(reqType);
|
||||
}
|
||||
|
||||
protected delegate int uv_ip4_addr_func(string ip, int port, out sockaddr addr);
|
||||
protected delegate int uv_ip4_addr_func(string ip, int port, out SockAddr addr);
|
||||
protected uv_ip4_addr_func _uv_ip4_addr;
|
||||
public int ip4_addr(string ip, int port, out sockaddr addr, out Exception error)
|
||||
public int ip4_addr(string ip, int port, out SockAddr addr, out Exception error)
|
||||
{
|
||||
return Check(_uv_ip4_addr(ip, port, out addr), out error);
|
||||
}
|
||||
|
||||
protected delegate int uv_ip6_addr_func(string ip, int port, out sockaddr addr);
|
||||
protected delegate int uv_ip6_addr_func(string ip, int port, out SockAddr addr);
|
||||
protected uv_ip6_addr_func _uv_ip6_addr;
|
||||
public int ip6_addr(string ip, int port, out sockaddr addr, out Exception error)
|
||||
public int ip6_addr(string ip, int port, out SockAddr addr, out Exception error)
|
||||
{
|
||||
return Check(_uv_ip6_addr(ip, port, out addr), out error);
|
||||
}
|
||||
|
|
@ -388,26 +392,27 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
_uv_walk(loop, walk_cb, arg);
|
||||
}
|
||||
|
||||
public delegate int uv_tcp_getsockname_func(UvTcpHandle handle, out SockAddr addr, ref int namelen);
|
||||
protected uv_tcp_getsockname_func _uv_tcp_getsockname;
|
||||
public void tcp_getsockname(UvTcpHandle handle, out SockAddr addr, ref int namelen)
|
||||
{
|
||||
handle.Validate();
|
||||
Check(_uv_tcp_getsockname(handle, out addr, ref namelen));
|
||||
}
|
||||
|
||||
public delegate int uv_tcp_getpeername_func(UvTcpHandle handle, out SockAddr addr, ref int namelen);
|
||||
protected uv_tcp_getpeername_func _uv_tcp_getpeername;
|
||||
public void tcp_getpeername(UvTcpHandle handle, out SockAddr addr, ref int namelen)
|
||||
{
|
||||
handle.Validate();
|
||||
Check(_uv_tcp_getpeername(handle, out addr, ref namelen));
|
||||
}
|
||||
|
||||
public uv_buf_t buf_init(IntPtr memory, int len)
|
||||
{
|
||||
return new uv_buf_t(memory, len, IsWindows);
|
||||
}
|
||||
|
||||
public struct sockaddr
|
||||
{
|
||||
// this type represents native memory occupied by sockaddr struct
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
|
||||
// although the c/c++ header defines it as a 2-byte short followed by a 14-byte array,
|
||||
// the simplest way to reserve the same size in c# is with four nameless long values
|
||||
|
||||
private long _field0;
|
||||
private long _field1;
|
||||
private long _field2;
|
||||
private long _field3;
|
||||
|
||||
public sockaddr(long ignored) { _field3 = _field0 = _field1 = _field2 = _field3 = 0; }
|
||||
}
|
||||
|
||||
public struct uv_buf_t
|
||||
{
|
||||
// this type represents a WSABUF struct on Windows
|
||||
|
|
@ -504,7 +509,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public static extern int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags);
|
||||
public static extern int uv_tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_open(UvTcpHandle handle, IntPtr hSocket);
|
||||
|
|
@ -564,10 +569,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public static extern int uv_req_size(RequestType reqType);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_ip4_addr(string ip, int port, out sockaddr addr);
|
||||
public static extern int uv_ip4_addr(string ip, int port, out SockAddr addr);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_ip6_addr(string ip, int port, out sockaddr addr);
|
||||
public static extern int uv_ip6_addr(string ip, int port, out SockAddr addr);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_getsockname(UvTcpHandle handle, out SockAddr name, ref int namelen);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_getpeername(UvTcpHandle handle, out SockAddr name, ref int namelen);
|
||||
|
||||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)]
|
||||
unsafe public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
|
||||
|
|
@ -606,7 +617,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public static extern int uv_tcp_init(UvLoopHandle loop, UvTcpHandle handle);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_bind(UvTcpHandle handle, ref sockaddr addr, int flags);
|
||||
public static extern int uv_tcp_bind(UvTcpHandle handle, ref SockAddr addr, int flags);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_open(UvTcpHandle handle, IntPtr hSocket);
|
||||
|
|
@ -666,10 +677,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public static extern int uv_req_size(RequestType reqType);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_ip4_addr(string ip, int port, out sockaddr addr);
|
||||
public static extern int uv_ip4_addr(string ip, int port, out SockAddr addr);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_ip6_addr(string ip, int port, out sockaddr addr);
|
||||
public static extern int uv_ip6_addr(string ip, int port, out SockAddr addr);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_getsockname(UvTcpHandle handle, out SockAddr name, ref int namelen);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int uv_tcp_getpeername(UvTcpHandle handle, out SockAddr name, ref int namelen);
|
||||
|
||||
[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
|
||||
unsafe public static extern int uv_walk(UvLoopHandle loop, uv_walk_cb walk_cb, IntPtr arg);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||
{
|
||||
public struct SockAddr
|
||||
{
|
||||
// this type represents native memory occupied by sockaddr struct
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
|
||||
// although the c/c++ header defines it as a 2-byte short followed by a 14-byte array,
|
||||
// the simplest way to reserve the same size in c# is with four nameless long values
|
||||
private long _field0;
|
||||
private long _field1;
|
||||
private long _field2;
|
||||
private long _field3;
|
||||
|
||||
public SockAddr(long ignored)
|
||||
{
|
||||
_field3 = _field0 = _field1 = _field2 = _field3 = 0;
|
||||
}
|
||||
|
||||
public IPEndPoint GetIPEndPoint()
|
||||
{
|
||||
// The bytes are represented in network byte order.
|
||||
//
|
||||
// Example 1: [2001:4898:e0:391:b9ef:1124:9d3e:a354]:39179
|
||||
//
|
||||
// 0000 0000 0b99 0017 => The third and fourth bytes 990B is the actual port
|
||||
// 9103 e000 9848 0120 => IPv6 address is represented in the 128bit field1 and field2.
|
||||
// 54a3 3e9d 2411 efb9 Read these two 64-bit long from right to left byte by byte.
|
||||
// 0000 0000 0000 0000
|
||||
//
|
||||
// Example 2: 10.135.34.141:39178 when adopt dual-stack sockets, IPv4 is mapped to IPv6
|
||||
//
|
||||
// 0000 0000 0a99 0017 => The port representation are the same
|
||||
// 0000 0000 0000 0000
|
||||
// 8d22 870a ffff 0000 => IPv4 occupies the last 32 bit: 0A.87.22.8d is the actual address.
|
||||
// 0000 0000 0000 0000
|
||||
//
|
||||
// Example 3: 10.135.34.141:12804, not dual-stack sockets
|
||||
// 8d22 870a fd31 0002 => sa_family == AF_INET (02)
|
||||
// 0000 0000 0000 0000
|
||||
// 0000 0000 0000 0000
|
||||
// 0000 0000 0000 0000
|
||||
|
||||
|
||||
// Quick calculate the port by mask the field and locate the byte 3 and byte 4
|
||||
// and then shift them to correct place to form a int.
|
||||
var port = ((int)(_field0 & 0x00FF0000) >> 8) | (int)((_field0 & 0xFF000000) >> 24);
|
||||
|
||||
var family = (int)_field0 & 0x000000FF;
|
||||
if (family == 0x00000002)
|
||||
{
|
||||
// AF_INET => IPv4
|
||||
return new IPEndPoint(new IPAddress((_field0 >> 32) & 0xFFFFFFFF), port);
|
||||
}
|
||||
else if (IsIPv4MappedToIPv6())
|
||||
{
|
||||
var ipv4bits = (_field2 >> 32) & 0x00000000FFFFFFFF;
|
||||
return new IPEndPoint(new IPAddress(ipv4bits), port);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise IPv6
|
||||
var bytes1 = BitConverter.GetBytes(_field1);
|
||||
var bytes2 = BitConverter.GetBytes(_field2);
|
||||
|
||||
var bytes = new byte[16];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
bytes[i] = bytes1[i];
|
||||
bytes[i + 8] = bytes2[i];
|
||||
}
|
||||
|
||||
return new IPEndPoint(new IPAddress(bytes), port);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsIPv4MappedToIPv6()
|
||||
{
|
||||
// If the IPAddress is an IPv4 mapped to IPv6, return the IPv4 representation instead.
|
||||
// For example [::FFFF:127.0.0.1] will be transform to IPAddress of 127.0.0.1
|
||||
if (_field1 != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (_field2 & 0xFFFFFFFF) == 0xFFFF0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Networking
|
||||
|
|
@ -17,7 +18,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
{
|
||||
CreateMemory(
|
||||
loop.Libuv,
|
||||
loop.ThreadId,
|
||||
loop.ThreadId,
|
||||
loop.Libuv.handle_size(Libuv.HandleType.TCP));
|
||||
|
||||
_uv.tcp_init(loop, this);
|
||||
|
|
@ -26,7 +27,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
public void Init(UvLoopHandle loop, Action<Action<IntPtr>, IntPtr> queueCloseHandle)
|
||||
{
|
||||
CreateHandle(
|
||||
loop.Libuv,
|
||||
loop.Libuv,
|
||||
loop.ThreadId,
|
||||
loop.Libuv.handle_size(Libuv.HandleType.TCP), queueCloseHandle);
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
{
|
||||
var endpoint = CreateIPEndpoint(address);
|
||||
|
||||
Libuv.sockaddr addr;
|
||||
SockAddr addr;
|
||||
var addressText = endpoint.Address.ToString();
|
||||
|
||||
Exception error1;
|
||||
|
|
@ -56,6 +57,24 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
|
|||
_uv.tcp_bind(this, ref addr, 0);
|
||||
}
|
||||
|
||||
public IPEndPoint GetPeerIPEndPoint()
|
||||
{
|
||||
SockAddr socketAddress;
|
||||
int namelen = Marshal.SizeOf<SockAddr>();
|
||||
_uv.tcp_getpeername(this, out socketAddress, ref namelen);
|
||||
|
||||
return socketAddress.GetIPEndPoint();
|
||||
}
|
||||
|
||||
public IPEndPoint GetSockIPEndPoint()
|
||||
{
|
||||
SockAddr socketAddress;
|
||||
int namelen = Marshal.SizeOf<SockAddr>();
|
||||
_uv.tcp_getsockname(this, out socketAddress, ref namelen);
|
||||
|
||||
return socketAddress.GetIPEndPoint();
|
||||
}
|
||||
|
||||
public void Open(IntPtr hSocket)
|
||||
{
|
||||
_uv.tcp_open(this, hSocket);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ using Microsoft.AspNet.Builder;
|
|||
using Microsoft.AspNet.Hosting;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.FunctionalTests
|
||||
|
|
@ -47,7 +49,7 @@ namespace Microsoft.AspNet.Server.Kestrel.FunctionalTests
|
|||
|
||||
await context.Response.WriteAsync(total.ToString(CultureInfo.InvariantCulture));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
using (var app = hostBuilder.Build().Start())
|
||||
{
|
||||
|
|
@ -58,7 +60,7 @@ namespace Microsoft.AspNet.Server.Kestrel.FunctionalTests
|
|||
{
|
||||
bytes[i] = (byte)i;
|
||||
}
|
||||
|
||||
|
||||
var response = await client.PostAsync("http://localhost:8791/", new ByteArrayContent(bytes));
|
||||
response.EnsureSuccessStatusCode();
|
||||
var sizeString = await response.Content.ReadAsStringAsync();
|
||||
|
|
@ -66,5 +68,60 @@ namespace Microsoft.AspNet.Server.Kestrel.FunctionalTests
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("127.0.0.1", "127.0.0.1", "8792")]
|
||||
[InlineData("localhost", "127.0.0.1", "8792")]
|
||||
public Task RemoteIPv4Address(string requestAddress, string expectAddress, string port)
|
||||
{
|
||||
return TestRemoteIPAddress("localhost", requestAddress, expectAddress, port);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task RemoteIPv6Address()
|
||||
{
|
||||
return TestRemoteIPAddress("[::1]", "[::1]", "::1", "8792");
|
||||
}
|
||||
|
||||
private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress, string port)
|
||||
{
|
||||
var config = new ConfigurationBuilder().AddInMemoryCollection(
|
||||
new Dictionary<string, string> {
|
||||
{ "server.urls", $"http://{registerAddress}:{port}" }
|
||||
}).Build();
|
||||
|
||||
var builder = new WebHostBuilder(config)
|
||||
.UseServer("Microsoft.AspNet.Server.Kestrel")
|
||||
.UseStartup(app =>
|
||||
{
|
||||
app.Run(async context =>
|
||||
{
|
||||
var connection = context.Connection;
|
||||
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
|
||||
{
|
||||
RemoteIPAddress = connection.RemoteIpAddress?.ToString(),
|
||||
RemotePort = connection.RemotePort,
|
||||
LocalIPAddress = connection.LocalIpAddress?.ToString(),
|
||||
LocalPort = connection.LocalPort,
|
||||
IsLocal = connection.IsLocal
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
using (var app = builder.Build().Start())
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var response = await client.GetAsync($"http://{requestAddress}:{port}/");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var connectionFacts = await response.Content.ReadAsStringAsync();
|
||||
Assert.NotEmpty(connectionFacts);
|
||||
|
||||
var facts = JsonConvert.DeserializeObject<JObject>(connectionFacts);
|
||||
Assert.Equal(expectAddress, facts["RemoteIPAddress"].Value<string>());
|
||||
Assert.NotEmpty(facts["RemotePort"].Value<string>());
|
||||
Assert.True(facts["IsLocal"].Value<bool>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +66,7 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
|
|||
typeof(IHttpRequestFeature),
|
||||
typeof(IHttpResponseFeature),
|
||||
typeof(IHttpUpgradeFeature),
|
||||
typeof(IHttpConnectionFeature)
|
||||
};
|
||||
|
||||
return $@"
|
||||
|
|
|
|||
Loading…
Reference in New Issue