From f79341e0c0d50278e3b8e2a877470d8f00e6f43c Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Mon, 27 Nov 2023 00:17:51 +0100 Subject: [PATCH] Prepare for parsing Kea dhcp leases memfile --- src/pdns-dhcp/Kea/KeaLeaseWatcher.cs | 70 ++++++++++++++++++++++++++-- src/pdns-dhcp/pdns-dhcp.csproj | 1 + 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/pdns-dhcp/Kea/KeaLeaseWatcher.cs b/src/pdns-dhcp/Kea/KeaLeaseWatcher.cs index e89f6f2..31ca565 100644 --- a/src/pdns-dhcp/Kea/KeaLeaseWatcher.cs +++ b/src/pdns-dhcp/Kea/KeaLeaseWatcher.cs @@ -1,3 +1,6 @@ +using System.Buffers; +using System.IO.Pipelines; +using System.Text; using System.Threading.Channels; using Microsoft.Extensions.Hosting; @@ -10,7 +13,7 @@ namespace pdns_dhcp.Kea; public abstract class KeaDhcpLeaseWatcher : IHostedService { - private static readonly FileStreamOptions _leaseFileStreamOptions = new() + private static readonly FileStreamOptions LeaseFileStreamOptions = new() { Access = FileAccess.Read, Mode = FileMode.Open, @@ -132,16 +135,77 @@ public abstract class KeaDhcpLeaseWatcher : IHostedService private async Task FileReader(CancellationToken stoppingToken) { + Pipe buffer = new(); + var writer = buffer.Writer; + var textDecoder = Encoding.UTF8.GetDecoder(); + SepReader? reader = null; try { - using var streamReader = new StreamReader(Options.Leases, _leaseFileStreamOptions); - using var reader = Sep.Reader().From(streamReader); + using var file = new FileStream(Options.Leases, LeaseFileStreamOptions); + bool awaitLineFeed = false; + int newLinesEncountered = 0; while (!stoppingToken.IsCancellationRequested) { + for (; newLinesEncountered > 0; newLinesEncountered--) + { + if (reader is null) + { + reader = Sep.Reader().From(buffer.Reader.AsStream()); + continue; + } + + if (!reader.MoveNext()) + { + // TODO Error state. + continue; + } + } + + var memory = writer.GetMemory(); + int read = await file.ReadAsync(memory, stoppingToken); + if (read > 0) + { + CountNewLines(textDecoder, memory[..read], ref newLinesEncountered, ref awaitLineFeed); + writer.Advance(read); + } + else + { + // TODO Await. + } } } catch { } + finally + { + writer.Complete(); + reader?.Dispose(); + } + + static void CountNewLines(Decoder decoder, in Memory memory, ref int newLinesEncountered, ref bool awaitLineFeed) + { + Span buffer = stackalloc char[128]; + bool completed = false; + ReadOnlySequence sequence = new(memory); + var reader = new SequenceReader(sequence); + while (!reader.End) + { + decoder.Convert(reader.UnreadSpan, buffer, false, out var bytesUsed, out var charsUsed, out completed); + reader.Advance(bytesUsed); + foreach (ref readonly char c in buffer[..charsUsed]) + { + if (awaitLineFeed || c == '\n') + { + newLinesEncountered++; + awaitLineFeed = false; + } + else if (c == '\r') + { + awaitLineFeed = true; + } + } + } + } } private void OnLeaseChanged(object sender, FileSystemEventArgs e) diff --git a/src/pdns-dhcp/pdns-dhcp.csproj b/src/pdns-dhcp/pdns-dhcp.csproj index e04c634..38c7c18 100644 --- a/src/pdns-dhcp/pdns-dhcp.csproj +++ b/src/pdns-dhcp/pdns-dhcp.csproj @@ -15,6 +15,7 @@ + \ No newline at end of file