From 56d7ee4f0b9182a75329b5d9ef8b8cc93943defa Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Thu, 4 Oct 2018 18:56:25 +0200 Subject: [PATCH] - IEC 61850/MMS client: Add support for write variable for array element with component - added lost README file for winpcap --- src/iec61850/client/ied_connection.c | 192 +++++++++++++++++- src/iec61850/inc/iec61850_client.h | 19 +- .../inc_private/ied_connection_private.h | 12 ++ src/mms/inc/mms_client_connection.h | 27 ++- src/mms/inc_private/mms_client_internal.h | 18 ++ src/mms/iso_mms/client/mms_client_common.c | 153 +++++++++++++- .../iso_mms/client/mms_client_connection.c | 61 ++++++ src/mms/iso_mms/client/mms_client_read.c | 127 +----------- src/mms/iso_mms/client/mms_client_write.c | 133 ++++++------ third_party/winpcap/README | 2 + 10 files changed, 546 insertions(+), 198 deletions(-) create mode 100644 third_party/winpcap/README diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index 9ebadac2..ed9e1ba9 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -33,6 +33,7 @@ #define DEFAULT_CONNECTION_TIMEOUT 10000 #define DATA_SET_MAX_NAME_LENGTH 64 /* is 32 according to standard! */ +#define OUTSTANDING_CALLS 12 typedef struct sICLogicalDevice { @@ -489,6 +490,9 @@ createNewConnectionObject(TLSConfiguration tlsConfig) self->stateMutex = Semaphore_create(1); self->reportHandlerMutex = Semaphore_create(1); + self->outstandingCallsLock = Semaphore_create(1); + self->outstandingCalls = (IedConnectionOutstandingCall) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(struct sIedConnectionOutstandingCall)); + self->connectionTimeout = DEFAULT_CONNECTION_TIMEOUT; } @@ -633,8 +637,11 @@ IedConnection_destroy(IedConnection self) if (self->enabledReports != NULL) LinkedList_destroyDeep(self->enabledReports, (LinkedListValueDeleteFunction) ClientReport_destroy); + GLOBAL_FREEMEM(self->outstandingCalls); + LinkedList_destroyStatic(self->clientControls); + Semaphore_destroy(self->outstandingCallsLock); Semaphore_destroy(self->stateMutex); Semaphore_destroy(self->reportHandlerMutex); @@ -676,6 +683,161 @@ IedConnection_getVariableSpecification(IedConnection self, IedClientError* error return varSpec; } +static IedConnectionOutstandingCall +allocateOutstandingCall(IedConnection self) +{ + Semaphore_wait(self->outstandingCallsLock); + + IedConnectionOutstandingCall call = NULL; + + int i = 0; + + for (i = 0; i < OUTSTANDING_CALLS; i++) { + if (self->outstandingCalls[i].used == false) { + self->outstandingCalls[i].used = true; + call = &(self->outstandingCalls[i]); + break; + } + } + + Semaphore_post(self->outstandingCallsLock); + + return call; +} + +static void +releaseOutstandingCall(IedConnection self, IedConnectionOutstandingCall call) +{ + Semaphore_wait(self->outstandingCallsLock); + + call->used = false; + + Semaphore_post(self->outstandingCallsLock); +} + +static IedConnectionOutstandingCall +lookupOutstandingCall(IedConnection self, uint32_t invokeId) +{ + Semaphore_wait(self->outstandingCallsLock); + + IedConnectionOutstandingCall call = NULL; + + int i = 0; + + for (i = 0; i < OUTSTANDING_CALLS; i++) { + + printf("%d: used: %d invokeId: %d\n", i, self->outstandingCalls[i].used, self->outstandingCalls[i].invokeId); + + if ((self->outstandingCalls[i].used) && (self->outstandingCalls[i].invokeId == invokeId)) { + call = &(self->outstandingCalls[i]); + break; + } + } + + Semaphore_post(self->outstandingCallsLock); + + return call; +} + +static void +readObjectHandlerInternal(int invokeId, void* parameter, MmsError err, MmsValue* value) +{ + printf("readObjectHandlerInternal %i\n", invokeId); + + IedConnection self = (IedConnection) parameter; + + IedConnectionOutstandingCall call = lookupOutstandingCall(self, invokeId); + + if (call) { + + IedConnection_ReadObjectHandler handler = (IedConnection_ReadObjectHandler) call->callback; + + handler(invokeId, call->callbackParameter, iedConnection_mapMmsErrorToIedError(err), value); + + releaseOutstandingCall(self, call); + } + else { + // if (DEBUG_IED_CLIENT) + printf("IED_CLIENT: internal error - no matching outstanding call!\n"); + } +} + +uint32_t +IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const char* objRef, FunctionalConstraint fc, + IedConnection_ReadObjectHandler handler, void* parameter) +{ + *error = IED_ERROR_OK; + + char domainIdBuffer[65]; + char itemIdBuffer[65]; + + char* domainId; + char* itemId; + + domainId = MmsMapping_getMmsDomainFromObjectReference(objRef, domainIdBuffer); + itemId = MmsMapping_createMmsVariableNameFromObjectReference(objRef, fc, itemIdBuffer); + + if ((domainId == NULL) || (itemId == NULL)) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + return 0; + } + + IedConnectionOutstandingCall call = allocateOutstandingCall(self); + + if (call == NULL) { + *error = IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED; + return 0; + } + + call->callback = handler; + call->callbackParameter = parameter; + + MmsError err = MMS_ERROR_NONE; + + /* check if item ID contains an array "(..)" */ + char* brace = strchr(itemId, '('); + + if (brace) { + char* secondBrace = strchr(brace, ')'); + + if (secondBrace) { + char* endPtr; + + int index = (int) strtol(brace + 1, &endPtr, 10); + + if (endPtr == secondBrace) { + char* component = NULL; + + if (strlen(secondBrace + 1) > 1) + component = secondBrace + 2; /* skip "." after array element specifier */ + + *brace = 0; + + call->invokeId = MmsConnection_readSingleArrayElementWithComponentAsync(self->connection, &err, domainId, itemId, index, component, readObjectHandlerInternal, self); + } + else + *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; + } + else + *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; + } + else + call->invokeId = MmsConnection_readVariableAsync(self->connection, &err, domainId, itemId, readObjectHandlerInternal, self); + + if ((err != MMS_ERROR_NONE) || (*error != IED_ERROR_OK)) { + + if (err != MMS_ERROR_NONE) + *error = iedConnection_mapMmsErrorToIedError(err); + + releaseOutstandingCall(self, call); + + return 0; + } + + return call->invokeId; +} + + MmsValue* IedConnection_readObject(IedConnection self, IedClientError* error, const char* objectReference, FunctionalConstraint fc) @@ -949,7 +1111,35 @@ IedConnection_writeObject(IedConnection self, IedClientError* error, const char* MmsError mmsError; - MmsConnection_writeVariable(self->connection, &mmsError, domainId, itemId, value); + /* check if item ID contains an array "(..)" */ + char* brace = strchr(itemId, '('); + + if (brace) { + char* secondBrace = strchr(brace, ')'); + + if (secondBrace) { + char* endPtr; + + int index = (int) strtol(brace + 1, &endPtr, 10); + + if (endPtr == secondBrace) { + char* component = NULL; + + if (strlen(secondBrace + 1) > 1) + component = secondBrace + 2; /* skip "." after array element specifier */ + + *brace = 0; + + MmsConnection_writeSingleArrayElementWithComponent(self->connection, &mmsError, domainId, itemId, index, component, value); + } + else + *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; + } + else + *error = IED_ERROR_USER_PROVIDED_INVALID_ARGUMENT; + } + else + MmsConnection_writeVariable(self->connection, &mmsError, domainId, itemId, value); *error = iedConnection_mapMmsErrorToIedError(mmsError); } diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 5f74bb39..f2222092 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -106,6 +106,9 @@ typedef enum { /** Connection rejected by server */ IED_ERROR_CONNECTION_REJECTED = 5, + /** Cannot send request because outstanding call limit is reached */ + IED_ERROR_OUTSTANDING_CALL_LIMIT_REACHED = 6, + /* client side errors */ /** API function has been called with an invalid argument */ @@ -303,7 +306,8 @@ LastApplError IedConnection_getLastApplError(IedConnection self); -typedef void (*IedConnectionClosedHandler) (void* parameter, IedConnection connection); +typedef void +(*IedConnectionClosedHandler) (void* parameter, IedConnection connection); /** * \brief Install a handler function that will be called when the connection is lost. @@ -316,6 +320,12 @@ void IedConnection_installConnectionClosedHandler(IedConnection self, IedConnectionClosedHandler handler, void* parameter); +typedef void +(*IedConnectionStateChangedHandler) (void* parameter, IedConnection connection, IedConnectionState newState); + +void +IedConnection_installStateChangedHandler(IedConnection self, IedConnectionStateChangedHandler handler, void* parameter); + /** * \brief get a handle to the underlying MmsConnection * @@ -1209,6 +1219,13 @@ ClientReportControlBlock_getOwner(ClientReportControlBlock self); MmsValue* IedConnection_readObject(IedConnection self, IedClientError* error, const char* dataAttributeReference, FunctionalConstraint fc); +typedef void +(*IedConnection_ReadObjectHandler) (int invokeId, void* parameter, IedClientError err, MmsValue* value); + +uint32_t +IedConnection_readObjectAsync(IedConnection self, IedClientError* error, const char* objRef, FunctionalConstraint fc, + IedConnection_ReadObjectHandler handler, void* parameter); + /** * \brief write a functional constrained data attribute (FCDA) or functional constrained data (FCD). * diff --git a/src/iec61850/inc_private/ied_connection_private.h b/src/iec61850/inc_private/ied_connection_private.h index b2a7bb6d..decd3630 100644 --- a/src/iec61850/inc_private/ied_connection_private.h +++ b/src/iec61850/inc_private/ied_connection_private.h @@ -30,6 +30,15 @@ #include "hal_thread.h" +typedef struct sIedConnectionOutstandingCall* IedConnectionOutstandingCall; + +struct sIedConnectionOutstandingCall { + bool used; + uint32_t invokeId; + void* callback; + void* callbackParameter; +}; + struct sIedConnection { MmsConnection connection; @@ -42,6 +51,9 @@ struct sIedConnection Semaphore stateMutex; Semaphore reportHandlerMutex; + Semaphore outstandingCallsLock; + IedConnectionOutstandingCall outstandingCalls; + IedConnectionClosedHandler connectionCloseHandler; void* connectionClosedParameter; uint32_t connectionTimeout; diff --git a/src/mms/inc/mms_client_connection.h b/src/mms/inc/mms_client_connection.h index 9c448fee..6a846c6c 100644 --- a/src/mms/inc/mms_client_connection.h +++ b/src/mms/inc/mms_client_connection.h @@ -579,10 +579,35 @@ MmsConnection_writeVariableAsync(MmsConnection self, MmsError* mmsError, const char* domainId, const char* itemId, MmsValue* value, MmsConnection_WriteVariableHandler handler, void* parameter); + +/** + * \brief Write a single array element with a component to an array type variable + * + * \param self MmsConnection instance to operate on + * \param mmsError user provided variable to store error code + * \param domainId the domain name of the variable to be written + * \param itemId name of the variable to be written + * \param arrayIndex the index of the array element. + * \param componentId the name of the component of the array element + * \param value value of the array element component to be written. + * + * \return when successful, the data access error value returned by the server + */ +MmsDataAccessError +MmsConnection_writeSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, + uint32_t arrayIndex, const char* componentId, MmsValue* value); + +uint32_t +MmsConnection_writeSingleArrayElementWithComponentAsync(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, + uint32_t arrayIndex, const char* componentId, MmsValue* value, + MmsConnection_WriteVariableHandler handler, void* parameter); + /** * \brief Write a single array element or a sub array to an array type variable * - * When a single array element is address the MmsValue object value has to be of the type + * When a single array element is addressed the MmsValue object value has to be of the type * of the array elements. When multiple array elements have to be written (index range) the * MmsValue object value has to be of type MMS_ARRAY containing "numberOfElements" elements. * diff --git a/src/mms/inc_private/mms_client_internal.h b/src/mms/inc_private/mms_client_internal.h index 2a1a78cb..00e5978d 100644 --- a/src/mms/inc_private/mms_client_internal.h +++ b/src/mms/inc_private/mms_client_internal.h @@ -176,6 +176,18 @@ mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* writeBuffer); MmsPdu_t* mmsClient_createConfirmedRequestPdu(uint32_t invokeId); +AlternateAccess_t* +mmsClient_createAlternateAccess(uint32_t index, uint32_t elementCount); + +void +mmsClient_deleteAlternateAccess(AlternateAccess_t* alternateAccess); + +void +mmsClient_deleteAlternateAccessIndexComponent(AlternateAccess_t* alternateAccess); + +AlternateAccess_t* +mmsClient_createAlternateAccessIndexComponent(uint32_t index, const char* componentName); + int mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writeBuffer, const char* continueAfter); @@ -260,6 +272,12 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const int startIndex, int elementCount, MmsValue* value, ByteBuffer* writeBuffer); +int +mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId, + uint32_t arrayIndex, const char* component, + MmsValue* value, + ByteBuffer* writeBuffer); + void mmsClient_createDefineNamedVariableListRequest(uint32_t invokeId, ByteBuffer* writeBuffer, const char* domainId, const char* listNameId, LinkedList /**/ listOfVariables, diff --git a/src/mms/iso_mms/client/mms_client_common.c b/src/mms/iso_mms/client/mms_client_common.c index 9fd94705..468cd00c 100644 --- a/src/mms/iso_mms/client/mms_client_common.c +++ b/src/mms/iso_mms/client/mms_client_common.c @@ -1,7 +1,7 @@ /* * mms_client_common.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013-2018 Michael Zillgith * * This file is part of libIEC61850. * @@ -58,3 +58,154 @@ mmsClient_createConfirmedRequestPdu(uint32_t invokeId) return mmsPdu; } + +AlternateAccess_t* +mmsClient_createAlternateAccess(uint32_t index, uint32_t elementCount) +{ + AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); + alternateAccess->list.count = 1; + alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); + alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); + alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; + + alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); + + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; + + if (elementCount > 0) { + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_indexRange; + + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex); + + asn_long2INTEGER(asnIndex, index); + + asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements); + + asn_long2INTEGER(asnIndex, elementCount); + } + else { + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_index; + + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); + + asn_long2INTEGER(asnIndex, index); + } + + return alternateAccess; +} + +void +mmsClient_deleteAlternateAccess(AlternateAccess_t* alternateAccess) +{ + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf != NULL) { + GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf = NULL; + } + + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf != NULL) { + GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf = NULL; + } + + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf != NULL) { + GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf = NULL; + } + + if (alternateAccess->list.array[0]->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess) { + if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess != NULL) { + mmsClient_deleteAlternateAccess(alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess); + } + } + + GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed); + GLOBAL_FREEMEM(alternateAccess->list.array[0]); + GLOBAL_FREEMEM(alternateAccess->list.array); + GLOBAL_FREEMEM(alternateAccess); +} + +static AlternateAccess_t* +createAlternateAccessComponent(const char* componentName) +{ + AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); + alternateAccess->list.count = 1; + alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); + alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); + alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; + + alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); + + const char* separator = strchr(componentName, '$'); + + if (separator) { + int size = separator - componentName; + + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present = + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component; + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.buf = + (uint8_t*) StringUtils_copySubString((char*) componentName, (char*) separator); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.size = size; + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(separator + 1); + } + else { + int size = strlen(componentName); + + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_component; + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.buf = + (uint8_t*) StringUtils_copyString(componentName); + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.size = size; + } + + return alternateAccess; +} + +AlternateAccess_t* +mmsClient_createAlternateAccessIndexComponent(uint32_t index, const char* componentName) +{ + AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); + alternateAccess->list.count = 1; + alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); + alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); + alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; + + alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); + + if (componentName) { + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present = + AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index; + + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); + + asn_long2INTEGER(asnIndex, index); + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(componentName); + } + else { + alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; + + alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = + AlternateAccessSelection__selectAccess_PR_index; + + INTEGER_t* asnIndex = + &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); + + asn_long2INTEGER(asnIndex, index); + } + + return alternateAccess; +} diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c index 4c117ddb..3836370f 100644 --- a/src/mms/iso_mms/client/mms_client_connection.c +++ b/src/mms/iso_mms/client/mms_client_connection.c @@ -3953,6 +3953,67 @@ exit_function: return invokeId; } +MmsDataAccessError +MmsConnection_writeSingleArrayElementWithComponent(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, + uint32_t arrayIndex, const char* componentId, MmsValue* value) +{ + struct writeVariableParameters parameter; + + MmsError err = MMS_ERROR_NONE; + + parameter.waitForResponse = Semaphore_create(1); + parameter.err = MMS_ERROR_NONE; + parameter.accessError = DATA_ACCESS_ERROR_SUCCESS; + + Semaphore_wait(parameter.waitForResponse); + + MmsConnection_writeSingleArrayElementWithComponentAsync(self, &err, domainId, itemId, arrayIndex, componentId, value, writeVariableHandler, ¶meter); + + if (err == MMS_ERROR_NONE) { + Semaphore_wait(parameter.waitForResponse); + + err = parameter.err; + } + + Semaphore_destroy(parameter.waitForResponse); + + if (mmsError) + *mmsError = err; + + return parameter.accessError; +} + +uint32_t +MmsConnection_writeSingleArrayElementWithComponentAsync(MmsConnection self, MmsError* mmsError, + const char* domainId, const char* itemId, + uint32_t arrayIndex, const char* componentId, MmsValue* value, + MmsConnection_WriteVariableHandler handler, void* parameter) +{ + uint32_t invokeId = 0; + + if (getConnectionState(self) != MMS_CONNECTION_STATE_CONNECTED) { + if (mmsError) + *mmsError = MMS_ERROR_CONNECTION_LOST; + goto exit_function; + } + + ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient); + + invokeId = getNextInvokeId(self); + + mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, arrayIndex, + componentId, value, payload); + + MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, NULL); + + if (mmsError) + *mmsError = err; + +exit_function: + return invokeId; +} + struct writeMultipleVariablesParameter { Semaphore sem; diff --git a/src/mms/iso_mms/client/mms_client_read.c b/src/mms/iso_mms/client/mms_client_read.c index 30a211c6..8eb2caf3 100644 --- a/src/mms/iso_mms/client/mms_client_read.c +++ b/src/mms/iso_mms/client/mms_client_read.c @@ -421,127 +421,6 @@ mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char* return rval.encoded; } -static AlternateAccess_t* -createAlternateAccess(uint32_t index, uint32_t elementCount) -{ - AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); - alternateAccess->list.count = 1; - alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); - alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); - alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - - alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - - if (elementCount > 0) { - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_indexRange; - - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex); - - asn_long2INTEGER(asnIndex, index); - - asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements); - - asn_long2INTEGER(asnIndex, elementCount); - } - else { - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_index; - - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); - - asn_long2INTEGER(asnIndex, index); - } - - return alternateAccess; -} - -static AlternateAccess_t* -createAlternateAccessComponent(const char* componentName) -{ - AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); - alternateAccess->list.count = 1; - alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); - alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); - alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - - alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - - const char* separator = strchr(componentName, '$'); - - if (separator) { - int size = separator - componentName; - - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present = - AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_component; - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.buf = - (uint8_t*) StringUtils_copySubString((char*) componentName, (char*) separator); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.component.size = size; - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(separator + 1); - } - else { - int size = strlen(componentName); - - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_component; - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.buf = - (uint8_t*) StringUtils_copyString(componentName); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.component.size = size; - } - - return alternateAccess; -} - -static AlternateAccess_t* -createAlternateAccessIndexComponent(uint32_t index, const char* componentName) -{ - AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); - alternateAccess->list.count = 1; - alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); - alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); - alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - - alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - - if (componentName) { - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAlternateAccess; - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.accessSelection.present = - AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index; - - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); - - asn_long2INTEGER(asnIndex, index); - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess = createAlternateAccessComponent(componentName); - } - else { - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_index; - - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); - - asn_long2INTEGER(asnIndex, index); - } - - return alternateAccess; -} - static ListOfVariableSeq_t* createVariableIdentifier(const char* domainId, const char* itemId) { @@ -575,7 +454,7 @@ mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* d readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier; - variableIdentifier->alternateAccess = createAlternateAccess(index, elementCount); + variableIdentifier->alternateAccess = mmsClient_createAlternateAccess(index, elementCount); asn_enc_rval_t rval; @@ -594,7 +473,7 @@ mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* d int mmsClient_createReadRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId, - uint32_t index, const char* component, ByteBuffer* writeBuffer) + uint32_t arrayIndex, const char* component, ByteBuffer* writeBuffer) { MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); ReadRequest_t* readRequest = createReadRequest(mmsPdu); @@ -610,7 +489,7 @@ mmsClient_createReadRequestAlternateAccessSingleIndexComponent(uint32_t invokeId readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier; - variableIdentifier->alternateAccess = createAlternateAccessIndexComponent(index, component); + variableIdentifier->alternateAccess = mmsClient_createAlternateAccessIndexComponent(arrayIndex, component); asn_enc_rval_t rval; diff --git a/src/mms/iso_mms/client/mms_client_write.c b/src/mms/iso_mms/client/mms_client_write.c index 99b07e65..248ca613 100644 --- a/src/mms/iso_mms/client/mms_client_write.c +++ b/src/mms/iso_mms/client/mms_client_write.c @@ -197,74 +197,6 @@ exit_function: return retVal; } -//TODO remove redundant code (see mms_client_read.c) - -static AlternateAccess_t* -createAlternateAccess(uint32_t index, uint32_t elementCount) -{ - AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t)); - alternateAccess->list.count = 1; - alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*)); - alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member)); - alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed; - - alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t)); - - alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess; - - if (elementCount > 0) { - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_indexRange; - - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex); - - asn_long2INTEGER(asnIndex, index); - - asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements); - - asn_long2INTEGER(asnIndex, elementCount); - } - else { - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.present = - AlternateAccessSelection__selectAccess_PR_index; - - INTEGER_t* asnIndex = - &(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index); - - asn_long2INTEGER(asnIndex, index); - } - - return alternateAccess; -} - -static void -deleteAlternateAccess(AlternateAccess_t* alternateAccess) -{ - if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf != NULL) { - GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.lowIndex.buf = NULL; - } - - if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf != NULL) { - GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.indexRange.numberOfElements.buf = NULL; - } - - if (alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf != NULL) { - GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf); - alternateAccess->list.array[0]->choice.unnamed->choice.selectAccess.choice.index.buf = NULL; - } - - GLOBAL_FREEMEM(alternateAccess->list.array[0]->choice.unnamed); - GLOBAL_FREEMEM(alternateAccess->list.array[0]); - GLOBAL_FREEMEM(alternateAccess->list.array); - GLOBAL_FREEMEM(alternateAccess); - -} - - static ListOfVariableSeq_t* createNewDomainVariableSpecification(const char* domainId, const char* itemId) { @@ -556,7 +488,7 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); ListOfVariableSeq_t* variableIdentifier = createNewDomainVariableSpecification(domainId, itemId); - variableIdentifier->alternateAccess = createAlternateAccess(startIndex, elementCount); + variableIdentifier->alternateAccess = mmsClient_createAlternateAccess(startIndex, elementCount); request->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier; /* Create list of typed data values */ @@ -573,7 +505,7 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); /* Free ASN structure */ - deleteAlternateAccess(variableIdentifier->alternateAccess); + mmsClient_deleteAlternateAccess(variableIdentifier->alternateAccess); request->variableAccessSpecification.choice.listOfVariable.list.count = 0; @@ -582,6 +514,67 @@ mmsClient_createWriteRequestArray(uint32_t invokeId, const char* domainId, const request->variableAccessSpecification.choice.listOfVariable.list.array = 0; + request->listOfData.list.count = 0; + + deleteDataElement(request->listOfData.list.array[0]); + + GLOBAL_FREEMEM(request->listOfData.list.array); + request->listOfData.list.array = 0; + + asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0); + + return rval.encoded; +} + +int +mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(uint32_t invokeId, const char* domainId, const char* itemId, + uint32_t arrayIndex, const char* component, + MmsValue* value, + ByteBuffer* writeBuffer) +{ + MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId); + + mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present = + ConfirmedServiceRequest_PR_write; + WriteRequest_t* request = + &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.write); + + /* Create list of variable specifications */ + request->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable; + request->variableAccessSpecification.choice.listOfVariable.list.count = 1; + //request->variableAccessSpecification.choice.listOfVariable.list.size = 1; + request->variableAccessSpecification.choice.listOfVariable.list.array = + (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*)); + + ListOfVariableSeq_t* variableIdentifier = createNewDomainVariableSpecification(domainId, itemId); + + request->variableAccessSpecification.choice.listOfVariable.list.array[0] = variableIdentifier; + + variableIdentifier->alternateAccess = mmsClient_createAlternateAccessIndexComponent(arrayIndex, component); + + + /* Create list of typed data values */ + request->listOfData.list.count = 1; + request->listOfData.list.size = 1; + request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(1, sizeof(struct Data*)); + request->listOfData.list.array[0] = mmsMsg_createBasicDataElement(value); + + /* Encode complete ASN1 structure */ + + asn_enc_rval_t rval; + + rval = der_encode(&asn_DEF_MmsPdu, mmsPdu, + (asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer); + + /* Free ASN structure */ + // mmsClient_deleteAlternateAccessIndexComponent(variableIdentifier->alternateAccess); + mmsClient_deleteAlternateAccess(variableIdentifier->alternateAccess); + request->variableAccessSpecification.choice.listOfVariable.list.count = 0; + + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[0]); + GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array); + request->variableAccessSpecification.choice.listOfVariable.list.array = 0; + request->listOfData.list.count = 0; deleteDataElement(request->listOfData.list.array[0]); diff --git a/third_party/winpcap/README b/third_party/winpcap/README new file mode 100644 index 00000000..9050673d --- /dev/null +++ b/third_party/winpcap/README @@ -0,0 +1,2 @@ +For GOOSE support add winpcap source and headers here. Rerun cmake to configure the build system for GOOSE support. +