- implemented server side obtain file procedure

This commit is contained in:
Michael Zillgith 2016-10-30 20:50:34 +01:00
parent 4d5a9e27a1
commit d15e2c73b1
20 changed files with 1097 additions and 82 deletions

View file

@ -179,6 +179,9 @@
/* Maximum number of the members in a data set (named variable list) */
#define CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS 100
/* maximum number of contemporary file upload tasks (obtainFile) per server instance */
#define CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS 5
/* Definition of supported services */
#define MMS_DEFAULT_PROFILE 1
@ -194,6 +197,7 @@
#define MMS_STATUS_SERVICE 1
#define MMS_IDENTIFY_SERVICE 1
#define MMS_FILE_SERVICE 1
#define MMS_OBTAIN_FILE_SERVICE 1
#endif /* MMS_DEFAULT_PROFILE */
#if (MMS_WRITE_SERVICE != 1)
@ -216,7 +220,7 @@
/* use short FC defines as in old API */
#define CONFIG_PROVIDE_OLD_FC_DEFINES 0
/* Support user acccess to raw messages */
/* Support user access to raw messages */
#define CONFIG_MMS_RAW_MESSAGE_LOGGING 1
#endif /* STACK_CONFIG_H_ */

View file

@ -186,6 +186,7 @@
#define MMS_STATUS_SERVICE 1
#define MMS_IDENTIFY_SERVICE 1
#define MMS_FILE_SERVICE 1
#define MMS_OBTAIN_FILE_SERVICE 1
#endif /* MMS_DEFAULT_PROFILE */
#if (MMS_WRITE_SERVICE != 1)

View file

@ -35,6 +35,7 @@ DataAttribute* toDataAttribute(ModelNode * MN)
%include "iec61850_server.h"
%include "iec61850_dynamic_model.h"
%include "iec61850_cdc.h"
%include "linked_list.h
ModelNode* toModelNode(LogicalNode *);
ModelNode* toModelNode(DataObject *);
DataAttribute* toDataAttribute(DataObject *);

View file

@ -3021,6 +3021,9 @@ processPeriodicTasks(MmsMapping* self)
#if (CONFIG_IEC61850_LOG_SERVICE == 1)
Logging_processIntegrityLogs(self, currentTimeInMs);
#endif
/* handle low priority MMS backgound tasks (like file upload...) */
MmsServer_handleBackgroundTasks(self->mmsServer);
}
void

View file

@ -661,9 +661,13 @@ typedef void
typedef void
(*MmsFileReadHandler) (void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t bytesReceived);
/**
* \brief open a file for read
*
* \param self MmsConnection instance to operate on
* \param mmsError user provided variable to store error code
*
* \return the FRSM ID (file read state machine) handle of the opened file
*/
int32_t

View file

@ -124,6 +124,17 @@ typedef MmsError (*MmsNamedVariableListChangedHandler)(void* parameter, bool cre
void
MmsServer_installVariableListChangedHandler(MmsServer self, MmsNamedVariableListChangedHandler handler, void* parameter);
typedef bool (*MmsObtainFileHandler)(void* parameter, MmsServerConnection connection, const char* sourceFilename, const char* destinationFilename);
void
MmsServer_installObtainFileHandler(MmsServer self, MmsObtainFileHandler handler, void* parameter);
typedef void (*MmsGetFileCompleteHandler)(void* parameter, MmsServerConnection connection, const char* destinationFilename);
void
MmsServer_installGetFileCompleteHandler(MmsServer self, MmsGetFileCompleteHandler handler, void* parameter);
/**
* \brief lock the cached server data model
*
@ -209,6 +220,14 @@ MmsServer_waitReady(MmsServer self, unsigned int timeoutMs);
void
MmsServer_handleIncomingMessages(MmsServer self);
/**
* \brief Handle MmsServer background task
*
* \param self the MmsServer instance to operate on
*/
void
MmsServer_handleBackgroundTasks(MmsServer self);
/**
* \brief Stop the server (for non-threaded operation mode)
*

View file

@ -32,6 +32,8 @@
#include "hal_thread.h"
#include "mms_common_internal.h"
#ifndef CONFIG_MMS_RAW_MESSAGE_LOGGING
#define CONFIG_MMS_RAW_MESSAGE_LOGGING 0
#endif
@ -96,6 +98,11 @@ struct sMmsConnection {
/* state of an active connection conclude/release process */
int concludeState;
#if (MMS_OBTAIN_FILE_SERVICE == 1)
int32_t nextFrsmId;
MmsFileReadStateMachine frsms[CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION];
#endif
};
@ -231,15 +238,9 @@ mmsClient_parseStatusResponse(MmsConnection self, int* vmdLogicalStatus, int* vm
void
mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName, uint32_t initialPosition);
bool
mmsClient_parseFileOpenResponse(MmsConnection self, int32_t* frsmId, uint32_t* fileSize, uint64_t* lastModified);
void
mmsClient_createFileReadRequest(uint32_t invokeId, ByteBuffer* request, int32_t frsmId);
bool
mmsClient_parseFileReadResponse(MmsConnection self, int32_t frsmId, bool* moreFollows, MmsFileReadHandler handler, void* handlerParameter);
void
mmsClient_createFileCloseRequest(uint32_t invokeId, ByteBuffer* request, int32_t frsmId);
@ -280,4 +281,25 @@ mmsClient_createReadJournalRequestStartAfter(uint32_t invokeId, ByteBuffer* requ
bool
mmsClient_parseReadJournalResponse(MmsConnection self, bool* moreFollows, LinkedList* result);
void
mmsClient_handleFileOpenRequest(MmsConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId, ByteBuffer* response);
void
mmsClient_handleFileReadRequest(
MmsConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId,
ByteBuffer* response);
void
mmsClient_handleFileReadRequest(
MmsConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId,
ByteBuffer* response);
#endif /* MMS_MSG_INTERNAL_H_ */

View file

@ -27,6 +27,50 @@
#include "mms_value.h"
#include "MmsPdu.h"
#include "conversions.h"
#include "byte_buffer.h"
#if (MMS_FILE_SERVICE == 1)
#ifndef CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION
#define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5
#endif
#include "hal_filesystem.h"
typedef struct {
int32_t frsmId;
uint32_t readPosition;
uint32_t fileSize;
FileHandle fileHandle;
} MmsFileReadStateMachine;
//TODO already defined in public API mms_connection.h
typedef void
(*MmsFileReadHandler) (void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t bytesReceived);
bool
mmsMsg_parseFileOpenResponse(uint8_t* buffer, int bufPos, int maxBufPos, int32_t* frsmId, uint32_t* fileSize, uint64_t* lastModified);
bool
mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, int32_t frsmId, bool* moreFollows, MmsFileReadHandler handler, void* handlerParameter);
void
mmsMsg_createFileReadResponse(int maxPduSize, uint32_t invokeId, ByteBuffer* response, MmsFileReadStateMachine* frsm);
void
mmsMsg_createFileCloseResponse(uint32_t invokeId, ByteBuffer* response);
#endif /* (MMS_FILE_SERVICE == 1) */
typedef struct sMmsServiceError
{
int errorClass;
int errorCode;
} MmsServiceError;
int
mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, MmsServiceError* serviceError);
MmsValue*
mmsMsg_parseDataElement(Data_t* dataElement);

