Skip to content

Commit

Permalink
Added IConnectionSocketFeature (#31588)
Browse files Browse the repository at this point in the history
- Removed the nullable from the Socket property as approved in API review
- Make the IConnectionSocketFeature an additional feature instead of one implemented on the TransportConnection.
- Added a test to verify it works
  • Loading branch information
davidfowl authored Apr 7, 2021
1 parent da8ac73 commit 469faaf
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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.Net.Sockets;

namespace Microsoft.AspNetCore.Connections.Features
{
/// <summary>
/// Provides access to the connection's underlying <see cref="Socket"/>.
/// </summary>
public interface IConnectionSocketFeature
{
/// <summary>
/// Gets the underlying <see cref="Socket"/>.
/// </summary>
Socket Socket { get; }
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#nullable enable
*REMOVED*Microsoft.AspNetCore.Connections.IConnectionListener.AcceptAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Connections.ConnectionContext!>
Microsoft.AspNetCore.Connections.Features.IConnectionSocketFeature
Microsoft.AspNetCore.Connections.Features.IConnectionSocketFeature.Socket.get -> System.Net.Sockets.Socket!
Microsoft.AspNetCore.Connections.IConnectionListener.AcceptAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<Microsoft.AspNetCore.Connections.ConnectionContext?>
Microsoft.AspNetCore.Connections.Experimental.IMultiplexedConnectionBuilder
Microsoft.AspNetCore.Connections.Experimental.IMultiplexedConnectionBuilder.ApplicationServices.get -> System.IServiceProvider!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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.Net.Sockets;
using Microsoft.AspNetCore.Connections.Features;

namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
{
internal sealed partial class SocketConnection : IConnectionSocketFeature
{
public Socket Socket => _socket;

private void InitiaizeFeatures()
{
_currentIConnectionSocketFeature = this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
{
internal sealed class SocketConnection : TransportConnection
internal sealed partial class SocketConnection : TransportConnection
{
private static readonly int MinAllocBufferSize = SlabMemoryPool.BlockSize / 2;

Expand Down Expand Up @@ -70,6 +70,8 @@ internal SocketConnection(Socket socket,
// Set the transport and connection id
Transport = _originalTransport = pair.Transport;
Application = pair.Application;

InitiaizeFeatures();
}

public PipeWriter Input => Application.Output;
Expand Down
24 changes: 24 additions & 0 deletions src/Servers/Kestrel/shared/TransportConnection.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ internal partial class TransportConnection : IFeatureCollection,
internal protected IMemoryPoolFeature? _currentIMemoryPoolFeature;
internal protected IConnectionLifetimeFeature? _currentIConnectionLifetimeFeature;

// Other reserved feature slots
internal protected IConnectionSocketFeature? _currentIConnectionSocketFeature;

private int _featureRevision;

private List<KeyValuePair<Type, object>>? MaybeExtra;
Expand All @@ -39,6 +42,7 @@ private void FastReset()
_currentIMemoryPoolFeature = this;
_currentIConnectionLifetimeFeature = this;

_currentIConnectionSocketFeature = null;
}

// Internal for testing
Expand Down Expand Up @@ -130,6 +134,10 @@ private void ExtraFeatureSet(Type key, object? value)
{
feature = _currentIConnectionLifetimeFeature;
}
else if (key == typeof(IConnectionSocketFeature))
{
feature = _currentIConnectionSocketFeature;
}
else if (MaybeExtra != null)
{
feature = ExtraFeatureGet(key);
Expand Down Expand Up @@ -162,6 +170,10 @@ private void ExtraFeatureSet(Type key, object? value)
{
_currentIConnectionLifetimeFeature = (IConnectionLifetimeFeature?)value;
}
else if (key == typeof(IConnectionSocketFeature))
{
_currentIConnectionSocketFeature = (IConnectionSocketFeature?)value;
}
else
{
ExtraFeatureSet(key, value);
Expand Down Expand Up @@ -196,6 +208,10 @@ private void ExtraFeatureSet(Type key, object? value)
{
feature = Unsafe.As<IConnectionLifetimeFeature?, TFeature?>(ref _currentIConnectionLifetimeFeature);
}
else if (typeof(TFeature) == typeof(IConnectionSocketFeature))
{
feature = Unsafe.As<IConnectionSocketFeature?, TFeature?>(ref _currentIConnectionSocketFeature);
}
else if (MaybeExtra != null)
{
feature = (TFeature?)(ExtraFeatureGet(typeof(TFeature)));
Expand Down Expand Up @@ -231,6 +247,10 @@ private void ExtraFeatureSet(Type key, object? value)
{
_currentIConnectionLifetimeFeature = Unsafe.As<TFeature?, IConnectionLifetimeFeature?>(ref feature);
}
else if (typeof(TFeature) == typeof(IConnectionSocketFeature))
{
_currentIConnectionSocketFeature = Unsafe.As<TFeature?, IConnectionSocketFeature?>(ref feature);
}
else
{
ExtraFeatureSet(typeof(TFeature), feature);
Expand Down Expand Up @@ -259,6 +279,10 @@ private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{
yield return new KeyValuePair<Type, object>(typeof(IConnectionLifetimeFeature), _currentIConnectionLifetimeFeature);
}
if (_currentIConnectionSocketFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(IConnectionSocketFeature), _currentIConnectionSocketFeature);
}

if (MaybeExtra != null)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.FunctionalTests;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Hosting;
using Xunit;

namespace Sockets.FunctionalTests
{
public class SocketTranspotTests : LoggedTestBase
{
[Fact]
public async Task SocketTransportExposesSocketsFeature()
{
var builder = TransportSelector.GetHostBuilder()
.ConfigureWebHost(webHostBuilder =>
{
webHostBuilder
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app =>
{
app.Run(context =>
{
var socket = context.Features.Get<IConnectionSocketFeature>().Socket;
Assert.NotNull(socket);
Assert.Equal(ProtocolType.Tcp, socket.ProtocolType);
var ip = (IPEndPoint)socket.RemoteEndPoint;
Assert.Equal(ip.Address, context.Connection.RemoteIpAddress);
Assert.Equal(ip.Port, context.Connection.RemotePort);

return Task.CompletedTask;
});
});
})
.ConfigureServices(AddTestLogging);

using var host = builder.Build();
using var client = new HttpClient();

await host.StartAsync();

var response = await client.GetAsync($"http://127.0.0.1:{host.GetPort()}/");
response.EnsureSuccessStatusCode();

await host.StopAsync();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,18 @@ public static string GenerateFile()
{
// NOTE: This list MUST always match the set of feature interfaces implemented by TransportConnection.
// See also: shared/TransportConnection.FeatureCollection.cs
var features = new[]

var allFeatures = new[]
{
"IConnectionIdFeature",
"IConnectionTransportFeature",
"IConnectionItemsFeature",
"IMemoryPoolFeature",
"IConnectionLifetimeFeature",
"IConnectionSocketFeature"
};

var implementedFeatures = new[]
{
"IConnectionIdFeature",
"IConnectionTransportFeature",
Expand All @@ -27,8 +38,8 @@ public static string GenerateFile()
return FeatureCollectionGenerator.GenerateFile(
namespaceName: "Microsoft.AspNetCore.Connections",
className: "TransportConnection",
allFeatures: features,
implementedFeatures: features,
allFeatures: allFeatures,
implementedFeatures: implementedFeatures,
extraUsings: usings,
fallbackFeatures: null);
}
Expand Down

0 comments on commit 469faaf

Please sign in to comment.