diff --git a/.azurepipelines/signlistDebug.txt b/.azurepipelines/signlistDebug.txt
index 6dc42d3c09..2c4f289024 100644
--- a/.azurepipelines/signlistDebug.txt
+++ b/.azurepipelines/signlistDebug.txt
@@ -1,6 +1,9 @@
Stack\Opc.Ua.Core\bin\Debug\netstandard2.1\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Debug\netstandard2.0\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Debug\net462\Opc.Ua.Core.dll
+Stack\Opc.Ua.Bindings.Https\bin\Debug\netstandard2.1\Opc.Ua.Bindings.Https.dll
+Stack\Opc.Ua.Bindings.Https\bin\Debug\netstandard2.0\Opc.Ua.Bindings.Https.dll
+Stack\Opc.Ua.Bindings.Https\bin\Debug\net462\Opc.Ua.Bindings.Https.dll
Libraries\Opc.Ua.Server\bin\Debug\netstandard2.1\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Debug\netstandard2.0\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Debug\net462\Opc.Ua.Server.dll
@@ -19,3 +22,5 @@ Libraries\Opc.Ua.Gds.Client.Common\bin\Debug\net462\Opc.Ua.Gds.Client.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\netstandard2.0\Opc.Ua.Gds.Server.Common.dll
Libraries\Opc.Ua.Gds.Server.Common\bin\Debug\net462\Opc.Ua.Gds.Server.Common.dll
+
+
diff --git a/.azurepipelines/signlistRelease.txt b/.azurepipelines/signlistRelease.txt
index 63e5fa9fb4..ed5b2e403f 100644
--- a/.azurepipelines/signlistRelease.txt
+++ b/.azurepipelines/signlistRelease.txt
@@ -1,6 +1,9 @@
Stack\Opc.Ua.Core\bin\Release\netstandard2.1\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Release\netstandard2.0\Opc.Ua.Core.dll
Stack\Opc.Ua.Core\bin\Release\net462\Opc.Ua.Core.dll
+Stack\Opc.Ua.Bindings.Https\bin\Release\netstandard2.1\Opc.Ua.Bindings.Https.dll
+Stack\Opc.Ua.Bindings.Https\bin\Release\netstandard2.0\Opc.Ua.Bindings.Https.dll
+Stack\Opc.Ua.Bindings.Https\bin\Release\net462\Opc.Ua.Bindings.Https.dll
Libraries\Opc.Ua.Server\bin\Release\netstandard2.1\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Release\netstandard2.0\Opc.Ua.Server.dll
Libraries\Opc.Ua.Server\bin\Release\net462\Opc.Ua.Server.dll
diff --git a/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj b/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj
index 52b459ed8a..cc6f323d01 100644
--- a/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj
+++ b/Applications/ConsoleReferenceClient/ConsoleReferenceClient.csproj
@@ -6,12 +6,15 @@
Exe
ConsoleReferenceClient
OPC Foundation
- OPC UA SDK
.NET Console Reference Client
Copyright © 2004-2020 OPC Foundation, Inc
Quickstarts.ConsoleReferenceClient
+
+
+
+
diff --git a/Applications/ConsoleReferenceClient/Program.cs b/Applications/ConsoleReferenceClient/Program.cs
index d6e983961b..0f1d4d12e2 100644
--- a/Applications/ConsoleReferenceClient/Program.cs
+++ b/Applications/ConsoleReferenceClient/Program.cs
@@ -33,7 +33,7 @@ using Opc.Ua.Configuration;
namespace Quickstarts.ConsoleReferenceClient
{
- public class Program
+ public static class Program
{
public static void Main(string[] args)
{
diff --git a/Applications/ConsoleReferenceServer/NetCoreReferenceServer.csproj b/Applications/ConsoleReferenceServer/NetCoreReferenceServer.csproj
index 2fee8b2a85..8adc3ca952 100644
--- a/Applications/ConsoleReferenceServer/NetCoreReferenceServer.csproj
+++ b/Applications/ConsoleReferenceServer/NetCoreReferenceServer.csproj
@@ -6,7 +6,6 @@
Exe
ConsoleReferenceServer
OPC Foundation
- OPC UA SDK
.NET Core Reference Server
Copyright © 2004-2020 OPC Foundation, Inc
@@ -19,6 +18,10 @@
+
+
+
+
@@ -35,8 +38,4 @@
-
-
-
-
diff --git a/Applications/ReferenceClient/Reference Client.csproj b/Applications/ReferenceClient/Reference Client.csproj
index 45b8b50b53..fc349d942a 100644
--- a/Applications/ReferenceClient/Reference Client.csproj
+++ b/Applications/ReferenceClient/Reference Client.csproj
@@ -120,6 +120,10 @@
+
+ {92d98d3d-2a7d-4f4b-8c72-1a98908d0221}
+ Opc.Ua.Bindings.Https
+
{4569aaa2-710b-4e8b-a4c6-f917777814da}
Opc.Ua.Core
diff --git a/Applications/ReferenceServer/Reference Server.csproj b/Applications/ReferenceServer/Reference Server.csproj
index 55e4a00fd9..f8e175e6d4 100644
--- a/Applications/ReferenceServer/Reference Server.csproj
+++ b/Applications/ReferenceServer/Reference Server.csproj
@@ -67,6 +67,7 @@
+
@@ -134,6 +135,10 @@
+
+ {92d98d3d-2a7d-4f4b-8c72-1a98908d0221}
+ Opc.Ua.Bindings.Https
+
{4569aaa2-710b-4e8b-a4c6-f917777814da}
Opc.Ua.Core
diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/Opc.Ua.Client.ComplexTypes.csproj b/Libraries/Opc.Ua.Client.ComplexTypes/Opc.Ua.Client.ComplexTypes.csproj
index 1741297670..b338cbc5a1 100644
--- a/Libraries/Opc.Ua.Client.ComplexTypes/Opc.Ua.Client.ComplexTypes.csproj
+++ b/Libraries/Opc.Ua.Client.ComplexTypes/Opc.Ua.Client.ComplexTypes.csproj
@@ -26,6 +26,7 @@
+
diff --git a/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj b/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj
index 62e7599d26..f893ce0cda 100644
--- a/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj
+++ b/Libraries/Opc.Ua.Client/Opc.Ua.Client.csproj
@@ -19,10 +19,6 @@
-
-
-
-
diff --git a/Libraries/Opc.Ua.Client/Properties/AssemblyInfo.cs b/Libraries/Opc.Ua.Client/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..dc0263bfa2
--- /dev/null
+++ b/Libraries/Opc.Ua.Client/Properties/AssemblyInfo.cs
@@ -0,0 +1,24 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - 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.Runtime.CompilerServices;
+
+#if SIGNASSEMBLY
+[assembly: InternalsVisibleTo("Opc.Ua.Client.Tests, PublicKey = " +
+ // OPC Foundation Strong Name Public Key
+ "0024000004800000940000000602000000240000525341310004000001000100d987b12f068b35" +
+ "80429f3dde01397508880fc7e62621397618456ca1549aeacfbdb90c62adfe918f05ce3677b390" +
+ "f78357b8745cb6e1334655afce1a9527ac92fc829ff585ea79f007e52ba0f83ead627e3edda40b" +
+ "ec5ae574128fc9342cb57cb8285aa4e5b589c0ebef3be571b5c8f2ab1067f7c880e8f8882a73c8" +
+ "0a12a1ef")]
+#else
+[assembly: InternalsVisibleTo("Opc.Ua.Client.Tests")]
+#endif
diff --git a/Libraries/Opc.Ua.Server/Opc.Ua.Server.csproj b/Libraries/Opc.Ua.Server/Opc.Ua.Server.csproj
index ce6241b356..ae097b7729 100644
--- a/Libraries/Opc.Ua.Server/Opc.Ua.Server.csproj
+++ b/Libraries/Opc.Ua.Server/Opc.Ua.Server.csproj
@@ -16,17 +16,9 @@
$(PackageId).Debug
-
- $(DefineConstants);NO_HTTPS
-
-
-
-
-
-
diff --git a/Libraries/Opc.Ua.Server/Properties/AssemblyInfo.cs b/Libraries/Opc.Ua.Server/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..554126623d
--- /dev/null
+++ b/Libraries/Opc.Ua.Server/Properties/AssemblyInfo.cs
@@ -0,0 +1,24 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - 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.Runtime.CompilerServices;
+
+#if SIGNASSEMBLY
+[assembly: InternalsVisibleTo("Opc.Ua.Server.Tests, PublicKey = " +
+ // OPC Foundation Strong Name Public Key
+ "0024000004800000940000000602000000240000525341310004000001000100d987b12f068b35" +
+ "80429f3dde01397508880fc7e62621397618456ca1549aeacfbdb90c62adfe918f05ce3677b390" +
+ "f78357b8745cb6e1334655afce1a9527ac92fc829ff585ea79f007e52ba0f83ead627e3edda40b" +
+ "ec5ae574128fc9342cb57cb8285aa4e5b589c0ebef3be571b5c8f2ab1067f7c880e8f8882a73c8" +
+ "0a12a1ef")]
+#else
+[assembly: InternalsVisibleTo("Opc.Ua.Server.Tests")]
+#endif
diff --git a/Libraries/Opc.Ua.Server/Server/StandardServer.cs b/Libraries/Opc.Ua.Server/Server/StandardServer.cs
index 486c3a7d23..ec992f9dd4 100644
--- a/Libraries/Opc.Ua.Server/Server/StandardServer.cs
+++ b/Libraries/Opc.Ua.Server/Server/StandardServer.cs
@@ -33,6 +33,7 @@ using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
+using Opc.Ua.Bindings;
namespace Opc.Ua.Server
{
@@ -51,7 +52,7 @@ namespace Opc.Ua.Server
}
#endregion
-
+
#region IDisposable Members
///
/// An overrideable version of the Dispose.
@@ -59,7 +60,7 @@ namespace Opc.Ua.Server
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "m_serverInternal"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "m_registrationTimer"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "m_configurationWatcher")]
protected override void Dispose(bool disposing)
- {
+ {
if (disposing)
{
// halt any outstanding timer.
@@ -68,14 +69,14 @@ namespace Opc.Ua.Server
Utils.SilentDispose(m_registrationTimer);
m_registrationTimer = null;
}
-
+
// close the watcher.
if (m_configurationWatcher != null)
{
Utils.SilentDispose(m_configurationWatcher);
m_configurationWatcher = null;
}
-
+
// close the server.
if (m_serverInternal != null)
{
@@ -101,16 +102,16 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader FindServers(
- RequestHeader requestHeader,
- string endpointUrl,
- StringCollection localeIds,
- StringCollection serverUris,
+ RequestHeader requestHeader,
+ string endpointUrl,
+ StringCollection localeIds,
+ StringCollection serverUris,
out ApplicationDescriptionCollection servers)
{
servers = new ApplicationDescriptionCollection();
-
+
ValidateRequest(requestHeader);
-
+
lock (m_lock)
{
// parse the url provided by the client.
@@ -131,7 +132,7 @@ namespace Opc.Ua.Server
}
// build list of unique servers.
- Dictionary uniqueServers = new Dictionary();
+ Dictionary uniqueServers = new Dictionary();
foreach (EndpointDescription description in GetEndpoints())
{
@@ -173,7 +174,7 @@ namespace Opc.Ua.Server
servers.Add(application);
}
}
-
+
return CreateResponse(requestHeader, StatusCodes.Good);
}
@@ -189,14 +190,14 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader GetEndpoints(
- RequestHeader requestHeader,
- string endpointUrl,
- StringCollection localeIds,
- StringCollection profileUris,
+ RequestHeader requestHeader,
+ string endpointUrl,
+ StringCollection localeIds,
+ StringCollection profileUris,
out EndpointDescriptionCollection endpoints)
- {
+ {
endpoints = null;
-
+
ValidateRequest(requestHeader);
lock (m_lock)
@@ -286,25 +287,25 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader CreateSession(
- RequestHeader requestHeader,
- ApplicationDescription clientDescription,
- string serverUri,
- string endpointUrl,
- string sessionName,
- byte[] clientNonce,
- byte[] clientCertificate,
- double requestedSessionTimeout,
- uint maxResponseMessageSize,
- out NodeId sessionId,
- out NodeId authenticationToken,
- out double revisedSessionTimeout,
- out byte[] serverNonce,
- out byte[] serverCertificate,
- out EndpointDescriptionCollection serverEndpoints,
+ RequestHeader requestHeader,
+ ApplicationDescription clientDescription,
+ string serverUri,
+ string endpointUrl,
+ string sessionName,
+ byte[] clientNonce,
+ byte[] clientCertificate,
+ double requestedSessionTimeout,
+ uint maxResponseMessageSize,
+ out NodeId sessionId,
+ out NodeId authenticationToken,
+ out double revisedSessionTimeout,
+ out byte[] serverNonce,
+ out byte[] serverCertificate,
+ out EndpointDescriptionCollection serverEndpoints,
out SignedSoftwareCertificateCollection serverSoftwareCertificates,
- out SignatureData serverSignature,
- out uint maxRequestMessageSize)
- {
+ out SignatureData serverSignature,
+ out uint maxRequestMessageSize)
+ {
sessionId = 0;
revisedSessionTimeout = 0;
serverNonce = null;
@@ -314,7 +315,7 @@ namespace Opc.Ua.Server
maxRequestMessageSize = (uint)MessageContext.MaxMessageSize;
OperationContext context = ValidateRequest(requestHeader, RequestType.CreateSession);
-
+
try
{
// check the server uri.
@@ -466,7 +467,7 @@ namespace Opc.Ua.Server
}
throw TranslateException((DiagnosticsMasks)requestHeader.ReturnDiagnostics, new StringCollection(), e);
- }
+ }
finally
{
OnRequestComplete(context);
@@ -489,31 +490,31 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader ActivateSession(
- RequestHeader requestHeader,
- SignatureData clientSignature,
+ RequestHeader requestHeader,
+ SignatureData clientSignature,
SignedSoftwareCertificateCollection clientSoftwareCertificates,
- StringCollection localeIds,
- ExtensionObject userIdentityToken,
- SignatureData userTokenSignature,
- out byte[] serverNonce,
- out StatusCodeCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
- {
+ StringCollection localeIds,
+ ExtensionObject userIdentityToken,
+ SignatureData userTokenSignature,
+ out byte[] serverNonce,
+ out StatusCodeCollection results,
+ out DiagnosticInfoCollection diagnosticInfos)
+ {
serverNonce = null;
results = null;
diagnosticInfos = null;
-
+
OperationContext context = ValidateRequest(requestHeader, RequestType.ActivateSession);
-
+
try
{
// validate client's software certificates.
List softwareCertificates = new List();
-
+
if (context.SecurityPolicyUri != SecurityPolicies.None)
{
bool diagnosticsExist = false;
-
+
if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
{
diagnosticInfos = new DiagnosticInfoCollection();
@@ -534,7 +535,7 @@ namespace Opc.Ua.Server
if (ServiceResult.IsBad(result))
{
results.Add(result.Code);
-
+
// add diagnostics if requested.
if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
{
@@ -547,7 +548,7 @@ namespace Opc.Ua.Server
{
softwareCertificates.Add(softwareCertificate);
results.Add(StatusCodes.Good);
-
+
// add diagnostics if requested.
if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
{
@@ -561,10 +562,10 @@ namespace Opc.Ua.Server
diagnosticInfos.Clear();
}
}
-
+
// check if certificates meet the server's requirements.
ValidateSoftwareCertificates(softwareCertificates);
-
+
// activate the session.
bool identityChanged = ServerInternal.SessionManager.ActivateSession(
context,
@@ -606,7 +607,7 @@ namespace Opc.Ua.Server
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -704,11 +705,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -722,16 +723,16 @@ namespace Opc.Ua.Server
///
public override ResponseHeader Cancel(
RequestHeader requestHeader,
- uint requestHandle,
- out uint cancelCount)
+ uint requestHandle,
+ out uint cancelCount)
{
cancelCount = 0;
OperationContext context = ValidateRequest(requestHeader, RequestType.Cancel);
-
+
try
{
- m_serverInternal.RequestManager.CancelRequests(requestHandle, out cancelCount);
+ m_serverInternal.RequestManager.CancelRequests(requestHandle, out cancelCount);
return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
@@ -747,11 +748,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -767,11 +768,11 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader Browse(
- RequestHeader requestHeader,
- ViewDescription view,
- uint requestedMaxReferencesPerNode,
- BrowseDescriptionCollection nodesToBrowse,
- out BrowseResultCollection results,
+ RequestHeader requestHeader,
+ ViewDescription view,
+ uint requestedMaxReferencesPerNode,
+ BrowseDescriptionCollection nodesToBrowse,
+ out BrowseResultCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
results = null;
@@ -809,11 +810,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -828,17 +829,17 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader BrowseNext(
- RequestHeader requestHeader,
- bool releaseContinuationPoints,
- ByteStringCollection continuationPoints,
- out BrowseResultCollection results,
+ RequestHeader requestHeader,
+ bool releaseContinuationPoints,
+ ByteStringCollection continuationPoints,
+ out BrowseResultCollection results,
out DiagnosticInfoCollection diagnosticInfos)
- {
+ {
results = null;
diagnosticInfos = null;
-
+
OperationContext context = ValidateRequest(requestHeader, RequestType.BrowseNext);
-
+
try
{
if (continuationPoints == null || continuationPoints.Count == 0)
@@ -853,7 +854,7 @@ namespace Opc.Ua.Server
out results,
out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -868,11 +869,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -885,8 +886,8 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader RegisterNodes(
- RequestHeader requestHeader,
- NodeIdCollection nodesToRegister,
+ RequestHeader requestHeader,
+ NodeIdCollection nodesToRegister,
out NodeIdCollection registeredNodeIds)
{
registeredNodeIds = null;
@@ -924,7 +925,7 @@ namespace Opc.Ua.Server
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -969,7 +970,7 @@ namespace Opc.Ua.Server
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -983,10 +984,10 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader TranslateBrowsePathsToNodeIds(
- RequestHeader requestHeader,
- BrowsePathCollection browsePaths,
- out BrowsePathResultCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
+ RequestHeader requestHeader,
+ BrowsePathCollection browsePaths,
+ out BrowsePathResultCollection results,
+ out DiagnosticInfoCollection diagnosticInfos)
{
results = null;
diagnosticInfos = null;
@@ -1006,7 +1007,7 @@ namespace Opc.Ua.Server
out results,
out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1021,11 +1022,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1041,11 +1042,11 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader Read(
- RequestHeader requestHeader,
- double maxAge,
- TimestampsToReturn timestampsToReturn,
- ReadValueIdCollection nodesToRead,
- out DataValueCollection results,
+ RequestHeader requestHeader,
+ double maxAge,
+ TimestampsToReturn timestampsToReturn,
+ ReadValueIdCollection nodesToRead,
+ out DataValueCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.Read);
@@ -1065,7 +1066,7 @@ namespace Opc.Ua.Server
out results,
out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1080,11 +1081,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1101,20 +1102,20 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader HistoryRead(
- RequestHeader requestHeader,
- ExtensionObject historyReadDetails,
- TimestampsToReturn timestampsToReturn,
- bool releaseContinuationPoints,
- HistoryReadValueIdCollection nodesToRead,
- out HistoryReadResultCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
+ RequestHeader requestHeader,
+ ExtensionObject historyReadDetails,
+ TimestampsToReturn timestampsToReturn,
+ bool releaseContinuationPoints,
+ HistoryReadValueIdCollection nodesToRead,
+ out HistoryReadResultCollection results,
+ out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.HistoryRead);
-
+
try
{
if (nodesToRead == null || nodesToRead.Count == 0)
- {
+ {
throw new ServiceResultException(StatusCodes.BadNothingToDo);
}
@@ -1125,9 +1126,9 @@ namespace Opc.Ua.Server
releaseContinuationPoints,
nodesToRead,
out results,
- out diagnosticInfos);
+ out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1142,11 +1143,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1160,9 +1161,9 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader Write(
- RequestHeader requestHeader,
- WriteValueCollection nodesToWrite,
- out StatusCodeCollection results,
+ RequestHeader requestHeader,
+ WriteValueCollection nodesToWrite,
+ out StatusCodeCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.Write);
@@ -1195,7 +1196,7 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
@@ -1213,17 +1214,17 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader HistoryUpdate(
- RequestHeader requestHeader,
- ExtensionObjectCollection historyUpdateDetails,
+ RequestHeader requestHeader,
+ ExtensionObjectCollection historyUpdateDetails,
out HistoryUpdateResultCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
- {
+ out DiagnosticInfoCollection diagnosticInfos)
+ {
OperationContext context = ValidateRequest(requestHeader, RequestType.HistoryUpdate);
-
+
try
{
if (historyUpdateDetails == null || historyUpdateDetails.Count == 0)
- {
+ {
throw new ServiceResultException(StatusCodes.BadNothingToDo);
}
@@ -1231,9 +1232,9 @@ namespace Opc.Ua.Server
context,
historyUpdateDetails,
out results,
- out diagnosticInfos);
+ out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1248,7 +1249,7 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
@@ -1274,16 +1275,16 @@ namespace Opc.Ua.Server
///
public override ResponseHeader CreateSubscription(
RequestHeader requestHeader,
- double requestedPublishingInterval,
- uint requestedLifetimeCount,
- uint requestedMaxKeepAliveCount,
- uint maxNotificationsPerPublish,
- bool publishingEnabled,
- byte priority,
- out uint subscriptionId,
- out double revisedPublishingInterval,
- out uint revisedLifetimeCount,
- out uint revisedMaxKeepAliveCount)
+ double requestedPublishingInterval,
+ uint requestedLifetimeCount,
+ uint requestedMaxKeepAliveCount,
+ uint maxNotificationsPerPublish,
+ bool publishingEnabled,
+ byte priority,
+ out uint subscriptionId,
+ out double revisedPublishingInterval,
+ out uint revisedLifetimeCount,
+ out uint revisedMaxKeepAliveCount)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.CreateSubscription);
@@ -1300,9 +1301,9 @@ namespace Opc.Ua.Server
out subscriptionId,
out revisedPublishingInterval,
out revisedLifetimeCount,
- out revisedMaxKeepAliveCount);
+ out revisedMaxKeepAliveCount);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1317,11 +1318,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1335,9 +1336,9 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader DeleteSubscriptions(
- RequestHeader requestHeader,
- UInt32Collection subscriptionIds,
- out StatusCodeCollection results,
+ RequestHeader requestHeader,
+ UInt32Collection subscriptionIds,
+ out StatusCodeCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.DeleteSubscriptions);
@@ -1347,15 +1348,15 @@ namespace Opc.Ua.Server
if (subscriptionIds == null || subscriptionIds.Count == 0)
{
throw new ServiceResultException(StatusCodes.BadNothingToDo);
- }
+ }
ServerInternal.SubscriptionManager.DeleteSubscriptions(
context,
subscriptionIds,
out results,
- out diagnosticInfos);
+ out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1370,11 +1371,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1392,14 +1393,14 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader Publish(
- RequestHeader requestHeader,
- SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
- out uint subscriptionId,
- out UInt32Collection availableSequenceNumbers,
- out bool moreNotifications,
- out NotificationMessage notificationMessage,
- out StatusCodeCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
+ RequestHeader requestHeader,
+ SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
+ out uint subscriptionId,
+ out UInt32Collection availableSequenceNumbers,
+ out bool moreNotifications,
+ out NotificationMessage notificationMessage,
+ out StatusCodeCollection results,
+ out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.Publish);
@@ -1415,9 +1416,9 @@ namespace Opc.Ua.Server
requestHeader.Timestamp);
}
*/
-
+
Utils.Trace("PUBLISH #{0} RECEIVED. TIME={1:hh:mm:ss.fff}", requestHeader.RequestHandle, requestHeader.Timestamp);
-
+
notificationMessage = ServerInternal.SubscriptionManager.Publish(
context,
subscriptionAcknowledgements,
@@ -1440,7 +1441,7 @@ namespace Opc.Ua.Server
}
*/
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1455,7 +1456,7 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
@@ -1474,13 +1475,13 @@ namespace Opc.Ua.Server
try
{
AsyncPublishOperation operation = new AsyncPublishOperation(context, request, this);
-
- uint subscriptionId = 0;
- UInt32Collection availableSequenceNumbers = null;
- bool moreNotifications = false;
- NotificationMessage notificationMessage = null;
- StatusCodeCollection results = null;
- DiagnosticInfoCollection diagnosticInfos = null;
+
+ uint subscriptionId = 0;
+ UInt32Collection availableSequenceNumbers = null;
+ bool moreNotifications = false;
+ NotificationMessage notificationMessage = null;
+ StatusCodeCollection results = null;
+ DiagnosticInfoCollection diagnosticInfos = null;
notificationMessage = ServerInternal.SubscriptionManager.Publish(
context,
@@ -1574,9 +1575,9 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader Republish(
- RequestHeader requestHeader,
- uint subscriptionId,
- uint retransmitSequenceNumber,
+ RequestHeader requestHeader,
+ uint subscriptionId,
+ uint retransmitSequenceNumber,
out NotificationMessage notificationMessage)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.Republish);
@@ -1586,9 +1587,9 @@ namespace Opc.Ua.Server
notificationMessage = ServerInternal.SubscriptionManager.Republish(
context,
subscriptionId,
- retransmitSequenceNumber);
+ retransmitSequenceNumber);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1603,11 +1604,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1628,18 +1629,18 @@ namespace Opc.Ua.Server
///
public override ResponseHeader ModifySubscription(
RequestHeader requestHeader,
- uint subscriptionId,
- double requestedPublishingInterval,
- uint requestedLifetimeCount,
- uint requestedMaxKeepAliveCount,
- uint maxNotificationsPerPublish,
- byte priority,
- out double revisedPublishingInterval,
- out uint revisedLifetimeCount,
- out uint revisedMaxKeepAliveCount)
+ uint subscriptionId,
+ double requestedPublishingInterval,
+ uint requestedLifetimeCount,
+ uint requestedMaxKeepAliveCount,
+ uint maxNotificationsPerPublish,
+ byte priority,
+ out double revisedPublishingInterval,
+ out uint revisedLifetimeCount,
+ out uint revisedMaxKeepAliveCount)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.ModifySubscription);
-
+
try
{
ServerInternal.SubscriptionManager.ModifySubscription(
@@ -1654,7 +1655,7 @@ namespace Opc.Ua.Server
out revisedLifetimeCount,
out revisedMaxKeepAliveCount);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1669,11 +1670,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1688,20 +1689,20 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader SetPublishingMode(
- RequestHeader requestHeader,
- bool publishingEnabled,
- UInt32Collection subscriptionIds,
- out StatusCodeCollection results,
+ RequestHeader requestHeader,
+ bool publishingEnabled,
+ UInt32Collection subscriptionIds,
+ out StatusCodeCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.SetPublishingMode);
-
+
try
{
if (subscriptionIds == null || subscriptionIds.Count == 0)
{
throw new ServiceResultException(StatusCodes.BadNothingToDo);
- }
+ }
ServerInternal.SubscriptionManager.SetPublishingMode(
context,
@@ -1710,7 +1711,7 @@ namespace Opc.Ua.Server
out results,
out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1725,11 +1726,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1802,7 +1803,7 @@ namespace Opc.Ua.Server
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1818,12 +1819,12 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader CreateMonitoredItems(
- RequestHeader requestHeader,
- uint subscriptionId,
- TimestampsToReturn timestampsToReturn,
- MonitoredItemCreateRequestCollection itemsToCreate,
- out MonitoredItemCreateResultCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
+ RequestHeader requestHeader,
+ uint subscriptionId,
+ TimestampsToReturn timestampsToReturn,
+ MonitoredItemCreateRequestCollection itemsToCreate,
+ out MonitoredItemCreateResultCollection results,
+ out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.CreateMonitoredItems);
@@ -1832,7 +1833,7 @@ namespace Opc.Ua.Server
if (itemsToCreate == null || itemsToCreate.Count == 0)
{
throw new ServiceResultException(StatusCodes.BadNothingToDo);
- }
+ }
ServerInternal.SubscriptionManager.CreateMonitoredItems(
context,
@@ -1842,7 +1843,7 @@ namespace Opc.Ua.Server
out results,
out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1857,11 +1858,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1877,12 +1878,12 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader ModifyMonitoredItems(
- RequestHeader requestHeader,
- uint subscriptionId,
- TimestampsToReturn timestampsToReturn,
- MonitoredItemModifyRequestCollection itemsToModify,
- out MonitoredItemModifyResultCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
+ RequestHeader requestHeader,
+ uint subscriptionId,
+ TimestampsToReturn timestampsToReturn,
+ MonitoredItemModifyRequestCollection itemsToModify,
+ out MonitoredItemModifyResultCollection results,
+ out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.ModifyMonitoredItems);
@@ -1891,7 +1892,7 @@ namespace Opc.Ua.Server
if (itemsToModify == null || itemsToModify.Count == 0)
{
throw new ServiceResultException(StatusCodes.BadNothingToDo);
- }
+ }
ServerInternal.SubscriptionManager.ModifyMonitoredItems(
context,
@@ -1901,7 +1902,7 @@ namespace Opc.Ua.Server
out results,
out diagnosticInfos);
- return CreateResponse(requestHeader, context.StringTable);
+ return CreateResponse(requestHeader, context.StringTable);
}
catch (ServiceResultException e)
{
@@ -1916,11 +1917,11 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
- }
+ }
}
///
@@ -1935,20 +1936,20 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader DeleteMonitoredItems(
- RequestHeader requestHeader,
- uint subscriptionId,
- UInt32Collection monitoredItemIds,
- out StatusCodeCollection results,
+ RequestHeader requestHeader,
+ uint subscriptionId,
+ UInt32Collection monitoredItemIds,
+ out StatusCodeCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.DeleteMonitoredItems);
-
+
try
{
if (monitoredItemIds == null || monitoredItemIds.Count == 0)
{
throw new ServiceResultException(StatusCodes.BadNothingToDo);
- }
+ }
ServerInternal.SubscriptionManager.DeleteMonitoredItems(
context,
@@ -1972,7 +1973,7 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
@@ -1992,21 +1993,21 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader SetMonitoringMode(
- RequestHeader requestHeader,
- uint subscriptionId,
- MonitoringMode monitoringMode,
- UInt32Collection monitoredItemIds,
- out StatusCodeCollection results,
+ RequestHeader requestHeader,
+ uint subscriptionId,
+ MonitoringMode monitoringMode,
+ UInt32Collection monitoredItemIds,
+ out StatusCodeCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.SetMonitoringMode);
-
+
try
{
if (monitoredItemIds == null || monitoredItemIds.Count == 0)
{
throw new ServiceResultException(StatusCodes.BadNothingToDo);
- }
+ }
ServerInternal.SubscriptionManager.SetMonitoringMode(
context,
@@ -2031,7 +2032,7 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
@@ -2049,13 +2050,13 @@ namespace Opc.Ua.Server
/// Returns a object
///
public override ResponseHeader Call(
- RequestHeader requestHeader,
- CallMethodRequestCollection methodsToCall,
+ RequestHeader requestHeader,
+ CallMethodRequestCollection methodsToCall,
out CallMethodResultCollection results,
- out DiagnosticInfoCollection diagnosticInfos)
+ out DiagnosticInfoCollection diagnosticInfos)
{
OperationContext context = ValidateRequest(requestHeader, RequestType.Call);
-
+
try
{
if (methodsToCall == null || methodsToCall.Count == 0)
@@ -2100,15 +2101,15 @@ namespace Opc.Ua.Server
}
throw TranslateException(context, e);
- }
+ }
finally
{
OnRequestComplete(context);
}
}
-#endregion
+ #endregion
-#region Public Methods used by the Host Process
+ #region Public Methods used by the Host Process
///
/// The state object associated with the server.
/// It provides the shared components for the Server.
@@ -2121,13 +2122,13 @@ namespace Opc.Ua.Server
lock (m_lock)
{
if (m_serverInternal == null)
- {
+ {
throw new ServiceResultException(StatusCodes.BadServerHalted);
}
return m_serverInternal;
}
- }
+ }
}
///
@@ -2155,7 +2156,7 @@ namespace Opc.Ua.Server
{
ApplicationConfiguration configuration = string.IsNullOrEmpty(base.Configuration.SourceFilePath) ? base.Configuration : await ApplicationConfiguration.Load(new FileInfo(base.Configuration.SourceFilePath), ApplicationType.Server, null, false);
CertificateValidationEventHandler registrationCertificateValidator = new CertificateValidationEventHandler(RegistrationValidator_CertificateValidation);
- configuration.CertificateValidator.CertificateValidation += registrationCertificateValidator;
+ configuration.CertificateValidator.CertificateValidation += registrationCertificateValidator;
try
{
@@ -2259,8 +2260,8 @@ namespace Opc.Ua.Server
{
configuration.CertificateValidator.CertificateValidation -= registrationCertificateValidator;
}
- }
-
+ }
+
return false;
}
@@ -2298,7 +2299,7 @@ namespace Opc.Ua.Server
try
{
lock (m_registrationLock)
- {
+ {
// halt any outstanding timer.
if (m_registrationTimer != null)
{
@@ -2311,13 +2312,13 @@ namespace Opc.Ua.Server
{
// schedule next registration.
lock (m_registrationLock)
- {
+ {
if (m_maxRegistrationInterval > 0)
{
m_registrationTimer = new Timer(
- OnRegisterServer,
- this,
- m_maxRegistrationInterval,
+ OnRegisterServer,
+ this,
+ m_maxRegistrationInterval,
Timeout.Infinite);
m_lastRegistrationInterval = m_minRegistrationInterval;
@@ -2328,7 +2329,7 @@ namespace Opc.Ua.Server
else
{
lock (m_registrationLock)
- {
+ {
if (m_registrationTimer == null)
{
// calculate next registration attempt.
@@ -2340,7 +2341,7 @@ namespace Opc.Ua.Server
}
Utils.Trace("Register server failed. Trying again in {0} ms", m_lastRegistrationInterval);
-
+
// create timer.
m_registrationTimer = new Timer(OnRegisterServer, this, m_lastRegistrationInterval, Timeout.Infinite);
}
@@ -2348,13 +2349,13 @@ namespace Opc.Ua.Server
}
}
catch (Exception e)
- {
+ {
Utils.Trace(e, "Unexpected exception handling registration timer.");
}
}
-#endregion
+ #endregion
-#region Protected Members used for Request Processing
+ #region Protected Members used for Request Processing
///
/// The synchronization object.
///
@@ -2371,12 +2372,12 @@ namespace Opc.Ua.Server
ServerInternalData serverInternal = m_serverInternal;
if (serverInternal == null)
- {
+ {
throw new ServiceResultException(StatusCodes.BadServerHalted);
}
return serverInternal;
- }
+ }
}
///
@@ -2392,7 +2393,7 @@ namespace Opc.Ua.Server
{
throw new ServiceResultException(error);
}
-
+
// check server state.
ServerInternalData serverInternal = m_serverInternal;
@@ -2418,7 +2419,7 @@ namespace Opc.Ua.Server
}
if (m_serverInternal == null)
- {
+ {
throw new ServiceResultException(StatusCodes.BadServerHalted);
}
@@ -2517,7 +2518,7 @@ namespace Opc.Ua.Server
{
return null;
}
-
+
// check if inner result required.
ServiceResult innerResult = null;
@@ -2574,16 +2575,16 @@ namespace Opc.Ua.Server
lock (m_lock)
{
if (m_serverInternal == null)
- {
+ {
throw new ServiceResultException(StatusCodes.BadServerHalted);
}
-
+
m_serverInternal.RequestManager.RequestCompleted(context);
}
- }
-#endregion
+ }
+ #endregion
-#region Protected Members used for Initialization
+ #region Protected Members used for Initialization
///
/// Raised when the configuration changes.
///
@@ -2649,7 +2650,7 @@ namespace Opc.Ua.Server
lock (m_lock)
{
base.OnServerStarting(configuration);
-
+
// save minimum nonce length.
m_minNonceLength = configuration.SecurityConfiguration.NonceLength;
@@ -2657,7 +2658,7 @@ namespace Opc.Ua.Server
m_useRegisterServer2 = true;
}
}
-
+
///
/// Creates the endpoints and creates the hosts.
///
@@ -2668,8 +2669,8 @@ namespace Opc.Ua.Server
/// Returns IList of a host for a UA service.
///
protected override IList InitializeServiceHosts(
- ApplicationConfiguration configuration,
- out ApplicationDescription serverDescription,
+ ApplicationConfiguration configuration,
+ out ApplicationDescription serverDescription,
out EndpointDescriptionCollection endpoints)
{
serverDescription = null;
@@ -2679,17 +2680,17 @@ namespace Opc.Ua.Server
// ensure at least one security policy exists.
if (configuration.ServerConfiguration.SecurityPolicies.Count == 0)
- {
+ {
configuration.ServerConfiguration.SecurityPolicies.Add(new ServerSecurityPolicy());
}
-
+
// ensure at least one user token policy exists.
if (configuration.ServerConfiguration.UserTokenPolicies.Count == 0)
- {
+ {
UserTokenPolicy userTokenPolicy = new UserTokenPolicy();
-
+
userTokenPolicy.TokenType = UserTokenType.Anonymous;
- userTokenPolicy.PolicyId = userTokenPolicy.TokenType.ToString();
+ userTokenPolicy.PolicyId = userTokenPolicy.TokenType.ToString();
configuration.ServerConfiguration.UserTokenPolicies.Add(userTokenPolicy);
}
@@ -2706,27 +2707,25 @@ namespace Opc.Ua.Server
endpoints = new EndpointDescriptionCollection();
IList endpointsForHost = null;
- // create UA TCP host.
- endpointsForHost = CreateUaTcpServiceHost(
- hosts,
- configuration,
- configuration.ServerConfiguration.BaseAddresses,
- serverDescription,
- configuration.ServerConfiguration.SecurityPolicies);
+ foreach (var scheme in Utils.DefaultUriSchemes)
+ {
+ var binding = TransportBindings.Listeners.GetBinding(scheme);
+ if (binding != null)
+ {
+ endpointsForHost = binding.CreateServiceHost(
+ this,
+ hosts,
+ configuration,
+ configuration.ServerConfiguration.BaseAddresses,
+ serverDescription,
+ configuration.ServerConfiguration.SecurityPolicies,
+ InstanceCertificate,
+ InstanceCertificateChain
+ );
+ endpoints.AddRange(endpointsForHost);
+ }
+ }
- endpoints.InsertRange(0, endpointsForHost);
-
- // create HTTPS host.
-#if !NO_HTTPS
- endpointsForHost = CreateHttpsServiceHost(
- hosts,
- configuration,
- configuration.ServerConfiguration.BaseAddresses,
- serverDescription,
- configuration.ServerConfiguration.SecurityPolicies);
-
- endpoints.AddRange(endpointsForHost);
-#endif
return new List(hosts.Values);
}
@@ -2753,19 +2752,19 @@ namespace Opc.Ua.Server
protected override void StartApplication(ApplicationConfiguration configuration)
{
base.StartApplication(configuration);
-
+
lock (m_lock)
{
try
{
// create the datastore for the instance.
m_serverInternal = new ServerInternalData(
- ServerProperties,
- configuration,
+ ServerProperties,
+ configuration,
MessageContext,
new CertificateValidator(),
InstanceCertificate);
-
+
// create the manager responsible for providing localized string resources.
ResourceManager resourceManager = CreateResourceManager(m_serverInternal, configuration);
@@ -2774,20 +2773,20 @@ namespace Opc.Ua.Server
// create the master node manager.
MasterNodeManager masterNodeManager = CreateMasterNodeManager(m_serverInternal, configuration);
-
+
// add the node manager to the datastore.
m_serverInternal.SetNodeManager(masterNodeManager);
// put the node manager into a state that allows it to be used by other objects.
masterNodeManager.Startup();
-
+
// create the manager responsible for handling events.
EventManager eventManager = CreateEventManager(m_serverInternal, configuration);
// creates the server object.
m_serverInternal.CreateServerObject(
eventManager,
- resourceManager,
+ resourceManager,
requestManager);
// do any additional processing now that the node manager is up and running.
@@ -2795,20 +2794,20 @@ namespace Opc.Ua.Server
// create the manager responsible for aggregates.
m_serverInternal.AggregateManager = CreateAggregateManager(m_serverInternal, configuration);
-
+
// start the session manager.
SessionManager sessionManager = CreateSessionManager(m_serverInternal, configuration);
sessionManager.Startup();
-
+
// start the subscription manager.
SubscriptionManager subscriptionManager = CreateSubscriptionManager(m_serverInternal, configuration);
subscriptionManager.Startup();
-
+
// add the session manager to the datastore.
m_serverInternal.SetSessionManager(sessionManager, subscriptionManager);
-
+
ServerError = null;
-
+
// setup registration information.
lock (m_registrationLock)
{
@@ -2840,7 +2839,7 @@ namespace Opc.Ua.Server
m_registrationInfo.DiscoveryUrls.Add(uri.ToString());
}
-
+
// build list of registration endpoints.
m_registrationEndpoints = new ConfiguredEndpointCollection(configuration);
@@ -2858,7 +2857,7 @@ namespace Opc.Ua.Server
m_registrationEndpoints.Add(endpoint);
- m_minRegistrationInterval = 1000;
+ m_minRegistrationInterval = 1000;
m_lastRegistrationInterval = m_minRegistrationInterval;
// start registration timer.
@@ -2878,8 +2877,8 @@ namespace Opc.Ua.Server
SetServerState(ServerState.Running);
// all initialization is complete.
- OnServerStarted(m_serverInternal);
-
+ OnServerStarted(m_serverInternal);
+
// monitor the configuration file.
if (!String.IsNullOrEmpty(configuration.SourceFilePath))
{
@@ -2939,7 +2938,7 @@ namespace Opc.Ua.Server
}
catch (Exception e)
{
- ServerError = new ServiceResult(e);
+ ServerError = new ServiceResult(e);
}
finally
{
@@ -3061,7 +3060,7 @@ namespace Opc.Ua.Server
return manager;
}
-
+
///
/// Creates the resource manager for the server.
///
diff --git a/Stack/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj b/Stack/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj
new file mode 100644
index 0000000000..eb2ee31210
--- /dev/null
+++ b/Stack/Opc.Ua.Bindings.Https/Opc.Ua.Bindings.Https.csproj
@@ -0,0 +1,51 @@
+
+
+
+ $(DefineConstants);NET_STANDARD
+ $(LibTargetFrameworks)
+ 6
+ Opc.Ua.Bindings.Https
+ OPCFoundation.NetStandard.Opc.Ua.Bindings.Https
+ Opc.Ua.Bindings
+ OPC UA Https Binding Library
+ true
+ true
+
+
+
+ $(PackageId).Debug
+
+
+
+ $(DefineConstants);SIGNASSEMBLY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Stack/Opc.Ua.Bindings.Https/Properties/AssemblyInfo.cs b/Stack/Opc.Ua.Bindings.Https/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..289dc8e489
--- /dev/null
+++ b/Stack/Opc.Ua.Bindings.Https/Properties/AssemblyInfo.cs
@@ -0,0 +1,24 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - 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.Runtime.CompilerServices;
+
+#if SIGNASSEMBLY
+[assembly: InternalsVisibleTo("Opc.Ua.Core.Tests, PublicKey = " +
+ // OPC Foundation Strong Name Public Key
+ "0024000004800000940000000602000000240000525341310004000001000100d987b12f068b35" +
+ "80429f3dde01397508880fc7e62621397618456ca1549aeacfbdb90c62adfe918f05ce3677b390" +
+ "f78357b8745cb6e1334655afce1a9527ac92fc829ff585ea79f007e52ba0f83ead627e3edda40b" +
+ "ec5ae574128fc9342cb57cb8285aa4e5b589c0ebef3be571b5c8f2ab1067f7c880e8f8882a73c8" +
+ "0a12a1ef")]
+#else
+[assembly: InternalsVisibleTo("Opc.Ua.Core.Tests")]
+#endif
diff --git a/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs
new file mode 100644
index 0000000000..ee8f41e50f
--- /dev/null
+++ b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsServiceHost.cs
@@ -0,0 +1,175 @@
+/* ========================================================================
+ * Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
+ *
+ * OPC Reciprocal Community License ("RCL") Version 1.00
+ *
+ * Unless explicitly acquired and licensed from Licensor under another
+ * license, the contents of this file are subject to the Reciprocal
+ * Community License ("RCL") Version 1.00, or subsequent versions
+ * as allowed by the RCL, and You may not copy or use this file in either
+ * source code or executable form, except in compliance with the terms and
+ * conditions of the RCL.
+ *
+ * All software distributed under the RCL is provided strictly on an
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+ * AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the RCL for specific
+ * language governing rights and limitations under the RCL.
+ *
+ * The complete license agreement can be found here:
+ * http://opcfoundation.org/License/RCL/1.00/
+ * ======================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+
+
+namespace Opc.Ua.Bindings
+{
+ ///
+ /// Creates a new with
+ /// interface.
+ ///
+ public abstract class HttpsServiceHost : ITransportListenerFactory
+ {
+ ///
+ /// The protocol supported by the listener.
+ ///
+ public abstract string UriScheme { get; }
+
+ ///
+ /// The method creates a new instance of a .
+ ///
+ /// The transport listener.
+ public abstract ITransportListener Create();
+
+ ///
+ ///
+ /// Create a new service host for UA HTTPS.
+ ///
+ public List CreateServiceHost(
+ ServerBase serverBase,
+ IDictionary hosts,
+ ApplicationConfiguration configuration,
+ IList baseAddresses,
+ ApplicationDescription serverDescription,
+ List securityPolicies,
+ X509Certificate2 instanceCertificate,
+ X509Certificate2Collection instanceCertificateChain
+ )
+ {
+ // generate a unique host name.
+ string hostName = String.Empty;
+
+ if (hosts.ContainsKey(hostName))
+ {
+ hostName = "/Https";
+ }
+
+ if (hosts.ContainsKey(hostName))
+ {
+ hostName += Utils.Format("/{0}", hosts.Count);
+ }
+
+ // build list of uris.
+ List uris = new List();
+ EndpointDescriptionCollection endpoints = new EndpointDescriptionCollection();
+
+ // create the endpoint configuration to use.
+ EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(configuration);
+ string computerName = Utils.GetHostName();
+
+ for (int ii = 0; ii < baseAddresses.Count; ii++)
+ {
+ if (!baseAddresses[ii].StartsWith(Utils.UriSchemeHttps, StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ UriBuilder uri = new UriBuilder(baseAddresses[ii]);
+
+ if (uri.Path[uri.Path.Length - 1] != '/')
+ {
+ uri.Path += "/";
+ }
+
+ if (String.Compare(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ uri.Host = computerName;
+ }
+
+ uris.Add(uri.Uri);
+
+ if (uri.Scheme == Utils.UriSchemeHttps)
+ {
+ // Can only support one policy with HTTPS
+ // So pick the first policy with security mode sign and encrypt
+ ServerSecurityPolicy bestPolicy = null;
+ foreach (ServerSecurityPolicy policy in securityPolicies)
+ {
+ if (policy.SecurityMode != MessageSecurityMode.SignAndEncrypt)
+ {
+ continue;
+ }
+
+ bestPolicy = policy;
+ break;
+ }
+
+ // Pick the first policy from the list if no policies with sign and encrypt defined
+ if (bestPolicy == null)
+ {
+ bestPolicy = securityPolicies[0];
+ }
+
+ EndpointDescription description = new EndpointDescription();
+
+ description.EndpointUrl = uri.ToString();
+ description.Server = serverDescription;
+
+ if (instanceCertificate != null)
+ {
+ description.ServerCertificate = instanceCertificate.RawData;
+ // check if complete chain should be sent.
+ if (configuration.SecurityConfiguration.SendCertificateChain &&
+ instanceCertificateChain != null &&
+ instanceCertificateChain.Count > 0)
+ {
+ List serverCertificateChain = new List();
+
+ for (int i = 0; i < instanceCertificateChain.Count; i++)
+ {
+ serverCertificateChain.AddRange(instanceCertificateChain[i].RawData);
+ }
+
+ description.ServerCertificate = serverCertificateChain.ToArray();
+ }
+ }
+
+ description.SecurityMode = bestPolicy.SecurityMode;
+ description.SecurityPolicyUri = bestPolicy.SecurityPolicyUri;
+ description.SecurityLevel = ServerSecurityPolicy.CalculateSecurityLevel(bestPolicy.SecurityMode, bestPolicy.SecurityPolicyUri);
+ description.UserIdentityTokens = serverBase.GetUserTokenPolicies(configuration, description);
+ description.TransportProfileUri = Profiles.HttpsBinaryTransport;
+
+ ITransportListener listener = Create();
+ if (listener != null)
+ {
+ endpoints.Add(description);
+ serverBase.CreateServiceHostEndpoint(uri.Uri, endpoints, endpointConfiguration, listener,
+ configuration.CertificateValidator.GetChannelValidator());
+ }
+ else
+ {
+ Utils.Trace(Utils.TraceMasks.Error, "Failed to create endpoint {0} because the transport profile is unsupported.", uri);
+ }
+ }
+ }
+
+ return endpoints;
+ }
+ }
+}
diff --git a/Stack/Opc.Ua.Core/Stack/Https/HttpsTransportChannel.cs b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportChannel.cs
similarity index 85%
rename from Stack/Opc.Ua.Core/Stack/Https/HttpsTransportChannel.cs
rename to Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportChannel.cs
index bb4b586049..1ef2f2e264 100644
--- a/Stack/Opc.Ua.Core/Stack/Https/HttpsTransportChannel.cs
+++ b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportChannel.cs
@@ -11,18 +11,36 @@
*/
-#if !NO_HTTPS
-
using System;
using System.IO;
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
namespace Opc.Ua.Bindings
{
+ ///
+ /// Creates a new HttpsTransportChannel with ITransportChannel interface.
+ ///
+ public class HttpsTransportChannelFactory : ITransportChannelFactory
+ {
+ ///
+ /// The protocol supported by the channel.
+ ///
+ public string UriScheme => Utils.UriSchemeHttps;
+
+ ///
+ /// The method creates a new instance of a Https transport channel
+ ///
+ /// The transport channel
+ public ITransportChannel Create()
+ {
+ return new HttpsTransportChannel();
+ }
+ }
+
///
/// Wraps the HttpsTransportChannel and provides an ITransportChannel implementation.
///
@@ -34,34 +52,22 @@ namespace Opc.Ua.Bindings
}
///
- public TransportChannelFeatures SupportedFeatures
- {
- get { return TransportChannelFeatures.Open | TransportChannelFeatures.Reconnect | TransportChannelFeatures.BeginSendRequest; }
- }
+ public string UriScheme => Utils.UriSchemeHttps;
///
- public EndpointDescription EndpointDescription
- {
- get { return m_settings.Description; }
- }
+ public TransportChannelFeatures SupportedFeatures => TransportChannelFeatures.Open | TransportChannelFeatures.Reconnect | TransportChannelFeatures.BeginSendRequest;
///
- public EndpointConfiguration EndpointConfiguration
- {
- get { return m_settings.Configuration; }
- }
+ public EndpointDescription EndpointDescription => m_settings.Description;
///
- public ServiceMessageContext MessageContext
- {
- get { return m_quotas.MessageContext; }
- }
+ public EndpointConfiguration EndpointConfiguration => m_settings.Configuration;
///
- public ChannelToken CurrentToken
- {
- get { return null; }
- }
+ public ServiceMessageContext MessageContext => m_quotas.MessageContext;
+
+ ///
+ public ChannelToken CurrentToken => null;
///
public int OperationTimeout
@@ -114,8 +120,7 @@ namespace Opc.Ua.Bindings
try
{
handler.ServerCertificateCustomValidationCallback =
- (httpRequestMessage, cert, chain, policyErrors) =>
- {
+ (httpRequestMessage, cert, chain, policyErrors) => {
try
{
m_quotas.CertificateValidator?.Validate(cert);
@@ -187,22 +192,21 @@ namespace Opc.Ua.Bindings
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
AsyncResult result = new AsyncResult(callback, callbackData, m_operationTimeout, request, null);
- Task.Run(async () =>
- {
- try
- {
- response = await m_client.PostAsync(m_url, content);
- response.EnsureSuccessStatusCode();
- }
- catch (Exception ex)
- {
- Utils.Trace("Exception sending HTTPS request: " + ex.Message);
- result.Exception = ex;
- response = null;
- }
- result.Response = response;
- result.OperationCompleted();
- });
+ Task.Run(async () => {
+ try
+ {
+ response = await m_client.PostAsync(m_url, content);
+ response.EnsureSuccessStatusCode();
+ }
+ catch (Exception ex)
+ {
+ Utils.Trace("Exception sending HTTPS request: " + ex.Message);
+ result.Exception = ex;
+ response = null;
+ }
+ result.Response = response;
+ result.OperationCompleted();
+ });
return result;
}
@@ -345,4 +349,4 @@ namespace Opc.Ua.Bindings
private HttpClient m_client;
}
}
-#endif
+
diff --git a/Stack/Opc.Ua.Core/Stack/Https/HttpsListener.cs b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs
similarity index 93%
rename from Stack/Opc.Ua.Core/Stack/Https/HttpsListener.cs
rename to Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs
index 5409597a77..520bacd15e 100644
--- a/Stack/Opc.Ua.Core/Stack/Https/HttpsListener.cs
+++ b/Stack/Opc.Ua.Bindings.Https/Stack/Https/HttpsTransportListener.cs
@@ -21,8 +21,6 @@
* http://opcfoundation.org/License/RCL/1.00/
* ======================================================================*/
-#if !NO_HTTPS
-
using System;
using System.IO;
using System.Net;
@@ -38,14 +36,35 @@ using Microsoft.AspNetCore.Server.Kestrel.Https;
namespace Opc.Ua.Bindings
{
///
- /// Implements the startup of the Https listener.
+ /// Creates a new with
+ /// interface.
+ ///
+ public class HttpsTransportListenerFactory : HttpsServiceHost
+ {
+ ///
+ /// The protocol supported by the listener.
+ ///
+ public override string UriScheme => Utils.UriSchemeHttps;
+
+ ///
+ /// The method creates a new instance of a .
+ ///
+ /// The transport listener.
+ public override ITransportListener Create()
+ {
+ return new HttpsTransportListener();
+ }
+ }
+
+ ///
+ /// Implements the kestrel startup of the Https listener.
///
public class Startup
{
///
/// Get the Https listener.
///
- public static UaHttpsChannelListener Listener { get; set; }
+ public static HttpsTransportListener Listener { get; set; }
///
/// Configure the request pipeline for the listener.
@@ -72,13 +91,13 @@ namespace Opc.Ua.Bindings
///
/// Manages the connections for a UA HTTPS server.
///
- public partial class UaHttpsChannelListener : ITransportListener
+ public class HttpsTransportListener : ITransportListener
{
#region Constructors
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- public UaHttpsChannelListener()
+ public HttpsTransportListener()
{
}
#endregion
@@ -381,5 +400,3 @@ namespace Opc.Ua.Bindings
#endregion
}
}
-
-#endif
diff --git a/Stack/Opc.Ua.Core/Documentation/Opc.Ua.Bindings.cs b/Stack/Opc.Ua.Core/Documentation/Opc.Ua.Bindings.cs
index f2044565e5..a49f80ea1c 100644
--- a/Stack/Opc.Ua.Core/Documentation/Opc.Ua.Bindings.cs
+++ b/Stack/Opc.Ua.Core/Documentation/Opc.Ua.Bindings.cs
@@ -13,7 +13,7 @@
namespace Opc.Ua.Bindings
{
///
- /// The Opc.Ua.Bindings namespace contains classes that implement the WCF bindings for the
+ /// The Opc.Ua.Bindings namespace contains classes that implement the bindings for the
/// mappings described in Part 6 of the UA specification. It also includes an implementation for
/// the UA TCP protocol.
///
diff --git a/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj b/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj
index e6cfd90ab8..49c5235370 100644
--- a/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj
+++ b/Stack/Opc.Ua.Core/Opc.Ua.Core.csproj
@@ -16,10 +16,6 @@
$(PackageId).Debug
-
- $(DefineConstants);NO_HTTPS
-
-
$(DefineConstants);SIGNASSEMBLY
@@ -47,33 +43,20 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Stack/Opc.Ua.Core/Security/Constants/SecurityConstants.cs b/Stack/Opc.Ua.Core/Security/Constants/SecurityConstants.cs
index d1aa17c959..60fc921df4 100644
--- a/Stack/Opc.Ua.Core/Security/Constants/SecurityConstants.cs
+++ b/Stack/Opc.Ua.Core/Security/Constants/SecurityConstants.cs
@@ -102,7 +102,12 @@ namespace Opc.Ua
/// Communicates with UA TCP, UA Security and UA Binary.
///
public const string UaTcpTransport = "http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary";
-
+
+ ///
+ /// Communicates with UA TCP over secure Websockets, UA Security and UA Binary.
+ ///
+ public const string UaWssTransport = "http://opcfoundation.org/UA-Profile/Transport/uawss-uasc-uabinary";
+
///
/// Communicates with UA Binary over HTTPS.
///
diff --git a/Stack/Opc.Ua.Core/Stack/Bindings/BaseBinding.cs b/Stack/Opc.Ua.Core/Stack/Bindings/BaseBinding.cs
index 1a45f8b3b9..a2520e518a 100644
--- a/Stack/Opc.Ua.Core/Stack/Bindings/BaseBinding.cs
+++ b/Stack/Opc.Ua.Core/Stack/Bindings/BaseBinding.cs
@@ -10,14 +10,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
-using System.ServiceModel.Channels;
-
namespace Opc.Ua.Bindings
{
///
/// The binding for the UA native stack
///
- public abstract class BaseBinding : Binding
+ public abstract class BaseBinding
{
#region Constructors
///
diff --git a/Stack/Opc.Ua.Core/Stack/Bindings/ITransportBindings.cs b/Stack/Opc.Ua.Core/Stack/Bindings/ITransportBindings.cs
new file mode 100644
index 0000000000..918471ce93
--- /dev/null
+++ b/Stack/Opc.Ua.Core/Stack/Bindings/ITransportBindings.cs
@@ -0,0 +1,118 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - 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.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+
+namespace Opc.Ua.Bindings
+{
+ ///
+ /// This is an interface to the scheme of a transport binding.
+ ///
+ public interface ITransportBindingScheme
+ {
+ ///
+ /// The protocol scheme supported by the binding.
+ ///
+ string UriScheme { get; }
+ }
+
+ ///
+ /// This is an interface to the factory of a transport binding.
+ ///
+ public interface ITransportBindingFactory
+ : ITransportBindingScheme
+ {
+ ///
+ /// The factory to create a new transport.
+ ///
+ /// The transport.
+ T Create();
+ }
+
+ ///
+ /// The interface to manage transport bindings.
+ ///
+ public interface ITransportBindings
+ {
+ ///
+ /// Get a transport binding for a uri scheme.
+ ///
+ /// The uri scheme.
+ T GetBinding(string uriScheme);
+
+ ///
+ /// Return if there is a transport listener for a uri scheme.
+ ///
+ /// The uri scheme.
+ bool HasBinding(string uriScheme);
+
+ ///
+ /// Set the transport factory to the binding.
+ /// Overrides other bindings with the same uri scheme.
+ ///
+ void SetBinding(T binding);
+
+ ///
+ /// Add all bindings with interface exported from a assembly.
+ ///
+ /// The assembly with the bindings.
+ IEnumerable AddBindings(Assembly assembly);
+
+ ///
+ /// Add all bindings with interface from a list.
+ ///
+ /// The array of binding types with interface .
+ IEnumerable AddBindings(IEnumerable bindings);
+ }
+
+ ///
+ /// This is the transport listener factory interface for a binding (server).
+ ///
+ public interface ITransportListenerFactory :
+ ITransportBindingFactory
+ {
+ ///
+ /// Create the service host for a server using
+ ///
+ /// The server base.
+ /// The service hosts are added to this list.
+ /// The application configuration.
+ /// The base addreses for the service host.
+ /// The server description.
+ /// The list of supported security policies.
+ /// The server certificate.
+ /// The cert cahin of the server certificate.
+ List CreateServiceHost(
+ ServerBase serverBase,
+ IDictionary hosts,
+ ApplicationConfiguration configuration,
+ IList baseAddresses,
+ ApplicationDescription serverDescription,
+ List securityPolicies,
+ X509Certificate2 instanceCertificate,
+ X509Certificate2Collection instanceCertificateChain
+ );
+ }
+
+ ///
+ /// This is the transport channel factory interface for a binding (client).
+ ///
+ public interface ITransportChannelFactory :
+ ITransportBindingFactory
+ {
+ }
+
+}
diff --git a/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs b/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs
new file mode 100644
index 0000000000..b8f343a165
--- /dev/null
+++ b/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindings.cs
@@ -0,0 +1,88 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - 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;
+
+namespace Opc.Ua.Bindings
+{
+ ///
+ /// The transpaort bindings available for teh stack.
+ ///
+ public static class TransportBindings
+ {
+ static TransportBindings()
+ {
+ Channels = new TransportChannelBindings(new Type[] { typeof(TcpTransportChannelFactory) });
+ Listeners = new TransportListenerBindings(new Type[] { typeof(TcpTransportListenerFactory) });
+ }
+
+ ///
+ /// The bindings for transport channels (client).
+ ///
+ public static TransportChannelBindings Channels { get; private set; }
+
+ ///
+ /// The bindings for transport listeners (server).
+ ///
+ public static TransportListenerBindings Listeners { get; private set; }
+
+ ///
+ /// The bindings for the transport channels.
+ ///
+ public class TransportChannelBindings :
+ TransportBindingsBase
+ {
+ ///
+ /// Initialize the transport listener.
+ ///
+ /// List of known default bindings.
+ public TransportChannelBindings(Type[] defaultBindings) : base(defaultBindings)
+ {
+ }
+
+ ///
+ /// Get a transport channel for the specified uri scheme.
+ ///
+ /// The uri scheme of the transport.
+ public ITransportChannel GetChannel(string uriScheme)
+ {
+ var binding = GetBinding(uriScheme);
+ return binding?.Create();
+ }
+ }
+
+ ///
+ /// The bindings for the transport listeners.
+ ///
+ public class TransportListenerBindings :
+ TransportBindingsBase
+ {
+ ///
+ /// Initialize the transport listener.
+ ///
+ /// List of known default bindings.
+ public TransportListenerBindings(Type[] defaultBindings) : base(defaultBindings)
+ {
+ }
+
+ ///
+ /// Get a transport listener for the specified uri scheme.
+ ///
+ /// The uri scheme of the transport.
+ public ITransportListener GetListener(string uriScheme)
+ {
+ var binding = GetBinding(uriScheme);
+ return binding?.Create();
+ }
+ }
+ }
+}
diff --git a/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindingsBase.cs b/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindingsBase.cs
new file mode 100644
index 0000000000..004252534f
--- /dev/null
+++ b/Stack/Opc.Ua.Core/Stack/Bindings/TransportBindingsBase.cs
@@ -0,0 +1,174 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - 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.Linq;
+using System.Reflection;
+
+namespace Opc.Ua.Bindings
+{
+ ///
+ /// The bindings for the transport listeners.
+ ///
+ public class TransportBindingsBase :
+ ITransportBindings where T : class, ITransportBindingScheme
+ {
+ ///
+ /// Implement the default constructor.
+ ///
+ ///
+ /// The default constructor adds all interfaces T.
+ ///
+ protected TransportBindingsBase()
+ {
+ Bindings = new Dictionary();
+ AddBindings(typeof(TransportBindingsBase).Assembly);
+ }
+
+ ///
+ /// Initialize object with default list of bindings.
+ ///
+ protected TransportBindingsBase(Type[] defaultBindings)
+ {
+ Bindings = new Dictionary();
+ AddBindings(defaultBindings);
+ }
+
+ #region Public Properties
+ ///
+ /// Dictionary of bindings of type .
+ ///
+ protected Dictionary Bindings { get; private set; }
+ #endregion
+
+ #region ITransportBindings
+ ///
+ public T GetBinding(string uriScheme)
+ {
+ T binding;
+ if (!Bindings.TryGetValue(uriScheme, out binding))
+ {
+ TryAddDefaultTransportBindings(uriScheme);
+ if (!Bindings.TryGetValue(uriScheme, out binding))
+ {
+ return default(T);
+ }
+ }
+ return binding;
+ }
+
+ ///
+ public bool HasBinding(string uriScheme)
+ {
+ T binding;
+ if (Bindings.TryGetValue(uriScheme, out binding))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ public void SetBinding(T binding)
+ {
+ Bindings[binding.UriScheme] = binding;
+ }
+
+ ///
+ public IEnumerable AddBindings(Assembly assembly)
+ {
+ var bindings = assembly.GetExportedTypes().Where(type => IsBindingType(type));
+ return AddBindings(bindings);
+ }
+
+ ///
+ public IEnumerable AddBindings(IEnumerable bindings)
+ {
+ var result = new List();
+ foreach (Type bindingType in bindings)
+ {
+ var binding = Activator.CreateInstance(bindingType) as T;
+ if (binding != null)
+ {
+ Bindings[binding.UriScheme] = binding;
+ result.Add(bindingType);
+ }
+ }
+ return result;
+ }
+ #endregion
+
+ #region Private Methods
+ ///
+ /// Validate the type is a transport listener.
+ ///
+ protected static bool IsBindingType(System.Type bindingType)
+ {
+ if (bindingType == null)
+ {
+ return false;
+ }
+
+ var bindingTypeInfo = bindingType.GetTypeInfo();
+ if (bindingTypeInfo.IsAbstract ||
+ !typeof(T).GetTypeInfo().IsAssignableFrom(bindingTypeInfo))
+ {
+ return false;
+ }
+
+ var listener = Activator.CreateInstance(bindingType) as T;
+ if (listener == null)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Try to load a binding from well known assemblies at runtime.
+ ///
+ /// The uri scheme of the binding.
+ private bool TryAddDefaultTransportBindings(string scheme)
+ {
+ string assemblyName;
+ if (Utils.DefaultBindings.TryGetValue(scheme, out assemblyName))
+ {
+ Assembly assembly = null;
+ string fullName = Utils.DefaultOpcUaCoreAssemblyFullName.Replace(Utils.DefaultOpcUaCoreAssemblyName, assemblyName);
+ try
+ {
+ assembly = Assembly.Load(fullName);
+ }
+ catch
+ {
+ Utils.Trace(Utils.TraceMasks.Error, "Failed to load the assembly {0} for transport binding {1}.",
+ fullName, scheme
+ );
+ }
+
+ if (assembly != null)
+ {
+ var listeners = AddBindings(assembly);
+ return listeners.Count() > 0;
+ }
+ }
+ else
+ {
+ Utils.Trace(Utils.TraceMasks.Error, "The transport binding {0} is unsupported.", scheme);
+ }
+ return false;
+ }
+ #endregion
+ }
+}
diff --git a/Stack/Opc.Ua.Core/Stack/Bindings/TransportListenerBindings.cs b/Stack/Opc.Ua.Core/Stack/Bindings/TransportListenerBindings.cs
deleted file mode 100644
index db9f56a309..0000000000
--- a/Stack/Opc.Ua.Core/Stack/Bindings/TransportListenerBindings.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
- The source code in this file is covered under a dual-license scenario:
- - RCL: for OPC Foundation members in good-standing
- - 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.Linq;
-using System.Reflection;
-
-namespace Opc.Ua.Bindings
-{
- ///
- /// The binding for the transport listeners.
- ///
- public static class TransportListenerBindings
- {
- static TransportListenerBindings()
- {
- TransportListeners = new Dictionary();
- var listeners = typeof(TransportListenerBindings).Assembly.GetExportedTypes().Where(type => IsTransportListenerType(type));
- foreach (var listenerType in listeners)
- {
- Add(listenerType);
- }
- }
-
- #region Public Properties
- ///
- /// Dictionary of transported listeners.
- ///
- public static Dictionary TransportListeners { get; private set; }
-
- ///
- /// Get a transport listener for a uri scheme.
- ///
- /// The uri scheme.
- public static ITransportListener GetTransportListener(string uriScheme)
- {
- Type listenerType;
- if (TransportListeners.TryGetValue(uriScheme, out listenerType))
- {
- return Activator.CreateInstance(listenerType) as ITransportListener;
- }
- return null;
- }
-
- ///
- /// Add a transport listener to the binding.
- ///
- public static void Add(Type listenerType)
- {
- if (IsTransportListenerType(listenerType))
- {
- var listener = Activator.CreateInstance(listenerType) as ITransportListener;
- TransportListeners.Add(listener.UriScheme, listenerType);
- }
- }
-
- ///
- /// Validate the type is a transport listener.
- ///
- private static bool IsTransportListenerType(System.Type systemType)
- {
- if (systemType == null)
- {
- return false;
- }
-
- var systemTypeInfo = systemType.GetTypeInfo();
- if (systemTypeInfo.IsAbstract ||
- !typeof(ITransportListener).GetTypeInfo().IsAssignableFrom(systemTypeInfo))
- {
- return false;
- }
-
- var listener = Activator.CreateInstance(systemType) as ITransportListener;
- if (listener == null)
- {
- return false;
- }
-
- listener.Dispose();
-
- return true;
- }
- #endregion
- }
-}
diff --git a/Stack/Opc.Ua.Core/Stack/Client/ReverseConnectHost.cs b/Stack/Opc.Ua.Core/Stack/Client/ReverseConnectHost.cs
index 10bbbed0df..8df9a91cea 100644
--- a/Stack/Opc.Ua.Core/Stack/Client/ReverseConnectHost.cs
+++ b/Stack/Opc.Ua.Core/Stack/Client/ReverseConnectHost.cs
@@ -32,9 +32,13 @@ namespace Opc.Ua
{
if (url == null) throw new ArgumentNullException(nameof(url));
- var listener = TransportListenerBindings.GetTransportListener(url.Scheme);
-
- if (listener == null) throw new ArgumentException(nameof(url), "No suitable listener found.");
+ var listener = TransportBindings.Listeners.GetListener(url.Scheme);
+ if (listener == null)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadProtocolVersionUnsupported,
+ "Unsupported transport profile for scheme {0}\r\n", url.Scheme);
+ }
m_listener = listener;
Url = url;
diff --git a/Stack/Opc.Ua.Core/Stack/Client/UaChannelBase.cs b/Stack/Opc.Ua.Core/Stack/Client/UaChannelBase.cs
index d97703a95c..3e6ab9f4ad 100644
--- a/Stack/Opc.Ua.Core/Stack/Client/UaChannelBase.cs
+++ b/Stack/Opc.Ua.Core/Stack/Client/UaChannelBase.cs
@@ -692,28 +692,14 @@ namespace Opc.Ua
X509Certificate2Collection clientCertificateChain,
ServiceMessageContext messageContext)
{
- bool useUaTcp = description.EndpointUrl.StartsWith(Utils.UriSchemeOpcTcp);
- bool useHttps = description.EndpointUrl.StartsWith(Utils.UriSchemeHttps);
-
// initialize the channel which will be created with the server.
- ITransportChannel channel = null;
-
- if (useUaTcp)
- {
- channel = new TcpTransportChannel();
- }
-#if !NO_HTTPS
- else if (useHttps)
- {
- channel = new HttpsTransportChannel();
- }
-#endif
-
+ string uriScheme = new Uri(description.EndpointUrl).Scheme;
+ ITransportChannel channel = TransportBindings.Channels.GetChannel(uriScheme);
if (channel == null)
{
throw ServiceResultException.Create(
StatusCodes.BadProtocolVersionUnsupported,
- "Unsupported transport profile\r\n");
+ "Unsupported transport profile for scheme {0}\r\n", uriScheme);
}
// create a UA channel.
@@ -780,42 +766,37 @@ namespace Opc.Ua
X509Certificate2Collection clientCertificateChain,
ServiceMessageContext messageContext)
{
- bool useUaTcp = description.EndpointUrl.StartsWith(Utils.UriSchemeOpcTcp);
- bool useHttps = description.EndpointUrl.StartsWith(Utils.UriSchemeHttps);
+ string uriScheme = new Uri(description.EndpointUrl).Scheme;
switch (description.TransportProfileUri)
{
case Profiles.UaTcpTransport:
{
- useUaTcp = true;
+ uriScheme = Utils.UriSchemeOpcTcp;
break;
}
case Profiles.HttpsBinaryTransport:
{
- useHttps = true;
+ uriScheme = Utils.UriSchemeHttps;
break;
}
+
+ case Profiles.UaWssTransport:
+ {
+ uriScheme = Utils.UriSchemeOpcWss;
+ break;
+ }
+
}
// initialize the channel which will be created with the server.
- ITransportChannel channel = null;
- if (useUaTcp)
- {
- channel = new TcpTransportChannel();
- }
-#if !NO_HTTPS
- else if (useHttps)
- {
- channel = new HttpsTransportChannel();
- }
-#endif
-
+ ITransportChannel channel = TransportBindings.Channels.GetChannel(uriScheme);
if (channel == null)
{
throw ServiceResultException.Create(
StatusCodes.BadProtocolVersionUnsupported,
- "Unsupported transport profile\r\n");
+ "Unsupported transport profile for scheme {0}\r\n", uriScheme);
}
// create a UA-TCP channel.
diff --git a/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs b/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs
index 2e59f8ad9e..b4a4f3a96e 100644
--- a/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs
+++ b/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs
@@ -699,282 +699,60 @@ namespace Opc.Ua
}
///
- /// Create a new service host for UA TCP.
+ /// Create the transport listener for the service host endpoint.
///
- protected List CreateUaTcpServiceHost(
- IDictionary hosts,
- ApplicationConfiguration configuration,
- IList baseAddresses,
- ApplicationDescription serverDescription,
- List securityPolicies)
+ /// The endpoint Uri.
+ /// The description of the endpoints.
+ /// The configuration of the endpoints.
+ /// The transport listener.
+ /// The certificate validator for the transport.
+ public virtual void CreateServiceHostEndpoint(
+ Uri endpointUri,
+ EndpointDescriptionCollection endpoints,
+ EndpointConfiguration endpointConfiguration,
+ ITransportListener listener,
+ ICertificateValidator certificateValidator
+ )
{
- // generate a unique host name.
- string hostName = String.Empty;
-
- if (hosts.ContainsKey(hostName))
+ // create the stack listener.
+ try
{
- hostName = "/Tcp";
- }
+ TransportListenerSettings settings = new TransportListenerSettings();
- if (hosts.ContainsKey(hostName))
+ settings.Descriptions = endpoints;
+ settings.Configuration = endpointConfiguration;
+ settings.ServerCertificate = InstanceCertificate;
+ settings.CertificateValidator = certificateValidator;
+ settings.NamespaceUris = MessageContext.NamespaceUris;
+ settings.Factory = MessageContext.Factory;
+
+ listener.Open(
+ endpointUri,
+ settings,
+ GetEndpointInstance(this));
+
+ TransportListeners.Add(listener);
+
+ listener.ConnectionStatusChanged += OnConnectionStatusChanged;
+ }
+ catch (Exception e)
{
- hostName += Utils.Format("/{0}", hosts.Count);
+ string message = $"Could not load {endpointUri.Scheme} Stack Listener.";
+ if (e.InnerException != null)
+ {
+ message += (" " + e.InnerException.Message);
+ }
+ Utils.Trace(e, message);
}
-
- // build list of uris.
- List uris = new List();
- EndpointDescriptionCollection endpoints = new EndpointDescriptionCollection();
-
- // create the endpoint configuration to use.
- EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(configuration);
- string computerName = Utils.GetHostName();
-
- for (int ii = 0; ii < baseAddresses.Count; ii++)
- {
- // UA TCP and HTTPS endpoints support multiple policies.
- if (!baseAddresses[ii].StartsWith(Utils.UriSchemeOpcTcp, StringComparison.Ordinal))
- {
- continue;
- }
-
- UriBuilder uri = new UriBuilder(baseAddresses[ii]);
-
- if (String.Compare(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase) == 0)
- {
- uri.Host = computerName;
- }
-
- uris.Add(uri.Uri);
-
- foreach (ServerSecurityPolicy policy in securityPolicies)
- {
- // create the endpoint description.
- EndpointDescription description = new EndpointDescription();
-
- description.EndpointUrl = uri.ToString();
- description.Server = serverDescription;
-
- description.SecurityMode = policy.SecurityMode;
- description.SecurityPolicyUri = policy.SecurityPolicyUri;
- description.SecurityLevel = ServerSecurityPolicy.CalculateSecurityLevel(policy.SecurityMode, policy.SecurityPolicyUri);
- description.UserIdentityTokens = GetUserTokenPolicies(configuration, description);
- description.TransportProfileUri = Profiles.UaTcpTransport;
-
- bool requireEncryption = RequireEncryption(description);
-
- if (requireEncryption)
- {
- description.ServerCertificate = InstanceCertificate.RawData;
-
- // check if complete chain should be sent.
- if (configuration.SecurityConfiguration.SendCertificateChain &&
- InstanceCertificateChain != null &&
- InstanceCertificateChain.Count > 0)
- {
- List serverCertificateChain = new List();
-
- for (int i = 0; i < InstanceCertificateChain.Count; i++)
- {
- serverCertificateChain.AddRange(InstanceCertificateChain[i].RawData);
- }
-
- description.ServerCertificate = serverCertificateChain.ToArray();
- }
- }
-
- endpoints.Add(description);
- }
-
- // create the UA-TCP stack listener.
- try
- {
- TransportListenerSettings settings = new TransportListenerSettings();
-
- settings.Descriptions = endpoints;
- settings.Configuration = endpointConfiguration;
- settings.CertificateValidator = configuration.CertificateValidator.GetChannelValidator();
- settings.NamespaceUris = this.MessageContext.NamespaceUris;
- settings.Factory = this.MessageContext.Factory;
- settings.ServerCertificate = this.InstanceCertificate;
-
- if (configuration.SecurityConfiguration.SendCertificateChain)
- {
- settings.ServerCertificateChain = this.InstanceCertificateChain;
- }
-
- ITransportListener listener = new Opc.Ua.Bindings.TcpListener();
-
- listener.Open(
- uri.Uri,
- settings,
- GetEndpointInstance(this));
-
- TransportListeners.Add(listener);
-
- listener.ConnectionStatusChanged += OnConnectionStatusChanged;
- }
- catch (Exception e)
- {
- Utils.Trace(e, "Could not load UA-TCP Stack Listener.");
- throw;
- }
- }
-
- return endpoints;
}
-#if !NO_HTTPS
- ///
- /// Create a new service host for UA HTTPS.
- ///
- protected List CreateHttpsServiceHost(
- IDictionary hosts,
- ApplicationConfiguration configuration,
- IList baseAddresses,
- ApplicationDescription serverDescription,
- List securityPolicies)
- {
- // generate a unique host name.
- string hostName = String.Empty;
-
- if (hosts.ContainsKey(hostName))
- {
- hostName = "/Https";
- }
-
- if (hosts.ContainsKey(hostName))
- {
- hostName += Utils.Format("/{0}", hosts.Count);
- }
-
- // build list of uris.
- List uris = new List();
- EndpointDescriptionCollection endpoints = new EndpointDescriptionCollection();
-
- // create the endpoint configuration to use.
- EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(configuration);
- string computerName = Utils.GetHostName();
-
- for (int ii = 0; ii < baseAddresses.Count; ii++)
- {
- if (!baseAddresses[ii].StartsWith(Utils.UriSchemeHttps, StringComparison.Ordinal))
- {
- continue;
- }
-
- UriBuilder uri = new UriBuilder(baseAddresses[ii]);
-
- if (uri.Path[uri.Path.Length - 1] != '/')
- {
- uri.Path += "/";
- }
-
- if (String.Compare(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase) == 0)
- {
- uri.Host = computerName;
- }
-
- uris.Add(uri.Uri);
-
- if (uri.Scheme == Utils.UriSchemeHttps)
- {
- // Can only support one policy with HTTPS
- // So pick the first policy with security mode sign and encrypt
- ServerSecurityPolicy bestPolicy = null;
- foreach (ServerSecurityPolicy policy in securityPolicies)
- {
- if (policy.SecurityMode != MessageSecurityMode.SignAndEncrypt)
- {
- continue;
- }
-
- bestPolicy = policy;
- break;
- }
-
- // Pick the first policy from the list if no policies with sign and encrypt defined
- if (bestPolicy == null)
- {
- bestPolicy = securityPolicies[0];
- }
-
- EndpointDescription description = new EndpointDescription();
-
- description.EndpointUrl = uri.ToString();
- description.Server = serverDescription;
-
- if (InstanceCertificate != null)
- {
- description.ServerCertificate = InstanceCertificate.RawData;
-
- // check if complete chain should be sent.
- if (configuration.SecurityConfiguration.SendCertificateChain && InstanceCertificateChain != null && InstanceCertificateChain.Count > 0)
- {
- List serverCertificateChain = new List();
-
- for (int i = 0; i < InstanceCertificateChain.Count; i++)
- {
- serverCertificateChain.AddRange(InstanceCertificateChain[i].RawData);
- }
-
- description.ServerCertificate = serverCertificateChain.ToArray();
- }
- }
-
- description.SecurityMode = bestPolicy.SecurityMode;
- description.SecurityPolicyUri = bestPolicy.SecurityPolicyUri;
- description.SecurityLevel = ServerSecurityPolicy.CalculateSecurityLevel(bestPolicy.SecurityMode, bestPolicy.SecurityPolicyUri);
- description.UserIdentityTokens = GetUserTokenPolicies(configuration, description);
- description.TransportProfileUri = Profiles.HttpsBinaryTransport;
-
- endpoints.Add(description);
- }
-
- // create the stack listener.
- try
- {
- TransportListenerSettings settings = new TransportListenerSettings();
-
- settings.Descriptions = endpoints;
- settings.Configuration = endpointConfiguration;
- settings.ServerCertificate = this.InstanceCertificate;
- settings.CertificateValidator = configuration.CertificateValidator.GetChannelValidator();
- settings.NamespaceUris = this.MessageContext.NamespaceUris;
- settings.Factory = this.MessageContext.Factory;
-
- ITransportListener listener = new Opc.Ua.Bindings.UaHttpsChannelListener();
-
- listener.Open(
- uri.Uri,
- settings,
- GetEndpointInstance(this));
-
- TransportListeners.Add(listener);
-
- listener.ConnectionStatusChanged += OnConnectionStatusChanged;
- }
- catch (Exception e)
- {
- string message = "Could not load HTTPS Stack Listener.";
- if (e.InnerException != null)
- {
- message += (" " + e.InnerException.Message);
- }
- Utils.Trace(e, message);
- }
- }
-
- return endpoints;
- }
-#endif
-
///
/// Returns the UserTokenPolicies supported by the server.
///
/// The configuration.
/// The description.
/// Returns a collection of UserTokenPolicy objects, the return type is .
- protected virtual UserTokenPolicyCollection GetUserTokenPolicies(ApplicationConfiguration configuration, EndpointDescription description)
+ public virtual UserTokenPolicyCollection GetUserTokenPolicies(ApplicationConfiguration configuration, EndpointDescription description)
{
UserTokenPolicyCollection policies = new UserTokenPolicyCollection();
diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/ChannelQuotas.cs b/Stack/Opc.Ua.Core/Stack/Tcp/ChannelQuotas.cs
index d736acd641..6581fadd57 100644
--- a/Stack/Opc.Ua.Core/Stack/Tcp/ChannelQuotas.cs
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/ChannelQuotas.cs
@@ -10,8 +10,6 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
-using System.IdentityModel.Selectors;
-
namespace Opc.Ua.Bindings
{
///
diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs
index 6b30a3bf36..223e186b54 100644
--- a/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs
@@ -39,6 +39,11 @@ namespace Opc.Ua.Bindings
///
public class TcpTransportChannelFactory : ITransportChannelFactory
{
+ ///
+ /// The protocol supported by the channel.
+ ///
+ public string UriScheme => Utils.UriSchemeOpcTcp;
+
///
/// The method creates a new instance of a TCP transport channel
///
@@ -311,7 +316,6 @@ namespace Opc.Ua.Bindings
/// The socket handle.
public int Handle => m_socket != null ? m_socket.GetHashCode() : -1;
-
///
/// Gets the transport channel features implemented by this message socket.
///
diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpServiceHost.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpServiceHost.cs
new file mode 100644
index 0000000000..5f3a6c5ca3
--- /dev/null
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpServiceHost.cs
@@ -0,0 +1,142 @@
+/* Copyright (c) 1996-2020 The OPC Foundation. All rights reserved.
+ The source code in this file is covered under a dual-license scenario:
+ - RCL: for OPC Foundation members in good-standing
+ - 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;
+using System.Threading.Tasks;
+
+namespace Opc.Ua.Bindings
+{
+ ///
+ /// Creates a new Tcp service host.
+ ///
+ ///
+ /// This class can be used by a transport which
+ /// implements the
+ ///
+ public abstract class TcpServiceHost : ITransportListenerFactory
+ {
+ ///
+ public abstract string UriScheme { get; }
+
+ ///
+ public abstract ITransportListener Create();
+
+ ///
+ ///
+ /// Create a new service host for UA TCP.
+ ///
+ public List CreateServiceHost(
+ ServerBase serverBase,
+ IDictionary hosts,
+ ApplicationConfiguration configuration,
+ IList baseAddresses,
+ ApplicationDescription serverDescription,
+ List securityPolicies,
+ X509Certificate2 instanceCertificate,
+ X509Certificate2Collection instanceCertificateChain)
+ {
+ // generate a unique host name.
+ string hostName = String.Empty;
+
+ if (hosts.ContainsKey(hostName))
+ {
+ hostName = "/Tcp";
+ }
+
+ if (hosts.ContainsKey(hostName))
+ {
+ hostName += Utils.Format("/{0}", hosts.Count);
+ }
+
+ // build list of uris.
+ List uris = new List();
+ EndpointDescriptionCollection endpoints = new EndpointDescriptionCollection();
+
+ // create the endpoint configuration to use.
+ EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(configuration);
+ string computerName = Utils.GetHostName();
+
+ for (int ii = 0; ii < baseAddresses.Count; ii++)
+ {
+ // UA TCP and HTTPS endpoints support multiple policies.
+ if (!baseAddresses[ii].StartsWith(Utils.UriSchemeOpcTcp, StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ UriBuilder uri = new UriBuilder(baseAddresses[ii]);
+
+ if (String.Compare(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ uri.Host = computerName;
+ }
+
+ ITransportListener listener = this.Create();
+ if (listener != null)
+ {
+ uris.Add(uri.Uri);
+
+ foreach (ServerSecurityPolicy policy in securityPolicies)
+ {
+ // create the endpoint description.
+ EndpointDescription description = new EndpointDescription();
+
+ description.EndpointUrl = uri.ToString();
+ description.Server = serverDescription;
+
+ description.SecurityMode = policy.SecurityMode;
+ description.SecurityPolicyUri = policy.SecurityPolicyUri;
+ description.SecurityLevel = ServerSecurityPolicy.CalculateSecurityLevel(policy.SecurityMode, policy.SecurityPolicyUri);
+ description.UserIdentityTokens = serverBase.GetUserTokenPolicies(configuration, description);
+ description.TransportProfileUri = Profiles.UaTcpTransport;
+
+ bool requireEncryption = ServerBase.RequireEncryption(description);
+
+ if (requireEncryption)
+ {
+ description.ServerCertificate = instanceCertificate.RawData;
+
+ // check if complete chain should be sent.
+ if (configuration.SecurityConfiguration.SendCertificateChain &&
+ instanceCertificateChain != null &&
+ instanceCertificateChain.Count > 0)
+ {
+ List serverCertificateChain = new List();
+
+ for (int i = 0; i < instanceCertificateChain.Count; i++)
+ {
+ serverCertificateChain.AddRange(instanceCertificateChain[i].RawData);
+ }
+
+ description.ServerCertificate = serverCertificateChain.ToArray();
+ }
+ }
+
+ endpoints.Add(description);
+ }
+
+ serverBase.CreateServiceHostEndpoint(uri.Uri, endpoints, endpointConfiguration, listener,
+ configuration.CertificateValidator.GetChannelValidator()
+ );
+ }
+ else
+ {
+ Utils.Trace(Utils.TraceMasks.Error, "Failed to create endpoint {0} because the transport profile is unsupported.", uri);
+ }
+ }
+
+ return endpoints;
+ }
+ }
+}
diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/TcpListener.cs b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs
similarity index 97%
rename from Stack/Opc.Ua.Core/Stack/Tcp/TcpListener.cs
rename to Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs
index 3e3e31e680..640b86b94a 100644
--- a/Stack/Opc.Ua.Core/Stack/Tcp/TcpListener.cs
+++ b/Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs
@@ -20,9 +20,24 @@ using System.Threading.Tasks;
namespace Opc.Ua.Bindings
{
///
- /// Manages the connections for a UA TCP server.
+ /// Creates a new TcpTransportListener with ITransportListener interface.
///
- public class TcpListener : ITransportListener, ITcpChannelListener
+ public class TcpTransportListenerFactory : TcpServiceHost
+ {
+ ///
+ public override string UriScheme => Utils.UriSchemeOpcTcp;
+
+ ///
+ public override ITransportListener Create()
+ {
+ return new TcpTransportListener();
+ }
+ }
+
+ ///
+ /// Manages the transport for a UA TCP server.
+ ///
+ public class TcpTransportListener : ITransportListener, ITcpChannelListener
{
#region IDisposable Members
///
diff --git a/Stack/Opc.Ua.Core/Stack/Transport/ITransportChannel.cs b/Stack/Opc.Ua.Core/Stack/Transport/ITransportChannel.cs
index 8b6a65535c..18c45c50fb 100644
--- a/Stack/Opc.Ua.Core/Stack/Transport/ITransportChannel.cs
+++ b/Stack/Opc.Ua.Core/Stack/Transport/ITransportChannel.cs
@@ -15,18 +15,6 @@ using Opc.Ua.Bindings;
namespace Opc.Ua
{
- ///
- /// This is an interface to a channel which supports a factory
- ///
- public interface ITransportChannelFactory
- {
- ///
- /// The method creates a new transport channel
- ///
- /// the transport channel
- ITransportChannel Create();
- }
-
///
/// This is an interface to a channel which supports
///
diff --git a/Stack/Opc.Ua.Core/Stack/Transport/TransportListenerSettings.cs b/Stack/Opc.Ua.Core/Stack/Transport/TransportListenerSettings.cs
index 050c659f3a..0122b590f0 100644
--- a/Stack/Opc.Ua.Core/Stack/Transport/TransportListenerSettings.cs
+++ b/Stack/Opc.Ua.Core/Stack/Transport/TransportListenerSettings.cs
@@ -10,7 +10,6 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
-using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
namespace Opc.Ua
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs b/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs
index ae5e38eece..ce67819561 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/EncodeableFactory.cs
@@ -55,7 +55,7 @@ namespace Opc.Ua
public EncodeableFactory(bool shared)
{
m_encodeableTypes = new Dictionary();
- AddEncodeableTypes("Opc.Ua.Core");
+ AddEncodeableTypes(Utils.DefaultOpcUaCoreAssemblyFullName);
#if DEBUG
m_instanceId = Interlocked.Increment(ref m_globalInstanceCount);
diff --git a/Stack/Opc.Ua.Core/Types/Utils/Utils.cs b/Stack/Opc.Ua.Core/Types/Utils/Utils.cs
index 06d1b2e534..9210aa8e07 100644
--- a/Stack/Opc.Ua.Core/Types/Utils/Utils.cs
+++ b/Stack/Opc.Ua.Core/Types/Utils/Utils.cs
@@ -25,7 +25,7 @@ using System.Threading.Tasks;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Net;
-
+using System.Collections.ObjectModel;
namespace Opc.Ua
{
@@ -50,11 +50,30 @@ namespace Opc.Ua
///
public const string UriSchemeOpcTcp = "opc.tcp";
+ ///
+ /// The URI scheme for the UA TCP protocol over Secure WebSockets.
+ ///
+ public const string UriSchemeOpcWss = "opc.wss";
+
+ ///
+ /// The URI schemes which are supported in the core server.
+ ///
+ public static readonly string[] DefaultUriSchemes = new string []
+ {
+ Utils.UriSchemeOpcTcp,
+ Utils.UriSchemeHttps
+ };
+
///
/// The default port for the UA TCP protocol.
///
public const int UaTcpDefaultPort = 4840;
+ ///
+ /// The default port for the UA TCP protocol over WebSockets.
+ ///
+ public const int UaWebSocketsDefaultPort = 4843;
+
///
/// The urls of the discovery servers on a node.
///
@@ -67,11 +86,6 @@ namespace Opc.Ua
"http://{0}/UADiscovery/Default.svc"
};
- ///
- /// The class that provides the default implementation for the UA TCP protocol.
- ///
- public const string UaTcpBindingDefault = "Opc.Ua.Bindings.UaTcpBinding";
-
///
/// The default certificate store's type.
///
@@ -87,6 +101,23 @@ namespace Opc.Ua
///
public static string DefaultLocalFolder = Directory.GetCurrentDirectory();
+ ///
+ /// The full name of the Opc.Ua.Core assembly.
+ ///
+ public static readonly string DefaultOpcUaCoreAssemblyFullName = typeof(Utils).Assembly.GetName().FullName;
+
+ ///
+ /// The name of the Opc.Ua.Core assembly.
+ ///
+ public static readonly string DefaultOpcUaCoreAssemblyName = typeof(Utils).Assembly.GetName().Name;
+
+ ///
+ /// List of known default bindings hosted in other assemblies.
+ ///
+ public static ReadOnlyDictionary DefaultBindings = new ReadOnlyDictionary(
+ new Dictionary() {
+ { Utils.UriSchemeHttps, "Opc.Ua.Bindings.Https"}
+ });
#endregion
#region Trace Support
@@ -854,7 +885,6 @@ namespace Opc.Ua
#region String, Object and Data Convienence Functions
private const int MAX_MESSAGE_LENGTH = 1024;
-
private const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
private const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
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 14221f9736..ae1c254fc8 100644
--- a/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj
+++ b/Tests/Opc.Ua.Core.Tests/Opc.Ua.Core.Tests.csproj
@@ -22,6 +22,7 @@
+
diff --git a/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj b/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj
index f93fef7748..10f96647b0 100644
--- a/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj
+++ b/Tests/Opc.Ua.Gds.Tests/Opc.Ua.Gds.Tests.csproj
@@ -22,6 +22,7 @@
+
diff --git a/UA Core Library.sln b/UA Core Library.sln
index 725b95e149..1985786346 100644
--- a/UA Core Library.sln
+++ b/UA Core Library.sln
@@ -54,6 +54,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "azurepipelines", "azurepipe
.azurepipelines\testcc.yml = .azurepipelines\testcc.yml
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Opc.Ua.Bindings.Https", "Stack\Opc.Ua.Bindings.Https\Opc.Ua.Bindings.Https.csproj", "{759563A2-AF35-4E7B-B813-082F047C8705}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -100,6 +102,10 @@ Global
{7F726313-45CA-4571-AC8E-67DDBC196B21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F726313-45CA-4571-AC8E-67DDBC196B21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F726313-45CA-4571-AC8E-67DDBC196B21}.Release|Any CPU.Build.0 = Release|Any CPU
+ {759563A2-AF35-4E7B-B813-082F047C8705}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {759563A2-AF35-4E7B-B813-082F047C8705}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {759563A2-AF35-4E7B-B813-082F047C8705}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {759563A2-AF35-4E7B-B813-082F047C8705}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/UA Reference.sln b/UA Reference.sln
index 38aa6502f3..ea1a329d34 100644
--- a/UA Reference.sln
+++ b/UA Reference.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2010
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30523.141
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Opc.Ua.Server", "Libraries\Opc.Ua.Server\Opc.Ua.Server.csproj", "{6C449A1E-244E-4515-9949-A7E22012537C}"
EndProject
@@ -37,6 +37,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reference Server", "Applica
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleReferenceClient", "Applications\ConsoleReferenceClient\ConsoleReferenceClient.csproj", "{8121879E-D2FD-4B6A-97D9-0F6CBC294411}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Opc.Ua.Bindings.Https", "Stack\Opc.Ua.Bindings.Https\Opc.Ua.Bindings.Https.csproj", "{92D98D3D-2A7D-4F4B-8C72-1A98908D0221}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -180,6 +182,18 @@ Global
{8121879E-D2FD-4B6A-97D9-0F6CBC294411}.Release|x64.Build.0 = Release|Any CPU
{8121879E-D2FD-4B6A-97D9-0F6CBC294411}.Release|x86.ActiveCfg = Release|Any CPU
{8121879E-D2FD-4B6A-97D9-0F6CBC294411}.Release|x86.Build.0 = Release|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Debug|x64.Build.0 = Debug|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Debug|x86.Build.0 = Debug|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Release|Any CPU.Build.0 = Release|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Release|x64.ActiveCfg = Release|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Release|x64.Build.0 = Release|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Release|x86.ActiveCfg = Release|Any CPU
+ {92D98D3D-2A7D-4F4B-8C72-1A98908D0221}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/nuget/Opc.Ua.Symbols.nuspec b/nuget/Opc.Ua.Symbols.nuspec
index 6c1d3fd39f..ef36589737 100644
--- a/nuget/Opc.Ua.Symbols.nuspec
+++ b/nuget/Opc.Ua.Symbols.nuspec
@@ -14,6 +14,7 @@
OPCFoundation OPC-UA netstandard ios linux dotnet net netcore uwp
+
diff --git a/nuget/Opc.Ua.nuspec b/nuget/Opc.Ua.nuspec
index 83fa9d8771..02733abec4 100644
--- a/nuget/Opc.Ua.nuspec
+++ b/nuget/Opc.Ua.nuspec
@@ -14,6 +14,7 @@
OPCFoundation OPC-UA netstandard ios linux dotnet net netcore uwp
+