diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index 28f28660..98f63819 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -473,8 +473,12 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError) self->lastApplError.ctlNum = MmsValue_toUint32(ctlNum); self->lastApplError.addCause = (ControlAddCause) MmsValue_toInt32(addCause); self->lastApplError.error = (ControlLastApplError) MmsValue_toInt32(error); + + Semaphore_wait(self->clientControlsLock); + LinkedList control = LinkedList_getNext(self->clientControls); - while (control != NULL) { + + while (control) { ControlObjectClient object = (ControlObjectClient) control->data; const char* objectRef = ControlObjectClient_getObjectReference(object); @@ -485,6 +489,8 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError) control = LinkedList_getNext(control); } + + Semaphore_post(self->clientControlsLock); } static void @@ -515,9 +521,11 @@ informationReportHandler(void* parameter, char* domainName, if (DEBUG_IED_CLIENT) printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName); + Semaphore_wait(self->clientControlsLock); + LinkedList control = LinkedList_getNext(self->clientControls); - while (control != NULL) { + while (control) { ControlObjectClient object = (ControlObjectClient) control->data; const char* objectRef = ControlObjectClient_getObjectReference(object); @@ -527,6 +535,8 @@ informationReportHandler(void* parameter, char* domainName, control = LinkedList_getNext(control); } + + Semaphore_post(self->clientControlsLock); } MmsValue_delete(value); @@ -585,6 +595,7 @@ createNewConnectionObject(TLSConfiguration tlsConfig, bool useThreads) if (self) { self->enabledReports = LinkedList_create(); self->logicalDevices = NULL; + self->clientControlsLock = Semaphore_create(1); self->clientControls = LinkedList_create(); @@ -810,6 +821,7 @@ IedConnection_destroy(IedConnection self) LinkedList_destroyStatic(self->clientControls); + Semaphore_destroy(self->clientControlsLock); Semaphore_destroy(self->outstandingCallsLock); Semaphore_destroy(self->stateMutex); Semaphore_destroy(self->reportHandlerMutex); @@ -3796,13 +3808,21 @@ IedConnection_getLastApplError(IedConnection self) void iedConnection_addControlClient(IedConnection self, ControlObjectClient control) { + Semaphore_wait(self->clientControlsLock); + LinkedList_add(self->clientControls, control); + + Semaphore_post(self->clientControlsLock); } void iedConnection_removeControlClient(IedConnection self, ControlObjectClient control) { + Semaphore_wait(self->clientControlsLock); + LinkedList_remove(self->clientControls, control); + + Semaphore_post(self->clientControlsLock); } FileDirectoryEntry diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index ffe8ff1f..0418c255 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -1957,14 +1957,32 @@ ControlObjectClient_createEx(const char* objectReference, IedConnection connecti LIB61850_API void ControlObjectClient_destroy(ControlObjectClient self); +/** + * Cause of the \ref ControlObjectClient_ControlActionHandler invocation + */ typedef enum { - CONTROL_ACTION_TYPE_SELECT = 0, - CONTROL_ACTION_TYPE_OPERATE = 1, - CONTROL_ACTION_TYPE_CANCEL = 2 + CONTROL_ACTION_TYPE_SELECT = 0, /** < callback was invoked because of a select command */ + CONTROL_ACTION_TYPE_OPERATE = 1, /** < callback was invoked because of an operate command */ + CONTROL_ACTION_TYPE_CANCEL = 2 /** < callback was invoked because of a cancel command */ } ControlActionType; - +/** + * \brief A callback handler that is invoked when a command termination message is received. + * + * This callback is invoked whenever a CommandTermination+ or CommandTermination- message is received. + * To distinguish between a CommandTermination+ and CommandTermination- please use the + * ControlObjectClient_getLastApplError function. + * + * NOTE: Do not call \ref ControlObjectClient_destroy inside of this callback! Doing so will cause a dead-lock. + * + * \param invokeId invoke ID of the command sent by the client + * \param parameter the user parameter that is passed to the callback function + * \param err the error code when an error occurred, or IED_ERROR_OK + * \param type control action type that caused the callback + * \param success true, when the command was successful, false otherwise + * + */ typedef void (*ControlObjectClient_ControlActionHandler) (uint32_t invokeId, void* parameter, IedClientError err, ControlActionType type, bool success); @@ -2196,7 +2214,7 @@ ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int * NOTE: Some non-standard compliant servers may require this to accept oper/cancel requests * * \param self the ControlObjectClient instance - * \param useContantT enable this behaviour with true, disable with false + * \param useContantT enable this behavior with true, disable with false */ LIB61850_API void ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT); @@ -2233,13 +2251,15 @@ ControlObjectClient_setSynchroCheck(ControlObjectClient self, bool value); /** - * \brief Private a callback handler that is invoked when a command termination message is received. + * \brief A callback handler that is invoked when a command termination message is received. * * This callback is invoked whenever a CommandTermination+ or CommandTermination- message is received. * To distinguish between a CommandTermination+ and CommandTermination- please use the * ControlObjectClient_getLastApplError function. * - * \param parameter the user paramter that is passed to the callback function + * NOTE: Do not call \ref ControlObjectClient_destroy inside of this callback! Doing so will cause a dead-lock. + * + * \param parameter the user parameter that is passed to the callback function * \param controlClient the ControlObjectClient instance */ typedef void (*CommandTerminationHandler) (void* parameter, ControlObjectClient controlClient); diff --git a/src/iec61850/inc_private/ied_connection_private.h b/src/iec61850/inc_private/ied_connection_private.h index 3b061b5b..5b7200ed 100644 --- a/src/iec61850/inc_private/ied_connection_private.h +++ b/src/iec61850/inc_private/ied_connection_private.h @@ -56,7 +56,10 @@ struct sIedConnection IedConnectionState state; LinkedList enabledReports; LinkedList logicalDevices; + + Semaphore clientControlsLock; LinkedList clientControls; + LastApplError lastApplError; Semaphore stateMutex;