diff --git a/Libraries/Opc.Ua.Server/Diagnostics/CustomNodeManager.cs b/Libraries/Opc.Ua.Server/Diagnostics/CustomNodeManager.cs index 72c3539bcc..314f142336 100644 --- a/Libraries/Opc.Ua.Server/Diagnostics/CustomNodeManager.cs +++ b/Libraries/Opc.Ua.Server/Diagnostics/CustomNodeManager.cs @@ -583,6 +583,17 @@ namespace Opc.Ua.Server m_predefinedNodes = new NodeIdDictionary(); } + // assign a default value to any variable in namespace 0 + if (node is BaseVariableState nodeStateVar) + { + if (nodeStateVar.NodeId.NamespaceIndex == 0 && nodeStateVar.Value == null) + { + nodeStateVar.Value = TypeInfo.GetDefaultValue(nodeStateVar.DataType, + nodeStateVar.ValueRank, + Server.TypeTree); + } + } + NodeState activeNode = AddBehaviourToPredefinedNode(context, node); m_predefinedNodes[activeNode.NodeId] = activeNode; diff --git a/Libraries/Opc.Ua.Server/Diagnostics/DiagnosticsNodeManager.cs b/Libraries/Opc.Ua.Server/Diagnostics/DiagnosticsNodeManager.cs index 3a46df0b41..1f71be025a 100644 --- a/Libraries/Opc.Ua.Server/Diagnostics/DiagnosticsNodeManager.cs +++ b/Libraries/Opc.Ua.Server/Diagnostics/DiagnosticsNodeManager.cs @@ -141,9 +141,9 @@ namespace Opc.Ua.Server Server.CoreNodeManager.ImportNodes(SystemContext, PredefinedNodes.Values, true); // hook up the server GetMonitoredItems method. - MethodState getMonitoredItems = (MethodState)FindPredefinedNode( + GetMonitoredItemsMethodState getMonitoredItems = (GetMonitoredItemsMethodState)FindPredefinedNode( MethodIds.Server_GetMonitoredItems, - typeof(MethodState)); + typeof(GetMonitoredItemsMethodState)); if (getMonitoredItems != null) { @@ -169,11 +169,29 @@ namespace Opc.Ua.Server getMonitoredItemsOutputArguments.ClearChangeMasks(SystemContext, false); } } + + // Subscription Durable mode not supported by the server. + ServerObjectState serverObject = (ServerObjectState)FindPredefinedNode( + ObjectIds.Server, + typeof(ServerObjectState)); + + if (serverObject != null) + { + NodeState setSubscriptionDurableNode = serverObject.FindChild( + SystemContext, + BrowseNames.SetSubscriptionDurable); + + if (setSubscriptionDurableNode != null) + { + DeleteNode(SystemContext, MethodIds.Server_SetSubscriptionDurable); + serverObject.SetSubscriptionDurable = null; + } + } } } /// - /// Called when a client locks the server. + /// Called when a client gets the monitored items of a subscription. /// public ServiceResult OnGetMonitoredItems( ISystemContext context, diff --git a/Libraries/Opc.Ua.Server/Server/ServerInternalData.cs b/Libraries/Opc.Ua.Server/Server/ServerInternalData.cs index 668102a5fa..f253ffc544 100644 --- a/Libraries/Opc.Ua.Server/Server/ServerInternalData.cs +++ b/Libraries/Opc.Ua.Server/Server/ServerInternalData.cs @@ -602,6 +602,20 @@ namespace Opc.Ua.Server operationLimits.MaxMonitoredItemsPerCall = null; } + // setup PublishSubscribe Status State value + PubSubState pubSubState = PubSubState.Disabled; + + var default_PubSubState = (BaseVariableState)m_diagnosticsNodeManager.FindPredefinedNode( + VariableIds.PublishSubscribe_Status_State, + typeof(BaseVariableState)); + default_PubSubState.Value = pubSubState; + + // setup value for SupportedTransportProfiles + var default_SupportedTransportProfiles = (BaseVariableState)m_diagnosticsNodeManager.FindPredefinedNode( + VariableIds.PublishSubscribe_SupportedTransportProfiles, + typeof(BaseVariableState)); + default_SupportedTransportProfiles.Value = "uadp"; + // setup callbacks for dynamic values. serverObject.NamespaceArray.OnSimpleReadValue = OnReadNamespaceArray; serverObject.NamespaceArray.MinimumSamplingInterval = 1000; diff --git a/Libraries/Opc.Ua.Server/Subscription/SubscriptionManager.cs b/Libraries/Opc.Ua.Server/Subscription/SubscriptionManager.cs index d5d2faef05..d00057f33d 100644 --- a/Libraries/Opc.Ua.Server/Subscription/SubscriptionManager.cs +++ b/Libraries/Opc.Ua.Server/Subscription/SubscriptionManager.cs @@ -435,10 +435,10 @@ namespace Opc.Ua.Server if (!NodeId.IsNull(sessionId)) { - // check that the subscrition is the owner. + // check that the subscription is the owner. if (context != null && !Object.ReferenceEquals(context.Session, subscription.Session)) { - throw new ServiceResultException(StatusCodes.BadSessionIdInvalid); + throw new ServiceResultException(StatusCodes.BadSubscriptionIdInvalid); } SessionPublishQueue queue = null; diff --git a/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs b/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs index 5edfa2d1e2..e8e3a0877d 100644 --- a/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs +++ b/Stack/Opc.Ua.Core/Stack/Server/ServerBase.cs @@ -1075,6 +1075,12 @@ namespace Opc.Ua continue; } + if (endpointUrl.Port != baseAddress.Url.Port) + { + continue; + } + + EndpointDescription translation = new EndpointDescription(); translation.EndpointUrl = baseAddress.Url.ToString(); @@ -1094,22 +1100,8 @@ namespace Opc.Ua translation.UserIdentityTokens = endpoint.UserIdentityTokens; translation.Server = application; - // skip duplicates. - bool duplicateFound = false; + translations.Add(translation); - foreach (EndpointDescription existingTranslation in translations) - { - if (existingTranslation.IsEqual(translation)) - { - duplicateFound = true; - break; - } - } - - if (!duplicateFound) - { - translations.Add(translation); - } } } diff --git a/Stack/Opc.Ua.Core/Stack/State/MethodState.cs b/Stack/Opc.Ua.Core/Stack/State/MethodState.cs index 3755891c54..50e3fa25d6 100644 --- a/Stack/Opc.Ua.Core/Stack/State/MethodState.cs +++ b/Stack/Opc.Ua.Core/Stack/State/MethodState.cs @@ -612,11 +612,16 @@ namespace Opc.Ua expectedCount = InputArguments.Value.Length; } - if (expectedCount != inputArguments.Count) + if (expectedCount > inputArguments.Count) { return StatusCodes.BadArgumentsMissing; } + if (expectedCount < inputArguments.Count) + { + return StatusCodes.BadTooManyArguments; + } + // validate individual arguements. bool error = false; diff --git a/Stack/Opc.Ua.Core/Stack/State/NodeState.cs b/Stack/Opc.Ua.Core/Stack/State/NodeState.cs index 0084c2563d..097b90ee6a 100644 --- a/Stack/Opc.Ua.Core/Stack/State/NodeState.cs +++ b/Stack/Opc.Ua.Core/Stack/State/NodeState.cs @@ -3454,7 +3454,12 @@ namespace Opc.Ua value = description; } - return result; + if (value != null) + { + return result; + } + + break; } case Attributes.WriteMask: @@ -3505,7 +3510,12 @@ namespace Opc.Ua value = rolePermissions; } - return result; + if (value != null) + { + return result; + } + + break; } case Attributes.UserRolePermissions: @@ -3522,7 +3532,12 @@ namespace Opc.Ua value = userRolePermissions; } - return result; + if (value != null) + { + return result; + } + + break; } case Attributes.AccessRestrictions: diff --git a/Stack/Opc.Ua.Core/Types/BuiltIn/Variant.cs b/Stack/Opc.Ua.Core/Types/BuiltIn/Variant.cs index 874720042f..b22895a47d 100644 --- a/Stack/Opc.Ua.Core/Types/BuiltIn/Variant.cs +++ b/Stack/Opc.Ua.Core/Types/BuiltIn/Variant.cs @@ -861,6 +861,24 @@ namespace Opc.Ua throw new FormatException(Utils.Format("Invalid format string: '{0}'.", format)); } + /// + /// Append a ByteString as a hex string. + /// + private void AppendByteString(StringBuilder buffer, byte[] bytes, IFormatProvider formatProvider) + { + if (bytes != null) + { + for (int ii = 0; ii < bytes.Length; ii++) + { + buffer.AppendFormat(formatProvider, "{0:X2}", bytes[ii]); + } + } + else + { + buffer.Append("(null)"); + } + } + /// /// Formats a value as a string. /// @@ -877,12 +895,7 @@ namespace Opc.Ua if (m_typeInfo.BuiltInType == BuiltInType.ByteString && m_typeInfo.ValueRank < 0) { byte[] bytes = (byte[])value; - - for (int ii = 0; ii < bytes.Length; ii++) - { - buffer.AppendFormat(formatProvider, "{0:X2}", bytes[ii]); - } - + AppendByteString(buffer, bytes, formatProvider); return; } @@ -901,15 +914,33 @@ namespace Opc.Ua { buffer.Append('{'); - if (array.Length > 0) + if (m_typeInfo.BuiltInType == BuiltInType.ByteString) { - AppendFormat(buffer, array.GetValue(0), formatProvider); - } + if (array.Length > 0) + { + byte[] bytes = (byte[])array.GetValue(0); + AppendByteString(buffer, bytes, formatProvider); + } - for (int ii = 1; ii < array.Length; ii++) + for (int ii = 1; ii < array.Length; ii++) + { + buffer.Append('|'); + byte[] bytes = (byte[])array.GetValue(ii); + AppendByteString(buffer, bytes, formatProvider); + } + } + else { - buffer.Append(" |"); - AppendFormat(buffer, array.GetValue(ii), formatProvider); + if (array.Length > 0) + { + AppendFormat(buffer, array.GetValue(0), formatProvider); + } + + for (int ii = 1; ii < array.Length; ii++) + { + buffer.Append('|'); + AppendFormat(buffer, array.GetValue(ii), formatProvider); + } } buffer.Append('}'); diff --git a/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs index 38ef3379a1..e335ac09e0 100644 --- a/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs +++ b/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs @@ -2206,7 +2206,7 @@ namespace Opc.Ua } else { - value = new Variant(array); + value = new Variant(array, new TypeInfo(builtInType, 1)); } } }