Compare commits

...

15 Commits
v1.5 ... 1.1.2

@ -1,3 +1,35 @@
Changes to version 1.1.2
------------------------
- MMS client: fixed parsing initiate response message
- SV publisher: conditional encoding for SmpRate
- MmsValue_update function now allows adjusting octet-string size of target object
- .NET API: Added DeleteFile
- CDC helper functions: added helper functions for VSS and VSG CDC
- added additional locks in client and server
Changes to version 1.1.1
------------------------
- IEC 61850 client: fixed bug in APC control handling
- IEC 61850 client: ClientReportControlBlock now accepts "$" and "." as seperator for RCB object reference
- MMS client: fixed bug in MmsConnection_connect (COTP payload buffer was not reset in case of an error during connect -> connection failed in case of reuse of MmsConnection object
- MMS client: delete named variable list service supports VMD specific lists
- SV subscriber/publisher: additional features and bug fixes
- SV: fixed data type for smpRate
- SV: fixed encoding of optional smpMod attribute
- SV receiver: Added semaphore to make subscriber list thread-safe
- .NET API: ControlObject implements IDisposable interface
- IED server: added new function IedServer_udpateDbposValue
- fixed problem with cmake include folders
- MMS client: file services -fixed encoding problem with long file names
- MMS server: ACSE authenticator passes application reference (ap-title and ae-qualifier)
- example directory cleanup
- MMS: fixed potential memory leak in asn1 code that can be caused by malformed MMS messages
- MMS client: MmsConnection_getVariableAccessAttributes support for VMD specific variables
- Java SCL parser: added support for "Val" elements for Octet64 types
Changes to version 1.1.0 Changes to version 1.1.0
------------------------ ------------------------

@ -12,7 +12,7 @@ ENABLE_TESTING()
set(LIB_VERSION_MAJOR "1") set(LIB_VERSION_MAJOR "1")
set(LIB_VERSION_MINOR "1") set(LIB_VERSION_MINOR "1")
set(LIB_VERSION_PATCH "0") set(LIB_VERSION_PATCH "2")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/third_party/cmake/modules/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/third_party/cmake/modules/")

@ -28,7 +28,7 @@
#define DEBUG_HAL_ETHERNET 0 #define DEBUG_HAL_ETHERNET 0
/* Maximum MMS PDU SIZE - default is 65000 */ /* Maximum MMS PDU SIZE - default is 65000 */
#define CONFIG_MMS_MAXIMUM_PDU_SIZE 120000 #define CONFIG_MMS_MAXIMUM_PDU_SIZE 65000
/* /*
* Enable single threaded mode * Enable single threaded mode
@ -37,7 +37,7 @@
* 0 ==> server runs in multi-threaded mode (one thread for each connection and * 0 ==> server runs in multi-threaded mode (one thread for each connection and
* one server background thread ) * one server background thread )
*/ */
#define CONFIG_MMS_SINGLE_THREADED 0 #define CONFIG_MMS_SINGLE_THREADED 1
/* /*
* Optimize stack for threadless operation - don't use semaphores * Optimize stack for threadless operation - don't use semaphores

@ -17,7 +17,7 @@ using System.Runtime.CompilerServices;
// The form "{Major}.{Minor}.*" will automatically update the build and revision, // The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision. // and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.1.2")]
// The following attributes are used to specify the signing key for the assembly, // The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing. // if desired. See the Mono documentation for more information about signing.

@ -1035,6 +1035,18 @@ namespace IEC61850
if (error != 0) if (error != 0)
throw new IedConnectionException ("Write value failed", error); throw new IedConnectionException ("Write value failed", error);
}
/// <summary>Delete file</summary>
/// <param name="fileName">The name of the file.</param>
/// <exception cref="IedConnectionException">This exception is thrown if there is a connection or service error</exception>
public void DeleteFile (string fileName)
{
int error;
IedConnection_deleteFile (connection, out error, fileName);
if (error != 0)
throw new IedConnectionException ("Deleting file " + fileName + " failed", error);
} }
/// <summary>Read the content of a file directory.</summary> /// <summary>Read the content of a file directory.</summary>

@ -50,8 +50,6 @@ int main(int argc, char** argv) {
if (error == IED_ERROR_OK) { if (error == IED_ERROR_OK) {
IedConnection_getServerDirectory(con, &error, false);
/* read an analog measurement value from server */ /* read an analog measurement value from server */
MmsValue* value = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX); MmsValue* value = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX);

@ -15,7 +15,7 @@
#include "platform_endian.h" #include "platform_endian.h"
#define LIBIEC61850_VERSION "1.1.0" #define LIBIEC61850_VERSION "1.1.2"
#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME #ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"

@ -18,7 +18,7 @@ DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libIEC61850" PROJECT_NAME = "libIEC61850"
PROJECT_NUMBER = 1.1 PROJECT_NUMBER = 1.1.2
PROJECT_BRIEF = "Open-source IEC 61850 MMS/GOOSE/SV server and client library" PROJECT_BRIEF = "Open-source IEC 61850 MMS/GOOSE/SV server and client library"

