diff --git a/src/S7CommPlusDriver/ClientApi/PlcTag.cs b/src/S7CommPlusDriver/ClientApi/PlcTag.cs
index 7cdef54..c40b5c0 100644
--- a/src/S7CommPlusDriver/ClientApi/PlcTag.cs
+++ b/src/S7CommPlusDriver/ClientApi/PlcTag.cs
@@ -64,6 +64,26 @@ public virtual void ProcessWriteResult(UInt64 error)
internal abstract PValue GetWriteValue();
+ ///
+ /// Gets the tag's current typed value as a boxed via its public Value property.
+ ///
+ /// The boxed value, or when the concrete tag type has no public Value property.
+ public virtual object GetValue()
+ {
+ var valueProperty = GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance);
+ return valueProperty?.GetValue(this);
+ }
+
+ ///
+ /// Sets the tag's current typed value from a boxed via its public Value property.
+ ///
+ /// The value to assign, which must be assignable to the concrete tag's Value property type.
+ public virtual void SetValue(object value)
+ {
+ var valueProperty = GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance);
+ valueProperty?.SetValue(this, value);
+ }
+
internal void SetTraceAddressMetadata(VarInfo variable)
{
if (variable == null)
diff --git a/src/S7CommPlusDriver/Core/POffsetInfoType.cs b/src/S7CommPlusDriver/Core/POffsetInfoType.cs
index 1972a65..c7b3251 100644
--- a/src/S7CommPlusDriver/Core/POffsetInfoType.cs
+++ b/src/S7CommPlusDriver/Core/POffsetInfoType.cs
@@ -69,6 +69,12 @@ public enum OffsetInfoType
public abstract bool Is1Dim();
public abstract bool IsMDim();
+ ///
+ /// Gets the maximum string length for a String/WString offset info, or 0 when not applicable.
+ ///
+ /// The maximum length in characters, or 0 for non-string offset info types.
+ public virtual int MaxStringLength() { return 0; }
+
public static POffsetInfoType Deserialize(Stream buffer, int offsetinfotype, out int length)
{
switch ((OffsetInfoType)offsetinfotype)
@@ -455,6 +461,8 @@ public class POffsetInfoType_ArrayMDim : POffsetInfoType, IOffsetInfoType_MDim
public override bool HasRelation() { return false; }
public override bool Is1Dim() { return false; }
public override bool IsMDim() { return true; }
+ // For a string array, UnspecifiedOffsetinfo1 carries the maximum string length of the array elements.
+ public override int MaxStringLength() { return UnspecifiedOffsetinfo1; }
public static POffsetInfoType_ArrayMDim Deserialize(Stream buffer, out int length)
{
@@ -542,6 +550,8 @@ public class POffsetInfoType_Array1Dim : POffsetInfoType, IOffsetInfoType_1Dim
public override bool HasRelation() { return false; }
public override bool Is1Dim() { return true; }
public override bool IsMDim() { return false; }
+ // For a string array, UnspecifiedOffsetinfo1 carries the maximum string length of the array elements.
+ public override int MaxStringLength() { return UnspecifiedOffsetinfo1; }
public static POffsetInfoType_Array1Dim Deserialize(Stream buffer, out int length)
{
@@ -599,6 +609,8 @@ public class POffsetInfoType_String: POffsetInfoType
public override bool HasRelation() { return false; }
public override bool Is1Dim() { return false; }
public override bool IsMDim() { return false; }
+ // Some firmware versions swap UnspecifiedOffsetinfo1/2, so take the smaller value as the max. string length.
+ public override int MaxStringLength() { return Math.Min(UnspecifiedOffsetinfo1, UnspecifiedOffsetinfo2); }
public static POffsetInfoType_String Deserialize(Stream buffer, out int length)
{
diff --git a/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs b/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs
index da21d9a..5f513a4 100644
--- a/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs
+++ b/src/S7CommPlusDriver/OpenSSL/OpenSSLConnector.cs
@@ -33,6 +33,8 @@ public class OpenSSLConnector : IDisposable
private readonly byte[] m_buffer = new byte[4096];
private readonly DataBufferList m_pendingWriteList;
private readonly DataBufferList m_pendingReadList;
+ private readonly object m_readListLock = new object();
+ private readonly object m_writeListLock = new object();
private bool m_fatalError;
private bool m_disposed;
@@ -277,8 +279,16 @@ protected void RunSSL()
while (!m_fatalError && ((!m_readRequired && dataToWrite) || dataToRead))
{
- int pendingReadBefore = m_pendingReadList.Count;
- int pendingWriteBefore = m_pendingWriteList.Count;
+ int pendingReadBefore;
+ int pendingWriteBefore;
+ lock (m_readListLock)
+ {
+ pendingReadBefore = m_pendingReadList.Count;
+ }
+ lock (m_writeListLock)
+ {
+ pendingWriteBefore = m_pendingWriteList.Count;
+ }
bool readRequiredBefore = m_readRequired;
var bioPendingBefore = Native.BIO_ctrl_pending(m_pBioOut);
@@ -304,8 +314,18 @@ protected void RunSSL()
GetPendingOperations(ref dataToRead, ref dataToWrite);
var bioPendingAfter = Native.BIO_ctrl_pending(m_pBioOut);
- if (pendingReadBefore == m_pendingReadList.Count &&
- pendingWriteBefore == m_pendingWriteList.Count &&
+ int pendingReadAfter;
+ int pendingWriteAfter;
+ lock (m_readListLock)
+ {
+ pendingReadAfter = m_pendingReadList.Count;
+ }
+ lock (m_writeListLock)
+ {
+ pendingWriteAfter = m_pendingWriteList.Count;
+ }
+ if (pendingReadBefore == pendingReadAfter &&
+ pendingWriteBefore == pendingWriteAfter &&
readRequiredBefore == m_readRequired &&
bioPendingBefore == bioPendingAfter)
{
@@ -341,8 +361,14 @@ public void ReadCompleted(byte[] pData, int dataLen)
private void GetPendingOperations(ref bool dataToRead, ref bool dataToWrite)
{
- dataToRead = m_pendingReadList.Count > 0;
- dataToWrite = m_pendingWriteList.Count > 0;
+ lock (m_readListLock)
+ {
+ dataToRead = m_pendingReadList.Count > 0;
+ }
+ lock (m_writeListLock)
+ {
+ dataToWrite = m_pendingWriteList.Count > 0;
+ }
}
private void PerformRead()
@@ -437,23 +463,35 @@ private void UseData(DataBufferList list, DataBuffer pBuffer, int result)
private void AppendBuffer(DataBufferList list, DataBuffer pBuffer)
{
- list.AddLast(pBuffer);
+ object lockObject = (list == m_pendingReadList) ? m_readListLock : m_writeListLock;
+ lock (lockObject)
+ {
+ list.AddLast(pBuffer);
+ }
}
DataBuffer GetNextBuffer(DataBufferList list)
{
DataBuffer head = null;
- if (list.Count > 0)
+ object lockObject = (list == m_pendingReadList) ? m_readListLock : m_writeListLock;
+ lock (lockObject)
{
- head = list.First.Value;
- list.RemoveFirst();
+ if (list.Count > 0)
+ {
+ head = list.First.Value;
+ list.RemoveFirst();
+ }
}
return head;
}
void PutbackBuffer(DataBufferList list, DataBuffer pBuffer)
{
- list.AddFirst(pBuffer);
+ object lockObject = (list == m_pendingReadList) ? m_readListLock : m_writeListLock;
+ lock (lockObject)
+ {
+ list.AddFirst(pBuffer);
+ }
}
///