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);