diff --git a/docs/DataChannels.md b/docs/DataChannels.md index 6fd97c8b5d..2c0a321ae5 100644 --- a/docs/DataChannels.md +++ b/docs/DataChannels.md @@ -56,14 +56,25 @@ sequence-checks every chunk before the engine sees it. Core itself carries no da vocabulary — `ISecureChannelMessageExtension` and `ISecureChannelMessageHost` name only "a MessageType that is neither a Service call nor part of establishing the SecureChannel". +Both are `internal`, reached through the `InternalsVisibleTo` that Core already grants its +sibling first-party assemblies (`Opc.Ua.Client`, `Opc.Ua.Bindings.Quic`, +`Opc.Ua.Bindings.Https`). The seam exists to keep the engine out of Core, not to invite +other implementers — there is exactly one, and the `opc.quic` binding does not use any of +it, because a QUIC data channel rides its own stream and never becomes a UASC chunk. +Publishing it would commit Core to an abstraction with one implementer for ever. + Two things stay in Core because they are the SecureChannel's own concerns rather than the feature's: `SequenceNumberBudget`, which tracks the sequence space every MessageType draws on, and `UaSCSecureChannelRegistry`, which maps a SecureChannel identifier to the channel -that owns it. Because the budget is Core's, the channel claims the SequenceNumber itself -while it secures the chunk and refuses the send with `Bad_SecureChannelTokenUnknown` when -the space under the current token is exhausted — an extension stalls rather than reuse a -number, and never has to reason about the serialization to do so. The `opc.quic` transport -remains its own package, `OPCFoundation.NetStandard.Opc.Ua.Bindings.Quic`. +that owns it. The budget is internal for the same reason as the seam; the registry is +public because an application writing its own `IServerDataChannelTransport` for inline +framing needs it to resolve the channel behind a request, which +`samples/ConsoleDataChannelStreaming` demonstrates. Because the budget is Core's, the +channel claims the SequenceNumber itself while it secures the chunk and refuses the send +with `Bad_SecureChannelTokenUnknown` when the space under the current token is exhausted — +an extension stalls rather than reuse a number, and never has to reason about the +serialization to do so. The `opc.quic` transport remains its own package, +`OPCFoundation.NetStandard.Opc.Ua.Bindings.Quic`. ## Server side diff --git a/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs b/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs index f8da82d827..00b39b014d 100644 --- a/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs +++ b/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs @@ -42,7 +42,7 @@ namespace Opc.Ua.Bindings /// This owns the STR MessageType on the channel and is the only thing that /// knows the frame format; the channel itself sees an opaque body. /// - public sealed class DataChannelExtension : ISecureChannelMessageExtension, IDataChannelTransport + internal sealed class DataChannelExtension : ISecureChannelMessageExtension, IDataChannelTransport { /// /// Attaches data channels to a SecureChannel. diff --git a/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs b/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs index 1a39843ed7..f648992301 100644 --- a/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs +++ b/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs @@ -111,10 +111,16 @@ namespace Opc.Ua.Bindings /// Returns the extension that owns the STR MessageType on a /// SecureChannel, if one is registered. /// + /// + /// The extension is an implementation detail of the inline framing: + /// a consumer reaches the channels through + /// , which returns the engine rather + /// than the adapter that drives it. + /// /// The SecureChannel. /// The extension. /// is null. - public static bool TryGetDataChannelExtension( + internal static bool TryGetDataChannelExtension( this UaSCUaBinaryChannel channel, out DataChannelExtension? extension) { diff --git a/src/Opc.Ua.Core/Opc.Ua.Core.csproj b/src/Opc.Ua.Core/Opc.Ua.Core.csproj index 20b2c981e0..449293d2e3 100644 --- a/src/Opc.Ua.Core/Opc.Ua.Core.csproj +++ b/src/Opc.Ua.Core/Opc.Ua.Core.csproj @@ -23,6 +23,7 @@ + diff --git a/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs b/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs index f30316b422..05c972907a 100644 --- a/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs +++ b/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs @@ -43,7 +43,7 @@ namespace Opc.Ua.Bindings /// from the channel's single SequenceNumber space. This is the surface that /// makes that possible without publishing the channel's internals. /// - public interface ISecureChannelMessageHost + internal interface ISecureChannelMessageHost { /// /// The largest chunk the peer accepts. @@ -114,7 +114,7 @@ namespace Opc.Ua.Bindings /// faults, which is what OPC 10000-6 §6.7.2.2 requires of a receiver that /// does not implement it. /// - public interface ISecureChannelMessageExtension + internal interface ISecureChannelMessageExtension { /// /// The MessageType this extension owns, without the chunk type. diff --git a/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs b/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs index 249220b916..e2d1703716 100644 --- a/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs +++ b/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs @@ -64,7 +64,7 @@ namespace Opc.Ua.Bindings /// than emitting a chunk that would reuse a value. /// /// - public sealed class SequenceNumberBudget + internal sealed class SequenceNumberBudget { /// /// Creates a budget. diff --git a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs index e6d686435b..1711120965 100644 --- a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs +++ b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs @@ -60,7 +60,7 @@ namespace Opc.Ua.Bindings /// under the current SecurityToken. Every MessageType the channel /// carries draws on the same space. /// - public SequenceNumberBudget SequenceBudget + internal SequenceNumberBudget SequenceBudget { get { @@ -89,7 +89,7 @@ namespace Opc.Ua.Bindings /// The registered extension, which is /// unless another was registered first. /// is null. - public ISecureChannelMessageExtension RegisterMessageExtension( + internal ISecureChannelMessageExtension RegisterMessageExtension( ISecureChannelMessageExtension extension) { if (extension == null) @@ -105,7 +105,7 @@ namespace Opc.Ua.Bindings /// /// The MessageType, without the chunk type. /// The extension. - public bool TryGetMessageExtension( + internal bool TryGetMessageExtension( uint messageType, out ISecureChannelMessageExtension? extension) {