fix(probe): bound AbLegacy handshake by timeout CTS + stop sw; correct FOCAS timeout comment (code-review)

This commit is contained in:
Joseph Doherty
2026-06-16 07:03:55 -04:00
parent 9bfbbb0fd8
commit 5df3c73204
2 changed files with 13 additions and 3 deletions
@@ -59,12 +59,17 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
var host = parsed.Gateway;
var port = parsed.Port;
// Bound both phases by the caller timeout, independent of `ct`, so a device that accepts
// TCP but stalls the PCCC session cannot hang the probe.
using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
cts.CancelAfter(timeout);
// Phase 1: bare TCP preflight — fast rejection for unreachable hosts.
var sw = Stopwatch.StartNew();
try
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync(host, port, ct);
await socket.ConnectAsync(host, port, cts.Token);
}
catch (SocketException ex)
{
@@ -104,7 +109,7 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
var rt = new LibplctagLegacyTagRuntime(p);
try
{
await rt.InitializeAsync(ct);
await rt.InitializeAsync(cts.Token);
sw.Stop();
// InitializeAsync completed without throwing — either the tag was found (Ok) or
@@ -129,7 +134,10 @@ public sealed class AbLegacyDriverProbe : IDriverProbe
{
// LibPlcTagException carries the Status; classify as reachable vs transport failure.
if (IsReachableException(ex))
{
sw.Stop();
return new(true, "PCCC session OK (controller reachable; probe tag not found)", sw.Elapsed);
}
return new(false, $"Reachable at {host}:{port} but PCCC handshake failed: {ex.Message}", null);
}
@@ -114,7 +114,9 @@ public sealed class FocasDriverProbe : IDriverProbe
}
catch (OperationCanceledException)
{
// ct cancelled or the native handshake exceeded the timeout budget.
// The caller cancelled, or the Task.Run was cancelled before the native call started.
// (A native cnc_allclibhndl3 that is already running is bounded by the timeoutSeconds
// argument passed into it, not by handshakeCts — see TryAllocateAndFreeHandle.)
return new(false, $"Probe timed out after {timeout.TotalSeconds:F0}s.", null);
}
}