View file

@ -98,6 +98,9 @@ MmsServerConnection_sendWriteResponse(MmsServerConnection self, uint32_t invokeI
uint32_t
MmsServerConnection_getLastInvokeId(MmsServerConnection self);
uint32_t
MmsServerConnection_getNextRequestInvokeId(MmsServerConnection self);
#endif /* MMS_SERVER_CONNECTION_H_ */

View file

@ -26,7 +26,7 @@
#include "libiec61850_platform_includes.h"
#include <MmsPdu.h>
#include "MmsPdu.h"
#include "mms_common.h"
#include "mms_indication.h"
#include "mms_server_connection.h"
@ -44,6 +44,11 @@
#include "ber_encoder.h"
#include "ber_decode.h"
#if (MMS_OBTAIN_FILE_SERVICE == 1)
#include "hal_filesystem.h"
#endif
#ifndef DEBUG_MMS_SERVER
#define DEBUG_MMS_SERVER 0
#endif
@ -60,6 +65,42 @@
#define MMS_FILE_SERVICE 1
#endif
#ifndef CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS
#define CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS 5
#endif
#if (MMS_OBTAIN_FILE_SERVICE == 1)
#define MMS_FILE_UPLOAD_STATE_NOT_USED 0
#define MMS_FILE_UPLOAD_STATE_READY 1
#define MMS_FILE_UPLOAD_STATE_FILE_OPEN_SENT 2
#define MMS_FILE_UPLOAD_STATE_SEND_FILE_READ 3
#define MMS_FILE_UPLOAD_STATE_FILE_READ_SENT 4
#define MMS_FILE_UPLOAD_STATE_SEND_FILE_CLOSE 5
#define MMS_FILE_UPLOAD_STATE_FILE_CLOSE_SENT 6
#define MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_SOURCE 8
#define MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_DESTINATION 9
#define MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_RESPONSE 10
typedef struct sMmsObtainFileTask* MmsObtainFileTask;
struct sMmsObtainFileTask {
MmsServerConnection connection;
uint32_t lastRequestInvokeId;
uint32_t obtainFileRequestInvokeId;
FileHandle fileHandle;
char destinationFilename[256];
uint64_t nextTimeout;
int32_t frmsId;
int state;
};
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
struct sMmsServer {
IsoServer isoServer;
MmsDevice* device;
@ -83,7 +124,10 @@ struct sMmsServer {
Map valueCaches;
bool isLocked;
ByteBuffer* reportBuffer; /* global buffer for encoding reports */
ByteBuffer* transmitBuffer; /* global buffer for encoding reports, delayed responses... */
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore transmitBufferMutex;
#endif
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore modelMutex;
@ -101,24 +145,18 @@ struct sMmsServer {
char* modelName;
char* revision;
#endif /* MMS_IDENTIFY_SERVICE == 1 */
};
#if (MMS_FILE_SERVICE == 1)
#if (MMS_OBTAIN_FILE_SERVICE == 1)
MmsObtainFileHandler obtainFileHandler;
void* obtainFileHandlerParameter;
#ifndef CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION
#define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5
MmsGetFileCompleteHandler getFileCompleteHandler;
void* getFileCompleteHandlerParameter;
struct sMmsObtainFileTask fileUploadTasks[CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS];
#endif
#include "hal_filesystem.h"
typedef struct {
int32_t frsmId;
uint32_t readPosition;
uint32_t fileSize;
FileHandle fileHandle;
} MmsFileReadStateMachine;
#endif /* (MMS_FILE_SERVICE == 1) */
};
struct sMmsServerConnection {
int maxServOutstandingCalling;
@ -129,6 +167,10 @@ struct sMmsServerConnection {
MmsServer server;
uint32_t lastInvokeId;
#if (MMS_OBTAIN_FILE_SERVICE == 1)
uint32_t lastRequestInvokeId; /* only used by obtainFile service */
#endif
#if (MMS_DYNAMIC_DATA_SETS == 1)
LinkedList /*<MmsNamedVariableList>*/namedVariableLists; /* aa-specific named variable lists */
#endif
@ -137,13 +179,25 @@ struct sMmsServerConnection {
int32_t nextFrsmId;
MmsFileReadStateMachine frsms[CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION];
#endif
};
#if (MMS_OBTAIN_FILE_SERVICE == 1)
MmsObtainFileTask
MmsServer_getObtainFileTask(MmsServer self);
#endif
ByteBuffer*
MmsServer_reserveTransmitBuffer(MmsServer self);
void
MmsServer_releaseTransmitBuffer(MmsServer self);
/* write_out function required for ASN.1 encoding */
int
mmsServer_write_out(const void *buffer, size_t size, void *app_key);
void
mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
@ -275,6 +329,13 @@ mmsServer_handleFileCloseRequest(
uint32_t invokeId,
ByteBuffer* response);
void
mmsServer_handleObtainFileRequest(
MmsServerConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId,
ByteBuffer* response);
int
mmsServer_isIndexAccess(AlternateAccess_t* alternateAccess);

View file

@ -327,7 +327,7 @@ sendRequestAndWaitForResponse(MmsConnection self, uint32_t invokeId, ByteBuffer*
if (!success) {
if (DEBUG_MMS_CLIENT)
printf("TIMEOUT for request %u: \n", invokeId);
printf("MMS_CLIENT: TIMEOUT for request %u: \n", invokeId);
self->lastResponseError = MMS_ERROR_SERVICE_TIMEOUT;
}
@ -372,12 +372,6 @@ waitUntilLastResponseHasBeenProcessed(MmsConnection self)
}
}
typedef struct sMmsServiceError
{
int errorClass;
int errorCode;
} MmsServiceError;
static MmsError
convertServiceErrorToMmsError(MmsServiceError serviceError)
{
@ -519,12 +513,9 @@ parseServiceError(uint8_t* buffer, int bufPos, int maxLength, MmsServiceError* e
return bufPos;
}
static int
parseConfirmedErrorPDU(ByteBuffer* message, uint32_t* invokeId, MmsServiceError* serviceError)
int
mmsMsg_parseConfirmedErrorPDU(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t* invokeId, MmsServiceError* serviceError)
{
uint8_t* buffer = message->buffer;
int maxBufPos = message->size;
int bufPos = 0;
int length;
uint8_t tag = buffer[bufPos++];
@ -675,7 +666,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
uint32_t invokeId;
MmsServiceError serviceError = {0, 0};
if (parseConfirmedErrorPDU(payload, &invokeId, &serviceError) < 0) {
if (mmsMsg_parseConfirmedErrorPDU(payload->buffer, 0, payload->size, &invokeId, &serviceError) < 0) {
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: Error parsing confirmedErrorPDU!\n");
}
@ -742,6 +733,124 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
else
goto exit_with_error;
}
#if (MMS_OBTAIN_FILE_SERVICE == 1)
else if (tag == 0xa0) {
printf("MMS_CLIENT: received confirmed request PDU (size=%i)\n", payload->size);
// TODO handle confirmed request PDU only when obtainFile service is enabled
// TODO extract function
int bufPos = 1;
int length;
bufPos = BerDecoder_decodeLength(buf, &length, bufPos, payload->size);
uint32_t invokeId;
while (bufPos < payload->size) {
uint8_t tag = buf[bufPos++];
bool extendedTag = false;
if ((tag & 0x1f) == 0x1f) {
extendedTag = true;
tag = buf[bufPos++];
}
bufPos = BerDecoder_decodeLength(buf, &length, bufPos, payload->size);
// printf("tag:%02x len:%i\n", tag, length);
// if (bufPos < 0) {
// mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response);
// return;
// }
if (extendedTag) {
switch(tag) {
#if (MMS_FILE_SERVICE == 1)
case 0x48: /* file-open-request */
{
printf("MMS_CLIENT: received file-open-request\n");
ByteBuffer* response = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
mmsClient_handleFileOpenRequest(self, buf, bufPos, bufPos + length, invokeId, response);
IsoClientConnection_sendMessage(self->isoClient, response);
IsoClientConnection_releaseReceiveBuffer(self->isoClient);
}
break;
case 0x49: /* file-read-request */
{
printf("MMS_CLIENT: received file-read-request\n");
ByteBuffer* response = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
mmsClient_handleFileReadRequest(self, buf, bufPos, bufPos + length, invokeId, response);
IsoClientConnection_sendMessage(self->isoClient, response);
IsoClientConnection_releaseReceiveBuffer(self->isoClient);
}
break;
case 0x4a: /* file-close-request */
{
printf("MMS_CLIENT: received file-close-request\n");
ByteBuffer* response = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
mmsClient_handleFileCloseRequest(self, buf, bufPos, bufPos + length, invokeId, response);
IsoClientConnection_sendMessage(self->isoClient, response);
IsoClientConnection_releaseReceiveBuffer(self->isoClient);
}
break;
#endif /* MMS_FILE_SERVICE == 1 */
default:
// mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response);
printf("MMS_CLIENT: unexpected message from server!\n");
IsoClientConnection_releaseReceiveBuffer(self->isoClient);
break;
}
}
else {
switch(tag) {
case 0x02: /* invoke Id */
invokeId = BerDecoder_decodeUint32(buf, length, bufPos);
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: received request with invokeId: %i\n", invokeId);
self->lastInvokeId = invokeId;
break;
default:
// mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response);
printf("MMS_CLIENT: unexpected message from server!\n");
IsoClientConnection_releaseReceiveBuffer(self->isoClient);
goto exit_with_error;
break;
}
}
bufPos += length;
}
}
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: LEAVE mmsIsoCallback - OK\n");
@ -752,6 +861,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
if (DEBUG_MMS_CLIENT)
printf("received malformed message from server!\n");
IsoClientConnection_releaseReceiveBuffer(self->isoClient);
@ -1811,7 +1921,12 @@ MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, const char* filen
if (self->lastResponseError != MMS_ERROR_NONE)
*mmsError = self->lastResponseError;
else if (responseMessage != NULL) {
if (mmsClient_parseFileOpenResponse(self, &frsmId, fileSize, lastModified) == false)
uint8_t* buffer = self->lastResponse->buffer;
int maxBufPos = self->lastResponse->size;
int bufPos = self->lastResponseBufPos;
if (mmsMsg_parseFileOpenResponse(buffer, bufPos, maxBufPos, &frsmId, fileSize, lastModified) == false)
*mmsError = MMS_ERROR_PARSING_RESPONSE;
}
@ -1890,7 +2005,11 @@ MmsConnection_fileRead(MmsConnection self, MmsError* mmsError, int32_t frsmId, M
if (self->lastResponseError != MMS_ERROR_NONE)
*mmsError = self->lastResponseError;
else if (responseMessage != NULL) {
if (mmsClient_parseFileReadResponse(self, frsmId, &moreFollows, handler, handlerParameter) == false)
uint8_t* buffer = self->lastResponse->buffer;
int maxBufPos = self->lastResponse->size;
int bufPos = self->lastResponseBufPos;
if (mmsMsg_parseFileReadResponse(buffer, bufPos, maxBufPos, frsmId, &moreFollows, handler, handlerParameter) == false)
*mmsError = MMS_ERROR_PARSING_RESPONSE;
}
@ -1968,14 +2087,17 @@ MmsConnection_obtainFile(MmsConnection self, MmsError* mmsError, const char* sou
uint32_t invokeId = getNextInvokeId(self);
//TODO enable file service
mmsClient_createObtainFileRequest(invokeId, payload, sourceFile, destinationFile);
sendRequestAndWaitForResponse(self, invokeId, payload);
ByteBuffer* responseMessage = sendRequestAndWaitForResponse(self, invokeId, payload);
if (self->lastResponseError != MMS_ERROR_NONE)
*mmsError = self->lastResponseError;
/* nothing to do - response contains no data to evaluate */
releaseResponse(self);
if (self->associationState == MMS_STATE_CLOSED)

View file

@ -1,7 +1,7 @@
/*
* mms_client_files.c
*
* Copyright 2013, 2014 Michael Zillgith
* Copyright 2013 - 2016 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -32,6 +32,222 @@
#include "ber_decode.h"
#include "conversions.h"
#if (MMS_OBTAIN_FILE_SERVICE == 1)
static MmsFileReadStateMachine*
getFreeFrsm(MmsConnection connection)
{
int i;
MmsFileReadStateMachine* freeFrsm = NULL;
for (i = 0; i < CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION; i++) {
if (connection->frsms[i].fileHandle == NULL) {
freeFrsm = &(connection->frsms[i]);
break;
}
}
return freeFrsm;
}
static MmsFileReadStateMachine*
getFrsm(MmsConnection connection, int32_t frsmId)
{
int i;
MmsFileReadStateMachine* frsm = NULL;
for (i = 0; i < CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION; i++) {
if (connection->frsms[i].fileHandle != NULL) {
if (connection->frsms[i].frsmId == frsmId) {
frsm = &(connection->frsms[i]);
break;
}
}
}
return frsm;
}
static int32_t
getNextFrsmId(MmsConnection connection)
{
uint32_t nextFrsmId = connection->nextFrsmId;
connection->nextFrsmId++;
return nextFrsmId;
}
//TODO remove redundancy (with server implementation)
static void
createExtendedFilename(char* extendedFileName, char* fileName)
{
strcpy(extendedFileName, CONFIG_VIRTUAL_FILESTORE_BASEPATH);
strncat(extendedFileName, fileName, sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256);
}
//TODO remove redundancy (with server implementation)
static FileHandle
openFile(char* fileName, bool readWrite)
{
char extendedFileName[sizeof(CONFIG_VIRTUAL_FILESTORE_BASEPATH) + 256];
createExtendedFilename(extendedFileName, fileName);
printf("open file %s\n", extendedFileName);
return FileSystem_openFile(extendedFileName, readWrite);
}
//TODO remove redundancy (with server implementation)
static bool
parseFileName(char* filename, uint8_t* buffer, int* bufPos, int maxBufPos , uint32_t invokeId, ByteBuffer* response)
{
uint8_t tag = buffer[(*bufPos)++];
int length;
if (tag != 0x19) {
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
return false;
}
*bufPos = BerDecoder_decodeLength(buffer, &length, *bufPos, maxBufPos);
if (*bufPos < 0) {
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
return false;
}
if (length > 255) {
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
return false;
}
memcpy(filename, buffer + *bufPos, length);
filename[length] = 0;
*bufPos += length;
return true;
}
void
mmsClient_handleFileOpenRequest(
MmsConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId, ByteBuffer* response)
{
char filename[256];
bool hasFileName = false;
uint32_t filePosition = 0;
while (bufPos < maxBufPos) {
uint8_t tag = buffer[bufPos++];
int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) goto exit_reject_invalid_pdu;
switch(tag) {
case 0xa0: /* filename */
if (!parseFileName(filename, buffer, &bufPos, bufPos + length, invokeId, response))
return;
hasFileName = true;
break;
case 0x81: /* initial position */
filePosition = BerDecoder_decodeUint32(buffer, length, bufPos);
bufPos += length;
break;
default: /* unrecognized parameter */
bufPos += length;
goto exit_reject_invalid_pdu;
}
}
if (hasFileName) {
MmsFileReadStateMachine* frsm = getFreeFrsm(connection);
if (frsm != NULL) {
FileHandle fileHandle = openFile(filename, false);
if (fileHandle != NULL) {
frsm->fileHandle = fileHandle;
frsm->readPosition = filePosition;
frsm->frsmId = getNextFrsmId(connection);
mmsServer_createFileOpenResponse(invokeId, response, filename, frsm);
}
else
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);
}
else
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER);
}
else
goto exit_invalid_parameter;
return;
exit_invalid_parameter:
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
return;
exit_reject_invalid_pdu:
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
}
void
mmsClient_handleFileReadRequest(
MmsConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId,
ByteBuffer* response)
{
int32_t frsmId = (int32_t) BerDecoder_decodeUint32(buffer, maxBufPos - bufPos, bufPos);
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsClient_handleFileReadRequest read request for frsmId: %i\n", frsmId);
MmsFileReadStateMachine* frsm = getFrsm(connection, frsmId);
if (frsm != NULL)
mmsMsg_createFileReadResponse(connection, invokeId, response, frsm);
else
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_OTHER);
}
void
mmsClient_handleFileCloseRequest(
MmsConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId,
ByteBuffer* response)
{
int32_t frsmId = (int32_t) BerDecoder_decodeUint32(buffer, maxBufPos - bufPos, bufPos);
MmsFileReadStateMachine* frsm = getFrsm(connection, frsmId);
FileSystem_closeFile(frsm->fileHandle);
frsm->fileHandle = NULL;
frsm->frsmId = 0;
mmsMsg_createFileCloseResponse(invokeId, response);
}
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
void
mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName, uint32_t initialPosition)
{
@ -446,26 +662,23 @@ mmsClient_parseFileDirectoryResponse(MmsConnection self, MmsFileDirectoryHandler
}
bool
mmsClient_parseFileOpenResponse(MmsConnection self, int32_t* frsmId, uint32_t* fileSize, uint64_t* lastModified)
mmsMsg_parseFileOpenResponse(uint8_t* buffer, int bufPos, int maxBufPos, int32_t* frsmId, uint32_t* fileSize, uint64_t* lastModified)
{
uint8_t* buffer = self->lastResponse->buffer;
int maxBufPos = self->lastResponse->size;
int bufPos = self->lastResponseBufPos;
int length;
uint8_t tag = buffer[bufPos++];
if (tag != 0xbf) {
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileOpenResponse: unknown tag %02x\n", tag);
//if (DEBUG_MMS_CLIENT)
printf("MMS: mmsClient_parseFileOpenResponse: unknown tag %02x\n", tag);
return false;
}
tag = buffer[bufPos++];
if (tag != 0x48) {
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileOpenResponse: unknown tag %02x\n", tag);
//if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT: mmsClient_parseFileOpenResponse: unknown tag %02x\n", tag);
return false;
}
@ -477,7 +690,7 @@ mmsClient_parseFileOpenResponse(MmsConnection self, int32_t* frsmId, uint32_t* f
if (endPos > maxBufPos) {
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileOpenResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos);
printf("MMS_CLIENT/SERVER: mmsClient_parseFileOpenResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos);
return false;
}
@ -499,7 +712,7 @@ mmsClient_parseFileOpenResponse(MmsConnection self, int32_t* frsmId, uint32_t* f
default:
bufPos += length;
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileOpenResponse: message contains unknown tag %02x!\n", tag);
printf("MMS_CLIENT/SERVER: mmsClient_parseFileOpenResponse: message contains unknown tag %02x!\n", tag);
break;
}
}
@ -509,18 +722,15 @@ mmsClient_parseFileOpenResponse(MmsConnection self, int32_t* frsmId, uint32_t* f
bool
mmsClient_parseFileReadResponse(MmsConnection self, int32_t frsmId, bool* moreFollows, MmsFileReadHandler handler, void* handlerParameter)
mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, int frsmId, bool* moreFollows, MmsFileReadHandler handler, void* handlerParameter)
{
uint8_t* buffer = self->lastResponse->buffer;
int maxBufPos = self->lastResponse->size;
int bufPos = self->lastResponseBufPos;
int length;
uint8_t tag = buffer[bufPos++];
if (tag != 0xbf) {
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileReadResponse: unknown tag %02x\n", tag);
printf("MMS_CLIENT/SERVER: mmsClient_parseFileReadResponse: unknown tag %02x\n", tag);
return false;
}
@ -530,7 +740,7 @@ mmsClient_parseFileReadResponse(MmsConnection self, int32_t frsmId, bool* moreF
if (tag != 0x49) {
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileReadResponse: unknown tag %02x\n", tag);
printf("MMS_CLIENT/SERVER: mmsClient_parseFileReadResponse: unknown tag %02x\n", tag);
return false;
}
@ -542,7 +752,7 @@ mmsClient_parseFileReadResponse(MmsConnection self, int32_t frsmId, bool* moreF
if (endPos > maxBufPos) {
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileReadResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos);
printf("MMS_CLIENT/SERVER: mmsClient_parseFileReadResponse: message to short (length:%i maxBufPos:%i)!\n", length, maxBufPos);
return false;
}
@ -563,7 +773,7 @@ mmsClient_parseFileReadResponse(MmsConnection self, int32_t frsmId, bool* moreF
default:
bufPos += length;
if (DEBUG_MMS_CLIENT)
printf("mmsClient_parseFileReadResponse: message contains unknown tag %02x!\n", tag);
printf("MMS_CLIENT/SERVER: mmsClient_parseFileReadResponse: message contains unknown tag %02x!\n", tag);
return false;
}

View file

@ -110,8 +110,6 @@ encodeFileAttributes(uint8_t tag, uint32_t fileSize, char* gtString, uint8_t* bu
+ 2 + gtStringSize;
if (buffer == NULL) {
return fileAttributesSize;
}
else {
@ -180,8 +178,8 @@ deleteFile(char* fileName) {
return FileSystem_deleteFile(extendedFileName);
}
static void
createFileOpenResponse(uint32_t invokeId, ByteBuffer* response, char* fullPath, MmsFileReadStateMachine* frsm)
void
mmsServer_createFileOpenResponse(uint32_t invokeId, ByteBuffer* response, char* fullPath, MmsFileReadStateMachine* frsm)
{
uint64_t msTime;
@ -347,7 +345,7 @@ mmsServer_handleFileOpenRequest(
frsm->readPosition = filePosition;
frsm->frsmId = getNextFrsmId(connection);
createFileOpenResponse(invokeId, response, filename, frsm);
mmsServer_createFileOpenResponse(invokeId, response, filename, frsm);
}
else
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);
@ -370,9 +368,240 @@ exit_reject_invalid_pdu:
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
}
#if (MMS_OBTAIN_FILE_SERVICE == 1)
static void
createFileReadResponse(MmsServerConnection connection, uint32_t invokeId,
createObtainFileResponse(uint32_t invokeId, ByteBuffer* response)
{
createNullResponseExtendedTag(invokeId, response, 0x2e);
}
//#define MMS_FILE_UPLOAD_STATE_COMPLETE 11
void
mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
{
//send response message
/*
* states:
* 0 - no state / not used
* 1 -
* 2 - file open sent
* 3 - file read sent
* 4 - file close sent
*
*/
printf("mmsServer_fileUploadTask (%p) state=%i\n", task, task->state);
switch (task->state) {
case MMS_FILE_UPLOAD_STATE_NOT_USED: /* state: not-used */
break;
case MMS_FILE_UPLOAD_STATE_FILE_OPEN_SENT:
{
if (Hal_getTimeInMs() > task->nextTimeout) {
printf("MMS_SERVER: file open timeout!\n");
task->state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_RESPONSE;
}
}
break;
case MMS_FILE_UPLOAD_STATE_SEND_FILE_READ:
{
ByteBuffer* request = MmsServer_reserveTransmitBuffer(self);
task->lastRequestInvokeId = MmsServerConnection_getNextRequestInvokeId(task->connection);
mmsClient_createFileReadRequest(task->lastRequestInvokeId, request, task->frmsId);
IsoConnection_sendMessage(task->connection->isoConnection, request, false);
MmsServer_releaseTransmitBuffer(self);
task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */
task->state = MMS_FILE_UPLOAD_STATE_FILE_READ_SENT;
}
break;
case MMS_FILE_UPLOAD_STATE_FILE_READ_SENT:
if (Hal_getTimeInMs() > task->nextTimeout) {
printf("MMS_SERVER: file read timeout!\n");
task->state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_RESPONSE;
}
break;
case MMS_FILE_UPLOAD_STATE_SEND_FILE_CLOSE:
{
ByteBuffer* request = MmsServer_reserveTransmitBuffer(self);
task->lastRequestInvokeId = MmsServerConnection_getNextRequestInvokeId(task->connection);
mmsClient_createFileCloseRequest(task->lastRequestInvokeId, request, task->frmsId);
IsoConnection_sendMessage(task->connection->isoConnection, request, false);
MmsServer_releaseTransmitBuffer(self);
task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */
task->state = MMS_FILE_UPLOAD_STATE_FILE_CLOSE_SENT;
}
break;
case MMS_FILE_UPLOAD_STATE_FILE_CLOSE_SENT:
if (Hal_getTimeInMs() > task->nextTimeout) {
printf("MMS_SERVER: file close timeout!\n");
task->state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_RESPONSE;
}
break;
case MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_SOURCE:
// TODO send ObtainFileError
printf("MMS_SERVER: ObtainFile service: failed to open file from client\n");
task->state = MMS_FILE_UPLOAD_STATE_NOT_USED;
break;
case MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_RESPONSE:
{
ByteBuffer* response = MmsServer_reserveTransmitBuffer(self);
createObtainFileResponse(task->obtainFileRequestInvokeId, response);
IsoConnection_sendMessage(task->connection->isoConnection, response, false);
MmsServer_releaseTransmitBuffer(self);
if (self->getFileCompleteHandler)
self->getFileCompleteHandler(self->getFileCompleteHandlerParameter, task->connection, task->destinationFilename);
task->state = MMS_FILE_UPLOAD_STATE_NOT_USED;
}
break;
}
}
void
mmsServer_handleObtainFileRequest(
MmsServerConnection connection,
uint8_t* buffer, int bufPos, int maxBufPos,
uint32_t invokeId,
ByteBuffer* response)
{
char sourceFilename[256];
bool hasSourceFileName = false;
char destinationFilename[256];
bool hasDestinationFilename = false;
while (bufPos < maxBufPos) {
uint8_t tag = buffer[bufPos++];
int length;
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) goto exit_reject_invalid_pdu;
switch(tag) {
case 0xa1: /* source filename */
if (!parseFileName(sourceFilename, buffer, &bufPos, bufPos + length, invokeId, response))
return;
hasSourceFileName = true;
break;
case 0xa2: /* destination filename */
if (!parseFileName(destinationFilename, buffer, &bufPos, bufPos + length, invokeId, response))
return;
hasDestinationFilename = true;
break;
default: /* unrecognized parameter */
bufPos += length;
goto exit_reject_invalid_pdu;
}
}
if (hasSourceFileName && hasDestinationFilename) {
/* call callback to check if access is allowed */
if (connection->server->obtainFileHandler)
if (connection->server->obtainFileHandler(connection->server->obtainFileHandlerParameter, connection, sourceFilename, destinationFilename) == false)
goto exit_access_denied;
//TODO check if destination file already exists. If exists return error message
printf("Download file %s from client to local file %s...\n", sourceFilename, destinationFilename);
MmsObtainFileTask task = MmsServer_getObtainFileTask(connection->server);
if (task != NULL) {
/* send file open request */
task->lastRequestInvokeId = MmsServerConnection_getNextRequestInvokeId(connection);
task->connection = connection;
strcpy(task->destinationFilename, destinationFilename);
ByteBuffer* request = MmsServer_reserveTransmitBuffer(connection->server);
mmsClient_createFileOpenRequest(task->lastRequestInvokeId, request, sourceFilename, 0);
IsoConnection_sendMessage(task->connection->isoConnection, request, false);
MmsServer_releaseTransmitBuffer(connection->server);
task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */
task->state = MMS_FILE_UPLOAD_STATE_FILE_OPEN_SENT;
}
else
goto exit_unavailable;
}
else
goto exit_invalid_parameter;
return;
exit_invalid_parameter:
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
return;
exit_access_denied:
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_DENIED);
return;
exit_unavailable:
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_TEMPORARILY_UNAVAILABLE);
return;
exit_reject_invalid_pdu:
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_INVALID_PDU, response);
}
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
void
mmsMsg_createFileReadResponse(int maxPduSize, uint32_t invokeId,
ByteBuffer* response, MmsFileReadStateMachine* frsm)
{
/* determine remaining bytes in file */
@ -380,7 +609,7 @@ createFileReadResponse(MmsServerConnection connection, uint32_t invokeId,
uint32_t fileChunkSize = 0;
uint32_t maxFileChunkSize = connection->maxPduSize - 20;
uint32_t maxFileChunkSize = maxPduSize - 20;
uint32_t fileReadResponseSize = 1; /* for tag */
@ -442,18 +671,17 @@ mmsServer_handleFileReadRequest(
MmsFileReadStateMachine* frsm = getFrsm(connection, frsmId);
if (frsm != NULL)
createFileReadResponse(connection, invokeId, response, frsm);
mmsMsg_createFileReadResponse(connection->maxPduSize, invokeId, response, frsm);
else
mmsServer_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_OTHER);
}
static void
createFileCloseResponse(uint32_t invokeId, ByteBuffer* response)
void
mmsMsg_createFileCloseResponse(uint32_t invokeId, ByteBuffer* response)
{
createNullResponseExtendedTag(invokeId, response, 0x4a);
}
void
mmsServer_handleFileCloseRequest(
MmsServerConnection connection,
@ -469,7 +697,7 @@ mmsServer_handleFileCloseRequest(
frsm->fileHandle = NULL;
frsm->frsmId = 0;
createFileCloseResponse(invokeId, response);
mmsMsg_createFileCloseResponse(invokeId, response);
}

View file

@ -59,7 +59,7 @@ MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConn
if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReportSingle variable: %s\n", itemId);
ByteBuffer* reportBuffer = self->server->reportBuffer;
ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server);
uint8_t* buffer = reportBuffer->buffer;
int bufPos = 0;
@ -82,6 +82,8 @@ MmsServerConnection_sendInformationReportSingleVariableVMDSpecific(MmsServerConn
IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode);
MmsServer_releaseTransmitBuffer(self->server);
exit_function:
return;
}
@ -151,7 +153,7 @@ MmsServerConnection_sendInformationReportListOfVariables(
}
/* encode message */
ByteBuffer* reportBuffer = self->server->reportBuffer;
ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server);
uint8_t* buffer = reportBuffer->buffer;
int bufPos = 0;
@ -212,6 +214,8 @@ MmsServerConnection_sendInformationReportListOfVariables(
IsoConnection_sendMessage(self->isoConnection, reportBuffer, handlerMode);
MmsServer_releaseTransmitBuffer(self->server);
exit_function:
return;
}
@ -264,7 +268,7 @@ MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, c
if (DEBUG_MMS_SERVER) printf("MMS_SERVER: sendInfReport\n");
ByteBuffer* reportBuffer = self->server->reportBuffer;
ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server);
uint8_t* buffer = reportBuffer->buffer;
int bufPos = 0;
@ -294,6 +298,8 @@ MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, c
IsoConnection_sendMessage(self->isoConnection, reportBuffer, false);
MmsServer_releaseTransmitBuffer(self->server);
exit_function:
return;
}

