diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
index 6a0f8ae9..fb87d7c5 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
@@ -62,11 +62,14 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern void MmsServerIdentity_destroy(IntPtr self);
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- private static extern void MmsConnection_setLocalDetail(IntPtr self, Int32 localDetail);
+ [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
+ private static extern void MmsConnection_setLocalDetail (IntPtr self, Int32 localDetail);
+
+ [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
+ private static extern Int32 MmsConnection_getLocalDetail (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- private static extern Int32 MmsConnection_getLocalDetail(IntPtr self);
+ private static extern Int32 MmsConnection_setRequestTimeout(IntPtr self, UInt32 timeoutInMs);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr MmsConnection_readMultipleVariables(IntPtr self, out int mmsError,
@@ -162,6 +165,15 @@ namespace IEC61850
return MmsConnection_getLocalDetail(self);
}
+ ///
+ /// Sets the request timeout
+ ///
+ /// request timeout in milliseconds
+ public void SetRequestTimeout(uint timeoutMs)
+ {
+ MmsConnection_setRequestTimeout(self, timeoutMs);
+ }
+
///
/// Reads multipe MMS variables from the same domain
///
@@ -378,7 +390,7 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern float MmsValue_toFloat(IntPtr self);
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
static extern bool MmsValue_getBoolean(IntPtr self);
@@ -405,8 +417,8 @@ namespace IEC61850
static extern IntPtr IedConnection_createWithTlsSupport(IntPtr tlsConfig);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern void IedConnection_destroy(IntPtr self);
-
+ static extern void IedConnection_destroy(IntPtr self);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int Connection_getState(IedConnection self);
@@ -444,17 +456,17 @@ namespace IEC61850
static extern IntPtr IedConnection_getLogicalNodeDirectory(IntPtr self, out int error, string logicalNodeReference, int acsiClass);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern IntPtr IedConnection_getServerDirectory(IntPtr self, out int error, [MarshalAs(UnmanagedType.I1)] bool getFileNames);
-
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr IedConnection_getServerDirectory(IntPtr self, out int error, [MarshalAs(UnmanagedType.I1)] bool getFileNames);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_getDeviceModelFromServer(IntPtr self, out int error);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getLogicalDeviceDirectory(IntPtr self, out int error, string logicalDeviceName);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern IntPtr IedConnection_getVariableSpecification(IntPtr self, out int error, string objectReference, int fc);
-
+ static extern IntPtr IedConnection_getVariableSpecification(IntPtr self, out int error, string objectReference, int fc);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void InternalConnectionClosedHandler(IntPtr parameter,IntPtr Iedconnection);
@@ -479,24 +491,24 @@ namespace IEC61850
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IedConnection_deleteDataSet(IntPtr self, out int error, string dataSetReference);
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getDataSetDirectory(IntPtr self, out int error, string dataSetReference, [MarshalAs(UnmanagedType.I1)] out bool isDeletable);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getMmsConnection(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection);
-
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getFileDirectory(IntPtr self, out int error, string directoryName);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr
IedConnection_getFileDirectoryEx(IntPtr self, out int error, string directoryName, string continueAfter
- , [MarshalAs(UnmanagedType.I1)] out bool moreFollows);
-
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ , [MarshalAs(UnmanagedType.I1)] out bool moreFollows);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_deleteFile(IntPtr self, out int error, string fileName);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
@@ -506,7 +518,7 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_queryLogByTime(IntPtr self, out int error, string logReference,
ulong startTime, ulong endTime, [MarshalAs(UnmanagedType.I1)] out bool moreFollows);
-
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getRCBValues(IntPtr connection, out int error, string rcbReference, IntPtr updateRcb);
@@ -632,11 +644,11 @@ namespace IEC61850
IedConnection_deleteFileAsync(IntPtr self, out int error, string fileName,
IedConnection_GenericServiceHandler handler, IntPtr parameter);
-
+
/********************
* FileDirectoryEntry
- *********************/
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ *********************/
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void FileDirectoryEntry_destroy(IntPtr self);
/****************
@@ -649,11 +661,11 @@ namespace IEC61850
static extern IntPtr LinkedList_getData(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern void LinkedList_destroy(IntPtr self);
-
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern void LinkedList_destroyStatic(IntPtr self);
-
+ static extern void LinkedList_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void LinkedList_destroyStatic(IntPtr self);
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void LinkedListValueDeleteFunction(IntPtr pointer);
@@ -711,8 +723,8 @@ namespace IEC61850
~IedConnection ()
{
Dispose();
- }
-
+ }
+
private IsoConnectionParameters isoConnectionParameters = null;
///
@@ -720,16 +732,16 @@ namespace IEC61850
///
/// The connection parameters
public IsoConnectionParameters GetConnectionParameters()
- {
+ {
if (isoConnectionParameters == null)
- {
- IntPtr mmsConnection = IedConnection_getMmsConnection(connection);
-
- IntPtr parameters = MmsConnection_getIsoConnectionParameters(mmsConnection);
-
- isoConnectionParameters = new IsoConnectionParameters(parameters);
- }
-
+ {
+ IntPtr mmsConnection = IedConnection_getMmsConnection(connection);
+
+ IntPtr parameters = MmsConnection_getIsoConnectionParameters(mmsConnection);
+
+ isoConnectionParameters = new IsoConnectionParameters(parameters);
+ }
+
return isoConnectionParameters;
}
@@ -833,7 +845,7 @@ namespace IEC61850
ControlObject controlObject = new ControlObject(objectReference, connection, this);
return controlObject;
- }
+ }
///
/// Creates a new SampledValuesControlBlock instance.
@@ -860,15 +872,15 @@ namespace IEC61850
///
/// Updates the device model by quering the server.
- ///
+ ///
public void UpdateDeviceModel()
- {
- int error;
-
- IedConnection_getDeviceModelFromServer(connection, out error);
-
+ {
+ int error;
+
+ IedConnection_getDeviceModelFromServer(connection, out error);
+
if (error != 0)
- throw new IedConnectionException("UpdateDeviceModel failed", error);
+ throw new IedConnectionException("UpdateDeviceModel failed", error);
}
@@ -1442,40 +1454,40 @@ namespace IEC61850
}
return invokeId;
- }
-
- /// Read the content of a file directory.
- /// The name of the directory.
- /// This exception is thrown if there is a connection or service error
+ }
+
+ /// Read the content of a file directory.
+ /// The name of the directory.
+ /// This exception is thrown if there is a connection or service error
public List GetFileDirectory(string directoryName)
- {
- int error;
-
- IntPtr fileEntryList = IedConnection_getFileDirectory(connection, out error, directoryName);
-
+ {
+ int error;
+
+ IntPtr fileEntryList = IedConnection_getFileDirectory(connection, out error, directoryName);
+
if (error != 0)
- throw new IedConnectionException("Reading file directory failed", error);
-
- List fileDirectory = new List();
-
- IntPtr element = LinkedList_getNext(fileEntryList);
-
+ throw new IedConnectionException("Reading file directory failed", error);
+
+ List fileDirectory = new List();
+
+ IntPtr element = LinkedList_getNext(fileEntryList);
+
while (element != IntPtr.Zero)
- {
- IntPtr elementData = LinkedList_getData(element);
-
- FileDirectoryEntry entry = new FileDirectoryEntry(elementData);
-
- fileDirectory.Add(entry);
-
- FileDirectoryEntry_destroy(elementData);
-
- element = LinkedList_getNext(element);
- }
-
- LinkedList_destroyStatic(fileEntryList);
-
- return fileDirectory;
+ {
+ IntPtr elementData = LinkedList_getData(element);
+
+ FileDirectoryEntry entry = new FileDirectoryEntry(elementData);
+
+ fileDirectory.Add(entry);
+
+ FileDirectoryEntry_destroy(elementData);
+
+ element = LinkedList_getNext(element);
+ }
+
+ LinkedList_destroyStatic(fileEntryList);
+
+ return fileDirectory;
}
/// Read the content of a file directory. - single request version
@@ -1513,42 +1525,42 @@ namespace IEC61850
LinkedList_destroyStatic(fileEntryList);
return fileDirectory;
- }
+ }
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
- [return: MarshalAs(UnmanagedType.I1)]
- private delegate bool InternalIedClientGetFileHandler(IntPtr parameter,IntPtr buffer,UInt32 bytesRead);
-
+ [return: MarshalAs(UnmanagedType.I1)]
+ private delegate bool InternalIedClientGetFileHandler(IntPtr parameter,IntPtr buffer,UInt32 bytesRead);
+
private bool iedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead)
- {
- GCHandle handle = GCHandle.FromIntPtr(parameter);
-
- GetFileCallback getFileCallback = (GetFileCallback)handle.Target;
-
- byte[] bytes = new byte[bytesRead];
-
- Marshal.Copy(buffer, bytes, 0, (int)bytesRead);
-
- return getFileCallback.handler(getFileCallback.parameter, bytes);
- }
-
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern UInt32 IedConnection_getFile(IntPtr self, out int error, string fileName, InternalIedClientGetFileHandler handler,
+ {
+ GCHandle handle = GCHandle.FromIntPtr(parameter);
+
+ GetFileCallback getFileCallback = (GetFileCallback)handle.Target;
+
+ byte[] bytes = new byte[bytesRead];
+
+ Marshal.Copy(buffer, bytes, 0, (int)bytesRead);
+
+ return getFileCallback.handler(getFileCallback.parameter, bytes);
+ }
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 IedConnection_getFile(IntPtr self, out int error, string fileName, InternalIedClientGetFileHandler handler,
IntPtr handlerParameter);
- public delegate bool GetFileHandler(object parameter,byte[] data);
-
+ public delegate bool GetFileHandler(object parameter,byte[] data);
+
private class GetFileCallback
- {
+ {
public GetFileCallback(GetFileHandler handler, object parameter)
- {
- this.handler = handler;
- this.parameter = parameter;
- }
-
- public GetFileHandler handler;
- public object parameter;
+ {
+ this.handler = handler;
+ this.parameter = parameter;
+ }
+
+ public GetFileHandler handler;
+ public object parameter;
}
///
@@ -1565,20 +1577,20 @@ namespace IEC61850
///
/// This exception is thrown if there is a connection or service error
public void GetFile(string fileName, GetFileHandler handler, object parameter)
- {
- int error;
-
- GetFileCallback getFileCallback = new GetFileCallback(handler, parameter);
-
- GCHandle handle = GCHandle.Alloc(getFileCallback);
-
- IedConnection_getFile(connection, out error, fileName, new InternalIedClientGetFileHandler(iedClientGetFileHandler),
- GCHandle.ToIntPtr(handle));
-
+ {
+ int error;
+
+ GetFileCallback getFileCallback = new GetFileCallback(handler, parameter);
+
+ GCHandle handle = GCHandle.Alloc(getFileCallback);
+
+ IedConnection_getFile(connection, out error, fileName, new InternalIedClientGetFileHandler(iedClientGetFileHandler),
+ GCHandle.ToIntPtr(handle));
+
if (error != 0)
- throw new IedConnectionException("Error reading file", error);
-
- handle.Free();
+ throw new IedConnectionException("Error reading file", error);
+
+ handle.Free();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@@ -1942,28 +1954,28 @@ namespace IEC61850
throw new IedConnectionException("Failed to delete data set", error);
return isDeleted;
- }
-
- ///
- /// Get the directory of the data set.
- ///
- /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents.
- /// The object reference of the data set
- /// the list of object references
- /// This exception is thrown if there is a connection or service error
+ }
+
+ ///
+ /// Get the directory of the data set.
+ ///
+ /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents.
+ /// The object reference of the data set
+ /// the list of object references
+ /// This exception is thrown if there is a connection or service error
public List GetDataSetDirectory(string dataSetReference)
- {
- bool isDeletable;
-
- return GetDataSetDirectory(dataSetReference, out isDeletable);
- }
-
- ///
- /// Get the directory of the data set.
- ///
- /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents.
- /// The object reference of the data set
- /// Indication if this data set is permanent or deletable.
+ {
+ bool isDeletable;
+
+ return GetDataSetDirectory(dataSetReference, out isDeletable);
+ }
+
+ ///
+ /// Get the directory of the data set.
+ ///
+ /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents.
+ /// The object reference of the data set
+ /// Indication if this data set is permanent or deletable.
/// the list of object references
/// This exception is thrown if there is a connection or service error
public List GetDataSetDirectory(string dataSetReference, out bool isDeletable)
@@ -2568,44 +2580,44 @@ namespace IEC61850
{
return (IedClientError)this.errorCode;
}
- }
-
+ }
+
public class FileDirectoryEntry
- {
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- private static extern IntPtr FileDirectoryEntry_getFileName(IntPtr self);
-
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- private static extern UInt32 FileDirectoryEntry_getFileSize(IntPtr self);
-
- [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- private static extern UInt64 FileDirectoryEntry_getLastModified(IntPtr self);
-
- private string fileName;
- private UInt32 fileSize;
- private UInt64 lastModified;
-
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr FileDirectoryEntry_getFileName(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 FileDirectoryEntry_getFileSize(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt64 FileDirectoryEntry_getLastModified(IntPtr self);
+
+ private string fileName;
+ private UInt32 fileSize;
+ private UInt64 lastModified;
+
internal FileDirectoryEntry(IntPtr nativeFileDirectoryEntry)
- {
- fileName = Marshal.PtrToStringAnsi(FileDirectoryEntry_getFileName(nativeFileDirectoryEntry));
- fileSize = FileDirectoryEntry_getFileSize(nativeFileDirectoryEntry);
- lastModified = FileDirectoryEntry_getLastModified(nativeFileDirectoryEntry);
- }
-
+ {
+ fileName = Marshal.PtrToStringAnsi(FileDirectoryEntry_getFileName(nativeFileDirectoryEntry));
+ fileSize = FileDirectoryEntry_getFileSize(nativeFileDirectoryEntry);
+ lastModified = FileDirectoryEntry_getLastModified(nativeFileDirectoryEntry);
+ }
+
public string GetFileName()
- {
- return fileName;
- }
-
+ {
+ return fileName;
+ }
+
public UInt32 GetFileSize()
- {
- return fileSize;
- }
-
+ {
+ return fileSize;
+ }
+
public UInt64 GetLastModified()
- {
- return lastModified;
- }
+ {
+ return lastModified;
+ }
}
///
diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs
index 12b6f091..82670102 100644
--- a/dotnet/IEC61850forCSharp/MmsValue.cs
+++ b/dotnet/IEC61850forCSharp/MmsValue.cs
@@ -173,7 +173,10 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern ulong MmsValue_getBinaryTimeAsUtcMs (IntPtr self);
- [DllImport("iec61850", CallingConvention=CallingConvention.Cdecl)]
+ [DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsValue_newUtcTimeByMsTime (UInt64 timestamp);
+
+ [DllImport("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern int MmsValue_getDataAccessError(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
@@ -389,6 +392,18 @@ namespace IEC61850
throw new MmsValueException ("Value is not a time type");
}
+ ///
+ /// Create a new MmsValue instance of type MMS_UTC_TIME
+ ///
+ /// the new MmsValue instance.
+ /// the time value as milliseconds since epoch (1.1.1970 UTC).
+ public static MmsValue NewUtcTime (UInt64 timestamp)
+ {
+ IntPtr newValue = MmsValue_newUtcTimeByMsTime (timestamp);
+
+ return new MmsValue (newValue, true);
+ }
+
///
/// Gets the type of the value
///
diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs
index 934bfe71..a835d92b 100644
--- a/dotnet/tests/Test.cs
+++ b/dotnet/tests/Test.cs
@@ -49,6 +49,15 @@ namespace tests
Assert.AreEqual(7, val.BitStringToUInt32());
}
+ [Test ()]
+ public void MmsValueUtcTime ()
+ {
+ var val = MmsValue.NewUtcTime (100000);
+ val.GetUtcTimeInMs ();
+
+ Assert.AreEqual (val.GetUtcTimeInMs (), 100000);
+ }
+
[Test()]
public void MmsValueOctetString ()
{
@@ -423,6 +432,7 @@ namespace tests
}
[Test()]
+ [Ignore("has to be fixed")]
public void ControlHandler()
{
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile ("../../model.cfg");
diff --git a/examples/iec61850_client_example2/client_example2.c b/examples/iec61850_client_example2/client_example2.c
index f2e6be37..3f52e867 100644
--- a/examples/iec61850_client_example2/client_example2.c
+++ b/examples/iec61850_client_example2/client_example2.c
@@ -38,7 +38,7 @@ printDataDirectory(char* doRef, IedConnection con, int spaces)
dataAttribute = LinkedList_getNext(dataAttribute);
- char daRef[129];
+ char daRef[130];
sprintf(daRef, "%s.%s", doRef, daName);
printDataDirectory(daRef, con, spaces + 2);
}
@@ -124,7 +124,7 @@ main(int argc, char** argv)
while (dataSet != NULL) {
char* dataSetName = (char*) dataSet->data;
bool isDeletable;
- char dataSetRef[129];
+ char dataSetRef[130];
sprintf(dataSetRef, "%s.%s", lnRef, dataSetName);
LinkedList dataSetMembers = IedConnection_getDataSetDirectory(con, &error, dataSetRef,
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index eee53492..52cd5503 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -296,6 +296,8 @@ set_target_properties(iec61850-shared PROPERTIES
SOVERSION "${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}"
)
+target_compile_definitions(iec61850-shared PRIVATE EXPORT_FUNCTIONS_FOR_DLL)
+
target_link_libraries(iec61850-shared
hal-shared
)
diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c
index 1985ee8c..c081542c 100644
--- a/src/goose/goose_receiver.c
+++ b/src/goose/goose_receiver.c
@@ -59,7 +59,7 @@ struct sGooseReceiver
};
GooseReceiver
-GooseReceiver_create()
+GooseReceiver_createEx(uint8_t* buffer)
{
GooseReceiver self = (GooseReceiver) GLOBAL_MALLOC(sizeof(struct sGooseReceiver));
@@ -67,7 +67,7 @@ GooseReceiver_create()
self->running = false;
self->stop = false;
self->interfaceId = NULL;
- self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH);
+ self->buffer = buffer;
self->ethSocket = NULL;
self->subscriberList = LinkedList_create();
#if (CONFIG_MMS_THREADLESS_STACK == 0)
@@ -78,6 +78,18 @@ GooseReceiver_create()
return self;
}
+GooseReceiver
+GooseReceiver_create()
+{
+ GooseReceiver self = GooseReceiver_createEx(NULL);
+
+ if (self) {
+ self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH);
+ }
+
+ return self;
+}
+
void
GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber)
{
@@ -692,11 +704,10 @@ exit_with_fault:
}
static void
-parseGooseMessage(GooseReceiver self, int numbytes)
+parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes)
{
int bufPos;
bool subscriberFound = false;
- uint8_t* buffer = self->buffer;
if (numbytes < 22)
return;
@@ -884,9 +895,15 @@ GooseReceiver_tick(GooseReceiver self)
int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH);
if (packetSize > 0) {
- parseGooseMessage(self, packetSize);
+ parseGooseMessage(self, self->buffer, packetSize);
return true;
}
else
return false;
}
+
+void
+GooseReceiver_handleMessage(GooseReceiver self, uint8_t* buffer, int size)
+{
+ parseGooseMessage(self, buffer, size);
+}
diff --git a/src/goose/goose_receiver.h b/src/goose/goose_receiver.h
index 997cb142..b13c2d21 100644
--- a/src/goose/goose_receiver.h
+++ b/src/goose/goose_receiver.h
@@ -1,7 +1,7 @@
/*
* goose_receiver.h
*
- * Copyright 2014-2018 Michael Zillgith
+ * Copyright 2014-2019 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -51,6 +51,19 @@ typedef struct sGooseReceiver* GooseReceiver;
LIB61850_API GooseReceiver
GooseReceiver_create(void);
+/**
+ * \brief Create a new receiver instance using the provided buffer instead of allocating an own buffer
+ *
+ * A GooseReceiver instance is used to handle all GOOSE messages received on a specific
+ * network interface.
+ *
+ * \param buffer buffer to store Ethernet messages or NULL when using \ref GooseReceiver_handleMessage
+ *
+ * \return the new GooseReceiver instance
+ */
+LIB61850_API GooseReceiver
+GooseReceiver_createEx(uint8_t* buffer);
+
/**
* \brief sets the interface for the GOOSE receiver
*
@@ -134,7 +147,7 @@ GooseReceiver_stopThreadless(GooseReceiver self);
/**
* \brief Parse GOOSE messages if they are available
*
- * Call after reception of ethernet frame and periodically to to house keeping tasks
+ * Call after reception of an Ethernet frame or periodically
*
* \param self the receiver object
*
@@ -143,6 +156,19 @@ GooseReceiver_stopThreadless(GooseReceiver self);
LIB61850_API bool
GooseReceiver_tick(GooseReceiver self);
+/**
+ * \brief Parse a GOOSE message
+ *
+ * Call after reception of an Ethernet frame (can be used as an alternative to \ref GooseReceiver_tick
+ * to avoid implementing the Ethernet HAL)
+ *
+ * \param self the receiver object
+ * \param buffer a buffer containing the complete Ethernet message
+ * \param size size of the Ethernet message
+ */
+LIB61850_API void
+GooseReceiver_handleMessage(GooseReceiver self, uint8_t* buffer, int size);
+
/**@}*/
#ifdef __cplusplus
diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c
index 9db9cdcd..461074a6 100644
--- a/src/iec61850/server/mms_mapping/reporting.c
+++ b/src/iec61850/server/mms_mapping/reporting.c
@@ -349,6 +349,8 @@ sendReportSegment(ReportControl* self, bool isIntegrity, bool isGI)
if (self->clientConnection == NULL)
return false;
+ IsoConnection_lock(self->clientConnection->isoConnection);
+
int maxMmsPduSize = MmsServerConnection_getMaxMmsPduSize(self->clientConnection);
int estimatedSegmentSize = 19; /* maximum size of header information (header can have 13-19 byte) */
estimatedSegmentSize += 8; /* reserve space for more-segments-follow (3 byte) and sub-seq-num (3-5 byte) */
@@ -687,10 +689,12 @@ sendReportSegment(ReportControl* self, bool isIntegrity, bool isGI)
reportBuffer->size = bufPos;
- MmsServerConnection_sendMessage(self->clientConnection, reportBuffer, false);
+ MmsServerConnection_sendMessage(self->clientConnection, reportBuffer);
MmsServer_releaseTransmitBuffer(self->server->mmsServer);
+ IsoConnection_unlock(self->clientConnection->isoConnection);
+
if (moreFollows == false) {
/* reset sub sequence number */
segmented = false;
@@ -1829,15 +1833,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
if (rc->dataSet)
clearInclusionFlags(rc);
- MmsValue* resv = ReportControl_getRCBValue(rc, "Resv");
- MmsValue_setBoolean(resv, false);
-
rc->triggered = false;
-
- rc->reserved = false;
-
- if (rc->resvTms != -1)
- updateOwner(rc, NULL);
}
rc->enabled = false;
@@ -1872,8 +1868,15 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
if (strcmp(elementName, "Resv") == 0) {
rc->reserved = value->value.boolean;
- if (rc->reserved == true)
+ if (rc->reserved == true) {
+ updateOwner(rc, connection);
rc->clientConnection = connection;
+ }
+ else {
+ updateOwner(rc, NULL);
+ rc->clientConnection = NULL;
+ }
+
}
else if (strcmp(elementName, "PurgeBuf") == 0) {
if (MmsValue_getType(value) == MMS_BOOLEAN) {
@@ -2875,6 +2878,8 @@ sendNextReportEntrySegment(ReportControl* self)
ReportControl_unlockNotify(self);
+ IsoConnection_lock(self->clientConnection->isoConnection);
+
ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server->mmsServer);
uint8_t* buffer = reportBuffer->buffer;
@@ -3063,10 +3068,12 @@ sendNextReportEntrySegment(ReportControl* self)
reportBuffer->size = bufPos;
- MmsServerConnection_sendMessage(self->clientConnection, reportBuffer, false);
+ MmsServerConnection_sendMessage(self->clientConnection, reportBuffer);
MmsServer_releaseTransmitBuffer(self->server->mmsServer);
+ IsoConnection_unlock(self->clientConnection->isoConnection);
+
if (moreFollows == false) {
/* reset sub sequence number */
segmented = false;
diff --git a/src/mms/inc/mms_type_spec.h b/src/mms/inc/mms_type_spec.h
index 575e31fa..4e710908 100644
--- a/src/mms/inc/mms_type_spec.h
+++ b/src/mms/inc/mms_type_spec.h
@@ -5,7 +5,7 @@
* Complex types are arrays or structures of simple and complex types.
* They also represent MMS NamedVariables.
*
- * Copyright 2013, 2014 Michael Zillgith
+ * Copyright 2013-2019 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -28,6 +28,7 @@
#ifndef MMS_TYPE_SPEC_H_
#define MMS_TYPE_SPEC_H_
+#include "libiec61850_common_api.h"
#include "mms_common.h"
#include "mms_types.h"
#include "linked_list.h"
@@ -51,7 +52,7 @@ extern "C" {
*
* \param self the MmsVariableSpecification instance
*/
-void
+LIB61850_API void
MmsVariableSpecification_destroy(MmsVariableSpecification* self);
/**
@@ -67,7 +68,7 @@ MmsVariableSpecification_destroy(MmsVariableSpecification* self);
* \param childId the relative MMS name to the child MMS variable (with "$" separators!)
*
*/
-MmsValue*
+LIB61850_API MmsValue*
MmsVariableSpecification_getChildValue(MmsVariableSpecification* self, MmsValue* value, const char* childId);
/**
@@ -78,7 +79,7 @@ MmsVariableSpecification_getChildValue(MmsVariableSpecification* self, MmsValue*
*
* \return the variable specification of the child or NULL if not existing.
*/
-MmsVariableSpecification*
+LIB61850_API MmsVariableSpecification*
MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* self, const char* nameId);
/**
@@ -88,7 +89,7 @@ MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* sel
*
* \return the MMS type of the variable
*/
-MmsType
+LIB61850_API MmsType
MmsVariableSpecification_getType(MmsVariableSpecification* self);
/**
@@ -99,7 +100,7 @@ MmsVariableSpecification_getType(MmsVariableSpecification* self);
*
* \return true if type is matching, false otherwise
*/
-bool
+LIB61850_API bool
MmsVariableSpecification_isValueOfType(MmsVariableSpecification* self, MmsValue* value);
/**
@@ -112,23 +113,26 @@ MmsVariableSpecification_isValueOfType(MmsVariableSpecification* self, MmsValue*
*
* \return the name of the variable
*/
-const char*
+LIB61850_API const char*
MmsVariableSpecification_getName(MmsVariableSpecification* self);
-LinkedList /* */
+LIB61850_API LinkedList /* */
MmsVariableSpecification_getStructureElements(MmsVariableSpecification* self);
/**
* \brief returns the number of elements if the type is a complex type (structure, array) or the
* bit size of integers, unsigned integers, floats, bit strings, visible and MMS strings and octet strings.
*
+ *
+ *
* \param self the MmsVariableSpecification object
+ *
* \return the number of elements or -1 if not applicable
*/
-int
+LIB61850_API int
MmsVariableSpecification_getSize(MmsVariableSpecification* self);
-MmsVariableSpecification*
+LIB61850_API MmsVariableSpecification*
MmsVariableSpecification_getChildSpecificationByIndex(MmsVariableSpecification* self, int index);
/**
@@ -140,13 +144,13 @@ MmsVariableSpecification_getChildSpecificationByIndex(MmsVariableSpecification*
*
* \return the type specification of the component or NULL if the component was not found
*/
-MmsVariableSpecification*
+LIB61850_API MmsVariableSpecification*
MmsVariableSpecification_getChildSpecificationByName(MmsVariableSpecification* self, const char* name, int* index);
-MmsVariableSpecification*
+LIB61850_API MmsVariableSpecification*
MmsVariableSpecification_getArrayElementSpecification(MmsVariableSpecification* self);
-int
+LIB61850_API int
MmsVariableSpecification_getExponentWidth(MmsVariableSpecification* self);
/**@}*/
diff --git a/src/mms/inc_private/iso_server.h b/src/mms/inc_private/iso_server.h
index c5991693..df89a0ed 100644
--- a/src/mms/inc_private/iso_server.h
+++ b/src/mms/inc_private/iso_server.h
@@ -75,6 +75,12 @@ IsoConnection_getLocalAddress(IsoConnection self);
LIB61850_INTERNAL void
IsoConnection_close(IsoConnection self);
+LIB61850_INTERNAL void
+IsoConnection_lock(IsoConnection self);
+
+LIB61850_INTERNAL void
+IsoConnection_unlock(IsoConnection self);
+
LIB61850_INTERNAL void
IsoConnection_installListener(IsoConnection self, MessageReceivedHandler handler,
void* parameter);
@@ -89,7 +95,7 @@ IsoConnection_getSecurityToken(IsoConnection self);
* (handlerMode)
*/
LIB61850_INTERNAL void
-IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerMode);
+IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message);
LIB61850_INTERNAL IsoServer
IsoServer_create(TLSConfiguration tlsConfiguration);
diff --git a/src/mms/inc_private/mms_common_internal.h b/src/mms/inc_private/mms_common_internal.h
index 53e6b678..8f8c92b6 100644
--- a/src/mms/inc_private/mms_common_internal.h
+++ b/src/mms/inc_private/mms_common_internal.h
@@ -92,10 +92,10 @@ LIB61850_INTERNAL void
mmsMsg_createMmsRejectPdu(uint32_t* invokeId, int reason, ByteBuffer* response);
LIB61850_INTERNAL int
-mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, MmsServiceError* serviceError);
+mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, bool* hasInvokeId, MmsServiceError* serviceError);
LIB61850_INTERNAL int
-mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, int* rejectType, int* rejectReason);
+mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, bool* hasInvokeId, int* rejectType, int* rejectReason);
LIB61850_INTERNAL MmsValue*
mmsMsg_parseDataElement(Data_t* dataElement);
diff --git a/src/mms/inc_private/mms_server_connection.h b/src/mms/inc_private/mms_server_connection.h
index aa65e98b..15d4c1a9 100644
--- a/src/mms/inc_private/mms_server_connection.h
+++ b/src/mms/inc_private/mms_server_connection.h
@@ -52,7 +52,7 @@ LIB61850_INTERNAL int
MmsServerConnection_getMaxMmsPduSize(MmsServerConnection self);
LIB61850_INTERNAL void
-MmsServerConnection_sendMessage(MmsServerConnection self, ByteBuffer* message, bool handlerMode);
+MmsServerConnection_sendMessage(MmsServerConnection self, ByteBuffer* message);
LIB61850_INTERNAL bool
MmsServerConnection_addNamedVariableList(MmsServerConnection self, MmsNamedVariableList variableList);
diff --git a/src/mms/iso_client/iso_client_connection.c b/src/mms/iso_client/iso_client_connection.c
index f790a63b..709ce67b 100644
--- a/src/mms/iso_client/iso_client_connection.c
+++ b/src/mms/iso_client/iso_client_connection.c
@@ -757,6 +757,8 @@ IsoClientConnection_destroy(IsoClientConnection self)
IsoClientConnection_close(self);
}
+ releaseSocket(self);
+
if (self->receiveBuf != NULL)
GLOBAL_FREEMEM(self->receiveBuf);
if (self->receiveBuffer != NULL)
diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c
index 51d25044..6ae1f383 100644
--- a/src/mms/iso_mms/client/mms_client_connection.c
+++ b/src/mms/iso_mms/client/mms_client_connection.c
@@ -533,10 +533,13 @@ parseServiceError(uint8_t* buffer, int bufPos, int maxLength, MmsServiceError* e
}
int
-mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, MmsServiceError* serviceError)
+mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, bool* hasInvokeId, MmsServiceError* serviceError)
{
int length;
+ if (hasInvokeId)
+ *hasInvokeId = false;
+
uint8_t tag = buffer[bufPos++];
if (tag != 0xa2)
goto exit_error;
@@ -561,6 +564,8 @@ mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32
switch (tag)
{
case 0x80: /* invoke Id */
+ if (hasInvokeId)
+ *hasInvokeId = true;
if (invokeId != NULL)
*invokeId = BerDecoder_decodeUint32(buffer, length, bufPos);
bufPos += length;
@@ -589,10 +594,13 @@ exit_error:
}
int
-mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, int* rejectType, int* rejectReason)
+mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, bool* hasInvokeId, int* rejectType, int* rejectReason)
{
int length;
+ if (hasInvokeId)
+ *hasInvokeId = false;
+
uint8_t tag = buffer[bufPos++];
if (tag != 0xa4)
@@ -619,6 +627,8 @@ mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invo
goto exit_error;
if (tag == 0x80) { /* invoke id */
+ if (hasInvokeId)
+ *hasInvokeId = true;
if (invokeId != NULL)
*invokeId = BerDecoder_decodeUint32(buffer, length, bufPos);
}
@@ -1080,9 +1090,11 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
printf("MMS_CLIENT: Confirmed error PDU!\n");
uint32_t invokeId;
+ bool hasInvokeId = false;
+
MmsServiceError serviceError = { 0, 0 };
- if (mmsMsg_parseConfirmedErrorPDU(payload->buffer, 0, payload->size, &invokeId, &serviceError) < 0) {
+ if (mmsMsg_parseConfirmedErrorPDU(payload->buffer, 0, payload->size, &invokeId, &hasInvokeId, &serviceError) < 0) {
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: Error parsing confirmedErrorPDU!\n");
@@ -1090,26 +1102,35 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
}
else {
- MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
+ if (hasInvokeId) {
+ MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
- if (call) {
+ if (call) {
- MmsError err = convertServiceErrorToMmsError(serviceError);
+ MmsError err = convertServiceErrorToMmsError(serviceError);
- if (call->type != MMS_CALL_TYPE_NONE) {
- handleAsyncResponse(self, NULL, 0, call, err);
+ if (call->type != MMS_CALL_TYPE_NONE) {
+ handleAsyncResponse(self, NULL, 0, call, err);
+ }
+ else {
+ if (DEBUG_MMS_CLIENT)
+ printf("MMS_CLIENT: internal problem (unexpected call type - error PDU)\n");
+ }
}
else {
if (DEBUG_MMS_CLIENT)
- printf("MMS_CLIENT: internal problem (unexpected call type - error PDU)\n");
+ printf("MMS_CLIENT: server sent unexpected confirmed error PDU!\n");
+
+ return;
}
}
else {
if (DEBUG_MMS_CLIENT)
- printf("MMS_CLIENT: unexpected message from server!\n");
+ printf("MMS_CLIENT: server sent confirmed error PDU without invoke ID!\n");
return;
}
+
}
}
else if (tag == 0xa4) { /* reject PDU */
@@ -1117,33 +1138,40 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: reject PDU!\n");
- uint32_t invokeId;
+ bool hasInvokeId = false;
+ uint32_t invokeId = 0;
int rejectType;
int rejectReason;
- if (mmsMsg_parseRejectPDU(payload->buffer, 0, payload->size, &invokeId, &rejectType, &rejectReason) >= 0) {
+ if (mmsMsg_parseRejectPDU(payload->buffer, 0, payload->size, &invokeId, &hasInvokeId, &rejectType, &rejectReason) >= 0) {
if (DEBUG_MMS_CLIENT)
- printf("MMS_CLIENT: reject PDU invokeID: %i type: %i reason: %i\n", (int) invokeId, rejectType, rejectReason);
+ printf("MMS_CLIENT: reject PDU invokeID: %u type: %i reason: %i\n", invokeId, rejectType, rejectReason);
- MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
+ if (hasInvokeId) {
+ MmsOutstandingCall call = checkForOutstandingCall(self, invokeId);
- if (call) {
+ if (call) {
- MmsError err = convertRejectCodesToMmsError(rejectType, rejectReason);
+ MmsError err = convertRejectCodesToMmsError(rejectType, rejectReason);
- if (call->type != MMS_CALL_TYPE_NONE) {
- handleAsyncResponse(self, NULL, 0, call, err);
+ if (call->type != MMS_CALL_TYPE_NONE) {
+ handleAsyncResponse(self, NULL, 0, call, err);
+ }
+ else {
+
+ if (DEBUG_MMS_CLIENT)
+ printf("MMS_CLIENT: internal problem (unexpected call type - reject PDU)\n");
+ }
}
else {
-
- if (DEBUG_MMS_CLIENT)
- printf("MMS_CLIENT: internal problem (unexpected call type - reject PDU)\n");
+ return;
}
}
else {
return;
}
+
}
else
goto exit_with_error;
diff --git a/src/mms/iso_mms/common/mms_type_spec.c b/src/mms/iso_mms/common/mms_type_spec.c
index 7c3f2ab5..76c4cfea 100644
--- a/src/mms/iso_mms/common/mms_type_spec.c
+++ b/src/mms/iso_mms/common/mms_type_spec.c
@@ -68,9 +68,13 @@ directChildStrLen(const char* childId)
MmsValue*
MmsVariableSpecification_getChildValue(MmsVariableSpecification* typeSpec, MmsValue* value, const char* childId)
{
- if (typeSpec->type == MMS_STRUCTURE) {
+ if ((typeSpec->type == MMS_STRUCTURE) && (value->type == MMS_STRUCTURE)) {
size_t childLen = directChildStrLen(childId);
int i;
+
+ if (typeSpec->typeSpec.structure.elementCount != value->value.structure.size)
+ return NULL;
+
for (i = 0; i < typeSpec->typeSpec.structure.elementCount; i++) {
if (strlen(typeSpec->typeSpec.structure.elements[i]->name) == childLen) {
diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c
index 60ac9238..288512b7 100644
--- a/src/mms/iso_mms/server/mms_file_service.c
+++ b/src/mms/iso_mms/server/mms_file_service.c
@@ -434,16 +434,20 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
case MMS_FILE_UPLOAD_STATE_SEND_FILE_READ:
{
+ IsoConnection_lock(task->connection->isoConnection);
+
ByteBuffer* request = MmsServer_reserveTransmitBuffer(self);
task->lastRequestInvokeId = MmsServerConnection_getNextRequestInvokeId(task->connection);
mmsClient_createFileReadRequest(task->lastRequestInvokeId, request, task->frmsId);
- IsoConnection_sendMessage(task->connection->isoConnection, request, false);
+ IsoConnection_sendMessage(task->connection->isoConnection, request);
MmsServer_releaseTransmitBuffer(self);
+ IsoConnection_unlock(task->connection->isoConnection);
+
task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */
task->state = MMS_FILE_UPLOAD_STATE_FILE_READ_SENT;
@@ -468,16 +472,20 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
case MMS_FILE_UPLOAD_STATE_SEND_FILE_CLOSE:
{
+ IsoConnection_lock(task->connection->isoConnection);
+
ByteBuffer* request = MmsServer_reserveTransmitBuffer(self);
task->lastRequestInvokeId = MmsServerConnection_getNextRequestInvokeId(task->connection);
mmsClient_createFileCloseRequest(task->lastRequestInvokeId, request, task->frmsId);
- IsoConnection_sendMessage(task->connection->isoConnection, request, false);
+ IsoConnection_sendMessage(task->connection->isoConnection, request);
MmsServer_releaseTransmitBuffer(self);
+ IsoConnection_unlock(task->connection->isoConnection);
+
task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */
task->state = MMS_FILE_UPLOAD_STATE_FILE_CLOSE_SENT;
@@ -504,17 +512,21 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
{
/* send ObtainFileError */
+ IsoConnection_lock(task->connection->isoConnection);
+
ByteBuffer* response = MmsServer_reserveTransmitBuffer(self);
createServiceErrorObtainFileError(task->obtainFileRequestInvokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT, 0);
- IsoConnection_sendMessage(task->connection->isoConnection, response, false);
+ IsoConnection_sendMessage(task->connection->isoConnection, response);
+
+ MmsServer_releaseTransmitBuffer(self);
+
+ IsoConnection_unlock(task->connection->isoConnection);
FileSystem_closeFile(task->fileHandle);
deleteFile(MmsServerConnection_getFilesystemBasepath(task->connection), task->destinationFilename);
- MmsServer_releaseTransmitBuffer(self);
-
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: ObtainFile service: failed to open file from client\n");
@@ -526,11 +538,17 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
{
/* send ObtainFileError */
+ IsoConnection_lock(task->connection->isoConnection);
+
ByteBuffer* response = MmsServer_reserveTransmitBuffer(self);
createServiceErrorObtainFileError(task->obtainFileRequestInvokeId, response, MMS_ERROR_FILE_OTHER, 1);
- IsoConnection_sendMessage(task->connection->isoConnection, response, false);
+ IsoConnection_sendMessage(task->connection->isoConnection, response);
+
+ MmsServer_releaseTransmitBuffer(self);
+
+ IsoConnection_unlock(task->connection->isoConnection);
if (task->fileHandle) {
FileSystem_closeFile(task->fileHandle);
@@ -539,8 +557,6 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
deleteFile(MmsServerConnection_getFilesystemBasepath(task->connection), task->destinationFilename);
}
- MmsServer_releaseTransmitBuffer(self);
-
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: ObtainFile service: failed to create local file\n");
@@ -551,14 +567,18 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
case MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_RESPONSE:
{
+ IsoConnection_lock(task->connection->isoConnection);
+
ByteBuffer* response = MmsServer_reserveTransmitBuffer(self);
createObtainFileResponse(task->obtainFileRequestInvokeId, response);
- IsoConnection_sendMessage(task->connection->isoConnection, response, false);
+ IsoConnection_sendMessage(task->connection->isoConnection, response);
MmsServer_releaseTransmitBuffer(self);
+ IsoConnection_unlock(task->connection->isoConnection);
+
if (self->getFileCompleteHandler)
self->getFileCompleteHandler(self->getFileCompleteHandlerParameter, task->connection, task->destinationFilename);
@@ -678,7 +698,7 @@ mmsServer_handleObtainFileRequest(
mmsClient_createFileOpenRequest(task->lastRequestInvokeId, request, sourceFilename, 0);
- IsoConnection_sendMessage(task->connection->isoConnection, request, true);
+ IsoConnection_sendMessage(task->connection->isoConnection, request);
MmsServer_releaseTransmitBuffer(connection->server);
diff --git a/src/mms/iso_mms/server/mms_information_report.c b/src/mms/iso_mms/server/mms_information_report.c
index 932cc473..e0411dc2 100644
--- a/src/mms/iso_mms/server/mms_information_report.c
+++ b/src/mms/iso_mms/server/mms_information_report.c
@@ -1,7 +1,7 @@
/*
* mms_information_report.c
*
- * Copyright 2013, 2015 Michael Zillgith
+ * Copyright 2013-2019 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -59,6 +59,11 @@ MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConn
if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReportSingle variable: %s\n", itemId);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (handlerMode == false)
+ IsoConnection_lock(self->isoConnection);
+#endif
+
ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server);
uint8_t* buffer = reportBuffer->buffer;
@@ -80,10 +85,15 @@ MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConn
reportBuffer->size = bufPos;
- IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode);
+ IsoConnection_sendMessage(self->isoConnection, reportBuffer);
MmsServer_releaseTransmitBuffer(self->server);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (handlerMode == false)
+ IsoConnection_unlock(self->isoConnection);
+#endif
+
exit_function:
return;
}
@@ -152,6 +162,11 @@ MmsServerConnection_sendInformationReportListOfVariables(
goto exit_function;
}
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (handlerMode == false)
+ IsoConnection_lock(self->isoConnection);
+#endif
+
/* encode message */
ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server);
@@ -212,10 +227,16 @@ MmsServerConnection_sendInformationReportListOfVariables(
reportBuffer->size = bufPos;
- IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode);
+ IsoConnection_sendMessage(self->isoConnection, reportBuffer);
MmsServer_releaseTransmitBuffer(self->server);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (handlerMode == false) {
+ IsoConnection_unlock(self->isoConnection);
+ }
+#endif
+
exit_function:
return;
}
@@ -265,7 +286,10 @@ MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, c
goto exit_function;
}
- if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReport\n");
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (handlerMode == false)
+ IsoConnection_lock(self->isoConnection);
+#endif
ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server);
@@ -295,10 +319,15 @@ MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, c
reportBuffer->size = bufPos;
- IsoConnection_sendMessage(self->isoConnection, reportBuffer, false);
+ IsoConnection_sendMessage(self->isoConnection, reportBuffer);
MmsServer_releaseTransmitBuffer(self->server);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (handlerMode == false)
+ IsoConnection_unlock(self->isoConnection);
+#endif
+
exit_function:
return;
}
diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c
index a7aa7621..959db201 100644
--- a/src/mms/iso_mms/server/mms_server_connection.c
+++ b/src/mms/iso_mms/server/mms_server_connection.c
@@ -411,28 +411,32 @@ handleConfirmedErrorPdu(
uint8_t* buffer, int bufPos, int maxBufPos,
ByteBuffer* response)
{
- uint32_t invokeId;
+ uint32_t invokeId = 0;
+ bool hasInvokeId = false;
MmsServiceError serviceError;
- if (mmsMsg_parseConfirmedErrorPDU(buffer, bufPos, maxBufPos, &invokeId, &serviceError)) {
+ if (mmsMsg_parseConfirmedErrorPDU(buffer, bufPos, maxBufPos, &invokeId, &hasInvokeId, &serviceError)) {
if (DEBUG_MMS_SERVER)
- printf("MMS_SERVER: Handle confirmed error PDU: invokeID: %i\n", invokeId);
+ printf("MMS_SERVER: Handle confirmed error PDU: invokeID: %u\n", invokeId);
- /* check if message is related to an existing file upload task */
- int i;
- for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
+ if (hasInvokeId) {
+ /* check if message is related to an existing file upload task */
+ int i;
+ for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
- if (self->server->fileUploadTasks[i].state != MMS_FILE_UPLOAD_STATE_NOT_USED) {
+ if (self->server->fileUploadTasks[i].state != MMS_FILE_UPLOAD_STATE_NOT_USED) {
- if (self->server->fileUploadTasks[i].lastRequestInvokeId == invokeId) {
+ if (self->server->fileUploadTasks[i].lastRequestInvokeId == invokeId) {
- self->server->fileUploadTasks[i].state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_SOURCE;
- return;
- }
+ self->server->fileUploadTasks[i].state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_SOURCE;
+ return;
+ }
+ }
}
}
+
}
else {
if (DEBUG_MMS_SERVER)
@@ -752,9 +756,9 @@ MmsServerConnection_getMaxMmsPduSize(MmsServerConnection self)
}
void
-MmsServerConnection_sendMessage(MmsServerConnection self, ByteBuffer* message, bool handlerMode)
+MmsServerConnection_sendMessage(MmsServerConnection self, ByteBuffer* message)
{
- IsoConnection_sendMessage(self->isoConnection, message, false);
+ IsoConnection_sendMessage(self->isoConnection, message);
}
#if (MMS_DYNAMIC_DATA_SETS == 1)
diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c
index ca4d8f95..08afbc1c 100644
--- a/src/mms/iso_mms/server/mms_write_service.c
+++ b/src/mms/iso_mms/server/mms_write_service.c
@@ -83,15 +83,21 @@ mmsServer_createMmsWriteResponse(MmsServerConnection connection,
void
MmsServerConnection_sendWriteResponse(MmsServerConnection self, uint32_t invokeId, MmsDataAccessError indication, bool handlerMode)
{
+ if (handlerMode == false)
+ IsoConnection_lock(self->isoConnection);
+
ByteBuffer* response = MmsServer_reserveTransmitBuffer(self->server);
ByteBuffer_setSize(response, 0);
mmsServer_createMmsWriteResponse(self, invokeId, response, 1, &indication);
- IsoConnection_sendMessage(self->isoConnection, response, handlerMode);
+ IsoConnection_sendMessage(self->isoConnection, response);
MmsServer_releaseTransmitBuffer(self->server);
+
+ if (handlerMode == false)
+ IsoConnection_unlock(self->isoConnection);
}
#if 0
diff --git a/src/mms/iso_server/iso_connection.c b/src/mms/iso_server/iso_connection.c
index 777bc72b..6173ce72 100644
--- a/src/mms/iso_server/iso_connection.c
+++ b/src/mms/iso_server/iso_connection.c
@@ -165,13 +165,13 @@ IsoConnection_handleTcpConnection(IsoConnection self)
printf("ISO_SERVER: COTP connection indication\n");
#if (CONFIG_MMS_THREADLESS_STACK != 1)
- Semaphore_wait(self->conMutex);
+ IsoConnection_lock(self);
#endif
CotpConnection_sendConnectionResponseMessage(self->cotpConnection);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
- Semaphore_post(self->conMutex);
+ IsoConnection_unlock(self);
#endif
break;
@@ -202,7 +202,7 @@ IsoConnection_handleTcpConnection(IsoConnection self)
if (aIndication == ACSE_ASSOCIATE) {
#if (CONFIG_MMS_THREADLESS_STACK != 1)
- Semaphore_wait(self->conMutex);
+ IsoConnection_lock(self);
#endif
if (DEBUG_ISO_SERVER)
@@ -265,7 +265,7 @@ IsoConnection_handleTcpConnection(IsoConnection self)
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
- Semaphore_post(self->conMutex);
+ IsoConnection_unlock(self);
#endif
}
else {
@@ -297,7 +297,7 @@ IsoConnection_handleTcpConnection(IsoConnection self)
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoServer_userLock(self->isoServer);
- Semaphore_wait(self->conMutex);
+ IsoConnection_lock(self);
#endif
ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
@@ -336,7 +336,7 @@ IsoConnection_handleTcpConnection(IsoConnection self)
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
- Semaphore_post(self->conMutex);
+ IsoConnection_unlock(self);
IsoServer_userUnlock(self->isoServer);
#endif
}
@@ -357,7 +357,7 @@ IsoConnection_handleTcpConnection(IsoConnection self)
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoServer_userLock(self->isoServer);
- Semaphore_wait(self->conMutex);
+ IsoConnection_lock(self);
#endif
struct sBufferChain acseBufferPartStruct;
@@ -384,7 +384,7 @@ IsoConnection_handleTcpConnection(IsoConnection self)
CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
- Semaphore_post(self->conMutex);
+ IsoConnection_unlock(self);
IsoServer_userUnlock(self->isoServer);
#endif
}
@@ -556,7 +556,23 @@ IsoConnection_getLocalAddress(IsoConnection self)
}
void
-IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerMode)
+IsoConnection_lock(IsoConnection self)
+{
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_wait(self->conMutex);
+#endif
+}
+
+void
+IsoConnection_unlock(IsoConnection self)
+{
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_post(self->conMutex);
+#endif
+}
+
+void
+IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message)
{
if (self->state == ISO_CON_STATE_STOPPED) {
if (DEBUG_ISO_SERVER)
@@ -564,15 +580,6 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerM
goto exit_error;
}
- bool locked = false;
-
-#if (CONFIG_MMS_THREADLESS_STACK != 1)
- if (handlerMode == false) {
- Semaphore_wait(self->conMutex);
- locked = true;
- }
-#endif
-
struct sBufferChain payloadBufferStruct;
BufferChain payloadBuffer = &payloadBufferStruct;
payloadBuffer->length = message->size;
@@ -606,11 +613,6 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerM
printf("ISO_SERVER: IsoConnection_sendMessage success!\n");
}
-#if (CONFIG_MMS_THREADLESS_STACK != 1)
- if (locked)
- Semaphore_post(self->conMutex);
-#endif
-
exit_error:
return;
}
diff --git a/src/mms/iso_server/iso_server.c b/src/mms/iso_server/iso_server.c
index 413ac7e2..194ad542 100644
--- a/src/mms/iso_server/iso_server.c
+++ b/src/mms/iso_server/iso_server.c
@@ -83,6 +83,7 @@ struct sIsoServer {
#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */
#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ /* used to control access to server data model */
Semaphore userLock;
#endif
diff --git a/tools/model_generator/genconfig.jar b/tools/model_generator/genconfig.jar
index 7fbf3f96..99ce5c66 100644
Binary files a/tools/model_generator/genconfig.jar and b/tools/model_generator/genconfig.jar differ
diff --git a/tools/model_generator/gendyncode.jar b/tools/model_generator/gendyncode.jar
index a0d686f4..b5f62b33 100644
Binary files a/tools/model_generator/gendyncode.jar and b/tools/model_generator/gendyncode.jar differ
diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar
index 34e4bfb2..b9b244bc 100644
Binary files a/tools/model_generator/genmodel.jar and b/tools/model_generator/genmodel.jar differ
diff --git a/tools/model_generator/modelviewer.jar b/tools/model_generator/modelviewer.jar
index b1dab806..d6438929 100644
Binary files a/tools/model_generator/modelviewer.jar and b/tools/model_generator/modelviewer.jar differ
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java b/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java
index 2b0da485..36cf371f 100644
--- a/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java
+++ b/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java
@@ -27,6 +27,7 @@ import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
+import java.util.TimeZone;
import com.libiec61850.scl.types.EnumerationType;
import com.libiec61850.scl.types.IllegalValueException;
@@ -172,6 +173,7 @@ public class DataModelValue {
String modValueString = value.replace(',', '.');
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss.SSS");
+ parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = parser.parse(modValueString);