dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.45k stars 10.03k forks source link

Add support for binding to AF_VSOCK and AF_HYPERV sockets #34050

Open shirhatti opened 3 years ago

shirhatti commented 3 years ago

Windows added support (in Win 10.14290) for AF_HYPERV (for Hyper-V hosts/ Windows guests) and Linux support for AF_VSOCK has existed in mainline kernel since 3.9 (for Linux hosts/guests). This is useful for IPC communication between process on the hypervisor and in the guest OS

For example, this is what the Docker Desktop for Windows uses to communicate with the Docker Daemon when running in WSL2. I can see this being super useful for workloads like gRPC.

Links:

shirhatti commented 3 years ago

I assume if I new up and bind to the socket myself, calling KestrelServerOptions.ListenHandle() should just work.

EDIT:

It doesn't just work. Found an issue at https://github.com/dotnet/aspnetcore/blob/main/src/Servers/Kestrel/Core/src/ListenOptions.cs#L106-L119

ghost commented 3 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

shirhatti commented 3 years ago
crit: Microsoft.AspNetCore.Server.Kestrel[0]
      The connection listener failed to accept any new connections.
      System.InvalidOperationException: You must call the Bind method before performing this operation.
         at System.Net.Sockets.Socket.AcceptAsync(SocketAsyncEventArgs e) in System.Net.Sockets.dll:token 0x600022d+0x3e
         at System.Net.Sockets.Socket.AcceptAsync(Socket acceptSocket) in System.Net.Sockets.dll:token 0x600026a+0x42
         at System.Net.Sockets.Socket.AcceptAsync() in System.Net.Sockets.dll:token 0x6000269+0x0
         at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.AcceptAsync(CancellationToken cancellationToken) in Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll:token 0x600006f+0x14
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.ConnectionDispatcher`1.<>c__DisplayClass9_0.<<StartAcceptingConnectionsCore>g__AcceptConnectionsAsync|0>d.MoveNext() in Microsoft.AspNetCore.Server.Kestrel.Core.dll:token 0x600109a+0x7e
Microsoft.AspNetCore.Server.Kestrel: Critical: The connection listener failed to accept any new connections.

System.InvalidOperationException: You must call the Bind method before performing this operation.
   at System.Net.Sockets.Socket.AcceptAsync(SocketAsyncEventArgs e) in System.Net.Sockets.dll:token 0x600022d+0x3e
   at System.Net.Sockets.Socket.AcceptAsync(Socket acceptSocket) in System.Net.Sockets.dll:token 0x600026a+0x42
   at System.Net.Sockets.Socket.AcceptAsync() in System.Net.Sockets.dll:token 0x6000269+0x0
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.AcceptAsync(CancellationToken cancellationToken) in Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll:token 0x600006f+0x14
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.ConnectionDispatcher`1.<>c__DisplayClass9_0.<<StartAcceptingConnectionsCore>g__AcceptConnectionsAsync|0>d.MoveNext() in Microsoft.AspNetCore.Server.Kestrel.Core.dll:token 0x600109a+0x7e
The thread 0x1a3b has exited with code 0 (0x0).
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Private.CoreLib.dll: 'Operation is not valid due to the current state of the object.'
Stack trace:
 >   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.GetDisplayName()
 >   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.<BindAsync>d__47.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
 >   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.<BindAsync>d__2.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
 >   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.<BindAsync>d__0.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
 >   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<BindAsync>d__32.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
 >   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<StartAsync>d__29`1.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
 >   at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__34.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
 >   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__11.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
 >   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
 >   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
 >   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 >   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
 >   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
 >   at Microsoft.AspNetCore.Builder.WebApplication.Run(String url)
 >   at <Program>$.<Main>$(String[] args) in C:\Users\shirh\source\repos\WebApplicationVSock\WebApplicationVSock\Program.cs:line 40
System.InvalidOperationException
  HResult=0x80131509
  Message=Operation is not valid due to the current state of the object.
  Source=Microsoft.AspNetCore.Server.Kestrel.Core
  StackTrace:
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.GetDisplayName()
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.<BindAsync>d__47.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.<BindAsync>d__2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.<BindAsync>d__0.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<BindAsync>d__32.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<StartAsync>d__29`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__34.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__11.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at Microsoft.AspNetCore.Builder.WebApplication.Run(String url)
   at <Program>$.<Main>$(String[] args) in C:\Users\shirh\source\repos\WebApplicationVSock\WebApplicationVSock\Program.cs:line 40

  This exception was originally thrown at this call stack:
    Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.GetDisplayName()
    Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBindContext, System.Threading.CancellationToken)
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
    Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.EndpointsStrategy.BindAsync(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBindContext, System.Threading.CancellationToken)
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    ...
    [Call Stack Truncated]

