From 98d91464cbba79b2c7a148cab1a810775ba14487 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 23 Feb 2015 17:36:19 +0100 Subject: [PATCH] - prevent server from crashing when reports are too large for maximum PDU size - improved memory handling for reports --- .../client_example_reporting.c | 1 - src/iec61850/server/mms_mapping/mms_mapping.c | 2 +- src/mms/inc_private/mms_server_internal.h | 2 + .../iso_mms/server/mms_information_report.c | 46 +++++++++++++++---- src/mms/iso_mms/server/mms_read_service.c | 31 +++++++++---- src/mms/iso_mms/server/mms_server.c | 6 ++- 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/examples/iec61850_client_example_reporting/client_example_reporting.c b/examples/iec61850_client_example_reporting/client_example_reporting.c index 4c80c89f..ba119f0b 100644 --- a/examples/iec61850_client_example_reporting/client_example_reporting.c +++ b/examples/iec61850_client_example_reporting/client_example_reporting.c @@ -33,7 +33,6 @@ reportCallbackFunction(void* parameter, ClientReport report) if (ClientReport_hasTimestamp(report)) { time_t unixTime = ClientReport_getTimestamp(report) / 1000; -//#ifdef _MSC_VER #ifdef WIN32 char* timeBuf = ctime(&unixTime); #else diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index cbdedff9..07ee68fa 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2510,7 +2510,7 @@ eventWorkerThread(MmsMapping* self) while (running) { processPeriodicTasks(self); - Thread_sleep(10); /* hand-over control to other threads */ + Thread_sleep(1); /* hand-over control to other threads */ running = self->reportThreadRunning; } diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 2bc0c150..4dede146 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -83,6 +83,8 @@ struct sMmsServer { Map valueCaches; bool isLocked; + ByteBuffer* reportBuffer; /* global buffer for encoding reports */ + #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore modelMutex; #endif diff --git a/src/mms/iso_mms/server/mms_information_report.c b/src/mms/iso_mms/server/mms_information_report.c index 41972b4d..eee0bb25 100644 --- a/src/mms/iso_mms/server/mms_information_report.c +++ b/src/mms/iso_mms/server/mms_information_report.c @@ -1,7 +1,7 @@ /* * mms_information_report.c * - * Copyright 2013 Michael Zillgith + * Copyright 2013, 2015 Michael Zillgith * * This file is part of libIEC61850. * @@ -49,9 +49,18 @@ MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConn uint32_t informationReportSize = 1 + BerEncoder_determineLengthSize(informationReportContentSize) + informationReportContentSize; + uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize); + + if (completeMessageSize > self->maxPduSize) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, self->maxPduSize); + + goto exit_function; + } + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReportSingle variable: %s\n", itemId); - ByteBuffer* reportBuffer = ByteBuffer_create(NULL, self->maxPduSize); + ByteBuffer* reportBuffer = self->server->reportBuffer; uint8_t* buffer = reportBuffer->buffer; int bufPos = 0; @@ -74,7 +83,8 @@ MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConn IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode); - ByteBuffer_destroy(reportBuffer); +exit_function: + return; } void @@ -132,8 +142,17 @@ MmsServerConnection_sendInformationReportListOfVariables( uint32_t informationReportSize = 1 + BerEncoder_determineLengthSize(informationReportContentSize) + informationReportContentSize; + uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize); + + if (completeMessageSize > self->maxPduSize) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, self->maxPduSize); + + goto exit_function; + } + /* encode message */ - ByteBuffer* reportBuffer = ByteBuffer_create(NULL, self->maxPduSize); + ByteBuffer* reportBuffer = self->server->reportBuffer; uint8_t* buffer = reportBuffer->buffer; int bufPos = 0; @@ -145,8 +164,6 @@ MmsServerConnection_sendInformationReportListOfVariables( /* encode list of variable access specifications */ bufPos = BerEncoder_encodeTL(0xa0, listOfVariableSize, buffer, bufPos); - - specElement = LinkedList_getNext(variableAccessDeclarations); i = 0; @@ -196,7 +213,8 @@ MmsServerConnection_sendInformationReportListOfVariables( IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode); - ByteBuffer_destroy(reportBuffer); +exit_function: + return; } @@ -240,9 +258,18 @@ MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, c informationReportSize = 1 + informationReportContentSize + BerEncoder_determineLengthSize(informationReportContentSize); + uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize); + + if (completeMessageSize > self->maxPduSize) { + if (DEBUG_MMS_SERVER) + printf("MMS_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, self->maxPduSize); + + goto exit_function; + } + if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReport: %i items\n", variableCount); - ByteBuffer* reportBuffer = ByteBuffer_create(NULL, self->maxPduSize); + ByteBuffer* reportBuffer = self->server->reportBuffer; uint8_t* buffer = reportBuffer->buffer; int bufPos = 0; @@ -272,7 +299,8 @@ MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, c IsoConnection_sendMessage(self->isoConnection, reportBuffer, false); - ByteBuffer_destroy(reportBuffer); +exit_function: + return; } diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index f1339fff..30cf3436 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -55,9 +55,8 @@ addNamedVariableValue(MmsVariableSpecification* namedVariable, MmsServerConnecti value = mmsServer_getValue(connection->server, domain, itemId, connection); - if (value != NULL) { - return value; - } + if (value != NULL) + goto exit_function; else { int componentCount = namedVariable->typeSpec.structure.elementCount; @@ -92,6 +91,7 @@ addNamedVariableValue(MmsVariableSpecification* namedVariable, MmsServerConnecti value = mmsServer_getValue(connection->server, domain, itemId, connection); } +exit_function: return value; } @@ -153,13 +153,15 @@ static MmsValue* getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecification* namedVariable, MmsValue* structuredValue) { + MmsValue* retValue = NULL; + if (isAccessToArrayComponent(alternateAccess)) { Identifier_t component = alternateAccess->list.array[0]->choice.unnamed->choice.selectAlternateAccess.alternateAccess ->list.array[0]->choice.unnamed->choice.selectAccess.choice.component; if (component.size > 129) - return NULL; + goto exit_function; int elementCount = namedVariable->typeSpec.structure.elementCount; @@ -172,12 +174,16 @@ getComponentOfArrayElement(AlternateAccess_t* alternateAccess, MmsVariableSpecif component.size) == 0) { MmsValue* value = MmsValue_getElement(structuredValue, i); - return value; + + retValue = value; + + goto exit_function; } } } - return NULL; +exit_function: + return retValue; } static void @@ -246,6 +252,7 @@ alternateArrayAccess(MmsServerConnection connection, } else { // invalid access if (DEBUG_MMS_SERVER) printf("Invalid alternate access\n"); + appendErrorToResultList(values, 10 /* object-non-existant*/); } } @@ -339,8 +346,10 @@ encodeVariableAccessSpecification(VarAccessSpec* accessSpec, uint8_t* buffer, in varAccessSpecSize += 1 + BerEncoder_determineLengthSize(varAccessSpecLength); - if (encode == false) - return varAccessSpecSize; + if (encode == false) { + bufPos = varAccessSpecSize; + goto exit_function; + } /* encode to buffer */ bufPos = BerEncoder_encodeTL(0xa0, varAccessSpecLength, buffer, bufPos); @@ -367,6 +376,7 @@ encodeVariableAccessSpecification(VarAccessSpec* accessSpec, uint8_t* buffer, in bufPos = BerEncoder_encodeStringWithTag(0x1a, accessSpec->itemId, buffer, bufPos); } +exit_function: return bufPos; } @@ -424,7 +434,8 @@ encodeReadResponse(MmsServerConnection connection, mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_SERVICE_OTHER); - return; + + goto exit_function; } /* encode message */ @@ -465,6 +476,8 @@ encodeReadResponse(MmsServerConnection connection, if (DEBUG_MMS_SERVER) printf("MMS read: sent message for request with id %u (size = %i)\n", invokeId, bufPos); +exit_function: + return; } static void diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index 44f19926..dc01e8e6 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -1,7 +1,7 @@ /* * mms_server.c * - * Copyright 2013, 2014 Michael Zillgith + * Copyright 2013, 2014, 2015 Michael Zillgith * * This file is part of libIEC61850. * @@ -59,6 +59,8 @@ MmsServer_create(IsoServer isoServer, MmsDevice* device) self->valueCaches = createValueCaches(device); self->isLocked = false; + self->reportBuffer = ByteBuffer_create(NULL, CONFIG_MMS_MAXIMUM_PDU_SIZE); + #if (CONFIG_MMS_THREADLESS_STACK != 1) self->modelMutex = Semaphore_create(1); @@ -150,6 +152,8 @@ MmsServer_destroy(MmsServer self) Semaphore_destroy(self->modelMutex); #endif + ByteBuffer_destroy(self->reportBuffer); + GLOBAL_FREEMEM(self); }