- fixed - MMS server: messages can be corrupted when TCP buffer is full (LIB61850-385)

pull/437/merge
Michael Zillgith 3 years ago
parent a385a74c4d
commit 76fd58e9be

@ -101,6 +101,7 @@ printRawMmsMessage(void* parameter, uint8_t* message, int messageLength, bool re
int main(int argc, char** argv)
{
int returnCode = 0;
char* hostname = StringUtils_copyString("localhost");
int tcpPort = 102;
@ -213,6 +214,10 @@ int main(int argc, char** argv)
if (!MmsConnection_connect(con, &error, hostname, tcpPort)) {
printf("MMS connect failed!\n");
if (error != MMS_ERROR_NONE)
returnCode = error;
goto exit;
}
else
@ -222,6 +227,9 @@ int main(int argc, char** argv)
MmsServerIdentity* identity =
MmsConnection_identify(con, &error);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (identity != NULL) {
printf("\nServer identity:\n----------------\n");
printf(" vendor:\t%s\n", identity->vendorName);
@ -235,14 +243,23 @@ int main(int argc, char** argv)
if (readDeviceList) {
printf("\nDomains present on server:\n--------------------------\n");
LinkedList nameList = MmsConnection_getDomainNames(con, &error);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (nameList) {
LinkedList_printStringList(nameList);
LinkedList_destroy(nameList);
}
}
if (getDeviceDirectory) {
LinkedList variableList = MmsConnection_getDomainVariableNames(con, &error,
domainName);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList) {
LinkedList element = LinkedList_getNext(variableList);
@ -264,6 +281,9 @@ int main(int argc, char** argv)
variableList = MmsConnection_getDomainJournals(con, &error, domainName);
if (error != MMS_ERROR_NONE)
returnCode = error;
if (variableList) {
LinkedList element = variableList;
@ -309,6 +329,9 @@ int main(int argc, char** argv)
LinkedList journalEntries = MmsConnection_readJournalTimeRange(con, &error, logDomain, logName, startTime, endTime,
&moreFollows);
if (error != MMS_ERROR_NONE)
returnCode = error;
MmsValue_delete(startTime);
MmsValue_delete(endTime);
@ -375,6 +398,8 @@ int main(int argc, char** argv)
if (error != MMS_ERROR_NONE) {
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
printf("Read SUCCESS\n");
@ -403,6 +428,8 @@ int main(int argc, char** argv)
if (error != MMS_ERROR_NONE) {
printf("Reading variable failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
printf("Read SUCCESS\n");
@ -421,6 +448,8 @@ int main(int argc, char** argv)
if (error != MMS_ERROR_NONE) {
printf("Reading variable list directory failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
LinkedList varListElem = LinkedList_getNext(varListDir);
@ -454,12 +483,19 @@ int main(int argc, char** argv)
char* continueAfter = NULL;
while (MmsConnection_getFileDirectory(con, &error, "", continueAfter, mmsFileDirectoryHandler, lastName)) {
if (error != MMS_ERROR_NONE)
returnCode = error;
continueAfter = lastName;
}
}
if (getFileAttributes) {
MmsConnection_getFileDirectory(con, &error, filename, NULL, mmsGetFileAttributeHandler, NULL);
if (error != MMS_ERROR_NONE)
returnCode = error;
}
if (deleteFile) {
@ -467,6 +503,7 @@ int main(int argc, char** argv)
if (error != MMS_ERROR_NONE) {
printf("Delete file failed: (ERROR %i)\n", error);
returnCode = error;
}
else {
printf("File deleted\n");
@ -482,6 +519,6 @@ int main(int argc, char** argv)
MmsConnection_destroy(con);
return 0;
return returnCode;
}

@ -114,4 +114,7 @@ CotpConnection_getRemoteRef(CotpConnection* self);
LIB61850_INTERNAL int
CotpConnection_getLocalRef(CotpConnection* self);
LIB61850_INTERNAL void
CotpConnection_flushBuffer(CotpConnection* self);
#endif /* COTP_H_ */

@ -5,7 +5,7 @@
*
* Partial implementation of the ISO 8073 COTP (ISO TP0) protocol for MMS.
*
* Copyright 2013-2018 Michael Zillgith
* Copyright 2013-2023 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -174,6 +174,38 @@ writeToSocket(CotpConnection* self, uint8_t* buf, int size)
#endif
}
static bool
flushBuffer(CotpConnection* self)
{
if (self->socketExtensionBufferFill > 0) {
int sentBytes = writeToSocket(self, self->socketExtensionBuffer, self->socketExtensionBufferFill);
if (sentBytes > 0) {
if (sentBytes != self->socketExtensionBufferFill) {
int target = 0;
int i;
uint8_t* buf = self->socketExtensionBuffer;
for (i = sentBytes; i < self->socketExtensionBufferFill; i++) {
buf[target++] = buf[i];
}
self->socketExtensionBufferFill = self->socketExtensionBufferFill - sentBytes;
}
else {
self->socketExtensionBufferFill = 0;
}
}
else if (sentBytes == -1) {
return false;
}
}
return true;
}
static bool
sendBuffer(CotpConnection* self)
{
@ -182,7 +214,15 @@ sendBuffer(CotpConnection* self)
bool retVal = false;
int sentBytes = writeToSocket(self, buffer, remainingSize);
if (flushBuffer(self) == false) {
goto exit_function;
}
int sentBytes = 0;
if (self->socketExtensionBufferFill == 0) {
sentBytes = writeToSocket(self, buffer, remainingSize);
}
if (sentBytes == -1)
goto exit_function;
@ -215,33 +255,6 @@ exit_function:
return retVal;
}
static void
flushBuffer(CotpConnection* self)
{
if (self->socketExtensionBufferFill > 0) {
int sentBytes = writeToSocket(self, self->socketExtensionBuffer, self->socketExtensionBufferFill);
if (sentBytes > 0) {
if (sentBytes != self->socketExtensionBufferFill) {
int target = 0;
int i;
uint8_t* buf = self->socketExtensionBuffer;
for (i = sentBytes; i < self->socketExtensionBufferFill; i++) {
buf[target++] = buf[i];
}
self->socketExtensionBufferFill = self->socketExtensionBufferFill - sentBytes;
}
else {
self->socketExtensionBufferFill = 0;
}
}
}
}
CotpIndication
CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
{
@ -262,7 +275,9 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
int totalSize = (fragments * (COTP_DATA_HEADER_SIZE + 4)) + payload->length;
/* try to flush extension buffer */
flushBuffer(self);
if (flushBuffer(self) == false) {
return COTP_ERROR;
}
/* check if totalSize will fit in extension buffer */
if (self->socketExtensionBuffer) {
@ -281,7 +296,7 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
int currentChainIndex = 0;
if (DEBUG_COTP)
printf("\nCOTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength);
printf("COTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength);
uint8_t* buffer = self->writeBuffer->buffer;
@ -307,7 +322,7 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
if (currentChainIndex >= currentChain->partLength) {
currentChain = currentChain->nextPart;
if (DEBUG_COTP)
printf("\nCOTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength);
printf("COTP: nextBufferPart: len:%i partLen:%i\n", currentChain->length, currentChain->partLength);
currentChainIndex = 0;
}
@ -756,6 +771,13 @@ readFromSocket(CotpConnection* self, uint8_t* buf, int size)
#endif
}
void
CotpConnection_flushBuffer(CotpConnection* self)
{
if (self->socketExtensionBufferFill > 0)
flushBuffer(self);
}
TpktState
CotpConnection_readToTpktBuffer(CotpConnection* self)
{
@ -765,6 +787,14 @@ CotpConnection_readToTpktBuffer(CotpConnection* self)
assert (bufferSize > 4);
if (self->socketExtensionBufferFill > 0) {
if (flushBuffer(self) == false)
goto exit_error;
if (self->socketExtensionBufferFill > 0)
goto exit_waiting;
}
int readBytes;
if (bufPos < 4) {

@ -1,7 +1,7 @@
/*
* iso_connection.c
*
* Copyright 2013-2022 Michael Zillgith
* Copyright 2013-2023 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -160,6 +160,8 @@ IsoConnection_removeFromHandleSet(const IsoConnection self, HandleSet handles)
void
IsoConnection_callTickHandler(IsoConnection self)
{
CotpConnection_flushBuffer(self->cotpConnection);
if (self->tickHandler) {
self->tickHandler(self->handlerParameter);
}
@ -171,10 +173,7 @@ IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
#if (CONFIG_MMS_SINGLE_THREADED != 1)
if (isSingleThread == false) {
/* call tick handler */
if (self->tickHandler) {
self->tickHandler(self->handlerParameter);
}
IsoConnection_callTickHandler(self);
if (Handleset_waitReady(self->handleSet, 10) < 1)
goto exit_function;

@ -455,7 +455,6 @@ exit_function:
return success;
}
/** used by single and multi-threaded versions
*
* \param isSingleThread when true server is running in single thread or non-thread mode

Loading…
Cancel
Save