Auto: opcuaclient-11 — reverse connect (server-initiated)

Closes #283
This commit is contained in:
Joseph Doherty
2026-04-26 06:08:30 -04:00
parent 9a3bc08e1c
commit 5c72deb839
10 changed files with 920 additions and 26 deletions

View File

@@ -253,8 +253,66 @@ public sealed class OpcUaClientDriverOptions
/// short enough that single-node adds re-import promptly.
/// </summary>
public TimeSpan ModelChangeDebounce { get; init; } = TimeSpan.FromSeconds(5);
/// <summary>
/// Reverse-connect (server-initiated) configuration. When
/// <see cref="ReverseConnectOptions.Enabled"/> is <c>true</c> the driver flips the
/// transport direction: instead of dialling the upstream server, it opens a TCP
/// listener on <see cref="ReverseConnectOptions.ListenerUrl"/> and waits for the
/// upstream server to initiate the connection ("ReverseHello"). Required for
/// OT-DMZ deployments where the firewall only permits outbound traffic from the
/// plant network — the upstream server reaches out, the gateway listens.
/// </summary>
public ReverseConnectOptions ReverseConnect { get; init; } = new();
}
/// <summary>
/// Driver knobs for OPC UA reverse-connect (server-initiated) sessions. Mirrors the
/// SDK's <c>Opc.Ua.Client.ReverseConnectManager</c> surface but expressed as plain
/// config so the driver can decide listener-mode vs dial-mode at startup.
/// </summary>
/// <remarks>
/// <para>
/// <b>Direction</b>: in conventional OPC UA the client opens the TCP connection
/// to the server. Reverse-connect inverts this — the server initiates a TCP
/// connection to a listener the client exposes, then sends a <c>ReverseHello</c>
/// message naming itself; the client picks the right session config and continues
/// the OPC UA handshake on the inbound socket. Critical for OT-DMZ networks where
/// the plant firewall only allows outbound traffic.
/// </para>
/// <para>
/// <b>Singleton listener</b>: a single <c>ReverseConnectManager</c> per process
/// keyed on <see cref="ListenerUrl"/> multiplexes inbound connections across
/// driver instances. Two drivers configured with the same listener URL share one
/// underlying TCP socket; the manager dispatches by the upstream's reported
/// <c>ServerUri</c>. See <c>ReverseConnectListener</c>.
/// </para>
/// </remarks>
/// <param name="Enabled">
/// When <c>true</c>, the driver opens a listener at <see cref="ListenerUrl"/> and
/// waits for the upstream server to initiate the session. When <c>false</c>
/// (default), the driver uses the conventional dial path against
/// <see cref="OpcUaClientDriverOptions.EndpointUrls"/>.
/// </param>
/// <param name="ListenerUrl">
/// Local listener URL the SDK binds when reverse-connect is enabled. Typically
/// <c>opc.tcp://0.0.0.0:4844</c> to accept on every interface, or pinned to a
/// specific NIC for multi-homed gateways. Required when
/// <see cref="Enabled"/> is <c>true</c>.
/// </param>
/// <param name="ExpectedServerUri">
/// The upstream server's <c>ApplicationUri</c> the driver expects to see in the
/// <c>ReverseHello</c>. The SDK passes this as the <c>serverUri</c> filter to
/// <c>WaitForConnectionAsync</c> so connections from a different upstream are ignored
/// — important when the listener is shared across multiple drivers and several
/// upstreams might dial in. Leave <c>null</c> to accept the first connection regardless
/// (only safe when exactly one upstream targets the listener).
/// </param>
public sealed record ReverseConnectOptions(
bool Enabled = false,
string? ListenerUrl = null,
string? ExpectedServerUri = null);
/// <summary>
/// Selective import + namespace remap rules for the OPC UA Client driver. Pure local
/// filtering inside <c>BrowseRecursiveAsync</c> + <c>EnrichAndRegisterVariablesAsync</c>;