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

Commit 6f30dc2

Browse files
committed
Rio Transport
1 parent db15919 commit 6f30dc2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3514
-0
lines changed

KestrelHttpServer.sln

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server
6868
EndProject
6969
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Tests", "test\Microsoft.AspNetCore.Server.Kestrel.Tests\Microsoft.AspNetCore.Server.Kestrel.Tests.csproj", "{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}"
7070
EndProject
71+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio", "src\Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio\Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio.csproj", "{504F585D-5DC4-48C4-80D5-2E0573510E26}"
72+
EndProject
73+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransportChoiceApp", "samples\TransportChoiceApp\TransportChoiceApp.csproj", "{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}"
74+
EndProject
7175
Global
7276
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7377
Debug|Any CPU = Debug|Any CPU
@@ -234,6 +238,30 @@ Global
234238
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x64.Build.0 = Release|Any CPU
235239
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x86.ActiveCfg = Release|Any CPU
236240
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x86.Build.0 = Release|Any CPU
241+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
242+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Debug|Any CPU.Build.0 = Debug|Any CPU
243+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Debug|x64.ActiveCfg = Debug|Any CPU
244+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Debug|x64.Build.0 = Debug|Any CPU
245+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Debug|x86.ActiveCfg = Debug|Any CPU
246+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Debug|x86.Build.0 = Debug|Any CPU
247+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Release|Any CPU.ActiveCfg = Release|Any CPU
248+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Release|Any CPU.Build.0 = Release|Any CPU
249+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Release|x64.ActiveCfg = Release|Any CPU
250+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Release|x64.Build.0 = Release|Any CPU
251+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Release|x86.ActiveCfg = Release|Any CPU
252+
{504F585D-5DC4-48C4-80D5-2E0573510E26}.Release|x86.Build.0 = Release|Any CPU
253+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
254+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Debug|Any CPU.Build.0 = Debug|Any CPU
255+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Debug|x64.ActiveCfg = Debug|Any CPU
256+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Debug|x64.Build.0 = Debug|Any CPU
257+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Debug|x86.ActiveCfg = Debug|Any CPU
258+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Debug|x86.Build.0 = Debug|Any CPU
259+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Release|Any CPU.ActiveCfg = Release|Any CPU
260+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Release|Any CPU.Build.0 = Release|Any CPU
261+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Release|x64.ActiveCfg = Release|Any CPU
262+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Release|x64.Build.0 = Release|Any CPU
263+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Release|x86.ActiveCfg = Release|Any CPU
264+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39}.Release|x86.Build.0 = Release|Any CPU
237265
EndGlobalSection
238266
GlobalSection(SolutionProperties) = preSolution
239267
HideSolutionNode = FALSE
@@ -254,5 +282,7 @@ Global
254282
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
255283
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
256284
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
285+
{504F585D-5DC4-48C4-80D5-2E0573510E26} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
286+
{18BE39D5-C307-4F4D-BBB8-082BFAE8AF39} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
257287
EndGlobalSection
258288
EndGlobal