strace output:

while true; do pid=$(pgrep 'dotnet' | head -1); if [[ -n "$pid" ]];
then strace  -s 2000 -e trace=socket,bind,accept -vvtf -p "$pid"; break; fi; done

strace: Process 5763 attached
[pid  5763] 11:32:19 socket(AF_UNIX, SOCK_STREAM, 0) = 8
[pid  5763] 11:32:19 bind(8, {sa_family=AF_UNIX, sun_path="/tmp/dotnet-diagnostic-5763-331616-socket"}, 110) = 0
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=TRAP_TRACE, si_pid=3907216543, si_uid=32740} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=TRAP_TRACE, si_pid=3907216552, si_uid=32740} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=TRAP_TRACE, si_pid=3907216556, si_uid=32740} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=TRAP_TRACE, si_pid=3907217414, si_uid=32740} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=TRAP_TRACE, si_pid=3907216565, si_uid=32740} ---
[pid  5763] 11:32:20 --- SIGTRAP {si_signo=SIGTRAP, si_code=TRAP_TRACE, si_pid=3907216569, si_uid=32740} ---
[pid  5763] 11:32:20 socket(AF_VSOCK, SOCK_STREAM, 0) = 35
[pid  5763] 11:32:20 bind(35, {sa_family=AF_VSOCK, sa_data="\0\0\377\377\377\377\377\377\377\377\0\0\0\0"}, 16) = 0

Repro app:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using System;
using System.Runtime.InteropServices;
using Tmds.Linux;
using static Tmds.Linux.LibC;

var handle = socket(AF_VSOCK, SOCK_STREAM, 0);
sockaddr_vm address = new()
{
    sa_family = AF_VSOCK,
    svm_reserved1 = 0,
    svm_port = uint.MaxValue, // VMADDR_PORT_ANY
    svm_cid = uint.MaxValue // VMADDR_CID_ANY
};
unsafe
{
    int rv = bind(handle, (sockaddr*)&address, 16);
    if (rv != 0)
    {
        PlatformException.Throw();
    }
}

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenHandle((ulong)handle);
});
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapGet("/", (Func<string>)(() => "Hello World!"));

app.Run();

[StructLayout(LayoutKind.Explicit)]
public unsafe struct sockaddr_vm
{
    [FieldOffset(0)]
    public sa_family_t sa_family;
    [FieldOffset(2)]
    public ushort svm_reserved1;
    [FieldOffset(4)]
    public uint svm_port;      /* Port # in host byte order */
    [FieldOffset(8)]
    public uint svm_cid;       /* Address in host byte order */
    [FieldOffset(12)]
    private fixed byte _sa_data[4];
}

internal class PlatformException : Exception
{
    public PlatformException(int errno) : base(GetErrorMessage(errno)) => HResult = errno;
    public PlatformException() : this(LibC.errno) { }

    private unsafe static string GetErrorMessage(int errno)
    {
        int bufferLength = 1024;
        byte* buffer = stackalloc byte[bufferLength];
        int rv = strerror_r(errno, buffer, bufferLength);
        return rv == 0 ? Marshal.PtrToStringAnsi((IntPtr)buffer) : $"errno {errno}";
    }

    public static void Throw() => throw new PlatformException();
}
davidfowl commented 3 years ago

This looks like low hanging fruit.

kanpov commented 5 months ago

Any update on this? Would be incredibly useful