@ -149,6 +149,7 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
bool hasOper = false; bool hasOper = false;
bool hasTimeActivatedControl = false; bool hasTimeActivatedControl = false;
bool hasCtlNum = false; bool hasCtlNum = false;
bool isAPC = false;
MmsVariableSpecification* ctlVal = NULL; MmsVariableSpecification* ctlVal = NULL;
MmsVariableSpecification* t = NULL; MmsVariableSpecification* t = NULL;
@ -157,7 +158,12 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
if (oper) if (oper)
{ {
hasOper = true; hasOper = true;
ctlVal = MmsVariableSpecification_getNamedVariableRecursive(oper, "ctlVal");
if (MmsVariableSpecification_getType(ctlVal) == MMS_STRUCTURE)
isAPC = true;
MmsVariableSpecification* operTm = MmsVariableSpecification_getNamedVariableRecursive(oper, "operTm"); MmsVariableSpecification* operTm = MmsVariableSpecification_getNamedVariableRecursive(oper, "operTm");
@ -169,7 +175,6 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
if (ctlNum) if (ctlNum)
hasCtlNum = true; hasCtlNum = true;
ctlVal = MmsVariableSpecification_getNamedVariableRecursive(oper, "ctlVal");
t = MmsVariableSpecification_getNamedVariableRecursive(oper, "T"); t = MmsVariableSpecification_getNamedVariableRecursive(oper, "T");
} }
} }
@ -200,6 +205,11 @@ ControlObjectClient_create(const char* objectReference, IedConnection connection
self->hasCtlNum = hasCtlNum; self->hasCtlNum = hasCtlNum;
self->ctlVal = MmsValue_newDefaultValue(ctlVal); self->ctlVal = MmsValue_newDefaultValue(ctlVal);
if (isAPC)
self->analogValue = MmsValue_createEmptyStructure(1);
else
self->analogValue = NULL;
/* Check for T element type (Binary time -> Ed.1,UTC time -> Ed.2) */ /* Check for T element type (Binary time -> Ed.1,UTC time -> Ed.2) */
if (MmsVariableSpecification_getType(t) == MMS_BINARY_TIME) if (MmsVariableSpecification_getType(t) == MMS_BINARY_TIME)
self->edition = 1; self->edition = 1;
@ -218,162 +228,6 @@ exit_function:
return self; return self;
} }
#if 0
ControlObjectClient
ControlObjectClient_create(const char* objectReference, IedConnection connection)
{
ControlObjectClient self = NULL;
/* request control model from server */
char domainId[65];
char itemId[129];
char* domainName = MmsMapping_getMmsDomainFromObjectReference(objectReference, domainId);
if (domainName == NULL)
goto exit_function;
convertToMmsAndInsertFC(itemId, objectReference + strlen(domainId) + 1, "CF");
int controlObjectItemIdLen = strlen(itemId);
strncat(itemId, "$ctlModel", 64 - controlObjectItemIdLen);
MmsError mmsError;
MmsValue* ctlModel = MmsConnection_readVariable(IedConnection_getMmsConnection(connection),
&mmsError, domainId, itemId);
if (ctlModel == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: ControlObjectClient_create: failed to get ctlModel from server\n");
goto exit_function;
}
int ctlModelVal = MmsValue_toUint32(ctlModel);
MmsValue_delete(ctlModel);
IedClientError error;
LinkedList dataDirectory =
IedConnection_getDataDirectory(connection, &error, objectReference);
if (dataDirectory == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: ControlObjectClient_create: failed to get data directory of control object\n");
goto exit_function;
}
/* check what control elements are available */
bool hasOper = false;
LinkedList element = LinkedList_getNext(dataDirectory);
while (element != NULL) {
char* objectName = (char*) element->data;
if (strcmp(objectName, "Oper") == 0)
hasOper = true;
element = LinkedList_getNext(element);
}
LinkedList_destroy(dataDirectory);
if (hasOper == false) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: control is missing required element \"Oper\"\n");
goto exit_function;
}
/* check for time activated control and ctlNum */
bool hasTimeActivatedControl = false;
bool hasCtlNum = false;
strcpy(itemId, objectReference);
strcat(itemId, ".Oper");
dataDirectory = IedConnection_getDataDirectory(connection, &error, itemId);
if (dataDirectory == NULL)
goto exit_function;
element = LinkedList_getNext(dataDirectory);
while (element != NULL) {
char* objectName = (char*) element->data;
if (strcmp(objectName, "operTm") == 0) {
hasTimeActivatedControl = true;
}
else if (strcmp(objectName, "ctlNum") == 0) {
hasCtlNum = true;
}
element = LinkedList_getNext(element);
}
LinkedList_destroy(dataDirectory);
/* get default parameters for Oper control variable */
MmsValue* oper = IedConnection_readObject(connection, &error, itemId, IEC61850_FC_CO);
if (oper == NULL) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: reading \"Oper\" failed!\n");
goto exit_function;
}
self = (ControlObjectClient) GLOBAL_CALLOC(1, sizeof(struct sControlObjectClient));
if (self == NULL)
goto exit_function;
self->objectReference = StringUtils_copyString(objectReference);
self->connection = connection;
self->ctlModel = (ControlModel) ctlModelVal;
self->hasTimeActivatedMode = hasTimeActivatedControl;
self->hasCtlNum = hasCtlNum;
self->ctlVal = MmsValue_getElement(oper, 0);
if (MmsValue_getType(self->ctlVal) == MMS_STRUCTURE)
self->analogValue = MmsValue_createEmptyStructure(1);
else
self->analogValue = NULL;
/* Check for T element type (Binary time -> Ed.1,UTC time -> Ed.2) */
MmsValue* t;
if (hasTimeActivatedControl)
t = MmsValue_getElement(oper, 4);
else
t = MmsValue_getElement(oper, 3);
if (MmsValue_getType(t) == MMS_BINARY_TIME)
self->edition = 1;
else
self->edition = 2;
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: Detected edition %i control\n", self->edition);
MmsValue_setElement(oper, 0, NULL);
MmsValue_delete(oper);
private_IedConnection_addControlClient(connection, self);
exit_function:
return self;
}
#endif
void void
ControlObjectClient_destroy(ControlObjectClient self) ControlObjectClient_destroy(ControlObjectClient self)
{ {

@ -32,12 +32,19 @@
#include "libiec61850_platform_includes.h" #include "libiec61850_platform_includes.h"
static bool static bool
isBufferedRcb(const char* objectReference) isBufferedRcb(const char* objectReference, bool* isValid)
{ {
const char* separator = strchr(objectReference, '.'); const char* separator = strchr(objectReference, '.');
if (separator == NULL) if (separator == NULL)
separator = strchr(objectReference, '$');
if (separator == NULL) {
*isValid = false;
return false; return false;
}
*isValid = true;
if (*(separator + 1) == 'B') if (*(separator + 1) == 'B')
return true; return true;
@ -48,12 +55,24 @@ isBufferedRcb(const char* objectReference)
ClientReportControlBlock ClientReportControlBlock
ClientReportControlBlock_create(const char* objectReference) ClientReportControlBlock_create(const char* objectReference)
{ {
ClientReportControlBlock self = (ClientReportControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientReportControlBlock)); bool isReferenceValid;
bool isBuffered;
isBuffered = isBufferedRcb(objectReference, &isReferenceValid);
if (isReferenceValid == false) {
if (DEBUG_IED_CLIENT)
printf("DEBUG_IED_CLIENT: RCB reference invalid\n");
return NULL;
}
//TODO check validity of object reference?! ClientReportControlBlock self = (ClientReportControlBlock) GLOBAL_CALLOC(1, sizeof(struct sClientReportControlBlock));
self->objectReference = StringUtils_copyString(objectReference); if (self) {
self->isBuffered = isBufferedRcb(objectReference); self->objectReference = StringUtils_copyString(objectReference);
self->isBuffered = isBuffered;
}
return self; return self;
} }

@ -184,7 +184,8 @@ CDC_ENS_create(const char* dataObjectName, ModelNode* parent, uint32_t options);
DataObject* DataObject*
CDC_BCR_create(const char* dataObjectName, ModelNode* parent, uint32_t options); CDC_BCR_create(const char* dataObjectName, ModelNode* parent, uint32_t options);
DataObject*
CDC_VSS_create(const char* dataObjectName, ModelNode* parent, uint32_t options);
/** /**
* \brief create a new SEC (Security violation) CDC instance (data object) * \brief create a new SEC (Security violation) CDC instance (data object)
@ -340,6 +341,16 @@ CDC_ACT_create(const char* dataObjectName, ModelNode* parent, uint32_t options);
DataObject* DataObject*
CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options); CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options);
/**
* \brief Visible string setting (VSG)
*
* \param dataObjectName the name of the new object
* \param parent the parent of the new data object (either a LogicalNode or another DataObject)
* \param options bit mask to encode required optional elements
*/
DataObject*
CDC_VSG_create(const char* dataObjectName, ModelNode* parent, uint32_t options);
/** /**
* \brief Enumerated status setting (ENG) * \brief Enumerated status setting (ENG)
* *

@ -379,7 +379,23 @@ CDC_SEC_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
} }
DataObject*
CDC_VSS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{
DataObject* newSPS = DataObject_create(dataObjectName, parent, 0);
CDC_addStatusToDataObject(newSPS, IEC61850_VISIBLE_STRING_255);
if (options & CDC_OPTION_PICS_SUBST)
CDC_addOptionPicsSubst(newSPS, IEC61850_BOOLEAN);
if (options & CDC_OPTION_BLK_ENA)
DataAttribute_create("blkEna", (ModelNode*) newSPS, IEC61850_BOOLEAN, IEC61850_FC_BL, 0, 0, 0);
CDC_addStandardOptions(newSPS, options);
return newSPS;
}
/** /**
* CDC_OPTION_INST_MAG * CDC_OPTION_INST_MAG
@ -931,6 +947,19 @@ CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
return newSPG; return newSPG;
} }
DataObject*
CDC_VSG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{
DataObject* newSPG = DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("setVal", (ModelNode*) newSPG, IEC61850_VISIBLE_STRING_255, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0);
CDC_addStandardOptions(newSPG, options);
return newSPG;
}
DataObject* DataObject*
CDC_ENG_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_ENG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {

@ -79,8 +79,12 @@ struct sMmsConnection {
uint32_t connectTimeout; uint32_t connectTimeout;
IsoClientConnection isoClient; IsoClientConnection isoClient;
AssociationState associationState;
ConnectionState connectionState; volatile AssociationState associationState;
Semaphore associationStateLock;
volatile ConnectionState connectionState;
Semaphore connectionStateLock;
MmsConnectionParameters parameters; MmsConnectionParameters parameters;
IsoConnectionParameters isoParameters; IsoConnectionParameters isoParameters;
@ -97,7 +101,8 @@ struct sMmsConnection {
#endif #endif
/* state of an active connection conclude/release process */ /* state of an active connection conclude/release process */
int concludeState; volatile int concludeState;
Semaphore concludeStateLock;
#if (MMS_OBTAIN_FILE_SERVICE == 1) #if (MMS_OBTAIN_FILE_SERVICE == 1)
int32_t nextFrsmId; int32_t nextFrsmId;

@ -55,7 +55,10 @@ struct sIsoClientConnection
{ {
IsoIndicationCallback callback; IsoIndicationCallback callback;
void* callbackParameter; void* callbackParameter;
volatile int state; volatile int state;
Semaphore stateMutex;
Socket socket; Socket socket;
CotpConnection* cotpConnection; CotpConnection* cotpConnection;
IsoPresentation* presentation; IsoPresentation* presentation;
@ -86,13 +89,32 @@ struct sIsoClientConnection
Thread thread; Thread thread;
}; };
static void
setState(IsoClientConnection self, int newState)
{
Semaphore_wait(self->stateMutex);
self->state = newState;
Semaphore_post(self->stateMutex);
}
static int
getState(IsoClientConnection self)
{
int stateVal;
Semaphore_wait(self->stateMutex);
stateVal = self->state;
Semaphore_post(self->stateMutex);
return stateVal;
}
static void static void
connectionHandlingThread(IsoClientConnection self) connectionHandlingThread(IsoClientConnection self)
{ {
IsoSessionIndication sessionIndication; IsoSessionIndication sessionIndication;
self->handlingThreadRunning = true; self->handlingThreadRunning = true;
self->stopHandlingThread = false;
if (DEBUG_ISO_CLIENT) if (DEBUG_ISO_CLIENT)
printf("ISO_CLIENT_CONNECTION: new connection %p\n", self); printf("ISO_CLIENT_CONNECTION: new connection %p\n", self);
@ -157,7 +179,7 @@ connectionHandlingThread(IsoClientConnection self)
self->callback(ISO_IND_CLOSED, self->callbackParameter, NULL);; self->callback(ISO_IND_CLOSED, self->callbackParameter, NULL);;
self->state = STATE_IDLE; setState(self, STATE_IDLE);
Socket_destroy(self->socket); Socket_destroy(self->socket);
@ -202,7 +224,9 @@ IsoClientConnection_create(IsoIndicationCallback callback, void* callbackParamet
self->callback = callback; self->callback = callback;
self->callbackParameter = callbackParameter; self->callbackParameter = callbackParameter;
self->state = STATE_IDLE; self->state = STATE_IDLE;
self->stateMutex = Semaphore_create(1);
self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE); self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE);
@ -235,6 +259,12 @@ IsoClientConnection_create(IsoIndicationCallback callback, void* callbackParamet
self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection)); self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection));
self->handlingThreadRunning = false;
self->stopHandlingThread = false;
self->destroyHandlingThread = false;
self->startHandlingThread = false;
return self; return self;
} }
@ -361,7 +391,7 @@ IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters
/* wait for upper layer to release buffer */ /* wait for upper layer to release buffer */
Semaphore_wait(self->receiveBufferMutex); Semaphore_wait(self->receiveBufferMutex);
self->state = STATE_ASSOCIATED; setState(self, STATE_ASSOCIATED);
if (self->thread == NULL) { if (self->thread == NULL) {
self->thread = Thread_create(connectionThreadFunction, self, false); self->thread = Thread_create(connectionThreadFunction, self, false);
@ -378,7 +408,7 @@ IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters
returnError: returnError:
self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL); self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL);
self->state = STATE_ERROR; setState(self, STATE_ERROR);
Socket_destroy(self->socket); Socket_destroy(self->socket);
self->socket = NULL; self->socket = NULL;
@ -432,7 +462,7 @@ IsoClientConnection_close(IsoClientConnection self)
Thread_sleep(1); Thread_sleep(1);
} }
self->state = STATE_IDLE; setState(self, STATE_IDLE);
} }
@ -442,7 +472,7 @@ IsoClientConnection_destroy(IsoClientConnection self)
if (DEBUG_ISO_CLIENT) if (DEBUG_ISO_CLIENT)
printf("ISO_CLIENT: IsoClientConnection_destroy\n"); printf("ISO_CLIENT: IsoClientConnection_destroy\n");
if (self->state == STATE_ASSOCIATED) { if (getState(self) == STATE_ASSOCIATED) {
if (DEBUG_ISO_CLIENT) if (DEBUG_ISO_CLIENT)
printf("ISO_CLIENT: call IsoClientConnection_close\n"); printf("ISO_CLIENT: call IsoClientConnection_close\n");
@ -489,6 +519,7 @@ IsoClientConnection_destroy(IsoClientConnection self)
Semaphore_destroy(self->receiveBufferMutex); Semaphore_destroy(self->receiveBufferMutex);
Semaphore_destroy(self->transmitBufferMutex); Semaphore_destroy(self->transmitBufferMutex);
Semaphore_destroy(self->stateMutex);
GLOBAL_FREEMEM(self->sendBuffer); GLOBAL_FREEMEM(self->sendBuffer);
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);

@ -39,6 +39,66 @@
#define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000 #define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000
#define OUTSTANDING_CALLS 10 #define OUTSTANDING_CALLS 10
static void
setAssociationState(MmsConnection self, AssociationState newState)
{
Semaphore_wait(self->associationStateLock);
self->associationState = newState;
Semaphore_post(self->associationStateLock);
}
static AssociationState
getAssociationState(MmsConnection self)
{
AssociationState state;
Semaphore_wait(self->associationStateLock);
state = self->associationState;
Semaphore_post(self->associationStateLock);
return state;
}
static void
setConnectionState(MmsConnection self, ConnectionState newState)
{
Semaphore_wait(self->connectionStateLock);
self->connectionState = newState;
Semaphore_post(self->connectionStateLock);
}
static ConnectionState
getConnectionState(MmsConnection self)
{
ConnectionState state;
Semaphore_wait(self->connectionStateLock);
state = self->connectionState;
Semaphore_post(self->connectionStateLock);
return state;
}
static void
setConcludeState(MmsConnection self, int newState)
{
Semaphore_wait(self->concludeStateLock);
self->concludeState = newState;
Semaphore_post(self->concludeStateLock);
}
static int
getConcludeState(MmsConnection self)
{
int state;
Semaphore_wait(self->concludeStateLock);
state = self->concludeState;
Semaphore_post(self->concludeStateLock);
return state;
}
static void static void
handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message) handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
{ {
@ -310,7 +370,7 @@ sendRequestAndWaitForResponse(MmsConnection self, uint32_t invokeId, ByteBuffer*
while (currentTime < waitUntilTime) { while (currentTime < waitUntilTime) {
uint32_t receivedInvokeId; uint32_t receivedInvokeId;
if (self->associationState == MMS_STATE_CLOSED) { if (getAssociationState(self) == MMS_STATE_CLOSED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto connection_lost; goto connection_lost;
} }
@ -688,8 +748,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (indication == ISO_IND_CLOSED) { if (indication == ISO_IND_CLOSED) {
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsIsoCallback: Connection lost or closed by client!\n"); printf("MMS_CLIENT: mmsIsoCallback: Connection lost or closed by client!\n");
self->connectionState = MMS_CON_IDLE; setConnectionState(self, MMS_CON_IDLE);
self->associationState = MMS_STATE_CLOSED; setAssociationState(self, MMS_STATE_CLOSED);
/* Call user provided callback function */ /* Call user provided callback function */
if (self->connectionLostHandler != NULL) if (self->connectionLostHandler != NULL)
@ -701,8 +761,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (indication == ISO_IND_ASSOCIATION_FAILED) { if (indication == ISO_IND_ASSOCIATION_FAILED) {
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsIsoCallback: association failed!\n"); printf("MMS_CLIENT: mmsIsoCallback: association failed!\n");
self->connectionState = MMS_CON_ASSOCIATION_FAILED; setConnectionState(self, MMS_CON_ASSOCIATION_FAILED);
self->associationState = MMS_STATE_CLOSED; setAssociationState(self, MMS_STATE_CLOSED);
return; return;
} }
@ -728,12 +788,12 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
printf("MMS_CLIENT: MMS-PDU: %02x\n", tag); printf("MMS_CLIENT: MMS-PDU: %02x\n", tag);
if (tag == 0xa9) { /* initiate response PDU */ if (tag == 0xa9) { /* initiate response PDU */
if (indication == ISO_IND_ASSOCIATION_SUCCESS) {
self->connectionState = MMS_CON_ASSOCIATED; if (indication == ISO_IND_ASSOCIATION_SUCCESS)
} setConnectionState(self, MMS_CON_ASSOCIATED);
else { else
self->connectionState = MMS_CON_ASSOCIATION_FAILED; setConnectionState(self, MMS_CON_ASSOCIATION_FAILED);
}
self->lastResponse = payload; self->lastResponse = payload;
IsoClientConnection_releaseReceiveBuffer(self->isoClient); IsoClientConnection_releaseReceiveBuffer(self->isoClient);
@ -746,7 +806,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: received conclude.request\n"); printf("MMS_CLIENT: received conclude.request\n");
self->concludeState = CONCLUDE_STATE_REQUESTED; setConcludeState(self, CONCLUDE_STATE_REQUESTED);
/* TODO block all new user requests? */ /* TODO block all new user requests? */
@ -756,7 +816,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: received conclude.reponse+\n"); printf("MMS_CLIENT: received conclude.reponse+\n");
self->concludeState = CONCLUDE_STATE_ACCEPTED; setConcludeState(self, CONCLUDE_STATE_ACCEPTED);
IsoClientConnection_release(self->isoClient); IsoClientConnection_release(self->isoClient);
@ -766,7 +826,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: received conclude.reponse-\n"); printf("MMS_CLIENT: received conclude.reponse-\n");
self->concludeState = CONCLUDE_STATE_REJECTED; setConcludeState(self, CONCLUDE_STATE_REJECTED);
IsoClientConnection_releaseReceiveBuffer(self->isoClient); IsoClientConnection_releaseReceiveBuffer(self->isoClient);
} }
@ -1030,6 +1090,10 @@ MmsConnection_create()
self->lastResponseLock = Semaphore_create(1); self->lastResponseLock = Semaphore_create(1);
self->outstandingCallsLock = Semaphore_create(1); self->outstandingCallsLock = Semaphore_create(1);
self->connectionStateLock = Semaphore_create(1);
self->concludeStateLock = Semaphore_create(1);
self->associationStateLock = Semaphore_create(1);
self->lastResponseError = MMS_ERROR_NONE; self->lastResponseError = MMS_ERROR_NONE;
self->outstandingCalls = (uint32_t*) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(uint32_t)); self->outstandingCalls = (uint32_t*) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(uint32_t));
@ -1065,6 +1129,10 @@ MmsConnection_destroy(MmsConnection self)
Semaphore_destroy(self->lastResponseLock); Semaphore_destroy(self->lastResponseLock);
Semaphore_destroy(self->outstandingCallsLock); Semaphore_destroy(self->outstandingCallsLock);
Semaphore_destroy(self->associationStateLock);
Semaphore_destroy(self->connectionStateLock);
Semaphore_destroy(self->concludeStateLock);
GLOBAL_FREEMEM(self->outstandingCalls); GLOBAL_FREEMEM(self->outstandingCalls);
#if (MMS_OBTAIN_FILE_SERVICE == 1) #if (MMS_OBTAIN_FILE_SERVICE == 1)
@ -1172,7 +1240,7 @@ waitForConnectResponse(MmsConnection self)
uint64_t waitUntilTime = currentTime + self->requestTimeout; uint64_t waitUntilTime = currentTime + self->requestTimeout;
while (currentTime < waitUntilTime) { while (currentTime < waitUntilTime) {
if (self->connectionState != MMS_CON_WAITING) if (getConnectionState(self) != MMS_CON_WAITING)
break; break;
Thread_sleep(10); Thread_sleep(10);
@ -1200,7 +1268,7 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* server
} }
#endif /* (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) */ #endif /* (CONFIG_MMS_RAW_MESSAGE_LOGGING == 1) */
self->connectionState = MMS_CON_WAITING; setConnectionState(self, MMS_CON_WAITING);
IsoClientConnection_associate(self->isoClient, self->isoParameters, payload, IsoClientConnection_associate(self->isoClient, self->isoParameters, payload,
self->connectTimeout); self->connectTimeout);
@ -1208,25 +1276,24 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* server
waitForConnectResponse(self); waitForConnectResponse(self);
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MmsConnection_connect: received response conState: %i\n", self->connectionState); printf("MmsConnection_connect: received response conState: %i\n", getConnectionState(self));
if (self->connectionState == MMS_CON_ASSOCIATED) { if (getConnectionState(self) == MMS_CON_ASSOCIATED) {
mmsClient_parseInitiateResponse(self); mmsClient_parseInitiateResponse(self);
releaseResponse(self); releaseResponse(self);
self->associationState = MMS_STATE_CONNECTED; setAssociationState(self, MMS_STATE_CONNECTED);
}
else {
self->associationState = MMS_STATE_CLOSED;
} }
else
setAssociationState(self, MMS_STATE_CLOSED);
self->connectionState = MMS_CON_IDLE; setConnectionState(self, MMS_CON_IDLE);
if (DEBUG_MMS_CLIENT) if (DEBUG_MMS_CLIENT)
printf("MmsConnection_connect: states: con %i ass %i\n", self->connectionState, self->associationState); printf("MmsConnection_connect: states: con %i ass %i\n", getConnectionState(self), getAssociationState(self));
if (self->associationState == MMS_STATE_CONNECTED) { if (getAssociationState(self) == MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_NONE; *mmsError = MMS_ERROR_NONE;
return true; return true;
} }
@ -1241,7 +1308,7 @@ MmsConnection_close(MmsConnection self)
{ {
self->connectionLostHandler = NULL; self->connectionLostHandler = NULL;
if (self->associationState == MMS_STATE_CONNECTED) if (getAssociationState(self) == MMS_STATE_CONNECTED)
IsoClientConnection_close(self->isoClient); IsoClientConnection_close(self->isoClient);
} }
@ -1254,7 +1321,7 @@ MmsConnection_abort(MmsConnection self, MmsError* mmsError)
bool success = true; bool success = true;
if (self->associationState == MMS_STATE_CONNECTED) if (getAssociationState(self) == MMS_STATE_CONNECTED)
success = IsoClientConnection_abort(self->isoClient); success = IsoClientConnection_abort(self->isoClient);
if (success == false) { if (success == false) {
@ -1278,16 +1345,16 @@ sendConcludeRequestAndWaitForResponse(MmsConnection self)
mmsClient_createConcludeRequest(self, concludeMessage); mmsClient_createConcludeRequest(self, concludeMessage);
self->concludeState = CONCLUDE_STATE_REQUESTED; setConcludeState(self, CONCLUDE_STATE_REQUESTED);
IsoClientConnection_sendMessage(self->isoClient, concludeMessage); IsoClientConnection_sendMessage(self->isoClient, concludeMessage);
while (currentTime < waitUntilTime) { while (currentTime < waitUntilTime) {
if (self->associationState == MMS_STATE_CLOSED) if (getAssociationState(self) == MMS_STATE_CLOSED)
goto exit_function; goto exit_function;
if (self->concludeState != CONCLUDE_STATE_REQUESTED) { if (getConcludeState(self) != CONCLUDE_STATE_REQUESTED) {
success = true; success = true;
break; break;
} }
@ -1310,7 +1377,7 @@ exit_function:
void void
MmsConnection_conclude(MmsConnection self, MmsError* mmsError) MmsConnection_conclude(MmsConnection self, MmsError* mmsError)
{ {
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1324,12 +1391,12 @@ MmsConnection_conclude(MmsConnection self, MmsError* mmsError)
releaseResponse(self); releaseResponse(self);
if (self->concludeState != CONCLUDE_STATE_ACCEPTED) { if (getConcludeState(self) != CONCLUDE_STATE_ACCEPTED) {
if (self->associationState == MMS_STATE_CLOSED) if (getAssociationState(self) == MMS_STATE_CLOSED)
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
if (self->concludeState == CONCLUDE_STATE_REJECTED) if (getConcludeState(self) == CONCLUDE_STATE_REJECTED)
*mmsError = MMS_ERROR_CONCLUDE_REJECTED; *mmsError = MMS_ERROR_CONCLUDE_REJECTED;
} }
@ -1359,7 +1426,7 @@ mmsClient_getNameListSingleRequest(
{ {
bool moreFollows = false; bool moreFollows = false;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1462,7 +1529,7 @@ MmsConnection_readVariable(MmsConnection self, MmsError* mmsError,
{ {
MmsValue* value = NULL; MmsValue* value = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1491,7 +1558,7 @@ MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError,
{ {
MmsValue* value = NULL; MmsValue* value = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1520,7 +1587,7 @@ MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError,
{ {
MmsValue* value = NULL; MmsValue* value = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1549,7 +1616,7 @@ MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError
{ {
MmsValue* value = NULL; MmsValue* value = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1580,7 +1647,7 @@ MmsConnection_readNamedVariableListValuesAssociationSpecific(
{ {
MmsValue* value = NULL; MmsValue* value = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1609,7 +1676,7 @@ MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsEr
{ {
LinkedList attributes = NULL; LinkedList attributes = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1639,7 +1706,7 @@ MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection se
{ {
LinkedList attributes = NULL; LinkedList attributes = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1667,7 +1734,7 @@ void
MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError, MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError,
const char* domainId, const char* listName, LinkedList variableSpecs) const char* domainId, const char* listName, LinkedList variableSpecs)
{ {
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1695,7 +1762,7 @@ void
MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self, MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self,
MmsError* mmsError, const char* listName, LinkedList variableSpecs) MmsError* mmsError, const char* listName, LinkedList variableSpecs)
{ {
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1726,7 +1793,7 @@ MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError,
{ {
bool isDeleted = false; bool isDeleted = false;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1755,7 +1822,7 @@ MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self,
{ {
bool isDeleted = false; bool isDeleted = false;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1785,7 +1852,7 @@ MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError
{ {
MmsVariableSpecification* typeSpec = NULL; MmsVariableSpecification* typeSpec = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }
@ -1812,7 +1879,7 @@ MmsConnection_identify(MmsConnection self, MmsError* mmsError)
{ {
MmsServerIdentity* identity = NULL; MmsServerIdentity* identity = NULL;
if (self->associationState != MMS_STATE_CONNECTED) { if (getAssociationState(self) != MMS_STATE_CONNECTED) {
*mmsError = MMS_ERROR_CONNECTION_LOST; *mmsError = MMS_ERROR_CONNECTION_LOST;
goto exit_function; goto exit_function;
} }

@ -170,20 +170,30 @@ mmsClient_parseInitiateResponse(MmsConnection self)
self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED; self->parameters.maxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING; self->parameters.maxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
int bufPos = 0; int bufPos = 1; /* ignore tag - already checked */
int maxBufPos = ByteBuffer_getSize(self->lastResponse); int maxBufPos = ByteBuffer_getSize(self->lastResponse);
uint8_t* buffer = ByteBuffer_getBuffer(self->lastResponse); uint8_t* buffer = ByteBuffer_getBuffer(self->lastResponse);
int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0)
return false;
if (bufPos + length > maxBufPos)
return false;
while (bufPos < maxBufPos) { while (bufPos < maxBufPos) {
uint8_t tag = buffer[bufPos++]; uint8_t tag = buffer[bufPos++];
int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos); bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) { if (bufPos < 0)
// TODO write initiate error PDU! return false;
if (bufPos + length > maxBufPos)
return false; return false;
}
switch (tag) { switch (tag) {
case 0x80: /* local-detail-calling */ case 0x80: /* local-detail-calling */

@ -223,67 +223,76 @@ MmsValue_equalTypes(const MmsValue* self, const MmsValue* otherValue)
bool bool
MmsValue_update(MmsValue* self, const MmsValue* update) MmsValue_update(MmsValue* self, const MmsValue* update)
{ {
if (self->type == update->type) { if (self->type == update->type) {
switch (self->type) { switch (self->type) {
case MMS_STRUCTURE: case MMS_STRUCTURE:
case MMS_ARRAY: case MMS_ARRAY:
if (updateStructuredComponent(self, update) == false) if (updateStructuredComponent(self, update) == false)
return false; return false;
break; break;
case MMS_BOOLEAN: case MMS_BOOLEAN:
self->value.boolean = update->value.boolean; self->value.boolean = update->value.boolean;
break; break;
case MMS_FLOAT: case MMS_FLOAT:
if (self->value.floatingPoint.formatWidth == update->value.floatingPoint.formatWidth) { if (self->value.floatingPoint.formatWidth == update->value.floatingPoint.formatWidth) {
self->value.floatingPoint.exponentWidth = update->value.floatingPoint.exponentWidth; self->value.floatingPoint.exponentWidth = update->value.floatingPoint.exponentWidth;
memcpy(self->value.floatingPoint.buf, update->value.floatingPoint.buf, memcpy(self->value.floatingPoint.buf, update->value.floatingPoint.buf,
self->value.floatingPoint.formatWidth / 8); self->value.floatingPoint.formatWidth / 8);
} }
else return false; else
break; return false;
case MMS_INTEGER: break;
case MMS_UNSIGNED: case MMS_INTEGER:
if (BerInteger_setFromBerInteger(self->value.integer, update->value.integer)) case MMS_UNSIGNED:
return true; if (BerInteger_setFromBerInteger(self->value.integer, update->value.integer))
else return true;
return false; else
break; return false;
case MMS_UTC_TIME: break;
memcpy(self->value.utcTime, update->value.utcTime, 8); case MMS_UTC_TIME:
break; memcpy(self->value.utcTime, update->value.utcTime, 8);
case MMS_BIT_STRING: break;
if (self->value.bitString.size == update->value.bitString.size) case MMS_BIT_STRING:
memcpy(self->value.bitString.buf, update->value.bitString.buf, bitStringByteSize(self)); if (self->value.bitString.size == update->value.bitString.size)
else return false; memcpy(self->value.bitString.buf, update->value.bitString.buf, bitStringByteSize(self));
break; else
case MMS_OCTET_STRING: return false;
if (self->value.octetString.maxSize == update->value.octetString.maxSize) { break;
memcpy(self->value.octetString.buf, update->value.octetString.buf, case MMS_OCTET_STRING:
update->value.octetString.size); {
int size = update->value.octetString.size;
self->value.octetString.size = update->value.octetString.size;
} if (size > self->value.octetString.maxSize) {
else return false; GLOBAL_FREEMEM(self->value.octetString.buf);
break; self->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size);
case MMS_VISIBLE_STRING: self->value.octetString.maxSize = size;
MmsValue_setVisibleString(self, update->value.visibleString.buf); }
break; size = self->value.octetString.maxSize;
case MMS_STRING:
MmsValue_setMmsString(self, update->value.visibleString.buf); memcpy(self->value.octetString.buf, update->value.octetString.buf, size);
break;
case MMS_BINARY_TIME: self->value.octetString.size = size;
self->value.binaryTime.size = update->value.binaryTime.size; }
memcpy(self->value.binaryTime.buf, update->value.binaryTime.buf, break;
update->value.binaryTime.size); case MMS_VISIBLE_STRING:
break; MmsValue_setVisibleString(self, update->value.visibleString.buf);
default: break;
return false; case MMS_STRING:
break; MmsValue_setMmsString(self, update->value.visibleString.buf);
} break;
return true; case MMS_BINARY_TIME:
} self->value.binaryTime.size = update->value.binaryTime.size;
else memcpy(self->value.binaryTime.buf, update->value.binaryTime.buf,
return false; update->value.binaryTime.size);
break;
default:
return false;
break;
}
return true;
}
else
return false;
} }
MmsValue* MmsValue*
@ -1015,9 +1024,7 @@ MmsValue_cloneToBuffer(const MmsValue* self, uint8_t* destinationAddress)
int i; int i;
for (i = 0; i < self->value.structure.size; i++) { for (i = 0; i < self->value.structure.size; i++) {
newValue->value.structure.components[i] = (MmsValue*) destinationAddress; memcpy(&(newValue->value.structure.components[i]), &(destinationAddress), sizeof (MmsValue*));
//memcpy(&(newValue->value.structure.components[i]), &(destinationAddress), sizeof (MmsValue*));
destinationAddress = MmsValue_cloneToBuffer(self->value.structure.components[i], destinationAddress); destinationAddress = MmsValue_cloneToBuffer(self->value.structure.components[i], destinationAddress);
} }
} }

@ -1,7 +1,7 @@
/* /*
* iso_server.c * iso_server.c
* *
* Copyright 2013, 2014 Michael Zillgith * Copyright 2013-2018 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -51,6 +51,11 @@
struct sIsoServer { struct sIsoServer {
IsoServerState state; IsoServerState state;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore stateLock;
#endif
ConnectionIndicationHandler connectionHandler; ConnectionIndicationHandler connectionHandler;
void* connectionHandlerParameter; void* connectionHandlerParameter;
@ -83,6 +88,34 @@ struct sIsoServer {
int connectionCounter; int connectionCounter;
}; };
static void
setState(IsoServer self, IsoServerState newState)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->stateLock);
#endif
self->state = newState;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->stateLock);
#endif
}
static IsoServerState
getState(IsoServer self)
{
IsoServerState state;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->stateLock);
#endif
state = self->state;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->stateLock);
#endif
return state;
}
#if (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED == 0) #if (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED == 0)
static inline void static inline void
lockClientConnections(IsoServer self) lockClientConnections(IsoServer self)
@ -301,7 +334,7 @@ setupIsoServer(IsoServer self)
self->serverSocket = (Socket) TcpServerSocket_create(self->localIpAddress, self->tcpPort); self->serverSocket = (Socket) TcpServerSocket_create(self->localIpAddress, self->tcpPort);
if (self->serverSocket == NULL) { if (self->serverSocket == NULL) {
self->state = ISO_SVR_STATE_ERROR; setState(self, ISO_SVR_STATE_ERROR);
success = false; success = false;
goto exit_function; goto exit_function;
@ -311,7 +344,7 @@ setupIsoServer(IsoServer self)
ServerSocket_listen((ServerSocket) self->serverSocket); ServerSocket_listen((ServerSocket) self->serverSocket);
self->state = ISO_SVR_STATE_RUNNING; setState(self, ISO_SVR_STATE_RUNNING);
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1) #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1)
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
@ -438,6 +471,10 @@ IsoServer_create()
self->state = ISO_SVR_STATE_IDLE; self->state = ISO_SVR_STATE_IDLE;
self->tcpPort = TCP_PORT; self->tcpPort = TCP_PORT;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->stateLock = Semaphore_create(1);
#endif
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) #if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
self->openClientConnections = LinkedList_create(); self->openClientConnections = LinkedList_create();
#else #else
@ -470,7 +507,7 @@ IsoServer_setLocalIpAddress(IsoServer self, char* ipAddress)
IsoServerState IsoServerState
IsoServer_getState(IsoServer self) IsoServer_getState(IsoServer self)
{ {
return self->state; return getState(self);
} }
void void
@ -531,7 +568,7 @@ IsoServer_startListeningThreadless(IsoServer self)
self->serverSocket = NULL; self->serverSocket = NULL;
} }
else { else {
self->state = ISO_SVR_STATE_RUNNING; setState(self, ISO_SVR_STATE_RUNNING);
if (DEBUG_ISO_SERVER) if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: new iso server (threadless) started\n"); printf("ISO_SERVER: new iso server (threadless) started\n");
@ -543,7 +580,7 @@ IsoServer_waitReady(IsoServer self, unsigned int timeoutMs)
{ {
int result; int result;
if (self->state == ISO_SVR_STATE_RUNNING) { if (getState(self) == ISO_SVR_STATE_RUNNING) {
HandleSet handles; HandleSet handles;
handles = Handleset_new(); handles = Handleset_new();
@ -613,14 +650,15 @@ IsoServer_waitReady(IsoServer self, unsigned int timeoutMs)
void void
IsoServer_processIncomingMessages(IsoServer self) IsoServer_processIncomingMessages(IsoServer self)
{ {
if (self->state == ISO_SVR_STATE_RUNNING) if (getState(self) == ISO_SVR_STATE_RUNNING)
handleIsoConnectionsThreadless(self); handleIsoConnectionsThreadless(self);
} }
static void static void
stopListening(IsoServer self) stopListening(IsoServer self)
{ {
self->state = ISO_SVR_STATE_STOPPED; setState(self, ISO_SVR_STATE_STOPPED);
if (self->serverSocket != NULL) { if (self->serverSocket != NULL) {
ServerSocket_destroy((ServerSocket) self->serverSocket); ServerSocket_destroy((ServerSocket) self->serverSocket);
self->serverSocket = NULL; self->serverSocket = NULL;
@ -661,7 +699,7 @@ IsoServer_stopListening(IsoServer self)
void void
IsoServer_closeConnection(IsoServer self, IsoConnection isoConnection) IsoServer_closeConnection(IsoServer self, IsoConnection isoConnection)
{ {
if (self->state != ISO_SVR_STATE_IDLE) { if (getState(self) != ISO_SVR_STATE_IDLE) {
self->connectionHandler(ISO_CONNECTION_CLOSED, self->connectionHandlerParameter, self->connectionHandler(ISO_CONNECTION_CLOSED, self->connectionHandlerParameter,
isoConnection); isoConnection);
} }
@ -709,6 +747,10 @@ IsoServer_destroy(IsoServer self)
Semaphore_destroy(self->openClientConnectionsMutex); Semaphore_destroy(self->openClientConnectionsMutex);
#endif #endif
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->stateLock);
#endif
GLOBAL_FREEMEM(self); GLOBAL_FREEMEM(self);
} }

@ -398,8 +398,10 @@ SV_ASDU_encodeToBuffer(SV_ASDU self, uint8_t* buffer, int bufPos)
buffer[bufPos++] = self->smpSynch; buffer[bufPos++] = self->smpSynch;
/* SmpRate */ /* SmpRate */
bufPos = BerEncoder_encodeTL(0x86, 2, buffer, bufPos); if (self->hasSmpRate) {
bufPos = encodeUInt16FixedSize(self->smpRate, buffer, bufPos); bufPos = BerEncoder_encodeTL(0x86, 2, buffer, bufPos);
bufPos = encodeUInt16FixedSize(self->smpRate, buffer, bufPos);
}
/* Sample */ /* Sample */
bufPos = BerEncoder_encodeTL(0x87, self->dataSize, buffer, bufPos); bufPos = BerEncoder_encodeTL(0x87, self->dataSize, buffer, bufPos);

Loading…
Cancel
Save