fix(ab-transport): trim-only CIP path canonicalisation, observe abandoned shared opens, no Forward Open after dispose during connect

This commit is contained in:
Joseph Doherty
2026-10-07 16:49:19 -04:00
parent a251954bf7
commit 33dbd342e5
5 changed files with 41 additions and 8 deletions
@@ -123,7 +123,14 @@ public sealed class CipConnection : ICipChannel, IAsyncDisposable
}
pending = _pendingOpen;
}
if (started is not null) _ = RunOpenAsync(started);
if (started is not null)
{
// Every waiter may have abandoned the open (its own token); observe a failure so it never
// surfaces as UnobservedTaskException.
_ = started.Task.ContinueWith(static t => _ = t.Exception, CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
_ = RunOpenAsync(started);
}
return pending.WaitAsync(ct);
}
@@ -170,6 +177,12 @@ public sealed class CipConnection : ICipChannel, IAsyncDisposable
{
ThrowIfDisposed(); // disposal may have begun while this attempt waited out the throttle
var client = await EncapsulationClient.ConnectAsync(_key.Host, _key.Port, _o.Timeout, ct).ConfigureAwait(false);
if (Volatile.Read(ref _disposed) != 0)
{
// Disposal began during the TCP connect / RegisterSession: never put a Forward Open on the wire.
await client.DisposeAsync().ConfigureAwait(false);
throw new AbTransportException(AbStatus.Abort, "Connection disposed.");
}
if (_o.Routing != CipRouting.Connected) return new Open(client, null, 0, UnconnectedMessageLimit);
try
{