Port to Kestrel

This commit is contained in:
Jöran Malek 2023-12-15 22:44:49 +01:00
parent 7f9dc36473
commit 5c9db5d5f2
6 changed files with 76 additions and 114 deletions

View file

@ -0,0 +1,11 @@
using System.Net;
using System.Net.Sockets;
namespace pdns_dhcp.Connections;
public class ProtocolSocketIPEndPoint(IPAddress address, int port, ProtocolType protocolType, SocketType socketType) : IPEndPoint(address, port)
{
public ProtocolType ProtocolType => protocolType;
public SocketType SocketType => socketType;
}

View file

@ -1,10 +0,0 @@
using System.Net.Sockets;
using Stl.Interception;
namespace pdns_dhcp.PowerDns;
public interface IPowerDnsFactory : IRequiresFullProxy
{
PowerDnsStreamClient CreateClient(Stream stream);
}

View file

@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Connections;
namespace pdns_dhcp.PowerDns;
public class PowerDnsHandler : ConnectionHandler
{
public override Task OnConnectedAsync(ConnectionContext connection)
{
return Task.CompletedTask;
}
}

View file

@ -1,77 +0,0 @@
using System.Text.Json;
namespace pdns_dhcp.PowerDns;
public class PowerDnsStreamClient : IDisposable
{
private readonly Stream _stream;
private CancellationTokenSource _cts = new();
private Task _task;
public PowerDnsStreamClient(Stream stream)
{
_stream = stream;
}
~PowerDnsStreamClient()
{
DisposeCore();
}
public void Dispose()
{
_cts.Cancel();
if (Interlocked.Exchange(ref _task, null!) is { } task)
{
task
.ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing)
.GetAwaiter().GetResult();
}
DisposeCore();
GC.SuppressFinalize(this);
}
public void Start(CancellationToken stoppingToken)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
using var old = Interlocked.Exchange(ref _cts, cts);
old.Cancel();
_task = Run(cts.Token);
}
private void DisposeCore()
{
_cts.Dispose();
_stream.Dispose();
}
private async Task Run(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
switch (await JsonSerializer.DeserializeAsync<Method>(_stream, cancellationToken: stoppingToken).ConfigureAwait(false))
{
case InitializeMethod init:
break;
case LookupMethod lookup:
break;
default:
break;
}
}
}
finally
{
if (Interlocked.Exchange(ref _task, null!) is not null)
{
Dispose();
}
}
}
}

View file

@ -1,7 +1,14 @@
using Microsoft.AspNetCore.Builder;
using System.Net;
using System.Net.Sockets;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using pdns_dhcp.Connections;
using pdns_dhcp.Kea;
using pdns_dhcp.Options;
using pdns_dhcp.PowerDns;
@ -10,6 +17,7 @@ using pdns_dhcp.Services;
using Stl.Interception;
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<DhcpOptions>(builder.Configuration.GetRequiredSection("Dhcp"));
builder.Services.Configure<PowerDnsOptions>(builder.Configuration.GetRequiredSection("PowerDns"));
@ -17,9 +25,50 @@ builder.Services.AddHostedService<DhcpLeaseWatcher>();
builder.Services.AddHostedService<PowerDnsBackend>();
builder.Services.AddTypedFactory<IDhcpLeaseWatcherFactory>();
builder.Services.AddTypedFactory<IPowerDnsFactory>();
builder.Services.AddTransient<KeaDhcp4LeaseHandler>();
builder.Services.AddTransient<KeaDhcp6LeaseHandler>();
builder.WebHost.UseSockets(options =>
{
options.CreateBoundListenSocket = endpoint =>
{
Socket socket;
switch (endpoint)
{
case ProtocolSocketIPEndPoint socketIp:
socket = new Socket(socketIp.AddressFamily, socketIp.SocketType, socketIp.ProtocolType);
if (socketIp.Address.Equals(IPAddress.IPv6Any))
{
socket.DualMode = true;
}
break;
default:
return SocketTransportOptions.CreateDefaultBoundListenSocket(endpoint);
}
socket.Bind(endpoint);
return socket;
};
});
builder.WebHost.UseKestrelCore();
builder.WebHost.ConfigureKestrel((context, options) =>
{
if (context.Configuration.GetRequiredSection("PowerDns:Listener").Get<PowerDnsListenerOptions>() is { } pdnsOptions)
{
var path = PathEx.ExpandPath(pdnsOptions.Socket);
FileInfo file = new(path);
file.Directory!.Create();
file.Delete();
options.ListenUnixSocket(path, options =>
{
options.UseConnectionHandler<PowerDnsHandler>();
});
}
});
builder.Build().Run();

View file

@ -1,27 +1,11 @@
using System.Net.Sockets;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using pdns_dhcp.Options;
using pdns_dhcp.PowerDns;
namespace pdns_dhcp.Services;
public class PowerDnsBackend : BackgroundService
{
private readonly IPowerDnsFactory _factory;
private readonly Socket _socket;
public PowerDnsBackend(IOptions<PowerDnsOptions> options, IPowerDnsFactory socketFactory)
public PowerDnsBackend()
{
_factory = socketFactory;
_socket = new(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
var path = PathEx.ExpandPath(options.Value.Listener.Socket);
FileInfo file = new(path);
file.Directory!.Create();
file.Delete();
_socket.Bind(new UnixDomainSocketEndPoint(path));
}
~PowerDnsBackend()
@ -29,14 +13,9 @@ public class PowerDnsBackend : BackgroundService
DisposeCore();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_socket.Listen();
while (await _socket.AcceptAsync(stoppingToken) is { } client)
{
_factory.CreateClient(new NetworkStream(client, true))
.Start(stoppingToken);
}
return Task.CompletedTask;
}
public override void Dispose()
@ -48,6 +27,5 @@ public class PowerDnsBackend : BackgroundService
private void DisposeCore()
{
_socket.Dispose();
}
}