samples/TransportChoiceApp/Startup.cs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.IO;
5+
using System.Net;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore.Builder;
9+
using Microsoft.AspNetCore.Hosting;
10+
using System;
11+
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
12+
13+
namespace TransportChoiceApp
14+
{
15+
public class Startup
16+
{
17+
private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
18+
19+
public void Configure(IApplicationBuilder app)
20+
{
21+
app.Run((httpContext) =>
22+
{
23+
var response = httpContext.Response;
24+
var payloadLength = _helloWorldPayload.Length;
25+
response.StatusCode = 200;
26+
response.ContentType = "text/plain";
27+
response.ContentLength = payloadLength;
28+
return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength);
29+
});
30+
}
31+
32+
public static void Main(string[] args)
33+
{
34+
var hostBuilder = new WebHostBuilder()
35+
.UseKestrel(options =>
36+
{
37+
options.Listen(IPAddress.Loopback, 5001);
38+
39+
});
40+
41+
Console.WriteLine(@"
42+
Choose a Transport
43+
1. Libuv
44+
2. Rio
45+
");
46+
47+
switch (Console.ReadKey().KeyChar)
48+
{
49+
case '1':
50+
hostBuilder.UseLibuv(options =>
51+
{
52+
//options.ThreadCount = 4;
53+
});
54+
break;
55+
case '2':
56+
hostBuilder.UseRio(options =>
57+
{
58+
//options.SendThreadCount = 4;
59+
//options.ReceiveThreadCount = 4;
60+
});
61+
break;
62+
default:
63+
Console.WriteLine("Invalid option");
64+
return;
65+
}
66+
67+
Console.WriteLine();
68+
69+
hostBuilder
70+
.UseContentRoot(Directory.GetCurrentDirectory())
71+
.UseStartup<Startup>();
72+
73+
var host = hostBuilder.Build();
74+
75+
host.ServerFeatures.Get<InternalKestrelServerOptions>().ThreadPoolDispatching = false;
76+
77+
host.Run();
78+
}
79+
}
80+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<Import Project="..\..\build\common.props" />
4+
5+
<PropertyGroup>
6+
<TargetFramework>netcoreapp2.0</TargetFramework>
7+
<IsPackable>false</IsPackable>
8+
<OutputType>exe</OutputType>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio\Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio.csproj" />
13+
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel\Microsoft.AspNetCore.Server.Kestrel.csproj" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
6+
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio.Internal
7+
{
8+
interface IAsyncDisposable
9+
{
10+
Task DisposeAsync();
11+
}
12+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.Extensions.Logging;
6+
7+
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio.Internal
8+
{
9+
public interface IRioTrace : ILogger
10+
{
11+
void ConnectionRead(string connectionId, int count);
12+
13+
void ConnectionReadFin(string connectionId);
14+
15+
void ConnectionWriteFin(string connectionId);
16+
17+
void ConnectionWroteFin(string connectionId, int status);
18+
19+
void ConnectionWrite(string connectionId, int count);
20+
21+
void ConnectionWriteCallback(string connectionId, int status);
22+
23+
void ConnectionError(string connectionId, Exception ex);
24+
25+
void ConnectionReset(string connectionId);
26+
27+
void NotAllConnectionsClosedGracefully();
28+
29+
void NotAllConnectionsAborted();
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Diagnostics;
6+
7+
namespace System.Net.Sockets
8+
{
9+
internal static class IPEndPointExtensions
10+
{
11+
public static Internals.SocketAddress Serialize(EndPoint endpoint)
12+
{
13+
if (endpoint is DnsEndPoint)
14+
{
15+
throw new NotSupportedException();
16+
}
17+
18+
var ipEndPoint = endpoint as IPEndPoint;
19+
if (ipEndPoint != null)
20+
{
21+
return new Internals.SocketAddress(ipEndPoint.Address, ipEndPoint.Port);
22+
}
23+
24+
throw new NotSupportedException();
25+
}
26+
}
27+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Net;
5+
using System.Runtime.InteropServices;
6+
7+
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Windows.Rio.Internal
8+
{
9+
[StructLayout(LayoutKind.Sequential)]
10+
public struct SockAddr
11+
{
12+
// this type represents native memory occupied by sockaddr struct
13+
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
14+
// although the c/c++ header defines it as a 2-byte short followed by a 14-byte array,
15+
// the simplest way to reserve the same size in c# is with four nameless long values
16+
private long _field0;
17+
private long _field1;
18+
private long _field2;
19+
private long _field3;
20+
21+
public SockAddr(long ignored)
22+
{
23+
_field0 = _field1 = _field2 = _field3 = 0;
24+
}
25+
26+
public unsafe IPEndPoint GetIPEndPoint()
27+
{
28+
// The bytes are represented in network byte order.
29+
//
30+
// Example 1: [2001:4898:e0:391:b9ef:1124:9d3e:a354]:39179
31+
//
32+
// 0000 0000 0b99 0017 => The third and fourth bytes 990B is the actual port
33+
// 9103 e000 9848 0120 => IPv6 address is represented in the 128bit field1 and field2.
34+
// 54a3 3e9d 2411 efb9 Read these two 64-bit long from right to left byte by byte.
35+
// 0000 0000 0000 0010 => Scope ID 0x10 (eg [::1%16]) the first 4 bytes of field3 in host byte order.
36+
//
37+
// Example 2: 10.135.34.141:39178 when adopt dual-stack sockets, IPv4 is mapped to IPv6
38+
//
39+
// 0000 0000 0a99 0017 => The port representation are the same
40+
// 0000 0000 0000 0000
41+
// 8d22 870a ffff 0000 => IPv4 occupies the last 32 bit: 0A.87.22.8d is the actual address.
42+
// 0000 0000 0000 0000
43+
//
44+
// Example 3: 10.135.34.141:12804, not dual-stack sockets
45+
//
46+
// 8d22 870a fd31 0002 => sa_family == AF_INET (02)
47+
// 0000 0000 0000 0000
48+
// 0000 0000 0000 0000
49+
// 0000 0000 0000 0000
50+
//
51+
// Example 4: 127.0.0.1:52798, on a Mac OS
52+
//
53+
// 0100 007F 3ECE 0210 => sa_family == AF_INET (02) Note that struct sockaddr on mac use
54+
// 0000 0000 0000 0000 the second unint8 field for sa family type
55+
// 0000 0000 0000 0000 http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/socket.h
56+
// 0000 0000 0000 0000
57+
//
58+
// Reference:
59+
// - Windows: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
60+
// - Linux: https://github.com/torvalds/linux/blob/6a13feb9c82803e2b815eca72fa7a9f5561d7861/include/linux/socket.h
61+
// - Linux (sin6_scope_id): https://github.com/torvalds/linux/blob/5924bbecd0267d87c24110cbe2041b5075173a25/net/sunrpc/addr.c#L82
62+
// - Apple: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/socket.h
63+
64+
// Quick calculate the port by mask the field and locate the byte 3 and byte 4
65+
// and then shift them to correct place to form a int.
66+
var port = ((int)(_field0 & 0x00FF0000) >> 8) | (int)((_field0 & 0xFF000000) >> 24);
67+
68+
int family = (int)_field0;
69+
if (PlatformApis.IsDarwin)
70+
{
71+
// see explaination in example 4
72+
family = family >> 8;
73+
}
74+
family = family & 0xFF;
75+
76+
if (family == 2)
77+
{
78+
// AF_INET => IPv4
79+
return new IPEndPoint(new IPAddress((_field0 >> 32) & 0xFFFFFFFF), port);
80+
}
81+
else if (IsIPv4MappedToIPv6())
82+
{
83+
var ipv4bits = (_field2 >> 32) & 0x00000000FFFFFFFF;
84+
return new IPEndPoint(new IPAddress(ipv4bits), port);
85+
}
86+
else
87+
{
88+
// otherwise IPv6
89+
var bytes = new byte[16];
90+
fixed (byte* b = bytes)
91+
{
92+
*((long*)b) = _field1;
93+
*((long*)(b + 8)) = _field2;
94+
}
95+
96+
return new IPEndPoint(new IPAddress(bytes, scopeid: _field3 & 0xFFFFFFFF), port);
97+
}
98+
}
99+
100+
private bool IsIPv4MappedToIPv6()
101+
{
102+
// If the IPAddress is an IPv4 mapped to IPv6, return the IPv4 representation instead.
103+
// For example [::FFFF:127.0.0.1] will be transform to IPAddress of 127.0.0.1
104+
if (_field1 != 0)
105+
{
106+
return false;
107+
}
108+
109+
return (_field2 & 0xFFFFFFFF) == 0xFFFF0000;
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)