diff --git a/SampleApplications/SDK/Opc.Ua.Client/NodeCache.cs b/SampleApplications/SDK/Opc.Ua.Client/NodeCache.cs
index 3ecfb5fb49..ea70c708f1 100644
--- a/SampleApplications/SDK/Opc.Ua.Client/NodeCache.cs
+++ b/SampleApplications/SDK/Opc.Ua.Client/NodeCache.cs
@@ -642,6 +642,12 @@ namespace Opc.Ua.Client
// create a placeholder for the node if it does not already exist.
if (!m_nodes.Exists(reference.NodeId))
{
+ // transform absolute identifiers.
+ if (reference.NodeId != null && reference.NodeId.IsAbsolute)
+ {
+ reference.NodeId = ExpandedNodeId.ToNodeId(reference.NodeId, NamespaceUris);
+ }
+
Node target = new Node(reference);
m_nodes.Attach(target);
}
diff --git a/SampleApplications/SDK/Opc.Ua.Server/NodeManager/ServerSystemContext.cs b/SampleApplications/SDK/Opc.Ua.Server/NodeManager/ServerSystemContext.cs
index 596cf50438..50cb6db7f9 100644
--- a/SampleApplications/SDK/Opc.Ua.Server/NodeManager/ServerSystemContext.cs
+++ b/SampleApplications/SDK/Opc.Ua.Server/NodeManager/ServerSystemContext.cs
@@ -128,36 +128,36 @@ namespace Opc.Ua.Server
///
/// The session to use.
///
- /// A copy of the system context that references the new operation context.
+ /// A copy of the system context that references the new session.
///
public ServerSystemContext Copy(Session session)
{
ServerSystemContext copy = (ServerSystemContext)MemberwiseClone();
- OperationContext = null;
+ copy.OperationContext = null;
if (session != null)
{
- SessionId = session.Id;
- UserIdentity = session.Identity;
- PreferredLocales = session.PreferredLocales;
+ copy.SessionId = session.Id;
+ copy.UserIdentity = session.Identity;
+ copy.PreferredLocales = session.PreferredLocales;
}
else
{
- SessionId = null;
- UserIdentity = null;
- PreferredLocales = null;
+ copy.SessionId = null;
+ copy.UserIdentity = null;
+ copy.PreferredLocales = null;
}
return copy;
}
///
- /// Creates a copy of the context that can be used with the specified session.
+ /// Creates a copy of the context that can be used with the specified server context.
///
- /// The session to use.
+ /// The server context to use.
///
- /// A copy of the system context that references the new operation context.
+ /// A copy of the system context that references the new server context.
///
public ServerSystemContext Copy(ServerSystemContext context)
{
@@ -165,14 +165,14 @@ namespace Opc.Ua.Server
if (context != null)
{
- OperationContext = context.OperationContext;
- SessionId = context.SessionId;
- UserIdentity = context.UserIdentity;
- PreferredLocales = context.PreferredLocales;
- NamespaceUris = context.NamespaceUris;
- ServerUris = context.ServerUris;
- TypeTable = context.TypeTable;
- EncodeableFactory = context.EncodeableFactory;
+ copy.OperationContext = context.OperationContext;
+ copy.SessionId = context.SessionId;
+ copy.UserIdentity = context.UserIdentity;
+ copy.PreferredLocales = context.PreferredLocales;
+ copy.NamespaceUris = context.NamespaceUris;
+ copy.ServerUris = context.ServerUris;
+ copy.TypeTable = context.TypeTable;
+ copy.EncodeableFactory = context.EncodeableFactory;
}
return copy;
diff --git a/SampleApplications/SDK/Opc.Ua.Server/Subscription/Subscription.cs b/SampleApplications/SDK/Opc.Ua.Server/Subscription/Subscription.cs
index bf9fb9b222..dea0d9f14d 100644
--- a/SampleApplications/SDK/Opc.Ua.Server/Subscription/Subscription.cs
+++ b/SampleApplications/SDK/Opc.Ua.Server/Subscription/Subscription.cs
@@ -335,8 +335,11 @@ namespace Opc.Ua.Server
public void Delete(OperationContext context)
{
// delete the diagnostics.
- ServerSystemContext systemContext = m_server.DefaultSystemContext.Copy(m_session);
- m_server.DiagnosticsNodeManager.DeleteSubscriptionDiagnostics(systemContext, m_diagnosticsId);
+ if (m_diagnosticsId != null && !m_diagnosticsId.IsNullNodeId)
+ {
+ ServerSystemContext systemContext = m_server.DefaultSystemContext.Copy(m_session);
+ m_server.DiagnosticsNodeManager.DeleteSubscriptionDiagnostics(systemContext, m_diagnosticsId);
+ }
lock (m_lock)
{
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs
index 0c450df7ae..7daeda9aa0 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/BinaryDecoder.cs
@@ -40,6 +40,7 @@ namespace Opc.Ua
m_istrm = new MemoryStream(buffer, start, count, false);
m_reader = new BinaryReader(m_istrm);
m_context = context;
+ m_nestingLevel = 0;
}
///
@@ -52,6 +53,7 @@ namespace Opc.Ua
m_istrm = stream;
m_reader = new BinaryReader(m_istrm);
m_context = context;
+ m_nestingLevel = 0;
}
#endregion
@@ -577,6 +579,17 @@ namespace Opc.Ua
///
public DiagnosticInfo ReadDiagnosticInfo(string fieldName)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
// read the encoding byte.
byte encodingByte = m_reader.ReadByte();
@@ -618,6 +631,8 @@ namespace Opc.Ua
value.InnerDiagnosticInfo = ReadDiagnosticInfo(null);
}
+ m_nestingLevel--;
+
return value;
}
@@ -665,551 +680,22 @@ namespace Opc.Ua
///
/// Reads an Variant from the stream.
///
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
public Variant ReadVariant(string fieldName)
{
- // read the encoding byte.
- byte encodingByte = m_reader.ReadByte();
-
- Variant value = new Variant();
-
- if ((encodingByte & (byte)VariantArrayEncodingBits.Array) != 0)
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
{
- // read the array length.
- int length = m_reader.ReadInt32();
-
- if (length < 0)
- {
- return value;
- }
-
- Array array = null;
-
- BuiltInType builtInType = (BuiltInType)(encodingByte & (byte)VariantArrayEncodingBits.TypeMask);
-
- switch (builtInType)
- {
- case BuiltInType.Boolean:
- {
- bool[] values = new bool[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadBoolean(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.SByte:
- {
- sbyte[] values = new sbyte[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadSByte(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Byte:
- {
- byte[] values = new byte[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadByte(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Int16:
- {
- short[] values = new short[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadInt16(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.UInt16:
- {
- ushort[] values = new ushort[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadUInt16(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Int32:
- case BuiltInType.Enumeration:
- {
- int[] values = new int[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadInt32(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.UInt32:
- {
- uint[] values = new uint[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadUInt32(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Int64:
- {
- long[] values = new long[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadInt64(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.UInt64:
- {
- ulong[] values = new ulong[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadUInt64(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Float:
- {
- float[] values = new float[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadFloat(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Double:
- {
- double[] values = new double[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadDouble(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.String:
- {
- string[] values = new string[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadString(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.DateTime:
- {
- DateTime[] values = new DateTime[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadDateTime(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Guid:
- {
- Uuid[] values = new Uuid[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadGuid(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.ByteString:
- {
- byte[][] values = new byte[length][];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadByteString(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.XmlElement:
- {
- try
- {
- XmlElement[] values = new XmlElement[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadXmlElement(null);
- }
-
- array = values;
- }
- catch (Exception ex)
- {
- Utils.Trace(ex, "Error reading variant.");
- }
-
- break;
- }
-
- case BuiltInType.NodeId:
- {
- NodeId[] values = new NodeId[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadNodeId(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.ExpandedNodeId:
- {
- ExpandedNodeId[] values = new ExpandedNodeId[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadExpandedNodeId(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.StatusCode:
- {
- StatusCode[] values = new StatusCode[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadStatusCode(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.QualifiedName:
- {
- QualifiedName[] values = new QualifiedName[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadQualifiedName(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.LocalizedText:
- {
- LocalizedText[] values = new LocalizedText[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadLocalizedText(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.ExtensionObject:
- {
- ExtensionObject[] values = new ExtensionObject[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadExtensionObject();
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.DataValue:
- {
- DataValue[] values = new DataValue[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadDataValue(null);
- }
-
- array = values;
- break;
- }
-
- case BuiltInType.Variant:
- {
- Variant[] values = new Variant[length];
-
- for (int ii = 0; ii < values.Length; ii++)
- {
- values[ii] = ReadVariant(null);
- }
-
- array = values;
- break;
- }
-
- default:
- {
- throw new ServiceResultException(
- StatusCodes.BadDecodingError,
- Utils.Format("Cannot decode unknown type in Variant object (0x{0:X2}).", encodingByte));
- }
- }
-
- if (array == null)
- {
- value = new Variant(StatusCodes.BadEncodingError);
- }
- else
- {
- // check for multi-dimensional arrays.
- if ((encodingByte & (byte)VariantArrayEncodingBits.ArrayDimensions) != 0)
- {
- Int32Collection dimensions = ReadInt32Array(null);
-
- if (dimensions != null && dimensions.Count > 0)
- {
- value = new Variant(new Matrix(array, builtInType, dimensions.ToArray()));
- }
- else
- {
- value = new Variant(new Matrix(array, builtInType));
- }
- }
- else
- {
- value = new Variant(array);
- }
- }
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
}
- else
- {
- switch ((BuiltInType)encodingByte)
- {
- case BuiltInType.Null:
- {
- value.Value = null;
- break;
- }
+ m_nestingLevel++;
- case BuiltInType.Boolean:
- {
- value.Set(ReadBoolean(null));
- break;
- }
+ Variant value = ReadVariantValue(fieldName);
- case BuiltInType.SByte:
- {
- value.Set(ReadSByte(null));
- break;
- }
-
- case BuiltInType.Byte:
- {
- value.Set(ReadByte(null));
- break;
- }
-
- case BuiltInType.Int16:
- {
- value.Set(ReadInt16(null));
- break;
- }
-
- case BuiltInType.UInt16:
- {
- value.Set(ReadUInt16(null));
- break;
- }
-
- case BuiltInType.Int32:
- case BuiltInType.Enumeration:
- {
- value.Set(ReadInt32(null));
- break;
- }
-
- case BuiltInType.UInt32:
- {
- value.Set(ReadUInt32(null));
- break;
- }
-
- case BuiltInType.Int64:
- {
- value.Set(ReadInt64(null));
- break;
- }
-
- case BuiltInType.UInt64:
- {
- value.Set(ReadUInt64(null));
- break;
- }
-
- case BuiltInType.Float:
- {
- value.Set(ReadFloat(null));
- break;
- }
-
- case BuiltInType.Double:
- {
- value.Set(ReadDouble(null));
- break;
- }
-
- case BuiltInType.String:
- {
- value.Set(ReadString(null));
- break;
- }
-
- case BuiltInType.DateTime:
- {
- value.Set(ReadDateTime(null));
- break;
- }
-
- case BuiltInType.Guid:
- {
- value.Set(ReadGuid(null));
- break;
- }
-
- case BuiltInType.ByteString:
- {
- value.Set(ReadByteString(null));
- break;
- }
-
- case BuiltInType.XmlElement:
- {
- try
- {
- value.Set(ReadXmlElement(null));
- }
- catch (Exception ex)
- {
- Utils.Trace(ex, "Error reading xml element for variant.");
- value.Set(StatusCodes.BadEncodingError);
- }
- break;
- }
-
- case BuiltInType.NodeId:
- {
- value.Set(ReadNodeId(null));
- break;
- }
-
- case BuiltInType.ExpandedNodeId:
- {
- value.Set(ReadExpandedNodeId(null));
- break;
- }
-
- case BuiltInType.StatusCode:
- {
- value.Set(ReadStatusCode(null));
- break;
- }
-
- case BuiltInType.QualifiedName:
- {
- value.Set(ReadQualifiedName(null));
- break;
- }
-
- case BuiltInType.LocalizedText:
- {
- value.Set(ReadLocalizedText(null));
- break;
- }
-
- case BuiltInType.ExtensionObject:
- {
- value.Set(ReadExtensionObject());
- break;
- }
-
- case BuiltInType.DataValue:
- {
- value.Set(ReadDataValue(null));
- break;
- }
-
- default:
- {
- throw new ServiceResultException(
- StatusCodes.BadDecodingError,
- Utils.Format("Cannot decode unknown type in Variant object (0x{0:X2}).", encodingByte));
- }
- }
- }
+ m_nestingLevel--;
return value;
}
@@ -1282,8 +768,21 @@ namespace Opc.Ua
Utils.Format("Cannot decode type '{0}'.", systemType.FullName));
}
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
encodeable.Decode(this);
+ m_nestingLevel--;
+
return encodeable;
}
@@ -2088,6 +1587,579 @@ namespace Opc.Ua
extension.Body = encodeable;
return extension;
}
+
+ ///
+ /// Reads an Variant from the stream.
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
+ private Variant ReadVariantValue(string fieldName)
+ {
+ // read the encoding byte.
+ byte encodingByte = m_reader.ReadByte();
+
+ Variant value = new Variant();
+
+ if ((encodingByte & (byte)VariantArrayEncodingBits.Array) != 0)
+ {
+ // read the array length.
+ int length = m_reader.ReadInt32();
+
+ if (length < 0)
+ {
+ return value;
+ }
+
+ Array array = null;
+
+ BuiltInType builtInType = (BuiltInType)(encodingByte & (byte)VariantArrayEncodingBits.TypeMask);
+
+ switch (builtInType)
+ {
+ case BuiltInType.Boolean:
+ {
+ bool[] values = new bool[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadBoolean(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.SByte:
+ {
+ sbyte[] values = new sbyte[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadSByte(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Byte:
+ {
+ byte[] values = new byte[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadByte(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Int16:
+ {
+ short[] values = new short[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadInt16(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.UInt16:
+ {
+ ushort[] values = new ushort[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadUInt16(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Int32:
+ case BuiltInType.Enumeration:
+ {
+ int[] values = new int[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadInt32(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.UInt32:
+ {
+ uint[] values = new uint[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadUInt32(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Int64:
+ {
+ long[] values = new long[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadInt64(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.UInt64:
+ {
+ ulong[] values = new ulong[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadUInt64(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Float:
+ {
+ float[] values = new float[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadFloat(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Double:
+ {
+ double[] values = new double[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadDouble(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.String:
+ {
+ string[] values = new string[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadString(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.DateTime:
+ {
+ DateTime[] values = new DateTime[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadDateTime(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Guid:
+ {
+ Uuid[] values = new Uuid[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadGuid(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.ByteString:
+ {
+ byte[][] values = new byte[length][];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadByteString(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.XmlElement:
+ {
+ try
+ {
+ XmlElement[] values = new XmlElement[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadXmlElement(null);
+ }
+
+ array = values;
+ }
+ catch (Exception ex)
+ {
+ Utils.Trace(ex, "Error reading variant.");
+ }
+
+ break;
+ }
+
+ case BuiltInType.NodeId:
+ {
+ NodeId[] values = new NodeId[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadNodeId(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.ExpandedNodeId:
+ {
+ ExpandedNodeId[] values = new ExpandedNodeId[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadExpandedNodeId(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.StatusCode:
+ {
+ StatusCode[] values = new StatusCode[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadStatusCode(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.QualifiedName:
+ {
+ QualifiedName[] values = new QualifiedName[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadQualifiedName(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.LocalizedText:
+ {
+ LocalizedText[] values = new LocalizedText[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadLocalizedText(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.ExtensionObject:
+ {
+ ExtensionObject[] values = new ExtensionObject[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadExtensionObject();
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.DataValue:
+ {
+ DataValue[] values = new DataValue[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadDataValue(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ case BuiltInType.Variant:
+ {
+ Variant[] values = new Variant[length];
+
+ for (int ii = 0; ii < values.Length; ii++)
+ {
+ values[ii] = ReadVariant(null);
+ }
+
+ array = values;
+ break;
+ }
+
+ default:
+ {
+ throw new ServiceResultException(
+ StatusCodes.BadDecodingError,
+ Utils.Format("Cannot decode unknown type in Variant object (0x{0:X2}).", encodingByte));
+ }
+ }
+
+ if (array == null)
+ {
+ value = new Variant(StatusCodes.BadEncodingError);
+ }
+ else
+ {
+ // check for multi-dimensional arrays.
+ if ((encodingByte & (byte)VariantArrayEncodingBits.ArrayDimensions) != 0)
+ {
+ Int32Collection dimensions = ReadInt32Array(null);
+
+ // check if ArrayDimensions are consistent with the ArrayLength.
+ if (dimensions == null || dimensions.Count == 0)
+ {
+ throw new ServiceResultException(
+ StatusCodes.BadDecodingError,
+ "ArrayDimensions not specified when ArrayDimensions encoding bit was set in Variant object.");
+ }
+
+ int[] dimensionsArray = dimensions.ToArray();
+ int matrixLength = 1;
+
+ for (int ii = 0; ii < dimensionsArray.Length; ii++)
+ {
+ if (dimensionsArray[ii] == 0 && length > 0)
+ {
+ throw new ServiceResultException(
+ StatusCodes.BadDecodingError,
+ Utils.Format("ArrayDimensions [{0}] is zero in Variant object.", ii));
+ }
+
+ matrixLength *= dimensionsArray[ii];
+ }
+
+ if (matrixLength != length)
+ {
+ throw new ServiceResultException(StatusCodes.BadDecodingError, "ArrayDimensions does not match with the ArrayLength in Variant object.");
+ }
+
+ value = new Variant(new Matrix(array, builtInType, dimensions.ToArray()));
+ }
+ else
+ {
+ value = new Variant(array);
+ }
+ }
+ }
+
+ else
+ {
+ switch ((BuiltInType)encodingByte)
+ {
+ case BuiltInType.Null:
+ {
+ value.Value = null;
+ break;
+ }
+
+ case BuiltInType.Boolean:
+ {
+ value.Set(ReadBoolean(null));
+ break;
+ }
+
+ case BuiltInType.SByte:
+ {
+ value.Set(ReadSByte(null));
+ break;
+ }
+
+ case BuiltInType.Byte:
+ {
+ value.Set(ReadByte(null));
+ break;
+ }
+
+ case BuiltInType.Int16:
+ {
+ value.Set(ReadInt16(null));
+ break;
+ }
+
+ case BuiltInType.UInt16:
+ {
+ value.Set(ReadUInt16(null));
+ break;
+ }
+
+ case BuiltInType.Int32:
+ case BuiltInType.Enumeration:
+ {
+ value.Set(ReadInt32(null));
+ break;
+ }
+
+ case BuiltInType.UInt32:
+ {
+ value.Set(ReadUInt32(null));
+ break;
+ }
+
+ case BuiltInType.Int64:
+ {
+ value.Set(ReadInt64(null));
+ break;
+ }
+
+ case BuiltInType.UInt64:
+ {
+ value.Set(ReadUInt64(null));
+ break;
+ }
+
+ case BuiltInType.Float:
+ {
+ value.Set(ReadFloat(null));
+ break;
+ }
+
+ case BuiltInType.Double:
+ {
+ value.Set(ReadDouble(null));
+ break;
+ }
+
+ case BuiltInType.String:
+ {
+ value.Set(ReadString(null));
+ break;
+ }
+
+ case BuiltInType.DateTime:
+ {
+ value.Set(ReadDateTime(null));
+ break;
+ }
+
+ case BuiltInType.Guid:
+ {
+ value.Set(ReadGuid(null));
+ break;
+ }
+
+ case BuiltInType.ByteString:
+ {
+ value.Set(ReadByteString(null));
+ break;
+ }
+
+ case BuiltInType.XmlElement:
+ {
+ try
+ {
+ value.Set(ReadXmlElement(null));
+ }
+ catch (Exception ex)
+ {
+ Utils.Trace(ex, "Error reading xml element for variant.");
+ value.Set(StatusCodes.BadEncodingError);
+ }
+ break;
+ }
+
+ case BuiltInType.NodeId:
+ {
+ value.Set(ReadNodeId(null));
+ break;
+ }
+
+ case BuiltInType.ExpandedNodeId:
+ {
+ value.Set(ReadExpandedNodeId(null));
+ break;
+ }
+
+ case BuiltInType.StatusCode:
+ {
+ value.Set(ReadStatusCode(null));
+ break;
+ }
+
+ case BuiltInType.QualifiedName:
+ {
+ value.Set(ReadQualifiedName(null));
+ break;
+ }
+
+ case BuiltInType.LocalizedText:
+ {
+ value.Set(ReadLocalizedText(null));
+ break;
+ }
+
+ case BuiltInType.ExtensionObject:
+ {
+ value.Set(ReadExtensionObject());
+ break;
+ }
+
+ case BuiltInType.DataValue:
+ {
+ value.Set(ReadDataValue(null));
+ break;
+ }
+
+ default:
+ {
+ throw new ServiceResultException(
+ StatusCodes.BadDecodingError,
+ Utils.Format("Cannot decode unknown type in Variant object (0x{0:X2}).", encodingByte));
+ }
+ }
+ }
+
+ return value;
+ }
#endregion
#region Private Fields
@@ -2096,6 +2168,7 @@ namespace Opc.Ua
private ServiceMessageContext m_context;
private ushort[] m_namespaceMappings;
private ushort[] m_serverMappings;
+ private uint m_nestingLevel;
#endregion
}
}
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs
index 0dce860272..a1c397334f 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/BinaryEncoder.cs
@@ -33,6 +33,7 @@ namespace Opc.Ua
m_ostrm = new MemoryStream();
m_writer = new BinaryWriter(m_ostrm);
m_context = context;
+ m_nestingLevel = 0;
}
///
@@ -45,6 +46,7 @@ namespace Opc.Ua
m_ostrm = new MemoryStream(buffer, start, count);
m_writer = new BinaryWriter(m_ostrm);
m_context = context;
+ m_nestingLevel = 0;
}
///
@@ -57,6 +59,7 @@ namespace Opc.Ua
m_ostrm = stream;
m_writer = new BinaryWriter(m_ostrm);
m_context = context;
+ m_nestingLevel = 0;
}
#endregion
@@ -644,6 +647,15 @@ namespace Opc.Ua
///
public void WriteDiagnosticInfo(string fieldName, DiagnosticInfo value)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
// check for null.
if (value == null)
{
@@ -651,6 +663,8 @@ namespace Opc.Ua
return;
}
+ m_nestingLevel++;
+
// calculate the encoding.
byte encoding = 0;
@@ -727,6 +741,8 @@ namespace Opc.Ua
{
WriteDiagnosticInfo(null, value.InnerDiagnosticInfo);
}
+
+ m_nestingLevel--;
}
///
@@ -792,160 +808,24 @@ namespace Opc.Ua
}
///
- /// Writes an Variant array to the stream.
+ /// Writes an Variant to the stream.
///
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
public void WriteVariant(string fieldName, Variant value)
{
- // check for null.
- if (value.Value == null || value.TypeInfo == null || value.TypeInfo.BuiltInType == BuiltInType.Null)
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
{
- WriteByte(null, 0);
- return;
- }
-
- // encode enums as int32.
- byte encodingByte = (byte)value.TypeInfo.BuiltInType;
-
- if (value.TypeInfo.BuiltInType == BuiltInType.Enumeration)
- {
- encodingByte = (byte)BuiltInType.Int32;
- }
-
- object valueToEncode = value.Value;
-
- if (value.TypeInfo.ValueRank < 0)
- {
- WriteByte(null, encodingByte);
-
- switch (value.TypeInfo.BuiltInType)
- {
- case BuiltInType.Boolean: { WriteBoolean(null, (bool)valueToEncode); return; }
- case BuiltInType.SByte: { WriteSByte(null, (sbyte)valueToEncode); return; }
- case BuiltInType.Byte: { WriteByte(null, (byte)valueToEncode); return; }
- case BuiltInType.Int16: { WriteInt16(null, (short)valueToEncode); return; }
- case BuiltInType.UInt16: { WriteUInt16(null, (ushort)valueToEncode); return; }
- case BuiltInType.Int32: { WriteInt32(null, (int)valueToEncode); return; }
- case BuiltInType.UInt32: { WriteUInt32(null, (uint)valueToEncode); return; }
- case BuiltInType.Int64: { WriteInt64(null, (long)valueToEncode); return; }
- case BuiltInType.UInt64: { WriteUInt64(null, (ulong)valueToEncode); return; }
- case BuiltInType.Float: { WriteFloat(null, (float)valueToEncode); return; }
- case BuiltInType.Double: { WriteDouble(null, (double)valueToEncode); return; }
- case BuiltInType.String: { WriteString(null, (string)valueToEncode); return; }
- case BuiltInType.DateTime: { WriteDateTime(null, (DateTime)valueToEncode); return; }
- case BuiltInType.Guid: { WriteGuid(null, (Uuid)valueToEncode); return; }
- case BuiltInType.ByteString: { WriteByteString(null, (byte[])valueToEncode); return; }
- case BuiltInType.XmlElement: { WriteXmlElement(null, (XmlElement)valueToEncode); return; }
- case BuiltInType.NodeId: { WriteNodeId(null, (NodeId)valueToEncode); return; }
- case BuiltInType.ExpandedNodeId: { WriteExpandedNodeId(null, (ExpandedNodeId)valueToEncode); return; }
- case BuiltInType.StatusCode: { WriteStatusCode(null, (StatusCode)valueToEncode); return; }
- case BuiltInType.QualifiedName: { WriteQualifiedName(null, (QualifiedName)valueToEncode); return; }
- case BuiltInType.LocalizedText: { WriteLocalizedText(null, (LocalizedText)valueToEncode); return; }
- case BuiltInType.ExtensionObject: { WriteExtensionObject(null, (ExtensionObject)valueToEncode); return; }
- case BuiltInType.DataValue: { WriteDataValue(null, (DataValue)valueToEncode); return; }
- case BuiltInType.Enumeration: { WriteInt32(null, (int)valueToEncode); return; }
- }
-
throw ServiceResultException.Create(
- StatusCodes.BadEncodingError,
- "Unexpected type encountered while encoding a Variant: {0}",
- value.TypeInfo.BuiltInType);
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
}
- if (value.TypeInfo.ValueRank >= 0)
- {
- Matrix matrix = null;
+ m_nestingLevel++;
- encodingByte |= (byte)VariantArrayEncodingBits.Array;
+ WriteVariantValue(fieldName, value);
- if (value.TypeInfo.ValueRank > 1)
- {
- encodingByte |= (byte)VariantArrayEncodingBits.ArrayDimensions;
- matrix = (Matrix)valueToEncode;
- valueToEncode = matrix.Elements;
- }
-
- WriteByte(null, encodingByte);
-
- switch (value.TypeInfo.BuiltInType)
- {
- case BuiltInType.Boolean: { WriteBooleanArray(null, (bool[])valueToEncode); break; }
- case BuiltInType.SByte: { WriteSByteArray(null, (sbyte[])valueToEncode); break; }
- case BuiltInType.Byte: { WriteByteArray(null, (byte[])valueToEncode); break; }
- case BuiltInType.Int16: { WriteInt16Array(null, (short[])valueToEncode); break; }
- case BuiltInType.UInt16: { WriteUInt16Array(null, (ushort[])valueToEncode); break; }
- case BuiltInType.Int32: { WriteInt32Array(null, (int[])valueToEncode); break; }
- case BuiltInType.UInt32: { WriteUInt32Array(null, (uint[])valueToEncode); break; }
- case BuiltInType.Int64: { WriteInt64Array(null, (long[])valueToEncode); break; }
- case BuiltInType.UInt64: { WriteUInt64Array(null, (ulong[])valueToEncode); break; }
- case BuiltInType.Float: { WriteFloatArray(null, (float[])valueToEncode); break; }
- case BuiltInType.Double: { WriteDoubleArray(null, (double[])valueToEncode); break; }
- case BuiltInType.String: { WriteStringArray(null, (string[])valueToEncode); break; }
- case BuiltInType.DateTime: { WriteDateTimeArray(null, (DateTime[])valueToEncode); break; }
- case BuiltInType.Guid: { WriteGuidArray(null, (Uuid[])valueToEncode); break; }
- case BuiltInType.ByteString: { WriteByteStringArray(null, (byte[][])valueToEncode); break; }
- case BuiltInType.XmlElement: { WriteXmlElementArray(null, (XmlElement[])valueToEncode); break; }
- case BuiltInType.NodeId: { WriteNodeIdArray(null, (NodeId[])valueToEncode); break; }
- case BuiltInType.ExpandedNodeId: { WriteExpandedNodeIdArray(null, (ExpandedNodeId[])valueToEncode); break; }
- case BuiltInType.StatusCode: { WriteStatusCodeArray(null, (StatusCode[])valueToEncode); break; }
- case BuiltInType.QualifiedName: { WriteQualifiedNameArray(null, (QualifiedName[])valueToEncode); break; }
- case BuiltInType.LocalizedText: { WriteLocalizedTextArray(null, (LocalizedText[])valueToEncode); break; }
- case BuiltInType.ExtensionObject: { WriteExtensionObjectArray(null, (ExtensionObject[])valueToEncode); break; }
- case BuiltInType.DataValue: { WriteDataValueArray(null, (DataValue[])valueToEncode); break; }
-
- case BuiltInType.Enumeration:
- {
- Enum[] enums = valueToEncode as Enum[];
- int[] ints = new int[enums.Length];
-
- for (int ii = 0; ii < enums.Length; ii++)
- {
- ints[ii] = (int)(object)enums[ii];
- }
-
- WriteInt32Array(null, ints);
- return;
- }
-
- case BuiltInType.Variant:
- {
- Variant[] variants = valueToEncode as Variant[];
-
- if (variants != null)
- {
- WriteVariantArray(null, variants);
- break;
- }
-
- object[] objects = valueToEncode as object[];
-
- if (objects != null)
- {
- WriteObjectArray(null, objects);
- break;
- }
-
- throw ServiceResultException.Create(
- StatusCodes.BadEncodingError,
- "Unexpected type encountered while encoding a Matrix: {0}",
- valueToEncode.GetType());
- }
-
- default:
- {
- throw ServiceResultException.Create(
- StatusCodes.BadEncodingError,
- "Unexpected type encountered while encoding a Variant: {0}",
- value.TypeInfo.BuiltInType);
- }
- }
-
- // write the dimensions.
- if (value.TypeInfo.ValueRank > 1)
- {
- WriteInt32Array(null, (int[])matrix.Dimensions);
- }
- }
+ m_nestingLevel--;
}
///
@@ -1158,6 +1038,15 @@ namespace Opc.Ua
///
public void WriteEncodeable(string fieldName, IEncodeable value, System.Type systemType)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
// create a default object if a null object specified.
if (value == null)
{
@@ -1165,11 +1054,15 @@ namespace Opc.Ua
value = Activator.CreateInstance(systemType) as IEncodeable;
}
+ m_nestingLevel++;
+
// encode the object.
if (value != null)
{
value.Encode(this);
}
+
+ m_nestingLevel--;
}
///
@@ -1866,6 +1759,163 @@ namespace Opc.Ua
}
}
}
+
+ ///
+ /// Writes an Variant to the stream.
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
+ private void WriteVariantValue(string fieldName, Variant value)
+ {
+ // check for null.
+ if (value.Value == null || value.TypeInfo == null || value.TypeInfo.BuiltInType == BuiltInType.Null)
+ {
+ WriteByte(null, 0);
+ return;
+ }
+
+ // encode enums as int32.
+ byte encodingByte = (byte)value.TypeInfo.BuiltInType;
+
+ if (value.TypeInfo.BuiltInType == BuiltInType.Enumeration)
+ {
+ encodingByte = (byte)BuiltInType.Int32;
+ }
+
+ object valueToEncode = value.Value;
+
+ if (value.TypeInfo.ValueRank < 0)
+ {
+ WriteByte(null, encodingByte);
+
+ switch (value.TypeInfo.BuiltInType)
+ {
+ case BuiltInType.Boolean: { WriteBoolean(null, (bool)valueToEncode); return; }
+ case BuiltInType.SByte: { WriteSByte(null, (sbyte)valueToEncode); return; }
+ case BuiltInType.Byte: { WriteByte(null, (byte)valueToEncode); return; }
+ case BuiltInType.Int16: { WriteInt16(null, (short)valueToEncode); return; }
+ case BuiltInType.UInt16: { WriteUInt16(null, (ushort)valueToEncode); return; }
+ case BuiltInType.Int32: { WriteInt32(null, (int)valueToEncode); return; }
+ case BuiltInType.UInt32: { WriteUInt32(null, (uint)valueToEncode); return; }
+ case BuiltInType.Int64: { WriteInt64(null, (long)valueToEncode); return; }
+ case BuiltInType.UInt64: { WriteUInt64(null, (ulong)valueToEncode); return; }
+ case BuiltInType.Float: { WriteFloat(null, (float)valueToEncode); return; }
+ case BuiltInType.Double: { WriteDouble(null, (double)valueToEncode); return; }
+ case BuiltInType.String: { WriteString(null, (string)valueToEncode); return; }
+ case BuiltInType.DateTime: { WriteDateTime(null, (DateTime)valueToEncode); return; }
+ case BuiltInType.Guid: { WriteGuid(null, (Uuid)valueToEncode); return; }
+ case BuiltInType.ByteString: { WriteByteString(null, (byte[])valueToEncode); return; }
+ case BuiltInType.XmlElement: { WriteXmlElement(null, (XmlElement)valueToEncode); return; }
+ case BuiltInType.NodeId: { WriteNodeId(null, (NodeId)valueToEncode); return; }
+ case BuiltInType.ExpandedNodeId: { WriteExpandedNodeId(null, (ExpandedNodeId)valueToEncode); return; }
+ case BuiltInType.StatusCode: { WriteStatusCode(null, (StatusCode)valueToEncode); return; }
+ case BuiltInType.QualifiedName: { WriteQualifiedName(null, (QualifiedName)valueToEncode); return; }
+ case BuiltInType.LocalizedText: { WriteLocalizedText(null, (LocalizedText)valueToEncode); return; }
+ case BuiltInType.ExtensionObject: { WriteExtensionObject(null, (ExtensionObject)valueToEncode); return; }
+ case BuiltInType.DataValue: { WriteDataValue(null, (DataValue)valueToEncode); return; }
+ case BuiltInType.Enumeration: { WriteInt32(null, (int)valueToEncode); return; }
+ }
+
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingError,
+ "Unexpected type encountered while encoding a Variant: {0}",
+ value.TypeInfo.BuiltInType);
+ }
+
+ if (value.TypeInfo.ValueRank >= 0)
+ {
+ Matrix matrix = null;
+
+ encodingByte |= (byte)VariantArrayEncodingBits.Array;
+
+ if (value.TypeInfo.ValueRank > 1)
+ {
+ encodingByte |= (byte)VariantArrayEncodingBits.ArrayDimensions;
+ matrix = (Matrix)valueToEncode;
+ valueToEncode = matrix.Elements;
+ }
+
+ WriteByte(null, encodingByte);
+
+ switch (value.TypeInfo.BuiltInType)
+ {
+ case BuiltInType.Boolean: { WriteBooleanArray(null, (bool[])valueToEncode); break; }
+ case BuiltInType.SByte: { WriteSByteArray(null, (sbyte[])valueToEncode); break; }
+ case BuiltInType.Byte: { WriteByteArray(null, (byte[])valueToEncode); break; }
+ case BuiltInType.Int16: { WriteInt16Array(null, (short[])valueToEncode); break; }
+ case BuiltInType.UInt16: { WriteUInt16Array(null, (ushort[])valueToEncode); break; }
+ case BuiltInType.Int32: { WriteInt32Array(null, (int[])valueToEncode); break; }
+ case BuiltInType.UInt32: { WriteUInt32Array(null, (uint[])valueToEncode); break; }
+ case BuiltInType.Int64: { WriteInt64Array(null, (long[])valueToEncode); break; }
+ case BuiltInType.UInt64: { WriteUInt64Array(null, (ulong[])valueToEncode); break; }
+ case BuiltInType.Float: { WriteFloatArray(null, (float[])valueToEncode); break; }
+ case BuiltInType.Double: { WriteDoubleArray(null, (double[])valueToEncode); break; }
+ case BuiltInType.String: { WriteStringArray(null, (string[])valueToEncode); break; }
+ case BuiltInType.DateTime: { WriteDateTimeArray(null, (DateTime[])valueToEncode); break; }
+ case BuiltInType.Guid: { WriteGuidArray(null, (Uuid[])valueToEncode); break; }
+ case BuiltInType.ByteString: { WriteByteStringArray(null, (byte[][])valueToEncode); break; }
+ case BuiltInType.XmlElement: { WriteXmlElementArray(null, (XmlElement[])valueToEncode); break; }
+ case BuiltInType.NodeId: { WriteNodeIdArray(null, (NodeId[])valueToEncode); break; }
+ case BuiltInType.ExpandedNodeId: { WriteExpandedNodeIdArray(null, (ExpandedNodeId[])valueToEncode); break; }
+ case BuiltInType.StatusCode: { WriteStatusCodeArray(null, (StatusCode[])valueToEncode); break; }
+ case BuiltInType.QualifiedName: { WriteQualifiedNameArray(null, (QualifiedName[])valueToEncode); break; }
+ case BuiltInType.LocalizedText: { WriteLocalizedTextArray(null, (LocalizedText[])valueToEncode); break; }
+ case BuiltInType.ExtensionObject: { WriteExtensionObjectArray(null, (ExtensionObject[])valueToEncode); break; }
+ case BuiltInType.DataValue: { WriteDataValueArray(null, (DataValue[])valueToEncode); break; }
+
+ case BuiltInType.Enumeration:
+ {
+ Enum[] enums = valueToEncode as Enum[];
+ int[] ints = new int[enums.Length];
+
+ for (int ii = 0; ii < enums.Length; ii++)
+ {
+ ints[ii] = (int)(object)enums[ii];
+ }
+
+ WriteInt32Array(null, ints);
+ return;
+ }
+
+ case BuiltInType.Variant:
+ {
+ Variant[] variants = valueToEncode as Variant[];
+
+ if (variants != null)
+ {
+ WriteVariantArray(null, variants);
+ break;
+ }
+
+ object[] objects = valueToEncode as object[];
+
+ if (objects != null)
+ {
+ WriteObjectArray(null, objects);
+ break;
+ }
+
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingError,
+ "Unexpected type encountered while encoding a Matrix: {0}",
+ valueToEncode.GetType());
+ }
+
+ default:
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingError,
+ "Unexpected type encountered while encoding a Variant: {0}",
+ value.TypeInfo.BuiltInType);
+ }
+ }
+
+ // write the dimensions.
+ if (value.TypeInfo.ValueRank > 1)
+ {
+ WriteInt32Array(null, (int[])matrix.Dimensions);
+ }
+ }
+ }
#endregion
#region Private Fields
@@ -1874,6 +1924,7 @@ namespace Opc.Ua
private ServiceMessageContext m_context;
private ushort[] m_namespaceMappings;
private ushort[] m_serverMappings;
+ private uint m_nestingLevel;
#endregion
}
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/JsonDecoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/JsonDecoder.cs
index 8d13db559c..9e6959bbfa 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/JsonDecoder.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/JsonDecoder.cs
@@ -32,6 +32,7 @@ namespace Opc.Ua
private ServiceMessageContext m_context;
private ushort[] m_namespaceMappings;
private ushort[] m_serverMappings;
+ private uint m_nestingLevel;
#endregion
#region Constructors
@@ -40,8 +41,8 @@ namespace Opc.Ua
if (context == null) throw new ArgumentNullException("context");
Initialize();
-
m_context = context;
+ m_nestingLevel = 0;
m_reader = new JsonTextReader(new StringReader(json));
m_root = ReadObject();
m_stack = new Stack
public void WriteDiagnosticInfo(string fieldName, DiagnosticInfo value)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
if (value == null)
{
WriteSimpleField(fieldName, null, false);
@@ -773,6 +786,8 @@ namespace Opc.Ua
}
PopStructure();
+
+ m_nestingLevel--;
}
///
@@ -837,10 +852,21 @@ namespace Opc.Ua
}
///
- /// Writes an Variant array to the stream.
+ /// Writes an Variant to the stream.
///
public void WriteVariant(string fieldName, Variant value)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
if (Variant.Null == value)
{
WriteSimpleField(fieldName, null, false);
@@ -881,6 +907,8 @@ namespace Opc.Ua
PopStructure();
}
+
+ m_nestingLevel--;
}
///
@@ -987,6 +1015,17 @@ namespace Opc.Ua
///
public void WriteEncodeable(string fieldName, IEncodeable value, System.Type systemType)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
if (value == null)
{
WriteSimpleField(fieldName, null, false);
@@ -1001,6 +1040,8 @@ namespace Opc.Ua
}
PopStructure();
+
+ m_nestingLevel--;
}
///
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs
index 8ffd0b10cc..2e02d76caf 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/XmlDecoder.cs
@@ -33,8 +33,9 @@ namespace Opc.Ua
if (context == null) throw new ArgumentNullException("context");
Initialize();
m_context = context;
- }
-
+ m_nestingLevel = 0;
+ }
+
///
/// Initializes the object with an XML element to parse.
///
@@ -44,6 +45,7 @@ namespace Opc.Ua
Initialize();
m_reader = XmlReader.Create(new StringReader(element.OuterXml));
m_context = context;
+ m_nestingLevel = 0;
}
///
@@ -55,6 +57,7 @@ namespace Opc.Ua
m_reader = reader;
m_context = context;
+ m_nestingLevel = 0;
string ns = null;
string name = null;
@@ -82,11 +85,11 @@ namespace Opc.Ua
PushNamespace(ns);
BeginField(name, false);
- }
-
- ///
- /// Sets private members to default values.
- ///
+ }
+
+ ///
+ /// Sets private members to default values.
+ ///
private void Initialize()
{
m_reader = null;
@@ -1190,6 +1193,17 @@ namespace Opc.Ua
///
public DiagnosticInfo ReadDiagnosticInfo()
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
DiagnosticInfo value = new DiagnosticInfo();
if (BeginField("SymbolicId", true))
@@ -1225,6 +1239,8 @@ namespace Opc.Ua
EndField("InnerDiagnosticInfo");
}
+ m_nestingLevel--;
+
return value;
}
@@ -1321,6 +1337,17 @@ namespace Opc.Ua
///
public Variant ReadVariant(string fieldName)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
Variant value = new Variant();
if (BeginField(fieldName, true))
@@ -1348,6 +1375,8 @@ namespace Opc.Ua
EndField(fieldName);
}
+ m_nestingLevel--;
+
return value;
}
@@ -1443,6 +1472,17 @@ namespace Opc.Ua
Utils.Format("Type does not support IEncodeable interface: '{0}'", systemType.FullName));
}
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
if (BeginField(fieldName, true))
{
XmlQualifiedName xmlName = EncodeableFactory.GetXmlName(systemType);
@@ -1466,10 +1506,12 @@ namespace Opc.Ua
m_reader.Skip();
m_reader.MoveToContent();
}
-
+
EndField(fieldName);
}
-
+
+ m_nestingLevel--;
+
return value;
}
@@ -2742,6 +2784,7 @@ namespace Opc.Ua
private ServiceMessageContext m_context;
private ushort[] m_namespaceMappings;
private ushort[] m_serverMappings;
+ private uint m_nestingLevel;
#endregion
}
}
diff --git a/Stack/Opc.Ua.Core/Types/Encoders/XmlEncoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/XmlEncoder.cs
index 3eba96c803..1a213910d8 100644
--- a/Stack/Opc.Ua.Core/Types/Encoders/XmlEncoder.cs
+++ b/Stack/Opc.Ua.Core/Types/Encoders/XmlEncoder.cs
@@ -35,6 +35,7 @@ namespace Opc.Ua
m_destination = new StringBuilder();
m_context = context;
+ m_nestingLevel = 0;
XmlWriterSettings settings = new XmlWriterSettings();
settings.CheckCharacters = false;
@@ -72,6 +73,7 @@ namespace Opc.Ua
Initialize(root.Name, root.Namespace);
m_context = context;
+ m_nestingLevel = 0;
}
///
@@ -612,10 +614,21 @@ namespace Opc.Ua
///
public void WriteDiagnosticInfo(string fieldName, DiagnosticInfo value)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
if (BeginField(fieldName, value == null, true))
{
PushNamespace(Namespaces.OpcUaXsd);
-
+
if (value != null)
{
WriteInt32("SymbolicId", value.SymbolicId);
@@ -628,9 +641,11 @@ namespace Opc.Ua
}
PopNamespace();
-
+
EndField(fieldName);
}
+
+ m_nestingLevel--;
}
///
@@ -687,18 +702,31 @@ namespace Opc.Ua
///
public void WriteVariant(string fieldName, Variant value)
{
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
if (BeginField(fieldName, false, false))
{
PushNamespace(Namespaces.OpcUaXsd);
-
- m_writer.WriteStartElement("Value", Namespaces.OpcUaXsd);
- WriteVariantContents(value.Value, value.TypeInfo);
+
+ m_writer.WriteStartElement("Value", Namespaces.OpcUaXsd);
+ WriteVariantContents(value.Value, value.TypeInfo);
m_writer.WriteEndElement();
-
+
PopNamespace();
-
+
EndField(fieldName);
}
+
+ m_nestingLevel--;
}
///
@@ -804,7 +832,18 @@ namespace Opc.Ua
/// Writes an encodeable object to the stream.
///
public void WriteEncodeable(string fieldName, IEncodeable value, System.Type systemType)
- {
+ {
+ // check the nesting level for avoiding a stack overflow.
+ if (m_nestingLevel > m_context.MaxEncodingNestingLevels)
+ {
+ throw ServiceResultException.Create(
+ StatusCodes.BadEncodingLimitsExceeded,
+ "Maximum nesting level of {0} was exceeded",
+ m_context.MaxEncodingNestingLevels);
+ }
+
+ m_nestingLevel++;
+
if (BeginField(fieldName, value == null, true))
{
if (value != null)
@@ -814,7 +853,9 @@ namespace Opc.Ua
EndField(fieldName);
}
- }
+
+ m_nestingLevel--;
+ }
///
/// Writes an enumerated value array to the stream.
@@ -1959,6 +2000,7 @@ namespace Opc.Ua
private ServiceMessageContext m_context;
private ushort[] m_namespaceMappings;
private ushort[] m_serverMappings;
+ private uint m_nestingLevel;
#endregion
}
}
diff --git a/Stack/Opc.Ua.Core/Types/Utils/ServiceMessageContext.cs b/Stack/Opc.Ua.Core/Types/Utils/ServiceMessageContext.cs
index 23a6949dcb..0cd0a9a16a 100644
--- a/Stack/Opc.Ua.Core/Types/Utils/ServiceMessageContext.cs
+++ b/Stack/Opc.Ua.Core/Types/Utils/ServiceMessageContext.cs
@@ -31,24 +31,26 @@ namespace Opc.Ua
///
public ServiceMessageContext()
{
- m_maxStringLength = UInt16.MaxValue;
- m_maxByteStringLength = UInt16.MaxValue*16;
- m_maxArrayLength = UInt16.MaxValue;
- m_maxMessageSize = UInt16.MaxValue*32;
- m_namespaceUris = new NamespaceTable();
- m_serverUris = new StringTable();
- m_factory = EncodeableFactory.GlobalFactory;
+ m_maxStringLength = UInt16.MaxValue;
+ m_maxByteStringLength = UInt16.MaxValue*16;
+ m_maxArrayLength = UInt16.MaxValue;
+ m_maxMessageSize = UInt16.MaxValue*32;
+ m_namespaceUris = new NamespaceTable();
+ m_serverUris = new StringTable();
+ m_factory = EncodeableFactory.GlobalFactory;
+ m_maxEncodingNestingLevels = 200;
}
private ServiceMessageContext(bool shared) : this()
{
- m_maxStringLength = UInt16.MaxValue;
- m_maxByteStringLength = UInt16.MaxValue*16;
- m_maxArrayLength = UInt16.MaxValue;
- m_maxMessageSize = UInt16.MaxValue*32;
- m_namespaceUris = new NamespaceTable(shared);
- m_serverUris = new StringTable(shared);
- m_factory = EncodeableFactory.GlobalFactory;
+ m_maxStringLength = UInt16.MaxValue;
+ m_maxByteStringLength = UInt16.MaxValue*16;
+ m_maxArrayLength = UInt16.MaxValue;
+ m_maxMessageSize = UInt16.MaxValue*32;
+ m_namespaceUris = new NamespaceTable(shared);
+ m_serverUris = new StringTable(shared);
+ m_factory = EncodeableFactory.GlobalFactory;
+ m_maxEncodingNestingLevels = 200;
}
#endregion
@@ -123,6 +125,14 @@ namespace Opc.Ua
set { lock (m_lock) { m_maxMessageSize = value; } }
}
+ ///
+ /// The maximum nesting level accepted while encoding or decoding objects.
+ ///
+ public uint MaxEncodingNestingLevels
+ {
+ get { lock (m_lock) { return m_maxEncodingNestingLevels; } }
+ }
+
///
/// The table of namespaces used by the server.
///
@@ -205,6 +215,7 @@ namespace Opc.Ua
private int m_maxByteStringLength;
private int m_maxArrayLength;
private int m_maxMessageSize;
+ private uint m_maxEncodingNestingLevels;
private NamespaceTable m_namespaceUris;
private StringTable m_serverUris;
private EncodeableFactory m_factory;