View file

@ -1,7 +1,7 @@
/*
* mms_server.c
*
* Copyright 2013, 2014, 2015 Michael Zillgith
* Copyright 2013 - 2016 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -60,10 +60,11 @@ MmsServer_create(IsoServer isoServer, MmsDevice* device)
self->valueCaches = createValueCaches(device);
self->isLocked = false;
self->reportBuffer = ByteBuffer_create(NULL, CONFIG_MMS_MAXIMUM_PDU_SIZE);
self->transmitBuffer = ByteBuffer_create(NULL, CONFIG_MMS_MAXIMUM_PDU_SIZE);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->modelMutex = Semaphore_create(1);
self->transmitBufferMutex = Semaphore_create(1);
IsoServer_setUserLock(isoServer, self->modelMutex);
#endif
@ -87,6 +88,45 @@ MmsServer_unlockModel(MmsServer self)
#endif
}
ByteBuffer*
MmsServer_reserveTransmitBuffer(MmsServer self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->transmitBufferMutex);
#endif
return self->transmitBuffer;
}
void
MmsServer_releaseTransmitBuffer(MmsServer self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->transmitBufferMutex);
#endif
}
#if (MMS_OBTAIN_FILE_SERVICE == 1)
MmsObtainFileTask
MmsServer_getObtainFileTask(MmsServer self)
{
int i;
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
if (self->fileUploadTasks[i].state == 0) {
self->fileUploadTasks[i].state = 1;
return &(self->fileUploadTasks[i]);
}
}
return NULL;
}
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
void
MmsServer_installReadHandler(MmsServer self, MmsReadVariableHandler readHandler, void* parameter)
{
@ -151,9 +191,10 @@ MmsServer_destroy(MmsServer self)
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->modelMutex);
Semaphore_destroy(self->transmitBufferMutex);
#endif
ByteBuffer_destroy(self->reportBuffer);
ByteBuffer_destroy(self->transmitBuffer);
GLOBAL_FREEMEM(self);
}
@ -311,6 +352,22 @@ MmsServer_handleIncomingMessages(MmsServer self)
IsoServer_processIncomingMessages(self->isoServer);
}
void
MmsServer_handleBackgroundTasks(MmsServer self)
{
#if (MMS_OBTAIN_FILE_SERVICE == 1)
int i;
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++)
{
if (self->fileUploadTasks[i].state != 0)
mmsServer_fileUploadTask(self, &(self->fileUploadTasks[i]));
}
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
}
void
MmsServer_stopListeningThreadless(MmsServer self)
{

View file

@ -111,6 +111,12 @@ handleConfirmedRequestPdu(
if (extendedTag) {
switch(tag) {
#if (MMS_OBTAIN_FILE_SERVICE == 1)
case 0x2e: /* obtain-file */
mmsServer_handleObtainFileRequest(self, buffer, bufPos, bufPos + length, invokeId, response);
break;
#endif /* MMS_OBTAIN_FILE_SERVICE == 1 */
#if (MMS_JOURNAL_SERVICE == 1)
case 0x41: /* read-journal */
mmsServer_handleReadJournalRequest(self, buffer, bufPos, bufPos + length, invokeId, response);
@ -234,6 +240,199 @@ handleConfirmedRequestPdu(
}
}
#if (MMS_OBTAIN_FILE_SERVICE == 1)
static void
handleConfirmedErrorPdu(
MmsServerConnection self,
uint8_t* buffer, int bufPos, int maxBufPos,
ByteBuffer* response)
{
uint32_t invokeId;
MmsServiceError serviceError;
if (mmsMsg_parseConfirmedErrorPDU(buffer, bufPos, maxBufPos, &invokeId, &serviceError)) {
printf("MMS_SERVER: Handle confirmed error PDU: invokeID: %i\n", invokeId);
/* check if message is related to an existing file upload task */
int i;
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
if (self->server->fileUploadTasks[i].lastRequestInvokeId == invokeId) {
self->server->fileUploadTasks[i].state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_SOURCE;
return;
}
}
}
else {
printf("MMS_SERVER: error parsing confirmed error PDU\n");
}
}
static MmsObtainFileTask
getUploadTaskByInvokeId(MmsServer mmsServer, uint32_t invokeId)
{
int i;
for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) {
if (mmsServer->fileUploadTasks[i].lastRequestInvokeId == invokeId)
return &(mmsServer->fileUploadTasks[i]);
}
return NULL;
}
static void
mmsFileReadHandler(void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t bytesReceived)
{
MmsObtainFileTask task = (MmsObtainFileTask) parameter;
printf(" FILE %i received %i bytes\n", frsmId, bytesReceived);
//TODO write data to file
}
static void
handleConfirmedResponsePdu(
MmsServerConnection self,
uint8_t* buffer, int bufPos, int maxBufPos,
ByteBuffer* response)
{
uint32_t invokeId = 0;
while (bufPos < maxBufPos) {
int startBufPos = bufPos;
uint8_t tag = buffer[bufPos++];
int length;
bool extendedTag = false;
if ((tag & 0x1f) == 0x1f) {
extendedTag = true;
tag = buffer[bufPos++];
}
bufPos = BerDecoder_decodeLength(buffer, &length, bufPos, maxBufPos);
if (bufPos < 0) {
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response);
return;
}
if (extendedTag) {
switch(tag) {
#if (MMS_FILE_SERVICE == 1)
case 0x48: /* file-open-response */
printf("MMS_SERVER: received file-open-response\n");
{
MmsObtainFileTask fileTask = getUploadTaskByInvokeId(self->server, invokeId);
if (fileTask != NULL) {
int32_t frmsId;
if (mmsMsg_parseFileOpenResponse(buffer, startBufPos, maxBufPos, &frmsId, NULL, NULL)) {
printf("MMS_SERVER: received file-open-response with frmsId=%i\n", frmsId);
fileTask->frmsId = frmsId;
fileTask->state = MMS_FILE_UPLOAD_STATE_SEND_FILE_READ;
}
else {
printf("MMS_SERVER: error parsing file-open-response\n");
fileTask->state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_SOURCE;
}
}
else
printf("MMS_SERVER: unexpected file-open-response\n");
}
break;
case 0x49: /* file-read-response */
printf("MMS_SERVER: received file-read-response\n");
{
MmsObtainFileTask fileTask = getUploadTaskByInvokeId(self->server, invokeId);
if (fileTask != NULL) {
bool moreFollows;
if (mmsMsg_parseFileReadResponse(buffer, startBufPos, maxBufPos, fileTask->frmsId, &moreFollows, mmsFileReadHandler, (void*) fileTask)) {
printf("MMS_SERVER: received file data\n");
if (moreFollows) {
fileTask->state = MMS_FILE_UPLOAD_STATE_SEND_FILE_READ;
}
else {
//TODO close local file
fileTask->state = MMS_FILE_UPLOAD_STATE_SEND_FILE_CLOSE;
}
}
else {
fileTask->state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_ERROR_SOURCE;
printf("MMS_SERVER: error parsing file-read-response\n");
}
}
else
printf("MMS_SERVER: unexpected file-read-response\n");
}
break;
case 0x4a: /* file-close-response */
{
printf("MMS_SERVER: received file-close-response\n");
MmsObtainFileTask fileTask = getUploadTaskByInvokeId(self->server, invokeId);
if (fileTask != NULL) {
fileTask->state = MMS_FILE_UPLOAD_STATE_SEND_OBTAIN_FILE_RESPONSE;
}
else
printf("MMS_SERVER: unexpected file-close-response\n");
}
break;
#endif /* MMS_FILE_SERVICE == 1 */
default:
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response);
return;
break;
}
}
else {
switch(tag) {
case 0x02: /* invoke Id */
invokeId = BerDecoder_decodeUint32(buffer, length, bufPos);
if (DEBUG_MMS_SERVER)
printf("MMS_SERVER: received request with invokeId: %i\n", invokeId);
self->lastInvokeId = invokeId;
break;
default:
mmsServer_writeMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_UNRECOGNIZED_SERVICE, response);
return;
break;
}
}
bufPos += length;
}
} /* handleConfirmedResponsePdu */
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
MmsIndication
MmsServerConnection_parseMessage(MmsServerConnection self, ByteBuffer* message, ByteBuffer* response)
{
@ -266,6 +465,17 @@ MmsServerConnection_parseMessage(MmsServerConnection self, ByteBuffer* message,
handleConfirmedRequestPdu(self, buffer, bufPos, bufPos + pduLength, response);
retVal = MMS_CONFIRMED_REQUEST;
break;
#if (MMS_OBTAIN_FILE_SERVICE == 1)
case 0xa1: /* Confirmed response PDU */
handleConfirmedResponsePdu(self, buffer, bufPos, bufPos + pduLength, response);
retVal = MMS_CONFIRMED_REQUEST;
break;
case 0xa2: /* Confirmed error PDU */
handleConfirmedErrorPdu(self, buffer, 0, bufPos + pduLength, response);
retVal = MMS_CONFIRMED_REQUEST;
break;
#endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */
case 0x8b: /* Conclude request PDU */
mmsServer_writeConcludeResponsePdu(response);
retVal = MMS_CONCLUDE;
@ -317,6 +527,10 @@ MmsServerConnection_init(MmsServerConnection connection, MmsServer server, IsoCo
self->namedVariableLists = LinkedList_create();
#endif
#if (MMS_OBTAIN_FILE_SERVICE == 1)
self->lastRequestInvokeId = 0;
#endif
IsoConnection_installListener(isoCon, messageReceived, (void*) self);
return self;
@ -391,3 +605,10 @@ MmsServerConnection_getLastInvokeId(MmsServerConnection self)
{
return self->lastInvokeId;
}
uint32_t
MmsServerConnection_getNextRequestInvokeId(MmsServerConnection self)
{
self->lastRequestInvokeId++;
return self->lastRequestInvokeId;
}

View file

@ -38,6 +38,7 @@ int
mmsServer_createMmsWriteResponse(MmsServerConnection connection,
int invokeId, ByteBuffer* response, int numberOfItems, MmsDataAccessError* accessResults)
{
//TODO remove asn1c code
MmsPdu_t* mmsPdu = mmsServer_createConfirmedResponse(invokeId);
mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present =
@ -75,13 +76,15 @@ mmsServer_createMmsWriteResponse(MmsServerConnection connection,
void
MmsServerConnection_sendWriteResponse(MmsServerConnection self, uint32_t invokeId, MmsDataAccessError indication, bool handlerMode)
{
ByteBuffer* response = ByteBuffer_create(NULL, self->maxPduSize);
ByteBuffer* response = MmsServer_reserveTransmitBuffer(self->server);
ByteBuffer_setSize(response, 0);
mmsServer_createMmsWriteResponse(self, invokeId, response, 1, &indication);
IsoConnection_sendMessage(self->isoConnection, response, handlerMode);
ByteBuffer_destroy(response);
MmsServer_releaseTransmitBuffer(self->server);
}
void

View file

@ -54,10 +54,10 @@
struct sIsoConnection
{
uint8_t* receiveBuffer;
uint8_t* sendBuffer;
ByteBuffer rcvBuffer;
uint8_t* sendBuffer;
uint8_t* cotpReadBuf;
uint8_t* cotpWriteBuf;
ByteBuffer cotpReadBuffer;

View file

@ -551,3 +551,6 @@ EXPORTS
ModelNode_getType
ControlObjectClient_setTestMode
LogStorage_setMaxLogEntries
MmsServer_installObtainFileHandler
MmsServer_installGetFileCompleteHandler
MmsServer_handleBackgroundTasks

View file

@ -629,3 +629,6 @@ EXPORTS
ModelNode_getType
ControlObjectClient_setTestMode
LogStorage_setMaxLogEntries
MmsServer_installObtainFileHandler
MmsServer_installGetFileCompleteHandler
MmsServer_handleBackgroundTasks