diff --git a/src/pdns-dhcp/Kea/KeaDhcp4Lease.cs b/src/pdns-dhcp/Kea/KeaDhcp4Lease.cs index 0fb9b4a..1ed3223 100644 --- a/src/pdns-dhcp/Kea/KeaDhcp4Lease.cs +++ b/src/pdns-dhcp/Kea/KeaDhcp4Lease.cs @@ -20,64 +20,118 @@ public record struct KeaDhcp4Lease( string? UserContext, uint PoolId) { - public static KeaDhcp4Lease Parse(in SepReader.Row row) + public static KeaDhcp4Lease? Parse(in SepReader.Row row) { KeaDhcp4Lease result = new(); for (int i = 0; i < row.ColCount; i++) { - var span = row[i].Span; - switch (i) + if (Parse(ref result, i, row[i].Span) == false) { - case 0: - result.Address = IPAddress.Parse(span); - break; - - case 1 when !span.IsWhiteSpace(): - result.HWAddr = PhysicalAddress.Parse(span); - break; - - case 2: - result.ClientId = span.ToString(); - break; - - case 3: - result.ValidLifetime = uint.Parse(span); - break; - - case 4: - result.Expire = DateTimeOffset.FromUnixTimeSeconds(unchecked((long)ulong.Parse(span))); - break; - - case 5: - result.SubnetId = uint.Parse(span); - break; - - case 6: - result.FqdnFwd = byte.Parse(span) != 0; - break; - - case 7: - result.FqdnRev = byte.Parse(span) != 0; - break; - - case 8: - result.Hostname = KeaDhcpLease.Unescape(span); - break; - - case 9: - result.State = uint.Parse(span); - break; - - case 10: - result.UserContext = KeaDhcpLease.Unescape(span); - break; - - case 11: - result.PoolId = uint.Parse(span); - break; + return null; } } return result; } + + private static bool? Parse(ref KeaDhcp4Lease lease, int column, in ReadOnlySpan span) + { + return column switch + { + 0 => ToIPAddress(ref lease, span), + 1 when !span.IsWhiteSpace() => ToHWAddr(ref lease, span), + 2 => ToClientId(ref lease, span), + 3 => ToValidLifetime(ref lease, span), + 4 => ToExpire(ref lease, span), + 5 => ToSubnetId(ref lease, span), + 6 => ToFqdnFwd(ref lease, span), + 7 => ToFqdnRev(ref lease, span), + 8 => ToHostname(ref lease, span), + 9 => ToState(ref lease, span), + 10 => ToUserContext(ref lease, span), + 11 => ToPoolId(ref lease, span), + _ => null + }; + + static bool? ToIPAddress(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = IPAddress.TryParse(span, out var address); + lease.Address = address!; + return result; + } + + static bool? ToHWAddr(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = PhysicalAddress.TryParse(span, out var hwaddr); + lease.HWAddr = hwaddr!; + return result; + } + + static bool? ToClientId(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + lease.ClientId = span.ToString(); + return true; + } + + static bool? ToValidLifetime(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = uint.TryParse(span, out var validLifetime); + lease.ValidLifetime = validLifetime; + return result; + } + + static bool? ToExpire(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = ulong.TryParse(span, out var expire); + lease.Expire = DateTimeOffset.FromUnixTimeSeconds(unchecked((long)expire)); + return result; + } + + static bool? ToSubnetId(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = uint.TryParse(span, out var subnetId); + lease.SubnetId = subnetId; + return result; + } + + static bool? ToFqdnFwd(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = byte.TryParse(span, out var fqdnFwd); + lease.FqdnFwd = fqdnFwd != 0; + return result; + } + + static bool? ToFqdnRev(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = byte.TryParse(span, out var fqdnRev); + lease.FqdnRev = fqdnRev != 0; + return result; + } + + static bool? ToHostname(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + lease.Hostname = KeaDhcpLease.Unescape(span); + return true; + } + + static bool? ToState(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = uint.TryParse(span, out var state); + lease.State = state; + return result; + } + + static bool? ToUserContext(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + lease.UserContext = KeaDhcpLease.Unescape(span); + return true; + } + + static bool? ToPoolId(ref KeaDhcp4Lease lease, in ReadOnlySpan span) + { + bool result = uint.TryParse(span, out var poolId); + lease.PoolId = poolId; + return result; + } + } } diff --git a/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs b/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs index ecc716a..e26c2ad 100644 --- a/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs +++ b/src/pdns-dhcp/Kea/KeaDhcp4LeaseHandler.cs @@ -8,8 +8,11 @@ public class KeaDhcp4LeaseHandler : IKeaDhcpLeaseHandler { public DhcpLeaseChange? Handle(in SepReader.Row row) { - KeaDhcp4Lease lease = KeaDhcp4Lease.Parse(row); + if (KeaDhcp4Lease.Parse(row) is not { } lease) + { + return null; + } - return default; + return new(lease.Address, lease.Hostname, null, default); } } diff --git a/src/pdns-dhcp/Kea/KeaService.cs b/src/pdns-dhcp/Kea/KeaService.cs index 5087408..863be32 100644 --- a/src/pdns-dhcp/Kea/KeaService.cs +++ b/src/pdns-dhcp/Kea/KeaService.cs @@ -12,15 +12,19 @@ public class KeaService : IHostedService public KeaService(KeaDhcpOptions options, IKeaFactory factory) { + var services = ImmutableArray.CreateBuilder(); + if (options.Dhcp4 is { } dhcp4Options) { - _services.Add(factory.CreateWatcher(factory.CreateHandler4(), dhcp4Options)); + services.Add(factory.CreateWatcher(factory.CreateHandler4(), dhcp4Options)); } if (options.Dhcp6 is { } dhcp6Options) { - _services.Add(factory.CreateWatcher(factory.CreateHandler6(), dhcp6Options)); + services.Add(factory.CreateWatcher(factory.CreateHandler6(), dhcp6Options)); } + + _services = services.DrainToImmutable(); } public Task StartAsync(CancellationToken cancellationToken = default)