From defd048d135392c512bcaf3edc12d5468e6e02cc Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Fri, 28 Jun 2024 11:00:17 +0200 Subject: [PATCH 1/8] Fix macOS build, move https client transport back to core and other maintenance, (#2659) - change macOS 11 ci builds to newer ones, macOS 11 is deprecated - fix Opc.Ua.Client EventSource message numbering - bump nerdgit to 3.6.139 - include .NET Standard 2.0 builds back in Nuget packages for client and server (complex type support requires netcoreapp2.1 which is end of life) - include .NET Framework 4.7.2 as lowest supported .NET Framework platform - move https client channel back to core library, as it requires only netstandard2.0 and has no other dependencies. - Opc.Ua.Https is now only needed for a https server with kestrel. - fix security warning for system.private.uri - upload Quickstarts.Servers to the preview feed to allow use in the samples repo and avoid duplicate codebase --- .azurepipelines/get-matrix.ps1 | 2 +- .azurepipelines/get-version.ps1 | 2 +- .azurepipelines/preview.yml | 16 +++++++++++----- .azurepipelines/signlistDebug.txt | 15 +++++++++++++++ .azurepipelines/signlistRelease.txt | 15 +++++++++++++++ .../ConsoleReferencePublisher.csproj | 1 + .../ConsoleReferenceServer.csproj | 2 +- .../ConsoleReferenceSubscriber.csproj | 1 + .../Quickstarts.Servers.csproj | 2 +- Docs/PlatformBuild.md | 6 +++++- .../Opc.Ua.Client/OpcUaClientEventSource.cs | 2 +- Libraries/Opc.Ua.PubSub/Opc.Ua.PubSub.csproj | 2 +- .../Opc.Ua.Bindings.Https.csproj | 16 ++-------------- .../Stack/Https/HttpsServiceHost.cs | 5 +++++ .../Stack/Https/HttpsTransportListener.cs | 4 ++++ Stack/Opc.Ua.Core/Opc.Ua.Core.csproj | 6 +++++- .../Stack/Bindings/TransportBindings.cs | 8 ++++++-- .../Stack/Https/HttpsTransportChannel.cs | 2 -- .../Opc.Ua.Configuration.Tests.csproj | 1 + Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj | 1 + .../Opc.Ua.PubSub.Tests.csproj | 1 + Tests/codecoverage.cmd | 2 +- Tests/codecoverage.sh | 2 +- common.props | 5 +++-- targets.props | 8 ++++---- version.props | 4 ++-- 26 files changed, 90 insertions(+), 41 deletions(-) rename Stack/{Opc.Ua.Bindings.Https => Opc.Ua.Core}/Stack/Https/HttpsTransportChannel.cs (99%) diff --git a/.azurepipelines/get-matrix.ps1 b/.azurepipelines/get-matrix.ps1 index 669fca8d6c..c49229f88f 100644 --- a/.azurepipelines/get-matrix.ps1 +++ b/.azurepipelines/get-matrix.ps1 @@ -45,7 +45,7 @@ if ($AgentTable -eq $null -or $AgentTable.Count -eq 0) $agents = @{ windows = "windows-2022" linux = "ubuntu-22.04" - mac = "macOS-11" + mac = "macOS-13" } } else { diff --git a/.azurepipelines/get-version.ps1 b/.azurepipelines/get-version.ps1 index 4e1c732e21..51600fe4dd 100644 --- a/.azurepipelines/get-version.ps1 +++ b/.azurepipelines/get-version.ps1 @@ -10,7 +10,7 @@ try { # Try install tool # Note: Keep Version 3.6.133, it is known working for 4 digit versioning - & dotnet @("tool", "install", "--tool-path", "./tools", "--version", "3.6.133", "--framework", "net60", "nbgv") 2>&1 + & dotnet @("tool", "install", "--tool-path", "./tools", "--version", "3.6.139", "--framework", "net60", "nbgv") 2>&1 $props = (& ./tools/nbgv @("get-version", "-f", "json")) | ConvertFrom-Json if ($LastExitCode -ne 0) { diff --git a/.azurepipelines/preview.yml b/.azurepipelines/preview.yml index aafb51e28b..ac06f4d705 100644 --- a/.azurepipelines/preview.yml +++ b/.azurepipelines/preview.yml @@ -70,6 +70,7 @@ jobs: command: restore projects: 'UA Core Library.sln' arguments: '--configuration ${{parameters.config}}' + restoreArguments: '--disable-parallel' - task: DotNetCoreCLI@2 displayName: Build ${{parameters.config}} inputs: @@ -130,11 +131,6 @@ jobs: script: | NuGetKeyVaultSignTool sign $(Build.ArtifactStagingDirectory)/**/OPCFoundation.*.nupkg --file-digest sha256 --timestamp-rfc3161 http://timestamp.digicert.com --timestamp-digest sha256 --azure-key-vault-url "$(SigningVaultURL)" --azure-key-vault-client-id "$(SigningClientId)" --azure-key-vault-tenant-id "$(SigningTenantId)" --azure-key-vault-client-secret "$(SigningClientSecret)" --azure-key-vault-certificate "$(SigningCertName)" NuGetKeyVaultSignTool sign $(Build.ArtifactStagingDirectory)/**/OPCFoundation.*.snupkg --file-digest sha256 --timestamp-rfc3161 http://timestamp.digicert.com --timestamp-digest sha256 --azure-key-vault-url "$(SigningVaultURL)" --azure-key-vault-client-id "$(SigningClientId)" --azure-key-vault-tenant-id "$(SigningTenantId)" --azure-key-vault-client-secret "$(SigningClientSecret)" --azure-key-vault-certificate "$(SigningCertName)" - - task: PublishPipelineArtifact@1 - displayName: 'Publish Artifacts' - inputs: - path: $(Build.ArtifactStagingDirectory) - artifact: 'opcua_${{parameters.config}}_$(NBGV_Version)_$(NBGV_NugetPackageVersion)' - ${{ if eq(parameters.upload, 'True') }}: - task: NuGetCommand@2 displayName: Upload Nuget Preview @@ -144,3 +140,13 @@ jobs: nuGetFeedType: 'internal' publishVstsFeed: '$(VSTSFEED)' allowPackageConflicts: true + - task: CmdLine@2 + displayName: 'Remove Quickstarts.Servers' + inputs: + script: | + del /q /s $(Build.ArtifactStagingDirectory)\OPCFoundation.NetStandard.Opc.Ua.Quickstarts.Servers.*.*nupkg + - task: PublishPipelineArtifact@1 + displayName: 'Publish Artifacts' + inputs: + path: $(Build.ArtifactStagingDirectory) + artifact: 'opcua_${{parameters.config}}_$(NBGV_Version)_$(NBGV_NugetPackageVersion)' diff --git a/.azurepipelines/signlistDebug.txt b/.azurepipelines/signlistDebug.txt index 5c9998addd..c65a2d4cca 100644 --- a/.azurepipelines/signlistDebug.txt +++ b/.azurepipelines/signlistDebug.txt @@ -1,42 +1,57 @@ Stack\Opc.Ua.Core\bin\Debug\netstandard2.0\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Debug\netstandard2.1\Opc.Ua.Core.dll +Stack\Opc.Ua.Core\bin\Debug\net472\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Debug\net48\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Debug\net6.0\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Debug\net8.0\Opc.Ua.Core.dll Stack\Opc.Ua.Bindings.Https\bin\Debug\netcoreapp3.1\Opc.Ua.Bindings.Https.dll +Stack\Opc.Ua.Bindings.Https\bin\Debug\net472\Opc.Ua.Bindings.Https.dll Stack\Opc.Ua.Bindings.Https\bin\Debug\net48\Opc.Ua.Bindings.Https.dll Stack\Opc.Ua.Bindings.Https\bin\Debug\net6.0\Opc.Ua.Bindings.Https.dll Stack\Opc.Ua.Bindings.Https\bin\Debug\net8.0\Opc.Ua.Bindings.Https.dll +Libraries\Opc.Ua.Server\bin\Debug\netstandard2.0\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Debug\netstandard2.1\Opc.Ua.Server.dll +Libraries\Opc.Ua.Server\bin\Debug\net472\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Debug\net48\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Debug\net6.0\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Debug\net8.0\Opc.Ua.Server.dll +Libraries\Opc.Ua.Client\bin\Debug\netstandard2.0\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Debug\netstandard2.1\Opc.Ua.Client.dll +Libraries\Opc.Ua.Client\bin\Debug\net472\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Debug\net48\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Debug\net6.0\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Debug\net8.0\Opc.Ua.Client.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\netstandard2.1\Opc.Ua.Client.ComplexTypes.dll +Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\net472\Opc.Ua.Client.ComplexTypes.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\net48\Opc.Ua.Client.ComplexTypes.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\net6.0\Opc.Ua.Client.ComplexTypes.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Debug\net8.0\Opc.Ua.Client.ComplexTypes.dll +Libraries\Opc.Ua.Configuration\bin\Debug\netstandard2.0\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Debug\netstandard2.1\Opc.Ua.Configuration.dll +Libraries\Opc.Ua.Configuration\bin\Debug\net472\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Debug\net48\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Debug\net6.0\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Debug\net8.0\Opc.Ua.Configuration.dll +Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\netstandard2.0\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\netstandard2.1\Opc.Ua.Gds.Client.Common.dll +Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net472\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net48\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net6.0\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net8.0\Opc.Ua.Gds.Client.Common.dll +Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\netstandard2.0\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\netstandard2.1\Opc.Ua.Gds.Server.Common.dll +Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net472\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net48\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net6.0\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net8.0\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Security.Certificates\bin\Debug\netstandard2.0\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Debug\netstandard2.1\Opc.Ua.Security.Certificates.dll +Libraries\Opc.Ua.Security.Certificates\bin\Debug\net472\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Debug\net48\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Debug\net6.0\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Debug\net8.0\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.PubSub\bin\Debug\netstandard2.1\Opc.Ua.PubSub.dll +Libraries\Opc.Ua.PubSub\bin\Debug\net472\Opc.Ua.PubSub.dll Libraries\Opc.Ua.PubSub\bin\Debug\net48\Opc.Ua.PubSub.dll Libraries\Opc.Ua.PubSub\bin\Debug\net6.0\Opc.Ua.PubSub.dll Libraries\Opc.Ua.PubSub\bin\Debug\net8.0\Opc.Ua.PubSub.dll diff --git a/.azurepipelines/signlistRelease.txt b/.azurepipelines/signlistRelease.txt index 8a844e3475..824314c07a 100644 --- a/.azurepipelines/signlistRelease.txt +++ b/.azurepipelines/signlistRelease.txt @@ -1,42 +1,57 @@ Stack\Opc.Ua.Core\bin\Release\netstandard2.0\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Release\netstandard2.1\Opc.Ua.Core.dll +Stack\Opc.Ua.Core\bin\Release\net472\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Release\net48\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Release\net6.0\Opc.Ua.Core.dll Stack\Opc.Ua.Core\bin\Release\net8.0\Opc.Ua.Core.dll Stack\Opc.Ua.Bindings.Https\bin\Release\netcoreapp3.1\Opc.Ua.Bindings.Https.dll +Stack\Opc.Ua.Bindings.Https\bin\Release\net472\Opc.Ua.Bindings.Https.dll Stack\Opc.Ua.Bindings.Https\bin\Release\net48\Opc.Ua.Bindings.Https.dll Stack\Opc.Ua.Bindings.Https\bin\Release\net6.0\Opc.Ua.Bindings.Https.dll Stack\Opc.Ua.Bindings.Https\bin\Release\net8.0\Opc.Ua.Bindings.Https.dll +Libraries\Opc.Ua.Server\bin\Release\netstandard2.0\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Release\netstandard2.1\Opc.Ua.Server.dll +Libraries\Opc.Ua.Server\bin\Release\net472\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Release\net48\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Release\net6.0\Opc.Ua.Server.dll Libraries\Opc.Ua.Server\bin\Release\net8.0\Opc.Ua.Server.dll +Libraries\Opc.Ua.Client\bin\Release\netstandard2.0\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Release\netstandard2.1\Opc.Ua.Client.dll +Libraries\Opc.Ua.Client\bin\Release\net472\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Release\net48\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Release\net6.0\Opc.Ua.Client.dll Libraries\Opc.Ua.Client\bin\Release\net8.0\Opc.Ua.Client.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\netstandard2.1\Opc.Ua.Client.ComplexTypes.dll +Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\net472\Opc.Ua.Client.ComplexTypes.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\net48\Opc.Ua.Client.ComplexTypes.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\net6.0\Opc.Ua.Client.ComplexTypes.dll Libraries\Opc.Ua.Client.ComplexTypes\bin\Release\net8.0\Opc.Ua.Client.ComplexTypes.dll +Libraries\Opc.Ua.Configuration\bin\Release\netstandard2.0\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Release\netstandard2.1\Opc.Ua.Configuration.dll +Libraries\Opc.Ua.Configuration\bin\Release\net472\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Release\net48\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Release\net6.0\Opc.Ua.Configuration.dll Libraries\Opc.Ua.Configuration\bin\Release\net8.0\Opc.Ua.Configuration.dll +Libraries\Opc.Ua.Gds.Client.Common\bin\Release\netstandard2.0\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Release\netstandard2.1\Opc.Ua.Gds.Client.Common.dll +Libraries\Opc.Ua.Gds.Client.Common\bin\Release\net472\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Release\net48\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Release\net6.0\Opc.Ua.Gds.Client.Common.dll Libraries\Opc.Ua.Gds.Client.Common\bin\Release\net8.0\Opc.Ua.Gds.Client.Common.dll +Libraries\Opc.Ua.Gds.Server.Common\bin\Release\netstandard2.0\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Release\netstandard2.1\Opc.Ua.Gds.Server.Common.dll +Libraries\Opc.Ua.Gds.Server.Common\bin\Release\net472\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Release\net48\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Release\net6.0\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Gds.Server.Common\bin\Release\net8.0\Opc.Ua.Gds.Server.Common.dll Libraries\Opc.Ua.Security.Certificates\bin\Release\netstandard2.0\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Release\netstandard2.1\Opc.Ua.Security.Certificates.dll +Libraries\Opc.Ua.Security.Certificates\bin\Release\net472\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Release\net48\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Release\net6.0\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.Security.Certificates\bin\Release\net8.0\Opc.Ua.Security.Certificates.dll Libraries\Opc.Ua.PubSub\bin\Release\netstandard2.1\Opc.Ua.PubSub.dll +Libraries\Opc.Ua.PubSub\bin\Release\net472\Opc.Ua.PubSub.dll Libraries\Opc.Ua.PubSub\bin\Release\net48\Opc.Ua.PubSub.dll Libraries\Opc.Ua.PubSub\bin\Release\net6.0\Opc.Ua.PubSub.dll Libraries\Opc.Ua.PubSub\bin\Release\net8.0\Opc.Ua.PubSub.dll diff --git a/Applications/ConsoleReferencePublisher/ConsoleReferencePublisher.csproj b/Applications/ConsoleReferencePublisher/ConsoleReferencePublisher.csproj index fd6db35c7d..d4ce14e522 100644 --- a/Applications/ConsoleReferencePublisher/ConsoleReferencePublisher.csproj +++ b/Applications/ConsoleReferencePublisher/ConsoleReferencePublisher.csproj @@ -13,6 +13,7 @@ + diff --git a/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj b/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj index 718d44d212..c94b8bf06a 100644 --- a/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj +++ b/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj @@ -7,7 +7,7 @@ ConsoleReferenceServer OPC Foundation .NET Console Reference Server - Copyright © 2004-2023 OPC Foundation, Inc + Copyright © 2004-2024 OPC Foundation, Inc Quickstarts 46345736-a30f-4466-b3bb-42548ecfaacc diff --git a/Applications/ConsoleReferenceSubscriber/ConsoleReferenceSubscriber.csproj b/Applications/ConsoleReferenceSubscriber/ConsoleReferenceSubscriber.csproj index 51ade0d665..b6908d4800 100644 --- a/Applications/ConsoleReferenceSubscriber/ConsoleReferenceSubscriber.csproj +++ b/Applications/ConsoleReferenceSubscriber/ConsoleReferenceSubscriber.csproj @@ -13,6 +13,7 @@ + diff --git a/Applications/Quickstarts.Servers/Quickstarts.Servers.csproj b/Applications/Quickstarts.Servers/Quickstarts.Servers.csproj index 14690411d7..f613862414 100644 --- a/Applications/Quickstarts.Servers/Quickstarts.Servers.csproj +++ b/Applications/Quickstarts.Servers/Quickstarts.Servers.csproj @@ -9,7 +9,7 @@ OPC UA Quickstarts Servers Class Library PackageReference CS1591;CS1573;RCS1139 - false + true true diff --git a/Docs/PlatformBuild.md b/Docs/PlatformBuild.md index 634aeba152..b895fac253 100644 --- a/Docs/PlatformBuild.md +++ b/Docs/PlatformBuild.md @@ -40,6 +40,7 @@ Currently the released Nuget packages support a wide variety of .NET platforms: The following .NET versions are currently supported by the class libraries - .NET Standard 2.0 - .NET Standard 2.1 +- .NET Framework 4.7.2 - .NET Framework 4.8 * - .NET 6.0 * - .NET 8.0 ** @@ -47,6 +48,9 @@ The following .NET versions are currently supported by the class libraries The following platform is deprecated but can still be built and tested: - .NET Framework 4.6.2 +Limitations: +- .NET Standard 2.0 and .NET Framework 4.6.2 has no support for the complex types library, as it requires netcoreapp2.1 which is end of life. Similarly there will net be support for ECC profiles due to the missing ECC support. + To reduce the ci build overhead and the number of tests to be run in Visual Studio, only the tagged versions (* and **) are part of a qualifying ci build to pass a pull request. All other platforms are only tested in weekly scheduled or manual ci builds. @@ -56,7 +60,7 @@ Another option is to test run such a custom target in a command window with a ba ```xml diff --git a/Libraries/Opc.Ua.Client/OpcUaClientEventSource.cs b/Libraries/Opc.Ua.Client/OpcUaClientEventSource.cs index adda1a621f..c01e1abfdf 100644 --- a/Libraries/Opc.Ua.Client/OpcUaClientEventSource.cs +++ b/Libraries/Opc.Ua.Client/OpcUaClientEventSource.cs @@ -54,7 +54,7 @@ internal class OpcUaClientEventSource : EventSource private const int SubscriptionStateId = 1; private const int NotificationId = SubscriptionStateId + 1; private const int NotificationReceivedId = NotificationId + 1; - private const int PublishStartId = NotificationId + 1; + private const int PublishStartId = NotificationReceivedId + 1; private const int PublishStopId = PublishStartId + 1; /// diff --git a/Libraries/Opc.Ua.PubSub/Opc.Ua.PubSub.csproj b/Libraries/Opc.Ua.PubSub/Opc.Ua.PubSub.csproj index cba0c56ec2..d287a1fd39 100644 --- a/Libraries/Opc.Ua.PubSub/Opc.Ua.PubSub.csproj +++ b/Libraries/Opc.Ua.PubSub/Opc.Ua.PubSub.csproj @@ -2,7 +2,7 @@ Opc.Ua.PubSub - $(LibTargetFrameworks) + $(LibxTargetFrameworks) OPCFoundation.NetStandard.Opc.Ua.PubSub Opc.Ua.PubSub OPC UA PubSub Class Library diff --git a/Stack/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj b/Stack/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj index 73b3dc7811..c06b59084c 100644 --- a/Stack/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj +++ b/Stack/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj @@ -1,4 +1,4 @@ - + true @@ -6,7 +6,7 @@ Opc.Ua.Bindings.Https OPCFoundation.NetStandard.Opc.Ua.Bindings.Https Opc.Ua.Bindings - OPC UA Https Binding Library + OPC UA Https Binding Library for a Opc.Ua.Server. true true @@ -38,18 +38,6 @@ - - - - - - - - - - - - diff --git a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs index aad624e8ae..f76c18d2ee 100644 --- a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs +++ b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs @@ -4,8 +4,13 @@ - GPL V2: everybody else RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/ GNU General Public License as published by the Free Software Foundation; + version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2 + This source code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ + using System; using System.Collections.Generic; using System.Security.Cryptography.X509Certificates; diff --git a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs index 1f1c79f0ba..ea1e5fceb8 100644 --- a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs +++ b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs @@ -4,6 +4,10 @@ - GPL V2: everybody else RCL license terms accompanied with this source code. See http://opcfoundation.org/License/RCL/1.00/ GNU General Public License as published by the Free Software Foundation; + version 2 of the License are accompanied with this source code. See http://opcfoundation.org/License/GPLv2 + This source code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ using System; diff --git a/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj b/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj index 2498aa3c4e..280460251c 100644 --- a/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj +++ b/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj @@ -44,7 +44,7 @@ use latest versions only on .NET 5/6/7/8, otherwise 3.1.x --> - + @@ -74,6 +74,10 @@ + + + + diff --git a/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs b/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs index 36acfb737d..35f86ab053 100644 --- a/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs +++ b/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs @@ -21,8 +21,12 @@ public static class TransportBindings { static TransportBindings() { - Channels = new TransportChannelBindings(new Type[] { typeof(TcpTransportChannelFactory) }); - Listeners = new TransportListenerBindings(new Type[] { typeof(TcpTransportListenerFactory) }); + Channels = new TransportChannelBindings(new Type[] { + typeof(TcpTransportChannelFactory), + typeof(HttpsTransportChannelFactory), + typeof(OpcHttpsTransportChannelFactory) }); + Listeners = new TransportListenerBindings(new Type[] { + typeof(TcpTransportListenerFactory) }); } /// diff --git a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportChannel.cs b/Stack/Opc.Ua.Core/Stack/Https/HttpsTransportChannel.cs similarity index 99% rename from Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportChannel.cs rename to Stack/Opc.Ua.Core/Stack/Https/HttpsTransportChannel.cs index 21601552d1..387f224532 100644 --- a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportChannel.cs +++ b/Stack/Opc.Ua.Core/Stack/Https/HttpsTransportChannel.cs @@ -10,7 +10,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ - using System; using System.IO; using System.Net; @@ -515,4 +514,3 @@ private void SaveSettings(Uri url, TransportChannelSettings settings) private static readonly MediaTypeHeaderValue s_mediaTypeHeaderValue = new MediaTypeHeaderValue("application/octet-stream"); } } - diff --git a/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj b/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj index 973fbe789f..d1b385b75b 100644 --- a/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj +++ b/Tests/Opc.Ua.Configuration.Tests/Opc.Ua.Configuration.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj b/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj index 9fd3b5811b..3ae412bb0d 100644 --- a/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj +++ b/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj @@ -23,6 +23,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj b/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj index 0ddbba1646..dee35417b5 100644 --- a/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj +++ b/Tests/Opc.Ua.PubSub.Tests/Opc.Ua.PubSub.Tests.csproj @@ -22,6 +22,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Tests/codecoverage.cmd b/Tests/codecoverage.cmd index ecaa7f2e3c..66b9869004 100644 --- a/Tests/codecoverage.cmd +++ b/Tests/codecoverage.cmd @@ -8,7 +8,7 @@ set current-path=%~dp0 rem // remove trailing slash set current-path=%current-path:~0,-1% set build_root=%current-path%\.. -set framework=net6.0 +set framework=net8.0 cd %build_root% diff --git a/Tests/codecoverage.sh b/Tests/codecoverage.sh index e66636f549..8059165ed8 100755 --- a/Tests/codecoverage.sh +++ b/Tests/codecoverage.sh @@ -7,7 +7,7 @@ cd $BUILDROOT rm -r ./CodeCoverage rm -r ./TestResults -dotnet test "UA Core Library.sln" -v n --configuration Release --framework net6.0 --collect:"XPlat Code Coverage" --settings ./Tests/coverlet.runsettings.xml --results-directory ./TestResults +dotnet test "UA Core Library.sln" -v n --configuration Release --framework net8.0 --collect:"XPlat Code Coverage" --settings ./Tests/coverlet.runsettings.xml --results-directory ./TestResults # ensure latest report tool is installed dotnet tool uninstall -g dotnet-reportgenerator-globaltool diff --git a/common.props b/common.props index 3db40bb6b1..d3c770f8d2 100644 --- a/common.props +++ b/common.props @@ -14,10 +14,11 @@ true 7.3 - true - + + all + true diff --git a/targets.props b/targets.props index 2a7262ff73..c3e9f77ebe 100644 --- a/targets.props +++ b/targets.props @@ -118,10 +118,10 @@ net6.0;net48 net8.0 net48;net6.0 - net48;netstandard2.1;net6.0;net8.0 - net48;netstandard2.0;netstandard2.1;net6.0;net8.0 - net48;netstandard2.1;net6.0;net8.0 - net48;netcoreapp3.1;net6.0;net8.0 + net472;net48;netstandard2.0;netstandard2.1;net6.0;net8.0 + net472;net48;netstandard2.0;netstandard2.1;net6.0;net8.0 + net472;net48;netstandard2.1;net6.0;net8.0 + net472;net48;netcoreapp3.1;net6.0;net8.0 diff --git a/version.props b/version.props index f36a2406cd..2b2e2fd1d6 100644 --- a/version.props +++ b/version.props @@ -1,7 +1,7 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive From 14025f8b7224467e8c01c5c74095654bc77d7975 Mon Sep 17 00:00:00 2001 From: JSGInray <38945208+JSGInray@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:38:29 +0200 Subject: [PATCH 2/8] Fix NullReference in XmlDecoder.ReadExpandedNodeId (#2636) * Fix XmlDecoder.ReadExpandedNodeId fails with a NullReference when the ExpandedNodeId that was read is equal to ExpandedNodeId.Null --- Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs index 22c8f04cd6..823be9d7c3 100644 --- a/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs +++ b/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs @@ -1074,12 +1074,12 @@ public ExpandedNodeId ReadExpandedNodeId(string fieldName) EndField(fieldName); } - if (m_namespaceMappings != null && m_namespaceMappings.Length > value.NamespaceIndex) + if (m_namespaceMappings != null && m_namespaceMappings.Length > value.NamespaceIndex && !value.IsNull) { value.SetNamespaceIndex(m_namespaceMappings[value.NamespaceIndex]); } - if (m_serverMappings != null && m_serverMappings.Length > value.ServerIndex) + if (m_serverMappings != null && m_serverMappings.Length > value.ServerIndex && !value.IsNull) { value.SetServerIndex(m_serverMappings[value.ServerIndex]); } From 8cb76640bc933749f0d374f32e226c2e8894bfbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 16:39:34 +0200 Subject: [PATCH 3/8] Bump Serilog.Sinks.File and System.Diagnostics.DiagnosticSource (#2654) Bumps [Serilog.Sinks.File](https://github.com/serilog/serilog-sinks-file) and [System.Diagnostics.DiagnosticSource](https://github.com/dotnet/runtime). These dependencies needed to be updated together. Updates `Serilog.Sinks.File` from 5.0.0 to 6.0.0 - [Release notes](https://github.com/serilog/serilog-sinks-file/releases) - [Changelog](https://github.com/serilog/serilog-sinks-file/blob/dev/CHANGES.md) - [Commits](https://github.com/serilog/serilog-sinks-file/compare/v5.0.0...v6.0.0) Updates `System.Diagnostics.DiagnosticSource` from 6.0.1 to 8.0.1 - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v6.0.1...v8.0.1) --- updated-dependencies: - dependency-name: Serilog.Sinks.File dependency-type: direct:production update-type: version-update:semver-major - dependency-name: System.Diagnostics.DiagnosticSource dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../ConsoleReferenceClient/ConsoleReferenceClient.csproj | 2 +- .../ConsoleReferenceServer/ConsoleReferenceServer.csproj | 2 +- Applications/ReferenceServer/Reference Server.csproj | 2 +- Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj b/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj index 037838457b..8bb3208cac 100644 --- a/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj +++ b/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj @@ -28,7 +28,7 @@ - + diff --git a/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj b/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj index c94b8bf06a..dde23c3a79 100644 --- a/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj +++ b/Applications/ConsoleReferenceServer/ConsoleReferenceServer.csproj @@ -37,7 +37,7 @@ - + diff --git a/Applications/ReferenceServer/Reference Server.csproj b/Applications/ReferenceServer/Reference Server.csproj index f8c0263f09..2b29915f94 100644 --- a/Applications/ReferenceServer/Reference Server.csproj +++ b/Applications/ReferenceServer/Reference Server.csproj @@ -165,7 +165,7 @@ 3.0.0 - 5.0.0 + 6.0.0 diff --git a/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj b/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj index 6a9689c10d..6ea13f5fe7 100644 --- a/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj +++ b/Fuzzing/Encoders/Fuzz.Tools/Encoders.Fuzz.Tools.csproj @@ -26,7 +26,7 @@ - + From 57aebf4909e97610c8241c92a74c10b7ad9fd3d3 Mon Sep 17 00:00:00 2001 From: Suciu Mircea Adrian Date: Mon, 1 Jul 2024 16:47:57 +0300 Subject: [PATCH 4/8] [Client] Compute time intervals independent of System Time changes (#2639) * Client side time computations independent of system time * Fixed KeepAliveStopped after merge * Fix OnKeepAliveError after merge * Minor change (remove double cast) * rename to tickcount * fix comment * fixx session reconnect handler * fix subtraction * fix AsyncRequest calculation * fix comment --------- Co-authored-by: Martin Regen --- Libraries/Opc.Ua.Client/ISession.cs | 6 +++ .../Opc.Ua.Client/ReverseConnectManager.cs | 13 +++--- Libraries/Opc.Ua.Client/Session.cs | 44 +++++++++++++------ .../Opc.Ua.Client/SessionReconnectHandler.cs | 24 +++------- Libraries/Opc.Ua.Client/Subscription.cs | 27 ++++++++---- Libraries/Opc.Ua.Client/TraceableSession.cs | 3 ++ Tests/Opc.Ua.Client.Tests/ClientTest.cs | 1 + 7 files changed, 72 insertions(+), 46 deletions(-) diff --git a/Libraries/Opc.Ua.Client/ISession.cs b/Libraries/Opc.Ua.Client/ISession.cs index c1967befbc..6ff8c3dc57 100644 --- a/Libraries/Opc.Ua.Client/ISession.cs +++ b/Libraries/Opc.Ua.Client/ISession.cs @@ -248,9 +248,15 @@ public interface ISession : ISessionClient /// /// Gets the time of the last keep alive. + /// This time may not be monotonic if the system time is changed. /// DateTime LastKeepAliveTime { get; } + /// + /// Gets the TickCount in ms of the last keep alive based on . + /// + int LastKeepAliveTickCount { get; } + /// /// Gets the number of outstanding publish or keep alive requests. /// diff --git a/Libraries/Opc.Ua.Client/ReverseConnectManager.cs b/Libraries/Opc.Ua.Client/ReverseConnectManager.cs index 31c129bddc..d8a9985454 100644 --- a/Libraries/Opc.Ua.Client/ReverseConnectManager.cs +++ b/Libraries/Opc.Ua.Client/ReverseConnectManager.cs @@ -621,8 +621,9 @@ private void AddEndpointInternal(Uri endpointUrl, bool configEntry) /// private async Task OnConnectionWaiting(object sender, ConnectionWaitingEventArgs e) { - DateTime startTime = DateTime.UtcNow; - DateTime endTime = startTime + TimeSpan.FromMilliseconds(m_configuration.HoldTime); + int startTime = HiResClock.TickCount; + int endTime = startTime + m_configuration.HoldTime; + bool matched = MatchRegistration(sender, e); while (!matched) { @@ -632,8 +633,8 @@ private async Task OnConnectionWaiting(object sender, ConnectionWaitingEventArgs { ct = m_cts.Token; } - TimeSpan delay = endTime - DateTime.UtcNow; - if (delay.TotalMilliseconds > 0) + int delay = endTime - HiResClock.TickCount; + if (delay > 0) { await Task.Delay(delay, ct).ContinueWith(tsk => { if (tsk.IsCanceled) @@ -643,7 +644,7 @@ await Task.Delay(delay, ct).ContinueWith(tsk => { { Utils.LogInfo("Matched reverse connection {0} {1} after {2}ms", e.ServerUri, e.EndpointUrl, - (int)(DateTime.UtcNow - startTime).TotalMilliseconds); + HiResClock.TickCount - startTime); } } } @@ -654,7 +655,7 @@ await Task.Delay(delay, ct).ContinueWith(tsk => { Utils.LogInfo("{0} reverse connection: {1} {2} after {3}ms", e.Accepted ? "Accepted" : "Rejected", - e.ServerUri, e.EndpointUrl, (int)DateTime.UtcNow.Subtract(startTime).TotalMilliseconds); + e.ServerUri, e.EndpointUrl, HiResClock.TickCount - startTime); } /// diff --git a/Libraries/Opc.Ua.Client/Session.cs b/Libraries/Opc.Ua.Client/Session.cs index 1cb430bfb0..10d187c40d 100644 --- a/Libraries/Opc.Ua.Client/Session.cs +++ b/Libraries/Opc.Ua.Client/Session.cs @@ -757,10 +757,10 @@ public bool KeepAliveStopped StatusCode lastKeepAliveErrorStatusCode = m_lastKeepAliveErrorStatusCode; if (StatusCode.IsGood(lastKeepAliveErrorStatusCode) || lastKeepAliveErrorStatusCode == StatusCodes.BadNoCommunication) { - TimeSpan delta = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - Interlocked.Read(ref m_lastKeepAliveTime)); + int delta = HiResClock.TickCount - m_lastKeepAliveTickCount; // add a guard band to allow for network lag. - return (m_keepAliveInterval + kKeepAliveGuardBand) <= delta.TotalMilliseconds; + return (m_keepAliveInterval + kKeepAliveGuardBand) <= delta; } // another error was reported which caused keep alive to stop. @@ -780,6 +780,18 @@ public DateTime LastKeepAliveTime } } + /// + /// Gets the TickCount in ms of the last keep alive based on . + /// Independent of system time changes. + /// + public int LastKeepAliveTickCount + { + get + { + return m_lastKeepAliveTickCount; + } + } + /// /// Gets the number of outstanding publish or keep alive requests. /// @@ -3708,6 +3720,7 @@ private void StartKeepAliveTimer() m_lastKeepAliveErrorStatusCode = StatusCodes.Good; Interlocked.Exchange(ref m_lastKeepAliveTime, DateTime.UtcNow.Ticks); + m_lastKeepAliveTickCount = HiResClock.TickCount; m_serverState = ServerState.Unknown; @@ -3791,7 +3804,7 @@ private void AsyncRequestStarted(IAsyncResult result, uint requestId, uint typeI state.RequestId = requestId; state.RequestTypeId = typeId; state.Result = result; - state.Timestamp = DateTime.UtcNow; + state.TickCount = HiResClock.TickCount; m_outstandingRequests.AddLast(state); } @@ -3811,11 +3824,11 @@ private void AsyncRequestCompleted(IAsyncResult result, uint requestId, uint typ if (state != null) { // mark any old requests as default (i.e. the should have returned before this request). - DateTime maxAge = state.Timestamp.AddSeconds(-1); + const int maxAge = 1000; for (LinkedListNode ii = m_outstandingRequests.First; ii != null; ii = ii.Next) { - if (ii.Value.RequestTypeId == typeId && ii.Value.Timestamp < maxAge) + if (ii.Value.RequestTypeId == typeId && (state.TickCount - ii.Value.TickCount) > maxAge) { ii.Value.Defunct = true; } @@ -3831,7 +3844,7 @@ private void AsyncRequestCompleted(IAsyncResult result, uint requestId, uint typ state.RequestId = requestId; state.RequestTypeId = typeId; state.Result = result; - state.Timestamp = DateTime.UtcNow; + state.TickCount = HiResClock.TickCount; m_outstandingRequests.AddLast(state); } @@ -3984,6 +3997,7 @@ protected virtual void OnKeepAlive(ServerState currentState, DateTime currentTim m_lastKeepAliveErrorStatusCode = StatusCodes.Good; Interlocked.Exchange(ref m_lastKeepAliveTime, DateTime.UtcNow.Ticks); + m_lastKeepAliveTickCount = HiResClock.TickCount; lock (m_outstandingRequests) { @@ -4002,6 +4016,7 @@ protected virtual void OnKeepAlive(ServerState currentState, DateTime currentTim { m_lastKeepAliveErrorStatusCode = StatusCodes.Good; Interlocked.Exchange(ref m_lastKeepAliveTime, DateTime.UtcNow.Ticks); + m_lastKeepAliveTickCount = HiResClock.TickCount; } // save server state. @@ -4027,19 +4042,19 @@ protected virtual void OnKeepAlive(ServerState currentState, DateTime currentTim /// protected virtual bool OnKeepAliveError(ServiceResult result) { - DateTime now = DateTime.UtcNow; m_lastKeepAliveErrorStatusCode = result.StatusCode; if (result.StatusCode == StatusCodes.BadNoCommunication) { - // keep alive read timed out - long delta = now.Ticks - Interlocked.Read(ref m_lastKeepAliveTime); + //keep alive read timed out + int delta = HiResClock.TickCount - m_lastKeepAliveTickCount; Utils.LogInfo( - "KEEP ALIVE LATE: {0}s, EndpointUrl={1}, RequestCount={2}/{3}", - ((double)delta) / TimeSpan.TicksPerSecond, + "KEEP ALIVE LATE: {0}ms, EndpointUrl={1}, RequestCount={2}/{3}", + delta, this.Endpoint?.EndpointUrl, this.GoodPublishRequestCount, this.OutstandingRequestCount); + } KeepAliveEventHandler callback = m_KeepAlive; @@ -4048,7 +4063,7 @@ protected virtual bool OnKeepAliveError(ServiceResult result) { try { - KeepAliveEventArgs args = new KeepAliveEventArgs(result, ServerState.Unknown, now); + KeepAliveEventArgs args = new KeepAliveEventArgs(result, ServerState.Unknown, DateTime.UtcNow); callback(this, args); return !args.CancelKeepAlive; } @@ -4910,7 +4925,7 @@ public IAsyncResult BeginPublish(int timeout) var state = new AsyncRequestState { RequestTypeId = DataTypes.PublishRequest, RequestId = requestHeader.RequestHandle, - Timestamp = DateTime.UtcNow + TickCount = HiResClock.TickCount }; CoreClientUtils.EventLog.PublishStart((int)requestHeader.RequestHandle); @@ -6360,6 +6375,7 @@ private static void UpdateLatestSequenceNumberToSend(ref uint latestSequenceNumb private long m_publishCounter; private int m_tooManyPublishRequests; private long m_lastKeepAliveTime; + private int m_lastKeepAliveTickCount; private StatusCode m_lastKeepAliveErrorStatusCode; private ServerState m_serverState; private int m_keepAliveInterval; @@ -6380,7 +6396,7 @@ private class AsyncRequestState { public uint RequestTypeId; public uint RequestId; - public DateTime Timestamp; + public int TickCount; public IAsyncResult Result; public bool Defunct; } diff --git a/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs b/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs index eb2e9d4ca2..f471e5a1ee 100644 --- a/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs +++ b/Libraries/Opc.Ua.Client/SessionReconnectHandler.cs @@ -288,7 +288,7 @@ public virtual int CheckedReconnectPeriod(int reconnectPeriod, bool exponentialB /// private async void OnReconnectAsync(object state) { - DateTime reconnectStart = DateTime.UtcNow; + int reconnectStart = HiResClock.TickCount; try { // check for exit. @@ -354,7 +354,7 @@ await DoReconnectAsync().ConfigureAwait(false)) } else { - int elapsed = (int)DateTime.UtcNow.Subtract(reconnectStart).TotalMilliseconds; + int elapsed = HiResClock.TickCount - reconnectStart; Utils.LogInfo("Reconnect period is {0} ms, {1} ms elapsed in reconnect.", m_reconnectPeriod, elapsed); int adjustedReconnectPeriod = CheckedReconnectPeriod(m_reconnectPeriod - elapsed); adjustedReconnectPeriod = JitteredReconnectPeriod(adjustedReconnectPeriod); @@ -373,8 +373,6 @@ await DoReconnectAsync().ConfigureAwait(false)) private async Task DoReconnectAsync() { // helper to override operation timeout - int operationTimeout = m_session.OperationTimeout; - int reconnectOperationTimeout = Math.Max(m_reconnectPeriod, MinReconnectOperationTimeout); ITransportChannel transportChannel = null; // try a reconnect. @@ -382,7 +380,6 @@ private async Task DoReconnectAsync() { try { - m_session.OperationTimeout = reconnectOperationTimeout; if (m_reverseConnectManager != null) { var connection = await m_reverseConnectManager.WaitForConnection( @@ -415,10 +412,10 @@ private async Task DoReconnectAsync() sre.StatusCode == StatusCodes.BadTimeout) { // check if reactivating is still an option. - TimeSpan timeout = m_session.LastKeepAliveTime.AddMilliseconds(m_session.SessionTimeout) - DateTime.UtcNow; - if (timeout.TotalMilliseconds > 0) + int timeout = Convert.ToInt32(m_session.SessionTimeout) - (HiResClock.TickCount - m_session.LastKeepAliveTickCount); + if (timeout > 0) { - Utils.LogInfo("Retry to reactivate, est. session timeout in {0} ms.", timeout.TotalMilliseconds); + Utils.LogInfo("Retry to reactivate, est. session timeout in {0} ms.", timeout); return false; } } @@ -438,7 +435,7 @@ private async Task DoReconnectAsync() } else { - // wait for next scheduled reconnect if connection failed, + // wait for next scheduled reconnect if connection failed, // next attempt is to recreate session m_reconnectFailed = true; return false; @@ -451,17 +448,12 @@ private async Task DoReconnectAsync() m_reconnectFailed = true; } - finally - { - m_session.OperationTimeout = operationTimeout; - } } // re-create the session. try { ISession session; - m_session.OperationTimeout = reconnectOperationTimeout; if (m_reverseConnectManager != null) { ITransportWaitingConnection connection; @@ -530,10 +522,6 @@ await endpoint.UpdateFromServerAsync( Utils.LogError("Could not reconnect the Session. {0}", Redact.Create(exception)); return false; } - finally - { - m_session.OperationTimeout = operationTimeout; - } } /// diff --git a/Libraries/Opc.Ua.Client/Subscription.cs b/Libraries/Opc.Ua.Client/Subscription.cs index 5c68500de6..a231ddee2e 100644 --- a/Libraries/Opc.Ua.Client/Subscription.cs +++ b/Libraries/Opc.Ua.Client/Subscription.cs @@ -799,8 +799,8 @@ public bool PublishingStopped { get { - TimeSpan timeSinceLastNotification = TimeSpan.FromTicks(DateTime.UtcNow.Ticks - Interlocked.Read(ref m_lastNotificationTime)); - if (timeSinceLastNotification.TotalMilliseconds > m_keepAliveInterval + kKeepAliveTimerMargin) + int timeSinceLastNotification = HiResClock.TickCount - m_lastNotificationTickCount; + if (timeSinceLastNotification > m_keepAliveInterval + kKeepAliveTimerMargin) { return true; } @@ -1430,6 +1430,8 @@ public void SaveMessageInCache( DateTime now = DateTime.UtcNow; Interlocked.Exchange(ref m_lastNotificationTime, now.Ticks); + int tickCount = HiResClock.TickCount; + m_lastNotificationTickCount = tickCount; // save the string table that came with notification. message.StringTable = new List(stringTable); @@ -1441,7 +1443,7 @@ public void SaveMessageInCache( } // find or create an entry for the incoming sequence number. - IncomingMessage entry = FindOrCreateEntry(now, message.SequenceNumber); + IncomingMessage entry = FindOrCreateEntry(now, tickCount, message.SequenceNumber); // check for keep alive. if (message.NotificationData.Count > 0) @@ -1463,6 +1465,7 @@ public void SaveMessageInCache( IncomingMessage placeholder = new IncomingMessage(); placeholder.SequenceNumber = entry.SequenceNumber + 1; placeholder.Timestamp = now; + placeholder.TickCount = tickCount; node = m_incomingMessages.AddAfter(node, placeholder); continue; } @@ -1480,7 +1483,7 @@ public void SaveMessageInCache( // can only pull off processed or expired or missing messages. if (!entry.Processed && - !(entry.Republished && (entry.RepublishStatus != StatusCodes.Good || entry.Timestamp.AddMilliseconds(kRepublishMessageExpiredTimeout) < now))) + !(entry.Republished && (entry.RepublishStatus != StatusCodes.Good || (tickCount - entry.TickCount) > kRepublishMessageExpiredTimeout))) { break; } @@ -1741,7 +1744,8 @@ private void ProcessTransferredSequenceNumbers(UInt32Collection availableSequenc // only republish consecutive sequence numbers // triggers the republish mechanism immediately, // if event is in the past - var now = DateTime.UtcNow.AddMilliseconds(-kRepublishMessageTimeout * 2); + DateTime now = DateTime.UtcNow.AddMilliseconds(-kRepublishMessageTimeout * 2); + int tickCount = HiResClock.TickCount - (kRepublishMessageTimeout * 2); uint lastSequenceNumberToRepublish = m_lastSequenceNumberProcessed - 1; int availableNumbers = availableSequenceNumbers.Count; int republishMessages = 0; @@ -1752,7 +1756,7 @@ private void ProcessTransferredSequenceNumbers(UInt32Collection availableSequenc { if (lastSequenceNumberToRepublish == sequenceNumber) { - FindOrCreateEntry(now, sequenceNumber); + FindOrCreateEntry(now, tickCount, sequenceNumber); found = true; break; } @@ -1841,6 +1845,7 @@ private void StartKeepAliveTimer() m_publishTimer = null; Interlocked.Exchange(ref m_lastNotificationTime, DateTime.UtcNow.Ticks); + m_lastNotificationTickCount = HiResClock.TickCount; m_keepAliveInterval = (int)(Math.Min(m_currentPublishingInterval * (m_currentKeepAliveCount + 1), Int32.MaxValue)); if (m_keepAliveInterval < kMinKeepAliveTimerInterval) { @@ -2241,7 +2246,7 @@ private async Task OnMessageReceivedAsync(CancellationToken ct) { // tolerate if a single request was received out of order if (ii.Next.Next != null && - ii.Value.Timestamp.AddMilliseconds(kRepublishMessageTimeout) < DateTime.UtcNow) + (HiResClock.TickCount - ii.Value.TickCount) > kRepublishMessageTimeout) { ii.Value.Republished = true; publishStateChangedMask |= PublishStateChangedMask.Republish; @@ -2730,8 +2735,9 @@ private void SaveEvents(NotificationMessage message, EventNotificationList notif /// Find or create an entry for the incoming sequence number. /// /// The current Utc time. + /// The current monotonic time /// The sequence number for the new entry. - private IncomingMessage FindOrCreateEntry(DateTime utcNow, uint sequenceNumber) + private IncomingMessage FindOrCreateEntry(DateTime utcNow, int tickCount, uint sequenceNumber) { IncomingMessage entry = null; LinkedListNode node = m_incomingMessages.Last; @@ -2745,6 +2751,7 @@ private IncomingMessage FindOrCreateEntry(DateTime utcNow, uint sequenceNumber) if (entry.SequenceNumber == sequenceNumber) { entry.Timestamp = utcNow; + entry.TickCount = tickCount; break; } @@ -2753,6 +2760,7 @@ private IncomingMessage FindOrCreateEntry(DateTime utcNow, uint sequenceNumber) entry = new IncomingMessage(); entry.SequenceNumber = sequenceNumber; entry.Timestamp = utcNow; + entry.TickCount = tickCount; m_incomingMessages.AddAfter(node, entry); break; } @@ -2766,6 +2774,7 @@ private IncomingMessage FindOrCreateEntry(DateTime utcNow, uint sequenceNumber) entry = new IncomingMessage(); entry.SequenceNumber = sequenceNumber; entry.Timestamp = utcNow; + entry.TickCount = tickCount; m_incomingMessages.AddLast(entry); } @@ -2803,6 +2812,7 @@ private IncomingMessage FindOrCreateEntry(DateTime utcNow, uint sequenceNumber) private Timer m_publishTimer; #endif private long m_lastNotificationTime; + private int m_lastNotificationTickCount; private int m_keepAliveInterval; private int m_publishLateCount; private event PublishStateChangedEventHandler m_publishStatusChanged; @@ -2832,6 +2842,7 @@ private class IncomingMessage { public uint SequenceNumber; public DateTime Timestamp; + public int TickCount; public NotificationMessage Message; public bool Processed; public bool Republished; diff --git a/Libraries/Opc.Ua.Client/TraceableSession.cs b/Libraries/Opc.Ua.Client/TraceableSession.cs index 359e41dbfa..d72bb7ecdd 100644 --- a/Libraries/Opc.Ua.Client/TraceableSession.cs +++ b/Libraries/Opc.Ua.Client/TraceableSession.cs @@ -211,6 +211,9 @@ public int KeepAliveInterval /// public DateTime LastKeepAliveTime => m_session.LastKeepAliveTime; + /// + public int LastKeepAliveTickCount => m_session.LastKeepAliveTickCount; + /// public int OutstandingRequestCount => m_session.OutstandingRequestCount; diff --git a/Tests/Opc.Ua.Client.Tests/ClientTest.cs b/Tests/Opc.Ua.Client.Tests/ClientTest.cs index 65196b005e..c27adc39b8 100644 --- a/Tests/Opc.Ua.Client.Tests/ClientTest.cs +++ b/Tests/Opc.Ua.Client.Tests/ClientTest.cs @@ -851,6 +851,7 @@ public void ReadPublicProperties() TestContext.Out.WriteLine("SubscriptionCount: {0}", Session.SubscriptionCount); TestContext.Out.WriteLine("DefaultSubscription: {0}", Session.DefaultSubscription); TestContext.Out.WriteLine("LastKeepAliveTime: {0}", Session.LastKeepAliveTime); + TestContext.Out.WriteLine("LastKeepAliveTickCount: {0}", Session.LastKeepAliveTickCount); TestContext.Out.WriteLine("KeepAliveInterval: {0}", Session.KeepAliveInterval); Session.KeepAliveInterval += 1000; TestContext.Out.WriteLine("KeepAliveInterval: {0}", Session.KeepAliveInterval); From be3a3b0be3a9ff00592d7933a4a296ad237f7105 Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Mon, 1 Jul 2024 16:18:47 +0200 Subject: [PATCH 5/8] Fix exception in TcpTransportlistener OnAccept call (#2661) Check for m_channels null value in the OnAccept, it could be already disposed. --- .../Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs index 4c9df3f16a..246faeae80 100644 --- a/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs +++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs @@ -221,7 +221,7 @@ public bool ReconnectToExistingChannel( lock (m_lock) { - if (!m_channels.TryGetValue(channelId, out channel)) + if (m_channels?.TryGetValue(channelId, out channel) != true) { throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown, "Could not find secure channel referenced in the OpenSecureChannel request."); } @@ -445,7 +445,7 @@ public async Task TransferListenerChannel( TcpListenerChannel channel = null; lock (m_lock) { - if (!m_channels.TryGetValue(channelId, out channel)) + if (m_channels?.TryGetValue(channelId, out channel) != true) { throw ServiceResultException.Create(StatusCodes.BadTcpSecureChannelUnknown, "Could not find secure channel request."); } @@ -464,7 +464,7 @@ public async Task TransferListenerChannel( lock (m_lock) { // remove it so it does not get cleaned up as an inactive connection. - m_channels.Remove(channelId); + m_channels?.Remove(channelId); } } @@ -525,16 +525,17 @@ private void OnAccept(object sender, SocketAsyncEventArgs e) return; } - bool serveChannel = !(m_maxChannelCount > 0 && m_maxChannelCount < m_channels.Count); + int channelCount = m_channels?.Count ?? 0; + bool serveChannel = !(m_maxChannelCount > 0 && m_maxChannelCount < channelCount); if (!serveChannel) { Utils.LogError("OnAccept: Maximum number of channels {0} reached, serving channels is stopped until number is lower or equal than {1} ", - m_channels.Count, m_maxChannelCount); + channelCount, m_maxChannelCount); Utils.SilentDispose(e.AcceptSocket); } // check if the accept socket has been created. - if (serveChannel && e.AcceptSocket != null && e.SocketError == SocketError.Success) + if (serveChannel && e.AcceptSocket != null && e.SocketError == SocketError.Success && m_channels != null) { try { @@ -756,7 +757,7 @@ private uint GetNextChannelId() do { uint nextChannelId = ++m_lastChannelId; - if (nextChannelId != 0 && !m_channels.ContainsKey(nextChannelId)) + if (nextChannelId != 0 && m_channels?.ContainsKey(nextChannelId) != true) { return nextChannelId; } From 7b68ff7a0401685732e5c84b92fd22f492cf12f5 Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Tue, 2 Jul 2024 04:47:00 +0200 Subject: [PATCH 6/8] Fuzzing fixes for June (#2663) - Indempotent fuzzing revealed issue in DiagnosticInfo - Matrix may have been used to decode one dimensional array if encoder used the `ArrayDimensions` field, which doesn't seem forbidden. Matrix caused cast exceptionwhen encoding the one dim atrray wrapped in a Matrix object. - JsonEncoder throws InvalidCastException if NodeId Guid is encoded as Uuid. - Strings with trailing `0` need to strip off all, or indempotent encoding fails. --- .../Fuzz/FuzzableCode.BinaryDecoder.cs | 91 ++++++++++++++++++- .../Types/Encoders/BinaryDecoder.cs | 23 ++++- .../Types/Encoders/BinaryEncoder.cs | 45 +++++++-- .../Opc.Ua.Core/Types/Encoders/JsonEncoder.cs | 15 ++- 4 files changed, 160 insertions(+), 14 deletions(-) diff --git a/Fuzzing/Encoders/Fuzz/FuzzableCode.BinaryDecoder.cs b/Fuzzing/Encoders/Fuzz/FuzzableCode.BinaryDecoder.cs index 8a2dcd774a..11d1753138 100644 --- a/Fuzzing/Encoders/Fuzz/FuzzableCode.BinaryDecoder.cs +++ b/Fuzzing/Encoders/Fuzz/FuzzableCode.BinaryDecoder.cs @@ -29,6 +29,7 @@ using System; using System.IO; +using System.Linq; using Opc.Ua; /// @@ -74,6 +75,31 @@ public static void AflfuzzBinaryEncoder(Stream stream) } } + /// + /// The binary encoder indempotent fuzz target for afl-fuzz. + /// + /// The stdin stream from the afl-fuzz process. + public static void AflfuzzBinaryEncoderIndempotent(Stream stream) + { + IEncodeable encodeable = null; + byte[] serialized = null; + using (var memoryStream = PrepareArraySegmentStream(stream)) + { + try + { + encodeable = FuzzBinaryDecoderCore(memoryStream, true); + serialized = BinaryEncoder.EncodeMessage(encodeable, messageContext); + } + catch + { + return; + } + } + + // reencode the fuzzed input and see if they are indempotent + FuzzBinaryEncoderIndempotentCore(serialized, encodeable); + } + /// /// The binary decoder fuzz target for libfuzzer. /// @@ -86,7 +112,7 @@ public static void LibfuzzBinaryDecoder(ReadOnlySpan input) } /// - /// The binary encoder fuzz target for afl-fuzz. + /// The binary encoder fuzz target for libfuzzer. /// public static void LibfuzzBinaryEncoder(ReadOnlySpan input) { @@ -95,7 +121,7 @@ public static void LibfuzzBinaryEncoder(ReadOnlySpan input) { try { - encodeable = FuzzBinaryDecoderCore(memoryStream); + encodeable = FuzzBinaryDecoderCore(memoryStream, true); } catch { @@ -110,6 +136,30 @@ public static void LibfuzzBinaryEncoder(ReadOnlySpan input) } } + /// + /// The binary encoder indempotent fuzz target for libfuzzer. + /// + public static void LibfuzzBinaryEncoderIndempotent(ReadOnlySpan input) + { + IEncodeable encodeable = null; + byte[] serialized = null; + using (var memoryStream = new MemoryStream(input.ToArray())) + { + try + { + encodeable = FuzzBinaryDecoderCore(memoryStream, true); + serialized = BinaryEncoder.EncodeMessage(encodeable, messageContext); + } + catch + { + return; + } + } + + // reencode the fuzzed input and see if they are indempotent + FuzzBinaryEncoderIndempotentCore(serialized, encodeable); + } + /// /// The fuzz target for the BinaryDecoder. /// @@ -134,9 +184,46 @@ internal static IEncodeable FuzzBinaryDecoderCore(MemoryStream stream, bool thro return null; } break; + + default: + break; + } throw; + + } + } + + /// + /// The indempotent fuzz target core for the BinaryEncoder. + /// + /// The indempotent UA binary encoded data. + /// + internal static void FuzzBinaryEncoderIndempotentCore(byte[] serialized, IEncodeable encodeable) + { + if (serialized == null || encodeable == null) return; + + using (var memoryStream = new MemoryStream(serialized)) + { + IEncodeable encodeable2 = FuzzBinaryDecoderCore(memoryStream, true); + byte[] serialized2 = BinaryEncoder.EncodeMessage(encodeable2, messageContext); + + using (var memoryStream2 = new MemoryStream(serialized2)) + { + IEncodeable encodeable3 = FuzzBinaryDecoderCore(memoryStream2, true); + + string encodeableTypeName = encodeable2?.GetType().Name ?? "unknown type"; + if (serialized2 == null || !serialized.SequenceEqual(serialized2)) + { + throw new Exception(Utils.Format("Indempotent encoding failed. Type={0}.", encodeableTypeName)); + } + + if (!Utils.IsEqual(encodeable2, encodeable3)) + { + throw new Exception(Utils.Format("Indempotent 3rd gen decoding failed. Type={0}.", encodeableTypeName)); + } + } } } } diff --git a/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs index 6d6bd73b77..85a96a9146 100644 --- a/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs +++ b/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs @@ -425,8 +425,12 @@ public string ReadString(string fieldName, int maxStringLength) // length is always >= 1 here - // If 0 terminated, decrease length by one before converting to string - var utf8StringLength = bytes[bytes.Length - 1] == 0 ? bytes.Length - 1 : bytes.Length; + // If 0 terminated, decrease length to remove 0 terminators before converting to string + int utf8StringLength = bytes.Length; + while (utf8StringLength > 0 && bytes[utf8StringLength - 1] == 0) + { + utf8StringLength--; + } return Encoding.UTF8.GetString(bytes, 0, utf8StringLength); } @@ -1569,7 +1573,7 @@ private DiagnosticInfo ReadDiagnosticInfo(string fieldName, int depth) if ((encodingByte & (byte)DiagnosticInfoEncodingBits.InnerDiagnosticInfo) != 0) { - value.InnerDiagnosticInfo = ReadDiagnosticInfo(null, depth + 1); + value.InnerDiagnosticInfo = ReadDiagnosticInfo(null, depth + 1) ?? new DiagnosticInfo(); } return value; @@ -2075,6 +2079,8 @@ private ExtensionObject ReadExtensionObject() // update body. extension.Body = body; + + xmlDecoder.Close(); } catch (Exception e) { @@ -2270,7 +2276,14 @@ private Variant ReadVariantValue(string fieldName) "ArrayDimensions length does not match with the ArrayLength in Variant object."); } - value = new Variant(new Matrix(array, builtInType, dimensions.ToArray())); + if (dimensions.Count == 1) + { + value = new Variant(array, new TypeInfo(builtInType, 1)); + } + else + { + value = new Variant(new Matrix(array, builtInType, dimensionsArray)); + } } else { @@ -2387,7 +2400,7 @@ private Variant ReadVariantValue(string fieldName) } catch (Exception ex) { - Utils.LogError(ex, "Error reading xml element for variant."); + Utils.LogTrace(ex, "Error reading xml element for variant."); value.Set(StatusCodes.BadDecodingError); } break; diff --git a/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs index dfad98c2d1..b019c1bd13 100644 --- a/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs +++ b/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs @@ -11,6 +11,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ using System; +using System.Buffers; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -442,18 +443,26 @@ public void WriteString(string fieldName, string value) return; } - byte[] bytes = Encoding.UTF8.GetBytes(value); - - if (m_context.MaxStringLength > 0 && m_context.MaxStringLength < bytes.Length) + if (m_context.MaxStringLength > 0 && m_context.MaxStringLength < value.Length) { throw ServiceResultException.Create( StatusCodes.BadEncodingLimitsExceeded, "MaxStringLength {0} < {1}", m_context.MaxStringLength, - bytes.Length); + value.Length); } - WriteByteString(null, Encoding.UTF8.GetBytes(value)); + int maxByteCount = Encoding.UTF8.GetMaxByteCount(value.Length); + byte[] encodedBytes = ArrayPool.Shared.Rent(maxByteCount); + try + { + int count = Encoding.UTF8.GetBytes(value, 0, value.Length, encodedBytes, 0); + WriteByteString(null, encodedBytes, 0, count); + } + finally + { + ArrayPool.Shared.Return(encodedBytes); + } } /// @@ -536,7 +545,7 @@ public void WriteXmlElement(string fieldName, XmlElement value) return; } - WriteByteString(null, Encoding.UTF8.GetBytes(value.OuterXml)); + WriteString(fieldName, value.OuterXml); } /// @@ -1917,6 +1926,30 @@ public void WriteArray(string fieldName, object array, int valueRank, BuiltInTyp #endregion #region Private Methods + /// + /// Writes a byte string to the stream from a given index and length. + /// + private void WriteByteString(string fieldName, byte[] value, int index, int count) + { + if (value == null) + { + WriteInt32(null, -1); + return; + } + + if (m_context.MaxByteStringLength > 0 && m_context.MaxByteStringLength < count) + { + throw ServiceResultException.Create( + StatusCodes.BadEncodingLimitsExceeded, + "MaxByteStringLength {0} < {1}", + m_context.MaxByteStringLength, + value.Length); + } + + WriteInt32(null, count); + m_writer.Write(value, index, count); + } + /// /// Writes a DiagnosticInfo to the stream. /// Ignores InnerDiagnosticInfo field if the nesting level diff --git a/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs index fa53fded3d..fb958ce396 100644 --- a/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs +++ b/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs @@ -1062,7 +1062,20 @@ private void WriteNodeIdContents(NodeId value, string namespaceUri = null) case IdType.Guid: { - WriteGuid("Id", (Guid)value.Identifier); + if (value.Identifier is Guid guidIdentifier) + { + WriteGuid("Id", guidIdentifier); + } + else if (value.Identifier is Uuid uuidIdentifier) + { + WriteGuid("Id", uuidIdentifier); + } + else + { + throw new ServiceResultException( + StatusCodes.BadEncodingError, + "Invalid Identifier type to encode as Guid NodeId."); + } break; } From 332ed1ded97889f2684ddb494cac0e5dde3e2414 Mon Sep 17 00:00:00 2001 From: Michi Date: Tue, 2 Jul 2024 16:30:21 +0200 Subject: [PATCH 7/8] Fix: RegisterServer and RegisterServer2 do not initiate connection (#2664) --- Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs index 3e22c3fb74..058e43348d 100644 --- a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs +++ b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs @@ -818,7 +818,10 @@ private bool QueueConnectOperation(WriteOperation operation, int timeout, IServi request.TypeId == DataTypeIds.CreateSessionRequest || request.TypeId == DataTypeIds.GetEndpointsRequest || request.TypeId == DataTypeIds.FindServersOnNetworkRequest || - request.TypeId == DataTypeIds.FindServersRequest) + request.TypeId == DataTypeIds.FindServersRequest || + request.TypeId == DataTypeIds.RegisterServerRequest || + request.TypeId == DataTypeIds.RegisterServer2Request + ) { m_queuedOperations.Add(queuedOperation); return true; From c4cf54c5953260a214943823d6f26dbf9b9a148b Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Thu, 11 Jul 2024 09:55:49 +0200 Subject: [PATCH 8/8] Fix NodeId compare found by fuzzer, Bump Asn1 Nuget due to security update (#2669) * fix nodeid compare found by fuzzer * bump security Nuget updates for ASN.1 --- .../Opc.Ua.Security.Certificates.csproj | 6 +++--- Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs | 3 ++- Stack/Opc.Ua.Core/Types/BuiltIn/NodeId.cs | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Libraries/Opc.Ua.Security.Certificates/Opc.Ua.Security.Certificates.csproj b/Libraries/Opc.Ua.Security.Certificates/Opc.Ua.Security.Certificates.csproj index fab90dac50..6f413e4632 100644 --- a/Libraries/Opc.Ua.Security.Certificates/Opc.Ua.Security.Certificates.csproj +++ b/Libraries/Opc.Ua.Security.Certificates/Opc.Ua.Security.Certificates.csproj @@ -18,12 +18,12 @@ - + - + @@ -45,7 +45,7 @@ - + diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs index 246faeae80..5292d2f387 100644 --- a/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs +++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs @@ -185,8 +185,9 @@ public void UpdateChannelLastActiveTime(string globalChannelId) var channelIdString = globalChannelId.Substring(ListenerId.Length + 1); var channelId = Convert.ToUInt32(channelIdString); + TcpListenerChannel channel = null; if (channelId > 0 && - m_channels.TryGetValue(channelId, out TcpListenerChannel channel)) + m_channels?.TryGetValue(channelId, out channel) == true) { channel?.UpdateLastActiveTime(); } diff --git a/Stack/Opc.Ua.Core/Types/BuiltIn/NodeId.cs b/Stack/Opc.Ua.Core/Types/BuiltIn/NodeId.cs index dd3d0ceed9..d186696280 100644 --- a/Stack/Opc.Ua.Core/Types/BuiltIn/NodeId.cs +++ b/Stack/Opc.Ua.Core/Types/BuiltIn/NodeId.cs @@ -1573,6 +1573,11 @@ private int CompareTo(IdType idType, object id) byte[] id1 = (byte[])m_identifier; byte[] id2 = (byte[])id; + if (id1 == id2) + { + return 0; + } + if (id1.Length == id2.Length) { for (int ii = 0; ii < id1.Length; ii++)