diff --git a/config/stack_config.h b/config/stack_config.h index 3cd3e771..37e663e3 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -170,7 +170,7 @@ /* allow application to set server identity (for MMS identity service) at runtime */ #define CONFIG_IEC61850_SUPPORT_SERVER_IDENTITY 1 -/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */ +/* Force memory alignment - required for some platforms (requires more memory for buffered reporting) */ #define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1 /* compile with support for R-GOOSE (mbedtls requried) */ @@ -249,10 +249,24 @@ /* enable to configure MmsServer at runtime */ #define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1 +/* Define the default number of the maximum outstanding calls allowed by the caller (client) */ +#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5 + +/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */ +#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5 + /************************************************************************************ * Check configuration for consistency - DO NOT MODIFY THIS PART! ************************************************************************************/ +#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1) +#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!" +#endif + +#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1) +#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!" +#endif + #if (MMS_JOURNAL_SERVICE != 1) #if (CONFIG_IEC61850_LOG_SERVICE == 1) diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake index 52017dc2..28521f25 100644 --- a/config/stack_config.h.cmake +++ b/config/stack_config.h.cmake @@ -169,7 +169,7 @@ /* allow application to set server identity (for MMS identity service) at runtime */ #define CONFIG_IEC61850_SUPPORT_SERVER_IDENTITY 1 -/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */ +/* Force memory alignment - required for some platforms (requires more memory for buffered reporting) */ #define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1 /* default results for MMS identify service */ @@ -238,10 +238,24 @@ /* enable to configure MmsServer at runtime */ #define CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME 1 +/* Define the default number of the maximum outstanding calls allowed by the caller (client) */ +#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5 + +/* Define the default number of the maximum outstanding calls allowed by the calling endpoint (server) */ +#define CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5 + /************************************************************************************ * Check configuration for consistency - DO NOT MODIFY THIS PART! ************************************************************************************/ +#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING < 1) +#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING must be greater than 0!" +#endif + +#if (CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED < 1) +#error "Invalid configuration: CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED must be greater than 0!" +#endif + #if (MMS_JOURNAL_SERVICE != 1) #if (CONFIG_IEC61850_LOG_SERVICE == 1) diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 16d79a56..38db124c 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -431,6 +431,9 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_getRequestTimeout(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_setMaxOutstandingCalls(IntPtr self, int calling, int called); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_setTimeQuality(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool leapSecondKnown, [MarshalAs(UnmanagedType.I1)] bool clockFailure, [MarshalAs(UnmanagedType.I1)] bool clockNotSynchronized, int subsecondPrecision); @@ -559,6 +562,12 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_installStateChangedHandler(IntPtr connection, InternalStateChangedHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServer_ignoreReadAccess(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool ignore); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServer_ignoreClientRequests(IntPtr self, [MarshalAs(UnmanagedType.I1)] bool ignore); + /********************* * Async functions *********************/ @@ -815,6 +824,16 @@ namespace IEC61850 } } + /// + /// Set the maximum number outstanding calls allowed for this connection + /// + /// the maximum outstanding calls allowed by the caller (client) + /// the maximum outstanding calls allowed by the called endpoint (server) + public void SetMaxOutstandingCalls(int calling, int called) + { + IedConnection_setMaxOutstandingCalls(connection, calling, called); + } + /// /// Gets or sets the maximum size if a PDU (has to be set before calling connect!). /// @@ -1175,6 +1194,9 @@ namespace IEC61850 private static List WrapNativeLogQueryResult(IntPtr linkedList) { + if (linkedList == IntPtr.Zero) + return null; + List journalEntries = new List(); IntPtr element = LinkedList_getNext(linkedList); @@ -1945,6 +1967,24 @@ namespace IEC61850 } } + /// + /// Ignore all MMS requests from clients (for testing purposes) + /// + /// when true all requests from clients will be ignored + public void IgnoreClientRequests(bool ignore) + { + IedServer_ignoreClientRequests(connection, ignore); + } + + /// + /// Temporarily ignore read requests (for testing purposes) + /// + /// true to ignore read requests, false to handle read requests. + public void IgnoreReadAccess(bool ignore) + { + IedServer_ignoreReadAccess(connection, ignore); + } + /// /// Read the values of a data set (GetDataSetValues service). /// @@ -2238,22 +2278,27 @@ namespace IEC61850 GetDataSetDirectoryHandler handler = callbackInfo.Item1; object handlerParameter = callbackInfo.Item2; - IntPtr element = LinkedList_getNext(dataSetDirectory); - handle.Free(); - List newList = new List(); + List newList = null; - while (element != IntPtr.Zero) + if (dataSetDirectory != IntPtr.Zero) { - string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); + newList = new List(); - newList.Add(dataObject); + IntPtr element = LinkedList_getNext(dataSetDirectory); - element = LinkedList_getNext(element); - } + while (element != IntPtr.Zero) + { + string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); - LinkedList_destroy(dataSetDirectory); + newList.Add(dataObject); + + element = LinkedList_getNext(element); + } + + LinkedList_destroy(dataSetDirectory); + } handler.Invoke(invokeId, handlerParameter, (IedClientError)err, newList, isDeletable); } @@ -2428,11 +2473,9 @@ namespace IEC61850 dataSet = new DataSet(nativeDataSet); } - handler(invokeId, handlerParameter, clientError, dataSet); } - public delegate void ReadDataSetHandler(UInt32 invokeId,object parameter,IedClientError err,DataSet dataSet); /// @@ -2566,7 +2609,6 @@ namespace IEC61850 { handler(invokeId, handlerParameter, clientError, null, moreFollows); } - } /// @@ -2632,7 +2674,6 @@ namespace IEC61850 return GetLogicalDeviceDataSetsAsync(null, ldName, continueAfter, handler, parameter); } - public UInt32 GetLogicalDeviceDataSetsAsync(List result, string ldName, string continueAfter, GetNameListHandler handler, object parameter) { int error; @@ -2977,6 +3018,19 @@ namespace IEC61850 IED_STATE_CLOSING = 3 } + public static class IedClientErrorExtension + { + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedClientError_toString(int err); + + public static string ToString(this IedClientError err) + { + string stringVal = Marshal.PtrToStringAnsi(IedClientError_toString((int)err)); + + return stringVal; + } + } + /// /// Error codes for client side functions /// @@ -3062,6 +3116,9 @@ namespace IEC61850 /** Received an invalid response message from the server */ IED_ERROR_MALFORMED_MESSAGE = 34, + /** Service was not executed because required resource is still in use */ + IED_ERROR_OBJECT_CONSTRAINT_CONFLICT = 35, + /** Service not implemented */ IED_ERROR_SERVICE_NOT_IMPLEMENTED = 98, diff --git a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs index 818276c4..980d9ceb 100644 --- a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs @@ -1,7 +1,7 @@ /* * IEC61850CommonAPI.cs * - * Copyright 2014-2017 Michael Zillgith + * Copyright 2014-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -454,6 +454,9 @@ namespace IEC61850 SetByMmsUtcTime (mmsUtcTime); } + /// + /// Initializes a new instance of the class. + /// public Timestamp() { self = Timestamp_create (); @@ -461,6 +464,19 @@ namespace IEC61850 responsibleForDeletion = true; } + /// + /// Initializes a new instance of the class. + /// + public Timestamp(Timestamp other) : this() + { + SetTimeInSeconds (other.GetTimeInSeconds ()); + SetSubsecondPrecision (other.GetSubsecondPrecision ()); + SetFractionOfSecondPart (other.GetFractionOfSecondPart ()); + SetLeapSecondKnow(other.IsLeapSecondKnown()); + SetClockFailure(other.HasClockFailure()); + SetClockNotSynchronized(other.IsClockNotSynchronized()); + } + public Timestamp(byte[] value) { self = Timestamp_createFromByteArray (value); diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index b0d2c054..8a0c5bf3 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -1874,6 +1874,9 @@ namespace IEC61850 [return: MarshalAs(UnmanagedType.I1)] static extern bool ControlAction_getInterlockCheck(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ControlAction_getT(IntPtr self); + private IntPtr self; private IedServer.ControlHandlerInfo info; private IedServer iedServer; @@ -2003,6 +2006,18 @@ namespace IEC61850 { return ControlAction_getInterlockCheck(self); } + + /// + /// Gets the time (paramter T) of the control action + /// + public Timestamp GetT() + { + IntPtr tPtr = ControlAction_getT(self); + + Timestamp t = new Timestamp(tPtr, false); + + return new Timestamp(t); + } } public delegate void GoCBEventHandler(MmsGooseControlBlock goCB, int cbEvent, object parameter); @@ -2247,6 +2262,10 @@ namespace IEC61850 static extern void IedServer_handleWriteAccessForComplexAttribute(IntPtr self, IntPtr dataAttribute, InternalWriteAccessHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServer_handleWriteAccessForDataObject(IntPtr self, IntPtr dataObject, int fc, + InternalWriteAccessHandler handler, IntPtr parameter); + public delegate void ConnectionIndicationHandler(IedServer iedServer, ClientConnection clientConnection, bool connected, object parameter); private ConnectionIndicationHandler connectionHandler = null; @@ -2713,12 +2732,27 @@ namespace IEC61850 } } + private void AddHandlerInfoForDataObjectRecursive(DataObject dataObject, FunctionalConstraint fc, WriteAccessHandler handler, object parameter, InternalWriteAccessHandler internalHandler) + { + foreach (ModelNode child in dataObject.GetChildren()) + { + if (child is DataAttribute && (child as DataAttribute).FC == fc) + { + AddHandlerInfoForDataAttributeRecursive(child as DataAttribute, handler, parameter, internalHandler); + } + else if (child is DataObject) + { + AddHandlerInfoForDataObjectRecursive(child as DataObject, fc, handler, parameter, internalHandler); + } + } + } + /// /// Install a WriteAccessHandler for a data attribute and for all sub data attributes /// /// This instructs the server to monitor write attempts by MMS clients to specific - /// data attributes.If a client tries to write to the monitored data attribute the - /// handler is invoked.The handler can decide if the write access will be allowed + /// data attributes. If a client tries to write to the monitored data attribute the + /// handler is invoked. The handler can decide if the write access will be allowed /// or denied.If a WriteAccessHandler is set for a specific data attribute - the /// default write access policy will not be performed for that data attribute. /// @@ -2738,6 +2772,27 @@ namespace IEC61850 IedServer_handleWriteAccessForComplexAttribute(self, dataAttr.self, internalHandler, IntPtr.Zero); } + /// + /// Install a WriteAccessHandler for a data object and for all sub data objects and sub data attributes that have the same functional constraint + /// + /// This instructs the server to monitor write attempts by MMS clients to specific + /// data attributes. If a client tries to write to the monitored data attribute the + /// handler is invoked. The handler can decide if the write access will be allowed + /// or denied. If a WriteAccessHandler is set the + /// default write access policy will not be performed for the matching data attributes. + /// the data object to monitor + /// the functional constraint (FC) to monitor + /// the callback function that is invoked if a client tries to write to a monitored data attribute that is a child of the data object. + /// a user provided parameter that is passed to the WriteAccessHandler when called. + public void HandleWriteAccessForDataObject(DataObject dataObj, FunctionalConstraint fc, WriteAccessHandler handler, object parameter) + { + InternalWriteAccessHandler internalHandler = new InternalWriteAccessHandler(WriteAccessHandlerImpl); + + AddHandlerInfoForDataObjectRecursive(dataObj, fc, handler, parameter, internalHandler); + + IedServer_handleWriteAccessForDataObject(self, dataObj.self, (int)fc, internalHandler, IntPtr.Zero); + } + /// /// Set the defualt write access policy for a specific FC. The default policy is applied when no handler is installed for a data attribute /// diff --git a/dotnet/example2/WriteValueExample.cs b/dotnet/example2/WriteValueExample.cs index eb8b0228..b3ea3c04 100644 --- a/dotnet/example2/WriteValueExample.cs +++ b/dotnet/example2/WriteValueExample.cs @@ -36,7 +36,7 @@ namespace example2 } catch (IedConnectionException e) { - Console.WriteLine("IED connection excepion: " + e.Message); + Console.WriteLine("IED connection exception: " + e.Message + " err: " + e.GetIedClientError().ToString()); } // release all resources - do NOT use the object after this call!! diff --git a/hal/ethernet/linux/ethernet_linux.c b/hal/ethernet/linux/ethernet_linux.c index eaf1897a..bb989600 100644 --- a/hal/ethernet/linux/ethernet_linux.c +++ b/hal/ethernet/linux/ethernet_linux.c @@ -1,7 +1,7 @@ /* * ethernet_linux.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -57,7 +57,8 @@ EthernetHandleSet_new(void) { EthernetHandleSet result = (EthernetHandleSet) GLOBAL_MALLOC(sizeof(struct sEthernetHandleSet)); - if (result != NULL) { + if (result != NULL) + { result->handles = NULL; result->nhandles = 0; } @@ -68,8 +69,8 @@ EthernetHandleSet_new(void) void EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock) { - if (self != NULL && sock != NULL) { - + if (self != NULL && sock != NULL) + { int i = self->nhandles++; self->handles = realloc(self->handles, self->nhandles * sizeof(struct pollfd)); @@ -82,12 +83,14 @@ EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock) void EthernetHandleSet_removeSocket(EthernetHandleSet self, const EthernetSocket sock) { - if ((self != NULL) && (sock != NULL)) { - + if ((self != NULL) && (sock != NULL)) + { int i; - for (i = 0; i < self->nhandles; i++) { - if (self->handles[i].fd == sock->rawSocket) { + for (i = 0; i < self->nhandles; i++) + { + if (self->handles[i].fd == sock->rawSocket) + { memmove(&self->handles[i], &self->handles[i+1], sizeof(struct pollfd) * (self->nhandles - i - 1)); self->nhandles--; return; @@ -128,7 +131,8 @@ getInterfaceIndex(int sock, const char* deviceName) strncpy(ifr.ifr_name, deviceName, IFNAMSIZ - 1); - if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) { + if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) + { if (DEBUG_SOCKET) printf("ETHERNET_LINUX: Failed to get interface index"); return -1; @@ -157,7 +161,7 @@ Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr) int i; - for(i = 0; i < 6; i++ ) + for (i = 0; i < 6; i++ ) { addr[i] = (unsigned char)buffer.ifr_hwaddr.sa_data[i]; } @@ -166,106 +170,112 @@ Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr) EthernetSocket Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress) { - EthernetSocket ethernetSocket = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket)); + EthernetSocket self = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket)); - if (ethernetSocket) { - ethernetSocket->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (self) + { + self->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (ethernetSocket->rawSocket == -1) { + if (self->rawSocket == -1) + { if (DEBUG_SOCKET) printf("Error creating raw socket!\n"); - GLOBAL_FREEMEM(ethernetSocket); + GLOBAL_FREEMEM(self); return NULL; } - ethernetSocket->socketAddress.sll_family = PF_PACKET; - ethernetSocket->socketAddress.sll_protocol = htons(ETH_P_ALL); + self->socketAddress.sll_family = PF_PACKET; + self->socketAddress.sll_protocol = htons(ETH_P_ALL); - int ifcIdx = getInterfaceIndex(ethernetSocket->rawSocket, interfaceId); + int ifcIdx = getInterfaceIndex(self->rawSocket, interfaceId); - if (ifcIdx == -1) { - Ethernet_destroySocket(ethernetSocket); + if (ifcIdx == -1) + { + Ethernet_destroySocket(self); return NULL; } - ethernetSocket->socketAddress.sll_ifindex = ifcIdx; + self->socketAddress.sll_ifindex = ifcIdx; - ethernetSocket->socketAddress.sll_hatype = ARPHRD_ETHER; - ethernetSocket->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST; + self->socketAddress.sll_hatype = ARPHRD_ETHER; + self->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST; - ethernetSocket->socketAddress.sll_halen = ETH_ALEN; + self->socketAddress.sll_halen = ETH_ALEN; - memset(ethernetSocket->socketAddress.sll_addr, 0, 8); + memset(self->socketAddress.sll_addr, 0, 8); if (destAddress != NULL) - memcpy(ethernetSocket->socketAddress.sll_addr, destAddress, 6); + memcpy(self->socketAddress.sll_addr, destAddress, 6); + + self->isBind = false; - ethernetSocket->isBind = false; + Ethernet_setMode(self, ETHERNET_SOCKET_MODE_PROMISC); } - return ethernetSocket; + return self; } void -Ethernet_setMode(EthernetSocket ethSocket, EthernetSocketMode mode) +Ethernet_setMode(EthernetSocket self, EthernetSocketMode mode) { - if (ethSocket) { - - if (mode == ETHERNET_SOCKET_MODE_PROMISC) { - + if (self) + { + if (mode == ETHERNET_SOCKET_MODE_PROMISC) + { struct ifreq ifr; - if (ioctl (ethSocket->rawSocket, SIOCGIFFLAGS, &ifr) == -1) + if (ioctl (self->rawSocket, SIOCGIFFLAGS, &ifr) == -1) { if (DEBUG_SOCKET) printf("ETHERNET_LINUX: Problem getting device flags"); return; } - ifr.ifr_flags |= IFF_PROMISC; - if (ioctl (ethSocket->rawSocket, SIOCSIFFLAGS, &ifr) == -1) + if (ioctl (self->rawSocket, SIOCSIFFLAGS, &ifr) == -1) { if (DEBUG_SOCKET) printf("ETHERNET_LINUX: Setting device to promiscuous mode failed"); return; } } - else if (mode == ETHERNET_SOCKET_MODE_ALL_MULTICAST) { + else if (mode == ETHERNET_SOCKET_MODE_ALL_MULTICAST) + { struct ifreq ifr; - if (ioctl (ethSocket->rawSocket, SIOCGIFFLAGS, &ifr) == -1) + if (ioctl (self->rawSocket, SIOCGIFFLAGS, &ifr) == -1) { if (DEBUG_SOCKET) printf("ETHERNET_LINUX: Problem getting device flags"); return; } - ifr.ifr_flags |= IFF_ALLMULTI; - if (ioctl (ethSocket->rawSocket, SIOCSIFFLAGS, &ifr) == -1) + if (ioctl (self->rawSocket, SIOCSIFFLAGS, &ifr) == -1) { if (DEBUG_SOCKET) printf("ETHERNET_LINUX: Setting device to promiscuous mode failed"); return; } } - else if (mode == ETHERNET_SOCKET_MODE_HOST_ONLY) { - ethSocket->socketAddress.sll_pkttype = PACKET_HOST; + else if (mode == ETHERNET_SOCKET_MODE_HOST_ONLY) + { + self->socketAddress.sll_pkttype = PACKET_HOST; } - else if (mode == ETHERNET_SOCKET_MODE_MULTICAST) { - ethSocket->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST; + else if (mode == ETHERNET_SOCKET_MODE_MULTICAST) + { + self->socketAddress.sll_pkttype = PACKET_HOST | PACKET_MULTICAST; } } } void -Ethernet_addMulticastAddress(EthernetSocket ethSocket, uint8_t* multicastAddress) +Ethernet_addMulticastAddress(EthernetSocket self, uint8_t* multicastAddress) { struct packet_mreq mreq; memset(&mreq, 0, sizeof(struct packet_mreq)); - mreq.mr_ifindex = ethSocket->socketAddress.sll_ifindex; + mreq.mr_ifindex = self->socketAddress.sll_ifindex; mreq.mr_alen = ETH_ALEN; mreq.mr_type = PACKET_MR_MULTICAST; mreq.mr_address[0] = multicastAddress[0]; @@ -275,17 +285,17 @@ Ethernet_addMulticastAddress(EthernetSocket ethSocket, uint8_t* multicastAddress mreq.mr_address[4] = multicastAddress[4]; mreq.mr_address[5] = multicastAddress[5]; - int res = setsockopt(ethSocket->rawSocket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + int res = setsockopt(self->rawSocket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); - - if (res != 0) { + if (res != 0) + { if (DEBUG_SOCKET) printf("ETHERNET_LINUX: Setting multicast address failed"); } } void -Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType) +Ethernet_setProtocolFilter(EthernetSocket self, uint16_t etherType) { if (etherType == 0x88b8) { @@ -303,22 +313,22 @@ Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType) fprog.len = sizeof(filter) / sizeof(*filter); fprog.filter = filter; - if (setsockopt(ethSocket->rawSocket, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) == -1) + if (setsockopt(self->rawSocket, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) == -1) if (DEBUG_SOCKET) printf("ETHERNET_LINUX: Applying filter failed"); } else { - ethSocket->socketAddress.sll_protocol = htons(etherType); + self->socketAddress.sll_protocol = htons(etherType); } } - /* non-blocking receive */ int Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) { - if (self->isBind == false) { + if (self->isBind == false) + { if (bind(self->rawSocket, (struct sockaddr*) &self->socketAddress, sizeof(self->socketAddress)) == 0) self->isBind = true; else @@ -329,17 +339,20 @@ Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize) } void -Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize) +Ethernet_sendPacket(EthernetSocket self, uint8_t* buffer, int packetSize) { - sendto(ethSocket->rawSocket, buffer, packetSize, - 0, (struct sockaddr*) &(ethSocket->socketAddress), sizeof(ethSocket->socketAddress)); + sendto(self->rawSocket, buffer, packetSize, + 0, (struct sockaddr*) &(self->socketAddress), sizeof(self->socketAddress)); } void -Ethernet_destroySocket(EthernetSocket ethSocket) +Ethernet_destroySocket(EthernetSocket self) { - close(ethSocket->rawSocket); - GLOBAL_FREEMEM(ethSocket); + if (self) + { + close(self->rawSocket); + GLOBAL_FREEMEM(self); + } } bool @@ -347,4 +360,3 @@ Ethernet_isSupported() { return true; } - diff --git a/hal/socket/linux/socket_linux.c b/hal/socket/linux/socket_linux.c index d53ed419..44b4cbef 100644 --- a/hal/socket/linux/socket_linux.c +++ b/hal/socket/linux/socket_linux.c @@ -1,7 +1,7 @@ /* * socket_linux.c * - * Copyright 2013-2021 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of Platform Abstraction Layer (libpal) * for libiec61850, libmms, and lib60870. @@ -907,7 +907,7 @@ UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* m { //TODO add support for IPv6 struct sockaddr_storage remoteAddress; - + memset(&remoteAddress, 0, sizeof(struct sockaddr_storage)); socklen_t structSize = sizeof(struct sockaddr_storage); int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, (struct sockaddr*)&remoteAddress, &structSize); diff --git a/hal/socket/win32/socket_win32.c b/hal/socket/win32/socket_win32.c index f50ac05a..8976a825 100644 --- a/hal/socket/win32/socket_win32.c +++ b/hal/socket/win32/socket_win32.c @@ -843,6 +843,7 @@ UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* m { //TODO add support for IPv6 struct sockaddr_storage remoteAddress; + memset(&remoteAddress, 0, sizeof(struct sockaddr_storage)); socklen_t structSize = sizeof(struct sockaddr_storage); if (address) diff --git a/hal/tls/mbedtls/tls_mbedtls.c b/hal/tls/mbedtls/tls_mbedtls.c index e2f152d0..06b98234 100644 --- a/hal/tls/mbedtls/tls_mbedtls.c +++ b/hal/tls/mbedtls/tls_mbedtls.c @@ -37,9 +37,9 @@ #endif #if (CONFIG_DEBUG_TLS == 1) -#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__); +#define DEBUG_PRINT(appId, fmt, ...) fprintf(stderr, "%s: " fmt, appId, ## __VA_ARGS__) #else -#define DEBUG_PRINT(fmt, ...) {do {} while(0);} +#define DEBUG_PRINT(fmt, ...) do {} while(0) #endif @@ -265,7 +265,7 @@ TLSConfiguration_create() mbedtls_ssl_conf_authmode(&(self->conf), MBEDTLS_SSL_VERIFY_REQUIRED); - mbedtls_ssl_conf_renegotiation(&(self->conf), MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION); + mbedtls_ssl_conf_renegotiation(&(self->conf), MBEDTLS_SSL_RENEGOTIATION_ENABLED); /* static int hashes[] = {3,4,5,6,7,8,0}; */ /* mbedtls_ssl_conf_sig_hashes(&(self->conf), hashes); */ @@ -297,7 +297,7 @@ TLSConfiguration_create() void TLSConfiguration_setClientMode(TLSConfiguration self) { - self->conf.endpoint = MBEDTLS_SSL_IS_CLIENT; + mbedtls_ssl_conf_endpoint(&(self->conf), MBEDTLS_SSL_IS_CLIENT); } void @@ -852,20 +852,26 @@ TLSSocket_performHandshake(TLSSocket self) { int ret = mbedtls_ssl_renegotiate(&(self->ssl)); - if (ret == 0) { + if (ret == 0 || ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE || + ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS || ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) { if (getTLSVersion(self->ssl.major_ver, self->ssl.minor_ver) < TLS_VERSION_TLS_1_2) { raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_WRN_INSECURE_TLS_VERSION, "Warning: Insecure TLS version", self); } + + DEBUG_PRINT("TLS", "TLSSocket_performHandshake Success -> ret=%i\n", ret); + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "TLS session renegotiation completed", self); return true; } else { DEBUG_PRINT("TLS", "TLSSocket_performHandshake failed -> ret=%i\n", ret); - if (self->tlsConfig->eventHandler) { - uint32_t flags = mbedtls_ssl_get_verify_result(&(self->ssl)); + raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_WARNING, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Alarm: TLS session renegotiation failed", self); - createSecurityEvents(self->tlsConfig, ret, flags, self); + /* mbedtls_ssl_renegotiate mandates to reset the ssl session in case of errors */ + ret = mbedtls_ssl_session_reset(&(self->ssl)); + if (ret != 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -> ret: -0x%X\n", -ret); } return false; @@ -898,16 +904,10 @@ startRenegotiationIfRequired(TLSSocket self) if (Hal_getTimeInMs() <= self->lastRenegotiationTime + self->tlsConfig->renegotiationTimeInMs) return true; - raiseSecurityEvent(self->tlsConfig, TLS_SEC_EVT_INFO, TLS_EVENT_CODE_INF_SESSION_RENEGOTIATION, "Info: session renegotiation started", self); - - if (TLSSocket_performHandshake(self) == false) { - DEBUG_PRINT("TLS", " renegotiation failed\n"); + if (TLSSocket_performHandshake(self) == false) return false; - } - DEBUG_PRINT("TLS", " started renegotiation\n"); self->lastRenegotiationTime = Hal_getTimeInMs(); - return true; } @@ -920,22 +920,30 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size) return -1; } - int ret = mbedtls_ssl_read(&(self->ssl), buf, size); - - if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE)) - return 0; + int len = 0; + while (len < size) { + int ret = mbedtls_ssl_read(&(self->ssl), (buf + len), (size - len)); + if (ret > 0) { + len += ret; + continue; + } - if (ret < 0) { + switch (ret) { + case 0: // falling through + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: + case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS: + // Known "good" cases indicating the read is done + return len; - switch (ret) - { case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: DEBUG_PRINT("TLS", " connection was closed gracefully\n"); - return -1; + break; case MBEDTLS_ERR_NET_CONN_RESET: DEBUG_PRINT("TLS", " connection was reset by peer\n"); - return -1; + break; default: DEBUG_PRINT("TLS", " mbedtls_ssl_read returned -0x%x\n", -ret); @@ -945,19 +953,23 @@ TLSSocket_read(TLSSocket self, uint8_t* buf, int size) createSecurityEvents(self->tlsConfig, ret, flags, self); } + } - return -1; + int reset_err = mbedtls_ssl_session_reset(&(self->ssl)); + if (0 != reset_err) { + DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -0x%X\n", -reset_err); } + + return ret; } - return ret; + return len; } int TLSSocket_write(TLSSocket self, uint8_t* buf, int size) { - int ret; - int len = size; + int len = 0; checkForCRLUpdate(self); @@ -965,22 +977,26 @@ TLSSocket_write(TLSSocket self, uint8_t* buf, int size) return -1; } - while ((ret = mbedtls_ssl_write(&(self->ssl), buf, len)) <= 0) + while (len < size) { - if (ret == MBEDTLS_ERR_NET_CONN_RESET) - { - DEBUG_PRINT("TLS", "peer closed the connection\n"); - return -1; + int ret = mbedtls_ssl_write(&(self->ssl), (buf + len), (size -len)); + if ((ret == MBEDTLS_ERR_SSL_WANT_READ) || (ret == MBEDTLS_ERR_SSL_WANT_WRITE) || + (ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) || (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)) { + continue; } - if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) - { - DEBUG_PRINT("TLS", "mbedtls_ssl_write returned %d\n", ret); + if (ret < 0) { + DEBUG_PRINT("TLS", "mbedtls_ssl_write returned -0x%X\n", -ret); + + if (0 != (ret = mbedtls_ssl_session_reset(&(self->ssl)))) { + DEBUG_PRINT("TLS", "mbedtls_ssl_session_reset failed -0x%X\n", -ret); + } + return -1; } - } - len = ret; + len += ret; + } return len; } @@ -1008,6 +1024,7 @@ TLSSocket_close(TLSSocket self) if (self->peerCert) GLOBAL_FREEMEM(self->peerCert); + GLOBAL_FREEMEM(self); } diff --git a/pyiec61850/CMakeLists.txt b/pyiec61850/CMakeLists.txt index 159ef4bc..a42960f9 100644 --- a/pyiec61850/CMakeLists.txt +++ b/pyiec61850/CMakeLists.txt @@ -1,18 +1,22 @@ -# The SWIG functions/macros used in this module, swig_add_module and swig_add_library -# are not available in CMake versions earlier than 3.8 -# cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) + +cmake_policy(SET CMP0078 NEW) + +if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") + cmake_policy(SET CMP0086 NEW) +endif() find_package(SWIG REQUIRED) include(${SWIG_USE_FILE}) -find_package(PythonInterp ${BUILD_PYTHON_VERSION} REQUIRED) -find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT REQUIRED) +find_package(Python COMPONENTS Interpreter Development REQUIRED) -include_directories(${PYTHON_INCLUDE_PATH}) +include_directories(${Python_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_SWIG_FLAGS "") set_property(SOURCE iec61850.i PROPERTY CPLUSPLUS ON) +set_property(SOURCE iec61850.i PROPERTY SWIG_MODULE_NAME pyiec61850) if(WIN32) set(LIBS iec61850 ws2_32) @@ -20,25 +24,21 @@ else() set(LIBS iec61850-shared) endif() -if(${CMAKE_VERSION} VERSION_LESS 3.8) - swig_add_module(iec61850 python iec61850.i) -else() - swig_add_library(iec61850 - LANGUAGE python - SOURCES iec61850.i - ) -endif() +swig_add_library(pyiec61850 + LANGUAGE python + SOURCES iec61850.i +) -swig_link_libraries(iec61850 ${PYTHON_LIBRARIES} ${LIBS}) +swig_link_libraries(pyiec61850 ${LIBS}) # Finding python modules install path execute_process( - COMMAND ${PYTHON_EXECUTABLE} -c - "from distutils.sysconfig import get_python_lib; import sys; sys.stdout.write(get_python_lib())" + COMMAND ${Python_EXECUTABLE} -c + "from sysconfig import get_path; import sys; sys.stdout.write(get_path('platlib'))" OUTPUT_VARIABLE PYTHON_SITE_DIR ) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/iec61850.py DESTINATION ${PYTHON_SITE_DIR}) -install(TARGETS _iec61850 LIBRARY DESTINATION ${PYTHON_SITE_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pyiec61850.py DESTINATION ${PYTHON_SITE_DIR}) +install(TARGETS pyiec61850 LIBRARY DESTINATION ${PYTHON_SITE_DIR}) -add_test(test_pyiec61850 ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/test_pyiec61850.py) +add_test(test_pyiec61850 ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/test_pyiec61850.py) diff --git a/pyiec61850/README.md b/pyiec61850/README.md new file mode 100644 index 00000000..b2398919 --- /dev/null +++ b/pyiec61850/README.md @@ -0,0 +1,95 @@ +# Python wrapper for libIEC61850 + +## Building +Before building you should install SWIG and Python +(see the '[Setup development environment on Linux](#setup-development-environment-on-linux-ubuntu)' section for help). + +To build the Python bindings you have to turn on the BUILD\_PYTHON\_BINDINGS flag in CMake from cmake-gui or in command line: +```sh +$ mkdir build && cd build +$ cmake -DBUILD_PYTHON_BINDINGS=ON .. +``` + +Then compile the library and install it: +```sh +$ make +$ sudo make install +``` +(Eventually, update your ld cache with: `sudo ldconfig`) + +CMake and SWIG will automatically detect your Python version and install the Python library in Python library directories. + +For running the integrated tests: +```sh +$ make test +``` + +pyiec61850 library is to be imported calling: +```python +import pyiec61850 as iec61850 +``` + +## Client tutorial + +The Python bindings works similarly to the basic C library. However there are some differences: + +* a specific function is to be called to cast variables from one type to another +* arguments passed by pointer are to be removed from arguments and append to the return list + + +For example to create a connection, call: +```python + con = iec61850.IedConnection_create() + error = iec61850.IedConnection_connect(con, "localhost", 102) + if (error == iec61850.IED_ERROR_OK): + # Do some work + iec61850.IedConnection_close(con) + iec61850.IedConnection_destroy(con) +``` + +To iterate over a list of logical devices, the code becomes: +```python +[deviceList, error] = iec61850.IedConnection_getLogicalDeviceList(con) +device = iec61850.LinkedList_getNext(deviceList) + +while device: + print("LD: %s" % iec61850.toCharP(device.data)) + [logicalNodes, error] = iec61850.IedConnection_getLogicalDeviceDirectory( + con, iec61850.toCharP(device.data)) + device = iec61850.LinkedList_getNext(device) +iec61850.LinkedList_destroy(deviceList) +``` + +Reading and writing operations can be performed using this syntax: +```python +[floatValue, error] = iec61850.IedConnection_readFloatValue(con, + "simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX) +err = iec61850.IedConnection_writeFloatValue(con, + "simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX, 10.0) +``` + +## Appendix + +## Setup development environment on Linux Ubuntu + +_[Tested on Ubuntu 20.04 LTS, Ubuntu 22.04 LTS, Ubuntu 23.10]_ + +Here the minimum required packages for compiling libiec61850 and the Python +wrapper (without TLS, SQlite, ...): + +```sh +$ sudo apt-get update +$ sudo apt-get install g++ cmake swig git python3 python3-all-dev +``` + +## Setup development environment on Linux Alpine + +_[Tested on Alpine 3.18]_ + +Here the minimum required packages for compiling libiec61850 and the Python +wrapper (without TLS, SQlite, ...): + +```sh +$ apk update +$ apk add git g++ swig make cmake python3 python3-dev linux-headers +``` diff --git a/pyiec61850/examples/dispServerStruct.py b/pyiec61850/examples/dispServerStruct.py index aea02b4f..2b49479b 100755 --- a/pyiec61850/examples/dispServerStruct.py +++ b/pyiec61850/examples/dispServerStruct.py @@ -1,6 +1,6 @@ #!/usr/bin/python import os,sys -import iec61850 +import pyiec61850 as iec61850 if __name__=="__main__": hostname = "localhost"; tcpPort = 102 diff --git a/pyiec61850/examples/rcbSubscriptionExample.py b/pyiec61850/examples/rcbSubscriptionExample.py index d4d05aa5..7d1243be 100644 --- a/pyiec61850/examples/rcbSubscriptionExample.py +++ b/pyiec61850/examples/rcbSubscriptionExample.py @@ -27,7 +27,7 @@ The user needs to: import time import sys -import iec61850 +import pyiec61850 as iec61850 def open_connection(ip_address, mms_port): diff --git a/pyiec61850/iec61850.i b/pyiec61850/iec61850.i index 254fec64..4cdbe0ea 100644 --- a/pyiec61850/iec61850.i +++ b/pyiec61850/iec61850.i @@ -1,5 +1,5 @@ /* File : iec61850.i */ -%module(directors="1") iec61850 +%module(directors="1") pyiec61850 %ignore ControlObjectClient_setTestMode(ControlObjectClient self); %ignore CDA_OperBoolean(ModelNode* parent, bool isTImeActivated); %ignore LogicalNode_hasBufferedReports(LogicalNode* node); diff --git a/pyiec61850/test_pyiec61850.py b/pyiec61850/test_pyiec61850.py index aceb3fdb..6f6d8cdd 100755 --- a/pyiec61850/test_pyiec61850.py +++ b/pyiec61850/test_pyiec61850.py @@ -6,7 +6,7 @@ import traceback import signal import sys sys.path.append('.') -import iec61850 +import pyiec61850 as iec61850 def signal_handler(signal, frame): global running running =0 diff --git a/pyiec61850/tutorial.md b/pyiec61850/tutorial.md deleted file mode 100644 index ce766cab..00000000 --- a/pyiec61850/tutorial.md +++ /dev/null @@ -1,50 +0,0 @@ -# Building -Before building you should install swig and python. -To build python bindings you have to turn on the BUILD\_PYTHON\_BINDINGS flag in CMake from cmake-gui or in command line: -```sh -$ cmake -DBUILD_PYTHON_BINDINGS=ON . -``` -Then compile the library and install it. CMake and swig will automatically detect your python version and install the python library in python library directories. - -pyiec61850 library is to be imported calling -```python -import iec61850 -``` -# Client tutorial - -The python bindings works similarly to the basic C library. However there are some differences: - -* a specific function is to be called to cast variables from one type to another -* arguments passed by pointer are to be removed from arguments and append to the return list - - -For example to create a connection, call: -```python - con = iec61850.IedConnection_create() - error = iec61850.IedConnection_connect(con, "localhost", 102) - if (error == iec61850.IED_ERROR_OK): - # Do some work - iec61850.IedConnection_close(con) - iec61850.IedConnection_destroy(con) -``` - -To iterate over a list of logical devices, the code becomes: -```python -[deviceList, error] = iec61850.IedConnection_getLogicalDeviceList(con) -device = iec61850.LinkedList_getNext(deviceList) - -while device: - print("LD: %s" % iec61850.toCharP(device.data)) - [logicalNodes, error] = iec61850.IedConnection_getLogicalDeviceDirectory( - con, iec61850.toCharP(device.data)) - device = iec61850.LinkedList_getNext(device) -iec61850.LinkedList_destroy(deviceList) -``` - -Reading and writing operations can be performed using this syntax: -```python -[floatValue, error] = iec61850.IedConnection_readFloatValue(con, - "simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX) -err = iec61850.IedConnection_writeFloatValue(con, - "simpleIOGenericIO/GGIO1.AnIn1.mag.f", iec61850.IEC61850_FC_MX, 10.0) -``` diff --git a/src/common/string_utilities.c b/src/common/string_utilities.c index 2f659e6f..1608f964 100644 --- a/src/common/string_utilities.c +++ b/src/common/string_utilities.c @@ -90,14 +90,14 @@ StringUtils_copyStringToBufferAndReplace(const char* str, char* buffer, char old char* StringUtils_createStringFromBuffer(const uint8_t* buf, int size) { - char* newStr = (char*) GLOBAL_MALLOC(size + 1); + char* newStr = (char*) GLOBAL_MALLOC(size + 1); - if (newStr) { - memcpy(newStr, buf, size); - newStr[size] = 0; - } + if (newStr) { + memcpy(newStr, buf, size); + newStr[size] = 0; + } - return newStr; + return newStr; } char* @@ -429,11 +429,11 @@ getCharWeight(int c) { static bool initialized = false; static char lookupTable[LT_MAX_CHARS + 1]; + static const char* charOrder = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz$_0123456789"; if (!initialized) { int ltIndex; int weight = 1; - const char* charOrder = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz$_0123456789"; for (ltIndex = 1; ltIndex < LT_MAX_CHARS; ltIndex++) { if (strchr(charOrder, ltIndex)) continue; diff --git a/src/goose/goose_publisher.c b/src/goose/goose_publisher.c index a8023807..094881a5 100644 --- a/src/goose/goose_publisher.c +++ b/src/goose/goose_publisher.c @@ -1,7 +1,7 @@ /* * goose_publisher.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -106,12 +106,14 @@ GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, boo if (self) { - if (prepareGooseBuffer(self, parameters, interfaceID, useVlanTag)) { + if (prepareGooseBuffer(self, parameters, interfaceID, useVlanTag)) + { self->timestamp = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs()); GoosePublisher_reset(self); } - else { + else + { GoosePublisher_destroy(self); self = NULL; } @@ -257,71 +259,84 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* uint16_t vlanId; uint16_t appId; - if (parameters) { - dstAddr = defaultDstAddr; - priority = CONFIG_GOOSE_DEFAULT_PRIORITY; - vlanId = CONFIG_GOOSE_DEFAULT_VLAN_ID; - appId = CONFIG_GOOSE_DEFAULT_APPID; - } - else { + if (parameters) + { dstAddr = parameters->dstAddress; priority = parameters->vlanPriority; vlanId = parameters->vlanId; appId = parameters->appId; } + else + { + dstAddr = defaultDstAddr; + priority = CONFIG_GOOSE_DEFAULT_PRIORITY; + vlanId = CONFIG_GOOSE_DEFAULT_VLAN_ID; + appId = CONFIG_GOOSE_DEFAULT_APPID; + } if (interfaceID) self->ethernetSocket = Ethernet_createSocket(interfaceID, dstAddr); else self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr); - if (self->ethernetSocket) { + if (self->ethernetSocket) + { self->buffer = (uint8_t*) GLOBAL_MALLOC(GOOSE_MAX_MESSAGE_SIZE); - memcpy(self->buffer, dstAddr, 6); - memcpy(self->buffer + 6, srcAddr, 6); + if (self->buffer) + { + memcpy(self->buffer, dstAddr, 6); + memcpy(self->buffer + 6, srcAddr, 6); - int bufPos = 12; + int bufPos = 12; - if (useVlanTags) { - /* Priority tag - IEEE 802.1Q */ - self->buffer[bufPos++] = 0x81; - self->buffer[bufPos++] = 0x00; + if (useVlanTags) + { + /* Priority tag - IEEE 802.1Q */ + self->buffer[bufPos++] = 0x81; + self->buffer[bufPos++] = 0x00; - uint8_t tci1 = priority << 5; - tci1 += vlanId / 256; + uint8_t tci1 = priority << 5; + tci1 += vlanId / 256; - uint8_t tci2 = vlanId % 256; + uint8_t tci2 = vlanId % 256; - self->buffer[bufPos++] = tci1; /* Priority + VLAN-ID */ - self->buffer[bufPos++] = tci2; /* VLAN-ID */ - } + self->buffer[bufPos++] = tci1; /* Priority + VLAN-ID */ + self->buffer[bufPos++] = tci2; /* VLAN-ID */ + } - /* EtherType GOOSE */ - self->buffer[bufPos++] = 0x88; - self->buffer[bufPos++] = 0xB8; + /* EtherType GOOSE */ + self->buffer[bufPos++] = 0x88; + self->buffer[bufPos++] = 0xB8; - /* APPID */ - self->buffer[bufPos++] = appId / 256; - self->buffer[bufPos++] = appId % 256; + /* APPID */ + self->buffer[bufPos++] = appId / 256; + self->buffer[bufPos++] = appId % 256; - self->lengthField = bufPos; + self->lengthField = bufPos; - /* Length */ - self->buffer[bufPos++] = 0x00; - self->buffer[bufPos++] = 0x08; + /* Length */ + self->buffer[bufPos++] = 0x00; + self->buffer[bufPos++] = 0x08; - /* Reserved1 */ - self->buffer[bufPos++] = 0x00; - self->buffer[bufPos++] = 0x00; + /* Reserved1 */ + self->buffer[bufPos++] = 0x00; + self->buffer[bufPos++] = 0x00; - /* Reserved2 */ - self->buffer[bufPos++] = 0x00; - self->buffer[bufPos++] = 0x00; + /* Reserved2 */ + self->buffer[bufPos++] = 0x00; + self->buffer[bufPos++] = 0x00; - self->payloadStart = bufPos; + self->payloadStart = bufPos; - return true; + return true; + } + else + { + if (DEBUG_GOOSE_PUBLISHER) + printf("GOOSE_PUBLISHER: Failed to allocate buffer\n"); + return false; + } } else { return false; @@ -329,8 +344,8 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* } static int32_t -createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffer, size_t maxPayloadSize) { - +createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffer, size_t maxPayloadSize) +{ /* Step 1 - calculate length fields */ uint32_t goosePduLength = 0; @@ -365,13 +380,16 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe LinkedList element = LinkedList_getNext(dataSetValues); - while (element) { + while (element) + { MmsValue* dataSetEntry = (MmsValue*) element->data; - if (dataSetEntry) { + if (dataSetEntry) + { dataSetSize += MmsValue_encodeMmsData(dataSetEntry, NULL, 0, false); } - else { + else + { /* TODO encode MMS NULL */ if (DEBUG_GOOSE_PUBLISHER) printf("GOOSE_PUBLISHER: NULL value in data set!\n"); @@ -438,7 +456,8 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe /* Encode data set entries */ element = LinkedList_getNext(dataSetValues); - while (element) { + while (element) + { MmsValue* dataSetEntry = (MmsValue*) element->data; if (dataSetEntry) { @@ -503,7 +522,7 @@ GoosePublisher_publishAndDump(GoosePublisher self, LinkedList dataSet, char *msg int rc = GoosePublisher_publish(self, dataSet); if (rc == 0) - { + { int copied = self->payloadStart + self->payloadLength; if (bufSize < copied) diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c index 833fb2ff..6109eee9 100644 --- a/src/goose/goose_receiver.c +++ b/src/goose/goose_receiver.c @@ -1,7 +1,7 @@ /* * goose_receiver.c * - * Copyright 2014-2022 Michael Zillgith + * Copyright 2014-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -73,7 +73,8 @@ GooseReceiver_createEx(uint8_t* buffer) { GooseReceiver self = (GooseReceiver) GLOBAL_MALLOC(sizeof(struct sGooseReceiver)); - if (self != NULL) { + if (self != NULL) + { self->running = false; self->stop = false; self->interfaceId = NULL; @@ -148,9 +149,20 @@ static void createNewStringFromBufferElement(MmsValue* value, uint8_t* bufferSrc, int elementLength) { value->value.visibleString.buf = (char*) GLOBAL_MALLOC(elementLength + 1); - memcpy(value->value.visibleString.buf, bufferSrc, elementLength); - value->value.visibleString.buf[elementLength] = 0; - value->value.visibleString.size = elementLength; + + if (value->value.visibleString.buf) + { + memcpy(value->value.visibleString.buf, bufferSrc, elementLength); + value->value.visibleString.buf[elementLength] = 0; + value->value.visibleString.size = elementLength; + } + else + { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: failed to allocate memory for visible string\n"); + + value->value.visibleString.size = 0; + } } static GooseParseError @@ -165,24 +177,28 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) GooseParseError pe = GOOSE_PARSE_ERROR_NO_ERROR; uint8_t tag; - while (bufPos < allDataLength) { + while (bufPos < allDataLength) + { tag = buffer[bufPos++]; - if (elementIndex > maxIndex) { + if (elementIndex > maxIndex) + { pe = GOOSE_PARSE_ERROR_OVERFLOW; break; /* from while */ } MmsValue* value = MmsValue_getElement(dataSetValues, elementIndex); - if (value == NULL) { + if (value == NULL) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: type mismatch (element %i not found)\n", elementIndex); return GOOSE_PARSE_ERROR_TYPE_MISMATCH; } bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); - if (bufPos < 0) { + if (bufPos < 0) + { pe = GOOSE_PARSE_ERROR_TAGDECODE; break; /* from while */ } @@ -197,7 +213,8 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) case 0xa1: /* array */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n"); - if (MmsValue_getType(value) == MMS_ARRAY) { + if (MmsValue_getType(value) == MMS_ARRAY) + { if (parseAllData(buffer + bufPos, elementLength, value) != GOOSE_PARSE_ERROR_NO_ERROR) pe = GOOSE_PARSE_ERROR_SUBLEVEL; } @@ -209,7 +226,8 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) case 0xa2: /* structure */ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n"); - if (MmsValue_getType(value) == MMS_STRUCTURE) { + if (MmsValue_getType(value) == MMS_STRUCTURE) + { if (parseAllData(buffer + bufPos, elementLength, value) != GOOSE_PARSE_ERROR_NO_ERROR) pe = GOOSE_PARSE_ERROR_SUBLEVEL; } @@ -232,18 +250,23 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x84: /* BIT STRING */ - if (MmsValue_getType(value) == MMS_BIT_STRING) { + if (MmsValue_getType(value) == MMS_BIT_STRING) + { int padding = buffer[bufPos]; - if (padding > 7) { + if (padding > 7) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: invalid bit-string (padding not plausible)\n"); pe = GOOSE_PARSE_ERROR_INVALID_PADDING; } - else { + else + { int bitStringLength = (8 * (elementLength - 1)) - padding; - if (bitStringLength == value->value.bitString.size) { + + if (bitStringLength == value->value.bitString.size) + { memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1); } @@ -258,8 +281,10 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x85: /* integer */ - if (MmsValue_getType(value) == MMS_INTEGER) { - if (elementLength <= value->value.integer->maxSize) { + if (MmsValue_getType(value) == MMS_INTEGER) + { + if (elementLength <= value->value.integer->maxSize) + { value->value.integer->size = elementLength; memcpy(value->value.integer->octets, buffer + bufPos, elementLength); } @@ -273,8 +298,10 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x86: /* unsigned integer */ - if (MmsValue_getType(value) == MMS_UNSIGNED) { - if (elementLength <= value->value.integer->maxSize) { + if (MmsValue_getType(value) == MMS_UNSIGNED) + { + if (elementLength <= value->value.integer->maxSize) + { value->value.integer->size = elementLength; memcpy(value->value.integer->octets, buffer + bufPos, elementLength); } @@ -288,7 +315,8 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x87: /* Float */ - if (MmsValue_getType(value) == MMS_FLOAT) { + if (MmsValue_getType(value) == MMS_FLOAT) + { if (elementLength == 9) { MmsValue_setDouble(value, BerDecoder_decodeDouble(buffer, bufPos)); } @@ -305,15 +333,19 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x89: /* octet string */ - if (MmsValue_getType(value) == MMS_OCTET_STRING) { - if (elementLength <= abs(value->value.octetString.maxSize)) { + if (MmsValue_getType(value) == MMS_OCTET_STRING) + { + if (elementLength <= abs(value->value.octetString.maxSize)) + { value->value.octetString.size = elementLength; memcpy(value->value.octetString.buf, buffer + bufPos, elementLength); } - else { + else + { uint8_t* newBuf = (uint8_t*)GLOBAL_MALLOC(elementLength); - if (newBuf) { + if (newBuf) + { memcpy(newBuf, buffer + bufPos, elementLength); uint8_t* oldBuf = value->value.octetString.buf; @@ -324,7 +356,6 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) GLOBAL_FREEMEM(oldBuf); } - } } else { @@ -333,14 +364,17 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x8a: /* visible string */ - if (MmsValue_getType(value) == MMS_VISIBLE_STRING) { - - if (value->value.visibleString.buf != NULL) { - if ((int32_t) value->value.visibleString.size >= elementLength) { + if (MmsValue_getType(value) == MMS_VISIBLE_STRING) + { + if (value->value.visibleString.buf != NULL) + { + if ((int32_t) value->value.visibleString.size >= elementLength) + { memcpy(value->value.visibleString.buf, buffer + bufPos, elementLength); value->value.visibleString.buf[elementLength] = 0; } - else { + else + { GLOBAL_FREEMEM(value->value.visibleString.buf); createNewStringFromBufferElement(value, buffer + bufPos, elementLength); @@ -348,7 +382,6 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) } else createNewStringFromBufferElement(value, buffer + bufPos, elementLength); - } else { pe = GOOSE_PARSE_ERROR_TYPE_MISMATCH; @@ -356,7 +389,8 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x8c: /* binary time */ - if (MmsValue_getType(value) == MMS_BINARY_TIME) { + if (MmsValue_getType(value) == MMS_BINARY_TIME) + { if ((elementLength == 4) || (elementLength == 6)) { memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength); } @@ -367,7 +401,8 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) break; case 0x91: /* Utctime */ - if (elementLength == 8) { + if (elementLength == 8) + { if (MmsValue_getType(value) == MMS_UTC_TIME) { MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); } @@ -394,13 +429,15 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) elementIndex++; } - if (elementIndex <= maxIndex) { + if (elementIndex <= maxIndex) + { if (pe == GOOSE_PARSE_ERROR_NO_ERROR) { pe = GOOSE_PARSE_ERROR_UNDERFLOW; } } - if (DEBUG_GOOSE_SUBSCRIBER) { + if (DEBUG_GOOSE_SUBSCRIBER) + { switch (pe) { case GOOSE_PARSE_ERROR_UNKNOWN_TAG: printf("GOOSE_SUBSCRIBER: Found unkown tag %02x!\n", tag); @@ -443,11 +480,14 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt MmsValue* dataSetValues = NULL; - while (bufPos < allDataLength) { + while (bufPos < allDataLength) + { uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); - if (bufPos < 0) { + + if (bufPos < 0) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); return 0; @@ -498,11 +538,14 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt elementIndex = 0; bufPos = 0; - while (bufPos < allDataLength) { + while (bufPos < allDataLength) + { uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); - if (bufPos < 0) { + + if (bufPos < 0) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); return 0; @@ -552,22 +595,26 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt case 0x84: /* BIT STRING */ { - if (elementLength > 1) { + if (elementLength > 1) + { int padding = buffer[bufPos]; int rawBitLength = (elementLength - 1) * 8; - if (padding > 7) { + if (padding > 7) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: invalid bit-string (padding not plausible)\n"); goto exit_with_error; } - else { + else + { value = MmsValue_newBitString(rawBitLength - padding); memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1); } } - else { + else + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: invalid bit-string\n"); @@ -577,13 +624,15 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt break; case 0x85: /* integer */ - if (elementLength > 8) { - if (DEBUG_GOOSE_SUBSCRIBER) - printf("GOOSE_SUBSCRIBER: unsupported integer size(%i)\n", elementLength); + if (elementLength > 8) + { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: unsupported integer size(%i)\n", elementLength); - goto exit_with_error; + goto exit_with_error; } - else { + else + { value = MmsValue_newInteger(elementLength * 8); memcpy(value->value.integer->octets, buffer + bufPos, elementLength); value->value.integer->size = elementLength; @@ -592,13 +641,15 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt break; case 0x86: /* unsigned integer */ - if (elementLength > 8) { + if (elementLength > 8) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: unsupported unsigned size(%i)\n", elementLength); goto exit_with_error; } - else { + else + { value = MmsValue_newUnsigned(elementLength * 8); memcpy(value->value.integer->octets, buffer + bufPos, elementLength); value->value.integer->size = elementLength; @@ -634,13 +685,16 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt break; case 0x91: /* Utctime */ - if (elementLength == 8) { + if (elementLength == 8) + { value = MmsValue_newUtcTime(0); MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); } else - if (DEBUG_GOOSE_SUBSCRIBER) - printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); + { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n"); + } break; default: @@ -651,7 +705,8 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt bufPos += elementLength; - if (value != NULL) { + if (value != NULL) + { MmsValue_setElement(dataSetValues, elementIndex, value); elementIndex++; } @@ -686,10 +741,12 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) uint32_t numberOfDatSetEntries = 0; - if (buffer[bufPos++] == 0x61) { + if (buffer[bufPos++] == 0x61) + { int gooseLength; bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); return 0; @@ -697,12 +754,14 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) int gooseEnd = bufPos + gooseLength; - while (bufPos < gooseEnd) { + while (bufPos < gooseEnd) + { int elementLength; uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); return 0; @@ -720,16 +779,19 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) { LinkedList element = LinkedList_getNext(self->subscriberList); - while (element != NULL) { + while (element) + { GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); if (subscriber->isObserver) { - if (elementLength > 129) { + if (elementLength > 129) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: gocbRef too long!\n"); } - else { + else + { memcpy(subscriber->goCBRef, buffer + bufPos, elementLength); subscriber->goCBRef[elementLength] = 0; } @@ -737,8 +799,10 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) matchingSubscriber = subscriber; break; } - else if (subscriber->goCBRefLen == elementLength) { - if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) { + else if (subscriber->goCBRefLen == elementLength) + { + if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n"); matchingSubscriber = subscriber; @@ -768,12 +832,15 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found dataSet\n"); { - if (matchingSubscriber) { - if (elementLength > 129) { + if (matchingSubscriber) + { + if (elementLength > 129) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: datSet too long!\n"); } - else { + else + { memcpy(matchingSubscriber->datSet, buffer + bufPos, elementLength); matchingSubscriber->datSet[elementLength] = 0; } @@ -785,12 +852,15 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found goId\n"); { - if (matchingSubscriber) { - if (elementLength > 129) { + if (matchingSubscriber) + { + if (elementLength > 129) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: goId too long!\n"); } - else { + else + { memcpy(matchingSubscriber->goId, buffer + bufPos, elementLength); matchingSubscriber->goId[elementLength] = 0; } @@ -856,15 +926,17 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) bufPos += elementLength; } - if (matchingSubscriber != NULL) { - + if (matchingSubscriber != NULL) + { matchingSubscriber->timeAllowedToLive = timeAllowedToLive; matchingSubscriber->ndsCom = ndsCom; matchingSubscriber->simulation = simulation; - if (matchingSubscriber->dataSetValuesSelfAllocated) { + if (matchingSubscriber->dataSetValuesSelfAllocated) + { /* when confRev changed replaced old data set */ - if ((matchingSubscriber->dataSetValues != NULL) && (matchingSubscriber->confRev != confRev)) { + if ((matchingSubscriber->dataSetValues != NULL) && (matchingSubscriber->confRev != confRev)) + { MmsValue_delete(matchingSubscriber->dataSetValues); matchingSubscriber->dataSetValues = NULL; } @@ -874,14 +946,16 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) if (timestampBufPos) MmsValue_setUtcTimeByBuffer(matchingSubscriber->timestamp, timestampBufPos); - else { + else + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: GOOSE message has no time stamp\n"); MmsValue_setUtcTime(matchingSubscriber->timestamp, 0); } - if (matchingSubscriber->isObserver && matchingSubscriber->dataSetValues != NULL) { + if (matchingSubscriber->isObserver && matchingSubscriber->dataSetValues != NULL) + { MmsValue_delete(matchingSubscriber->dataSetValues); matchingSubscriber->dataSetValues = NULL; } @@ -890,7 +964,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) if (matchingSubscriber->dataSetValues == NULL) matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false); - else { + else + { GooseParseError parseError = parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues); if (parseError != GOOSE_PARSE_ERROR_NO_ERROR) { @@ -900,7 +975,8 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) matchingSubscriber->parseError = parseError; } - if (matchingSubscriber->stNum == stNum) { + if (matchingSubscriber->stNum == stNum) + { if (matchingSubscriber->sqNum >= sqNum) { isValid = false; } @@ -944,13 +1020,18 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes) uint8_t priority = 0; uint16_t vlanId = 0; bool vlanSet = false; + /* check for VLAN tag */ - if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) { + if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) + { priority = buffer[bufPos + 2] & 0xF8 >> 5; vlanId = ((buffer[bufPos + 2] & 0x07) << 8) + buffer[bufPos + 3]; vlanSet = true; bufPos += 4; /* skip VLAN tag */ headerLength += 4; + + if (numbytes < (22 + 4)) + return; } /* check for GOOSE Ethertype */ @@ -980,13 +1061,22 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes) int apduLength = length - 8; - if (numbytes < length + headerLength) { + if (apduLength < 0) + { + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: Invalid length field\n"); + return; + } + + if (numbytes < length + headerLength) + { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Invalid PDU size\n"); return; } - if (DEBUG_GOOSE_SUBSCRIBER) { + if (DEBUG_GOOSE_SUBSCRIBER) + { printf("GOOSE_SUBSCRIBER: GOOSE message:\nGOOSE_SUBSCRIBER: ----------------\n"); printf("GOOSE_SUBSCRIBER: DST-MAC: %02x:%02x:%02x:%02x:%02X:%02X\n", dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5]); @@ -998,7 +1088,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes) /* check if there is an interested subscriber */ LinkedList element = LinkedList_getNext(self->subscriberList); - while (element != NULL) { + while (element) + { GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); if (subscriber->isObserver) @@ -1014,7 +1105,8 @@ parseGooseMessage(GooseReceiver self, uint8_t* buffer, int numbytes) } if (((subscriber->appId == -1) || (subscriber->appId == appId)) && - (!subscriber->dstMacSet || (memcmp(subscriber->dstMac, dstMac,6) == 0))) { + (!subscriber->dstMacSet || (memcmp(subscriber->dstMac, dstMac,6) == 0))) + { subscriberFound = true; break; } @@ -1036,41 +1128,48 @@ gooseReceiverLoop(void *threadParameter) { GooseReceiver self = (GooseReceiver) threadParameter; - if (self->ethSocket) { + if (self->ethSocket) + { EthernetHandleSet handleSet = EthernetHandleSet_new(); EthernetHandleSet_addSocket(handleSet, self->ethSocket); - if (self->running) { - - while (self->running) { - switch (EthernetHandleSet_waitReady(handleSet, 100)) - { - case -1: - if (DEBUG_GOOSE_SUBSCRIBER) - printf("GOOSE_SUBSCRIBER: EhtnernetHandleSet_waitReady() failure\n"); - break; - case 0: - break; - default: - GooseReceiver_tick(self); - } + bool running = true; - if (self->stop) - break; + while (running) + { + switch (EthernetHandleSet_waitReady(handleSet, 100)) + { + case -1: + if (DEBUG_GOOSE_SUBSCRIBER) + printf("GOOSE_SUBSCRIBER: EhtnernetHandleSet_waitReady() failure\n"); + break; + case 0: + break; + default: + GooseReceiver_tick(self); } - GooseReceiver_stopThreadless(self); + if (self->stop) + break; + + running = self->running; } + GooseReceiver_stopThreadless(self); + EthernetHandleSet_destroy(handleSet); } -#if (CONFIG_IEC61850_R_GOOSE == 1) - else if (self->session) { +#if (CONFIG_IEC61850_R_GOOSE == 0) + else if (self->session) + { HandleSet handleSet = Handleset_new(); Handleset_addSocket(handleSet, RSession_getSocket(self->session)); - while (self->running) { + bool running = true; + + while (running) + { switch (Handleset_waitReady(handleSet, 100)) { case -1: @@ -1085,6 +1184,8 @@ gooseReceiverLoop(void *threadParameter) if (self->stop) break; + + running = self->running; } GooseReceiver_stopThreadless(self); @@ -1102,7 +1203,8 @@ void GooseReceiver_start(GooseReceiver self) { #if (CONFIG_MMS_THREADLESS_STACK == 0) - if (GooseReceiver_startThreadless(self)) { + if (GooseReceiver_startThreadless(self)) + { self->thread = Thread_create((ThreadExecutionFunction) gooseReceiverLoop, (void*) self, false); if (self->thread != NULL) { @@ -1160,7 +1262,8 @@ GooseReceiver_stop(GooseReceiver self) void GooseReceiver_destroy(GooseReceiver self) { - if (self) { + if (self) + { #if (CONFIG_MMS_THREADLESS_STACK == 0) if ((self->thread != NULL) && (GooseReceiver_isRunning(self))) GooseReceiver_stop(self); @@ -1185,12 +1288,14 @@ GooseReceiver_startThreadless(GooseReceiver self) { #if (CONFIG_IEC61850_R_GOOSE == 1) if (self->session) { - if (RSession_start(self->session) == R_SESSION_ERROR_OK) { + if (RSession_start(self->session) == R_SESSION_ERROR_OK) + { self->running = true; return (EthernetSocket)1; } - else { + else + { self->running = false; return (EthernetSocket)0; @@ -1204,7 +1309,8 @@ GooseReceiver_startThreadless(GooseReceiver self) else self->ethSocket = Ethernet_createSocket(self->interfaceId, NULL); - if (self->ethSocket != NULL) { + if (self->ethSocket != NULL) + { Ethernet_setProtocolFilter(self->ethSocket, ETH_P_GOOSE); /* set multicast addresses for subscribers */ @@ -1212,14 +1318,17 @@ GooseReceiver_startThreadless(GooseReceiver self) LinkedList element = LinkedList_getNext(self->subscriberList); - while (element != NULL) { + while (element != NULL) + { GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element); - if (subscriber->dstMacSet == false) { + if (subscriber->dstMacSet == false) + { /* no destination MAC address defined -> we have to switch to all multicast mode */ Ethernet_setMode(self->ethSocket, ETHERNET_SOCKET_MODE_ALL_MULTICAST); } - else { + else + { Ethernet_addMulticastAddress(self->ethSocket, subscriber->dstMac); } @@ -1262,18 +1371,20 @@ bool GooseReceiver_tick(GooseReceiver self) { #if (CONFIG_IEC61850_R_GOOSE == 1) - if (self->session) { + if (self->session) + { if (RSession_receiveMessage(self->session, handleSessionPayloadElement, (void*) self) == R_SESSION_ERROR_OK) return true; else return false; } - else { + else + { #endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ - int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH); - if (packetSize > 0) { + if (packetSize > 0) + { parseGooseMessage(self, self->buffer, packetSize); return true; } diff --git a/src/goose/goose_subscriber.c b/src/goose/goose_subscriber.c index 64227127..019c2b7e 100644 --- a/src/goose/goose_subscriber.c +++ b/src/goose/goose_subscriber.c @@ -1,7 +1,7 @@ /* * goose_subscriber.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -40,7 +40,8 @@ GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues) { GooseSubscriber self = (GooseSubscriber) GLOBAL_CALLOC(1, sizeof(struct sGooseSubscriber)); - if (self) { + if (self) + { StringUtils_copyStringMax(self->goCBRef, 130, goCbRef); self->goCBRefLen = strlen(goCbRef); @@ -97,7 +98,8 @@ GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId) void GooseSubscriber_destroy(GooseSubscriber self) { - if (self) { + if (self) + { MmsValue_delete(self->timestamp); if (self->dataSetValuesSelfAllocated) @@ -120,19 +122,19 @@ GooseSubscriber_getAppId(GooseSubscriber self) return self->appId; } -char * +char* GooseSubscriber_getGoId(GooseSubscriber self) { return self->goId; } -char * +char* GooseSubscriber_getGoCbRef(GooseSubscriber self) { return self->goCBRef; } -char * +char* GooseSubscriber_getDataSet(GooseSubscriber self) { return self->datSet; diff --git a/src/iec61850/client/client_report.c b/src/iec61850/client/client_report.c index af12d26a..321532e5 100644 --- a/src/iec61850/client/client_report.c +++ b/src/iec61850/client/client_report.c @@ -3,7 +3,7 @@ * * Client implementation for IEC 61850 reporting. * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -283,14 +283,27 @@ lookupReportHandler(IedConnection self, const char* rcbReference) return NULL; } +static void +uninstallReportHandler(IedConnection self, const char* rcbReference) +{ + ClientReport report = lookupReportHandler(self, rcbReference); + + if (report != NULL) { + LinkedList_remove(self->enabledReports, report); + ClientReport_destroy(report); + } +} + void IedConnection_installReportHandler(IedConnection self, const char* rcbReference, const char* rptId, ReportCallbackFunction handler, void* handlerParameter) { + Semaphore_wait(self->reportHandlerMutex); + ClientReport report = lookupReportHandler(self, rcbReference); if (report != NULL) { - IedConnection_uninstallReportHandler(self, rcbReference); + uninstallReportHandler(self, rcbReference); if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: Removed existing report callback handler for %s\n", rcbReference); @@ -306,8 +319,8 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference, else report->rptId = NULL; - Semaphore_wait(self->reportHandlerMutex); LinkedList_add(self->enabledReports, report); + Semaphore_post(self->reportHandlerMutex); if (DEBUG_IED_CLIENT) @@ -319,12 +332,7 @@ IedConnection_uninstallReportHandler(IedConnection self, const char* rcbReferenc { Semaphore_wait(self->reportHandlerMutex); - ClientReport report = lookupReportHandler(self, rcbReference); - - if (report != NULL) { - LinkedList_remove(self->enabledReports, report); - ClientReport_destroy(report); - } + uninstallReportHandler(self, rcbReference); Semaphore_post(self->reportHandlerMutex); } @@ -367,6 +375,8 @@ IedConnection_triggerGIReport(IedConnection self, IedClientError* error, const c void iedConnection_handleReport(IedConnection self, MmsValue* value) { + Semaphore_wait(self->reportHandlerMutex); + MmsValue* rptIdValue = MmsValue_getElement(value, 0); if ((rptIdValue == NULL) || (MmsValue_getType(rptIdValue) != MMS_VISIBLE_STRING)) { @@ -769,15 +779,14 @@ iedConnection_handleReport(IedConnection self, MmsValue* value) matchingReport->reasonForInclusion[i] = IEC61850_REASON_NOT_INCLUDED; } } - - Semaphore_wait(self->reportHandlerMutex); if (matchingReport->callback != NULL) matchingReport->callback(matchingReport->callbackParameter, matchingReport); +exit_function: + Semaphore_post(self->reportHandlerMutex); -exit_function: return; } diff --git a/src/iec61850/client/client_report_control.c b/src/iec61850/client/client_report_control.c index 6affd50e..65967cdb 100644 --- a/src/iec61850/client/client_report_control.c +++ b/src/iec61850/client/client_report_control.c @@ -528,39 +528,44 @@ readObjectHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, MmsV IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_GetRCBValuesHandler handler = (IedConnection_GetRCBValuesHandler) call->callback; ClientReportControlBlock updateRcb = (ClientReportControlBlock) call->specificParameter; char* rcbReference = (char*) call->specificParameter2.pointer; - - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), NULL); } - else { - - if (value == NULL) { + else + { + if (value == NULL) + { handler(invokeId, call->callbackParameter, IED_ERROR_OBJECT_DOES_NOT_EXIST, NULL); } - else { - if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) { + else + { + if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) + { if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: getRCBValues returned data-access-error!\n"); handler(invokeId, call->callbackParameter, iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)), NULL); } - else { - + else + { ClientReportControlBlock returnRcb = updateRcb; if (returnRcb == NULL) returnRcb = ClientReportControlBlock_create(rcbReference); - if (clientReportControlBlock_updateValues(returnRcb, value)) { + if (clientReportControlBlock_updateValues(returnRcb, value)) + { handler(invokeId, call->callbackParameter, IED_ERROR_OK, returnRcb); } - else { + else + { if (DEBUG_IED_CLIENT) printf("DEBUG_IED_CLIENT: getRCBValues returned wrong type!\n"); @@ -569,19 +574,18 @@ readObjectHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, MmsV if (updateRcb == NULL) ClientReportControlBlock_destroy(returnRcb); } - } MmsValue_delete(value); } - } GLOBAL_FREEMEM(rcbReference); iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -598,7 +602,8 @@ IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const char* domainName = MmsMapping_getMmsDomainFromObjectReference(rcbReference, domainId); - if (domainName == NULL) { + if (domainName == NULL) + { *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; return 0; } @@ -608,7 +613,8 @@ IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -627,7 +633,8 @@ IedConnection_getRCBValuesAsync(IedConnection self, IedClientError* error, const *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { GLOBAL_FREEMEM(call->specificParameter2.pointer); iedConnection_releaseOutstandingCall(self, call); return 0; diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index d64fc595..23ccf6ff 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -1,7 +1,7 @@ /* * ied_connection.c * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -33,7 +33,6 @@ #define DEFAULT_CONNECTION_TIMEOUT 10000 #define DATA_SET_MAX_NAME_LENGTH 64 /* is 32 according to standard! */ -#define OUTSTANDING_CALLS 12 typedef struct sICLogicalDevice { @@ -47,12 +46,107 @@ struct sClientDataSet MmsValue* dataSetValues; /* MmsValue instance of type MMS_ARRAY */ }; -struct sFileDirectoryEntry { +struct sFileDirectoryEntry +{ char* fileName; uint32_t fileSize; uint64_t lastModified; }; +const char* +IedClientError_toString(IedClientError err) +{ + switch (err) + { + case IED_ERROR_OK: + return "ok"; + + case IED_ERROR_NOT_CONNECTED: + return "not-connected"; + + case IED_ERROR_ALREADY_CONNECTED: + return "already-connected"; + + case IED_ERROR_CONNECTION_LOST: + return "connection-lost"; + + case IED_ERROR_SERVICE_NOT_SUPPORTED: + return "service-not-supported"; + + case IED_ERROR_CONNECTION_REJECTED: + return "connection-rejected"; + + case IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED: + return "outstanding-call-limit-reached"; + + case IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT: + return "invalid-argument"; + + case IED_ERROR_ENABLE_REPORT_FAILED_DATASET_MISMATCH: + return "enable-report-failed-due-to-dataset-mismatch"; + + case IED_ERROR_OBJECT_REFERENCE_INVALID: + return "object-reference-invalid"; + + case IED_ERROR_UNEXPECTED_VALUE_RECEIVED: + return "unexpected-value-received"; + + case IED_ERROR_TIMEOUT: + return "timeout"; + + case IED_ERROR_ACCESS_DENIED: + return "access-denied"; + + case IED_ERROR_OBJECT_DOES_NOT_EXIST: + return "object-does-not-exist"; + + case IED_ERROR_OBJECT_EXISTS: + return "object-exists"; + + case IED_ERROR_OBJECT_ACCESS_UNSUPPORTED: + return "object-access-unsupported"; + + case IED_ERROR_TYPE_INCONSISTENT: + return "type-inconsistent"; + + case IED_ERROR_TEMPORARILY_UNAVAILABLE: + return "temporary-unavailable"; + + case IED_ERROR_OBJECT_UNDEFINED: + return "object-undefined"; + + case IED_ERROR_INVALID_ADDRESS: + return "invalid-address"; + + case IED_ERROR_HARDWARE_FAULT: + return "hardware-fault"; + + case IED_ERROR_TYPE_UNSUPPORTED: + return "type-unsupported"; + + case IED_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT: + return "object-attribute-inconsistent"; + + case IED_ERROR_OBJECT_VALUE_INVALID: + return "object-value-invalid"; + + case IED_ERROR_OBJECT_INVALIDATED: + return "object-invalidated"; + + case IED_ERROR_MALFORMED_MESSAGE: + return "malformed-message"; + + case IED_ERROR_OBJECT_CONSTRAINT_CONFLICT: + return "object-constraint-conflict"; + + case IED_ERROR_SERVICE_NOT_IMPLEMENTED: + return "service-not-implemented"; + + default: + return "unknown-error"; + } +} + IedClientError iedConnection_mapMmsErrorToIedError(MmsError mmsError) { @@ -177,8 +271,10 @@ iedConnection_allocateOutstandingCall(IedConnection self) int i = 0; - for (i = 0; i < OUTSTANDING_CALLS; i++) { - if (self->outstandingCalls[i].used == false) { + for (i = 0; i < self->maxOutstandingCalled; i++) + { + if (self->outstandingCalls[i].used == false) + { self->outstandingCalls[i].used = true; call = &(self->outstandingCalls[i]); break; @@ -209,8 +305,10 @@ iedConnection_lookupOutstandingCall(IedConnection self, uint32_t invokeId) int i = 0; - for (i = 0; i < OUTSTANDING_CALLS; i++) { - if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId)) { + for (i = 0; i < self->maxOutstandingCalled; i++) + { + if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId)) + { call = &(self->outstandingCalls[i]); break; } @@ -618,7 +716,8 @@ createNewConnectionObject(TLSConfiguration tlsConfig, bool useThreads) self->reportHandlerMutex = Semaphore_create(1); self->outstandingCallsLock = Semaphore_create(1); - self->outstandingCalls = (IedConnectionOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sIedConnectionOutstandingCall)); + self->maxOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + self->outstandingCalls = (IedConnectionOutstandingCall) GLOBAL_CALLOC(CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED, sizeof(struct sIedConnectionOutstandingCall)); self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; @@ -663,6 +762,29 @@ IedConnection_setLocalAddress(IedConnection self, const char* localIpAddress, in IsoConnectionParameters_setLocalTcpParameters(isoP, localIpAddress, localPort); } +void +IedConnection_setMaxOutstandingCalls(IedConnection self, int calling, int called) +{ + if (calling < 1) + calling = 1; + + if (called < 1) + called = 1; + + if (self->outstandingCalls) + { + GLOBAL_FREEMEM(self->outstandingCalls); + } + + self->maxOutstandingCalled = called; + self->outstandingCalls = (IedConnectionOutstandingCall)GLOBAL_CALLOC(called, sizeof(struct sIedConnectionOutstandingCall)); + + if (self->connection) + { + MmsConnnection_setMaxOutstandingCalls(self->connection, calling, called); + } +} + void IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs) { @@ -672,7 +794,8 @@ IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs) void IedConnection_setRequestTimeout(IedConnection self, uint32_t timeoutInMs) { - if (self->connection) { + if (self->connection) + { MmsConnection_setRequestTimeout(self->connection, timeoutInMs); } } @@ -855,7 +978,7 @@ IedConnection_destroy(IedConnection self) GLOBAL_FREEMEM(self->outstandingCalls); - LinkedList_destroyStatic(self->clientControls); + LinkedList_destroyDeep(self->clientControls, (LinkedListValueDeleteFunction)ControlObjectClient_destroy); Semaphore_destroy(self->clientControlsLock); Semaphore_destroy(self->outstandingCallsLock); @@ -1027,7 +1150,8 @@ IedConnection_getServerDirectoryAsync(IedConnection self, IedClientError* error, MmsConnection_getDomainNamesAsync(self->connection, &(call->invokeId), &err, continueAfter, result, getNameListHandler, self); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(err); iedConnection_releaseOutstandingCall(self, call); @@ -1059,7 +1183,8 @@ IedConnection_getLogicalDeviceVariablesAsync(IedConnection self, IedClientError* MmsConnection_getDomainVariableNamesAsync(self->connection, &(call->invokeId), &err, ldName, continueAfter, result, getNameListHandler, self); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(err); iedConnection_releaseOutstandingCall(self, call); @@ -1091,7 +1216,8 @@ IedConnection_getLogicalDeviceDataSetsAsync(IedConnection self, IedClientError* MmsConnection_getDomainVariableListNamesAsync(self->connection, &(call->invokeId), &err, ldName, continueAfter, result, getNameListHandler, self); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(err); iedConnection_releaseOutstandingCall(self, call); @@ -1112,15 +1238,16 @@ readObjectHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, MmsV IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_ReadObjectHandler handler = (IedConnection_ReadObjectHandler) call->callback; handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), value); iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -1141,14 +1268,16 @@ IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const c domainId = MmsMapping_getMmsDomainFromObjectReference(objRef, domainIdBuffer); itemId = MmsMapping_createMmsVariableNameFromObjectReference(objRef, fc, itemIdBuffer); - if ((domainId == NULL) || (itemId == NULL)) { + if ((domainId == NULL) || (itemId == NULL)) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -1161,15 +1290,18 @@ IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const c /* check if item ID contains an array "(..)" */ char* brace = strchr(itemId, '('); - if (brace) { + if (brace) + { char* secondBrace = strchr(brace, ')'); - if (secondBrace) { + if (secondBrace) + { char* endPtr; int index = (int) strtol(brace + 1, &endPtr, 10); - if (endPtr == secondBrace) { + if (endPtr == secondBrace) + { char* component = NULL; if (strlen(secondBrace + 1) > 1) @@ -1188,8 +1320,8 @@ IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const c else MmsConnection_readVariableAsync(self->connection, &(call->invokeId), &err, domainId, itemId, readObjectHandlerInternal, self); - if ((err != MMS_ERROR_NONE) || (*error != IED_ERROR_OK)) { - + if ((err != MMS_ERROR_NONE) || (*error != IED_ERROR_OK)) + { if (err != MMS_ERROR_NONE) { *error = iedConnection_mapMmsErrorToIedError(err); } @@ -1202,7 +1334,6 @@ IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const c return call->invokeId; } - MmsValue* IedConnection_readObject(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) @@ -1217,7 +1348,8 @@ IedConnection_readObject(IedConnection self, IedClientError* error, const char* domainId = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainIdBuffer); itemId = MmsMapping_createMmsVariableNameFromObjectReference(objectReference, fc, itemIdBuffer); - if ((domainId == NULL) || (itemId == NULL)) { + if ((domainId == NULL) || (itemId == NULL)) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -1227,15 +1359,18 @@ IedConnection_readObject(IedConnection self, IedClientError* error, const char* /* check if item ID contains an array "(..)" */ char* brace = strchr(itemId, '('); - if (brace) { + if (brace) + { char* secondBrace = strchr(brace, ')'); - if (secondBrace) { + if (secondBrace) + { char* endPtr; int index = (int) strtol(brace + 1, &endPtr, 10); - if (endPtr == secondBrace) { + if (endPtr == secondBrace) + { char* component = NULL; if (strlen(secondBrace + 1) > 1) @@ -1269,10 +1404,12 @@ IedConnection_readBooleanValue(IedConnection self, IedClientError* error, const bool retVal = false; - if (value != NULL) { + if (value != NULL) + { if (MmsValue_getType(value) == MMS_BOOLEAN) retVal = MmsValue_getBoolean(value); - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1292,10 +1429,12 @@ IedConnection_readFloatValue(IedConnection self, IedClientError* error, const ch float retVal = 0.f; - if (value != NULL) { + if (value != NULL) + { if (MmsValue_getType(value) == MMS_FLOAT) retVal = MmsValue_toFloat(value); - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1315,10 +1454,12 @@ IedConnection_readStringValue(IedConnection self, IedClientError* error, const c char* retVal = NULL; - if (value != NULL) { + if (value != NULL) + { if ((MmsValue_getType(value) == MMS_VISIBLE_STRING) || (MmsValue_getType(value) == MMS_STRING)) retVal = StringUtils_copyString(MmsValue_toString(value)); - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1338,10 +1479,12 @@ IedConnection_readInt32Value(IedConnection self, IedClientError* error, const ch int32_t retVal = 0; - if (value != NULL) { + if (value != NULL) + { if ((MmsValue_getType(value) == MMS_INTEGER) || (MmsValue_getType(value) == MMS_UNSIGNED)) retVal = MmsValue_toInt32(value); - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1361,10 +1504,12 @@ IedConnection_readUnsigned32Value(IedConnection self, IedClientError* error, con uint32_t retVal = 0; - if (value != NULL) { + if (value != NULL) + { if ((MmsValue_getType(value) == MMS_INTEGER) || (MmsValue_getType(value) == MMS_UNSIGNED)) retVal = MmsValue_toUint32(value); - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1384,10 +1529,12 @@ IedConnection_readInt64Value(IedConnection self, IedClientError* error, const ch int64_t retVal = 0; - if (value != NULL) { + if (value != NULL) + { if ((MmsValue_getType(value) == MMS_INTEGER) || (MmsValue_getType(value) == MMS_UNSIGNED)) retVal = MmsValue_toInt64(value); - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1408,15 +1555,17 @@ IedConnection_readTimestampValue(IedConnection self, IedClientError* error, cons Timestamp* retVal = timeStamp; - if (value != NULL) { - if (MmsValue_getType(value) == MMS_UTC_TIME) { - + if (value != NULL) + { + if (MmsValue_getType(value) == MMS_UTC_TIME) + { if (retVal == NULL) retVal = (Timestamp*) GLOBAL_MALLOC(sizeof(Timestamp)); memcpy(retVal->val, value->value.utcTime, 8); } - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1437,12 +1586,13 @@ IedConnection_readQualityValue(IedConnection self, IedClientError* error, const Quality quality = QUALITY_VALIDITY_GOOD; - if (value != NULL) { - + if (value != NULL) + { if ((MmsValue_getType(value) == MMS_BIT_STRING) && (MmsValue_getBitStringSize(value) == 13)) { quality = Quality_fromMmsValue(value); } - else { + else + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) *error = iedConnection_mapDataAccessErrorToIedError(MmsValue_getDataAccessError(value)); else @@ -1469,7 +1619,8 @@ IedConnection_writeObject(IedConnection self, IedClientError* error, const char* domainId = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainIdBuffer); itemId = MmsMapping_createMmsVariableNameFromObjectReference(objectReference, fc, itemIdBuffer); - if ((domainId == NULL) || (itemId == NULL)) { + if ((domainId == NULL) || (itemId == NULL)) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return; } @@ -1479,15 +1630,18 @@ IedConnection_writeObject(IedConnection self, IedClientError* error, const char* /* check if item ID contains an array "(..)" */ char* brace = strchr(itemId, '('); - if (brace) { + if (brace) + { char* secondBrace = strchr(brace, ')'); - if (secondBrace) { + if (secondBrace) + { char* endPtr; int index = (int) strtol(brace + 1, &endPtr, 10); - if (endPtr == secondBrace) { + if (endPtr == secondBrace) + { char* component = NULL; if (strlen(secondBrace + 1) > 1) @@ -1505,7 +1659,8 @@ IedConnection_writeObject(IedConnection self, IedClientError* error, const char* else *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; } - else { + else + { MmsConnection_writeVariable(self->connection, &mmsError, domainId, itemId, value); *error = iedConnection_mapMmsErrorToIedError(mmsError); @@ -1519,8 +1674,8 @@ writeVariableHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataAc IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler) call->callback; IedClientError iedError = iedConnection_mapMmsErrorToIedError(err); @@ -1532,7 +1687,8 @@ writeVariableHandler(uint32_t invokeId, void* parameter, MmsError err, MmsDataAc iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -1553,14 +1709,16 @@ IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const domainId = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainIdBuffer); itemId = MmsMapping_createMmsVariableNameFromObjectReference(objectReference, fc, itemIdBuffer); - if ((domainId == NULL) || (itemId == NULL)) { + if ((domainId == NULL) || (itemId == NULL)) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -1574,7 +1732,8 @@ IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const /* check if item ID contains an array "(..)" */ char* brace = strchr(itemId, '('); - if (brace) { + if (brace) + { char* secondBrace = strchr(brace, ')'); if (secondBrace) { @@ -1582,7 +1741,8 @@ IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const int index = (int) strtol(brace + 1, &endPtr, 10); - if (endPtr == secondBrace) { + if (endPtr == secondBrace) + { char* component = NULL; if (strlen(secondBrace + 1) > 1) @@ -1601,13 +1761,15 @@ IedConnection_writeObjectAsync(IedConnection self, IedClientError* error, const else *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; } - else { + else + { MmsConnection_writeVariableAsync(self->connection, &(call->invokeId), &err, domainId, itemId, value, writeVariableHandler, self); *error = iedConnection_mapMmsErrorToIedError(err); } - if (*error != IED_ERROR_OK) { + if (*error != IED_ERROR_OK) + { iedConnection_releaseOutstandingCall(self, call); return 0; } @@ -1648,7 +1810,6 @@ IedConnection_writeInt32Value(IedConnection self, IedClientError* error, const c IedConnection_writeObject(self, error, objectReference, fc, &mmsValue); } - void IedConnection_writeUnsigned32Value(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc, uint32_t value) @@ -1717,9 +1878,10 @@ IedConnection_getDeviceModelFromServer(IedConnection self, IedClientError* error LinkedList logicalDeviceNames = MmsConnection_getDomainNames(self->connection, &mmsError); - if (logicalDeviceNames != NULL) { - - if (self->logicalDevices != NULL) { + if (logicalDeviceNames) + { + if (self->logicalDevices) + { LinkedList_destroyDeep(self->logicalDevices, (LinkedListValueDeleteFunction) ICLogicalDevice_destroy); self->logicalDevices = NULL; } @@ -1728,20 +1890,23 @@ IedConnection_getDeviceModelFromServer(IedConnection self, IedClientError* error LinkedList logicalDevices = LinkedList_create(); - while (logicalDevice != NULL) { + while (logicalDevice) + { char* name = (char*) logicalDevice->data; LinkedList variables = MmsConnection_getDomainVariableNames(self->connection, &mmsError, name); - if (variables != NULL) { + if (variables) + { ICLogicalDevice* icLogicalDevice = ICLogicalDevice_create(name); ICLogicalDevice_setVariableList(icLogicalDevice, variables); LinkedList_add(logicalDevices, icLogicalDevice); } - else { + else + { if (error) *error = iedConnection_mapMmsErrorToIedError(mmsError); break; @@ -1750,10 +1915,12 @@ IedConnection_getDeviceModelFromServer(IedConnection self, IedClientError* error logicalDevice = LinkedList_getNext(logicalDevice); } - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { LinkedList_destroyDeep(logicalDevices, (LinkedListValueDeleteFunction) ICLogicalDevice_destroy); } - else { + else + { self->logicalDevices = logicalDevices; } @@ -1768,19 +1935,22 @@ IedConnection_getLogicalDeviceList(IedConnection self, IedClientError* error) { *error = IED_ERROR_OK; - if (self->logicalDevices == NULL) { + if (self->logicalDevices == NULL) + { IedConnection_getDeviceModelFromServer(self, error); if (*error != IED_ERROR_OK) return NULL; } - if (self->logicalDevices != NULL) { + if (self->logicalDevices) + { LinkedList logicalDevice = LinkedList_getNext(self->logicalDevices); LinkedList logicalDeviceList = LinkedList_create(); - while (logicalDevice != NULL) { + while (logicalDevice) + { ICLogicalDevice* icLogicalDevice = (ICLogicalDevice*) logicalDevice->data; char* logicalDeviceName = StringUtils_copyString(icLogicalDevice->name); @@ -1790,11 +1960,16 @@ IedConnection_getLogicalDeviceList(IedConnection self, IedClientError* error) logicalDevice = LinkedList_getNext(logicalDevice); } - *error = IED_ERROR_OK; + if (error) + *error = IED_ERROR_OK; + return logicalDeviceList; } - else { - *error = IED_ERROR_UNKNOWN; + else + { + if (error) + *error = IED_ERROR_UNKNOWN; + return NULL; } } @@ -1822,19 +1997,22 @@ IedConnection_getFileDirectory(IedConnection self, IedClientError* error, const bool moreFollows = false; - do { + do + { moreFollows = MmsConnection_getFileDirectory(self->connection, &mmsError, directoryName, continueAfter, mmsFileDirectoryHandler, fileNames); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); LinkedList_destroyDeep(fileNames, (LinkedListValueDeleteFunction) FileDirectoryEntry_destroy); return NULL; } - if (moreFollows) { + if (moreFollows) + { FileDirectoryEntry lastDirectoryEntry = (FileDirectoryEntry) LinkedList_getData(LinkedList_getLastElement(fileNames)); @@ -1859,7 +2037,8 @@ IedConnection_getFileDirectoryEx(IedConnection self, IedClientError* error, cons bool moreFollowsInternal = MmsConnection_getFileDirectory(self->connection, &mmsError, directoryName, continueAfter, mmsFileDirectoryHandler, fileNames); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); LinkedList_destroyDeep(fileNames, (LinkedListValueDeleteFunction) FileDirectoryEntry_destroy); @@ -1880,9 +2059,10 @@ fileDirectoryHandlerEx(uint32_t invokeId, void* parameter, MmsError err, char* f IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - - if (call->specificParameter2.getFileDirectory.cont) { + if (call) + { + if (call->specificParameter2.getFileDirectory.cont) + { IedConnection_FileDirectoryEntryHandler handler = (IedConnection_FileDirectoryEntryHandler) call->callback; call->specificParameter2.getFileDirectory.cont = @@ -1892,7 +2072,8 @@ fileDirectoryHandlerEx(uint32_t invokeId, void* parameter, MmsError err, char* f if (filename == NULL) iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -1906,7 +2087,8 @@ IedConnection_getFileDirectoryAsyncEx(IedConnection self, IedClientError* error, IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -1920,7 +2102,8 @@ IedConnection_getFileDirectoryAsyncEx(IedConnection self, IedClientError* error, *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); return 0; } @@ -1960,7 +2143,8 @@ IedConnection_getFile(IedConnection self, IedClientError* error, const char* fil int32_t frsmId = MmsConnection_fileOpen(self->connection, &mmsError, fileName, 0, &fileSize, NULL); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); return 0; } @@ -1971,17 +2155,20 @@ IedConnection_getFile(IedConnection self, IedClientError* error, const char* fil clientFileReadHandler.retVal = true; clientFileReadHandler.byteReceived = 0; - while (true) { + while (true) + { bool moreFollows = MmsConnection_fileRead(self->connection, &mmsError, frsmId, mmsFileReadHandler, &clientFileReadHandler); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); return 0; } - if (clientFileReadHandler.retVal == false) { + if (clientFileReadHandler.retVal == false) + { *error = IED_ERROR_UNKNOWN; break; } @@ -2002,7 +2189,8 @@ mmsConnectionFileCloseHandler (uint32_t invokeId, void* parameter, MmsError mmsE { (void)success; - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: failed to close file error: %i (mms-error: %i)\n", iedConnection_mapMmsErrorToIedError(mmsError), mmsError); } @@ -2011,10 +2199,12 @@ mmsConnectionFileCloseHandler (uint32_t invokeId, void* parameter, MmsError mmsE IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { + if (call) + { iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -2028,46 +2218,53 @@ mmsConnectionFileReadHandler (uint32_t invokeId, void* parameter, MmsError mmsEr IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_GetFileAsyncHandler handler = (IedConnection_GetFileAsyncHandler) call->callback; - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError); handler(call->specificParameter2.getFileInfo.originalInvokeId, call->callbackParameter, err, invokeId, NULL, 0, false); - if (mmsError != MMS_ERROR_SERVICE_TIMEOUT) { + if (mmsError != MMS_ERROR_SERVICE_TIMEOUT) + { /* close file */ MmsConnection_fileCloseAsync(self->connection, &(call->invokeId), &mmsError, frsmId, mmsConnectionFileCloseHandler, self); if (mmsError != MMS_ERROR_NONE) iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: getFile timeout -> stop download\n"); iedConnection_releaseOutstandingCall(self, call); } } - else { + else + { bool cont = handler(call->specificParameter2.getFileInfo.originalInvokeId, call->callbackParameter, IED_ERROR_OK, invokeId, buffer, byteReceived, moreFollows); - if ((moreFollows == false) || (cont == false)) { + if ((moreFollows == false) || (cont == false)) + { /* close file */ MmsConnection_fileCloseAsync(self->connection, &(call->invokeId), &mmsError, frsmId, mmsConnectionFileCloseHandler, self); if (mmsError != MMS_ERROR_NONE) iedConnection_releaseOutstandingCall(self, call); } - else { + else + { /* send next read request */ MmsConnection_fileReadAsync(self->connection, &(call->invokeId), &mmsError, frsmId, mmsConnectionFileReadHandler, self); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError); handler(invokeId, call->callbackParameter, err, invokeId, NULL, 0, false); @@ -2075,16 +2272,16 @@ mmsConnectionFileReadHandler (uint32_t invokeId, void* parameter, MmsError mmsEr /* close file */ MmsConnection_fileCloseAsync(self->connection, &(call->invokeId), &mmsError, frsmId, mmsConnectionFileCloseHandler, self); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); } - } } } - } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -2100,24 +2297,27 @@ mmsConnectionFileOpenHandler (uint32_t invokeId, void* parameter, MmsError mmsEr IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_GetFileAsyncHandler handler = (IedConnection_GetFileAsyncHandler) call->callback; call->specificParameter2.getFileInfo.originalInvokeId = invokeId; - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError); handler(invokeId, call->callbackParameter, err, invokeId, NULL, 0, false); iedConnection_releaseOutstandingCall(self, call); } - else { + else + { call->specificParameter2.getFileInfo.originalInvokeId = invokeId; MmsConnection_fileReadAsync(self->connection, &(call->invokeId), &mmsError, frsmId, mmsConnectionFileReadHandler, self); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError); handler(invokeId, call->callbackParameter, err, invokeId, NULL, 0, false); @@ -2129,9 +2329,9 @@ mmsConnectionFileOpenHandler (uint32_t invokeId, void* parameter, MmsError mmsEr iedConnection_releaseOutstandingCall(self, call); } } - } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -2146,7 +2346,8 @@ IedConnection_getFileAsync(IedConnection self, IedClientError* error, const char IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -2158,7 +2359,8 @@ IedConnection_getFileAsync(IedConnection self, IedClientError* error, const char *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); return 0; } @@ -2200,14 +2402,16 @@ deleteFileAndSetFileHandler (uint32_t invokeId, void* parameter, MmsError mmsErr IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { + if (call) + { IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler) call->callback; handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(mmsError)); iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -2221,7 +2425,8 @@ IedConnection_setFileAsync(IedConnection self, IedClientError* error, const char IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -2233,7 +2438,8 @@ IedConnection_setFileAsync(IedConnection self, IedClientError* error, const char *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); return 0; } @@ -2273,7 +2479,8 @@ IedConnection_deleteFileAsync(IedConnection self, IedClientError* error, const c *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); return 0; } @@ -2305,15 +2512,18 @@ IedConnection_getLogicalDeviceDirectory(IedConnection self, IedClientError* erro LinkedList logicalDevice = LinkedList_getNext(self->logicalDevices); - while (logicalDevice != NULL) { + while (logicalDevice) + { ICLogicalDevice* device = (ICLogicalDevice*) logicalDevice->data; - if (strcmp(device->name, logicalDeviceName) == 0) { + if (strcmp(device->name, logicalDeviceName) == 0) + { LinkedList logicalNodeNames = LinkedList_create(); LinkedList variable = LinkedList_getNext(device->variables); - while (variable != NULL) { + while (variable) + { char* variableName = (char*) variable->data; if (strchr(variableName, '$') == NULL) @@ -2338,7 +2548,8 @@ addToStringSet(LinkedList set, char* string) { LinkedList element = set; - while (LinkedList_getNext(element) != NULL) { + while (LinkedList_getNext(element) != NULL) + { if (strcmp((char*) LinkedList_getNext(element)->data, string) == 0) return false; @@ -2354,21 +2565,25 @@ addVariablesWithFc(char* fc, char* lnName, LinkedList variables, LinkedList lnDi { LinkedList variable = LinkedList_getNext(variables); - while (variable != NULL) { + while (variable) + { char* variableName = (char*) variable->data; char* fcPos = strchr(variableName, '$'); - if (fcPos != NULL) { + if (fcPos != NULL) + { if (memcmp(fcPos + 1, fc, 2) != 0) goto next_element; int lnNameLen = (int)(fcPos - variableName); - if (strncmp(variableName, lnName, lnNameLen) == 0) { + if (strncmp(variableName, lnName, lnNameLen) == 0) + { char* fcEndPos = strchr(fcPos + 1, '$'); - if (fcEndPos != NULL) { + if (fcEndPos != NULL) + { char* nameEndPos = strchr(fcEndPos + 1, '$'); if (nameEndPos == NULL) @@ -2393,7 +2608,8 @@ getLogicalNodeDirectoryLogs(IedConnection self, IedClientError* error, const cha LinkedList journals = MmsConnection_getDomainJournals(mmsCon, &mmsError, logicalDeviceName); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); return NULL; } @@ -2402,17 +2618,19 @@ getLogicalNodeDirectoryLogs(IedConnection self, IedClientError* error, const cha LinkedList journal = LinkedList_getNext(journals); - while (journal != NULL) { - + while (journal) + { char* journalName = (char*) LinkedList_getData(journal); char* logName = strchr(journalName, '$'); - if (logName != NULL) { + if (logName) + { logName[0] = 0; logName += 1; - if (strcmp(journalName, logicalNodeName) == 0) { + if (strcmp(journalName, logicalNodeName) == 0) + { char* log = StringUtils_copyString(logName); LinkedList_add(logs, (void*) log); } @@ -2436,7 +2654,8 @@ getLogicalNodeDirectoryDataSets(IedConnection self, IedClientError* error, const LinkedList dataSets = MmsConnection_getDomainVariableListNames(mmsCon, &mmsError, logicalDeviceName); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); return NULL; } @@ -2445,16 +2664,19 @@ getLogicalNodeDirectoryDataSets(IedConnection self, IedClientError* error, const LinkedList dataSet = LinkedList_getNext(dataSets); - while (dataSet != NULL) { + while (dataSet) + { char* dataSetName = (char*) LinkedList_getData(dataSet); char* lnDataSetName = strchr(dataSetName, '$'); - if (lnDataSetName != NULL) { + if (lnDataSetName) + { lnDataSetName[0] = 0; lnDataSetName += 1; - if (strcmp(dataSetName, logicalNodeName) == 0) { + if (strcmp(dataSetName, logicalNodeName) == 0) + { char* lnDataSet = StringUtils_copyString(lnDataSetName); LinkedList_add(lnDataSets, (void*) lnDataSet); } @@ -2474,7 +2696,8 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, { *error = IED_ERROR_OK; - if (strlen(logicalNodeReference) > 129) { + if (strlen(logicalNodeReference) > 129) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2485,7 +2708,8 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, char* ldSep = strchr(lnRefCopy, '/'); - if (ldSep == NULL) { + if (ldSep == NULL) + { *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; return NULL; } @@ -2514,10 +2738,12 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, ICLogicalDevice* ld = NULL; - while (device != NULL) { + while (device) + { ICLogicalDevice* ldCandidate = (ICLogicalDevice*) device->data; - if (strcmp(logicalDeviceName, ldCandidate->name) == 0) { + if (strcmp(logicalDeviceName, ldCandidate->name) == 0) + { ld = ldCandidate; break; } @@ -2525,25 +2751,28 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, device = LinkedList_getNext(device); } - if (ld == NULL) { + if (ld == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } LinkedList lnDirectory = LinkedList_create(); - switch (acsiClass) { - + switch (acsiClass) + { case ACSI_CLASS_DATA_OBJECT: { LinkedList variable = LinkedList_getNext(ld->variables); - while (variable != NULL) { + while (variable) + { char* variableName = (char*) variable->data; char* fcPos = strchr(variableName, '$'); - if (fcPos != NULL) { + if (fcPos) + { if (memcmp(fcPos + 1, "RP", 2) == 0) goto next_element; @@ -2555,13 +2784,16 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, int lnNameLen = (int)(fcPos - variableName); - if (strncmp(variableName, logicalNodeName, lnNameLen) == 0) { + if (strncmp(variableName, logicalNodeName, lnNameLen) == 0) + { char* fcEndPos = strchr(fcPos + 1, '$'); - if (fcEndPos != NULL) { + if (fcEndPos) + { char* nameEndPos = strchr(fcEndPos + 1, '$'); - if (nameEndPos == NULL) { + if (nameEndPos == NULL) + { char* dataObjectName = StringUtils_copyString(fcEndPos + 1); if (!addToStringSet(lnDirectory, dataObjectName)) @@ -2582,7 +2814,8 @@ IedConnection_getLogicalNodeDirectory(IedConnection self, IedClientError* error, { LinkedList variable = LinkedList_getNext(ld->variables); - while (variable != NULL) { + while (variable) + { char* variableName = (char*) variable->data; if (strcmp(variableName, "LLN0$SP$SGCB") == 0) @@ -2625,7 +2858,8 @@ IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, { *error = IED_ERROR_OK; - if (strlen(logicalNodeReference) > 129) { + if (strlen(logicalNodeReference) > 129) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2642,7 +2876,8 @@ IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, char* ldSep = strchr(lnRefCopy, '/'); - if (ldSep == NULL) { + if (ldSep == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2659,10 +2894,12 @@ IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, ICLogicalDevice* ld = NULL; - while (device != NULL) { + while (device) + { ICLogicalDevice* ldCandidate = (ICLogicalDevice*) device->data; - if (strcmp(logicalDeviceName, ldCandidate->name) == 0) { + if (strcmp(logicalDeviceName, ldCandidate->name) == 0) + { ld = ldCandidate; break; } @@ -2670,7 +2907,8 @@ IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, device = LinkedList_getNext(device); } - if (ld == NULL) { + if (ld == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2682,15 +2920,18 @@ IedConnection_getLogicalNodeVariables(IedConnection self, IedClientError* error, LinkedList lnDirectory = LinkedList_create(); - while (variable != NULL) { + while (variable) + { char* variableName = (char*) variable->data; char* fcPos = strchr(variableName, '$'); - if (fcPos != NULL) { + if (fcPos) + { int lnNameLen = (int)(fcPos - variableName); - if (strncmp(variableName, logicalNodeName, lnNameLen) == 0) { + if (strncmp(variableName, logicalNodeName, lnNameLen) == 0) + { LinkedList_add(lnDirectory, StringUtils_copyString(fcPos + 1)); } } @@ -2708,7 +2949,8 @@ getDataDirectory(IedConnection self, IedClientError* error, { *error = IED_ERROR_OK; - if (strlen(dataReference) > 129) { + if (strlen(dataReference) > 129) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2733,7 +2975,8 @@ getDataDirectory(IedConnection self, IedClientError* error, char* logicalNodeNameEnd = strchr(logicalNodeName, '.'); - if (logicalNodeNameEnd == NULL) { + if (logicalNodeNameEnd == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2744,7 +2987,8 @@ getDataDirectory(IedConnection self, IedClientError* error, int dataNamePartLen = (int)strlen(dataNamePart); - if (dataNamePartLen < 1) { + if (dataNamePartLen < 1) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2757,10 +3001,12 @@ getDataDirectory(IedConnection self, IedClientError* error, ICLogicalDevice* ld = NULL; - while (device != NULL) { + while (device) + { ICLogicalDevice* ldCandidate = (ICLogicalDevice*) device->data; - if (strcmp(logicalDeviceName, ldCandidate->name) == 0) { + if (strcmp(logicalDeviceName, ldCandidate->name) == 0) + { ld = ldCandidate; break; } @@ -2768,7 +3014,8 @@ getDataDirectory(IedConnection self, IedClientError* error, device = LinkedList_getNext(device); } - if (ld == NULL) { + if (ld == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2777,18 +3024,20 @@ getDataDirectory(IedConnection self, IedClientError* error, LinkedList dataDirectory = LinkedList_create(); - while (variable != NULL) { + while (variable) + { char* variableName = (char*) variable->data; char* fcPos = strchr(variableName, '$'); - if (fcPos != NULL) { + if (fcPos) + { int lnNameLen = (int)(fcPos - variableName); - if (logicalNodeNameLen == lnNameLen) { - - if (memcmp(variableName, logicalNodeName, lnNameLen) == 0) { - + if (logicalNodeNameLen == lnNameLen) + { + if (memcmp(variableName, logicalNodeName, lnNameLen) == 0) + { /* ok we are in the correct logical node */ /* skip FC */ @@ -2804,10 +3053,10 @@ getDataDirectory(IedConnection self, IedClientError* error, if (remainingLen <= dataNamePartLen) goto next_variable; - if (remainingPart[dataNamePartLen] == '$') { - - if (memcmp(dataNamePart, remainingPart, dataNamePartLen) == 0) { - + if (remainingPart[dataNamePartLen] == '$') + { + if (memcmp(dataNamePart, remainingPart, dataNamePartLen) == 0) + { char* subElementName = remainingPart + dataNamePartLen + 1; char* subElementNameSep = strchr(subElementName, '$'); @@ -2817,7 +3066,8 @@ getDataDirectory(IedConnection self, IedClientError* error, char* elementName; - if (withFc) { + if (withFc) + { int elementNameLen = (int)strlen(subElementName); elementName = (char*) GLOBAL_MALLOC(elementNameLen + 5); @@ -2846,7 +3096,6 @@ getDataDirectory(IedConnection self, IedClientError* error, *error = IED_ERROR_OK; return dataDirectory; - } LinkedList @@ -2867,14 +3116,16 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, { *error = IED_ERROR_OK; - if (strlen(dataReference) > 129) { + if (strlen(dataReference) > 129) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } char* fcString = FunctionalConstraint_toString(fc); - if (fcString == NULL) { + if (fcString == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2899,7 +3150,8 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, char* logicalNodeNameEnd = strchr(logicalNodeName, '.'); - if (logicalNodeNameEnd == NULL) { + if (logicalNodeNameEnd == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2910,7 +3162,8 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, int dataNamePartLen = (int)strlen(dataNamePart); - if (dataNamePartLen < 1) { + if (dataNamePartLen < 1) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2923,10 +3176,12 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, ICLogicalDevice* ld = NULL; - while (device != NULL) { + while (device) + { ICLogicalDevice* ldCandidate = (ICLogicalDevice*) device->data; - if (strcmp(logicalDeviceName, ldCandidate->name) == 0) { + if (strcmp(logicalDeviceName, ldCandidate->name) == 0) + { ld = ldCandidate; break; } @@ -2934,7 +3189,8 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, device = LinkedList_getNext(device); } - if (ld == NULL) { + if (ld == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -2943,18 +3199,20 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, LinkedList dataDirectory = LinkedList_create(); - while (variable != NULL) { + while (variable) + { char* variableName = (char*) variable->data; char* fcPos = strchr(variableName, '$'); - if (fcPos != NULL) { + if (fcPos) + { int lnNameLen = (int)(fcPos - variableName); - if (logicalNodeNameLen == lnNameLen) { - - if (memcmp(variableName, logicalNodeName, lnNameLen) == 0) { - + if (logicalNodeNameLen == lnNameLen) + { + if (memcmp(variableName, logicalNodeName, lnNameLen) == 0) + { /* ok we are in the correct logical node */ /* skip FC */ @@ -2973,10 +3231,10 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, if (remainingLen <= dataNamePartLen) goto next_variable; - if (remainingPart[dataNamePartLen] == '$') { - - if (memcmp(dataNamePart, remainingPart, dataNamePartLen) == 0) { - + if (remainingPart[dataNamePartLen] == '$') + { + if (memcmp(dataNamePart, remainingPart, dataNamePartLen) == 0) + { char* subElementName = remainingPart + dataNamePartLen + 1; char* subElementNameSep = strchr(subElementName, '$'); @@ -3005,7 +3263,6 @@ getDataDirectoryByFc(IedConnection self, IedClientError* error, *error = IED_ERROR_OK; return dataDirectory; - } @@ -3026,9 +3283,10 @@ IedConnection_createDataSet(IedConnection self, IedClientError* error, const cha const char* itemId; bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3036,17 +3294,20 @@ IedConnection_createDataSet(IedConnection self, IedClientError* error, const cha else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } int domainIdLength = (int)strlen(domainId); - if ((strlen(dataSetReference) - domainIdLength - 1) > 32) { + if ((strlen(dataSetReference) - domainIdLength - 1) > 32) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3056,7 +3317,8 @@ IedConnection_createDataSet(IedConnection self, IedClientError* error, const cha itemId = itemIdRef; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } @@ -3067,12 +3329,13 @@ IedConnection_createDataSet(IedConnection self, IedClientError* error, const cha LinkedList dataSetElement = LinkedList_getNext(dataSetElements); - while (dataSetElement != NULL) { - + while (dataSetElement) + { MmsVariableAccessSpecification* dataSetEntry = MmsMapping_ObjectReferenceToVariableAccessSpec((char*) dataSetElement->data); - if (dataSetEntry == NULL) { + if (dataSetEntry == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto cleanup_list; } @@ -3110,8 +3373,10 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha int dataSetReferenceLength = (int)strlen(dataSetReference); - if (dataSetReference[0] != '@') { - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3119,16 +3384,18 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha else StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference); } - else { - - if (MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainId) == NULL) { + else + { + if (MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainId) == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } const char* itemIdString = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdString) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdString) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3138,8 +3405,10 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha StringUtils_replace(itemId, '.', '$'); } } - else { - if (dataSetReferenceLength > 33) { + else + { + if (dataSetReferenceLength > 33) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3169,13 +3438,14 @@ deleteNamedVariableListHandler(uint32_t invokeId, void* parameter, MmsError mmsE IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler)call->callback; IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError); - if (err == IED_ERROR_OK) { + if (err == IED_ERROR_OK) + { if (success == false) err = IED_ERROR_ACCESS_DENIED; } @@ -3184,7 +3454,8 @@ deleteNamedVariableListHandler(uint32_t invokeId, void* parameter, MmsError mmsE iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -3203,9 +3474,10 @@ IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, cons int dataSetReferenceLength = (int)strlen(dataSetReference); - if (dataSetReference[0] != '@') { - if ((dataSetReference[0] == '/') - || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3213,17 +3485,18 @@ IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, cons else StringUtils_copyStringMax(itemId, DATA_SET_MAX_NAME_LENGTH + 1, dataSetReference); } - else { - - if (MmsMapping_getMmsDomainFromObjectReference(dataSetReference, - domainId) == NULL) { + else + { + if (MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainId) == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } const char *itemIdString = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdString) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdString) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } @@ -3233,8 +3506,10 @@ IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, cons StringUtils_replace(itemId, '.', '$'); } } - else { - if (dataSetReferenceLength > 33) { + else + { + if (dataSetReferenceLength > 33) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } @@ -3246,7 +3521,8 @@ IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, cons MmsError mmsError; - if ((domainId == NULL) || (itemId[0] == 0)) { + if ((domainId == NULL) || (itemId[0] == 0)) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } @@ -3262,14 +3538,17 @@ IedConnection_deleteDataSetAsync(IedConnection self, IedClientError* error, cons call->callbackParameter = parameter; call->invokeId = 0; - if (isAssociationSpecific) { + if (isAssociationSpecific) + { MmsConnection_deleteAssociationSpecificNamedVariableListAsync(self->connection, &(call->invokeId), &mmsError, itemId, deleteNamedVariableListHandler, self); } - else { + else + { MmsConnection_deleteNamedVariableListAsync(self->connection, &(call->invokeId), &mmsError, domainId, itemId, deleteNamedVariableListHandler, self); } - if (*error != IED_ERROR_OK) { + if (*error != IED_ERROR_OK) + { iedConnection_releaseOutstandingCall(self, call); return 0; } @@ -3284,13 +3563,14 @@ createDataSetAsyncHandler(uint32_t invokeId, void* parameter, MmsError mmsError, IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_GenericServiceHandler handler = (IedConnection_GenericServiceHandler)call->callback; IedClientError err = iedConnection_mapMmsErrorToIedError(mmsError); - if (err == IED_ERROR_OK) { + if (err == IED_ERROR_OK) + { if (success == false) err = IED_ERROR_ACCESS_DENIED; } @@ -3299,7 +3579,8 @@ createDataSetAsyncHandler(uint32_t invokeId, void* parameter, MmsError mmsError, iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -3313,9 +3594,10 @@ IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, cons IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; - goto exit_function; + goto exit_function; } call->callback = handler; @@ -3329,9 +3611,10 @@ IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, cons const char* itemId; bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3339,17 +3622,20 @@ IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, cons else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } int domainIdLength = (int)strlen(domainId); - if ((strlen(dataSetReference) - domainIdLength - 1) > 32) { + if ((strlen(dataSetReference) - domainIdLength - 1) > 32) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3359,7 +3645,8 @@ IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, cons itemId = itemIdRef; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } @@ -3368,12 +3655,13 @@ IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, cons LinkedList dataSetElement = LinkedList_getNext(dataSetElements); - while (dataSetElement != NULL) { - + while (dataSetElement) + { MmsVariableAccessSpecification* dataSetEntry = MmsMapping_ObjectReferenceToVariableAccessSpec((char*) dataSetElement->data); - if (dataSetEntry == NULL) { + if (dataSetEntry == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto cleanup_list; } @@ -3383,11 +3671,13 @@ IedConnection_createDataSetAsync(IedConnection self, IedClientError* error, cons dataSetElement = LinkedList_getNext(dataSetElement); } - if (isAssociationSpecific) { + if (isAssociationSpecific) + { MmsConnection_defineNamedVariableListAssociationSpecificAsync(self->connection, &(call->invokeId), &mmsError, itemId, dataSetEntries, createDataSetAsyncHandler, self); } - else { + else + { MmsConnection_defineNamedVariableListAsync(self->connection, &(call->invokeId), &mmsError, domainId, itemId, dataSetEntries, createDataSetAsyncHandler, self); } @@ -3400,8 +3690,10 @@ cleanup_list: exit_function: - if (*error != IED_ERROR_OK) { - iedConnection_releaseOutstandingCall(self, call); + if (*error != IED_ERROR_OK) + { + if (call) + iedConnection_releaseOutstandingCall(self, call); return 0; } @@ -3425,8 +3717,10 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3434,17 +3728,20 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } const char* itemIdRef = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdRef) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdRef) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3454,7 +3751,8 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con itemId = itemIdRefInBuffer; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } @@ -3470,13 +3768,14 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con entries = MmsConnection_readNamedVariableListDirectory(self->connection, &mmsError, domainId, itemId, &deletable); - if (mmsError == MMS_ERROR_NONE) { - + if (mmsError == MMS_ERROR_NONE) + { LinkedList entry = LinkedList_getNext(entries); dataSetMembers = LinkedList_create(); - while (entry) { + while (entry) + { MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(entry); char* objectReference = MmsMapping_varAccessSpecToObjectReference(varAccessSpec); @@ -3507,17 +3806,20 @@ getDataSetDirectoryAsyncHandler(uint32_t invokeId, void* parameter, MmsError mms IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { + if (call) + { LinkedList dataSetMembers = NULL; if (mmsError != MMS_ERROR_NONE) err = iedConnection_mapMmsErrorToIedError(mmsError); - if (specs) { + if (specs) + { dataSetMembers = LinkedList_create(); LinkedList specElem = LinkedList_getNext(specs); - while (specElem) { + while (specElem) + { MmsVariableAccessSpecification* varAccessSpec = (MmsVariableAccessSpecification*)LinkedList_getData(specElem); char* objectReference = MmsMapping_varAccessSpecToObjectReference(varAccessSpec); @@ -3548,7 +3850,8 @@ IedConnection_getDataSetDirectoryAsync(IedConnection self, IedClientError* error IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -3565,8 +3868,10 @@ IedConnection_getDataSetDirectoryAsync(IedConnection self, IedClientError* error bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3574,17 +3879,20 @@ IedConnection_getDataSetDirectoryAsync(IedConnection self, IedClientError* error else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } const char* itemIdRef = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdRef) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdRef) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3594,7 +3902,8 @@ IedConnection_getDataSetDirectoryAsync(IedConnection self, IedClientError* error itemId = itemIdRefInBuffer; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } @@ -3609,12 +3918,14 @@ IedConnection_getDataSetDirectoryAsync(IedConnection self, IedClientError* error exit_function: - if (*error != IED_ERROR_OK) { + if (*error != IED_ERROR_OK) + { iedConnection_releaseOutstandingCall(self, call); return 0; } - else { + else + { return call->invokeId; } } @@ -3631,9 +3942,10 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3641,17 +3953,20 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3662,7 +3977,8 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const itemId = itemIdRef; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } @@ -3678,18 +3994,21 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const dataSetVal = MmsConnection_readNamedVariableListValues(self->connection, &mmsError, domainId, itemId, true); - if (dataSetVal == NULL) { + if (dataSetVal == NULL) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); goto exit_function; } else *error = IED_ERROR_OK; - if (dataSet == NULL) { + if (dataSet == NULL) + { dataSet = ClientDataSet_create(dataSetReference); ClientDataSet_setDataSetValues(dataSet, dataSetVal); } - else { + else + { MmsValue* dataSetValues = ClientDataSet_getValues(dataSet); MmsValue_update(dataSetValues, dataSetVal); MmsValue_delete(dataSetVal); @@ -3706,32 +4025,38 @@ getDataSetHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, MmsV IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_ReadDataSetHandler handler = (IedConnection_ReadDataSetHandler) call->callback; ClientDataSet dataSet = (ClientDataSet) call->specificParameter; char* dataSetReference = (char*) call->specificParameter2.pointer; - if (value != NULL) { - - if (dataSet == NULL) { + if (value) + { + if (dataSet == NULL) + { dataSet = ClientDataSet_create(dataSetReference); - ClientDataSet_setDataSetValues(dataSet, value); - GLOBAL_FREEMEM(dataSetReference); + ClientDataSet_setDataSetValues(dataSet, MmsValue_clone(value)); } - else { + else + { MmsValue* dataSetValues = ClientDataSet_getValues(dataSet); MmsValue_update(dataSetValues, value); - MmsValue_delete(value); } + + MmsValue_delete(value); } + if (dataSetReference) + GLOBAL_FREEMEM(dataSetReference); + handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), dataSet); iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -3749,9 +4074,10 @@ IedConnection_readDataSetValuesAsync(IedConnection self, IedClientError* error, bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3759,17 +4085,20 @@ IedConnection_readDataSetValuesAsync(IedConnection self, IedClientError* error, else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } @@ -3780,14 +4109,16 @@ IedConnection_readDataSetValuesAsync(IedConnection self, IedClientError* error, itemId = itemIdRef; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -3812,8 +4143,8 @@ IedConnection_readDataSetValuesAsync(IedConnection self, IedClientError* error, *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { - + if (err != MMS_ERROR_NONE) + { GLOBAL_FREEMEM(call->specificParameter2.pointer); iedConnection_releaseOutstandingCall(self, call); @@ -3836,9 +4167,10 @@ IedConnection_writeDataSetValues(IedConnection self, IedClientError* error, cons bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3846,17 +4178,20 @@ IedConnection_writeDataSetValues(IedConnection self, IedClientError* error, cons else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -3867,7 +4202,8 @@ IedConnection_writeDataSetValues(IedConnection self, IedClientError* error, cons itemId = itemIdRef; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } @@ -3889,15 +4225,16 @@ writeDataSetHandlerInternal(uint32_t invokeId, void* parameter, MmsError err, Li IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_WriteDataSetHandler handler = (IedConnection_WriteDataSetHandler) call->callback; handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), accessResults); iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -3915,9 +4252,10 @@ IedConnection_writeDataSetValuesAsync(IedConnection self, IedClientError* error, bool isAssociationSpecific = false; - if (dataSetReference[0] != '@') { - - if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) { + if (dataSetReference[0] != '@') + { + if ((dataSetReference[0] == '/') || (strchr(dataSetReference, '/') == NULL)) + { domainId = NULL; if (dataSetReference[0] == '/') @@ -3925,17 +4263,20 @@ IedConnection_writeDataSetValuesAsync(IedConnection self, IedClientError* error, else itemId = dataSetReference; } - else { + else + { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - if (domainId == NULL) { + if (domainId == NULL) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) { + if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } @@ -3946,14 +4287,16 @@ IedConnection_writeDataSetValuesAsync(IedConnection self, IedClientError* error, itemId = itemIdRef; } } - else { + else + { itemId = dataSetReference + 1; isAssociationSpecific = true; } IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -3967,7 +4310,8 @@ IedConnection_writeDataSetValuesAsync(IedConnection self, IedClientError* error, *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); return 0; @@ -3989,8 +4333,8 @@ IedConnection_queryLogByTime(IedConnection self, IedClientError* error, const ch char* logDomain = logRef; char* logName = strchr(logRef, '/'); - if (logName != NULL) { - + if (logName) + { logName[0] = 0; logName++; @@ -4006,18 +4350,19 @@ IedConnection_queryLogByTime(IedConnection self, IedClientError* error, const ch MmsValue_delete(startTimeMms); MmsValue_delete(endTimeMms); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); return NULL; } else return journalEntries; } - else { + else + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } - } static void @@ -4027,15 +4372,16 @@ readJournalHandler(uint32_t invokeId, void* parameter, MmsError err, LinkedList IedConnectionOutstandingCall call = iedConnection_lookupOutstandingCall(self, invokeId); - if (call) { - + if (call) + { IedConnection_QueryLogHandler handler = (IedConnection_QueryLogHandler) call->callback; handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), journalEntries, moreFollows); iedConnection_releaseOutstandingCall(self, call); } - else { + else + { if (DEBUG_IED_CLIENT) printf("IED_CLIENT: internal error - no matching outstanding call!\n"); } @@ -4052,14 +4398,15 @@ IedConnection_queryLogByTimeAsync(IedConnection self, IedClientError* error, con char* logDomain = logRef; char* logName = strchr(logRef, '/'); - if (logName != NULL) { - + if (logName != NULL) + { logName[0] = 0; logName++; IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -4083,18 +4430,19 @@ IedConnection_queryLogByTimeAsync(IedConnection self, IedClientError* error, con *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); return 0; } return call->invokeId; } - else { + else + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } - } uint32_t @@ -4108,14 +4456,15 @@ IedConnection_queryLogAfterAsync(IedConnection self, IedClientError* error, cons char* logDomain = logRef; char* logName = strchr(logRef, '/'); - if (logName != NULL) { - + if (logName) + { logName[0] = 0; logName++; IedConnectionOutstandingCall call = iedConnection_allocateOutstandingCall(self); - if (call == NULL) { + if (call == NULL) + { *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; return 0; } @@ -4135,14 +4484,16 @@ IedConnection_queryLogAfterAsync(IedConnection self, IedClientError* error, cons *error = iedConnection_mapMmsErrorToIedError(err); - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { iedConnection_releaseOutstandingCall(self, call); return 0; } return call->invokeId; } - else { + else + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return 0; } @@ -4161,8 +4512,8 @@ IedConnection_queryLogAfter(IedConnection self, IedClientError* error, const cha char* logDomain = logRef; char* logName = strchr(logRef, '/'); - if (logName != NULL) { - + if (logName) + { logName[0] = 0; logName++; @@ -4174,14 +4525,16 @@ IedConnection_queryLogAfter(IedConnection self, IedClientError* error, const cha MmsValue_delete(timeStampMms); - if (mmsError != MMS_ERROR_NONE) { + if (mmsError != MMS_ERROR_NONE) + { *error = iedConnection_mapMmsErrorToIedError(mmsError); return NULL; } else return journalEntries; } - else { + else + { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; return NULL; } @@ -4255,4 +4608,3 @@ FileDirectoryEntry_getLastModified(FileDirectoryEntry self) { return self->lastModified; } - diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 5e53efe2..5946bd00 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -1,7 +1,7 @@ /* * iec61850_client.h * - * Copyright 2013-2021 Michael Zillgith + * Copyright 2013-2023 Michael Zillgith * * This file is part of libIEC61850. * @@ -172,6 +172,14 @@ typedef enum { IED_ERROR_UNKNOWN = 99 } IedClientError; +/** + * \brief Convert error value to string + * + * \return string constant representing the error + */ +LIB61850_API const char* +IedClientError_toString(IedClientError err); + /************************************************** * Connection creation and destruction **************************************************/ @@ -258,6 +266,16 @@ IedConnection_setLocalAddress(IedConnection self, const char* localIpAddress, in LIB61850_API void IedConnection_setConnectTimeout(IedConnection self, uint32_t timeoutInMs); +/** + * \brief Set the maximum number outstanding calls allowed for this connection + * + * \param self the connection object + * \param calling the maximum outstanding calls allowed by the caller (client) + * \param called the maximum outstanding calls allowed by the called endpoint (server) + */ +LIB61850_API void +IedConnection_setMaxOutstandingCalls(IedConnection self, int calling, int called); + /** * \brief set the request timeout in ms * @@ -1154,15 +1172,6 @@ typedef int ReasonForInclusion; /** the reason for inclusion is unknown (e.g. report is not configured to include reason-for-inclusion) */ #define IEC61850_REASON_UNKNOWN 32 -#define REASON_NOT_INCLUDED IEC61850_REASON_NOT_INCLUDED -#define REASON_DATA_CHANGE IEC61850_REASON_DATA_CHANGE -#define REASON_QUALITY_CHANGE IEC61850_REASON_QUALITY_CHANGE -#define REASON_DATA_UPDATE IEC61850_REASON_DATA_UPDATE -#define REASON_INTEGRITY IEC61850_REASON_INTEGRITY -#define REASON_GI IEC61850_REASON_GI -#define REASON_UNKNOWN IEC61850_REASON_UNKNOWN - - /* Element encoding mask values for ClientReportControlBlock */ /** include the report ID into the setRCB request */ @@ -1259,9 +1268,11 @@ typedef void (*ReportCallbackFunction) (void* parameter, ClientReport report); * Otherwise the internal data structures storing the received data set values will not be updated * correctly. * - * When replacing a report handler you only have to call this function. There is no separate call to + * \note Replacing a report handler you only have to call this function. There is no separate call to * IedConnection_uninstallReportHandler() required. * + * \note Do not call this function inside of the ReportCallbackFunction. Doing so will cause a deadlock. + * * \param self the connection object * \param rcbReference object reference of the report control block * \param rptId a string that identifies the report. If the rptId is not available then the @@ -1276,6 +1287,8 @@ IedConnection_installReportHandler(IedConnection self, const char* rcbReference, /** * \brief uninstall a report handler function for the specified report control block (RCB) * + * \note Do not call this function inside of the ReportCallbackFunction. Doing so will cause a deadlock. + * * \param self the connection object * \param rcbReference object reference of the report control block */ diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index b14bb6cb..6dc69524 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -3,7 +3,7 @@ * * IEC 61850 server API for libiec61850. * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -815,7 +815,9 @@ LIB61850_API void IedServer_setConnectionIndicationHandler(IedServer self, IedConnectionIndicationHandler handler, void* parameter); /** - * \brief Ignore all requests from clients + * \brief Ignore all requests from clients (for testing purposes) + * + * NOTE: This function will block all client requests on MMS layer * * \param self the instance of IedServer to configure. * \param enable when true all requests from clients will be ignored @@ -1447,7 +1449,7 @@ LIB61850_API DataObject* ControlAction_getControlObject(ControlAction self); /** - * \brief Gets the time of the control, if it's a timeActivatedControl, returns 0, if it's not. + * \brief Gets the time of the control (attribute "operTm"), if it's a timeActivatedControl, returns 0, if it's not. * * \param self the control action instance * @@ -1456,6 +1458,16 @@ ControlAction_getControlObject(ControlAction self); LIB61850_API uint64_t ControlAction_getControlTime(ControlAction self); +/** + * \brief Gets the time (attribute "T") of the last received control action (Oper or Select) + * + * \param self the control action instance + * + * \return the time of the last received control action + */ +LIB61850_API Timestamp* +ControlAction_getT(ControlAction self); + /** * \brief Control model callback to perform the static tests (optional). * @@ -1845,6 +1857,19 @@ LIB61850_API void IedServer_handleWriteAccessForComplexAttribute(IedServer self, DataAttribute* dataAttribute, WriteAccessHandler handler, void* parameter); +/** + * \brief Install a WriteAccessHandler for all data attributes of a data object with a specific FC + * + * \param self the instance of IedServer to operate on. + * \param dataObject the data object to monitor + * \param fc the functional constraint to monitor + * \param handler the callback function that is invoked if a client tries to write to + * the monitored data attribute. + * \param parameter a user provided parameter that is passed to the WriteAccessHandler when called. +*/ +LIB61850_API void +IedServer_handleWriteAccessForDataObject(IedServer self, DataObject* dataObject, FunctionalConstraint fc, WriteAccessHandler handler, void* parameter); + typedef enum { ACCESS_POLICY_ALLOW, ACCESS_POLICY_DENY @@ -1997,6 +2022,15 @@ typedef bool LIB61850_API void IedServer_setControlBlockAccessHandler(IedServer self, IedServer_ControlBlockAccessHandler handler, void* parameter); +/** + * \brief Temporarily ignore read requests (for testing purposes) + * + * \param self the instance of IedServer to operate on. + * \param ignore true to ignore read requests, false to handle read requests. +*/ +LIB61850_API void +IedServer_ignoreReadAccess(IedServer self, bool ignore); + /**@}*/ /**@}*/ diff --git a/src/iec61850/inc_private/control.h b/src/iec61850/inc_private/control.h index 66cb6706..adf56731 100644 --- a/src/iec61850/inc_private/control.h +++ b/src/iec61850/inc_private/control.h @@ -1,7 +1,7 @@ /* * control.h * - * Copyright 2013-2019 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -90,6 +90,8 @@ struct sControlObject MmsValue* origin; MmsValue* timestamp; + Timestamp T; + MmsValue* ctlNumSt; MmsValue* originSt; diff --git a/src/iec61850/inc_private/ied_connection_private.h b/src/iec61850/inc_private/ied_connection_private.h index e571ca8e..52467747 100644 --- a/src/iec61850/inc_private/ied_connection_private.h +++ b/src/iec61850/inc_private/ied_connection_private.h @@ -1,7 +1,7 @@ /* * ied_connection_private.h * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -34,14 +34,16 @@ typedef struct sIedConnectionOutstandingCall* IedConnectionOutstandingCall; -struct sIedConnectionOutstandingCall { +struct sIedConnectionOutstandingCall +{ bool used; uint32_t invokeId; void* callback; void* callbackParameter; void* specificParameter; /* function/service specific parameter */ - union { + union + { void* pointer; struct { uint32_t originalInvokeId; @@ -69,6 +71,7 @@ struct sIedConnection Semaphore outstandingCallsLock; IedConnectionOutstandingCall outstandingCalls; + int maxOutstandingCalled; IedConnectionClosedHandler connectionCloseHandler; void* connectionClosedParameter; @@ -81,7 +84,8 @@ struct sIedConnection uint8_t timeQuality; }; -struct sClientReportControlBlock { +struct sClientReportControlBlock +{ char* objectReference; bool isBuffered; diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h index d5555659..8dc5fede 100644 --- a/src/iec61850/inc_private/ied_server_private.h +++ b/src/iec61850/inc_private/ied_server_private.h @@ -81,10 +81,11 @@ struct sIedServer uint8_t timeQuality; /* user settable time quality for internally updated times */ + bool ignoreReadAccess; /* when true don't answer read request (for test purposes) */ + bool running; }; - LIB61850_INTERNAL IEC61850_ServiceError private_IedServer_convertMmsDataAccessErrorToServiceError(MmsDataAccessError mmsError); diff --git a/src/iec61850/inc_private/logging.h b/src/iec61850/inc_private/logging.h index 82ef712b..79c3f246 100644 --- a/src/iec61850/inc_private/logging.h +++ b/src/iec61850/inc_private/logging.h @@ -124,7 +124,7 @@ LIB61850_INTERNAL MmsValue* LIBIEC61850_LOG_SVC_readAccessControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, MmsServerConnection connection); LIB61850_INTERNAL MmsDataAccessError -LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, +LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig, MmsValue* value, MmsServerConnection connection); #endif /* LIBIEC61850_SRC_IEC61850_INC_PRIVATE_LOGGING_H_ */ diff --git a/src/iec61850/inc_private/mms_mapping.h b/src/iec61850/inc_private/mms_mapping.h index 63ec5742..340a2d81 100644 --- a/src/iec61850/inc_private/mms_mapping.h +++ b/src/iec61850/inc_private/mms_mapping.h @@ -149,7 +149,7 @@ LIB61850_INTERNAL void MmsMapping_installReadAccessHandler(MmsMapping* self, ReadAccessHandler handler, void* paramter); LIB61850_INTERNAL MmsDataAccessError -Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, +Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig, MmsValue* value, MmsServerConnection connection); LIB61850_INTERNAL MmsValue* diff --git a/src/iec61850/inc_private/mms_sv.h b/src/iec61850/inc_private/mms_sv.h index 6f8663bf..a0bb0ded 100644 --- a/src/iec61850/inc_private/mms_sv.h +++ b/src/iec61850/inc_private/mms_sv.h @@ -41,7 +41,7 @@ LIB61850_INTERNAL MmsValue* LIBIEC61850_SV_readAccessSampledValueControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig , MmsServerConnection connection); LIB61850_INTERNAL MmsDataAccessError -LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, +LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig, MmsValue* value, MmsServerConnection connection); LIB61850_INTERNAL void diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index 558343c2..eddeb2d1 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -126,7 +126,7 @@ LIB61850_INTERNAL void ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, int flag, bool modelLocked); LIB61850_INTERNAL MmsValue* -ReportControl_getRCBValue(ReportControl* rc, char* elementName); +ReportControl_getRCBValue(ReportControl* rc, const char* elementName); LIB61850_INTERNAL MmsVariableSpecification* Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain, @@ -137,7 +137,7 @@ Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode, int reportsCount); LIB61850_INTERNAL MmsDataAccessError -Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value, +Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, const char* elementName, MmsValue* value, MmsServerConnection connection); LIB61850_INTERNAL bool diff --git a/src/iec61850/server/impl/client_connection.c b/src/iec61850/server/impl/client_connection.c index dbca770a..6eac160d 100644 --- a/src/iec61850/server/impl/client_connection.c +++ b/src/iec61850/server/impl/client_connection.c @@ -1,7 +1,7 @@ /* * client_connection.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -32,8 +32,8 @@ #include "libiec61850_platform_includes.h" -struct sClientConnection { - +struct sClientConnection +{ #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore tasksCountMutex; #endif @@ -47,7 +47,8 @@ private_ClientConnection_create(void* serverConnectionHandle) { ClientConnection self = (ClientConnection) GLOBAL_MALLOC(sizeof(struct sClientConnection)); - if (self) { + if (self) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) self->tasksCountMutex = Semaphore_create(1); #endif @@ -62,7 +63,8 @@ private_ClientConnection_create(void* serverConnectionHandle) void private_ClientConnection_destroy(ClientConnection self) { - if (self) { + if (self) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_destroy(self->tasksCountMutex); #endif @@ -123,7 +125,6 @@ private_ClientConnection_getServerConnectionHandle(ClientConnection self) return self->serverConnectionHandle; } - const char* ClientConnection_getPeerAddress(ClientConnection self) { diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 8a5c4baa..2acecedd 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -540,17 +540,18 @@ updateDataSetsWithCachedValues(IedServer self) } } - IedServer IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguration, IedServerConfig serverConfiguration) { IedServer self = (IedServer) GLOBAL_CALLOC(1, sizeof(struct sIedServer)); - if (self) { + if (self) + { self->model = dataModel; self->running = false; self->localIpAddress = NULL; + self->ignoreReadAccess = false; #if (CONFIG_IEC61850_EDITION_1 == 1) self->edition = IEC_61850_EDITION_1; @@ -561,7 +562,8 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) self->logServiceEnabled = true; - if (serverConfiguration) { + if (serverConfiguration) + { self->logServiceEnabled = serverConfiguration->enableLogService; self->edition = serverConfiguration->edition; } @@ -574,7 +576,8 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio #endif /* (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) */ #if (CONFIG_IEC61850_REPORT_SERVICE == 1) - if (serverConfiguration) { + if (serverConfiguration) + { self->reportBufferSizeBRCBs = serverConfiguration->reportBufferSize; self->reportBufferSizeURCBs = serverConfiguration->reportBufferSizeURCBs; self->enableBRCBResvTms = serverConfiguration->enableResvTmsForBRCB; @@ -582,7 +585,8 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio self->syncIntegrityReportTimes = serverConfiguration->syncIntegrityReportTimes; self->rcbSettingsWritable = serverConfiguration->reportSettingsWritable; } - else { + else + { self->reportBufferSizeBRCBs = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; self->reportBufferSizeURCBs = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; self->enableOwnerForRCB = false; @@ -602,11 +606,13 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio #endif #if (CONFIG_IEC61850_SETTING_GROUPS == 1) - if (serverConfiguration) { + if (serverConfiguration) + { self->enableEditSG = serverConfiguration->enableEditSG; self->hasSGCBResvTms = serverConfiguration->enableResvTmsForSGCB; } - else { + else + { self->enableEditSG = true; self->hasSGCBResvTms = true; } @@ -614,14 +620,15 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio self->mmsMapping = MmsMapping_create(dataModel, self); - if (self->mmsMapping) { - + if (self->mmsMapping) + { self->mmsDevice = MmsMapping_getMmsDeviceModel(self->mmsMapping); self->mmsServer = MmsServer_create(self->mmsDevice, tlsConfiguration); #if (CONFIG_MMS_SERVER_CONFIG_SERVICES_AT_RUNTIME == 1) - if (serverConfiguration) { + if (serverConfiguration) + { MmsServer_enableFileService(self->mmsServer, serverConfiguration->enableFileService); MmsServer_enableDynamicNamedVariableListService(self->mmsServer, serverConfiguration->enableDynamicDataSetService); MmsServer_setMaxAssociationSpecificDataSets(self->mmsServer, serverConfiguration->maxAssociationSpecificDataSets); @@ -668,7 +675,8 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio IedServer_setTimeQuality(self, true, false, false, 10); } - else { + else + { IedServer_destroy(self); self = NULL; } @@ -1679,6 +1687,38 @@ IedServer_handleWriteAccessForComplexAttribute(IedServer self, DataAttribute* da } } +void +IedServer_handleWriteAccessForDataObject(IedServer self, DataObject* dataObject, FunctionalConstraint fc, WriteAccessHandler handler, void* parameter) +{ + if (dataObject == NULL) { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: IedServer_handlerWriteAccessForDataObject - dataObject == NULL!\n"); + } + else + { + ModelNode* childElement = dataObject->firstChild; + + while (childElement) + { + if (childElement->modelType == DataAttributeModelType) + { + DataAttribute* dataAttribute = (DataAttribute*) childElement; + + if (dataAttribute->fc == fc) + { + IedServer_handleWriteAccessForComplexAttribute(self, dataAttribute, handler, parameter); + } + } + else if (childElement->modelType == DataObjectModelType) + { + IedServer_handleWriteAccessForDataObject(self, (DataObject*) childElement, fc, handler, parameter); + } + + childElement = childElement->sibling; + } + } +} + void IedServer_setReadAccessHandler(IedServer self, ReadAccessHandler handler, void* parameter) { @@ -1960,3 +2000,9 @@ IedServer_setControlBlockAccessHandler(IedServer self, IedServer_ControlBlockAcc self->mmsMapping->controlBlockAccessHandler = handler; self->mmsMapping->controlBlockAccessHandlerParameter = parameter; } + +void +IedServer_ignoreReadAccess(IedServer self, bool ignore) +{ + self->ignoreReadAccess = ignore; +} diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c index de2b6f89..07ef4324 100644 --- a/src/iec61850/server/mms_mapping/control.c +++ b/src/iec61850/server/mms_mapping/control.c @@ -74,7 +74,8 @@ ControlObject_unselect(ControlObject* self, MmsServerConnection connection, MmsM static MmsValue* getOperParameterCtlNum(MmsValue* operParameters) { - if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { if (MmsValue_getArraySize(operParameters) == 7) return MmsValue_getElement(operParameters, 3); else if (MmsValue_getArraySize(operParameters) == 6) @@ -87,7 +88,8 @@ getOperParameterCtlNum(MmsValue* operParameters) static MmsValue* getCancelParameterCtlNum(MmsValue* operParameters) { - if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { if (MmsValue_getArraySize(operParameters) == 6) return MmsValue_getElement(operParameters, 3); else if (MmsValue_getArraySize(operParameters) == 5) @@ -100,7 +102,8 @@ getCancelParameterCtlNum(MmsValue* operParameters) static MmsValue* getCancelParameterOrigin(MmsValue* operParameters) { - if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { if (MmsValue_getArraySize(operParameters) == 6) return MmsValue_getElement(operParameters, 2); else if (MmsValue_getArraySize(operParameters) == 5) @@ -166,6 +169,7 @@ getCancelParameterTest(MmsValue* operParameters) return NULL; } +/* access the MmsValue of Oper.T or SBOw.T */ static MmsValue* getOperParameterTime(MmsValue* operParameters) { @@ -179,7 +183,7 @@ getOperParameterTime(MmsValue* operParameters) timeParameter = MmsValue_getElement(operParameters, 3); } - if (timeParameter != NULL) + if (timeParameter) if ((MmsValue_getType(timeParameter) == MMS_UTC_TIME) || (MmsValue_getType(timeParameter) == MMS_BINARY_TIME)) return timeParameter; @@ -211,11 +215,12 @@ getCancelParameterTime(MmsValue* operParameters) static void copyControlValuesToTrackingObject(MmsMapping* self, ControlObject* controlObject, IEC61850_ServiceType serviceType) { - if (controlObject->ctlVal) { - + if (controlObject->ctlVal) + { ControlTrkInstance trkInst = NULL; - switch (controlObject->cdc) { + switch (controlObject->cdc) + { case CST_SPCTRK: trkInst = self->spcTrk; break; @@ -247,7 +252,8 @@ copyControlValuesToTrackingObject(MmsMapping* self, ControlObject* controlObject break; } - if (trkInst) { + if (trkInst) + { if (trkInst->ctlVal) MmsValue_update(trkInst->ctlVal->mmsValue, controlObject->ctlVal); @@ -265,16 +271,20 @@ copyControlValuesToTrackingObject(MmsMapping* self, ControlObject* controlObject MmsValue* operVal = NULL; - if (serviceType == IEC61850_SERVICE_TYPE_SELECT_WITH_VALUES) { + if (serviceType == IEC61850_SERVICE_TYPE_SELECT_WITH_VALUES) + { if (controlObject->sbow) operVal = controlObject->sbow; } - else if (serviceType == IEC61850_SERVICE_TYPE_OPERATE) { + else if (serviceType == IEC61850_SERVICE_TYPE_OPERATE) + { if (controlObject->oper) operVal = controlObject->oper; } - else if (serviceType == IEC61850_SERVICE_TYPE_CANCEL) { - if (controlObject->cancel) { + else if (serviceType == IEC61850_SERVICE_TYPE_CANCEL) + { + if (controlObject->cancel) + { operVal = controlObject->cancel; if (trkInst->Test) { MmsValue_update(trkInst->Test->mmsValue, getCancelParameterTest(operVal)); @@ -286,8 +296,8 @@ copyControlValuesToTrackingObject(MmsMapping* self, ControlObject* controlObject } } - if (operVal) { - + if (operVal) + { if (trkInst->Test) { MmsValue_update(trkInst->Test->mmsValue, getOperParameterTest(operVal)); } @@ -300,7 +310,6 @@ copyControlValuesToTrackingObject(MmsMapping* self, ControlObject* controlObject MmsValue_update(trkInst->T->mmsValue, getOperParameterTime(operVal)); } } - } } } @@ -310,8 +319,8 @@ convertCheckHandlerResultToServiceError(CheckHandlerResult controlHandlerResult) { IEC61850_ServiceError serviceError; - switch (controlHandlerResult) { - + switch (controlHandlerResult) + { case CONTROL_HARDWARE_FAULT: serviceError = IEC61850_SERVICE_ERROR_FAILED_DUE_TO_SERVER_CONSTRAINT; break; @@ -352,7 +361,8 @@ updateGenericTrackingObjectValues(MmsMapping* self, ControlObject* controlObject ServiceTrkInstance trkInst = NULL; - if (controlObject->ctlVal) { + if (controlObject->ctlVal) + { switch(controlObject->cdc) { case CST_SPCTRK: @@ -389,7 +399,8 @@ updateGenericTrackingObjectValues(MmsMapping* self, ControlObject* controlObject } } - if (trkInst) { + if (trkInst) + { if (trkInst->serviceType) MmsValue_setInt32(trkInst->serviceType->mmsValue, (int) serviceType); @@ -460,7 +471,8 @@ getState(ControlObject* self) static void setStSeld(ControlObject* self, bool value) { - if (self->stSeld) { + if (self->stSeld) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->pendingEventsLock); #endif @@ -479,7 +491,8 @@ setStSeld(ControlObject* self, bool value) static void updateSboTimeoutValue(ControlObject* self) { - if (self->sboTimeout != NULL) { + if (self->sboTimeout != NULL) + { uint32_t sboTimeoutVal = MmsValue_toInt32(self->sboTimeout); if (DEBUG_IED_SERVER) @@ -506,7 +519,8 @@ selectObject(ControlObject* self, uint64_t selectTime, MmsServerConnection conne updateNextControlTimeout(mmsMapping, selectTime); - if (self->selectStateChangedHandler) { + if (self->selectStateChangedHandler) + { self->selectStateChangedHandler((ControlAction) self, self->selectStateChangedHandlerParameter, true, @@ -517,7 +531,8 @@ selectObject(ControlObject* self, uint64_t selectTime, MmsServerConnection conne static void unselectObject(ControlObject* self, SelectStateChangedReason reason, MmsMapping* mmsMapping) { - if (getState(self) != STATE_UNSELECTED) { + if (getState(self) != STATE_UNSELECTED) + { setState(self, STATE_UNSELECTED); setStSeld(self, false); @@ -525,7 +540,8 @@ unselectObject(ControlObject* self, SelectStateChangedReason reason, MmsMapping* /* trigger timeout check in next cycle to update the next timeout value */ mmsMapping->nextControlTimeout = 0; - if (self->selectStateChangedHandler) { + if (self->selectStateChangedHandler) + { self->selectStateChangedHandler((ControlAction) self, self->selectStateChangedHandlerParameter, false, @@ -540,11 +556,14 @@ unselectObject(ControlObject* self, SelectStateChangedReason reason, MmsMapping* static void checkSelectTimeout(ControlObject* self, uint64_t currentTime, MmsMapping* mmsMapping) { - if ((self->ctlModel == 2) || (self->ctlModel == 4)) { - - if (getState(self) == STATE_READY) { - if (self->selectTimeout > 0) { - if (currentTime > (self->selectTime + self->selectTimeout)) { + if ((self->ctlModel == 2) || (self->ctlModel == 4)) + { + if (getState(self) == STATE_READY) + { + if (self->selectTimeout > 0) + { + if (currentTime > (self->selectTime + self->selectTimeout)) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: select-timeout (timeout-val = %u) for control %s/%s.%s\n", self->selectTimeout, MmsDomain_getName(self->mmsDomain), self->lnName, self->name); @@ -562,7 +581,8 @@ checkSelectTimeout(ControlObject* self, uint64_t currentTime, MmsMapping* mmsMap static void setOpRcvd(ControlObject* self, bool value) { - if (self->opRcvd) { + if (self->opRcvd) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->pendingEventsLock); #endif @@ -581,13 +601,16 @@ setOpRcvd(ControlObject* self, bool value) static void setOpOk(ControlObject* self, bool value, uint64_t currentTimeInMs) { - if (self->opOk) { + if (self->opOk) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->pendingEventsLock); #endif - if (value) { - if (self->tOpOk) { + if (value) + { + if (self->tOpOk) + { MmsValue* timestamp = self->tOpOk->mmsValue; MmsValue_setUtcTimeMsEx(timestamp, currentTimeInMs, self->iedServer->timeQuality); @@ -607,7 +630,8 @@ setOpOk(ControlObject* self, bool value, uint64_t currentTimeInMs) static bool isSboClassOperateOnce(ControlObject* self) { - if (self->sboClass != NULL) { + if (self->sboClass != NULL) + { if (MmsValue_toInt32(self->sboClass) == 1) return false; else @@ -620,8 +644,8 @@ isSboClassOperateOnce(ControlObject* self) static MmsValue* getOperParameterOperTime(MmsValue* operParameters) { - if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { - + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { if (MmsValue_getArraySize(operParameters) == 7) return MmsValue_getElement(operParameters, 1); } @@ -659,12 +683,14 @@ exitControlTask(ControlObject* self) static void abortControlOperation(ControlObject* self, bool unconditional, SelectStateChangedReason reason, MmsMapping* mmsMapping) { - if ((self->ctlModel == 2) || (self->ctlModel == 4)) { - - if (unconditional) { + if ((self->ctlModel == 2) || (self->ctlModel == 4)) + { + if (unconditional) + { unselectObject(self, reason, mmsMapping); } - else { + else + { if (isSboClassOperateOnce(self)) unselectObject(self, reason, mmsMapping); else @@ -694,7 +720,8 @@ operateControl(ControlObject* self, MmsValue* value, uint64_t currentTime, bool static void resetAddCause(ControlObject* self) { - if (self) { + if (self) + { self->addCauseValue = ADD_CAUSE_UNKNOWN; MmsValue_setInt32(self->addCause, self->addCauseValue); @@ -710,8 +737,8 @@ executeStateMachine: state = getState(controlObject); - switch (state) { - + switch (state) + { case STATE_WAIT_FOR_SELECT: { controlObject->isSelect = 1; @@ -724,12 +751,14 @@ executeStateMachine: controlObject->isSelect = 0; - if (checkHandlerResult != CONTROL_WAITING_FOR_SELECT) { - - if (controlObject->ctlModel == 2) { + if (checkHandlerResult != CONTROL_WAITING_FOR_SELECT) + { + if (controlObject->ctlModel == 2) + { LinkedList values = LinkedList_create(); - if (checkHandlerResult == CONTROL_ACCEPTED) { + if (checkHandlerResult == CONTROL_ACCEPTED) + { LinkedList_add(values, controlObject->sbo); selectObject(controlObject, Hal_getTimeInMs(), controlObject->mmsConnection, self); @@ -738,7 +767,8 @@ executeStateMachine: updateGenericTrackingObjectValues(self, controlObject, IEC61850_SERVICE_TYPE_SELECT, IEC61850_SERVICE_ERROR_NO_ERROR); #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ } - else { + else + { LinkedList_add(values, &emptyString); setState(controlObject, STATE_UNSELECTED); @@ -753,9 +783,10 @@ executeStateMachine: LinkedList_destroyStatic(values); } - else if (controlObject->ctlModel == 4) { - if (checkHandlerResult == CONTROL_ACCEPTED) { - + else if (controlObject->ctlModel == 4) + { + if (checkHandlerResult == CONTROL_ACCEPTED) + { selectObject(controlObject, Hal_getTimeInMs(), controlObject->mmsConnection, self); if (controlObject->ctlNumSt) @@ -773,8 +804,8 @@ executeStateMachine: if (DEBUG_IED_SERVER) printf("IED_SERVER: SBOw - selected successful\n"); } - else { - + else + { setState(controlObject, STATE_UNSELECTED); ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "SBOw", @@ -793,13 +824,15 @@ executeStateMachine: printf("IED_SERVER: SBOw - select rejected by application!\n"); } } - else { + else + { /* ERROR: invalid internal state! */ setState(controlObject, STATE_WAIT_FOR_SELECT); } } - else { + else + { updateNextControlTimeout(self, Hal_getTimeInMs() + 100); } @@ -818,19 +851,23 @@ executeStateMachine: controlObject->errorValue = CONTROL_ERROR_NO_ERROR; controlObject->addCauseValue = ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK; - if (controlObject->waitForExecutionHandler != NULL) { + if (controlObject->waitForExecutionHandler != NULL) + { dynamicCheckResult = controlObject->waitForExecutionHandler((ControlAction) controlObject, controlObject->waitForExecutionHandlerParameter, controlObject->ctlVal, controlObject->testMode, controlObject->synchroCheck); } - if (dynamicCheckResult == CONTROL_RESULT_FAILED) { - if ((controlObject->errorValue != CONTROL_ERROR_NO_ERROR) || (controlObject->addCauseValue != ADD_CAUSE_UNKNOWN)) { + if (dynamicCheckResult == CONTROL_RESULT_FAILED) + { + if ((controlObject->errorValue != CONTROL_ERROR_NO_ERROR) || (controlObject->addCauseValue != ADD_CAUSE_UNKNOWN)) + { ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "Oper", controlObject->errorValue, controlObject->addCauseValue, controlObject->ctlNum, controlObject->origin, false); } - if (!isTimeActivatedControl) { + if (!isTimeActivatedControl) + { MmsServerConnection_sendWriteResponse(controlObject->mmsConnection, controlObject->operateInvokeId, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED, true); @@ -838,7 +875,8 @@ executeStateMachine: updateGenericTrackingObjectValues(self, controlObject, IEC61850_SERVICE_TYPE_OPERATE, IEC61850_SERVICE_ERROR_ACCESS_NOT_ALLOWED_IN_CURRENT_STATE); #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ } - else { + else + { #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) updateGenericTrackingObjectValues(self, controlObject, IEC61850_SERVICE_TYPE_TIME_ACTIVATED_OPERATE, IEC61850_SERVICE_ERROR_ACCESS_NOT_ALLOWED_IN_CURRENT_STATE); #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ @@ -849,8 +887,10 @@ executeStateMachine: abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATE_FAILED, self); exitControlTask(controlObject); } - else if (dynamicCheckResult == CONTROL_RESULT_OK) { - if (isTimeActivatedControl) { + else if (dynamicCheckResult == CONTROL_RESULT_OK) + { + if (isTimeActivatedControl) + { ControlObject_sendCommandTerminationPositive(controlObject); #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) @@ -862,7 +902,8 @@ executeStateMachine: MmsValue_setUtcTime(operTm, 0); MmsValue_setUtcTimeQuality(operTm, self->iedServer->timeQuality); } - else { + else + { MmsServerConnection_sendWriteResponse(controlObject->mmsConnection, controlObject->operateInvokeId, DATA_ACCESS_ERROR_SUCCESS, true); @@ -877,7 +918,8 @@ executeStateMachine: goto executeStateMachine; } - else { + else + { updateNextControlTimeout(self, Hal_getTimeInMs() + 10); } } @@ -889,11 +931,12 @@ executeStateMachine: ControlHandlerResult result = operateControl(controlObject, controlObject->ctlVal, currentTime, controlObject->testMode); - if (result != CONTROL_RESULT_WAITING) { - - if (result == CONTROL_RESULT_OK) { - - if ((controlObject->ctlModel == 4) || (controlObject->ctlModel == 3)) { + if (result != CONTROL_RESULT_WAITING) + { + if (result == CONTROL_RESULT_OK) + { + if ((controlObject->ctlModel == 4) || (controlObject->ctlModel == 3)) + { ControlObject_sendCommandTerminationPositive(controlObject); #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) @@ -903,9 +946,10 @@ executeStateMachine: abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATED, self); } - else { - - if ((controlObject->ctlModel == 4) || (controlObject->ctlModel == 3)) { + else + { + if ((controlObject->ctlModel == 4) || (controlObject->ctlModel == 3)) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: operate failed!\n"); @@ -925,7 +969,8 @@ executeStateMachine: resetAddCause(controlObject); } - else { + else + { updateNextControlTimeout(self, currentTimeInMs + 10); } } @@ -949,7 +994,8 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* self->stateLock = Semaphore_create(1); self->pendingEventsLock = Semaphore_create(1); - if ((self->stateLock == NULL) || (self->pendingEventsLock == NULL)) { + if ((self->stateLock == NULL) || (self->pendingEventsLock == NULL)) + { ControlObject_destroy(self); self = NULL; goto exit_function; @@ -958,7 +1004,8 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* self->name = StringUtils_copyString(name); - if (self->name == NULL) { + if (self->name == NULL) + { ControlObject_destroy(self); self = NULL; goto exit_function; @@ -970,20 +1017,24 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* MmsVariableSpecification* ctlValSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "ctlVal", NULL); - if (ctlValSpec) { + if (ctlValSpec) + { self->ctlVal = MmsValue_newDefaultValue(ctlValSpec); } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: control object %s/%s.%s has no ctlVal element!\n", domain->domainName, lnName, name); } MmsVariableSpecification* originSpec = MmsVariableSpecification_getChildSpecificationByName(operSpec, "origin", NULL); - if (originSpec) { + if (originSpec) + { self->origin = MmsValue_newDefaultValue(originSpec); } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: control object %s/%s.%s has no origin element!\n", domain->domainName, lnName, name); } @@ -1015,7 +1066,8 @@ ControlObject_initialize(ControlObject* self) MmsValue* ctlModel = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, ctlModelName); - if (ctlModel == NULL) { + if (ctlModel == NULL) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: No control model found for variable %s\n", ctlModelName); } @@ -1028,7 +1080,8 @@ ControlObject_initialize(ControlObject* self) self->ctlNumSt = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, ctlNumName); - if (self->ctlNumSt == NULL) { + if (self->ctlNumSt == NULL) + { /* for APC */ ctlNumName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$MX$", self->name, "$ctlNum"); @@ -1039,7 +1092,8 @@ ControlObject_initialize(ControlObject* self) self->originSt = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, originName); - if (self->originSt == NULL) { + if (self->originSt == NULL) + { /* for APC */ originName = StringUtils_createStringInBuffer(strBuf, 130, 4, self->lnName, "$MX$", self->name, "$origin"); @@ -1053,7 +1107,8 @@ ControlObject_initialize(ControlObject* self) updateSboTimeoutValue(self); - if (self->sbo) { + if (self->sbo) + { char* controlObjectReference = StringUtils_createStringInBuffer(strBuf, 130, 5, self->mmsDomain->domainName, "/", self->lnName, "$CO$", self->name); @@ -1154,7 +1209,8 @@ ControlObject_initialize(ControlObject* self) self->stSeld = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, stSeldName); - if ((self->stSeld) && (self->stSeld->type != IEC61850_BOOLEAN)) { + if ((self->stSeld) && (self->stSeld->type != IEC61850_BOOLEAN)) + { self->stSeld = NULL; if (DEBUG_IED_SERVER) @@ -1165,7 +1221,8 @@ ControlObject_initialize(ControlObject* self) self->opRcvd = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, opRcvdName); - if ((self->opRcvd) && (self->opRcvd->type != IEC61850_BOOLEAN)) { + if ((self->opRcvd) && (self->opRcvd->type != IEC61850_BOOLEAN)) + { self->opRcvd = NULL; if (DEBUG_IED_SERVER) @@ -1176,7 +1233,8 @@ ControlObject_initialize(ControlObject* self) self->opOk = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, opOkName); - if ((self->opOk) && (self->opOk->type != IEC61850_BOOLEAN)) { + if ((self->opOk) && (self->opOk->type != IEC61850_BOOLEAN)) + { self->opOk = NULL; if (DEBUG_IED_SERVER) @@ -1187,7 +1245,8 @@ ControlObject_initialize(ControlObject* self) self->tOpOk = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, tOpOkName); - if ((self->tOpOk) && (self->tOpOk->type != IEC61850_TIMESTAMP)) { + if ((self->tOpOk) && (self->tOpOk->type != IEC61850_TIMESTAMP)) + { self->tOpOk = NULL; if (DEBUG_IED_SERVER) @@ -1197,7 +1256,8 @@ ControlObject_initialize(ControlObject* self) self->error = MmsValue_newIntegerFromInt32(0); self->addCause = MmsValue_newIntegerFromInt32(0); - if (ctlModel != NULL) { + if (ctlModel != NULL) + { int ctlModelVal = MmsValue_toInt32(ctlModel); if (DEBUG_IED_SERVER) @@ -1225,44 +1285,50 @@ ControlObject_handlePendingEvents(ControlObject* self) Semaphore_wait(self->pendingEventsLock); #endif - if (self->pendingEvents > 0) { - - if (self->pendingEvents & PENDING_EVENT_SELECTED) { + if (self->pendingEvents > 0) + { + if (self->pendingEvents & PENDING_EVENT_SELECTED) + { if (self->stSeld) IedServer_updateBooleanAttributeValue(self->iedServer, self->stSeld, true); self->pendingEvents &= ~(PENDING_EVENT_SELECTED); } - if (self->pendingEvents & PENDING_EVENT_UNSELECTED) { + if (self->pendingEvents & PENDING_EVENT_UNSELECTED) + { if (self->stSeld) IedServer_updateBooleanAttributeValue(self->iedServer, self->stSeld, false); self->pendingEvents &= ~(PENDING_EVENT_UNSELECTED); } - if (self->pendingEvents & PENDING_EVENT_OP_RCVD_TRUE) { + if (self->pendingEvents & PENDING_EVENT_OP_RCVD_TRUE) + { if (self->opRcvd) IedServer_updateBooleanAttributeValue(self->iedServer, self->opRcvd, true); self->pendingEvents &= ~(PENDING_EVENT_OP_RCVD_TRUE); } - if (self->pendingEvents & PENDING_EVENT_OP_RCVD_FALSE) { + if (self->pendingEvents & PENDING_EVENT_OP_RCVD_FALSE) + { if (self->opRcvd) IedServer_updateBooleanAttributeValue(self->iedServer, self->opRcvd, false); self->pendingEvents &= ~(PENDING_EVENT_OP_RCVD_FALSE); } - if (self->pendingEvents & PENDING_EVENT_OP_OK_TRUE) { + if (self->pendingEvents & PENDING_EVENT_OP_OK_TRUE) + { if (self->opOk) IedServer_updateBooleanAttributeValue(self->iedServer, self->opOk, true); self->pendingEvents &= ~(PENDING_EVENT_OP_OK_TRUE); } - if (self->pendingEvents & PENDING_EVENT_OP_OK_FALSE) { + if (self->pendingEvents & PENDING_EVENT_OP_OK_FALSE) + { if (self->opOk) IedServer_updateBooleanAttributeValue(self->iedServer, self->opOk, false); @@ -1278,7 +1344,8 @@ ControlObject_handlePendingEvents(ControlObject* self) void ControlObject_destroy(ControlObject* self) { - if (self) { + if (self) + { if (self->mmsValue) MmsValue_delete(self->mmsValue); @@ -1357,7 +1424,8 @@ ControlObject_getMmsValue(ControlObject* self) bool ControlObject_unselect(ControlObject* self, MmsServerConnection connection, MmsMapping* mmsMapping) { - if (self->mmsConnection == connection) { + if (self->mmsConnection == connection) + { abortControlOperation(self, true, SELECT_STATE_REASON_DISCONNECTED, mmsMapping); return true; } @@ -1415,29 +1483,32 @@ ControlObject_updateControlModel(ControlObject* self, ControlModel value, DataOb void Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) { - if (currentTimeInMs >= self->nextControlTimeout) { - + if (currentTimeInMs >= self->nextControlTimeout) + { /* invalidate nextControlTimeout */ self->nextControlTimeout = (uint64_t) 0xFFFFFFFFFFFFFFFFLLU; LinkedList element = LinkedList_getNext(self->controlObjects); - while (element != NULL) { + while (element != NULL) + { ControlObject* controlObject = (ControlObject*) element->data; - if (controlObject->state != STATE_UNSELECTED) { - - if ((controlObject->ctlModel == 1) || (controlObject->ctlModel == 3)) { - if (controlObject->state == STATE_READY) { + if (controlObject->state != STATE_UNSELECTED) + { + if ((controlObject->ctlModel == 1) || (controlObject->ctlModel == 3)) + { + if (controlObject->state == STATE_READY) + { element = LinkedList_getNext(element); continue; } } - if (controlObject->state == STATE_WAIT_FOR_ACTIVATION_TIME) { - - if (controlObject->operateTime <= currentTimeInMs) { - + if (controlObject->state == STATE_WAIT_FOR_ACTIVATION_TIME) + { + if (controlObject->operateTime <= currentTimeInMs) + { /* enter state Perform Test */ setOpRcvd(controlObject, true); @@ -1448,7 +1519,9 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) CheckHandlerResult checkResult = CONTROL_ACCEPTED; - if (controlObject->checkHandler != NULL) { /* perform operative tests */ + if (controlObject->checkHandler != NULL) + { + /* perform operative tests */ controlObject->errorValue = CONTROL_ERROR_NO_ERROR; controlObject->addCauseValue = ADD_CAUSE_BLOCKED_BY_INTERLOCKING; @@ -1458,8 +1531,8 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) controlObject->interlockCheck); } - if (checkResult == CONTROL_ACCEPTED) { - + if (checkResult == CONTROL_ACCEPTED) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: time activated operate: command accepted\n"); @@ -1468,8 +1541,8 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) executeControlTask(self, controlObject, currentTimeInMs); } - else { - + else + { ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "Oper", controlObject->errorValue, controlObject->addCauseValue, controlObject->ctlNum, controlObject->origin, false); @@ -1512,12 +1585,16 @@ Control_lookupControlObject(MmsMapping* self, MmsDomain* domain, char* lnName, c { LinkedList element = LinkedList_getNext(self->controlObjects); - while (element != NULL) { + while (element != NULL) + { ControlObject* controlObject = (ControlObject*) element->data; - if (ControlObject_getDomain(controlObject) == domain) { - if (strcmp(ControlObject_getLNName(controlObject), lnName) == 0) { - if (strcmp(ControlObject_getName(controlObject), objectName) == 0) { + if (ControlObject_getDomain(controlObject) == domain) + { + if (strcmp(ControlObject_getLNName(controlObject), lnName) == 0) + { + if (strcmp(ControlObject_getName(controlObject), objectName) == 0) + { return controlObject; } } @@ -1532,8 +1609,10 @@ Control_lookupControlObject(MmsMapping* self, MmsDomain* domain, char* lnName, c static MmsValue* getCtlVal(MmsValue* operParameters) { - if (MmsValue_getType(operParameters) == MMS_STRUCTURE) { - if (MmsValue_getArraySize(operParameters) > 5) { + if (MmsValue_getType(operParameters) == MMS_STRUCTURE) + { + if (MmsValue_getArraySize(operParameters) > 5) + { return MmsValue_getElement(operParameters, 0); } } @@ -1678,7 +1757,8 @@ ControlObject_sendLastApplError(ControlObject* self, MmsServerConnection connect StringUtils_createStringInBuffer(ctlObj, 130, 7, MmsDomain_getName(self->mmsDomain), "/", self->lnName, "$CO$", self->name, "$", ctlVariable); - if (DEBUG_IED_SERVER) { + if (DEBUG_IED_SERVER) + { printf("IED_SERVER: sendLastApplError:\n"); printf("IED_SERVER: control object: %s\n", ctlObj); printf("IED_SERVER: ctlNum: %u\n", MmsValue_toUint32(ctlNum)); @@ -1728,7 +1808,8 @@ doesElementEquals(char* element, char* name) { int i = 0; - while (name[i] != 0) { + while (name[i] != 0) + { if (element[i] == 0) return false; @@ -1766,9 +1847,6 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia char* lnName = variableId; - if (lnName == NULL) - return NULL; - char* objectName = MmsMapping_getNextNameElement(separator + 1); if (objectName == NULL) @@ -1776,13 +1854,14 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) { - + if (varName != NULL) + { bool foundVar = false; char* nextVarName = varName; - do { + do + { if (doesElementEquals(varName, "Oper") || doesElementEquals(varName, "SBO") || doesElementEquals(varName, "SBOw") || @@ -1795,10 +1874,10 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia nextVarName = MmsMapping_getNextNameElement(varName); - if (nextVarName != NULL) + if (nextVarName) varName = nextVarName; - } while (nextVarName != NULL); + } while (nextVarName); if (foundVar == false) varName = NULL; @@ -1809,24 +1888,28 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia ControlObject* controlObject = Control_lookupControlObject(self, domain, lnName, objectName); - if (controlObject != NULL) { - - if (varName != NULL) { + if (controlObject != NULL) + { + if (varName != NULL) + { if (strcmp(varName, "Oper") == 0) value = controlObject->oper; else if (strcmp(varName, "SBOw") == 0) value = controlObject->sbow; - else if (strcmp(varName, "SBO") == 0) { - if (controlObject->ctlModel == 2) { - + else if (strcmp(varName, "SBO") == 0) + { + if (controlObject->ctlModel == 2) + { uint64_t currentTime = Hal_getTimeInMs(); value = &emptyString; - if (isDirectAccess == true) { + if (isDirectAccess == true) + { checkSelectTimeout(controlObject, currentTime, self); - if (getState(controlObject) == STATE_UNSELECTED) { + if (getState(controlObject) == STATE_UNSELECTED) + { CheckHandlerResult checkResult = CONTROL_ACCEPTED; /* opRcvd must not be set here! */ @@ -1834,7 +1917,9 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia controlObject->addCauseValue = ADD_CAUSE_UNKNOWN; controlObject->mmsConnection = connection; - if (controlObject->checkHandler != NULL) { /* perform operative tests */ + if (controlObject->checkHandler != NULL) + { + /* perform operative tests */ controlObject->isSelect = 1; @@ -1844,7 +1929,8 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia controlObject->isSelect = 0; } - if (checkResult == CONTROL_ACCEPTED) { + if (checkResult == CONTROL_ACCEPTED) + { selectObject(controlObject, currentTime, connection, self); value = controlObject->sbo; @@ -1852,13 +1938,15 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia updateGenericTrackingObjectValues(self, controlObject, IEC61850_SERVICE_TYPE_SELECT, IEC61850_SERVICE_ERROR_NO_ERROR); #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ } - else if (checkResult == CONTROL_WAITING_FOR_SELECT) { + else if (checkResult == CONTROL_WAITING_FOR_SELECT) + { controlObject->mmsConnection = connection; controlObject->operateInvokeId = MmsServerConnection_getLastInvokeId(connection); setState(controlObject, STATE_WAIT_FOR_SELECT); value = &delayedResponse; } - else { + else + { #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) updateGenericTrackingObjectValues(self, controlObject, IEC61850_SERVICE_TYPE_SELECT, convertCheckHandlerResultToServiceError(checkResult)); @@ -1866,9 +1954,9 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia } } } - } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: select not applicable for control model %u\n", controlObject->ctlModel); @@ -1878,7 +1966,8 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia else if (strcmp(varName, "Cancel") == 0) value = controlObject->cancel; - else { + else + { value = MmsValue_getSubElement(ControlObject_getMmsValue(controlObject), ControlObject_getTypeSpec(controlObject), varName); } @@ -1887,7 +1976,8 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia value = ControlObject_getMmsValue(controlObject); } } - else { + else + { if (DEBUG_IED_SERVER) printf("IED_SERVER: Control object not found %s/%s.%s\n", domain->domainName, lnName, objectName); } @@ -1926,7 +2016,7 @@ checkValidityOfOriginParameter(MmsValue* origin) } MmsDataAccessError -Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, +Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig, MmsValue* value, MmsServerConnection connection) { MmsDataAccessError indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; @@ -1961,13 +2051,14 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari char* varName = MmsMapping_getNextNameElement(objectName); - if (varName != NULL) { - + if (varName != NULL) + { bool foundVar = false; char* nextVarName = varName; - do { + do + { if (doesElementEquals(varName, "Oper") || doesElementEquals(varName, "SBO") || doesElementEquals(varName, "SBOw") || @@ -1992,31 +2083,36 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari if (DEBUG_IED_SERVER) printf("IED_SERVER: write access control: objectName: (%s) varName: (%s)\n", objectName, varName); - if (varName == NULL) { + if (varName == NULL) + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } controlObject = Control_lookupControlObject(self, domain, lnName, objectName); - if (controlObject == NULL) { + if (controlObject == NULL) + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } - if (controlObject->ctlModel == CONTROL_MODEL_STATUS_ONLY) { + if (controlObject->ctlModel == CONTROL_MODEL_STATUS_ONLY) + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } - if (strcmp(varName, "SBOw") == 0) { /* select with value */ - + if (strcmp(varName, "SBOw") == 0) /* select with value */ + { serviceType = IEC61850_SERVICE_TYPE_SELECT_WITH_VALUES; - if (controlObject->ctlModel == 4) { - - if (controlObject->sbow) { - if (MmsValue_update(controlObject->sbow, value) == false) { + if (controlObject->ctlModel == 4) + { + if (controlObject->sbow) + { + if (MmsValue_update(controlObject->sbow, value) == false) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: SBOw - type mismatch\n"); } @@ -2024,14 +2120,16 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari MmsValue* ctlVal = getCtlVal(value); - if (ctlVal != NULL) { - + if (ctlVal != NULL) + { MmsValue* ctlNum = getOperParameterCtlNum(value); MmsValue* origin = getOperParameterOrigin(value); MmsValue* check = getOperParameterCheck(value); MmsValue* test = getOperParameterTest(value); + MmsValue* t = getOperParameterTime(value); - if (checkValidityOfOriginParameter(origin) == false) { + if (checkValidityOfOriginParameter(origin) == false) + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; ControlObject_sendLastApplError(controlObject, connection, "SBOw", CONTROL_ERROR_NO_ERROR, @@ -2043,15 +2141,21 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } + if (t) + { + Timestamp_fromMmsValue(&(controlObject->T), t); + } + int state = getState(controlObject); uint64_t currentTime = Hal_getTimeInMs(); checkSelectTimeout(controlObject, currentTime, self); - if (state != STATE_UNSELECTED) { - - if ((state == STATE_OPERATE) || (state == STATE_WAIT_FOR_EXECUTION)) { + if (state != STATE_UNSELECTED) + { + if ((state == STATE_OPERATE) || (state == STATE_WAIT_FOR_EXECUTION)) + { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "SBOw", @@ -2063,7 +2167,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } - else { + else + { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "SBOw", CONTROL_ERROR_NO_ERROR, @@ -2075,8 +2180,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } } - else { - + else + { CheckHandlerResult checkResult = CONTROL_ACCEPTED; /* opRcvd must not be set here! */ @@ -2091,7 +2196,9 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari controlObject->testMode = testCondition; - if (controlObject->checkHandler != NULL) { /* perform operative tests */ + if (controlObject->checkHandler != NULL) + { + /* perform operative tests */ controlObject->isSelect = 1; @@ -2103,7 +2210,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari controlObject->isSelect = 0; } - if (checkResult == CONTROL_ACCEPTED) { + if (checkResult == CONTROL_ACCEPTED) + { selectObject(controlObject, currentTime, connection, self); indication = DATA_ACCESS_ERROR_SUCCESS; @@ -2111,7 +2219,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari if (DEBUG_IED_SERVER) printf("IED_SERVER: SBOw - selected successful\n"); } - else if (checkResult == CONTROL_WAITING_FOR_SELECT) { + else if (checkResult == CONTROL_WAITING_FOR_SELECT) + { controlObject->mmsConnection = connection; controlObject->operateInvokeId = MmsServerConnection_getLastInvokeId(connection); @@ -2125,7 +2234,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari indication = DATA_ACCESS_ERROR_NO_RESPONSE; } - else { + else + { indication = (MmsDataAccessError) checkResult; ControlObject_sendLastApplError(controlObject, connection, "SBOw", controlObject->errorValue, @@ -2138,17 +2248,19 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari } } } - else { + else + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; } } - else { + else + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } } - else if (strcmp(varName, "Oper") == 0) { - + else if (strcmp(varName, "Oper") == 0) + { serviceType = IEC61850_SERVICE_TYPE_OPERATE; MmsValue* ctlVal = getCtlVal(value); @@ -2159,19 +2271,24 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari MmsValue* timeParameter = getOperParameterTime(value); if ((ctlVal == NULL) || (test == NULL) || (ctlNum == NULL) || (origin == NULL) || (check == NULL) - || (timeParameter == NULL)) { + || (timeParameter == NULL)) + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; goto free_and_return; } - if (checkValidityOfOriginParameter(origin) == false) { + Timestamp_fromMmsValue(&(controlObject->T), timeParameter); + + if (checkValidityOfOriginParameter(origin) == false) + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; ControlObject_sendLastApplError(controlObject, connection, "Oper", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_INCONSISTENT_PARAMETERS, ctlNum, origin, true); - if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { + if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) + { unselectObject(controlObject, SELECT_STATE_REASON_OPERATE_FAILED, self); } @@ -2184,7 +2301,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari int state = getState(controlObject); - if (state == STATE_WAIT_FOR_ACTIVATION_TIME) { + if (state == STATE_WAIT_FOR_ACTIVATION_TIME) + { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "Oper", @@ -2193,15 +2311,17 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } - else if (state == STATE_READY) { - + else if (state == STATE_READY) + { bool interlockCheck = MmsValue_getBitStringBit(check, 1); bool synchroCheck = MmsValue_getBitStringBit(check, 0); bool testCondition = MmsValue_getBoolean(test); - if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { - if (controlObject->mmsConnection != connection) { + if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) + { + if (controlObject->mmsConnection != connection) + { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; if (DEBUG_IED_SERVER) printf("IED_SERVER: Oper - operate from wrong client connection!\n"); @@ -2212,7 +2332,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } - if (controlObject->ctlModel == 4) { /* select-before-operate with enhanced security */ + if (controlObject->ctlModel == 4) /* select-before-operate with enhanced security */ + { if ((MmsValue_equals(ctlVal, controlObject->ctlVal) && MmsValue_equals(origin, controlObject->origin) && MmsValue_equals(ctlNum, controlObject->ctlNum) && @@ -2240,24 +2361,29 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari MmsValue* operTm = getOperParameterOperTime(value); - if (operTm != NULL) { + if (operTm != NULL) + { controlObject->operateTime = MmsValue_getUtcTimeInMs(operTm); - if (controlObject->operateTime > currentTime) { + if (controlObject->operateTime > currentTime) + { controlObject->timeActivatedOperate = true; controlObject->synchroCheck = synchroCheck; controlObject->interlockCheck = interlockCheck; controlObject->mmsConnection = connection; CheckHandlerResult checkResult = CONTROL_ACCEPTED; - if (controlObject->checkHandler != NULL) { /* perform operative tests */ + if (controlObject->checkHandler != NULL) + { + /* perform operative tests */ checkResult = controlObject->checkHandler((ControlAction) controlObject, controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck); } - if (checkResult == CONTROL_ACCEPTED) { + if (checkResult == CONTROL_ACCEPTED) + { initiateControlTask(controlObject); setState(controlObject, STATE_WAIT_FOR_ACTIVATION_TIME); @@ -2269,19 +2395,21 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari indication = DATA_ACCESS_ERROR_SUCCESS; } - else { + else + { indication = (MmsDataAccessError) checkResult; } } } - else{ + else + { controlObject->operateTime = 0; } MmsValue_update(controlObject->oper, value); - if (controlObject->timeActivatedOperate == false) { - + if (controlObject->timeActivatedOperate == false) + { CheckHandlerResult checkResult = CONTROL_ACCEPTED; /* enter state Perform Test */ @@ -2291,13 +2419,16 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari controlObject->addCauseValue = ADD_CAUSE_UNKNOWN; controlObject->mmsConnection = connection; - if (controlObject->checkHandler != NULL) { /* perform operative tests */ + if (controlObject->checkHandler != NULL) + { + /* perform operative tests */ checkResult = controlObject->checkHandler((ControlAction) controlObject, controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck); } - if (checkResult == CONTROL_ACCEPTED) { + if (checkResult == CONTROL_ACCEPTED) + { indication = DATA_ACCESS_ERROR_NO_RESPONSE; controlObject->mmsConnection = connection; @@ -2313,7 +2444,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari updateNextControlTimeout(self, currentTime); } - else { + else + { indication = (MmsDataAccessError) checkResult; /* leave state Perform Test */ @@ -2321,7 +2453,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATE_FAILED, self); - if ((controlObject->ctlModel == 3) || (controlObject->ctlModel == 4)) { + if ((controlObject->ctlModel == 3) || (controlObject->ctlModel == 4)) + { ControlObject_sendLastApplError(controlObject, connection, "Oper", controlObject->errorValue, controlObject->addCauseValue, ctlNum, origin, true); @@ -2330,7 +2463,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari } } - else if (state == STATE_UNSELECTED) { + else if (state == STATE_UNSELECTED) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: Oper failed - control not selected!\n"); @@ -2343,7 +2477,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } - else if ((state == STATE_OPERATE) || (state == STATE_WAIT_FOR_EXECUTION)) { + else if ((state == STATE_OPERATE) || (state == STATE_WAIT_FOR_EXECUTION)) + { if (DEBUG_IED_SERVER) printf("IED_SERVER: Oper failed - control already being executed!\n"); @@ -2356,8 +2491,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } } - else if (strcmp(varName, "Cancel") == 0) { - + else if (strcmp(varName, "Cancel") == 0) + { serviceType = IEC61850_SERVICE_TYPE_CANCEL; int state = getState(controlObject); @@ -2368,14 +2503,16 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari MmsValue* ctlNum = getCancelParameterCtlNum(value); MmsValue* origin = getCancelParameterOrigin(value); - if ((ctlNum == NULL) || (origin == NULL)) { + if ((ctlNum == NULL) || (origin == NULL)) + { indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; if (DEBUG_IED_SERVER) printf("IED_SERVER: Invalid cancel message!\n"); goto free_and_return; } - if ((state == STATE_OPERATE) || (state == STATE_WAIT_FOR_EXECUTION)) { + if ((state == STATE_OPERATE) || (state == STATE_WAIT_FOR_EXECUTION)) + { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "Cancel", @@ -2385,26 +2522,32 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } - if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) { - if (state != STATE_UNSELECTED) { - if (controlObject->mmsConnection == connection) { + if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4)) + { + if (state != STATE_UNSELECTED) + { + if (controlObject->mmsConnection == connection) + { indication = DATA_ACCESS_ERROR_SUCCESS; unselectObject(controlObject, SELECT_STATE_REASON_CANCELED, self); goto free_and_return; } - else { + else + { indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; ControlObject_sendLastApplError(controlObject, connection, "Cancel", CONTROL_ERROR_NO_ERROR, ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true); } } - else { + else + { indication = DATA_ACCESS_ERROR_SUCCESS; } } - if (controlObject->timeActivatedOperate) { + if (controlObject->timeActivatedOperate) + { controlObject->timeActivatedOperate = false; abortControlOperation(controlObject, false, SELECT_STATE_REASON_CANCELED, self); @@ -2417,14 +2560,18 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari free_and_return: #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) - if (controlObject) { - if (serviceError == IEC61850_SERVICE_ERROR_NO_ERROR) { - if (indication != DATA_ACCESS_ERROR_NO_RESPONSE) { + if (controlObject) + { + if (serviceError == IEC61850_SERVICE_ERROR_NO_ERROR) + { + if (indication != DATA_ACCESS_ERROR_NO_RESPONSE) + { updateGenericTrackingObjectValues(self, controlObject, serviceType, private_IedServer_convertMmsDataAccessErrorToServiceError(indication)); } } - else { + else + { updateGenericTrackingObjectValues(self, controlObject, serviceType, serviceError); } } @@ -2456,7 +2603,8 @@ ControlAction_getOrCat(ControlAction self) { ControlObject* controlObject = (ControlObject*) self; - if (controlObject->origin) { + if (controlObject->origin) + { MmsValue* orCat = MmsValue_getElement(controlObject->origin, 0); if (orCat) { @@ -2472,10 +2620,12 @@ ControlAction_getOrIdent(ControlAction self, int* orIdentSize) { ControlObject* controlObject = (ControlObject*) self; - if (controlObject->origin) { + if (controlObject->origin) + { MmsValue* orIdent = MmsValue_getElement(controlObject->origin, 1); - if (orIdent) { + if (orIdent) + { if (MmsValue_getType(orIdent) == MMS_OCTET_STRING) { *orIdentSize = MmsValue_getOctetStringSize(orIdent); return MmsValue_getOctetStringBuffer(orIdent); @@ -2549,5 +2699,12 @@ ControlAction_getControlTime(ControlAction self) return controlObject->operateTime; } -#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ +Timestamp* +ControlAction_getT(ControlAction self) +{ + ControlObject* controlObject = (ControlObject*) self; + return &(controlObject->T); +} + +#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ diff --git a/src/iec61850/server/mms_mapping/logging.c b/src/iec61850/server/mms_mapping/logging.c index 7fcb78f1..59b0ba40 100644 --- a/src/iec61850/server/mms_mapping/logging.c +++ b/src/iec61850/server/mms_mapping/logging.c @@ -482,7 +482,7 @@ copyLCBValuesToTrackingObject(MmsMapping* self, LogControl* logControl) #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ MmsDataAccessError -LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, +LIBIEC61850_LOG_SVC_writeAccessLogControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig, MmsValue* value, MmsServerConnection connection) { (void)connection; diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 27471a58..1435df2d 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -1,7 +1,7 @@ /* * mms_mapping.c * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -1335,8 +1335,8 @@ checkForServiceTrackingVariables(MmsMapping* self, LogicalNode* logicalNode) { ModelNode* modelNode = logicalNode->firstChild; - while (modelNode) { - + while (modelNode) + { if (!strcmp(modelNode->name, "SpcTrk") || !strcmp(modelNode->name, "DpcTrk") || !strcmp(modelNode->name, "IncTrk") || !strcmp(modelNode->name, "EncTrk1") || !strcmp(modelNode->name, "ApcFTrk") || !strcmp(modelNode->name, "ApcIntTrk") || @@ -2344,7 +2344,7 @@ lookupGCB(MmsMapping* self, MmsDomain* domain, char* lnName, char* objectName) #endif static MmsDataAccessError -writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, +writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig, MmsValue* value, MmsServerConnection connection) { char variableId[130]; @@ -2499,43 +2499,6 @@ writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variable #endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ -#if 0 -static MmsValue* -checkIfValueBelongsToModelNode(DataAttribute* dataAttribute, MmsValue* value, MmsValue* newValue) -{ - if (dataAttribute->mmsValue == value) - return newValue; - - DataAttribute* child = (DataAttribute*) dataAttribute->firstChild; - - while (child != NULL) { - MmsValue* tmpValue = checkIfValueBelongsToModelNode(child, value, newValue); - - if (tmpValue != NULL) - return tmpValue; - else - child = (DataAttribute*) child->sibling; - } - - if (MmsValue_getType(value) == MMS_STRUCTURE) { - int elementCount = MmsValue_getArraySize(value); - - int i; - for (i = 0; i < elementCount; i++) { - MmsValue* childValue = MmsValue_getElement(value, i); - MmsValue* childNewValue = MmsValue_getElement(newValue, i); - - MmsValue* tmpValue = checkIfValueBelongsToModelNode(dataAttribute, childValue, childNewValue); - - if (tmpValue != NULL) - return tmpValue; - } - } - - return NULL; -} -#endif - static FunctionalConstraint getFunctionalConstraintForWritableNode(char* separator) { @@ -2605,16 +2568,28 @@ getAccessPolicyForFC(MmsMapping* self, FunctionalConstraint fc) static MmsDataAccessError mmsWriteHandler(void* parameter, MmsDomain* domain, - char* variableId, MmsValue* value, MmsServerConnection connection) + const char* variableId, int arrayIdx, const char* componentId, MmsValue* value, MmsServerConnection connection) { MmsMapping* self = (MmsMapping*) parameter; if (DEBUG_IED_SERVER) - printf("IED_SERVER: Write requested %s\n", variableId); + { + if (arrayIdx != -1) { + if (componentId) { + printf("IED_SERVER: Write requested %s(%i).%s\n", variableId, arrayIdx, componentId); + } + else { + printf("IED_SERVER: Write requested %s(%i)\n", variableId, arrayIdx); + } + } + else { + printf("IED_SERVER: Write requested %s\n", variableId); + } + } /* Access control based on functional constraint */ - char* separator = strchr(variableId, '$'); + char* separator = (char*)strchr(variableId, '$'); if (separator == NULL) return DATA_ACCESS_ERROR_INVALID_ADDRESS; @@ -2691,7 +2666,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, if (rcNameLen == variableIdLen) { if (strncmp(variableId, rc->name, variableIdLen) == 0) { - char* elementName = variableId + rcNameLen + 1; + const char* elementName = variableId + rcNameLen + 1; return Reporting_RCBWriteAccessHandler(self, rc, elementName, value, connection); } @@ -2713,6 +2688,10 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, if (nextSep != NULL) { nextSep = strchr(nextSep + 1, '$'); + if (nextSep == NULL) { + return DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; + } + char* nameId = nextSep + 1; /* check access permissions */ @@ -2942,13 +2921,19 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, #endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ /* writable data model elements - SP, SV, CF, DC, BL */ - if (fc != IEC61850_FC_NONE) { + if (fc != IEC61850_FC_NONE) + { MmsValue* cachedValue; - cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId); - - if (cachedValue) { + if (arrayIdx != -1) { + cachedValue = MmsServer_getValueFromCacheEx2(self->mmsServer, domain, variableId, arrayIdx, componentId); + } + else { + cachedValue = MmsServer_getValueFromCache(self->mmsServer, domain, variableId); + } + if (cachedValue) + { if (!MmsValue_equalTypes(cachedValue, value)) { return DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } @@ -2961,7 +2946,8 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, printf("IED_SERVER: write to %s policy:%i\n", variableId, nodeAccessPolicy); #if (CONFIG_IEC61850_SETTING_GROUPS == 1) - if (isFunctionalConstraint("SE", separator)) { + if (isFunctionalConstraint("SE", separator)) + { SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); if (sg != NULL) { @@ -2978,12 +2964,13 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, /* Call write access handlers */ LinkedList writeHandlerListElement = LinkedList_getNext(self->attributeAccessHandlers); - while (writeHandlerListElement != NULL) { + while (writeHandlerListElement) + { AttributeAccessHandler* accessHandler = (AttributeAccessHandler*) writeHandlerListElement->data; DataAttribute* dataAttribute = accessHandler->attribute; - if (dataAttribute->mmsValue == cachedValue) { - + if (dataAttribute->mmsValue == cachedValue) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); @@ -2991,7 +2978,8 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, accessHandler->handler(dataAttribute, value, clientConnection, accessHandler->parameter); - if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) { + if ((handlerResult == DATA_ACCESS_ERROR_SUCCESS) || (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE)) + { handlerFound = true; if (handlerResult == DATA_ACCESS_ERROR_SUCCESS_NO_UPDATE) @@ -3007,14 +2995,14 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, } /* DENY access if no handler is found and default policy is DENY */ - if (!handlerFound) { - + if (!handlerFound) + { if (nodeAccessPolicy == ACCESS_POLICY_DENY) return DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; - } - if (updateValue) { + if (updateValue) + { DataAttribute* da = IedModel_lookupDataAttributeByMmsValue(self->model, cachedValue); if (da) @@ -3161,7 +3149,6 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo } #endif - #if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) /* GOOSE control blocks - GO */ if (isGooseControlBlock(separator)) { @@ -3188,8 +3175,8 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo #if (CONFIG_IEC61850_REPORT_SERVICE == 1) /* Report control blocks - BR, RP */ - if (isReportControlBlock(separator)) { - + if (isReportControlBlock(separator)) + { LinkedList reportControls = self->reportControls; LinkedList nextElement = reportControls; @@ -3210,11 +3197,12 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo else variableIdLen = strlen(variableId); - while ((nextElement = LinkedList_getNext(nextElement)) != NULL) { + while ((nextElement = LinkedList_getNext(nextElement)) != NULL) + { ReportControl* rc = (ReportControl*) nextElement->data; - if (rc->domain == domain) { - + if (rc->domain == domain) + { int parentLNNameStrLen = strlen(rc->parentLN->name); if (parentLNNameStrLen != lnNameLength) @@ -3223,7 +3211,8 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo if (memcmp(rc->parentLN->name, variableId, parentLNNameStrLen) != 0) continue; - if (strlen(rc->name) == variableIdLen) { + if (strlen(rc->name) == variableIdLen) + { if (strncmp(variableId, rc->name, variableIdLen) == 0) { char* elementName = MmsMapping_getNextNameElement(reportName); @@ -3640,15 +3629,26 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS if (DEBUG_IED_SERVER) printf("IED_SERVER: mmsReadAccessHandler: Requested %s\n", variableId); + if (self->iedServer->ignoreReadAccess) + { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: mmsReadAccessHandler - ignore request\n"); + + return DATA_ACCESS_ERROR_NO_RESPONSE; + } + char* separator = strchr(variableId, '$'); #if (CONFIG_IEC61850_SETTING_GROUPS == 1) - if (separator) { - if (isFunctionalConstraint("SE", separator)) { + if (separator) + { + if (isFunctionalConstraint("SE", separator)) + { SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); - if (sg != NULL) { + if (sg != NULL) + { if (sg->sgcb->editSG == 0) return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; } @@ -3670,7 +3670,8 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS { FunctionalConstraint fc = IEC61850_FC_NONE; - if (separator != NULL) { + if (separator != NULL) + { fc = FunctionalConstraint_fromString(separator + 1); if (fc == IEC61850_FC_BR || fc == IEC61850_FC_US || @@ -3691,23 +3692,27 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS { char* doStart = strchr(separator + 1, '$'); - if (doStart != NULL) { - + if (doStart != NULL) + { char* doEnd = strchr(doStart + 1, '$'); - if (doEnd == NULL) { + if (doEnd == NULL) + { StringUtils_copyStringToBuffer(doStart + 1, str); } - else { + else + { doEnd--; StringUtils_createStringFromBufferInBuffer(str, (uint8_t*) (doStart + 1), doEnd - doStart); } - if (fc == IEC61850_FC_SP) { + if (fc == IEC61850_FC_SP) + { if (!strcmp(str, "SGCB")) { - if (self->controlBlockAccessHandler) { + if (self->controlBlockAccessHandler) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); @@ -3722,10 +3727,10 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS ModelNode* dobj = ModelNode_getChild((ModelNode*) ln, str); - if (dobj != NULL) { - - if (dobj->modelType == DataObjectModelType) { - + if (dobj != NULL) + { + if (dobj->modelType == DataObjectModelType) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); @@ -3734,7 +3739,8 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS } } } - else { + else + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); @@ -3744,10 +3750,12 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS } } } - else { + else + { LogicalNode* ln = LogicalDevice_getLogicalNode(ld, variableId); - if (ln != NULL) { + if (ln != NULL) + { ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); return self->readAccessHandler(ld, ln, NULL, fc, clientConnection, @@ -4219,10 +4227,12 @@ MmsMapping_triggerReportObservers(MmsMapping* self, MmsValue* value, int flag) bool modelLocked = self->isModelLocked; - while ((element = LinkedList_getNext(element)) != NULL) { + while ((element = LinkedList_getNext(element)) != NULL) + { ReportControl* rc = (ReportControl*) element->data; - if (rc->enabled || (rc->buffered && rc->dataSet != NULL)) { + if (rc->enabled || (rc->buffered && rc->dataSet != NULL)) + { int index; switch (flag) { diff --git a/src/iec61850/server/mms_mapping/mms_sv.c b/src/iec61850/server/mms_mapping/mms_sv.c index ef2ad775..3fbd0d2b 100644 --- a/src/iec61850/server/mms_mapping/mms_sv.c +++ b/src/iec61850/server/mms_mapping/mms_sv.c @@ -131,7 +131,7 @@ MmsSampledValueControlBlock_isEnabled(MmsSampledValueControlBlock self) } MmsDataAccessError -LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, char* variableIdOrig, +LIBIEC61850_SV_writeAccessSVControlBlock(MmsMapping* self, MmsDomain* domain, const char* variableIdOrig, MmsValue* value, MmsServerConnection connection) { char variableId[130]; diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 493d5e48..0bb683f1 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1,7 +1,7 @@ /* * reporting.c * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -185,7 +185,8 @@ purgeBuf(ReportControl* rc) static void deleteDataSetValuesShadowBuffer(ReportControl* self) { - if (self->bufferedDataSetValues != NULL) { + if (self->bufferedDataSetValues != NULL) + { assert(self->dataSet != NULL); int dataSetSize = DataSet_getSize(self->dataSet); @@ -252,7 +253,7 @@ ReportControl_destroy(ReportControl* self) } MmsValue* -ReportControl_getRCBValue(ReportControl* rc, char* elementName) +ReportControl_getRCBValue(ReportControl* rc, const char* elementName) { if (rc->buffered) { if (strcmp(elementName, "RptID") == 0) @@ -460,7 +461,7 @@ copyRCBValuesToTrackingObject(MmsMapping* self, ReportControl* rc) } static void -updateSingleTrackingValue(MmsMapping* self, ReportControl* rc, char* name, MmsValue* newValue) +updateSingleTrackingValue(MmsMapping* self, ReportControl* rc, const char* name, MmsValue* newValue) { if (rc->buffered) { if (self->brcbTrk) { @@ -1906,7 +1907,7 @@ reserveRcb(ReportControl* rc, MmsServerConnection connection) } MmsDataAccessError -Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value, +Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, const char* elementName, MmsValue* value, MmsServerConnection connection) { MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; @@ -2911,13 +2912,14 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ int dataBlockSize = 0; - if (isIntegrity || isGI) { - + if (isIntegrity || isGI) + { DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas; int i; - for (i = 0; i < inclusionBitStringSize; i++) { + for (i = 0; i < inclusionBitStringSize; i++) + { /* don't need reason for inclusion in GI or integrity report */ int encodedSize; @@ -2925,7 +2927,8 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (dataSetEntry->value) { encodedSize = MmsValue_encodeMmsData(dataSetEntry->value, NULL, 0, false); } - else { + else + { MmsValue _errVal; _errVal.type = MMS_DATA_ACCESS_ERROR; _errVal.value.dataAccessError = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; @@ -2940,17 +2943,19 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ bufferEntrySize += MemoryAllocator_getAlignedSize(sizeof(int) + dataBlockSize); /* add aligned_size(LEN + DATA) */ } - else { /* other trigger reason */ + else + { + /* other trigger reason */ bufferEntrySize += inclusionFieldSize; int reasonForInclusionSize = 0; int i; - for (i = 0; i < inclusionBitStringSize; i++) { - - if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) { - + for (i = 0; i < inclusionBitStringSize; i++) + { + if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) + { reasonForInclusionSize++; assert(reportControl->bufferedDataSetValues[i] != NULL); @@ -2985,13 +2990,15 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (DEBUG_IED_SERVER) printf("IED_SERVER: number of reports in report buffer: %i\n", buffer->reportsCount); - if (buffer->lastEnqueuedReport == NULL) { /* buffer is empty - we start at the beginning of the memory block */ + if (buffer->lastEnqueuedReport == NULL) + { + /* buffer is empty - we start at the beginning of the memory block */ entryBufPos = buffer->memoryBlock; buffer->oldestReport = (ReportBufferEntry*) entryBufPos; buffer->nextToTransmit = (ReportBufferEntry*) entryBufPos; } - else { - + else + { assert(buffer->lastEnqueuedReport != NULL); assert(buffer->oldestReport != NULL); @@ -3003,12 +3010,16 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ if (DEBUG_IED_SERVER) printf ("IED_SERVER: Last buffer offset: %i\n", (int) ((uint8_t*) buffer->lastEnqueuedReport - buffer->memoryBlock)); - if (buffer->lastEnqueuedReport == buffer->oldestReport) { /* --> buffer->reportsCount == 1 */ + if (buffer->lastEnqueuedReport == buffer->oldestReport) + { + /* --> buffer->reportsCount == 1 */ assert(buffer->reportsCount == 1); entryBufPos = (uint8_t*) ((uint8_t*) buffer->lastEnqueuedReport + buffer->lastEnqueuedReport->entryLength); - if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) { /* buffer overflow */ + if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) + { + /* buffer overflow */ entryBufPos = buffer->memoryBlock; #if (DEBUG_IED_SERVER == 1) @@ -3022,7 +3033,8 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ buffer->oldestReport->next = NULL; buffer->nextToTransmit = NULL; } - else { + else + { if (buffer->nextToTransmit == buffer->oldestReport) buffer->nextToTransmit = buffer->lastEnqueuedReport; @@ -3031,17 +3043,22 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ } } - else if (buffer->lastEnqueuedReport > buffer->oldestReport) { + else if (buffer->lastEnqueuedReport > buffer->oldestReport) + { entryBufPos = (uint8_t*) ((uint8_t*) buffer->lastEnqueuedReport + buffer->lastEnqueuedReport->entryLength); - if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) { /* buffer overflow */ + if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) + { + /* buffer overflow */ entryBufPos = buffer->memoryBlock; /* remove old reports until enough space for new entry is available */ - while ((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) { + while ((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) + { assert(buffer->oldestReport != NULL); - if (buffer->nextToTransmit == buffer->oldestReport) { + if (buffer->nextToTransmit == buffer->oldestReport) + { buffer->nextToTransmit = buffer->oldestReport->next; buffer->isOverflow = true; overflow = true; @@ -3056,7 +3073,8 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ buffer->reportsCount--; - if (buffer->oldestReport == NULL) { + if (buffer->oldestReport == NULL) + { buffer->oldestReport = (ReportBufferEntry*) entryBufPos; buffer->oldestReport->next = NULL; break; @@ -3066,14 +3084,18 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ buffer->lastEnqueuedReport->next = (ReportBufferEntry*) entryBufPos; } - else if (buffer->lastEnqueuedReport < buffer->oldestReport) { + else if (buffer->lastEnqueuedReport < buffer->oldestReport) + { entryBufPos = (uint8_t*) ((uint8_t*) buffer->lastEnqueuedReport + buffer->lastEnqueuedReport->entryLength); - if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) { /* buffer overflow */ + if ((entryBufPos + bufferEntrySize) > (buffer->memoryBlock + buffer->memoryBlockSize)) + { + /* buffer overflow */ entryBufPos = buffer->memoryBlock; /* remove older reports in upper buffer part */ - while ((uint8_t*) buffer->oldestReport > buffer->memoryBlock) { + while ((uint8_t*) buffer->oldestReport > buffer->memoryBlock) + { assert(buffer->oldestReport != NULL); if (buffer->nextToTransmit == buffer->oldestReport) { @@ -3093,13 +3115,15 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ } /* remove older reports in lower buffer part that will be overwritten by new report */ - while ((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) { + while ((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) + { if (buffer->oldestReport == NULL) break; assert(buffer->oldestReport != NULL); - if (buffer->nextToTransmit == buffer->oldestReport) { + if (buffer->nextToTransmit == buffer->oldestReport) + { buffer->nextToTransmit = buffer->oldestReport->next; buffer->isOverflow = true; overflow = true; @@ -3115,15 +3139,17 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ buffer->reportsCount--; } } - else { - while (((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) && ((uint8_t*) buffer->oldestReport != buffer->memoryBlock)) { - + else + { + while (((entryBufPos + bufferEntrySize) > (uint8_t*) buffer->oldestReport) && ((uint8_t*) buffer->oldestReport != buffer->memoryBlock)) + { if (buffer->oldestReport == NULL) break; assert(buffer->oldestReport != NULL); - if (buffer->nextToTransmit == buffer->oldestReport) { + if (buffer->nextToTransmit == buffer->oldestReport) + { buffer->nextToTransmit = buffer->oldestReport->next; buffer->isOverflow = true; overflow = true; @@ -3154,7 +3180,8 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ entry->timeOfEntry = timeOfEntry; - if (isBuffered) { + if (isBuffered) + { /* ENTRY_ID is set to system time in ms! */ uint64_t entryId = timeOfEntry; @@ -3173,7 +3200,8 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ printf(" at pos %p\n", entryStartPos); #endif - if (reportControl->enabled == false) { + if (reportControl->enabled == false) + { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(reportControl->rcbValuesLock); #endif @@ -3200,7 +3228,8 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ entryBufPos += MemoryAllocator_getAlignedSize(sizeof(ReportBufferEntry)); - if (isIntegrity || isGI) { + if (isIntegrity || isGI) + { DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas; /* encode LEN */ @@ -3210,12 +3239,13 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ /* encode DATA */ int i; - for (i = 0; i < inclusionBitStringSize; i++) { - + for (i = 0; i < inclusionBitStringSize; i++) + { if (dataSetEntry->value) { entryBufPos += MmsValue_encodeMmsData(dataSetEntry->value, entryBufPos, 0, true); } - else { + else + { MmsValue _errVal; _errVal.type = MMS_DATA_ACCESS_ERROR; _errVal.value.dataAccessError = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; @@ -3225,9 +3255,9 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ dataSetEntry = dataSetEntry->sibling; } - } - else { + else + { /* encode inclusion bit string */ inclusionFieldStatic.value.bitString.buf = entryBufPos; memset(entryBufPos, 0, inclusionFieldSize); @@ -3240,10 +3270,10 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ /* encode DATA */ int i; - for (i = 0; i < inclusionBitStringSize; i++) { - - if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) { - + for (i = 0; i < inclusionBitStringSize; i++) + { + if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) + { /* update inclusion bit string for report entry */ MmsValue_setBitStringBit(inclusionField, i, true); @@ -3251,13 +3281,14 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ entryBufPos += MmsValue_encodeMmsData(reportControl->bufferedDataSetValues[i], entryBufPos, 0, true); } - } /* encode REASON */ - for (i = 0; i < inclusionBitStringSize; i++) { + for (i = 0; i < inclusionBitStringSize; i++) + { - if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) { + if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) + { *entryBufPos = (uint8_t) reportControl->inclusionFlags[i]; entryBufPos ++; } @@ -3286,10 +3317,12 @@ exit_function: Semaphore_post(buffer->lock); #endif - if (reportControl->server) { + if (reportControl->server) + { MmsMapping* mmsMapping = reportControl->server->mmsMapping; - if (mmsMapping->rcbEventHandler) { + if (mmsMapping->rcbEventHandler) + { if (overflow) { mmsMapping->rcbEventHandler(mmsMapping->rcbEventHandlerParameter, reportControl->rcb, NULL, RCB_EVENT_OVERFLOW, NULL, DATA_ACCESS_ERROR_SUCCESS); } @@ -3980,11 +4013,12 @@ Reporting_activateBufferedReports(MmsMapping* self) static void processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) { - if ((rc->enabled) || (rc->isBuffering)) { - - if (rc->triggerOps & TRG_OPT_GI) { - if (rc->gi) { - + if ((rc->enabled) || (rc->isBuffering)) + { + if (rc->triggerOps & TRG_OPT_GI) + { + if (rc->gi) + { /* send current events in event buffer before GI report */ if (rc->triggered) { rc->triggered = false; @@ -3999,12 +4033,12 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) } } - if (rc->triggerOps & TRG_OPT_INTEGRITY) { - - if (rc->intgPd > 0) { - - if (currentTimeInMs >= rc->nextIntgReportTime) { - + if (rc->triggerOps & TRG_OPT_INTEGRITY) + { + if (rc->intgPd > 0) + { + if (currentTimeInMs >= rc->nextIntgReportTime) + { /* send current events in event buffer before integrity report */ if (rc->triggered) { enqueueReport(rc, false, false, currentTimeInMs); @@ -4019,8 +4053,8 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) } /* check for system time change effects */ - if ((rc->nextIntgReportTime < currentTimeInMs) || (rc->nextIntgReportTime > currentTimeInMs + rc->intgPd)) { - + if ((rc->nextIntgReportTime < currentTimeInMs) || (rc->nextIntgReportTime > currentTimeInMs + rc->intgPd)) + { if (rc->server->syncIntegrityReportTimes) { rc->nextIntgReportTime = getNextRoundedStartTime(currentTimeInMs, rc->intgPd); } @@ -4033,9 +4067,11 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) rc->triggered = false; } - else { + else + { /* check for system time change effects */ - if ((rc->nextIntgReportTime < currentTimeInMs) || (rc->nextIntgReportTime > currentTimeInMs + rc->intgPd)) { + if ((rc->nextIntgReportTime < currentTimeInMs) || (rc->nextIntgReportTime > currentTimeInMs + rc->intgPd)) + { if (rc->server->syncIntegrityReportTimes) { rc->nextIntgReportTime = getNextRoundedStartTime(currentTimeInMs, rc->intgPd); } @@ -4047,9 +4083,10 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) } } - if (rc->triggered) { - if (currentTimeInMs >= rc->reportTime) { - + if (rc->triggered) + { + if (currentTimeInMs >= rc->reportTime) + { enqueueReport(rc, false, false, currentTimeInMs); rc->triggered = false; @@ -4065,11 +4102,12 @@ Reporting_processReportEvents(MmsMapping* self, uint64_t currentTimeInMs) Semaphore_wait(self->isModelLockedMutex); #endif - if (self->isModelLocked == false) { - + if (self->isModelLocked == false) + { LinkedList element = self->reportControls; - while ((element = LinkedList_getNext(element)) != NULL ) { + while ((element = LinkedList_getNext(element)) != NULL ) + { ReportControl* rc = (ReportControl*) element->data; ReportControl_lockNotify(rc); @@ -4093,11 +4131,12 @@ Reporting_sendReports(MmsMapping* self, MmsServerConnection connection) { LinkedList element = LinkedList_getNext(self->reportControls); - while (element) { + while (element) + { ReportControl* rc = (ReportControl*) LinkedList_getData(element); - if (rc->clientConnection == connection) { - + if (rc->clientConnection == connection) + { ReportControl_lockNotify(rc); if (rc->enabled) { @@ -4124,8 +4163,10 @@ static void copyValuesToReportBuffer(ReportControl* self) { int i; - for (i = 0; i < self->dataSet->elementCount; i++) { - if (self->inclusionFlags[i] & REPORT_CONTROL_NOT_UPDATED) { + for (i = 0; i < self->dataSet->elementCount; i++) + { + if (self->inclusionFlags[i] & REPORT_CONTROL_NOT_UPDATED) + { copySingleValueToReportBuffer(self, i); /* clear not-updated flag */ @@ -4142,13 +4183,14 @@ Reporting_processReportEventsAfterUnlock(MmsMapping* self) uint64_t currentTime = Hal_getTimeInMs(); - while ((element = LinkedList_getNext(element)) != NULL ) { + while ((element = LinkedList_getNext(element)) != NULL ) + { ReportControl* rc = (ReportControl*) element->data; ReportControl_lockNotify(rc); - if ((rc->enabled) || (rc->isBuffering)) { - + if ((rc->enabled) || (rc->isBuffering)) + { if (rc->triggered) { copyValuesToReportBuffer(rc); @@ -4166,10 +4208,13 @@ ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, int flag, { ReportControl_lockNotify(self); - if (self->inclusionFlags[dataSetEntryIndex] & flag) { /* report for this data set entry is already pending (bypass BufTm) */ + if (self->inclusionFlags[dataSetEntryIndex] & flag) + { + /* report for this data set entry is already pending (bypass BufTm and send report immediately) */ self->reportTime = Hal_getTimeInMs(); - if (modelLocked) { + if (modelLocked) + { /* buffer all relevant values */ copyValuesToReportBuffer(self); } @@ -4177,19 +4222,21 @@ ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, int flag, processEventsForReport(self, self->reportTime); } - if (modelLocked) { + if (modelLocked) + { /* set flag to update values when report is to be sent or data model unlocked */ self->inclusionFlags[dataSetEntryIndex] = self->inclusionFlags[dataSetEntryIndex] | flag | REPORT_CONTROL_NOT_UPDATED; - } - else { + else + { self->inclusionFlags[dataSetEntryIndex] = flag; /* buffer value for report */ copySingleValueToReportBuffer(self, dataSetEntryIndex); } - if (self->triggered == false) { + if (self->triggered == false) + { uint64_t currentTime = Hal_getTimeInMs(); MmsValue_setBinaryTime(self->timeOfEntry, currentTime); @@ -4218,7 +4265,8 @@ ReportControlBlock_getRptEna(ReportControlBlock* self) char* ReportControlBlock_getRptID(ReportControlBlock* self) { - if (self->trgOps & 64) { + if (self->trgOps & 64) + { ReportControl* rc = (ReportControl*)(self->sibling); #if (CONFIG_MMS_THREADLESS_STACK != 1) diff --git a/src/iec61850/server/model/config_file_parser.c b/src/iec61850/server/model/config_file_parser.c index 8f2abeca..f9489375 100644 --- a/src/iec61850/server/model/config_file_parser.c +++ b/src/iec61850/server/model/config_file_parser.c @@ -1,7 +1,7 @@ /* * config_file_parser.c * - * Copyright 2014-2022 Michael Zillgith + * Copyright 2014-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -28,9 +28,9 @@ #include "libiec61850_platform_includes.h" #include "stack_config.h" -#define READ_BUFFER_MAX_SIZE 1024 +#include -static uint8_t lineBuffer[READ_BUFFER_MAX_SIZE]; +#define READ_BUFFER_MAX_SIZE 1024 static int readLine(FileHandle fileHandle, uint8_t* buffer, int maxSize) @@ -114,18 +114,132 @@ ConfigFileParser_createModelFromConfigFileEx(const char* filename) return model; } +static bool +setValue(char* lineBuffer, DataAttribute* dataAttribute) +{ + char* valueIndicator = strchr((char*) lineBuffer, '='); + + if (valueIndicator != NULL) { + switch (dataAttribute->type) { + case IEC61850_UNICODE_STRING_255: + { + char* stringStart = valueIndicator + 2; + terminateString(stringStart, '"'); + dataAttribute->mmsValue = MmsValue_newMmsString(stringStart); + } + break; + + case IEC61850_VISIBLE_STRING_255: + case IEC61850_VISIBLE_STRING_129: + case IEC61850_VISIBLE_STRING_65: + case IEC61850_VISIBLE_STRING_64: + case IEC61850_VISIBLE_STRING_32: + case IEC61850_CURRENCY: + { + char* stringStart = valueIndicator + 2; + terminateString(stringStart, '"'); + dataAttribute->mmsValue = MmsValue_newVisibleString(stringStart); + } + break; + + case IEC61850_INT8: + case IEC61850_INT16: + case IEC61850_INT32: + case IEC61850_INT64: + case IEC61850_INT128: + case IEC61850_ENUMERATED: + { + int32_t intValue; + if (sscanf(valueIndicator + 1, "%i", &intValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newIntegerFromInt32(intValue); + } + break; + + case IEC61850_INT8U: + case IEC61850_INT16U: + case IEC61850_INT24U: + case IEC61850_INT32U: + { + uint32_t uintValue; + if (sscanf(valueIndicator + 1, "%u", &uintValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newUnsignedFromUint32(uintValue); + } + break; + + case IEC61850_FLOAT32: + { + float floatValue; + if (sscanf(valueIndicator + 1, "%f", &floatValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newFloat(floatValue); + } + break; + + case IEC61850_FLOAT64: + { + double doubleValue; + if (sscanf(valueIndicator + 1, "%lf", &doubleValue) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newDouble(doubleValue); + } + break; + + case IEC61850_BOOLEAN: + { + int boolean; + if (sscanf(valueIndicator + 1, "%i", &boolean) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newBoolean((bool) boolean); + } + break; + + case IEC61850_OPTFLDS: + { + int value; + if (sscanf(valueIndicator + 1, "%i", &value) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newBitString(-10); + MmsValue_setBitStringFromIntegerBigEndian(dataAttribute->mmsValue, value); + } + break; + + case IEC61850_TRGOPS: + { + int value; + if (sscanf(valueIndicator + 1, "%i", &value) != 1) goto exit_error; + dataAttribute->mmsValue = MmsValue_newBitString(-6); + MmsValue_setBitStringFromIntegerBigEndian(dataAttribute->mmsValue, value); + } + break; + + default: + break; + + } + } + + return true; + +exit_error: + return false; +} + IedModel* ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) { + uint8_t* lineBuffer = (uint8_t*)GLOBAL_MALLOC(READ_BUFFER_MAX_SIZE); + + if (lineBuffer == NULL) + goto exit_error; + int bytesRead = 1; bool stateInModel = false; int indendation = 0; + bool inArray = false; + bool inArrayElement = false; IedModel* model = NULL; LogicalDevice* currentLD = NULL; LogicalNode* currentLN = NULL; ModelNode* currentModelNode = NULL; + ModelNode* currentArrayNode = NULL; DataSet* currentDataSet = NULL; GSEControlBlock* currentGoCB = NULL; SVControlBlock* currentSMVCB = NULL; @@ -136,16 +250,30 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) int currentLine = 0; - while (bytesRead > 0) { + while (bytesRead > 0) + { bytesRead = readLine(fileHandle, lineBuffer, READ_BUFFER_MAX_SIZE); currentLine++; - if (bytesRead > 0) { + if (bytesRead > 0) + { lineBuffer[bytesRead] = 0; - if (stateInModel) { + /* trim trailing spaces */ + while (bytesRead > 1) { + bytesRead--; + + if (isspace(lineBuffer[bytesRead])) { + lineBuffer[bytesRead] = 0; + } + else { + break; + } + } + if (stateInModel) + { if (StringUtils_startsWith((char*) lineBuffer, "}")) { if (indendation == 1) { stateInModel = false; @@ -161,13 +289,25 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) indendation = 3; } else if (indendation > 4) { + + if (inArrayElement && currentModelNode->parent == currentArrayNode) { + inArrayElement = false; + } + else { + indendation--; + } + + if (inArray && currentModelNode == currentArrayNode) { + inArray = false; + } + currentModelNode = currentModelNode->parent; - indendation--; } } - - else if (indendation == 1) { - if (StringUtils_startsWith((char*) lineBuffer, "LD")) { + else if (indendation == 1) + { + if (StringUtils_startsWith((char*) lineBuffer, "LD")) + { indendation = 2; char ldName[65]; @@ -178,7 +318,8 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) terminateString(nameString, ')'); - if (ldName[0] != 0) { + if (ldName[0] != 0) + { terminateString(ldName, ')'); currentLD = LogicalDevice_createEx(nameString, model, ldName); @@ -190,8 +331,10 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) else goto exit_error; } - else if (indendation == 2) { - if (StringUtils_startsWith((char*) lineBuffer, "LN")) { + else if (indendation == 2) + { + if (StringUtils_startsWith((char*) lineBuffer, "LN")) + { indendation = 3; if (sscanf((char*) lineBuffer, "LN(%129s)", nameString) < 1) @@ -204,26 +347,35 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) else goto exit_error; } - else if (indendation == 3) { - if (StringUtils_startsWith((char*) lineBuffer, "DO")) { + else if (indendation == 3) + { + if (StringUtils_startsWith((char*) lineBuffer, "DO")) + { indendation = 4; int arrayElements = 0; - sscanf((char*) lineBuffer, "DO(%129s %i)", nameString, &arrayElements); + if (sscanf((char*)lineBuffer, "DO(%129s %i)", nameString, &arrayElements) != 2) { + goto exit_error; + } currentModelNode = (ModelNode*) DataObject_create(nameString, (ModelNode*) currentLN, arrayElements); } - else if (StringUtils_startsWith((char*) lineBuffer, "DS")) { + else if (StringUtils_startsWith((char*) lineBuffer, "DS")) + { indendation = 4; - sscanf((char*) lineBuffer, "DS(%129s)", nameString); + if (sscanf((char*)lineBuffer, "DS(%129s)", nameString) != 1) { + goto exit_error; + } + terminateString(nameString, ')'); currentDataSet = DataSet_create(nameString, currentLN); } - else if (StringUtils_startsWith((char*) lineBuffer, "RC")) { + else if (StringUtils_startsWith((char*) lineBuffer, "RC")) + { int isBuffered; uint32_t confRef; int trgOps; @@ -250,7 +402,8 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) ReportControlBlock_create(nameString, currentLN, rptId, (bool) isBuffered, dataSetName, confRef, trgOps, options, bufTm, intgPd); } - else if (StringUtils_startsWith((char*) lineBuffer, "LC")) { + else if (StringUtils_startsWith((char*) lineBuffer, "LC")) + { uint32_t trgOps; uint32_t intgPd; int logEna; @@ -271,7 +424,8 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) LogControlBlock_create(nameString, currentLN, dataSet, logRef, trgOps, intgPd, logEna, withReasonCode); } - else if (StringUtils_startsWith((char*) lineBuffer, "LOG")) { + else if (StringUtils_startsWith((char*) lineBuffer, "LOG")) + { int matchedItems = sscanf((char*) lineBuffer, "LOG(%129s)", nameString); if (matchedItems < 1) goto exit_error; @@ -281,7 +435,8 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) Log_create(nameString, currentLN); } - else if (StringUtils_startsWith((char*) lineBuffer, "GC")) { + else if (StringUtils_startsWith((char*) lineBuffer, "GC")) + { uint32_t confRef; int fixedOffs; int minTime = -1; @@ -296,9 +451,9 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) nameString3, confRef, fixedOffs, minTime, maxTime); indendation = 4; - } - else if (StringUtils_startsWith((char*) lineBuffer, "SMVC")) { + else if (StringUtils_startsWith((char*) lineBuffer, "SMVC")) + { uint32_t confRev; int smpMod; int smpRate; @@ -313,10 +468,10 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) currentSMVCB = SVControlBlock_create(nameString, currentLN, nameString2, nameString3, confRev, smpMod, smpRate, optFlds, (bool) isUnicast); indendation = 4; - } #if (CONFIG_IEC61850_SETTING_GROUPS == 1) - else if (StringUtils_startsWith((char*) lineBuffer, "SG")) { + else if (StringUtils_startsWith((char*) lineBuffer, "SG")) + { if (strcmp(currentLN->name, "LLN0") != 0) { if (DEBUG_IED_SERVER) @@ -345,8 +500,10 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) } } - else if (indendation > 3) { - if (StringUtils_startsWith((char*) lineBuffer, "DO")) { + else if (indendation > 3) + { + if (StringUtils_startsWith((char*) lineBuffer, "DO")) + { indendation++; int arrayElements = 0; @@ -356,129 +513,116 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) if (matchedItems != 2) goto exit_error; currentModelNode = (ModelNode*) DataObject_create(nameString, currentModelNode, arrayElements); - } - else if (StringUtils_startsWith((char*) lineBuffer, "DA")) { - int arrayElements = 0; + if (arrayElements > 0) + { + inArray = true; + currentArrayNode = currentModelNode; + } + } + else if (StringUtils_startsWith((char*) lineBuffer, "[")) + { + if (inArray == false) { + goto exit_error; + } - int attributeType = 0; - int functionalConstraint = 0; - int triggerOptions = 0; - uint32_t sAddr = 0; + int arrayIndex; - sscanf((char*) lineBuffer, "DA(%129s %i %i %i %i %u)", nameString, &arrayElements, &attributeType, &functionalConstraint, &triggerOptions, &sAddr); + if (sscanf((char*)lineBuffer, "[%i]", &arrayIndex) != 1) { + goto exit_error; + } - DataAttribute* dataAttribute = DataAttribute_create(nameString, currentModelNode, - (DataAttributeType) attributeType, (FunctionalConstraint) functionalConstraint, triggerOptions, arrayElements, sAddr); + if (arrayIndex < 0) { + goto exit_error; + } - char* valueIndicator = strchr((char*) lineBuffer, '='); + if (currentArrayNode->modelType == DataAttributeModelType) + { + if (StringUtils_endsWith((char*)lineBuffer, ";")) + { + /* array of basic data attribute */ + ModelNode* arrayElementNode = ModelNode_getChildWithIdx(currentArrayNode, arrayIndex); - if (valueIndicator != NULL) { - switch (dataAttribute->type) { - case IEC61850_UNICODE_STRING_255: - { - char* stringStart = valueIndicator + 2; - terminateString(stringStart, '"'); - dataAttribute->mmsValue = MmsValue_newMmsString(stringStart); - } - break; - - case IEC61850_VISIBLE_STRING_255: - case IEC61850_VISIBLE_STRING_129: - case IEC61850_VISIBLE_STRING_65: - case IEC61850_VISIBLE_STRING_64: - case IEC61850_VISIBLE_STRING_32: - case IEC61850_CURRENCY: - { - char* stringStart = valueIndicator + 2; - terminateString(stringStart, '"'); - dataAttribute->mmsValue = MmsValue_newVisibleString(stringStart); - } - break; - - case IEC61850_INT8: - case IEC61850_INT16: - case IEC61850_INT32: - case IEC61850_INT64: - case IEC61850_INT128: - case IEC61850_ENUMERATED: - { - int32_t intValue; - if (sscanf(valueIndicator + 1, "%i", &intValue) != 1) goto exit_error; - dataAttribute->mmsValue = MmsValue_newIntegerFromInt32(intValue); + if (arrayElementNode) { + setValue((char*)lineBuffer, (DataAttribute*)arrayElementNode); } - break; - - case IEC61850_INT8U: - case IEC61850_INT16U: - case IEC61850_INT24U: - case IEC61850_INT32U: - { - uint32_t uintValue; - if (sscanf(valueIndicator + 1, "%u", &uintValue) != 1) goto exit_error; - dataAttribute->mmsValue = MmsValue_newUnsignedFromUint32(uintValue); + else { + goto exit_error; } - break; - - case IEC61850_FLOAT32: - { - float floatValue; - if (sscanf(valueIndicator + 1, "%f", &floatValue) != 1) goto exit_error; - dataAttribute->mmsValue = MmsValue_newFloat(floatValue); - } - break; + } + else if (StringUtils_endsWith((char*)lineBuffer, "{")) + { + /* array of constructed data attribtute */ + currentModelNode = ModelNode_getChildWithIdx(currentArrayNode, arrayIndex); - case IEC61850_FLOAT64: - { - double doubleValue; - if (sscanf(valueIndicator + 1, "%lf", &doubleValue) != 1) goto exit_error; - dataAttribute->mmsValue = MmsValue_newDouble(doubleValue); + if (currentModelNode) { + inArrayElement = true; } - break; - - case IEC61850_BOOLEAN: - { - int boolean; - if (sscanf(valueIndicator + 1, "%i", &boolean) != 1) goto exit_error; - dataAttribute->mmsValue = MmsValue_newBoolean((bool) boolean); + else { + goto exit_error; } - break; - - case IEC61850_OPTFLDS: - { - int value; - if (sscanf(valueIndicator + 1, "%i", &value) != 1) goto exit_error; - dataAttribute->mmsValue = MmsValue_newBitString(-10); - MmsValue_setBitStringFromIntegerBigEndian(dataAttribute->mmsValue, value); + } + } + else if (currentArrayNode->modelType == DataObjectModelType) + { + if (StringUtils_endsWith((char*)lineBuffer, "{")) + { + /* array of constructed data attribtute */ + currentModelNode = ModelNode_getChildWithIdx(currentArrayNode, arrayIndex); + + if (currentModelNode) { + inArrayElement = true; } - break; - - case IEC61850_TRGOPS: - { - int value; - if (sscanf(valueIndicator + 1, "%i", &value) != 1) goto exit_error; - dataAttribute->mmsValue = MmsValue_newBitString(-6); - MmsValue_setBitStringFromIntegerBigEndian(dataAttribute->mmsValue, value); + else { + goto exit_error; } - break; + } + else + { + if (DEBUG_IED_SERVER) + printf("Unexpected character at end of line: %s\n", lineBuffer); + goto exit_error; + } + } + } + else if (StringUtils_startsWith((char*) lineBuffer, "DA")) + { + int arrayElements = 0; + + int attributeType = 0; + int functionalConstraint = 0; + int triggerOptions = 0; + uint32_t sAddr = 0; - default: - break; + if (sscanf((char*)lineBuffer, "DA(%129s %i %i %i %i %u)", nameString, &arrayElements, &attributeType, &functionalConstraint, &triggerOptions, &sAddr) != 6) { + goto exit_error; + } - } + DataAttribute* dataAttribute = DataAttribute_create(nameString, currentModelNode, + (DataAttributeType) attributeType, (FunctionalConstraint) functionalConstraint, triggerOptions, arrayElements, sAddr); + + if (arrayElements > 0) + { + inArray = true; + currentArrayNode = (ModelNode*)dataAttribute; } + setValue((char*)lineBuffer, dataAttribute); + int lineLength = (int) strlen((char*) lineBuffer); - if (lineBuffer[lineLength - 1] == '{') { + if (lineBuffer[lineLength - 1] == '{') + { indendation++; currentModelNode = (ModelNode*) dataAttribute; } } - else if (StringUtils_startsWith((char*) lineBuffer, "DE")) { + else if (StringUtils_startsWith((char*) lineBuffer, "DE")) + { char* start = strchr((char*) lineBuffer, '('); - if (start) { + if (start) + { start++; StringUtils_copyStringMax(nameString, 130, start); @@ -491,7 +635,8 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) /* check for index */ char* sep = strchr(nameString, ' '); - if (sep) { + if (sep) + { char* indexStr = sep + 1; *sep = 0; @@ -509,7 +654,8 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) DataSetEntry_create(currentDataSet, nameString, indexVal, componentVal); } } - else if (StringUtils_startsWith((char*) lineBuffer, "PA")) { + else if (StringUtils_startsWith((char*) lineBuffer, "PA")) + { uint32_t vlanPrio; uint32_t vlanId; uint32_t appId; @@ -525,7 +671,6 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) if (StringUtils_createBufferFromHexString(nameString, (uint8_t*) nameString2) != 6) goto exit_error; - PhyComAddress* dstAddress = PhyComAddress_create((uint8_t) vlanPrio, (uint16_t) vlanId, (uint16_t) appId, (uint8_t*) nameString2); @@ -541,18 +686,20 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) else goto exit_error; } - - } - else { - if (StringUtils_startsWith((char*) lineBuffer, "MODEL{")) { - + else + { + if (StringUtils_startsWith((char*) lineBuffer, "MODEL{")) + { model = IedModel_create(""); stateInModel = true; indendation = 1; } - else if (StringUtils_startsWith((char*) lineBuffer, "MODEL(")) { - sscanf((char*) lineBuffer, "MODEL(%129s)", nameString); + else if (StringUtils_startsWith((char*) lineBuffer, "MODEL(")) + { + if (sscanf((char*)lineBuffer, "MODEL(%129s)", nameString) != 1) + goto exit_error; + terminateString(nameString, ')'); model = IedModel_create(nameString); stateInModel = true; @@ -564,14 +711,18 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) } } + GLOBAL_FREEMEM(lineBuffer); + return model; exit_error: + + GLOBAL_FREEMEM(lineBuffer); + if (DEBUG_IED_SERVER) printf("IED_SERVER: error parsing line %i (indentation level = %i)\n", currentLine, indendation); IedModel_destroy(model); + return NULL; } - - diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c index 68710320..bfe266ed 100644 --- a/src/iec61850/server/model/dynamic_model.c +++ b/src/iec61850/server/model/dynamic_model.c @@ -1,7 +1,7 @@ /* * dynamic_model.c * - * Copyright 2014-2022 Michael Zillgith + * Copyright 2014-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -75,10 +75,12 @@ IedModel_addDataSet(IedModel* self, DataSet* dataSet) { if (self->dataSets == NULL) self->dataSets = dataSet; - else { + else + { DataSet* lastDataSet = self->dataSets; - while (lastDataSet != NULL) { + while (lastDataSet != NULL) + { if (lastDataSet->sibling == NULL) { lastDataSet->sibling = dataSet; break; @@ -94,7 +96,8 @@ IedModel_addLogicalDevice(IedModel* self, LogicalDevice* lDevice) { if (self->firstChild == NULL) self->firstChild = lDevice; - else { + else + { LogicalDevice* sibling = self->firstChild; while (sibling->sibling != NULL) @@ -109,7 +112,8 @@ IedModel_addLog(IedModel* self, Log* log) { if (self->logs == NULL) self->logs = log; - else { + else + { Log* lastLog = self->logs; while (lastLog->sibling != NULL) @@ -124,7 +128,8 @@ IedModel_addLogControlBlock(IedModel* self, LogControlBlock* lcb) { if (self->lcbs == NULL) self->lcbs = lcb; - else { + else + { LogControlBlock* lastLcb = self->lcbs; while (lastLcb->sibling != NULL) @@ -139,7 +144,8 @@ IedModel_addReportControlBlock(IedModel* self, ReportControlBlock* rcb) { if (self->rcbs == NULL) self->rcbs = rcb; - else { + else + { ReportControlBlock* lastRcb = self->rcbs; while (lastRcb->sibling != NULL) @@ -155,7 +161,8 @@ IedModel_addSettingGroupControlBlock(IedModel* self, SettingGroupControlBlock* s { if (self->sgcbs == NULL) self->sgcbs = sgcb; - else { + else + { SettingGroupControlBlock* lastSgcb = self->sgcbs; while (lastSgcb->sibling != NULL) @@ -171,7 +178,8 @@ IedModel_addGSEControlBlock(IedModel* self, GSEControlBlock* gcb) { if (self->gseCBs == NULL) self->gseCBs = gcb; - else { + else + { GSEControlBlock* lastGcb = self->gseCBs; while (lastGcb->sibling) @@ -187,7 +195,8 @@ IedModel_addSMVControlBlock(IedModel* self, SVControlBlock* smvcb) if (self->svCBs == NULL) { self->svCBs = smvcb; } - else { + else + { SVControlBlock* lastSvCB = self->svCBs; while (lastSvCB->sibling) @@ -202,7 +211,8 @@ LogicalDevice_createEx(const char* inst, IedModel* parent, const char* ldName) { LogicalDevice* self = (LogicalDevice*) GLOBAL_CALLOC(1, sizeof(LogicalDevice)); - if (self) { + if (self) + { self->name = StringUtils_copyString(inst); self->modelType = LogicalDeviceModelType; self->parent = (ModelNode*) parent; @@ -257,7 +267,8 @@ LogicalNode_create(const char* name, LogicalDevice* parent) { LogicalNode* self = (LogicalNode*) GLOBAL_MALLOC(sizeof(LogicalNode)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->parent = (ModelNode*) parent; self->modelType = LogicalNodeModelType; @@ -311,7 +322,8 @@ Log_create(const char* name, LogicalNode* parent) { Log* self = (Log*) GLOBAL_MALLOC(sizeof(Log)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->parent = parent; self->sibling = NULL; @@ -336,7 +348,8 @@ LogControlBlock_create(const char* name, LogicalNode* parent, const char* dataSe { LogControlBlock* self = (LogControlBlock*) GLOBAL_MALLOC(sizeof(LogControlBlock)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->parent = parent; self->sibling = NULL; @@ -388,7 +401,8 @@ ReportControlBlock_create(const char* name, LogicalNode* parent, const char* rpt { ReportControlBlock* self = (ReportControlBlock*) GLOBAL_MALLOC(sizeof(ReportControlBlock)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->parent = parent; @@ -469,7 +483,8 @@ SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numO SettingGroupControlBlock* self = (SettingGroupControlBlock*) GLOBAL_MALLOC(sizeof(SettingGroupControlBlock)); - if (self) { + if (self) + { self->parent = parent; self->actSG = actSG; self->numOfSGs = numOfSGs; @@ -497,7 +512,8 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, const char* appId, { GSEControlBlock* self = (GSEControlBlock*) GLOBAL_MALLOC(sizeof(GSEControlBlock)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->parent = parent; @@ -541,7 +557,8 @@ SVControlBlock_create(const char* name, LogicalNode* parent, const char* svID, c { SVControlBlock* self = (SVControlBlock*) GLOBAL_MALLOC(sizeof(SVControlBlock)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->parent = parent; @@ -587,7 +604,8 @@ PhyComAddress_create(uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint { PhyComAddress* self = (PhyComAddress*) GLOBAL_MALLOC(sizeof(PhyComAddress)); - if (self) { + if (self) + { self->vlanPriority = vlanPriority; self->vlanId = vlanId; self->appId = appId; @@ -630,7 +648,8 @@ DataObject_create(const char* name, ModelNode* parent, int arrayElements) { DataObject* self = (DataObject*) GLOBAL_MALLOC(sizeof(DataObject)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->modelType = DataObjectModelType; self->firstChild = NULL; @@ -640,21 +659,23 @@ DataObject_create(const char* name, ModelNode* parent, int arrayElements) self->elementCount = arrayElements; self->arrayIndex = -1; - if (arrayElements > 0) { + if (arrayElements > 0) + { int i; - for (i = 0; i < arrayElements; i++) { + for (i = 0; i < arrayElements; i++) + { DataObject* arrayElement = (DataObject*) GLOBAL_MALLOC(sizeof(DataObject)); - if (self) { - self->name = NULL; - self->modelType = DataObjectModelType; - self->firstChild = NULL; - self->parent = parent; - self->sibling = NULL; + if (arrayElement) { + arrayElement->name = NULL; + arrayElement->modelType = DataObjectModelType; + arrayElement->firstChild = NULL; + arrayElement->parent = (ModelNode*) self; + arrayElement->sibling = NULL; - self->elementCount = 0; - self->arrayIndex = i; + arrayElement->elementCount = 0; + arrayElement->arrayIndex = i; DataObject_addChild(self, (ModelNode*) arrayElement); } @@ -703,7 +724,8 @@ DataAttribute_create(const char* name, ModelNode* parent, DataAttributeType type { DataAttribute* self = (DataAttribute*) GLOBAL_MALLOC(sizeof(DataAttribute)); - if (self) { + if (self) + { self->name = StringUtils_copyString(name); self->elementCount = arrayElements; self->arrayIndex = -1; @@ -717,13 +739,16 @@ DataAttribute_create(const char* name, ModelNode* parent, DataAttributeType type self->triggerOptions = triggerOptions; self->sAddr = sAddr; - if (arrayElements > 0) { + if (arrayElements > 0) + { int i; - for (i = 0; i < arrayElements; i++) { + for (i = 0; i < arrayElements; i++) + { DataAttribute* arrayElement = (DataAttribute*) GLOBAL_MALLOC(sizeof(DataAttribute)); - if (arrayElement) { + if (arrayElement) + { arrayElement->name = NULL; arrayElement->elementCount = 0; arrayElement->arrayIndex = i; @@ -785,7 +810,8 @@ DataSet_create(const char* name, LogicalNode* parent) { DataSet* self = (DataSet*) GLOBAL_MALLOC(sizeof(DataSet)); - if (self) { + if (self) + { LogicalDevice* ld = (LogicalDevice*) parent->parent; self->name = StringUtils_createString(3, parent->name, "$", name); @@ -831,11 +857,12 @@ DataSet_addEntry(DataSet* self, DataSetEntry* newEntry) if (self->fcdas == NULL) self->fcdas = newEntry; - else { + else + { DataSetEntry* lastEntry = self->fcdas; - while (lastEntry != NULL) { - + while (lastEntry != NULL) + { if (lastEntry->sibling == NULL) { lastEntry->sibling = newEntry; break; @@ -851,21 +878,24 @@ DataSetEntry_create(DataSet* dataSet, const char* variable, int index, const cha { DataSetEntry* self = (DataSetEntry*) GLOBAL_MALLOC(sizeof(DataSetEntry)); - if (self) { + if (self) + { char variableName[130]; StringUtils_copyStringMax(variableName, 130, variable); char* separator = strchr(variableName, '/'); - if (separator != NULL) { + if (separator != NULL) + { *separator = 0; self->variableName = StringUtils_copyString(separator + 1); self->logicalDeviceName = StringUtils_copyString(variableName); self->isLDNameDynamicallyAllocated = true; } - else { + else + { self->variableName = StringUtils_copyString(variable); self->logicalDeviceName = dataSet->logicalDeviceName; self->isLDNameDynamicallyAllocated = false; @@ -891,14 +921,15 @@ DataSetEntry_create(DataSet* dataSet, const char* variable, int index, const cha static void ModelNode_destroy(ModelNode* modelNode) { - if (modelNode) { - + if (modelNode) + { if (modelNode->name) GLOBAL_FREEMEM(modelNode->name); ModelNode* currentChild = modelNode->firstChild; - while (currentChild != NULL) { + while (currentChild != NULL) + { ModelNode* nextChild = currentChild->sibling; ModelNode_destroy(currentChild); @@ -906,7 +937,8 @@ ModelNode_destroy(ModelNode* modelNode) currentChild = nextChild; } - if (modelNode->modelType == DataAttributeModelType) { + if (modelNode->modelType == DataAttributeModelType) + { DataAttribute* dataAttribute = (DataAttribute*) modelNode; if (dataAttribute->mmsValue != NULL) { @@ -929,8 +961,8 @@ IedModel_destroy(IedModel* model) LogicalDevice* ld = model->firstChild; - while (ld != NULL) { - + while (ld != NULL) + { if (ld->name) GLOBAL_FREEMEM(ld->name); @@ -939,7 +971,8 @@ IedModel_destroy(IedModel* model) LogicalNode* ln = (LogicalNode*) ld->firstChild; - while (ln != NULL) { + while (ln != NULL) + { GLOBAL_FREEMEM(ln->name); /* delete all data objects */ @@ -960,7 +993,6 @@ IedModel_destroy(IedModel* model) GLOBAL_FREEMEM(currentLn); } - LogicalDevice* currentLd = ld; ld = (LogicalDevice*) ld->sibling; @@ -1092,4 +1124,3 @@ IedModel_destroy(IedModel* model) GLOBAL_FREEMEM(model); } } - diff --git a/src/iec61850/server/model/model.c b/src/iec61850/server/model/model.c index 375d62f9..55b6409e 100644 --- a/src/iec61850/server/model/model.c +++ b/src/iec61850/server/model/model.c @@ -538,19 +538,34 @@ static int createObjectReference(ModelNode* node, char* objectReference, int bufSize, bool withoutIedName) { int bufPos; + int arrayIndex = -1; - if (node->modelType != LogicalNodeModelType) { + if (node->modelType != LogicalNodeModelType) + { bufPos = createObjectReference(node->parent, objectReference, bufSize, withoutIedName); + if (node->modelType == DataAttributeModelType) + { + arrayIndex = ((DataAttribute*)(node))->arrayIndex; + } + else if (node->modelType == DataObjectModelType) + { + arrayIndex = ((DataObject*)(node))->arrayIndex; + } + if (bufPos == -1) return -1; - if (bufPos < bufSize) - objectReference[bufPos++] = '.'; - else - return -1; + if (arrayIndex < 0) + { + if (bufPos < bufSize) + objectReference[bufPos++] = '.'; + else + return -1; + } } - else { + else + { LogicalNode* lNode = (LogicalNode*) node; LogicalDevice* lDevice = (LogicalDevice*) lNode->parent; @@ -559,12 +574,13 @@ createObjectReference(ModelNode* node, char* objectReference, int bufSize, bool bufPos = 0; - if (withoutIedName) { + if (withoutIedName) + { objectReference[0] = 0; StringUtils_appendString(objectReference, bufSize, lDevice->name); } - else { - + else + { if (lDevice->ldName) { StringUtils_copyStringMax(objectReference, bufSize, lDevice->ldName); } @@ -581,20 +597,49 @@ createObjectReference(ModelNode* node, char* objectReference, int bufSize, bool return -1; } - /* append own name */ - int nameLength = strlen(node->name); + if (node->name) + { + /* append own name */ + int nameLength = strlen(node->name); + + if (bufPos + nameLength < bufSize) + { + int i; + for (i = 0; i < nameLength; i++) { + objectReference[bufPos++] = node->name[i]; + } - if (bufPos + nameLength < bufSize) { - int i; - for (i = 0; i < nameLength; i++) { - objectReference[bufPos++] = node->name[i]; + return bufPos; + } + else { + return -1; } - - return bufPos; } - else { - return -1; + + if (arrayIndex > -1) + { + char arrayIndexStr[11]; + + snprintf(arrayIndexStr, 11, "%d", arrayIndex); + + int arrayIndexStrLength = strlen(arrayIndexStr); + + if (bufPos + arrayIndexStrLength + 2 < bufSize) + { + int i; + + objectReference[bufPos++] = '('; + + for (i = 0; i < arrayIndexStrLength; i++) { + objectReference[bufPos++] = arrayIndexStr[i]; + } + objectReference[bufPos++] = ')'; + } + else + return -1; } + + return bufPos; } char* @@ -608,15 +653,18 @@ ModelNode_getObjectReferenceEx(ModelNode* node, char* objectReference, bool with { bool allocated = false; - if (objectReference == NULL) { + if (objectReference == NULL) + { objectReference = (char*) GLOBAL_MALLOC(130); allocated = true; } - if (objectReference) { + if (objectReference) + { int bufPos = createObjectReference(node, objectReference, 130, withoutIedName); - if (bufPos == -1) { + if (bufPos == -1) + { if (allocated) GLOBAL_FREEMEM(objectReference); @@ -729,16 +777,16 @@ ModelNode_getChild(ModelNode* self, const char* name) ModelNode* matchingNode = NULL; - while (nextNode) { - + while (nextNode) + { if (nextNode->name == NULL) { break; /* is an array element */ } int nodeNameLen = strlen(nextNode->name); - if (nodeNameLen == nameElementLength) { - + if (nodeNameLen == nameElementLength) + { if (memcmp(nextNode->name, name, nodeNameLen) == 0) { matchingNode = nextNode; break; @@ -760,12 +808,14 @@ ModelNode_getChildWithIdx(ModelNode* self, int idx) { ModelNode* foundElement = NULL; - if (self->modelType == DataObjectModelType || self->modelType == DataAttributeModelType) { + if (self->modelType == DataObjectModelType || self->modelType == DataAttributeModelType) + { ModelNode* nextNode = self->firstChild; int currentIdx = 0; - while (nextNode) { + while (nextNode) + { if (currentIdx == idx) { foundElement = nextNode; break; @@ -797,14 +847,17 @@ ModelNode_getChildWithFc(ModelNode* self, const char* name, FunctionalConstraint ModelNode* matchingNode = NULL; - while (nextNode != NULL) { + while (nextNode != NULL) + { int nodeNameLen = strlen(nextNode->name); - if (nodeNameLen == nameElementLength) { - if (memcmp(nextNode->name, name, nodeNameLen) == 0) { - + if (nodeNameLen == nameElementLength) + { + if (memcmp(nextNode->name, name, nodeNameLen) == 0) + { if (separator == NULL) { - if (nextNode->modelType == DataAttributeModelType) { + if (nextNode->modelType == DataAttributeModelType) + { DataAttribute* da = (DataAttribute*) nextNode; if (da->fc == fc) { @@ -813,9 +866,10 @@ ModelNode_getChildWithFc(ModelNode* self, const char* name, FunctionalConstraint } } } - else { - - if (nextNode->modelType == DataAttributeModelType) { + else + { + if (nextNode->modelType == DataAttributeModelType) + { DataAttribute* da = (DataAttribute*) nextNode; if (da->fc == fc) { diff --git a/src/mms/inc/mms_client_connection.h b/src/mms/inc/mms_client_connection.h index 86f12c9b..7447b33b 100644 --- a/src/mms/inc/mms_client_connection.h +++ b/src/mms/inc/mms_client_connection.h @@ -160,6 +160,16 @@ MmsConnection_setFilestoreBasepath(MmsConnection self, const char* basepath); LIB61850_API void MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs); +/** + * \brief Set the maximum number outstanding calls allowed for this connection + * + * \param self MmsConnection instance to operate on + * \param calling the maximum outstanding calls allowed by the caller (client) + * \param called the maximum outstanding calls allowed by the called endpoint (server) + */ +LIB61850_API void +MmsConnnection_setMaxOutstandingCalls(MmsConnection self, int calling, int called); + /** * \brief Get the request timeout in ms for this connection * diff --git a/src/mms/inc_private/mms_client_internal.h b/src/mms/inc_private/mms_client_internal.h index aa0e60f3..5a7b2242 100644 --- a/src/mms/inc_private/mms_client_internal.h +++ b/src/mms/inc_private/mms_client_internal.h @@ -95,6 +95,8 @@ struct sMmsConnection { Semaphore outstandingCallsLock; MmsOutstandingCall outstandingCalls; + int maxOutstandingCalled; + int maxOutstandingCalling; uint32_t requestTimeout; uint32_t connectTimeout; diff --git a/src/mms/inc_private/mms_common_internal.h b/src/mms/inc_private/mms_common_internal.h index f096e7bc..61faea58 100644 --- a/src/mms/inc_private/mms_common_internal.h +++ b/src/mms/inc_private/mms_common_internal.h @@ -1,7 +1,7 @@ /* * mms_common_internal.h * - * Copyright 2013-2019 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -30,10 +30,10 @@ #include "byte_buffer.h" #include "mms_server.h" -#define DEFAULT_MAX_SERV_OUTSTANDING_CALLING 5 -#define DEFAULT_MAX_SERV_OUTSTANDING_CALLED 5 #define DEFAULT_DATA_STRUCTURE_NESTING_LEVEL 10 +typedef struct sMmsOutstandingCall* MmsOutstandingCall; + #if (MMS_FILE_SERVICE == 1) #ifndef CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION @@ -42,8 +42,6 @@ #include "hal_filesystem.h" -typedef struct sMmsOutstandingCall* MmsOutstandingCall; - typedef struct { int32_t frsmId; uint32_t readPosition; diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 08d0988a..3fae4f26 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -399,7 +399,7 @@ mmsServer_isAccessToArrayComponent(AlternateAccess_t* alternateAccess); LIB61850_INTERNAL MmsValue* mmsServer_getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable, - MmsValue* structuredValue); + MmsValue* structuredValue, char* componentId); LIB61850_INTERNAL int mmsServer_getLowIndex(AlternateAccess_t* alternateAccess); @@ -417,6 +417,10 @@ LIB61850_INTERNAL MmsDataAccessError mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, MmsServerConnection connection); +LIB61850_INTERNAL MmsDataAccessError +mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, + MmsServerConnection connection, int arrayIdx, const char* componentId); + /** * \brief Get the current value of a variable in the server data model * diff --git a/src/mms/inc_private/mms_server_libinternal.h b/src/mms/inc_private/mms_server_libinternal.h index bdaf4b68..f7daa70c 100644 --- a/src/mms/inc_private/mms_server_libinternal.h +++ b/src/mms/inc_private/mms_server_libinternal.h @@ -34,7 +34,7 @@ typedef MmsDataAccessError (*MmsReadAccessHandler) (void* parameter, MmsDomain* char* variableId, MmsServerConnection connection, bool isDirectAccess); typedef MmsDataAccessError (*MmsWriteVariableHandler)(void* parameter, - MmsDomain* domain, char* variableId, MmsValue* value, + MmsDomain* domain, const char* variableId, int arrayIdx, const char* componentId, MmsValue* value, MmsServerConnection connection); typedef bool (*MmsListAccessHandler) (void* parameter, MmsGetNameListType listType, MmsDomain* domain, diff --git a/src/mms/iso_acse/acse.c b/src/mms/iso_acse/acse.c index f46b024d..9f5b4186 100644 --- a/src/mms/iso_acse/acse.c +++ b/src/mms/iso_acse/acse.c @@ -1,7 +1,7 @@ /* * acse.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -43,9 +43,10 @@ checkAuthMechanismName(uint8_t* authMechanism, int authMechLen) { AcseAuthenticationMechanism authenticationMechanism = ACSE_AUTH_NONE; - if (authMechanism != NULL) { - - if (authMechLen == 3) { + if (authMechanism != NULL) + { + if (authMechLen == 3) + { if (memcmp(auth_mech_password_oid, authMechanism, 3) == 0) { authenticationMechanism = ACSE_AUTH_PASSWORD; } @@ -64,11 +65,13 @@ authenticateClient(AcseConnection* self, AcseAuthenticationMechanism mechanism, authParameter->mechanism = mechanism; - if (mechanism == ACSE_AUTH_PASSWORD) { + if (mechanism == ACSE_AUTH_PASSWORD) + { authParameter->value.password.octetString = authValue; authParameter->value.password.passwordLength = authValueLen; } - else if (mechanism == ACSE_AUTH_TLS) { + else if (mechanism == ACSE_AUTH_TLS) + { authParameter->value.certificate.buf = authValue; authParameter->value.certificate.length = authValueLen; } @@ -81,15 +84,15 @@ checkAuthentication(AcseConnection* self, uint8_t* authMechanism, int authMechLe { self->securityToken = NULL; - if (self->authenticator != NULL) { - + if (self->authenticator != NULL) + { AcseAuthenticationMechanism mechanism = checkAuthMechanismName(authMechanism, authMechLen); - if (mechanism == ACSE_AUTH_NONE) { - + if (mechanism == ACSE_AUTH_NONE) + { #if (CONFIG_MMS_SUPPORT_TLS == 1) - if (self->tlsSocket) { - + if (self->tlsSocket) + { int certLen; uint8_t* certBuf = TLSSocket_getPeerCertificate(self->tlsSocket, &certLen); @@ -120,13 +123,18 @@ parseUserInformation(AcseConnection* self, uint8_t* buffer, int bufPos, int maxB bool hasindirectReference = false; bool isDataValid = false; - while (bufPos < maxBufPos) { + while (bufPos < maxBufPos) + { uint8_t tag = buffer[bufPos++]; int len; bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); - if (bufPos < 0) { + if (len == 0) + continue; + + if ((bufPos < 0) || (bufPos + len > maxBufPos)) + { *userInfoValid = false; return -1; } @@ -155,7 +163,8 @@ parseUserInformation(AcseConnection* self, uint8_t* buffer, int bufPos, int maxB } } - if (DEBUG_ACSE) { + if (DEBUG_ACSE) + { if (!hasindirectReference) printf("ACSE: User data has no indirect reference!\n"); @@ -181,13 +190,22 @@ parseAarePdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) uint32_t result = 99; - while (bufPos < maxBufPos) { + while (bufPos < maxBufPos) + { uint8_t tag = buffer[bufPos++]; int len; bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); - if (bufPos < 0) + + if (len == 0) + continue; + + if ((bufPos < 0) || (bufPos + len > maxBufPos)) + { + if (DEBUG_ACSE) + printf("ACSE: Invalid PDU!\n"); return ACSE_ERROR; + } switch (tag) { @@ -212,12 +230,14 @@ parseAarePdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) break; case 0xbe: /* user information */ - if (buffer[bufPos] != 0x28) { + if (buffer[bufPos] != 0x28) + { if (DEBUG_ACSE) printf("ACSE: invalid user info\n"); bufPos += len; } - else { + else + { bufPos++; bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); @@ -263,13 +283,18 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) int authMechLen = 0; bool userInfoValid = false; - while (bufPos < maxBufPos) { + while (bufPos < maxBufPos) + { uint8_t tag = buffer[bufPos++]; int len; bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); - if (bufPos < 0) { + if (len == 0) + continue; + + if ((bufPos < 0) || (bufPos + len > maxBufPos)) + { if (DEBUG_ACSE) printf("ACSE: Invalid PDU!\n"); return ACSE_ASSOCIATE_FAILED; @@ -290,7 +315,9 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) case 0xa6: /* calling AP title */ { - if (buffer[bufPos] == 0x06) { /* ap-title-form2 */ + if (buffer[bufPos] == 0x06) + { + /* ap-title-form2 */ int innerLength = buffer[bufPos + 1]; @@ -303,7 +330,9 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) case 0xa7: /* calling AE qualifier */ { - if (buffer[bufPos] == 0x02) { /* ae-qualifier-form2 */ + if (buffer[bufPos] == 0x02) + { + /* ae-qualifier-form2 */ int innerLength = buffer[bufPos + 1]; @@ -328,7 +357,8 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) bufPos++; bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_ACSE) printf("ACSE: Invalid PDU!\n"); return ACSE_ASSOCIATE_FAILED; @@ -340,17 +370,20 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) break; case 0xbe: /* user information */ - if (buffer[bufPos] != 0x28) { + if (buffer[bufPos] != 0x28) + { if (DEBUG_ACSE) printf("ACSE: invalid user info\n"); bufPos += len; } - else { + else + { bufPos++; bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, maxBufPos); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_ACSE) printf("ACSE: Invalid PDU!\n"); return ACSE_ASSOCIATE_FAILED; @@ -358,7 +391,8 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) bufPos = parseUserInformation(self, buffer, bufPos, bufPos + len, &userInfoValid); - if (bufPos < 0) { + if (bufPos < 0) + { if (DEBUG_ACSE) printf("ACSE: Invalid PDU!\n"); return ACSE_ASSOCIATE_FAILED; @@ -378,14 +412,16 @@ parseAarqPdu(AcseConnection* self, uint8_t* buffer, int bufPos, int maxBufPos) } } - if (checkAuthentication(self, authMechanism, authMechLen, authValue, authValueLen) == false) { + if (checkAuthentication(self, authMechanism, authMechLen, authValue, authValueLen) == false) + { if (DEBUG_ACSE) printf("ACSE: parseAarqPdu: check authentication failed!\n"); return ACSE_ASSOCIATE_FAILED; } - if (userInfoValid == false) { + if (userInfoValid == false) + { if (DEBUG_ACSE) printf("ACSE: parseAarqPdu: user info invalid!\n"); @@ -420,6 +456,14 @@ AcseConnection_parseMessage(AcseConnection* self, ByteBuffer* message) { AcseIndication indication = ACSE_ERROR; + if (message == NULL || message->size < 1) + { + if (DEBUG_ACSE) + printf("ACSE: invalid message - no payload\n"); + + return ACSE_ERROR; + } + uint8_t* buffer = message->buffer; int messageSize = message->size; @@ -826,4 +870,3 @@ AcseConnection_createReleaseResponseMessage(AcseConnection* self, BufferChain wr writeBuffer->length = 2; writeBuffer->nextPart = NULL; } - diff --git a/src/mms/iso_client/iso_client_connection.c b/src/mms/iso_client/iso_client_connection.c index 4f37176b..ee2202a3 100644 --- a/src/mms/iso_client/iso_client_connection.c +++ b/src/mms/iso_client/iso_client_connection.c @@ -3,7 +3,7 @@ * * Client side representation of the ISO stack (COTP, session, presentation, ACSE) * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -146,7 +146,8 @@ IsoClientConnection_create(IsoConnectionParameters parameters, IsoIndicationCall { IsoClientConnection self = (IsoClientConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoClientConnection)); - if (self) { + if (self) + { self->parameters = parameters; self->callback = callback; self->callbackParameter = callbackParameter; @@ -196,7 +197,8 @@ sendConnectionRequestMessage(IsoClientConnection self) int socketExtensionBufferSize = CONFIG_MMS_MAXIMUM_PDU_SIZE + 1000; uint8_t* socketExtensionBuffer = NULL; - if (self->cotpConnection) { + if (self->cotpConnection) + { /* Destroy existing handle set when connection is reused */ if (self->cotpConnection->handleSet) Handleset_destroy(self->cotpConnection->handleSet); @@ -205,19 +207,20 @@ sendConnectionRequestMessage(IsoClientConnection self) socketExtensionBuffer = self->cotpConnection->socketExtensionBuffer; } - if (socketExtensionBuffer == NULL) { + if (socketExtensionBuffer == NULL) + { socketExtensionBuffer = (uint8_t*)GLOBAL_MALLOC(socketExtensionBufferSize); } - if (socketExtensionBuffer) { - + if (socketExtensionBuffer) + { /* COTP (ISO transport) handshake */ CotpConnection_init(self->cotpConnection, self->socket, self->receiveBuffer, self->cotpReadBuffer, self->cotpWriteBuffer, socketExtensionBuffer, socketExtensionBufferSize); #if (CONFIG_MMS_SUPPORT_TLS == 1) - if (self->parameters->tlsConfiguration) { - + if (self->parameters->tlsConfiguration) + { TLSConfiguration_setClientMode(self->parameters->tlsConfiguration); /* create TLSSocket and start TLS authentication */ @@ -225,8 +228,8 @@ sendConnectionRequestMessage(IsoClientConnection self) if (tlsSocket) self->cotpConnection->tlsSocket = tlsSocket; - else { - + else + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: TLS handshake failed!\n"); @@ -244,7 +247,8 @@ sendConnectionRequestMessage(IsoClientConnection self) else return true; } - else { + else + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Failed to allocate socket extension buffer\n"); @@ -298,14 +302,14 @@ sendAcseInitiateRequest(IsoClientConnection self) Semaphore_post(self->transmitBufferMutex); } - static void releaseSocket(IsoClientConnection self) { - if (self->socket) { - + if (self->socket) + { #if (CONFIG_MMS_SUPPORT_TLS == 1) - if (self->cotpConnection->tlsSocket) { + if (self->cotpConnection->tlsSocket) + { TLSSocket_close(self->cotpConnection->tlsSocket); self->cotpConnection->tlsSocket = NULL; } @@ -345,29 +349,34 @@ IsoClientConnection_handleConnection(IsoClientConnection self) { SocketState socketState = Socket_checkAsyncConnectState(self->socket); - if (socketState == SOCKET_STATE_CONNECTED) { - if (sendConnectionRequestMessage(self)) { + if (socketState == SOCKET_STATE_CONNECTED) + { + if (sendConnectionRequestMessage(self)) + { self->nextReadTimeout = Hal_getTimeInMs() + self->readTimeoutInMs; nextState = INT_STATE_WAIT_FOR_COTP_CONNECT_RESP; } - else { + else + { IsoClientConnection_releaseTransmitBuffer(self); self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); nextState = INT_STATE_CLOSE_ON_ERROR; } } - else if (socketState == SOCKET_STATE_FAILED) { + else if (socketState == SOCKET_STATE_FAILED) + { IsoClientConnection_releaseTransmitBuffer(self); self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); nextState = INT_STATE_CLOSE_ON_ERROR; } - else { - + else + { /* check connect timeout */ uint64_t currentTime = Hal_getTimeInMs(); - if (currentTime > self->nextReadTimeout) { + if (currentTime > self->nextReadTimeout) + { IsoClientConnection_releaseTransmitBuffer(self); self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); nextState = INT_STATE_CLOSE_ON_ERROR; @@ -385,8 +394,8 @@ IsoClientConnection_handleConnection(IsoClientConnection self) { uint64_t currentTime = Hal_getTimeInMs(); - if (currentTime > self->nextReadTimeout) { - + if (currentTime > self->nextReadTimeout) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Timeout waiting for COTP CR\n"); @@ -396,15 +405,16 @@ IsoClientConnection_handleConnection(IsoClientConnection self) nextState = INT_STATE_CLOSE_ON_ERROR; } - else { - + else + { TpktState packetState = CotpConnection_readToTpktBuffer(self->cotpConnection); - if (packetState == TPKT_PACKET_COMPLETE) { - + if (packetState == TPKT_PACKET_COMPLETE) + { CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); - if (cotpIndication != COTP_CONNECT_INDICATION) { + if (cotpIndication != COTP_CONNECT_INDICATION) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Unexpected COTP state (%i)\n", cotpIndication); @@ -414,7 +424,8 @@ IsoClientConnection_handleConnection(IsoClientConnection self) nextState = INT_STATE_CLOSE_ON_ERROR; } - else { + else + { sendAcseInitiateRequest(self); self->nextReadTimeout = Hal_getTimeInMs() + self->readTimeoutInMs; @@ -422,7 +433,8 @@ IsoClientConnection_handleConnection(IsoClientConnection self) nextState = INT_STATE_WAIT_FOR_ACSE_RESP; } } - else if (packetState == TPKT_ERROR) { + else if (packetState == TPKT_ERROR) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Error receiving COTP message\n"); @@ -435,7 +447,6 @@ IsoClientConnection_handleConnection(IsoClientConnection self) else { waits = true; } - } } break; @@ -444,8 +455,8 @@ IsoClientConnection_handleConnection(IsoClientConnection self) { uint64_t currentTime = Hal_getTimeInMs(); - if (currentTime > self->nextReadTimeout) { - + if (currentTime > self->nextReadTimeout) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Timeout waiting for ACSE initiate response\n"); @@ -453,15 +464,16 @@ IsoClientConnection_handleConnection(IsoClientConnection self) nextState = INT_STATE_CLOSE_ON_ERROR; } - else { - + else + { TpktState packetState = CotpConnection_readToTpktBuffer(self->cotpConnection); - if (packetState == TPKT_PACKET_COMPLETE) { - + if (packetState == TPKT_PACKET_COMPLETE) + { CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); - if (cotpIndication != COTP_DATA_INDICATION) { + if (cotpIndication != COTP_DATA_INDICATION) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Unexpected COTP state (%i)\n", cotpIndication); @@ -469,67 +481,71 @@ IsoClientConnection_handleConnection(IsoClientConnection self) nextState = INT_STATE_CLOSE_ON_ERROR; } - else { - + else + { /* parse ACSE response */ - IsoSessionIndication sessionIndication; - - sessionIndication = - IsoSession_parseMessage(self->session, CotpConnection_getPayload(self->cotpConnection)); + IsoSessionIndication sessionIndication; - if (sessionIndication != SESSION_CONNECT) { - if (DEBUG_ISO_CLIENT) - printf("ISO_CLIENT: IsoClientConnection_associate: no session connect indication\n"); + sessionIndication = + IsoSession_parseMessage(self->session, CotpConnection_getPayload(self->cotpConnection)); - self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); - - nextState = INT_STATE_CLOSE_ON_ERROR; - } - else { - - if (IsoPresentation_parseAcceptMessage(self->presentation, IsoSession_getUserData(self->session)) == false) { - - if (DEBUG_ISO_CLIENT) - printf("ISO_CLIENT: IsoClientConnection_associate: no presentation ok indication\n"); - - self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); - - nextState = INT_STATE_CLOSE_ON_ERROR; - } - else { - - AcseIndication acseIndication = AcseConnection_parseMessage(&(self->acseConnection), &self->presentation->nextPayload); - - if (acseIndication != ACSE_ASSOCIATE) { - if (DEBUG_ISO_CLIENT) - printf("ISO_CLIENT: IsoClientConnection_associate: no ACSE_ASSOCIATE indication\n"); - - self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); - - nextState = INT_STATE_CLOSE_ON_ERROR; - } - else { - - ByteBuffer_wrap(self->receivePayloadBuffer, self->acseConnection.userDataBuffer, - self->acseConnection.userDataBufferSize, self->acseConnection.userDataBufferSize); + if (sessionIndication != SESSION_CONNECT) + { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: IsoClientConnection_associate: no session connect indication\n"); - setState(self, STATE_CONNECTED); - nextState = INT_STATE_WAIT_FOR_DATA_MSG; + self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); - if (self->callback(ISO_IND_ASSOCIATION_SUCCESS, self->callbackParameter, self->receivePayloadBuffer) == false) { - nextState = INT_STATE_CLOSE_ON_ERROR; - } + nextState = INT_STATE_CLOSE_ON_ERROR; + } + else + { + if (IsoPresentation_parseAcceptMessage(self->presentation, IsoSession_getUserData(self->session)) == false) + { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: no presentation accept indication\n"); - } + self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); - } + nextState = INT_STATE_CLOSE_ON_ERROR; + } + else + { + AcseIndication acseIndication = AcseConnection_parseMessage(&(self->acseConnection), &self->presentation->nextPayload); + + if (acseIndication != ACSE_ASSOCIATE) + { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: no ACSE_ASSOCIATE indication\n"); + + self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); + + nextState = INT_STATE_CLOSE_ON_ERROR; + } + else + { + if (DEBUG_ISO_CLIENT) + printf("ISO_CLIENT: ACSE AARE - association accepted\n"); + + ByteBuffer_wrap(self->receivePayloadBuffer, self->acseConnection.userDataBuffer, + self->acseConnection.userDataBufferSize, self->acseConnection.userDataBufferSize); + + setState(self, STATE_CONNECTED); + nextState = INT_STATE_WAIT_FOR_DATA_MSG; + + if (self->callback(ISO_IND_ASSOCIATION_SUCCESS, self->callbackParameter, self->receivePayloadBuffer) == false) { + nextState = INT_STATE_CLOSE_ON_ERROR; + } + } + } - CotpConnection_resetPayload(self->cotpConnection); - } + CotpConnection_resetPayload(self->cotpConnection); + } } } - else if (packetState == TPKT_ERROR) { + else if (packetState == TPKT_ERROR) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Error receiving COTP message\n"); @@ -540,7 +556,6 @@ IsoClientConnection_handleConnection(IsoClientConnection self) else { waits = true; } - } } break; @@ -552,8 +567,8 @@ IsoClientConnection_handleConnection(IsoClientConnection self) if (packetState == TPKT_ERROR) { nextState = INT_STATE_CLOSE_ON_ERROR; } - else if (packetState == TPKT_PACKET_COMPLETE) { - + else if (packetState == TPKT_PACKET_COMPLETE) + { CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection); switch (cotpIndication) { @@ -576,23 +591,24 @@ IsoClientConnection_handleConnection(IsoClientConnection self) IsoSession_parseMessage(self->session, CotpConnection_getPayload(self->cotpConnection)); - if (sessionIndication != SESSION_DATA) { + if (sessionIndication != SESSION_DATA) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT_CONNECTION: Invalid session message\n"); nextState = INT_STATE_CLOSE_ON_ERROR; } - else { - - if (!IsoPresentation_parseUserData(self->presentation, IsoSession_getUserData(self->session))) { - + else + { + if (!IsoPresentation_parseUserData(self->presentation, IsoSession_getUserData(self->session))) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT_CONNECTION: Invalid presentation message\n"); nextState = INT_STATE_CLOSE_ON_ERROR; } - else { - + else + { self->callback(ISO_IND_DATA, self->callbackParameter, &(self->presentation->nextPayload)); @@ -659,7 +675,6 @@ IsoClientConnection_handleConnection(IsoClientConnection self) return waits; } - bool IsoClientConnection_associateAsync(IsoClientConnection self, uint32_t connectTimeoutInMs, uint32_t readTimeoutInMs) { @@ -669,7 +684,8 @@ IsoClientConnection_associateAsync(IsoClientConnection self, uint32_t connectTim self->socket = TcpSocket_create(); - if (self->socket == NULL) { + if (self->socket == NULL) + { Semaphore_post(self->tickMutex); return false; } @@ -697,8 +713,8 @@ IsoClientConnection_associateAsync(IsoClientConnection self, uint32_t connectTim Socket_bind(self->socket, self->parameters->localIpAddress, self->parameters->localTcpPort); } - if (Socket_connectAsync(self->socket, self->parameters->hostname, self->parameters->tcpPort) == false) { - + if (Socket_connectAsync(self->socket, self->parameters->hostname, self->parameters->tcpPort) == false) + { Socket_destroy(self->socket); self->socket = NULL; @@ -718,7 +734,8 @@ IsoClientConnection_associateAsync(IsoClientConnection self, uint32_t connectTim void IsoClientConnection_sendMessage(IsoClientConnection self, ByteBuffer* payloadBuffer) { - if (getState(self) == STATE_CONNECTED) { + if (getState(self) == STATE_CONNECTED) + { struct sBufferChain payloadBCMemory; BufferChain payload = &payloadBCMemory; @@ -743,7 +760,8 @@ IsoClientConnection_sendMessage(IsoClientConnection self, ByteBuffer* payloadBuf if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: IsoClientConnection_sendMessage: send message failed!\n"); } - else { + else + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: Not connected --> cannot send message\n"); } @@ -762,7 +780,8 @@ IsoClientConnection_close(IsoClientConnection self) eIsoClientInternalState intState = getIntState(self); - if ((intState != INT_STATE_IDLE) && (intState != INT_STATE_ERROR) && (intState != INT_STATE_CLOSE_ON_ERROR)) { + if ((intState != INT_STATE_IDLE) && (intState != INT_STATE_ERROR) && (intState != INT_STATE_CLOSE_ON_ERROR)) + { setIntState(self, INT_STATE_CLOSING_CONNECTION); Semaphore_post(self->tickMutex); @@ -783,8 +802,8 @@ IsoClientConnection_destroy(IsoClientConnection self) int state = getState(self); - if (state == STATE_CONNECTED) { - + if (state == STATE_CONNECTED) + { if (DEBUG_ISO_CLIENT) printf("ISO_CLIENT: call IsoClientConnection_close\n"); @@ -798,7 +817,8 @@ IsoClientConnection_destroy(IsoClientConnection self) if (self->receiveBuffer != NULL) GLOBAL_FREEMEM(self->receiveBuffer); - if (self->cotpConnection != NULL) { + if (self->cotpConnection != NULL) + { if (self->cotpConnection->handleSet != NULL) Handleset_destroy(self->cotpConnection->handleSet); @@ -910,7 +930,6 @@ IsoClientConnection_release(IsoClientConnection self) Semaphore_post(self->transmitBufferMutex); } - ByteBuffer* IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self) { diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index 6f743b0b..e92f8046 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -1,7 +1,7 @@ /* * mms_client_connection.c * - * Copyright 2013-2022 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -37,7 +37,6 @@ #define CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT 5000 #define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000 -#define OUTSTANDING_CALLS 10 static void setConnectionState(MmsConnection self, MmsConnectionState newState) @@ -65,7 +64,8 @@ getConnectionState(MmsConnection self) static void handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) { - if (self->reportHandler != NULL) { + if (self->reportHandler) + { MmsPdu_t* mmsPdu = NULL; /* allow asn1c to allocate structure */ if (DEBUG_MMS_CLIENT) @@ -74,12 +74,13 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu, (void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message)); - if (rval.code == RC_OK) { + if (rval.code == RC_OK) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: received report (size:%i)\n", (int) rval.consumed); - if (mmsPdu->present == MmsPdu_PR_unconfirmedPDU) { - + if (mmsPdu->present == MmsPdu_PR_unconfirmedPDU) + { if (mmsPdu->choice.unconfirmedPDU.unconfirmedService.present == UnconfirmedService_PR_informationReport) { @@ -121,7 +122,8 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) int listSize = report->listOfAccessResult.list.count; int variableSpecSize = report->variableAccessSpecification.choice.listOfVariable.list.count; - if (listSize != variableSpecSize) { + if (listSize != variableSpecSize) + { if (DEBUG_MMS_CLIENT) printf("report contains wrong number of access results\n"); return; @@ -131,7 +133,8 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) report->listOfAccessResult.list.array, listSize, false); int i; - for (i = 0; i < variableSpecSize; i++) { + for (i = 0; i < variableSpecSize; i++) + { if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]->variableSpecification.present == VariableSpecification_PR_name) { @@ -146,7 +149,8 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) report->variableAccessSpecification.choice.listOfVariable.list.array[i] ->variableSpecification.choice.name.choice.vmdspecific.buf; - if (nameSize < 129) { + if (nameSize < 129) + { char variableListName[129]; memcpy(variableListName, buffer, nameSize); variableListName[nameSize] = 0; @@ -167,8 +171,8 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) } } else if (report->variableAccessSpecification.choice.listOfVariable.list.array[i] - ->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) { - + ->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) + { int domainNameSize = report->variableAccessSpecification.choice.listOfVariable.list.array[i] ->variableSpecification.choice.name.choice.domainspecific.domainId.size; @@ -177,7 +181,8 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) report->variableAccessSpecification.choice.listOfVariable.list.array[i] ->variableSpecification.choice.name.choice.domainspecific.itemId.size; - if ((domainNameSize < 65) && (itemNameSize < 65)) { + if ((domainNameSize < 65) && (itemNameSize < 65)) + { char domainNameStr[65]; char itemNameStr[65]; @@ -216,7 +221,8 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) if (values != NULL) MmsValue_delete(values); } - else { + else + { /* Ignore */ if (DEBUG_MMS_CLIENT) printf("unrecognized information report\n"); @@ -226,7 +232,8 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("handleUnconfirmedMmsPdu: error parsing PDU at %u\n", (uint32_t) rval.consumed); } @@ -242,6 +249,10 @@ getNextInvokeId(MmsConnection self) Semaphore_wait(self->nextInvokeIdLock); self->nextInvokeId++; + + if (self->nextInvokeId == 0) + self->nextInvokeId = 1; + nextInvokeId = self->nextInvokeId; Semaphore_post(self->nextInvokeIdLock); @@ -255,9 +266,12 @@ checkForOutstandingCall(MmsConnection self, uint32_t invokeId) Semaphore_wait(self->outstandingCallsLock); - for (i = 0; i < OUTSTANDING_CALLS; i++) { - if (self->outstandingCalls[i].isUsed) { - if (self->outstandingCalls[i].invokeId == invokeId) { + for (i = 0; i < self->maxOutstandingCalled; i++) + { + if (self->outstandingCalls[i].isUsed) + { + if (self->outstandingCalls[i].invokeId == invokeId) + { Semaphore_post(self->outstandingCallsLock); return &(self->outstandingCalls[i]); } @@ -276,8 +290,10 @@ addToOutstandingCalls(MmsConnection self, uint32_t invokeId, eMmsOutstandingCall Semaphore_wait(self->outstandingCallsLock); - for (i = 0; i < OUTSTANDING_CALLS; i++) { - if (self->outstandingCalls[i].isUsed == false) { + for (i = 0; i < self->maxOutstandingCalled; i++) + { + if (self->outstandingCalls[i].isUsed == false) + { self->outstandingCalls[i].isUsed = true; self->outstandingCalls[i].invokeId = invokeId; self->outstandingCalls[i].timeout = Hal_getTimeInMs() + self->requestTimeout; @@ -302,9 +318,12 @@ removeFromOutstandingCalls(MmsConnection self, uint32_t invokeId) Semaphore_wait(self->outstandingCallsLock); - for (i = 0; i < OUTSTANDING_CALLS; i++) { - if (self->outstandingCalls[i].isUsed) { - if (self->outstandingCalls[i].invokeId == invokeId) { + for (i = 0; i < self->maxOutstandingCalled; i++) + { + if (self->outstandingCalls[i].isUsed) + { + if (self->outstandingCalls[i].invokeId == invokeId) + { self->outstandingCalls[i].isUsed = false; break; } @@ -321,16 +340,18 @@ mmsClient_getMatchingObtainFileRequest(MmsConnection self, const char* filename) Semaphore_wait(self->outstandingCallsLock); - for (i = 0; i < OUTSTANDING_CALLS; i++) { - if (self->outstandingCalls[i].isUsed) { - - if (self->outstandingCalls[i].type == MMS_CALL_TYPE_OBTAIN_FILE) { - + for (i = 0; i < self->maxOutstandingCalled; i++) + { + if (self->outstandingCalls[i].isUsed) + { + if (self->outstandingCalls[i].type == MMS_CALL_TYPE_OBTAIN_FILE) + { char* storedFilename = (char*) self->outstandingCalls[i].internalParameter.ptr; - if (storedFilename) { - - if (!strcmp(filename, storedFilename)) { + if (storedFilename) + { + if (!strcmp(filename, storedFilename)) + { Semaphore_post(self->outstandingCallsLock); return &(self->outstandingCalls[i]); } @@ -348,7 +369,8 @@ static void sendMessage(MmsConnection self, ByteBuffer* message) { #if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) - if (self->rawMmsMessageHandler != NULL) { + if (self->rawMmsMessageHandler != NULL) + { MmsRawMessageHandler handler = (MmsRawMessageHandler) self->rawMmsMessageHandler; handler(self->rawMmsMessageHandlerParameter, message->buffer, message->size, false); } @@ -361,8 +383,8 @@ static MmsError sendAsyncRequest(MmsConnection self, uint32_t invokeId, ByteBuffer* message, eMmsOutstandingCallType type, void* userCallback, void* userParameter, MmsClientInternalParameter internalParameter) { - if (addToOutstandingCalls(self, invokeId, type, userCallback, userParameter, internalParameter) == false) { - + if (addToOutstandingCalls(self, invokeId, type, userCallback, userParameter, internalParameter) == false) + { /* message cannot be sent - release resources */ IsoClientConnection_releaseTransmitBuffer(self->isoClient); @@ -527,7 +549,8 @@ parseServiceError(uint8_t* buffer, int bufPos, int maxLength, MmsServiceError* e int endPos = bufPos + maxLength; int length; - while (bufPos < endPos) { + while (bufPos < endPos) + { uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, endPos); @@ -588,7 +611,8 @@ mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32 int endPos = bufPos + length; - while (bufPos < endPos) { + while (bufPos < endPos) + { tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); @@ -649,7 +673,8 @@ mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invo int endPos = bufPos + length; - while (bufPos < endPos) { + while (bufPos < endPos) + { tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); @@ -657,13 +682,16 @@ mmsMsg_parseRejectPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invo if (bufPos < 0) goto exit_error; - if (tag == 0x80) { /* invoke id */ + if (tag == 0x80) + { + /* invoke id */ if (hasInvokeId) *hasInvokeId = true; if (invokeId != NULL) *invokeId = BerDecoder_decodeUint32(buffer, length, bufPos); } - else if (tag > 0x80 && tag < 0x8c) { + else if (tag > 0x80 && tag < 0x8c) + { *rejectType = tag - 0x80; *rejectReason = BerDecoder_decodeInt32(buffer, length, bufPos); } @@ -686,15 +714,19 @@ exit_error: static void handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, MmsOutstandingCall outstandingCall, MmsError err) { - if (outstandingCall->type == MMS_CALL_TYPE_READ_VARIABLE) { - + if (outstandingCall->type == MMS_CALL_TYPE_READ_VARIABLE) + { MmsConnection_ReadVariableHandler handler = (MmsConnection_ReadVariableHandler) outstandingCall->userCallback; if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL); - else { - if (response) { + } + else + { + if (response) + { MmsValue* value = mmsClient_parseReadResponse(response, NULL, false); if (value == NULL) @@ -705,15 +737,19 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M } } - else if (outstandingCall->type == MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES) { - + else if (outstandingCall->type == MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES) + { MmsConnection_ReadVariableHandler handler = (MmsConnection_ReadVariableHandler) outstandingCall->userCallback; if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL); - else { - if (response) { + } + else + { + if (response) + { MmsValue* value = mmsClient_parseReadResponse(response, NULL, true); if (value == NULL) @@ -721,19 +757,21 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M handler(outstandingCall->invokeId, outstandingCall->userParameter, err, value); } - } } - else if (outstandingCall->type == MMS_CALL_TYPE_WRITE_VARIABLE) { - + else if (outstandingCall->type == MMS_CALL_TYPE_WRITE_VARIABLE) + { MmsConnection_WriteVariableHandler handler = (MmsConnection_WriteVariableHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, DATA_ACCESS_ERROR_NO_RESPONSE); } - else { - if (response) { + else + { + if (response) + { MmsDataAccessError daError = mmsClient_parseWriteResponse(response, bufPos, &err); handler(outstandingCall->invokeId, outstandingCall->userParameter, err, daError); @@ -741,16 +779,19 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M } } - else if (outstandingCall->type == MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES) { - + else if (outstandingCall->type == MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES) + { MmsConnection_WriteMultipleVariablesHandler handler = (MmsConnection_WriteMultipleVariablesHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL); } - else { - if (response) { + else + { + if (response) + { LinkedList accessResults = NULL; mmsClient_parseWriteMultipleItemsResponse(response, bufPos, &err, -1, &accessResults); @@ -759,15 +800,19 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M } } } - else if (outstandingCall->type == MMS_CALL_TYPE_READ_NVL_DIRECTORY) { + else if (outstandingCall->type == MMS_CALL_TYPE_READ_NVL_DIRECTORY) + { MmsConnection_ReadNVLDirectoryHandler handler = (MmsConnection_ReadNVLDirectoryHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, false); } - else { - if (response) { + else + { + if (response) + { bool deletable = false; LinkedList accessSpec = mmsClient_parseGetNamedVariableListAttributesResponse(response, &deletable); @@ -779,15 +824,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M } } } - else if (outstandingCall->type == MMS_CALL_TYPE_DEFINE_NVL) { - + else if (outstandingCall->type == MMS_CALL_TYPE_DEFINE_NVL) + { MmsConnection_GenericServiceHandler handler = (MmsConnection_GenericServiceHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, false); } - else { + else + { bool success = false; if (!mmsClient_parseDefineNamedVariableResponse(response, NULL)) @@ -798,15 +845,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M handler(outstandingCall->invokeId, outstandingCall->userParameter, err, success); } } - else if (outstandingCall->type == MMS_CALL_TYPE_DELETE_NVL) { - + else if (outstandingCall->type == MMS_CALL_TYPE_DELETE_NVL) + { MmsConnection_GenericServiceHandler handler = (MmsConnection_GenericServiceHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, false); } - else { + else + { bool success = false; long numberMatched = 0; @@ -816,8 +865,11 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M success = true; if (numberMatched == 0) + { err = MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT; - else { + } + else + { if (numberDeleted == 0) err = MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED; } @@ -825,14 +877,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M handler(outstandingCall->invokeId, outstandingCall->userParameter, err, success); } } - else if (outstandingCall->type == MMS_CALL_TYPE_GET_VAR_ACCESS_ATTR) { + else if (outstandingCall->type == MMS_CALL_TYPE_GET_VAR_ACCESS_ATTR) + { MmsConnection_GetVariableAccessAttributesHandler handler = (MmsConnection_GetVariableAccessAttributesHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL); } - else { + else + { MmsVariableSpecification* typeSpec = mmsClient_parseGetVariableAccessAttributesResponse(response, NULL); if (typeSpec == NULL) @@ -841,14 +896,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M handler(outstandingCall->invokeId, outstandingCall->userParameter, err, typeSpec); } } - else if (outstandingCall->type == MMS_CALL_TYPE_GET_SERVER_STATUS) { + else if (outstandingCall->type == MMS_CALL_TYPE_GET_SERVER_STATUS) + { MmsConnection_GetServerStatusHandler handler = (MmsConnection_GetServerStatusHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, 0, 0); } - else { + else + { int vmdLogicalStatus; int vmdPhysicalStatus; @@ -858,15 +916,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M handler(outstandingCall->invokeId, outstandingCall->userParameter, err, vmdLogicalStatus, vmdPhysicalStatus); } } - else if (outstandingCall->type == MMS_CALL_TYPE_IDENTIFY) { + else if (outstandingCall->type == MMS_CALL_TYPE_IDENTIFY) + { MmsConnection_IdentifyHandler handler = (MmsConnection_IdentifyHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, NULL, NULL); } - else { - + else + { if (mmsClient_parseIdentifyResponse(self, response, bufPos, outstandingCall->invokeId, handler, outstandingCall->userParameter) == false) { @@ -876,15 +936,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M } } - else if (outstandingCall->type == MMS_CALL_TYPE_READ_JOURNAL) { - + else if (outstandingCall->type == MMS_CALL_TYPE_READ_JOURNAL) + { MmsConnection_ReadJournalHandler handler = (MmsConnection_ReadJournalHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, false); } - else { + else + { bool moreFollows = false; LinkedList entries = NULL; @@ -896,15 +958,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M } } } - else if (outstandingCall->type == MMS_CALL_TYPE_GET_NAME_LIST) { - + else if (outstandingCall->type == MMS_CALL_TYPE_GET_NAME_LIST) + { MmsConnection_GetNameListHandler handler = (MmsConnection_GetNameListHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, false); } - else { + else + { LinkedList nameList = (LinkedList) outstandingCall->internalParameter.ptr; bool moreFollows = mmsClient_parseGetNameListResponse(&nameList, response); @@ -917,15 +981,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M } } } - else if (outstandingCall->type == MMS_CALL_TYPE_FILE_OPEN) { - + else if (outstandingCall->type == MMS_CALL_TYPE_FILE_OPEN) + { MmsConnection_FileOpenHandler handler = (MmsConnection_FileOpenHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, 0, 0, 0); } - else { + else + { int32_t frsmId; uint32_t fileSize; uint64_t lastModified; @@ -935,21 +1001,25 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M { handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, 0, 0, 0); } - else { + else + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, frsmId, fileSize, lastModified); } } } - else if (outstandingCall->type == MMS_CALL_TYPE_FILE_READ) { + else if (outstandingCall->type == MMS_CALL_TYPE_FILE_READ) + { MmsConnection_FileReadHandler handler = (MmsConnection_FileReadHandler) outstandingCall->userCallback; int32_t frsmId = outstandingCall->internalParameter.i32; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, frsmId, NULL, 0, false); } - else { + else + { bool moreFollows; if (mmsMsg_parseFileReadResponse(ByteBuffer_getBuffer(response), bufPos, ByteBuffer_getSize(response), outstandingCall->invokeId, frsmId, &moreFollows, @@ -967,7 +1037,8 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M MmsConnection_GenericServiceHandler handler = (MmsConnection_GenericServiceHandler) outstandingCall->userCallback; - if (outstandingCall->type == MMS_CALL_TYPE_OBTAIN_FILE) { + if (outstandingCall->type == MMS_CALL_TYPE_OBTAIN_FILE) + { if (outstandingCall->internalParameter.ptr) GLOBAL_FREEMEM(outstandingCall->internalParameter.ptr); } @@ -979,14 +1050,17 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M handler(outstandingCall->invokeId, outstandingCall->userParameter, err, true); } } - else if (outstandingCall->type == MMS_CALL_TYPE_GET_FILE_DIR) { + else if (outstandingCall->type == MMS_CALL_TYPE_GET_FILE_DIR) + { MmsConnection_FileDirectoryHandler handler = (MmsConnection_FileDirectoryHandler) outstandingCall->userCallback; - if (err != MMS_ERROR_NONE) { + if (err != MMS_ERROR_NONE) + { handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, 0, 0, false); } - else { + else + { if (mmsClient_parseFileDirectoryResponse(response, bufPos, outstandingCall->invokeId, handler, outstandingCall->userParameter) == false) handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, NULL, 0, 0, false); } @@ -1005,24 +1079,24 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) if (indication != ISO_IND_TICK) printf("MMS_CLIENT: mmsIsoCallback called with indication %i\n", indication); - if (indication == ISO_IND_TICK) { - + if (indication == ISO_IND_TICK) + { /* check timeouts */ uint64_t currentTime = Hal_getTimeInMs(); int i = 0; - for (i = 0; i < OUTSTANDING_CALLS; i++) { - + for (i = 0; i < self->maxOutstandingCalled; i++) + { Semaphore_wait(self->outstandingCallsLock); - if (self->outstandingCalls[i].isUsed) { - + if (self->outstandingCalls[i].isUsed) + { Semaphore_post(self->outstandingCallsLock); - if (currentTime > self->outstandingCalls[i].timeout) { - + if (currentTime > self->outstandingCalls[i].timeout) + { if (self->outstandingCalls[i].type != MMS_CALL_TYPE_NONE) handleAsyncResponse(self, NULL, 0, &(self->outstandingCalls[i]), MMS_ERROR_SERVICE_TIMEOUT); @@ -1038,8 +1112,10 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) } } - if (self->concludeHandler) { - if (currentTime > self->concludeTimeout) { + if (self->concludeHandler) + { + if (currentTime > self->concludeTimeout) + { self->concludeHandler(self->concludeHandlerParameter, MMS_ERROR_SERVICE_TIMEOUT, false); self->concludeHandler = NULL; } @@ -1048,7 +1124,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) return true; } - if (indication == ISO_IND_CLOSED) { + if (indication == ISO_IND_CLOSED) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: mmsIsoCallback: Connection lost or closed by client!\n"); @@ -1062,12 +1139,12 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) { int i; - for (i = 0; i < OUTSTANDING_CALLS; i++) { - + for (i = 0; i < self->maxOutstandingCalled; i++) + { Semaphore_wait(self->outstandingCallsLock); - if (self->outstandingCalls[i].isUsed) { - + if (self->outstandingCalls[i].isUsed) + { Semaphore_post(self->outstandingCallsLock); if (self->outstandingCalls[i].type != MMS_CALL_TYPE_NONE) @@ -1085,7 +1162,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) return true; } - if (indication == ISO_IND_ASSOCIATION_FAILED) { + if (indication == ISO_IND_ASSOCIATION_FAILED) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: mmsIsoCallback: association failed!\n"); @@ -1093,7 +1171,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) return false; } - if (payload != NULL) { + if (payload != NULL) + { if (ByteBuffer_getSize(payload) < 1) { return false; } @@ -1102,7 +1181,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) uint8_t* buf = ByteBuffer_getBuffer(payload); #if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) - if (self->rawMmsMessageHandler != NULL) { + if (self->rawMmsMessageHandler != NULL) + { MmsRawMessageHandler handler = (MmsRawMessageHandler) self->rawMmsMessageHandler; handler(self->rawMmsMessageHandlerParameter, buf, payload->size, true); } @@ -1113,20 +1193,25 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: MMS-PDU: %02x\n", tag); - if (tag == 0xa9) { /* initiate response PDU */ - - if (indication == ISO_IND_ASSOCIATION_SUCCESS) { + if (tag == 0xa9) + { + /* initiate response PDU */ - if (mmsClient_parseInitiateResponse(self, payload)) { + if (indication == ISO_IND_ASSOCIATION_SUCCESS) + { + if (mmsClient_parseInitiateResponse(self, payload)) + { setConnectionState(self, MMS_CONNECTION_STATE_CONNECTED); } - else { + else + { setConnectionState(self, MMS_CONNECTION_STATE_CLOSING); goto exit_with_error; } } - else { + else + { setConnectionState(self, MMS_CONNECTION_STATE_CLOSING); if (DEBUG_MMS_CLIENT) @@ -1135,7 +1220,9 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) return false; } } - else if (tag == 0xaa) { /* initiate error PDU */ + else if (tag == 0xaa) + { + /* initiate error PDU */ if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: received initiate error PDU\n"); @@ -1144,36 +1231,48 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) return false; } - else if (tag == 0xa3) { /* unconfirmed PDU */ + else if (tag == 0xa3) + { + /* unconfirmed PDU */ handleUnconfirmedMmsPdu(self, payload); } - else if (tag == 0x8b) { /* conclude request PDU */ + else if (tag == 0x8b) + { + /* conclude request PDU */ if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: received conclude.request\n"); /* TODO block all new user requests? */ } - else if (tag == 0x8c) { /* conclude response PDU */ + else if (tag == 0x8c) + { + /* conclude response PDU */ if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: received conclude.response+\n"); - if (self->concludeHandler) { + if (self->concludeHandler) + { self->concludeHandler(self->concludeHandlerParameter, MMS_ERROR_NONE, true); self->concludeHandler = NULL; } IsoClientConnection_release(self->isoClient); } - else if (tag == 0x8d) { /* conclude error PDU */ + else if (tag == 0x8d) + { + /* conclude error PDU */ if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: received conclude.reponse-\n"); - if (self->concludeHandler) { + if (self->concludeHandler) + { self->concludeHandler(self->concludeHandlerParameter, MMS_ERROR_CONCLUDE_REJECTED, false); self->concludeHandler = NULL; } } - else if (tag == 0xa2) { /* confirmed error PDU */ + else if (tag == 0xa2) + { + /* confirmed error PDU */ if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: Confirmed error PDU!\n"); @@ -1183,37 +1282,43 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) MmsServiceError serviceError = { 0, 0 }; - if (mmsMsg_parseConfirmedErrorPDU(payload->buffer, 0, payload->size, &invokeId, &hasInvokeId, &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"); goto exit_with_error; } - else { - - if (hasInvokeId) { + else + { + if (hasInvokeId) + { MmsOutstandingCall call = checkForOutstandingCall(self, invokeId); - if (call) { - + if (call) + { MmsError err = convertServiceErrorToMmsError(serviceError); - if (call->type != MMS_CALL_TYPE_NONE) { + if (call->type != MMS_CALL_TYPE_NONE) + { handleAsyncResponse(self, NULL, 0, call, err); } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: internal problem (unexpected call type - error PDU)\n"); } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: server sent unexpected confirmed error PDU!\n"); return false; } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: server sent confirmed error PDU without invoke ID!\n"); @@ -1222,7 +1327,9 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) } } - else if (tag == 0xa4) { /* reject PDU */ + else if (tag == 0xa4) + { + /* reject PDU */ if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: reject PDU!\n"); @@ -1232,23 +1339,25 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) int rejectType; int rejectReason; - if (mmsMsg_parseRejectPDU(payload->buffer, 0, payload->size, &invokeId, &hasInvokeId, &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: %u type: %i reason: %i\n", invokeId, rejectType, rejectReason); - if (hasInvokeId) { + if (hasInvokeId) + { MmsOutstandingCall call = checkForOutstandingCall(self, invokeId); - if (call) { - + if (call) + { MmsError err = convertRejectCodesToMmsError(rejectType, rejectReason); - if (call->type != MMS_CALL_TYPE_NONE) { + if (call->type != MMS_CALL_TYPE_NONE) + { handleAsyncResponse(self, NULL, 0, call, err); } - else { - + else + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: internal problem (unexpected call type - reject PDU)\n"); } @@ -1260,12 +1369,13 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) else { return false; } - } else goto exit_with_error; } - else if (tag == 0xa1) { /* confirmed response PDU */ + else if (tag == 0xa1) + { + /* confirmed response PDU */ int length; int bufPos = 1; @@ -1274,7 +1384,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) if (bufPos < 0) goto exit_with_error; - if (buf[bufPos++] == 0x02) { + if (buf[bufPos++] == 0x02) + { int invokeIdLength; bufPos = BerDecoder_decodeLength(buf, &invokeIdLength, bufPos, payload->size); @@ -1292,17 +1403,20 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) MmsOutstandingCall call = checkForOutstandingCall(self, invokeId); - if (call) { - - if (call->type != MMS_CALL_TYPE_NONE) { + if (call) + { + if (call->type != MMS_CALL_TYPE_NONE) + { handleAsyncResponse(self, payload, bufPos, call, MMS_ERROR_NONE); } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: internal problem (unexpected call type - confirmed response PDU)\n"); } } - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: unexpected message from server!\n"); @@ -1313,8 +1427,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) goto exit_with_error; } #if (MMS_OBTAIN_FILE_SERVICE == 1) - else if (tag == 0xa0) { - + else if (tag == 0xa0) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: received confirmed request PDU (size=%i)\n", payload->size); @@ -1330,13 +1444,14 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) bool hasInvokeId = false; uint32_t invokeId = 0; - while (bufPos < payload->size) { - + while (bufPos < payload->size) + { uint8_t nestedTag = buf[bufPos++]; bool extendedTag = false; - if ((nestedTag & 0x1f) == 0x1f) { + if ((nestedTag & 0x1f) == 0x1f) + { extendedTag = true; nestedTag = buf[bufPos++]; } @@ -1345,9 +1460,10 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) if (bufPos < 0) goto exit_with_error; - if (extendedTag) { - - if (hasInvokeId == false) { + if (extendedTag) + { + if (hasInvokeId == false) + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: invalid message received - missing invoke ID!\n"); @@ -1434,7 +1550,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload) } #endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */ - else { + else + { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT: unknown message type\n"); @@ -1460,7 +1577,8 @@ connectionHandlingThread(void* parameter) { MmsConnection self = (MmsConnection) parameter; - while (self->connectionThreadRunning) { + while (self->connectionThreadRunning) + { if (MmsConnection_tick(self)) Thread_sleep(10); } @@ -1479,8 +1597,8 @@ MmsConnection_createInternal(TLSConfiguration tlsConfig, bool createThread) MmsConnection self = (MmsConnection) GLOBAL_CALLOC(1, sizeof(struct sMmsConnection)); - if (self) { - + if (self) + { self->parameters.dataStructureNestingLevel = -1; self->parameters.maxServOutstandingCalled = -1; self->parameters.maxServOutstandingCalling = -1; @@ -1498,7 +1616,9 @@ MmsConnection_createInternal(TLSConfiguration tlsConfig, bool createThread) self->concludeHandlerParameter = NULL; self->concludeTimeout = 0; - self->outstandingCalls = (MmsOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sMmsOutstandingCall)); + self->maxOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + self->maxOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + self->outstandingCalls = (MmsOutstandingCall) GLOBAL_CALLOC(CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED, sizeof(struct sMmsOutstandingCall)); self->isoParameters = IsoConnectionParameters_create(); @@ -1555,43 +1675,49 @@ MmsConnection_createNonThreaded(TLSConfiguration tlsConfig) void MmsConnection_destroy(MmsConnection self) { + if (self) + { #if (CONFIG_MMS_THREADLESS_STACK == 0) - if (self->createThread) { - if (self->connectionHandlingThread) { - if (self->connectionThreadRunning) { - self->connectionThreadRunning = false; - Thread_destroy(self->connectionHandlingThread); - self->connectionHandlingThread = NULL; + if (self->createThread) + { + if (self->connectionHandlingThread) + { + if (self->connectionThreadRunning) + { + self->connectionThreadRunning = false; + Thread_destroy(self->connectionHandlingThread); + self->connectionHandlingThread = NULL; + } } } - } #endif - if (self->isoClient != NULL) - IsoClientConnection_destroy(self->isoClient); + if (self->isoClient != NULL) + IsoClientConnection_destroy(self->isoClient); - if (self->isoParameters != NULL) - IsoConnectionParameters_destroy(self->isoParameters); + if (self->isoParameters != NULL) + IsoConnectionParameters_destroy(self->isoParameters); - Semaphore_destroy(self->nextInvokeIdLock); + Semaphore_destroy(self->nextInvokeIdLock); - Semaphore_destroy(self->outstandingCallsLock); + Semaphore_destroy(self->outstandingCallsLock); - Semaphore_destroy(self->associationStateLock); + Semaphore_destroy(self->associationStateLock); - GLOBAL_FREEMEM(self->outstandingCalls); + GLOBAL_FREEMEM(self->outstandingCalls); #if (MMS_OBTAIN_FILE_SERVICE == 1) #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) - if (self->filestoreBasepath != NULL) - GLOBAL_FREEMEM(self->filestoreBasepath); + if (self->filestoreBasepath != NULL) + GLOBAL_FREEMEM(self->filestoreBasepath); #endif - /* Close outstanding open files */ - mmsClient_closeOutstandingOpenFiles(self); + /* Close outstanding open files */ + mmsClient_closeOutstandingOpenFiles(self); #endif - GLOBAL_FREEMEM(self); + GLOBAL_FREEMEM(self); + } } void @@ -1599,7 +1725,8 @@ MmsConnection_setFilestoreBasepath(MmsConnection self, const char* basepath) { #if (MMS_OBTAIN_FILE_SERVICE == 1) #if (CONFIG_SET_FILESTORE_BASEPATH_AT_RUNTIME == 1) - if (self->filestoreBasepath != NULL) { + if (self->filestoreBasepath != NULL) + { GLOBAL_FREEMEM(self->filestoreBasepath); self->filestoreBasepath = NULL; } @@ -1657,6 +1784,25 @@ MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs) self->requestTimeout = timeoutInMs; } +void +MmsConnnection_setMaxOutstandingCalls(MmsConnection self, int calling, int called) +{ + if (calling < 1) + calling = 1; + + if (called < 1) + called = 1; + + if (self->outstandingCalls) + { + GLOBAL_FREEMEM(self->outstandingCalls); + } + + self->maxOutstandingCalling = calling; + self->maxOutstandingCalled = called; + self->outstandingCalls = (MmsOutstandingCall)GLOBAL_CALLOC(called, sizeof(struct sMmsOutstandingCall)); +} + uint32_t MmsConnection_getRequestTimeout(MmsConnection self) { @@ -1740,22 +1886,25 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* server MmsConnection_connectAsync(self, &err, serverName, serverPort); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(conParams.sem); - if (conParams.state == MMS_CONNECTION_STATE_CONNECTED) { + if (conParams.state == MMS_CONNECTION_STATE_CONNECTED) + { *mmsError = MMS_ERROR_NONE; success = true; } - else { + else + { *mmsError = MMS_ERROR_CONNECTION_REJECTED; } if (conParams.originalHandler) conParams.originalHandler(self, conParams.originalParameter, conParams.state); - } - else { + else + { *mmsError = err; } @@ -1770,7 +1919,8 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* server void MmsConnection_connectAsync(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort) { - if (serverPort == -1) { + if (serverPort == -1) + { #if (CONFIG_MMS_SUPPORT_TLS == 1) if (self->isoParameters->tlsConfiguration) serverPort = 3782; @@ -1782,9 +1932,10 @@ MmsConnection_connectAsync(MmsConnection self, MmsError* mmsError, const char* s } #if (CONFIG_MMS_THREADLESS_STACK == 0) - if (self->createThread) { - if (self->connectionHandlingThread == NULL) { - + if (self->createThread) + { + if (self->connectionHandlingThread == NULL) + { self->connectionHandlingThread = Thread_create(connectionHandlingThread, self, false); self->connectionThreadRunning = true; Thread_start(self->connectionHandlingThread); @@ -1802,13 +1953,15 @@ MmsConnection_connectAsync(MmsConnection self, MmsError* mmsError, const char* s mmsClient_createInitiateRequest(self, payload); #if (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) - if (self->rawMmsMessageHandler != NULL) { + if (self->rawMmsMessageHandler != NULL) + { MmsRawMessageHandler handler = (MmsRawMessageHandler) self->rawMmsMessageHandler; handler(self->rawMmsMessageHandlerParameter, payload->buffer, payload->size, false); } #endif /* (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) */ - if (IsoClientConnection_associateAsync(self->isoClient, self->connectTimeout, self->requestTimeout)) { + if (IsoClientConnection_associateAsync(self->isoClient, self->connectTimeout, self->requestTimeout)) + { setConnectionState(self, MMS_CONNECTION_STATE_CONNECTING); *mmsError = MMS_ERROR_NONE; } @@ -1837,7 +1990,8 @@ MmsConnection_abortAsync(MmsConnection self, MmsError* mmsError) { self->connectionLostHandler = NULL; - if (getConnectionState(self) == MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) == MMS_CONNECTION_STATE_CONNECTED) + { IsoClientConnection_abortAsync(self->isoClient); *mmsError = MMS_ERROR_NONE; } @@ -1855,14 +2009,16 @@ MmsConnection_abort(MmsConnection self, MmsError* mmsError) bool success = false; - if (getConnectionState(self) == MMS_CONNECTION_STATE_CONNECTED) { - + if (getConnectionState(self) == MMS_CONNECTION_STATE_CONNECTED) + { IsoClientConnection_abortAsync(self->isoClient); uint64_t timeout = Hal_getTimeInMs() + self->requestTimeout; - while (Hal_getTimeInMs() < timeout) { - if (getConnectionState(self) == MMS_CONNECTION_STATE_CLOSED) { + while (Hal_getTimeInMs() < timeout) + { + if (getConnectionState(self) == MMS_CONNECTION_STATE_CLOSED) + { success = true; break; } @@ -1870,10 +2026,10 @@ MmsConnection_abort(MmsConnection self, MmsError* mmsError) Thread_sleep(10); } } - } - if (success == false) { + if (success == false) + { IsoClientConnection_close(self->isoClient); *mmsError = MMS_ERROR_SERVICE_TIMEOUT; } @@ -1915,7 +2071,8 @@ MmsConnection_conclude(MmsConnection self, MmsError* mmsError) MmsConnection_concludeAsync(self, &err, concludeHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); err = parameter.err; } @@ -1929,7 +2086,8 @@ MmsConnection_conclude(MmsConnection self, MmsError* mmsError) void MmsConnection_concludeAsync(MmsConnection self, MmsError* mmsError, MmsConnection_ConcludeAbortHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; } @@ -1971,7 +2129,8 @@ mmsClient_getNameListSingleRequestAsync( void* parameter, LinkedList nameList) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -1987,8 +2146,8 @@ mmsClient_getNameListSingleRequestAsync( if (associationSpecific) mmsClient_createMmsGetNameListRequestAssociationSpecific(invokeId, payload, continueAfter); - else { - + else + { if (objectClass == MMS_OBJECT_CLASS_DOMAIN) mmsClient_createMmsGetNameListRequestVMDspecific(invokeId, payload, continueAfter); @@ -2032,7 +2191,6 @@ getNameListHandler(uint32_t invokeId, void* parameter, MmsError mmsError, Linked Semaphore_post(parameters->sem); } - static LinkedList /* */ mmsClient_getNameList(MmsConnection self, MmsError *mmsError, const char* domainId, @@ -2055,7 +2213,8 @@ mmsClient_getNameList(MmsConnection self, MmsError *mmsError, mmsClient_getNameListSingleRequestAsync(self, NULL, &err, domainId, objectClass, associationSpecific, NULL, getNameListHandler, ¶meter, NULL); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); err = parameter.err; list = parameter.nameList; @@ -2064,7 +2223,8 @@ mmsClient_getNameList(MmsConnection self, MmsError *mmsError, Semaphore_destroy(parameter.sem); - while (moreFollows) { + while (moreFollows) + { parameter.sem = Semaphore_create(1); char* continueAfter = NULL; @@ -2077,12 +2237,18 @@ mmsClient_getNameList(MmsConnection self, MmsError *mmsError, mmsClient_getNameListSingleRequestAsync(self, NULL, &err, domainId, objectClass, associationSpecific, continueAfter, getNameListHandler, ¶meter, list); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); err = parameter.err; list = parameter.nameList; moreFollows = parameter.moreFollows; } + else + { + /* exit loop when message cannot be sent */ + moreFollows = false; + } Semaphore_destroy(parameter.sem); } @@ -2090,8 +2256,10 @@ mmsClient_getNameList(MmsConnection self, MmsError *mmsError, if (mmsError) *mmsError = err; - if (err != MMS_ERROR_NONE) { - if (list) { + if (err != MMS_ERROR_NONE) + { + if (list) + { LinkedList_destroy(list); list = NULL; } @@ -2184,7 +2352,6 @@ MmsConnection_getVariableListNamesAssociationSpecificAsync(MmsConnection self, u continueAfter, handler, parameter, NULL); } - struct readNVParameters { Semaphore sem; @@ -2210,7 +2377,8 @@ void MmsConnection_readVariableAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* itemId, MmsConnection_ReadVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; @@ -2255,7 +2423,8 @@ MmsConnection_readVariable(MmsConnection self, MmsError* mmsError, MmsConnection_readVariableAsync(self, NULL, &err, domainId, itemId, readVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); value = parameter.value; @@ -2275,7 +2444,8 @@ MmsConnection_readVariableComponentAsync(MmsConnection self, uint32_t* usedInvok const char* domainId, const char* itemId, const char* componentId, MmsConnection_ReadVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; @@ -2320,7 +2490,8 @@ MmsConnection_readVariableComponent(MmsConnection self, MmsError* mmsError, MmsConnection_readVariableComponentAsync(self, NULL, &err, domainId, itemId, componentId, readVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); value = parameter.value; @@ -2354,7 +2525,8 @@ MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError, MmsConnection_readArrayElementsAsync(self, NULL, &err, domainId, itemId, startIndex, numberOfElements, readVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); value = parameter.value; @@ -2374,7 +2546,8 @@ MmsConnection_readArrayElementsAsync(MmsConnection self, uint32_t* usedInvokeId, uint32_t startIndex, uint32_t numberOfElements, MmsConnection_ReadVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2420,7 +2593,8 @@ MmsConnection_readSingleArrayElementWithComponent(MmsConnection self, MmsError* MmsConnection_readSingleArrayElementWithComponentAsync(self, NULL, &err, domainId, itemId, index, componentId, readVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); value = parameter.value; @@ -2442,7 +2616,8 @@ MmsConnection_readSingleArrayElementWithComponentAsync(MmsConnection self, uint3 uint32_t index, const char* componentId, MmsConnection_ReadVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2488,7 +2663,8 @@ MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError, MmsConnection_readMultipleVariablesAsync(self, NULL, &err, domainId, items, readVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); value = parameter.value; @@ -2508,7 +2684,8 @@ MmsConnection_readMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvok const char* domainId, LinkedList /**/items, MmsConnection_ReadVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2521,7 +2698,8 @@ MmsConnection_readMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvok if (usedInvokeId) *usedInvokeId = invokeId; - if (mmsClient_createReadRequestMultipleValues(invokeId, domainId, items, payload) > 0) { + if (mmsClient_createReadRequestMultipleValues(invokeId, domainId, items, payload) > 0) + { MmsClientInternalParameter intParam; intParam.ptr = NULL; @@ -2530,7 +2708,8 @@ MmsConnection_readMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvok if (mmsError) *mmsError = err; } - else { + else + { if (mmsError) *mmsError = MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE; } @@ -2558,7 +2737,8 @@ MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError MmsConnection_readNamedVariableListValuesAsync(self, NULL, &err, domainId, listName, specWithResult, readVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); value = parameter.value; @@ -2578,7 +2758,8 @@ MmsConnection_readNamedVariableListValuesAsync(MmsConnection self, uint32_t* use const char* domainId, const char* listName, bool specWithResult, MmsConnection_ReadVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2626,7 +2807,8 @@ MmsConnection_readNamedVariableListValuesAssociationSpecific( MmsConnection_readNamedVariableListValuesAssociationSpecificAsync(self, NULL, &err, listName, specWithResult, readVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); value = parameter.value; @@ -2646,7 +2828,8 @@ MmsConnection_readNamedVariableListValuesAssociationSpecificAsync(MmsConnection const char* listName, bool specWithResult, MmsConnection_ReadVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2716,7 +2899,8 @@ MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsEr MmsConnection_readNamedVariableListDirectoryAsync(self, NULL, &err, domainId, listName, readNVLDirectoryHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(waitForResponse); err = parameter.err; specs = parameter.specs; @@ -2738,7 +2922,8 @@ MmsConnection_readNamedVariableListDirectoryAsync(MmsConnection self, uint32_t* const char* domainId, const char* listName, MmsConnection_ReadNVLDirectoryHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2785,7 +2970,8 @@ MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection se MmsConnection_readNamedVariableListDirectoryAssociationSpecificAsync(self, NULL, &err, listName, readNVLDirectoryHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(waitForResponse); err = parameter.err; specs = parameter.specs; @@ -2807,7 +2993,8 @@ MmsConnection_readNamedVariableListDirectoryAssociationSpecificAsync(MmsConnecti const char* listName, MmsConnection_ReadNVLDirectoryHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2872,7 +3059,8 @@ MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError, MmsConnection_defineNamedVariableListAsync(self, NULL, &err, domainId, listName, variableSpecs, defineNVLHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; } @@ -2888,7 +3076,8 @@ MmsConnection_defineNamedVariableListAsync(MmsConnection self, uint32_t* usedInv const char* listName, LinkedList variableSpecs, MmsConnection_GenericServiceHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2931,7 +3120,8 @@ MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self, MmsConnection_defineNamedVariableListAssociationSpecificAsync(self, NULL, &err, listName, variableSpecs, defineNVLHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; } @@ -2947,7 +3137,8 @@ MmsConnection_defineNamedVariableListAssociationSpecificAsync(MmsConnection self const char* listName, LinkedList variableSpecs, MmsConnection_GenericServiceHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -2991,7 +3182,8 @@ MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError, MmsConnection_deleteNamedVariableListAsync(self, NULL, &err, domainId, listName, defineNVLHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; isDeleted = parameter.success; @@ -3009,7 +3201,8 @@ void MmsConnection_deleteNamedVariableListAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* listName, MmsConnection_GenericServiceHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3052,7 +3245,8 @@ MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self, MmsConnection_deleteAssociationSpecificNamedVariableListAsync(self, NULL, &err, listName, defineNVLHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; isDeleted = parameter.success; @@ -3070,7 +3264,8 @@ void MmsConnection_deleteAssociationSpecificNamedVariableListAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* listName, MmsConnection_GenericServiceHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3135,7 +3330,8 @@ MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError MmsConnection_getVariableAccessAttributesAsync(self, NULL, &err, domainId, itemId, getAccessAttrHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; typeSpec = parameter.typeSpec; @@ -3154,7 +3350,8 @@ MmsConnection_getVariableAccessAttributesAsync(MmsConnection self, uint32_t* use const char* domainId, const char* itemId, MmsConnection_GetVariableAccessAttributesHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3224,7 +3421,8 @@ MmsConnection_identify(MmsConnection self, MmsError* mmsError) MmsConnection_identifyAsync(self, NULL, &err, identifyHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; identity = parameter.identify; @@ -3242,7 +3440,8 @@ void MmsConnection_identifyAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, MmsConnection_IdentifyHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3310,7 +3509,8 @@ MmsConnection_getServerStatus(MmsConnection self, MmsError* mmsError, int* vmdLo MmsConnection_getServerStatusAsync(self, NULL, &err, extendedDerivation, getServerStatusHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -3331,7 +3531,8 @@ void MmsConnection_getServerStatusAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, bool extendedDerivation, MmsConnection_GetServerStatusHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3361,7 +3562,8 @@ exit_function: static void MmsJournalVariable_destroy(MmsJournalVariable self) { - if (self != NULL) { + if (self) + { GLOBAL_FREEMEM(self->tag); MmsValue_delete(self->value); GLOBAL_FREEMEM(self); @@ -3371,7 +3573,8 @@ MmsJournalVariable_destroy(MmsJournalVariable self) void MmsJournalEntry_destroy(MmsJournalEntry self) { - if (self != NULL) { + if (self) + { MmsValue_delete(self->entryID); MmsValue_delete(self->occurenceTime); LinkedList_destroyDeep(self->journalVariables, @@ -3451,7 +3654,8 @@ MmsConnection_readJournalTimeRange(MmsConnection self, MmsError* mmsError, const MmsConnection_readJournalTimeRangeAsync(self, NULL, &err, domainId, itemId, startTime, endTime, readJournalHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -3472,15 +3676,16 @@ void MmsConnection_readJournalTimeRangeAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* itemId, MmsValue* startTime, MmsValue* endTime, MmsConnection_ReadJournalHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; } if ((MmsValue_getType(startTime) != MMS_BINARY_TIME) || - (MmsValue_getType(endTime) != MMS_BINARY_TIME)) { - + (MmsValue_getType(endTime) != MMS_BINARY_TIME)) + { if (mmsError) *mmsError = MMS_ERROR_INVALID_ARGUMENTS; goto exit_function; @@ -3524,7 +3729,8 @@ MmsConnection_readJournalStartAfter(MmsConnection self, MmsError* mmsError, cons MmsConnection_readJournalStartAfterAsync(self, NULL, &err, domainId, itemId, timeSpecification, entrySpecification, readJournalHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -3545,15 +3751,16 @@ void MmsConnection_readJournalStartAfterAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError* mmsError, const char* domainId, const char* itemId, MmsValue* timeSpecification, MmsValue* entrySpecification, MmsConnection_ReadJournalHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; } if ((MmsValue_getType(timeSpecification) != MMS_BINARY_TIME) || - (MmsValue_getType(entrySpecification) != MMS_OCTET_STRING)) { - + (MmsValue_getType(entrySpecification) != MMS_OCTET_STRING)) + { if (mmsError) *mmsError = MMS_ERROR_INVALID_ARGUMENTS; goto exit_function; @@ -3626,7 +3833,8 @@ MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, const char* filen MmsConnection_fileOpenAsync(self, NULL, &err, filename, initialPosition, fileOpenHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -3659,7 +3867,8 @@ MmsConnection_fileOpenAsync(MmsConnection self, uint32_t* usedInvokeId, MmsError { #if (MMS_FILE_SERVICE == 1) - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3731,7 +3940,8 @@ MmsConnection_fileClose(MmsConnection self, MmsError* mmsError, int32_t frsmId) MmsConnection_fileCloseAsync(self, NULL, &err, frsmId, fileOperationHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -3755,7 +3965,8 @@ MmsConnection_fileCloseAsync(MmsConnection self, uint32_t* usedInvokeId, MmsErro { #if (MMS_FILE_SERVICE == 1) - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3806,7 +4017,8 @@ MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, const char* fil MmsConnection_fileDeleteAsync(self, NULL, &err, fileName, fileOperationHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -3831,7 +4043,8 @@ MmsConnection_fileDeleteAsync(MmsConnection self, uint32_t* usedInvokeId, MmsErr { #if (MMS_FILE_SERVICE == 1) - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -3913,7 +4126,8 @@ MmsConnection_fileRead(MmsConnection self, MmsError* mmsError, int32_t frsmId, M MmsConnection_fileReadAsync(self, NULL, &err, frsmId, fileReadHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -3993,7 +4207,8 @@ getFileDirHandler(uint32_t invokeId, void* parameter, MmsError mmsError, char* f parameters->err = mmsError; - if ((mmsError != MMS_ERROR_NONE) || (filename == NULL)) { + if ((mmsError != MMS_ERROR_NONE) || (filename == NULL)) + { parameters->moreFollows = moreFollows; /* last call --> unblock user thread */ @@ -4024,7 +4239,8 @@ MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, const cha MmsConnection_getFileDirectoryAsync(self, NULL, &err, fileSpecification, continueAfter, getFileDirHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; moreFollows = parameter.moreFollows; @@ -4051,7 +4267,8 @@ MmsConnection_getFileDirectoryAsync(MmsConnection self, uint32_t* usedInvokeId, { #if (MMS_FILE_SERVICE == 1) - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4102,7 +4319,8 @@ MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, const char* cur MmsConnection_fileRenameAsync(self, NULL, &err, currentFileName, newFileName, fileOperationHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -4126,7 +4344,8 @@ MmsConnection_fileRenameAsync(MmsConnection self, uint32_t* usedInvokeId, MmsErr { #if (MMS_FILE_SERVICE == 1) - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4177,7 +4396,8 @@ MmsConnection_obtainFile(MmsConnection self, MmsError* mmsError, const char* sou MmsConnection_obtainFileAsync(self, NULL, &err, sourceFile, destinationFile, fileOperationHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -4209,7 +4429,8 @@ MmsConnection_obtainFileAsync(MmsConnection self, uint32_t* usedInvokeId, MmsErr { #if (MMS_FILE_SERVICE == 1) - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4278,7 +4499,8 @@ MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError, MmsConnection_writeVariableAsync(self, NULL, &err, domainId, itemId, value, writeVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -4297,7 +4519,8 @@ MmsConnection_writeVariableAsync(MmsConnection self, uint32_t* usedInvokeId, Mms const char* domainId, const char* itemId, MmsValue* value, MmsConnection_WriteVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4341,7 +4564,8 @@ MmsConnection_writeSingleArrayElementWithComponent(MmsConnection self, MmsError* MmsConnection_writeSingleArrayElementWithComponentAsync(self, NULL, &err, domainId, itemId, arrayIndex, componentId, value, writeVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -4361,7 +4585,8 @@ MmsConnection_writeSingleArrayElementWithComponentAsync(MmsConnection self, uint uint32_t arrayIndex, const char* componentId, MmsValue* value, MmsConnection_WriteVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4406,7 +4631,8 @@ MmsConnection_writeVariableComponent(MmsConnection self, MmsError* mmsError, MmsConnection_writeVariableComponentAsync(self, NULL, &err, domainId, itemId, componentId, value, writeVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -4425,7 +4651,8 @@ MmsConnection_writeVariableComponentAsync(MmsConnection self, uint32_t* usedInvo const char* domainId, const char* itemId, const char* componentId, MmsValue* value, MmsConnection_WriteVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4491,8 +4718,8 @@ MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, con MmsConnection_writeMultipleVariablesAsync(self, NULL, &err, domainId, items, values, writeMultipleVariablesHandler, ¶meter); - if (err == MMS_ERROR_NONE) { - + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); err = parameter.err; @@ -4518,7 +4745,8 @@ MmsConnection_writeMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvo LinkedList /**/ items, LinkedList /* */ values, MmsConnection_WriteMultipleVariablesHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4531,7 +4759,8 @@ MmsConnection_writeMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvo if (usedInvokeId) *usedInvokeId = invokeId; - if (mmsClient_createWriteMultipleItemsRequest(invokeId, domainId, items, values, payload) != -1) { + if (mmsClient_createWriteMultipleItemsRequest(invokeId, domainId, items, values, payload) != -1) + { MmsClientInternalParameter intParam; intParam.ptr = NULL; @@ -4540,7 +4769,8 @@ MmsConnection_writeMultipleVariablesAsync(MmsConnection self, uint32_t* usedInvo if (mmsError) *mmsError = err; } - else { + else + { *mmsError = MMS_ERROR_RESOURCE_OTHER; } @@ -4566,7 +4796,8 @@ MmsConnection_writeArrayElements(MmsConnection self, MmsError* mmsError, MmsConnection_writeArrayElementsAsync(self, NULL, &err, domainId, itemId, index, numberOfElements, value, writeVariableHandler, ¶meter); - if (err == MMS_ERROR_NONE) { + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.waitForResponse); err = parameter.err; @@ -4586,7 +4817,8 @@ MmsConnection_writeArrayElementsAsync(MmsConnection self, uint32_t* usedInvokeId MmsValue* value, MmsConnection_WriteVariableHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4630,8 +4862,8 @@ MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, boo MmsConnection_writeNamedVariableListAsync(self, NULL, &err, isAssociationSpecific, domainId, itemId, values, writeMultipleVariablesHandler, ¶meter); - if (err == MMS_ERROR_NONE) { - + if (err == MMS_ERROR_NONE) + { Semaphore_wait(parameter.sem); err = parameter.err; @@ -4641,7 +4873,8 @@ MmsConnection_writeNamedVariableList(MmsConnection self, MmsError* mmsError, boo else LinkedList_destroyDeep(parameter.result, (LinkedListValueDeleteFunction) MmsValue_delete); } - else { + else + { if (accessResults) *accessResults = NULL; } @@ -4657,7 +4890,8 @@ MmsConnection_writeNamedVariableListAsync(MmsConnection self, uint32_t* usedInvo const char* domainId, const char* itemId, LinkedList /* */values, MmsConnection_WriteMultipleVariablesHandler handler, void* parameter) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4687,7 +4921,8 @@ exit_function: void MmsConnection_sendRawData(MmsConnection self, MmsError* mmsError, uint8_t* buffer, int bufSize) { - if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) + { if (mmsError) *mmsError = MMS_ERROR_CONNECTION_LOST; goto exit_function; @@ -4709,16 +4944,19 @@ exit_function: void MmsServerIdentity_destroy(MmsServerIdentity* self) { - if (self->modelName != NULL) - GLOBAL_FREEMEM(self->modelName); + if (self) + { + if (self->modelName != NULL) + GLOBAL_FREEMEM(self->modelName); - if (self->vendorName != NULL) - GLOBAL_FREEMEM(self->vendorName); + if (self->vendorName != NULL) + GLOBAL_FREEMEM(self->vendorName); - if (self->revision != NULL) - GLOBAL_FREEMEM(self->revision); + if (self->revision != NULL) + GLOBAL_FREEMEM(self->revision); - GLOBAL_FREEMEM(self); + GLOBAL_FREEMEM(self); + } } MmsVariableAccessSpecification* @@ -4727,10 +4965,13 @@ MmsVariableAccessSpecification_create(char* domainId, char* itemId) MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*) GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification)); - self->domainId = domainId; - self->itemId = itemId; - self->arrayIndex = -1; - self->componentName = NULL; + if (self) + { + self->domainId = domainId; + self->itemId = itemId; + self->arrayIndex = -1; + self->componentName = NULL; + } return self; } @@ -4742,10 +4983,13 @@ MmsVariableAccessSpecification_createAlternateAccess(char* domainId, char* itemI MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*) GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification)); - self->domainId = domainId; - self->itemId = itemId; - self->arrayIndex = index; - self->componentName = componentName; + if (self) + { + self->domainId = domainId; + self->itemId = itemId; + self->arrayIndex = index; + self->componentName = componentName; + } return self; } @@ -4753,14 +4997,17 @@ MmsVariableAccessSpecification_createAlternateAccess(char* domainId, char* itemI void MmsVariableAccessSpecification_destroy(MmsVariableAccessSpecification* self) { - if (self->domainId != NULL) - GLOBAL_FREEMEM((void*) self->domainId); + if (self) + { + if (self->domainId != NULL) + GLOBAL_FREEMEM((void*) self->domainId); - if (self->itemId != NULL) - GLOBAL_FREEMEM((void*) self->itemId); + if (self->itemId != NULL) + GLOBAL_FREEMEM((void*) self->itemId); - if (self->componentName != NULL) - GLOBAL_FREEMEM((void*) self->componentName); + if (self->componentName != NULL) + GLOBAL_FREEMEM((void*) self->componentName); - GLOBAL_FREEMEM(self); + GLOBAL_FREEMEM(self); + } } diff --git a/src/mms/iso_mms/client/mms_client_files.c b/src/mms/iso_mms/client/mms_client_files.c index 4fca418e..5ea8fb01 100644 --- a/src/mms/iso_mms/client/mms_client_files.c +++ b/src/mms/iso_mms/client/mms_client_files.c @@ -180,7 +180,6 @@ exit_reject_invalid_pdu: mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); } - void mmsClient_handleFileReadRequest( MmsConnection connection, @@ -191,7 +190,7 @@ mmsClient_handleFileReadRequest( int32_t frsmId = BerDecoder_decodeInt32(buffer, maxBufPos - bufPos, bufPos); if (DEBUG_MMS_CLIENT) - printf("MMS_CLIENT: mmsClient_handleFileReadRequest read request for frsmId: %i\n", frsmId); + printf("MMS_CLIENT: mmsClient_handleFileReadRequest read request for frsmId: %i\n", (int)frsmId); MmsFileReadStateMachine* frsm = getFrsm(connection, frsmId); @@ -401,7 +400,6 @@ mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, con request->size = bufPos; } - void mmsClient_createFileRenameRequest(uint32_t invokeId, ByteBuffer* request, const char* currentFileName, const char* newFileName) { @@ -466,7 +464,6 @@ mmsClient_createObtainFileRequest(uint32_t invokeId, ByteBuffer* request, const request->size = bufPos; } - static bool parseFileAttributes(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* fileSize, uint64_t* lastModified) { @@ -610,7 +607,6 @@ parseListOfDirectoryEntries(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t return true; } - bool mmsClient_parseFileDirectoryResponse(ByteBuffer* response, int bufPos, uint32_t invokeId, MmsConnection_FileDirectoryHandler handler, void* parameter) { @@ -731,16 +727,14 @@ mmsMsg_parseFileOpenResponse(uint8_t* buffer, int bufPos, int maxBufPos, int32_t } bool -mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t invokeId, int frsmId, bool* moreFollows, MmsConnection_FileReadHandler handler, void* handlerParameter) +mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t invokeId, int32_t frsmId, bool* moreFollows, MmsConnection_FileReadHandler handler, void* handlerParameter) { int length; uint8_t* data = NULL; int dataLen = 0; - uint8_t tag = buffer[bufPos++]; - if (tag != 0xbf) { if (DEBUG_MMS_CLIENT) printf("MMS_CLIENT/SERVER: mmsClient_parseFileReadResponse: unknown tag %02x\n", tag); diff --git a/src/mms/iso_mms/client/mms_client_initiate.c b/src/mms/iso_mms/client/mms_client_initiate.c index fdd9b94e..8eb930de 100644 --- a/src/mms/iso_mms/client/mms_client_initiate.c +++ b/src/mms/iso_mms/client/mms_client_initiate.c @@ -39,18 +39,16 @@ static uint8_t servicesSupported[] = { 0xee, 0x1c, 0x00, 0x00, 0x04, 0x08, 0x00, void mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message) { - int maxServerOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; - int maxServerOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; int dataStructureNestingLevel = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL; uint32_t localDetailSize = BerEncoder_UInt32determineEncodedSize(self->parameters.maxPduSize); uint32_t proposedMaxServerOutstandingCallingSize = - BerEncoder_UInt32determineEncodedSize(maxServerOutstandingCalling); + BerEncoder_UInt32determineEncodedSize(self->maxOutstandingCalling); uint32_t proposedMaxServerOutstandingCalledSize = - BerEncoder_UInt32determineEncodedSize(maxServerOutstandingCalled); + BerEncoder_UInt32determineEncodedSize(self->maxOutstandingCalled); uint32_t dataStructureNestingLevelSize = BerEncoder_UInt32determineEncodedSize(dataStructureNestingLevel); @@ -76,11 +74,11 @@ mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message) /* proposedMaxServerOutstandingCalling */ bufPos = BerEncoder_encodeTL(0x81, proposedMaxServerOutstandingCallingSize, buffer, bufPos); - bufPos = BerEncoder_encodeUInt32(maxServerOutstandingCalling, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(self->maxOutstandingCalling, buffer, bufPos); /* proposedMaxServerOutstandingCalled */ bufPos = BerEncoder_encodeTL(0x82, proposedMaxServerOutstandingCalledSize, buffer, bufPos); - bufPos = BerEncoder_encodeUInt32(maxServerOutstandingCalled, buffer, bufPos); + bufPos = BerEncoder_encodeUInt32(self->maxOutstandingCalled, buffer, bufPos); /* proposedDataStructureNestingLevel */ bufPos = BerEncoder_encodeTL(0x83, dataStructureNestingLevelSize, buffer, bufPos); @@ -169,8 +167,8 @@ mmsClient_parseInitiateResponse(MmsConnection self, ByteBuffer* response) { self->parameters.maxPduSize = CONFIG_MMS_MAXIMUM_PDU_SIZE; self->parameters.dataStructureNestingLevel = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL; - self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; - self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + self->parameters.maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + self->parameters.maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING; int bufPos = 1; /* ignore tag - already checked */ @@ -203,16 +201,16 @@ mmsClient_parseInitiateResponse(MmsConnection self, ByteBuffer* response) case 0x81: /* proposed-max-serv-outstanding-calling */ self->parameters.maxServOutstandingCalling = BerDecoder_decodeUint32(buffer, length, bufPos); - if (self->parameters.maxServOutstandingCalling > DEFAULT_MAX_SERV_OUTSTANDING_CALLING) - self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + if (self->parameters.maxServOutstandingCalling > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING) + self->parameters.maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING; break; case 0x82: /* proposed-max-serv-outstanding-called */ self->parameters.maxServOutstandingCalled = BerDecoder_decodeUint32(buffer, length, bufPos); - if (self->parameters.maxServOutstandingCalled > DEFAULT_MAX_SERV_OUTSTANDING_CALLED) - self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + if (self->parameters.maxServOutstandingCalled > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED) + self->parameters.maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED; break; case 0x83: /* proposed-data-structure-nesting-level */ diff --git a/src/mms/iso_mms/common/mms_type_spec.c b/src/mms/iso_mms/common/mms_type_spec.c index f83b804e..c1db5d89 100644 --- a/src/mms/iso_mms/common/mms_type_spec.c +++ b/src/mms/iso_mms/common/mms_type_spec.c @@ -1,7 +1,7 @@ /* * mms_type_spec.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -108,36 +108,40 @@ MmsVariableSpecification_getType(MmsVariableSpecification* self) bool MmsVariableSpecification_isValueOfType(MmsVariableSpecification* self, const MmsValue* value) { - if ((self->type) == (value->type)) { - - if ((self->type == MMS_STRUCTURE) || (self->type == MMS_ARRAY)) { - + if ((self->type) == (value->type)) + { + if ((self->type == MMS_STRUCTURE) || (self->type == MMS_ARRAY)) + { int componentCount = self->typeSpec.structure.elementCount; if (componentCount != (int) MmsValue_getArraySize(value)) return false; - if (self->type == MMS_STRUCTURE) { - + if (self->type == MMS_STRUCTURE) + { int i; - for (i = 0; i < componentCount; i++) { - + for (i = 0; i < componentCount; i++) + { if (MmsVariableSpecification_isValueOfType(self->typeSpec.structure.elements[i], MmsValue_getElement(value, i)) == false) return false; } return true; } - else { + else + { int i; - for (i = 0; i < componentCount; i++) { - + for (i = 0; i < componentCount; i++) + { if (MmsVariableSpecification_isValueOfType(self->typeSpec.array.elementTypeSpec, MmsValue_getElement(value, i)) == false) return false; } + + return true; } } - else if (self->type == MMS_BIT_STRING) { + else if (self->type == MMS_BIT_STRING) + { if (self->typeSpec.bitString == value->value.bitString.size) return true; diff --git a/src/mms/iso_mms/common/mms_value.c b/src/mms/iso_mms/common/mms_value.c index 549619a8..f88e232b 100644 --- a/src/mms/iso_mms/common/mms_value.c +++ b/src/mms/iso_mms/common/mms_value.c @@ -1463,13 +1463,15 @@ MmsValue_newOctetString(int size, int maxSize) { MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue)); - if (self) { + if (self) + { self->type = MMS_OCTET_STRING; self->value.octetString.size = size; self->value.octetString.maxSize = maxSize; self->value.octetString.buf = (uint8_t*) GLOBAL_CALLOC(1, abs(maxSize)); - if (self->value.octetString.buf == NULL) { + if ((maxSize != 0) && (self->value.octetString.buf == NULL)) + { GLOBAL_FREEMEM(self); self = NULL; } @@ -1677,14 +1679,16 @@ exit_function: } static void -setVisibleStringValue(MmsValue* self, const char* string) +setVisibleStringValue(MmsValue* self, const char* value) { - if (self->value.visibleString.buf != NULL) { - if (string != NULL) { - - int newStringSize = strlen(string); + if (self->value.visibleString.buf != NULL) + { + if (value != NULL) + { + int newStringSize = strlen(value); - if (newStringSize > self->value.visibleString.size) { + if (newStringSize > self->value.visibleString.size) + { GLOBAL_FREEMEM(self->value.visibleString.buf); self->value.visibleString.buf = (char*) GLOBAL_MALLOC(newStringSize + 1); @@ -1694,7 +1698,7 @@ setVisibleStringValue(MmsValue* self, const char* string) self->value.visibleString.size = newStringSize; } - StringUtils_copyStringMax(self->value.visibleString.buf, self->value.visibleString.size + 1, string); + StringUtils_copyStringMax(self->value.visibleString.buf, self->value.visibleString.size + 1, value); } else self->value.visibleString.buf[0] = 0; @@ -1906,7 +1910,8 @@ MmsValue_newStringFromByteArray(const uint8_t* byteArray, int size, MmsType type self->value.visibleString.buf = StringUtils_createStringFromBuffer(byteArray, size); - if (self->value.visibleString.buf == NULL) { + if (self->value.visibleString.buf == NULL) + { GLOBAL_FREEMEM(self); self = NULL; } @@ -2008,17 +2013,20 @@ MmsValue_createArray(const MmsVariableSpecification* elementType, int size) self->value.structure.size = size; self->value.structure.components = (MmsValue**) GLOBAL_CALLOC(size, sizeof(MmsValue*)); - if (self->value.structure.components == NULL) { + if (self->value.structure.components == NULL) + { GLOBAL_FREEMEM(self); self = NULL; goto exit_function; } int i; - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) + { self->value.structure.components[i] = MmsValue_newDefaultValue(elementType); - if (self->value.structure.components[i] == NULL) { + if (self->value.structure.components[i] == NULL) + { MmsValue_delete(self); self = NULL; goto exit_function; @@ -2102,9 +2110,10 @@ MmsValue_setDeletable(MmsValue* self) void MmsValue_setDeletableRecursive(MmsValue* self) { - if (self != NULL) { - - if ((MmsValue_getType(self) == MMS_ARRAY) || (MmsValue_getType(self) == MMS_STRUCTURE)) { + if (self) + { + if ((MmsValue_getType(self) == MMS_ARRAY) || (MmsValue_getType(self) == MMS_STRUCTURE)) + { int i; int elementCount = MmsValue_getArraySize(self); @@ -2179,7 +2188,8 @@ MmsValue_getTypeString(MmsValue* self) const char* MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) { - if (self == NULL) { + if (self == NULL) + { StringUtils_copyStringMax(buffer, bufferSize, "(null)"); return buffer; @@ -2240,7 +2250,8 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) int size = MmsValue_getBitStringSize(self); /* fill buffer with zeros */ - if (size + 1 > bufferSize) { + if (size + 1 > bufferSize) + { memset(buffer, 0, bufferSize); size = bufferSize - 1; @@ -2250,7 +2261,8 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) } int i; - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) + { if (MmsValue_getBitStringBit(self, i)) buffer[bufPos++] = '1'; else @@ -2290,7 +2302,8 @@ MmsValue_printToBuffer(const MmsValue* self, char* buffer, int bufferSize) int size = MmsValue_getOctetStringSize(self); int bufPos = 0; int i; - for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) + { snprintf(buffer + bufPos, bufferSize - bufPos, "%02x", self->value.octetString.buf[i]); bufPos += 2; diff --git a/src/mms/iso_mms/server/mms_access_result.c b/src/mms/iso_mms/server/mms_access_result.c index b17461f0..95dcef8a 100644 --- a/src/mms/iso_mms/server/mms_access_result.c +++ b/src/mms/iso_mms/server/mms_access_result.c @@ -171,9 +171,12 @@ MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBu if (bufPos < 0) goto exit_with_error; - /* if not indefinite length end tag, data length must be > 0 */ - if ((tag != 0) && (dataLength == 0)) - goto exit_with_error; + /* if not indefinite length end tag, visible-string, mms-string, or octet-string, data length must be > 0 */ + if (tag != 0) + { + if (tag != 0x8a && tag != 0x90 && tag != 0x89 && dataLength == 0) + goto exit_with_error; + } switch (tag) { @@ -192,8 +195,8 @@ MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBu int i; - for (i = 0; i < elementCount; i++) { - + for (i = 0; i < elementCount; i++) + { int elementLength; int newBufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos + 1, dataEndBufPos); @@ -304,7 +307,8 @@ MmsValue_decodeMmsData(uint8_t* buffer, int bufPos, int bufferLength, int* endBu break; case 0x91: /* MMS_UTC_TIME */ - if (dataLength == 8) { + if (dataLength == 8) + { value = MmsValue_newUtcTime(0); MmsValue_setUtcTimeByBuffer(value, buffer + bufPos); bufPos += dataLength; diff --git a/src/mms/iso_mms/server/mms_association_service.c b/src/mms/iso_mms/server/mms_association_service.c index 83a32f3e..667f365d 100644 --- a/src/mms/iso_mms/server/mms_association_service.c +++ b/src/mms/iso_mms/server/mms_association_service.c @@ -330,9 +330,9 @@ parseInitiateRequestPdu(MmsServerConnection self, uint8_t* buffer, int bufPos, i self->dataStructureNestingLevel = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL; - self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + self->maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED; - self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + self->maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING; self->negotiatedParameterCBC[0] = 0; self->negotiatedParameterCBC[1] = 0; @@ -367,16 +367,16 @@ parseInitiateRequestPdu(MmsServerConnection self, uint8_t* buffer, int bufPos, i case 0x81: /* proposed-max-serv-outstanding-calling */ self->maxServOutstandingCalling = BerDecoder_decodeUint32(buffer, length, bufPos); - if (self->maxServOutstandingCalling > DEFAULT_MAX_SERV_OUTSTANDING_CALLING) - self->maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; + if (self->maxServOutstandingCalling > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING) + self->maxServOutstandingCalling = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLING; break; case 0x82: /* proposed-max-serv-outstanding-called */ self->maxServOutstandingCalled = BerDecoder_decodeUint32(buffer, length, bufPos); - if (self->maxServOutstandingCalled > DEFAULT_MAX_SERV_OUTSTANDING_CALLED) - self->maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; + if (self->maxServOutstandingCalled > CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED) + self->maxServOutstandingCalled = CONFIG_DEFAULT_MAX_SERV_OUTSTANDING_CALLED; break; case 0x83: /* proposed-data-structure-nesting-level */ diff --git a/src/mms/iso_mms/server/mms_get_var_access_service.c b/src/mms/iso_mms/server/mms_get_var_access_service.c index c27ff76b..4adb6f4c 100644 --- a/src/mms/iso_mms/server/mms_get_var_access_service.c +++ b/src/mms/iso_mms/server/mms_get_var_access_service.c @@ -1,7 +1,7 @@ /* * mms_get_var_access_service.c * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -310,9 +310,12 @@ mmsServer_handleGetVariableAccessAttributesRequest( rval = ber_decode(NULL, &asn_DEF_GetVariableAccessAttributesRequest, (void**) &request, buffer + bufPos, maxBufPos - bufPos); - if (rval.code == RC_OK) { - if (request->present == GetVariableAccessAttributesRequest_PR_name) { - if (request->choice.name.present == ObjectName_PR_domainspecific) { + if (rval.code == RC_OK) + { + if (request->present == GetVariableAccessAttributesRequest_PR_name) + { + if (request->choice.name.present == ObjectName_PR_domainspecific) + { Identifier_t domainId = request->choice.name.choice.domainspecific.domainId; Identifier_t nameId = request->choice.name.choice.domainspecific.itemId; @@ -328,7 +331,8 @@ mmsServer_handleGetVariableAccessAttributesRequest( GLOBAL_FREEMEM(nameIdStr); } #if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) - else if (request->choice.name.present == ObjectName_PR_vmdspecific) { + else if (request->choice.name.present == ObjectName_PR_vmdspecific) + { Identifier_t nameId = request->choice.name.choice.vmdspecific; char* nameIdStr = StringUtils_createStringFromBuffer(nameId.buf, nameId.size); @@ -357,6 +361,12 @@ mmsServer_handleGetVariableAccessAttributesRequest( asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetVariableAccessAttributesRequest, request, 0); + if (ByteBuffer_getSize(response) > connection->maxPduSize) + { + ByteBuffer_setSize(response, 0); + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + } + return retVal; } diff --git a/src/mms/iso_mms/server/mms_named_variable_list_service.c b/src/mms/iso_mms/server/mms_named_variable_list_service.c index 85f1b960..a38cfd7f 100644 --- a/src/mms/iso_mms/server/mms_named_variable_list_service.c +++ b/src/mms/iso_mms/server/mms_named_variable_list_service.c @@ -130,16 +130,22 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection, goto exit_function; } - if ((mmsPdu->present == MmsPdu_PR_confirmedRequestPdu) && - (mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present - == ConfirmedServiceRequest_PR_deleteNamedVariableList)) - { - request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); - } - else { - mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); - goto exit_function; - } + if ((mmsPdu->present == MmsPdu_PR_confirmedRequestPdu) && + (mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present + == ConfirmedServiceRequest_PR_deleteNamedVariableList)) + { + request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList); + } + else { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_function; + } + + if (request->listOfVariableListName == NULL) + { + mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response); + goto exit_function; + } long scopeOfDelete = DeleteNamedVariableListRequest__scopeOfDelete_specific; @@ -675,7 +681,8 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response, LinkedList variable = LinkedList_getNext(variables); int i; - for (i = 0; i < variableCount; i++) { + for (i = 0; i < variableCount; i++) + { MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data; varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*) @@ -740,8 +747,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest( goto exit_function; } - if (request->present == ObjectName_PR_domainspecific) { - + if (request->present == ObjectName_PR_domainspecific) + { char domainName[65]; char itemName[65]; @@ -761,11 +768,12 @@ mmsServer_handleGetNamedVariableListAttributesRequest( MmsDomain* domain = MmsDevice_getDomain(mmsDevice, domainName); - if (domain != NULL) { + if (domain != NULL) + { MmsNamedVariableList varList = MmsDomain_getNamedVariableList(domain, itemName); - if (varList) { - + if (varList) + { MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_GET_DIRECTORY, MMS_DOMAIN_SPECIFIC, domain, varList->name, connection); if (accessError == MMS_ERROR_NONE) { @@ -792,8 +800,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest( } #if (MMS_DYNAMIC_DATA_SETS == 1) - else if (request->present == ObjectName_PR_aaspecific) { - + else if (request->present == ObjectName_PR_aaspecific) + { char listName[65]; if (request->choice.aaspecific.size > 64) { @@ -806,11 +814,12 @@ mmsServer_handleGetNamedVariableListAttributesRequest( MmsNamedVariableList varList = MmsServerConnection_getNamedVariableList(connection, listName); - if (varList) { - + if (varList) + { MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_GET_DIRECTORY, MMS_ASSOCIATION_SPECIFIC, NULL, varList->name, connection); - if (accessError == MMS_ERROR_NONE) { + if (accessError == MMS_ERROR_NONE) + { if (createGetNamedVariableListAttributesResponse(invokeId, response, varList) == false) { /* encoding failed - probably because buffer size is too small for message */ @@ -829,7 +838,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest( mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); } #endif /* (MMS_DYNAMIC_DATA_SETS == 1) */ - else if (request->present == ObjectName_PR_vmdspecific) { + else if (request->present == ObjectName_PR_vmdspecific) + { char listName[65]; if (request->choice.vmdspecific.size > 64) { @@ -844,11 +854,12 @@ mmsServer_handleGetNamedVariableListAttributesRequest( MmsNamedVariableList varList = mmsServer_getNamedVariableListWithName(mmsDevice->namedVariableLists, listName); - if (varList) { - + if (varList) + { MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_GET_DIRECTORY, MMS_VMD_SPECIFIC, NULL, varList->name, connection); - if (accessError == MMS_ERROR_NONE) { + if (accessError == MMS_ERROR_NONE) + { if (createGetNamedVariableListAttributesResponse(invokeId, response, varList) == false) { /* encoding failed - probably because buffer size is too small for message */ @@ -870,6 +881,12 @@ mmsServer_handleGetNamedVariableListAttributesRequest( mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); } + if (ByteBuffer_getSize(response) > connection->maxPduSize) + { + ByteBuffer_setSize(response, 0); + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + } + exit_function: asn_DEF_GetVariableAccessAttributesRequest.free_struct(&asn_DEF_GetNamedVariableListAttributesRequest, diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 2b33dc41..043e03ce 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -1,7 +1,7 @@ /* * mms_read_service.c * - * Copyright 2013-2023 Michael Zillgith + * Copyright 2013-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -202,30 +202,35 @@ alternateArrayAccess(MmsServerConnection connection, MmsValue* arrayValue = mmsServer_getValue(connection->server, domain, itemId, connection, false); - if (arrayValue != NULL) { - + if (arrayValue != NULL) + { MmsValue* value = NULL; if (numberOfElements == 0) - if (mmsServer_isAccessToArrayComponent(alternateAccess)) { + { + if (mmsServer_isAccessToArrayComponent(alternateAccess)) + { if (namedVariable->typeSpec.array.elementTypeSpec->type == MMS_STRUCTURE) { MmsValue* structValue = MmsValue_getElement(arrayValue, index); if (structValue != NULL) value = mmsServer_getComponentOfArrayElement(alternateAccess, - namedVariable, structValue); + namedVariable, structValue, NULL); } } else { value = MmsValue_getElement(arrayValue, index); } - else { + } + else + { value = MmsValue_createEmptyArray(numberOfElements); MmsValue_setDeletable(value); int resultIndex = 0; - while (index < lowIndex + numberOfElements) { + while (index < lowIndex + numberOfElements) + { MmsValue* elementValue = NULL; elementValue = MmsValue_getElement(arrayValue, index); @@ -352,7 +357,8 @@ encodeVariableAccessSpecification(VarAccessSpec* accessSpec, uint8_t* buffer, in varAccessSpecSize += itemIdLen + BerEncoder_determineLengthSize(itemIdLen) + 1; - if (accessSpec->domainId != NULL) { + if (accessSpec->domainId != NULL) + { uint32_t domainIdLen = strlen(accessSpec->domainId); varAccessSpecSize += domainIdLen + BerEncoder_determineLengthSize(domainIdLen) + 1; @@ -370,7 +376,8 @@ encodeVariableAccessSpecification(VarAccessSpec* accessSpec, uint8_t* buffer, in varAccessSpecSize += 1 + BerEncoder_determineLengthSize(varAccessSpecLength); - if (encode == false) { + if (encode == false) + { bufPos = varAccessSpecSize; goto exit_function; } @@ -378,8 +385,8 @@ encodeVariableAccessSpecification(VarAccessSpec* accessSpec, uint8_t* buffer, in /* encode to buffer */ bufPos = BerEncoder_encodeTL(0xa0, varAccessSpecLength, buffer, bufPos); - if (accessSpec->isNamedVariableList == true) { - + if (accessSpec->isNamedVariableList == true) + { bufPos = BerEncoder_encodeTL(0xa1, variableListNameLength, buffer, bufPos); if (accessSpec->specific == 0) { /* vmd-specific */ @@ -425,8 +432,8 @@ encodeReadResponse(MmsServerConnection connection, /* iterate values list to determine encoded size */ LinkedList value = LinkedList_getNext(values); - for (i = 0; i < variableCount; i++) { - + for (i = 0; i < variableCount; i++) + { MmsValue* data = (MmsValue*) value->data; accessResultSize += MmsValue_encodeMmsData(data, NULL, 0, false); @@ -452,12 +459,13 @@ encodeReadResponse(MmsServerConnection connection, confirmedResponseContentSize; /* Check if message would fit in the MMS PDU */ - if (mmsPduSize > connection->maxPduSize) { + if (mmsPduSize > connection->maxPduSize) + { if (DEBUG_MMS_SERVER) printf("MMS read: message to large! send error PDU!\n"); mmsMsg_createServiceErrorPdu(invokeId, response, - MMS_ERROR_SERVICE_OTHER); + MMS_ERROR_RESOURCE_OTHER); goto exit_function; } @@ -487,7 +495,8 @@ encodeReadResponse(MmsServerConnection connection, /* encode access results */ value = LinkedList_getNext(values); - for (i = 0; i < variableCount; i++) { + for (i = 0; i < variableCount; i++) + { MmsValue* data = (MmsValue*) value->data; bufPos = MmsValue_encodeMmsData(data, buffer, bufPos, true); @@ -529,16 +538,18 @@ handleReadListOfVariablesRequest( int i; - for (i = 0; i < variableCount; i++) { + for (i = 0; i < variableCount; i++) + { VariableSpecification_t varSpec = read->variableAccessSpecification.choice.listOfVariable.list.array[i]->variableSpecification; AlternateAccess_t* alternateAccess = read->variableAccessSpecification.choice.listOfVariable.list.array[i]->alternateAccess; - if (varSpec.present == VariableSpecification_PR_name) { - - if (varSpec.choice.name.present == ObjectName_PR_domainspecific) { + if (varSpec.present == VariableSpecification_PR_name) + { + if (varSpec.choice.name.present == ObjectName_PR_domainspecific) + { char domainIdStr[65]; char nameIdStr[65]; @@ -571,7 +582,8 @@ handleReadListOfVariablesRequest( } #if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) - else if (varSpec.choice.name.present == ObjectName_PR_vmdspecific) { + else if (varSpec.choice.name.present == ObjectName_PR_vmdspecific) + { char nameIdStr[65]; mmsMsg_copyAsn1IdentifierToStringBuffer(varSpec.choice.name.choice.vmdspecific, nameIdStr, 65); @@ -607,11 +619,12 @@ handleReadListOfVariablesRequest( LinkedList valueElement = LinkedList_getNext(values); - while (valueElement) { - + while (valueElement) + { MmsValue* value = (MmsValue*) LinkedList_getData(valueElement); - if (value) { + if (value) + { if (MmsValue_getType(value) == MMS_DATA_ACCESS_ERROR) { if (MmsValue_getDataAccessError(value) == DATA_ACCESS_ERROR_NO_RESPONSE) { sendResponse = false; @@ -637,21 +650,24 @@ static void addNamedVariableToNamedVariableListResultList(MmsVariableSpecification* namedVariable, MmsDomain* domain, char* nameIdStr, LinkedList /**/ values, MmsServerConnection connection, MmsNamedVariableListEntry listEntry) { - if (namedVariable != NULL) { - + if (namedVariable != NULL) + { if (DEBUG_MMS_SERVER) printf("MMS read: found named variable %s with search string %s\n", namedVariable->name, nameIdStr); MmsValue* value = mmsServer_getValue(connection->server, domain, nameIdStr, connection, false); - if (value) { - if (listEntry->arrayIndex != -1) { - if (MmsValue_getType(value) == MMS_ARRAY) { - + if (value) + { + if (listEntry->arrayIndex != -1) + { + if (MmsValue_getType(value) == MMS_ARRAY) + { MmsValue* elementValue = MmsValue_getElement(value, listEntry->arrayIndex); - if (listEntry->componentName) { + if (listEntry->componentName) + { MmsVariableSpecification* elementType = namedVariable->typeSpec.array.elementTypeSpec; MmsValue* subElementValue = MmsVariableSpecification_getChildValue(elementType, elementValue, listEntry->componentName); @@ -669,7 +685,8 @@ addNamedVariableToNamedVariableListResultList(MmsVariableSpecification* namedVar } } - else { + else + { if (DEBUG_MMS_SERVER) printf("MMS_SERVER: data set entry of unexpected type!\n"); @@ -697,8 +714,8 @@ createNamedVariableListResponse(MmsServerConnection connection, MmsNamedVariable LinkedList variable = LinkedList_getNext(variables); - while (variable) { - + while (variable) + { MmsNamedVariableListEntry variableListEntry = (MmsNamedVariableListEntry) variable->data; MmsDomain* variableDomain = MmsNamedVariableListEntry_getDomain(variableListEntry); @@ -757,11 +774,13 @@ handleReadNamedVariableListRequest( MmsDomain* domain = MmsDevice_getDomain(MmsServer_getDevice(connection->server), domainIdStr); - if (domain == NULL) { + if (domain == NULL) + { if (DEBUG_MMS_SERVER) printf("MMS read: domain %s not found!\n", domainIdStr); mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); } - else { + else + { MmsNamedVariableList namedList = MmsDomain_getNamedVariableList(domain, nameIdStr); if (namedList) @@ -796,12 +815,15 @@ handleReadNamedVariableListRequest( MmsNamedVariableList namedList = mmsServer_getNamedVariableListWithName(connection->server->device->namedVariableLists, listName); if (namedList == NULL) + { mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - else { - + } + else + { MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_READ, MMS_VMD_SPECIFIC, NULL, namedList->name, connection); - if (accessError == MMS_ERROR_NONE) { + if (accessError == MMS_ERROR_NONE) + { VarAccessSpec accessSpec; accessSpec.isNamedVariableList = true; @@ -816,7 +838,6 @@ handleReadNamedVariableListRequest( mmsMsg_createServiceErrorPdu(invokeId, response, accessError); } - } } #if (MMS_DYNAMIC_DATA_SETS == 1) @@ -831,13 +852,15 @@ handleReadNamedVariableListRequest( MmsNamedVariableList namedList = MmsServerConnection_getNamedVariableList(connection, listName); if (namedList == NULL) + { mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT); - else { - + } + else + { MmsError accessError = mmsServer_callVariableListChangedHandler(MMS_VARLIST_READ, MMS_ASSOCIATION_SPECIFIC, NULL, namedList->name, connection); - if (accessError == MMS_ERROR_NONE) { - + if (accessError == MMS_ERROR_NONE) + { VarAccessSpec accessSpec; accessSpec.isNamedVariableList = true; @@ -891,7 +914,8 @@ mmsServer_handleReadRequest( goto exit_function; } - if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) { + if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) + { MmsServer_lockModel(connection->server); handleReadListOfVariablesRequest(connection, request, invokeId, response); @@ -899,7 +923,8 @@ mmsServer_handleReadRequest( MmsServer_unlockModel(connection->server); } #if (MMS_DATA_SET_SERVICE == 1) - else if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_variableListName) { + else if (request->variableAccessSpecification.present == VariableAccessSpecification_PR_variableListName) + { MmsServer_lockModel(connection->server); handleReadNamedVariableListRequest(connection, request, invokeId, response); @@ -911,6 +936,12 @@ mmsServer_handleReadRequest( mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED); } + if (ByteBuffer_getSize(response) > connection->maxPduSize) + { + ByteBuffer_setSize(response, 0); + mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER); + } + exit_function: asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); } diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 18b95464..2f6f2b27 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -536,9 +536,10 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va { MmsDataAccessError indication; - if (self->writeHandler != NULL) { + if (self->writeHandler) + { indication = self->writeHandler(self->writeHandlerParameter, domain, - itemId, value, connection); + itemId, -1, NULL, value, connection); } else { MmsValue* cachedValue; @@ -548,7 +549,36 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va cachedValue = MmsServer_getValueFromCache(self, domain, itemId); - if (cachedValue != NULL) { + if (cachedValue) { + MmsValue_update(cachedValue, value); + indication = DATA_ACCESS_ERROR_SUCCESS; + } else + indication = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } + + return indication; +} + +MmsDataAccessError +mmsServer_setValueEx(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* value, + MmsServerConnection connection, int arrayIdx, const char* componentId) +{ + MmsDataAccessError indication; + + if (self->writeHandler) + { + indication = self->writeHandler(self->writeHandlerParameter, domain, + itemId, arrayIdx, componentId, value, connection); + } + else { + MmsValue* cachedValue = NULL; + + if (domain == NULL) + domain = (MmsDomain*) self->device; + + cachedValue = MmsServer_getValueFromCacheEx2(self, domain, itemId, arrayIdx, componentId); + + if (cachedValue) { MmsValue_update(cachedValue, value); indication = DATA_ACCESS_ERROR_SUCCESS; } else @@ -591,8 +621,6 @@ mmsServer_checkReadAccess(MmsServer self, MmsDomain* domain, char* itemId, MmsSe { MmsDataAccessError accessError = DATA_ACCESS_ERROR_SUCCESS; - printf("mmsServer_checkReadAccess(%s/%s)\n", domain->domainName, itemId); - if (self->readAccessHandler) { accessError = self->readAccessHandler(self->readAccessHandlerParameter, (domain == (MmsDomain*) self->device) ? NULL : domain, diff --git a/src/mms/iso_mms/server/mms_server_common.c b/src/mms/iso_mms/server/mms_server_common.c index 455a26ec..545702be 100644 --- a/src/mms/iso_mms/server/mms_server_common.c +++ b/src/mms/iso_mms/server/mms_server_common.c @@ -287,7 +287,7 @@ mmsServer_isAccessToArrayComponent(AlternateAccess_t* alternateAccess) MmsValue* mmsServer_getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable, - MmsValue* structuredValue) + MmsValue* structuredValue, char* componentId) { MmsValue* retValue = NULL; @@ -309,24 +309,43 @@ mmsServer_getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVari goto exit_function; int i; - for (i = 0; i < structSpec->typeSpec.structure.elementCount; i++) { - + for (i = 0; i < structSpec->typeSpec.structure.elementCount; i++) + { if ((int) strlen(structSpec->typeSpec.structure.elements[i]->name) - == component.size) { + == component.size) + { if (strncmp(structSpec->typeSpec.structure.elements[i]->name, - (char*) component.buf, component.size) == 0) { + (char*) component.buf, component.size) == 0) + { MmsValue* value = MmsValue_getElement(structuredValue, i); - if (mmsServer_isAccessToArrayComponent( - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess)) { - retValue = - mmsServer_getComponentOfArrayElement( - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess, - structSpec->typeSpec.structure.elements[i], - value); + if (value) + { + if (mmsServer_isAccessToArrayComponent( + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess)) + { + if (componentId) + { + strcat(componentId, structSpec->typeSpec.structure.elements[i]->name); + strcat(componentId, "$"); + } + + retValue = + mmsServer_getComponentOfArrayElement( + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess, + structSpec->typeSpec.structure.elements[i], + value, componentId); + } + else + { + if (componentId) + { + strcat(componentId, structSpec->typeSpec.structure.elements[i]->name); + } + + retValue = value; + } } - else - retValue = value; goto exit_function; } diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c index 096bc30f..f46ddef6 100644 --- a/src/mms/iso_mms/server/mms_write_service.c +++ b/src/mms/iso_mms/server/mms_write_service.c @@ -517,33 +517,36 @@ getComponent(MmsServerConnection connection, MmsDomain* domain, AlternateAccess_ { MmsVariableSpecification* retValue = NULL; - if (mmsServer_isComponentAccess(alternateAccess)) { + if (mmsServer_isComponentAccess(alternateAccess)) + { Identifier_t component = alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component; if (component.size > 129) goto exit_function; - if (namedVariable->type == MMS_STRUCTURE) { - + if (namedVariable->type == MMS_STRUCTURE) + { int i; - for (i = 0; i < namedVariable->typeSpec.structure.elementCount; i++) { - + for (i = 0; i < namedVariable->typeSpec.structure.elementCount; i++) + { if ((int) strlen(namedVariable->typeSpec.structure.elements[i]->name) - == component.size) { + == component.size) + { if (!strncmp(namedVariable->typeSpec.structure.elements[i]->name, (char*) component.buf, component.size)) { - if (strlen(variableName) + component.size < 199) { - + if (strlen(variableName) + component.size < 199) + { StringUtils_appendString(variableName, 200, "$"); /* here we need strncat because component.buf is not null terminated! */ strncat(variableName, (const char*)component.buf, (size_t)component.size); if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess - != NULL) { + != NULL) + { retValue = getComponent(connection, domain, alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess, @@ -598,12 +601,13 @@ mmsServer_handleWriteRequest( MmsServer_lockModel(connection->server); - if (writeRequest->variableAccessSpecification.present == VariableAccessSpecification_PR_variableListName) { + if (writeRequest->variableAccessSpecification.present == VariableAccessSpecification_PR_variableListName) + { handleWriteNamedVariableListRequest(connection, writeRequest, invokeId, response); goto exit_function; } - else if (writeRequest->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) { - + else if (writeRequest->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable) + { int numberOfWriteItems = writeRequest->variableAccessSpecification.choice.listOfVariable.list.count; if (numberOfWriteItems < 1) { @@ -627,7 +631,8 @@ mmsServer_handleWriteRequest( int i; - for (i = 0; i < numberOfWriteItems; i++) { + for (i = 0; i < numberOfWriteItems; i++) + { ListOfVariableSeq_t* varSpec = writeRequest->variableAccessSpecification.choice.listOfVariable.list.array[i]; @@ -644,7 +649,8 @@ mmsServer_handleWriteRequest( char nameIdStr[65]; - if (varSpec->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) { + if (varSpec->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) + { Identifier_t domainId = varSpec->variableSpecification.choice.name.choice.domainspecific.domainId; char domainIdStr[65]; @@ -687,8 +693,8 @@ mmsServer_handleWriteRequest( AlternateAccess_t* alternateAccess = varSpec->alternateAccess; - if (alternateAccess != NULL) { - + if (alternateAccess) + { if ((variable->type == MMS_STRUCTURE) && (mmsServer_isComponentAccess(alternateAccess) == false)) { accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT; continue; @@ -714,12 +720,13 @@ mmsServer_handleWriteRequest( continue; } - if (alternateAccess != NULL) { - + if (alternateAccess) + { if (domain == NULL) domain = (MmsDomain*) device; - if (mmsServer_isIndexAccess(alternateAccess)) { + if (mmsServer_isIndexAccess(alternateAccess)) + { MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr); if (cachedArray == NULL) { @@ -730,8 +737,8 @@ mmsServer_handleWriteRequest( int index = mmsServer_getLowIndex(alternateAccess); int numberOfElements = mmsServer_getNumberOfElements(alternateAccess); - if (numberOfElements == 0) { /* select single array element with index */ - + if (numberOfElements == 0) /* select single array element with index */ + { MmsValue* elementValue = MmsValue_getElement(cachedArray, index); if (elementValue == NULL) { @@ -739,34 +746,45 @@ mmsServer_handleWriteRequest( goto end_of_main_loop; } - if (mmsServer_isAccessToArrayComponent(alternateAccess)) { + if (mmsServer_isAccessToArrayComponent(alternateAccess)) + { MmsVariableSpecification* namedVariable = MmsDomain_getNamedVariable(domain, nameIdStr); + char componentId[65]; + componentId[0] = 0; + if (namedVariable) { - elementValue = mmsServer_getComponentOfArrayElement(alternateAccess, namedVariable, elementValue); + elementValue = mmsServer_getComponentOfArrayElement(alternateAccess, namedVariable, elementValue, componentId); } if ((namedVariable == NULL) || (elementValue == NULL)) { accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; - goto end_of_main_loop; } - } + else + { + accessResults[i] = mmsServer_setValueEx(connection->server, domain, nameIdStr, value, connection, index, componentId); + } - if (MmsValue_update(elementValue, value) == false) { - accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; + goto end_of_main_loop; + } + else + { + accessResults[i] = mmsServer_setValueEx(connection->server, domain, nameIdStr, value, connection, index, NULL); goto end_of_main_loop; } } - else { /* select sub-array with start-index and number-of-elements */ - - if (MmsValue_getType(value) != MMS_ARRAY) { + else /* select sub-array with start-index and number-of-elements */ + { + if (MmsValue_getType(value) != MMS_ARRAY) + { accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; goto end_of_main_loop; } int elementNo; - for (elementNo = 0; elementNo < numberOfElements; elementNo++) { + for (elementNo = 0; elementNo < numberOfElements; elementNo++) + { MmsValue* newElement = MmsValue_getElement(value, elementNo); MmsValue* elementValue = MmsValue_getElement(cachedArray, index++); @@ -785,36 +803,37 @@ mmsServer_handleWriteRequest( accessResults[i] = DATA_ACCESS_ERROR_SUCCESS; goto end_of_main_loop; } - else if (mmsServer_isComponentAccess(alternateAccess)) { + else if (mmsServer_isComponentAccess(alternateAccess)) + { variable = getComponent(connection, domain, alternateAccess, variable, nameIdStr); - if (variable == NULL) { + if (variable == NULL) + { accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT; goto end_of_main_loop; } } - else { + else + { accessResults[i] = DATA_ACCESS_ERROR_SUCCESS; goto end_of_main_loop; } } /* Check for correct type */ - if (MmsVariableSpecification_isValueOfType(variable, value) == false) { + if (MmsVariableSpecification_isValueOfType(variable, value) == false) + { accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT; goto end_of_main_loop; } - MmsDataAccessError valueIndication = - mmsServer_setValue(connection->server, domain, nameIdStr, value, connection); - - if (valueIndication == DATA_ACCESS_ERROR_NO_RESPONSE) - sendResponse = false; - - accessResults[i] = valueIndication; + accessResults[i] = mmsServer_setValue(connection->server, domain, nameIdStr, value, connection); end_of_main_loop: + if (accessResults[i] == DATA_ACCESS_ERROR_NO_RESPONSE) + sendResponse = false; + MmsValue_delete(value); } diff --git a/tools/model_generator/build2.sh b/tools/model_generator/build2.sh index 8bf31dfb..52bd6f80 100755 --- a/tools/model_generator/build2.sh +++ b/tools/model_generator/build2.sh @@ -4,7 +4,7 @@ mkdir build find src/ -name "*.java" > listFile.tmp -javac -target 1.6 -source 1.6 -d build @listFile.tmp +javac -target 1.8 -source 1.8 -d build @listFile.tmp jar cfm genconfig.jar manifest-dynamic.mf -C build/ com/ diff --git a/tools/model_generator/genconfig.jar b/tools/model_generator/genconfig.jar index 0ef0c1d3..51e83774 100644 Binary files a/tools/model_generator/genconfig.jar and b/tools/model_generator/genconfig.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 2bd18a3d..ccf4d8f0 100644 --- a/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java +++ b/tools/model_generator/src/com/libiec61850/scl/model/DataModelValue.java @@ -188,19 +188,35 @@ public class DataModelValue { case TIMESTAMP: case ENTRY_TIME: - try { + { String modValueString = value.replace(',', '.'); - SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss.SSS"); - parser.setTimeZone(TimeZone.getTimeZone("UTC")); + try { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss.SSS"); + parser.setTimeZone(TimeZone.getTimeZone("UTC")); + + Date date = parser.parse(modValueString); - Date date = parser.parse(modValueString); + this.value = new Long(date.toInstant().toEpochMilli()); + + break; + } + catch (java.text.ParseException e) {}; + + try { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss"); + parser.setTimeZone(TimeZone.getTimeZone("UTC")); + + Date date = parser.parse(modValueString); - this.value = new Long(date.toInstant().toEpochMilli()); - } - catch (java.text.ParseException e) { + this.value = new Long(date.toInstant().toEpochMilli()); + + break; + } + catch (java.text.ParseException e) {}; + this.value = null; - System.out.println("Warning: Val element does not contain a valid time stamp: " + e.getMessage()); + System.out.println("Warning: Val element does not contain a valid time stamp: " + value); } break; diff --git a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java index 2d5bf36e..fffd94ef 100644 --- a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java @@ -3,7 +3,7 @@ package com.libiec61850.tools; /* * DynamicModelGenerator.java * - * Copyright 2014-2020 Michael Zillgith + * Copyright 2014-2024 Michael Zillgith * * This file is part of libIEC61850. * @@ -447,11 +447,7 @@ public class DynamicModelGenerator { output.println("}"); } - private void exportDataObject(PrintStream output, DataObject dataObject, boolean isTransient) { - - if (dataObject.isTransient()) - isTransient = true; - + private void exportDataObjectChild(PrintStream output, DataObject dataObject, boolean isTransient) { for (DataObject subDataObject : dataObject.getSubDataObjects()) { output.print("DO(" + subDataObject.getName() + " " + subDataObject.getCount() + "){\n"); @@ -465,6 +461,105 @@ public class DynamicModelGenerator { } } + private void exportDataObject(PrintStream output, DataObject dataObject, boolean isTransient) { + + if (dataObject.isTransient()) + isTransient = true; + + if (dataObject.getCount() > 0) { + /* data object is an array */ + for (int i = 0; i < dataObject.getCount(); i++) { + output.print("[" + i + "]{\n"); + + exportDataObjectChild(output, dataObject, isTransient); + + output.print("}\n"); + } + } + else { + exportDataObjectChild(output, dataObject, isTransient); + } + + } + + private void printDataAttributeValue(PrintStream output, DataAttribute dataAttribute, boolean isTransient) + { + if (dataAttribute.isBasicAttribute()) { + DataModelValue value = dataAttribute.getValue(); + + /* if no value is given use default value for type if present */ + if (value == null) { + value = dataAttribute.getDefinition().getValue(); + + if (value != null) + if (value.getValue() == null) + value.updateEnumOrdValue(ied.getTypeDeclarations()); + } + + if (value != null) { + + switch (dataAttribute.getType()) { + case ENUMERATED: + case INT8: + case INT16: + case INT32: + case INT64: + output.print("=" + value.getIntValue()); + break; + case INT8U: + case INT16U: + case INT24U: + case INT32U: + output.print("=" + value.getLongValue()); + break; + case BOOLEAN: + { + Boolean boolVal = (Boolean) value.getValue(); + + if (boolVal.booleanValue()) + output.print("=1"); + } + break; + case UNICODE_STRING_255: + output.print("=\"" + value.getValue()+ "\""); + break; + case CURRENCY: + case VISIBLE_STRING_32: + case VISIBLE_STRING_64: + case VISIBLE_STRING_129: + case VISIBLE_STRING_255: + case VISIBLE_STRING_65: + output.print("=\"" + value.getValue()+ "\""); + break; + case FLOAT32: + case FLOAT64: + output.print("=" + value.getValue()); + break; + case TIMESTAMP: + case ENTRY_TIME: + output.print("=" + value.getLongValue()); + break; + + default: + System.out.println("Unknown default value for " + dataAttribute.getName() + " type: " + dataAttribute.getType()); + break; + } + + } + + output.println(";"); + } + else { + output.println("{"); + + for (DataAttribute subDataAttribute : dataAttribute.getSubDataAttributes()) { + exportDataAttribute(output, subDataAttribute, isTransient); + } + + output.println("}"); + } + } + private void exportDataAttribute(PrintStream output, DataAttribute dataAttribute, boolean isTransient) { output.print("DA(" + dataAttribute.getName() + " "); @@ -493,78 +588,22 @@ public class DynamicModelGenerator { else output.print("0"); - output.print(")"); - - if (dataAttribute.isBasicAttribute()) { - DataModelValue value = dataAttribute.getValue(); - - /* if no value is given use default value for type if present */ - if (value == null) { - value = dataAttribute.getDefinition().getValue(); - - if (value != null) - if (value.getValue() == null) - value.updateEnumOrdValue(ied.getTypeDeclarations()); - } - - if (value != null) { - - switch (dataAttribute.getType()) { - case ENUMERATED: - case INT8: - case INT16: - case INT32: - case INT64: - output.print("=" + value.getIntValue()); - break; - case INT8U: - case INT16U: - case INT24U: - case INT32U: - output.print("=" + value.getLongValue()); - break; - case BOOLEAN: - { - Boolean boolVal = (Boolean) value.getValue(); - - if (boolVal.booleanValue()) - output.print("=1"); - } - break; - case UNICODE_STRING_255: - output.print("=\"" + value.getValue()+ "\""); - break; - case CURRENCY: - case VISIBLE_STRING_32: - case VISIBLE_STRING_64: - case VISIBLE_STRING_129: - case VISIBLE_STRING_255: - case VISIBLE_STRING_65: - output.print("=\"" + value.getValue()+ "\""); - break; - case FLOAT32: - case FLOAT64: - output.print("=" + value.getValue()); - break; - default: - System.out.println("Unknown default value for " + dataAttribute.getName() + " type: " + dataAttribute.getType()); - break; - } - - } - - output.println(";"); - } - else { - output.println("{"); + output.print(")"); - for (DataAttribute subDataAttribute : dataAttribute.getSubDataAttributes()) { - exportDataAttribute(output, subDataAttribute, isTransient); + if (dataAttribute.getCount() > 0) { + output.print("{\n"); + + for (int i = 0; i < dataAttribute.getCount(); i++) { + output.print("[" + i + "]"); + + printDataAttributeValue(output, dataAttribute, isTransient); } - output.println("}"); + output.print("}\n"); + } + else { + printDataAttributeValue(output, dataAttribute, isTransient); } - } public static void main(String[] args) throws FileNotFoundException {