diff --git a/config/stack_config.h b/config/stack_config.h index 12dfd444..80f29ffe 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -219,6 +219,9 @@ /* maximum number of contemporary file upload tasks (obtainFile) per server instance */ #define CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS 5 +/* server side request timeout for file upload tasks (in milliseconds) */ +#define CONFIG_MMS_SERVER_REQUEST_TIMEOUT_MS 2000 + /* Definition of supported services */ #define MMS_DEFAULT_PROFILE 1 diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index 44f36a05..bce0341a 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -2558,6 +2558,9 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedServer_setListObjectsAccessHandler(IntPtr self, IedServer_ListObjectsAccessHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServer_setRequestTimeout(IntPtr self, Int32 timeoutMs); + /// /// Set a handler to control read and write access to control blocks and logs /// @@ -3543,6 +3546,15 @@ namespace IEC61850 return IedServer_getNumberOfOpenConnections(self); } + /// + /// Set the request timeout for the server (used for obtain file service) + /// + /// request timeout in milliseconds + public void SetRequestTimeout(int timeoutMs) + { + IedServer_setRequestTimeout(self, timeoutMs); + } + private ControlHandlerInfo GetControlHandlerInfo(DataObject controlObject) { ControlHandlerInfo info; diff --git a/examples/server_example_files/server_example_files.c b/examples/server_example_files/server_example_files.c index 9974fe6f..a8f0c7e4 100644 --- a/examples/server_example_files/server_example_files.c +++ b/examples/server_example_files/server_example_files.c @@ -5,12 +5,12 @@ * - How to control how files file services can be used */ -#include "iec61850_server.h" #include "hal_thread.h" +#include "iec61850_server.h" +#include #include -#include #include -#include +#include #include "static_model.h" @@ -24,7 +24,7 @@ sigint_handler(int signalId) } static void -connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter) +connectionHandler(IedServer self, ClientConnection connection, bool connected, void* parameter) { if (connected) printf("Connection opened\n"); @@ -33,8 +33,8 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected, } static MmsError -fileAccessHandler (void* parameter, MmsServerConnection connection, MmsFileServiceType service, - const char* localFilename, const char* otherFilename) +fileAccessHandler(void* parameter, MmsServerConnection connection, MmsFileServiceType service, + const char* localFilename, const char* otherFilename) { printf("fileAccessHandler: service = %i, local-file: %s other-file: %s\n", service, localFilename, otherFilename); @@ -43,7 +43,8 @@ fileAccessHandler (void* parameter, MmsServerConnection connection, MmsFileServi return MMS_ERROR_FILE_FILE_ACCESS_DENIED; /* Don't allow client to delete file "IEDSERVER.BIN" */ - if (service == MMS_FILE_ACCESS_TYPE_DELETE) { + if (service == MMS_FILE_ACCESS_TYPE_DELETE) + { if (strcmp(localFilename, "IEDSERVER.BIN") == 0) return MMS_ERROR_FILE_FILE_ACCESS_DENIED; } @@ -57,7 +58,8 @@ main(int argc, char** argv) { int tcpPort = 102; - if (argc > 1) { + if (argc > 1) + { tcpPort = atoi(argv[1]); } @@ -70,15 +72,18 @@ main(int argc, char** argv) IedServer_setFilestoreBasepath(iedServer, "./vmd-filestore/"); + IedServer_setRequestTimeout(iedServer, 5000); + /* Set a callback handler to control file accesses */ MmsServer_installFileAccessHandler(mmsServer, fileAccessHandler, NULL); - IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler)connectionHandler, NULL); /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, tcpPort); - if (!IedServer_isRunning(iedServer)) { + if (!IedServer_isRunning(iedServer)) + { printf("Starting server failed! Exit.\n"); IedServer_destroy(iedServer); exit(-1); @@ -88,16 +93,14 @@ main(int argc, char** argv) signal(SIGINT, sigint_handler); - while (running) Thread_sleep(100); - /* stop MMS server - close TCP server socket and all client sockets */ IedServer_stop(iedServer); /* Cleanup - free all resources */ IedServer_destroy(iedServer); - return 0; + return 0; } /* main() */ diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index cacbc524..80a71101 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -3,7 +3,7 @@ * * IEC 61850 server API for libiec61850. * - * Copyright 2013-2024 Michael Zillgith + * Copyright 2013-2025 Michael Zillgith * * This file is part of libIEC61850. * @@ -540,6 +540,15 @@ IedServer_setServerIdentity(IedServer self, const char* vendor, const char* mode LIB61850_API void IedServer_setFilestoreBasepath(IedServer self, const char* basepath); +/** + * \brief Set the request timeout for the server (used for obtain file service) + * + * \param self the IedServer instance to operate on + * \param timeoutMs the timeout value in milliseconds + */ +LIB61850_API void +IedServer_setRequestTimeout(IedServer self, int32_t timeoutMs); + /** * \brief Assign a \ref LogStorage instance to a log reference * diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 68c2232f..7496c495 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -937,6 +937,12 @@ IedServer_setFilestoreBasepath(IedServer self, const char* basepath) MmsServer_setFilestoreBasepath(self->mmsServer, basepath); } +void +IedServer_setRequestTimeout(IedServer self, int32_t timeoutMs) +{ + MmsServer_setRequestTimeout(self->mmsServer, timeoutMs); +} + void IedServer_setLocalIpAddress(IedServer self, const char* localIpAddress) { diff --git a/src/mms/inc_private/mms_server_internal.h b/src/mms/inc_private/mms_server_internal.h index 3fae4f26..ed5933ed 100644 --- a/src/mms/inc_private/mms_server_internal.h +++ b/src/mms/inc_private/mms_server_internal.h @@ -105,8 +105,8 @@ struct sMmsObtainFileTask { #endif /* (MMS_OBTAIN_FILE_SERVICE == 1) */ -struct sMmsServer { - +struct sMmsServer +{ LinkedList /**/ isoServerList; MmsDevice* device; @@ -177,6 +177,8 @@ struct sMmsServer { void* getFileCompleteHandlerParameter; struct sMmsObtainFileTask fileUploadTasks[CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS]; + + int32_t requestTimeoutMs; /* request timeout in milliseconds */ #endif #if (MMS_FILE_SERVICE == 1) diff --git a/src/mms/inc_private/mms_server_libinternal.h b/src/mms/inc_private/mms_server_libinternal.h index f7daa70c..70389297 100644 --- a/src/mms/inc_private/mms_server_libinternal.h +++ b/src/mms/inc_private/mms_server_libinternal.h @@ -205,4 +205,13 @@ MmsServer_stopListeningThreadless(MmsServer self); LIB61850_INTERNAL const char* MmsServer_getFilesystemBasepath(MmsServer self); +/** + * \brief Set the request timeout for the server (used for obtain file service) + * + * \param self the MmsServer instance to operate on + * \param timeoutMs the timeout value in milliseconds + */ +LIB61850_INTERNAL void +MmsServer_setRequestTimeout(MmsServer self, int32_t timeoutMs); + #endif /* MMS_SERVER_LIBINTERNAL_H_ */ diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c index ca5d80f7..d1367991 100644 --- a/src/mms/iso_mms/server/mms_file_service.c +++ b/src/mms/iso_mms/server/mms_file_service.c @@ -482,7 +482,7 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task, int taskState) task->state = MMS_FILE_UPLOAD_STATE_FILE_READ_SENT; IsoConnection_sendMessage(task->connection->isoConnection, message); - task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */ + task->nextTimeout = Hal_getTimeInMs() + self->requestTimeoutMs; } break; @@ -515,7 +515,7 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task, int taskState) IsoConnection_sendMessage(task->connection->isoConnection, message); - task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */ + task->nextTimeout = Hal_getTimeInMs() + self->requestTimeoutMs; } break; @@ -783,7 +783,7 @@ mmsServer_handleObtainFileRequest( MmsServer_releaseTransmitBuffer(connection->server); - task->nextTimeout = Hal_getTimeInMs() + 2000; /* timeout 2000 ms */ + task->nextTimeout = Hal_getTimeInMs() + connection->server->requestTimeoutMs; task->state = MMS_FILE_UPLOAD_STATE_FILE_OPEN_SENT; } diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c index a82627eb..aacf9118 100644 --- a/src/mms/iso_mms/server/mms_server.c +++ b/src/mms/iso_mms/server/mms_server.c @@ -28,6 +28,10 @@ #include "mms_server_internal.h" #include "iso_server_private.h" +#ifndef CONFIG_MMS_SERVER_REQUEST_TIMEOUT_MS +#define CONFIG_MMS_SERVER_REQUEST_TIMEOUT_MS 2000 +#endif + static Map createValueCaches(MmsDevice* device) { @@ -116,6 +120,8 @@ MmsServer_create(MmsDevice* device, TLSConfiguration tlsConfiguration) #if (MMS_OBTAIN_FILE_SERVICE == 1) { + self->requestTimeoutMs = CONFIG_MMS_SERVER_REQUEST_TIMEOUT_MS; + int i; for (i = 0; i < CONFIG_MMS_SERVER_MAX_GET_FILE_TASKS; i++) @@ -921,6 +927,14 @@ MmsServer_getFilesystemBasepath(MmsServer self) #endif } +void +MmsServer_setRequestTimeout(MmsServer self, int32_t timeoutMs) +{ +#if (MMS_OBTAIN_FILE_SERVICE == 1) + self->requestTimeoutMs = timeoutMs; +#endif +} + void MmsServer_ignoreClientRequests(MmsServer self, bool enable) {